From 2abd46c1fefdf176aa0b27cd45d1903fe0239626 Mon Sep 17 00:00:00 2001 From: Mentrillum Date: Sat, 21 Dec 2024 20:34:17 -0700 Subject: [PATCH 1/5] 12-21-2024 --- addons/sourcemod/scripting/include/sf2.inc | 1169 +++- .../scripting/include/sf2/defines.inc | 1 + .../include/sf2/profiles/profiles.inc | 112 +- .../include/sf2/profiles/profiles_chaser.inc | 53 +- .../scripting/include/sf2/stocks.inc | 4 +- addons/sourcemod/scripting/sf2.sp | 397 +- addons/sourcemod/scripting/sf2/adminmenu.sp | 64 +- addons/sourcemod/scripting/sf2/anticamping.sp | 1 + addons/sourcemod/scripting/sf2/changelog.sp | 1 + .../sourcemod/scripting/sf2/classconfigs.sp | 1 + addons/sourcemod/scripting/sf2/client.sp | 163 +- .../sourcemod/scripting/sf2/client/blink.sp | 7 +- .../scripting/sf2/client/breathing.sp | 1 + .../scripting/sf2/client/deathcam.sp | 345 +- .../scripting/sf2/client/flashlight.sp | 10 +- .../scripting/sf2/client/ghostmode.sp | 41 +- .../sourcemod/scripting/sf2/client/hints.sp | 3 + .../scripting/sf2/client/interactables.sp | 8 +- .../sourcemod/scripting/sf2/client/music.sp | 423 +- addons/sourcemod/scripting/sf2/client/peek.sp | 1 + .../sourcemod/scripting/sf2/client/proxy.sp | 1131 +++- .../sourcemod/scripting/sf2/client/sprint.sp | 145 +- .../sourcemod/scripting/sf2/client/static.sp | 37 +- .../sourcemod/scripting/sf2/client/think.sp | 397 +- .../scripting/sf2/client/ultravision.sp | 1 + addons/sourcemod/scripting/sf2/debug.sp | 1 + addons/sourcemod/scripting/sf2/effects.sp | 996 +++- .../scripting/sf2/entities/initialize.sp | 3 + .../projectiles/sf2_arrow_projectile.sp | 1 + .../projectiles/sf2_baseball_projectile.sp | 8 +- .../projectiles/sf2_cow_mangler_projectile.sp | 1 + .../projectiles/sf2_fireball_projectile.sp | 1 + .../projectiles/sf2_grenade_projectile.sp | 56 +- .../projectiles/sf2_iceball_projectile.sp | 1 + .../projectiles/sf2_rocket_projectile.sp | 1 + .../sf2_sentry_rocket_projectile.sp | 1 + .../sf2/entities/sf2_base_projectile.sp | 9 +- .../scripting/sf2/extras/afk_mode.sp | 1 + .../scripting/sf2/extras/commands.sp | 149 +- .../scripting/sf2/extras/game_events.sp | 80 +- .../sourcemod/scripting/sf2/extras/natives.sp | 11 +- .../scripting/sf2/gamemodes/renevant.sp | 7 +- addons/sourcemod/scripting/sf2/glow.sp | 3 + addons/sourcemod/scripting/sf2/logging.sp | 1 + addons/sourcemod/scripting/sf2/mapentities.sp | 1 + .../scripting/sf2/mapentities/base.sp | 1 + .../sf2/mapentities/base_spawnpoint.sp | 1 + .../sf2/mapentities/sf2_boss_maker.sp | 10 +- .../sf2/mapentities/sf2_game_text.sp | 1 + .../sf2/mapentities/sf2_gamerules.sp | 1 + .../sf2/mapentities/sf2_info_boss_spawn.sp | 1 + .../sf2/mapentities/sf2_info_page_music.sp | 1 + .../sf2/mapentities/sf2_info_page_spawn.sp | 1 + .../sf2_info_player_escapespawn.sp | 1 + .../mapentities/sf2_info_player_proxyspawn.sp | 1 + .../mapentities/sf2_info_player_pvpspawn.sp | 1 + .../sf2/mapentities/sf2_logic_arena.sp | 1 + .../sf2/mapentities/sf2_logic_boxing.sp | 1 + .../sf2/mapentities/sf2_logic_proxy.sp | 1 + .../sf2/mapentities/sf2_logic_raid.sp | 1 + .../sf2/mapentities/sf2_logic_slaughter.sp | 1 + .../sf2/mapentities/sf2_point_spotlight.sp | 9 +- .../mapentities/sf2_trigger_boss_despawn.sp | 1 + .../sf2/mapentities/sf2_trigger_escape.sp | 1 + .../sf2/mapentities/sf2_trigger_pve.sp | 1 + .../sf2/mapentities/sf2_trigger_pvp.sp | 1 + addons/sourcemod/scripting/sf2/menus.sp | 43 +- addons/sourcemod/scripting/sf2/methodmaps.sp | 184 +- addons/sourcemod/scripting/sf2/npc.sp | 2509 ++------- .../sf2/npc/entities/base/actions/deathcam.sp | 42 +- .../base/actions/playsequenceandwait.sp | 3 +- .../base/actions/playsequenceandwait_ex.sp | 102 + .../scripting/sf2/npc/entities/base/entity.sp | 165 +- .../sf2/npc/entities/chaser/actions/alert.sp | 59 +- .../sf2/npc/entities/chaser/actions/attack.sp | 1512 +++++- .../entities/chaser/actions/attacklayer.sp | 2 +- .../entities/chaser/actions/attacks/bullet.sp | 166 +- .../entities/chaser/actions/attacks/custom.sp | 58 +- .../chaser/actions/attacks/explosive_dance.sp | 84 +- .../chaser/actions/attacks/forward_based.sp | 72 +- .../chaser/actions/attacks/laser_beam.sp | 141 +- .../entities/chaser/actions/attacks/melee.sp | 146 +- .../chaser/actions/attacks/projectile.sp | 239 +- .../entities/chaser/actions/attacks/tongue.sp | 254 +- .../entities/chaser/actions/beatbox_freeze.sp | 1 + .../sf2/npc/entities/chaser/actions/chase.sp | 51 +- .../entities/chaser/actions/chaseinitial.sp | 24 +- .../npc/entities/chaser/actions/chaselayer.sp | 45 +- .../sf2/npc/entities/chaser/actions/death.sp | 77 +- .../npc/entities/chaser/actions/despawn.sp | 1 + .../entities/chaser/actions/flee_to_heal.sp | 58 +- .../sf2/npc/entities/chaser/actions/idle.sp | 81 +- .../npc/entities/chaser/actions/mainlayer.sp | 44 +- .../sf2/npc/entities/chaser/actions/rage.sp | 32 +- .../sf2/npc/entities/chaser/actions/smell.sp | 40 +- .../sf2/npc/entities/chaser/actions/spawn.sp | 1 + .../sf2/npc/entities/chaser/actions/stun.sp | 62 +- .../npc/entities/chaser/actions/tauntkill.sp | 13 +- .../sf2/npc/entities/chaser/entity.sp | 1588 +++--- .../npc/entities/chaser/postures/on_alert.sp | 56 +- .../npc/entities/chaser/postures/on_cloak.sp | 56 +- .../npc/entities/chaser/postures/on_look.sp | 55 +- .../entities/chaser/postures/rage_phase.sp | 84 +- .../entities/chaser/postures/running_away.sp | 55 +- .../entities/chaser/postures/within_bounds.sp | 77 +- .../entities/chaser/postures/within_range.sp | 132 +- .../scripting/sf2/npc/entities/initialize.sp | 1 + .../sf2/npc/entities/statue/actions/chase.sp | 43 +- .../sf2/npc/entities/statue/actions/idle.sp | 1 + .../npc/entities/statue/actions/mainlayer.sp | 31 +- .../sf2/npc/entities/statue/entity.sp | 64 +- addons/sourcemod/scripting/sf2/npc/glow.sp | 8 +- .../sourcemod/scripting/sf2/npc/npc_chaser.sp | 109 +- .../scripting/sf2/npc/npc_creeper.sp | 52 +- .../sourcemod/scripting/sf2/playergroups.sp | 1 + .../scripting/sf2/playergroups/menus.sp | 1 + addons/sourcemod/scripting/sf2/profiles.sp | 313 +- .../scripting/sf2/profiles/profile_chaser.sp | 3108 ++++++++++- .../sf2/profiles/profile_chaser_precache.sp | 1 + .../scripting/sf2/profiles/profile_statue.sp | 88 +- .../sf2/profiles/profiles_boss_functions.sp | 4683 ++++++++++------- addons/sourcemod/scripting/sf2/pve.sp | 35 +- addons/sourcemod/scripting/sf2/pvp.sp | 18 - addons/sourcemod/scripting/sf2/pvp/menus.sp | 1 + .../sourcemod/scripting/sf2/specialround.sp | 6 +- addons/sourcemod/scripting/sf2/stocks.sp | 55 +- addons/sourcemod/scripting/sf2/traps.sp | 57 +- 127 files changed, 14936 insertions(+), 8040 deletions(-) create mode 100644 addons/sourcemod/scripting/sf2/npc/entities/base/actions/playsequenceandwait_ex.sp diff --git a/addons/sourcemod/scripting/include/sf2.inc b/addons/sourcemod/scripting/include/sf2.inc index 64621c15..6e82b165 100644 --- a/addons/sourcemod/scripting/include/sf2.inc +++ b/addons/sourcemod/scripting/include/sf2.inc @@ -7,8 +7,8 @@ #include #include -#define PLUGIN_VERSION "1.8.0 M Alpha 2.7" -#define PLUGIN_VERSION_DISPLAY "1.8.0 M Alpha 2.7" +#define PLUGIN_VERSION "1.8.0 M Alpha 3 Indev 12-21-2024" +#define PLUGIN_VERSION_DISPLAY "1.8.0 M Alpha 3 Indev 12-21-2024" // Some defines. #define SF2_MAX_PROFILE_NAME_LENGTH 64 @@ -155,6 +155,7 @@ enum SF2BossSound_RageTwo = 15, SF2BossSound_RageThree, SF2BossSound_Despawn, + SF2BossSound_Hurt, SF2BossSound_MaxSounds }; @@ -223,7 +224,7 @@ enum SF2Attribute_Max }; -char g_SlenderVoiceList[SF2BossSound_MaxSounds][] = +stock char g_SlenderVoiceList[SF2BossSound_MaxSounds][] = { "sound_none", // Placeholder "sound_idle", @@ -242,10 +243,11 @@ char g_SlenderVoiceList[SF2BossSound_MaxSounds][] = "sound_rage", "sound_rage_2", "sound_rage_3", - "sound_despawn" + "sound_despawn", + "sound_hurt" }; -char g_SlenderAnimationsList[SF2BossAnimation_MaxAnimations][] = +stock char g_SlenderAnimationsList[SF2BossAnimation_MaxAnimations][] = { "idle", "walk", @@ -267,7 +269,7 @@ char g_SlenderAnimationsList[SF2BossAnimation_MaxAnimations][] = "despawn" }; -char g_AttributesList[SF2Attribute_Max][] = +stock char g_AttributesList[SF2Attribute_Max][] = { "reduced speed on look", "reduced walk speed on look", @@ -374,6 +376,7 @@ enum RenevantWave #define COND_ENEMYRECHASE (1 << 13) #define COND_DEBUG (1 << 14) #define COND_ALERT_TRIGGER_POS (1 << 15) +#define COND_ENEMYVISIBLE_NOGLASS (1 << 16) /** * Called after a boss profile is successfully loaded. @@ -381,14 +384,14 @@ enum RenevantWave * @param profile Profile name * @param kv Key Values */ -forward void SF2_OnBossProfileLoaded(const char[] profile, KeyValues kv); +forward void SF2_OnBossProfileLoaded(const char[] profile, SF2_BaseBossProfile data); /** * Called before a boss profile is unloaded. * * @param profile Profile name */ -forward void SF2_OnBossProfileUnloaded(const char[] profile); +forward void SF2_OnBossProfileUnloaded(const char[] profile, SF2_BaseBossProfile data); /** * Called when a boss is added into the game. @@ -516,8 +519,8 @@ forward void SF2_OnBossAttacked(int bossIndex, int attackIndex); /** * Called when the boss finishes validating all attack indexes. * - * @param bossIndex Boss index. - * @param attackArray ArrayList containing all valid attacks + * @param bossIndex Boss index. + * @param attackArray ArrayList containing all valid attack indexes. */ forward void SF2_OnBossPreAttack(int bossIndex, ArrayList attackArray); @@ -831,7 +834,7 @@ forward void SF2_OnDifficultyVoteFinished(ArrayList list, bool isRunOff); * @return Returning a value other than Plugin_Continue will block the boss from using * the attack. */ -forward Action SF2_OnIsBossCustomAttackPossible(SF2_ChaserBossEntity chaser, const char[] attackName, SF2ChaserBossProfileAttackData data, CBaseEntity target); +forward Action SF2_OnIsBossCustomAttackPossible(SF2_ChaserBossEntity chaser, const char[] attackName, SF2_ChaserBossProfileBaseAttack data, CBaseEntity target); /** * Called when the Chaser boss has selected the custom attack and is requesting a @@ -844,7 +847,7 @@ forward Action SF2_OnIsBossCustomAttackPossible(SF2_ChaserBossEntity chaser, con * @param action Parameter to fill with the NextBotAction * @return Return a value other than Plugin_Continue to use `action` */ -forward Action SF2_OnBossGetCustomAttackAction(SF2_ChaserBossEntity chaser, const char[] attackName, SF2ChaserBossProfileAttackData data, CBaseEntity target, NextBotAction &action); +forward Action SF2_OnBossGetCustomAttackAction(SF2_ChaserBossEntity chaser, const char[] attackName, SF2_ChaserBossProfileBaseAttack data, CBaseEntity target, NextBotAction &action); /** * Called when a projectile from SF2 has touched another entity successfully and has either exploded or dealt damage. @@ -1026,6 +1029,7 @@ native bool SF2_IsClientUbercharged(int client); */ native bool SF2_IsClientInKart(int client); +#if defined _tf2_included /** * Returns whether or not the client is in a specific condition for SF2. * @@ -1034,6 +1038,7 @@ native bool SF2_IsClientInKart(int client); * @return True if the player is in a condition, false if not. */ native bool SF2_IsClientInCondition(int client, TFCond condition); +#endif /** * Returns a bool about the client's elimination state. @@ -1365,7 +1370,7 @@ native void SF2_ForceBossJump(NextBotGroundLocomotion nextbotLocomotion, float s * @param playSpawnSound Play spawn sound. * @return Boss index, or -1 if failed. */ -native int SF2_AddBoss(const char[] profile, int flags=0, bool spawnCompanions=true, bool playSpawnSound=true); +native int SF2_AddBoss(const char[] profile, int flags = 0, bool spawnCompanions = true, bool playSpawnSound = true); /** * Removes a boss from the game. @@ -1515,10 +1520,10 @@ native void SF2_GetBossEyePosition(int bossIndex, float eyePos[3]); */ native void SF2_GetBossEyePositionOffset(int bossIndex, float eyePosOffset[3]); -#pragma deprecated Use SF2ChaserBossProfileAttackData.StunEnabled[Difficulty_Max] instead. +#pragma deprecated Use SF2_ChaserBossProfile instead. native bool SF2_IsBossStunnable(int bossIndex); -#pragma deprecated Use SF2ChaserBossProfileAttackData.StunFlashlight[Difficulty_Max] instead. +#pragma deprecated Use SF2_ChaserBossProfile instead. native bool SF2_IsBossStunnableByFlashlight(int bossIndex); /** @@ -1569,43 +1574,43 @@ native void SF2_GetBossGoalPosition(int bossIndex, float position[3]); */ native bool SF2_IsBossProfileValid(const char[] profile); -#pragma deprecated Use SF2BossProfileData instead. -native int SF2_GetBossProfileNum(const char[] profile, const char[] key, int defaultValue=0); +#pragma deprecated Use SF2_BaseBossProfile instead. +native int SF2_GetBossProfileNum(const char[] profile, const char[] key, int defaultValue = 0); -#pragma deprecated Use SF2BossProfileData instead. -native float SF2_GetBossProfileFloat(const char[] profile, const char[] key, float defaultValue=0.0); +#pragma deprecated Use SF2_BaseBossProfile instead. +native float SF2_GetBossProfileFloat(const char[] profile, const char[] key, float defaultValue = 0.0); -#pragma deprecated Use SF2BossProfileData instead. -native bool SF2_GetBossProfileString(const char[] profile, const char[] key, char[] buffer, int bufferLen, const char[] defaultValue=""); +#pragma deprecated Use SF2_BaseBossProfile instead. +native bool SF2_GetBossProfileString(const char[] profile, const char[] key, char[] buffer, int bufferLen, const char[] defaultValue = ""); -#pragma deprecated Use SF2BossProfileData instead. -native bool SF2_GetBossProfileVector(const char[] profile, const char[] key, float buffer[3], const float defaultValue[3]=NULL_VECTOR); +#pragma deprecated Use SF2_BaseBossProfile instead. +native bool SF2_GetBossProfileVector(const char[] profile, const char[] key, float buffer[3], const float defaultValue[3] = NULL_VECTOR); -#pragma deprecated Use SF2ChaserBossProfileData.Attacks instead. -native int SF2_GetBossAttackProfileNum(const char[] profile, const char[] key, int defaultValue=0, const int attackIndex); +#pragma deprecated Use SF2_ChaserBossProfileBaseAttack instead. +native int SF2_GetBossAttackProfileNum(const char[] profile, const char[] key, int defaultValue = 0, const int attackIndex); -#pragma deprecated Use SF2ChaserBossProfileData.Attacks instead. -native float SF2_GetBossAttackProfileFloat(const char[] profile, const char[] key, float defaultValue=0.0, const int attackIndex); +#pragma deprecated Use SF2_ChaserBossProfileBaseAttack instead. +native float SF2_GetBossAttackProfileFloat(const char[] profile, const char[] key, float defaultValue = 0.0, const int attackIndex); -#pragma deprecated Use SF2ChaserBossProfileData.Attacks instead. -native bool SF2_GetBossAttackProfileString(const char[] profile, const char[] key, char[] buffer, int bufferLen, const char[] defaultValue="", const int attackIndex); +#pragma deprecated Use SF2_ChaserBossProfileBaseAttack instead. +native bool SF2_GetBossAttackProfileString(const char[] profile, const char[] key, char[] buffer, int bufferLen, const char[] defaultValue = "", const int attackIndex); -#pragma deprecated Use SF2ChaserBossProfileData.Attacks instead. -native bool SF2_GetBossAttackProfileVector(const char[] profile, const char[] key, float buffer[3], const float defaultValue[3]=NULL_VECTOR, const int attackIndex); +#pragma deprecated Use SF2_ChaserBossProfileBaseAttack instead. +native bool SF2_GetBossAttackProfileVector(const char[] profile, const char[] key, float buffer[3], const float defaultValue[3] = NULL_VECTOR, const int attackIndex); -#pragma deprecated Use SF2BossProfileData instead. -native bool SF2_GetRandomStringFromBossProfile(const char[] profile, const char[] key, char[] buffer, int bufferLen, int index=-1); +#pragma deprecated Use SF2_BaseBossProfile instead. +native bool SF2_GetRandomStringFromBossProfile(const char[] profile, const char[] key, char[] buffer, int bufferLen, int index = -1); -#pragma deprecated Use SF2BossProfileData instead. +#pragma deprecated Use SF2_BaseBossProfile instead. native bool SF2_GetBossAttributeName(int bossIndex, int attribute); -#pragma deprecated Use SF2BossProfileData instead. +#pragma deprecated Use SF2_BaseBossProfile instead. native float SF2_GetBossAttributeValue(int bossIndex, int attribute); #pragma deprecated Use SF2_ChaserBossEntity.AttackIndex instead. native int SF2_GetBossCurrentAttackIndex(int bossIndex); -#pragma deprecated Use SF2ChaserBossProfileAttackData.Type instead. +#pragma deprecated Use SF2_ChaserBossProfileBaseAttack instead. native int SF2_GetBossAttackIndexType(int bossIndex, int attackIndex); #pragma deprecated This no longer does anything. @@ -1626,10 +1631,10 @@ native void SF2_PerformBossVoice(int bossIndex, const int attackIndex = -1, int #pragma deprecated Use SF2_ChaserBossEntity.CreateSoundHint instead. native void SF2_CreateBossSoundHint(int bossIndex, SoundType soundType, const float position[3], int difficulty); -#pragma deprecated Use SF2ChaserBossProfileAttackData.Damage[Difficulty_Max] instead. +#pragma deprecated Use SF2_ChaserBossProfileBaseAttack instead. native float SF2_GetBossAttackIndexDamage(int bossIndex, int attackIndex, int difficulty); -#pragma deprecated Use SF2ChaserBossProfileAttackData.DamageType[Difficulty_Max] instead. +#pragma deprecated Use SF2_ChaserBossProfileBaseAttack instead. native int SF2_GetBossAttackIndexDamageType(int bossIndex, int attackIndex); #pragma deprecated Use SF2_BaseBossEntity.ResetProfileAnimation instead. @@ -1661,41 +1666,19 @@ native void SF2_SetBossTeleportThinkTimer(int bossIndex, Handle timer); */ native int SF2_GetBossTeleportTarget(int bossIndex); -/** - * Returns the StringMap variable containing every precached base boss profile - * - * @return StringMap containing all base boss profile datas -*/ -native StringMap SF2_GetBossProfileData(); - -/** - * Returns the StringMap variable containing every precached chaser boss profile - * - * @return StringMap containing all chaser boss profile datas -*/ -native StringMap SF2_GetChaserBossProfileData(); - -/** - * Returns the StringMap variable containing every precached statue boss profile - * - * @return StringMap containing all statue boss profile datas -*/ -native StringMap SF2_GetStatueBossProfileData(); - /** * Spawns boss effects based on the list of effects used. * Note this will not spawn the extra effects like the festive lights and the disco ball * Only use this best for spawning in temporary effects. - * Note the array of effects must be an ArrayList that contains SF2BossProfileBaseEffectInfo. * - * @param effects The array of effects + * @param effects The effects section to use * @param bossIndex Boss to use * @param overridePos Override the spawn position of the effects * @param overrideAng Override the spawn angles of the effects * @param output The ArrayList that will contain all of the outputted entities as entity references * @param entityOverride If not INVALID_ENT_REFERENCE will attach all particles to the desired entity */ -native void SF2_SpawnBossEffects(ArrayList effects, int bossIndex, float overridePos[3] = NULL_VECTOR, float overrideAng[3] = NULL_VECTOR, ArrayList &output = null, int entityOverride = INVALID_ENT_REFERENCE); +native void SF2_SpawnBossEffects(SF2_ProfileEffectMaster effects, int bossIndex, float overridePos[3] = NULL_VECTOR, float overrideAng[3] = NULL_VECTOR, ArrayList &output = null, int entityOverride = INVALID_ENT_REFERENCE); /** * Returns if a boss can be seen by any player @@ -1710,7 +1693,7 @@ native bool SF2_CanBossBeSeen(int bossIndex, bool checkFOV = true, bool checkBli /** * Translates an activity name string into an Activity. * - * @param sActivity + * @param activity * @return Activity, or ACT_INVALID if not found. */ native Activity SF2_TranslateProfileActivityFromName(const char[] activity); @@ -1718,59 +1701,59 @@ native Activity SF2_TranslateProfileActivityFromName(const char[] activity); /** * Given an activity or sequence, translates into a sequence index. * - * @param iEntity Entity index - * @param sAnimation Activity/sequence string + * @param entity Entity index + * @param animation Activity/sequence string * @return Sequence index, or -1 if not found. */ native int SF2_LookupProfileAnimation(int entity, const char[] animation); /** - * Returns the profile data found on a boss index, note this is the basic profile data, I.E. what all bosses use + * Returns the profile data found on a boss index * * @param bossIndex Boss index. - * @param data Data to be stored in. Note this takes in SF2BossProfileData + * @return Stored profile data, or null if it doesn't exist */ -native void SF2_GetProfileFromBossIndex(int bossIndex, any data[sizeof(SF2BossProfileData)]); +native SF2_BaseBossProfile SF2_GetProfileFromBossIndex(int bossIndex); /** * Returns the chaser profile data found on a boss index. * * @param bossIndex Boss index. - * @param data Data to be stored in. Note this takes in SF2ChaserBossProfileData + * @return Stored profile data, or null if it doesn't exist */ -native void SF2_GetChaserProfileFromBossIndex(int bossIndex, any data[sizeof(SF2ChaserBossProfileData)]); +native SF2_ChaserBossProfile SF2_GetChaserProfileFromBossIndex(int bossIndex); /** * Returns the statue profile data found on a boss index. * * @param bossIndex Boss index. - * @param data Data to be stored in. Note this takes in SF2StatueBossProfileData + * @return Stored profile data, or null if it doesn't exist */ -native void SF2_GetStatueProfileFromBossIndex(int bossIndex, any data[sizeof(SF2StatueBossProfileData)]); +native SF2_StatueBossProfile SF2_GetStatueProfileFromBossIndex(int bossIndex); /** - * Returns the profile data found from a profile name, note this is the basic profile data, I.E. what all bosses use + * Returns the profile data found from a profile name * * @param profile Profile name. - * @param data Data to be stored in. Note this takes in SF2BossProfileData + * @return Stored profile data, or null if it doesn't exist */ -native bool SF2_GetProfileFromName(const char[] profile, any data[sizeof(SF2BossProfileData)]); +native SF2_BaseBossProfile SF2_GetProfileFromName(const char[] profile); /** * Returns the chaser profile data found from a profile name. * * @param profile Profile name. - * @param data Data to be stored in. Note this takes in SF2ChaserBossProfileData + * @return Stored profile data, or null if it doesn't exist */ -native bool SF2_GetChaserProfileFromName(const char[] profile, any data[sizeof(SF2ChaserBossProfileData)]); +native SF2_ChaserBossProfile SF2_GetChaserProfileFromName(const char[] profile); /** * Returns the statue profile data found from a profile name. * * @param profile Profile name. - * @param data Data to be stored in. Note this takes in SF2StatueBossProfileData + * @return Stored profile data, or null if it doesn't exist */ -native bool SF2_GetStatueProfileFromName(const char[] profile, any data[sizeof(SF2ChaserBossProfileData)]); +native SF2_StatueBossProfile SF2_GetStatueProfileFromName(const char[] profile); /** * Forces a boss to enter in the chase state and immediately go after the target. @@ -1870,6 +1853,15 @@ methodmap SF2_BaseBossEntity < CBaseCombatCharacter */ public native void GetName(char[] buffer, int bufferLen); + /** + * Prevents any animation from being played + */ + property bool LockAnimations + { + public native get(); + public native set(bool value); + } + /** * Attempts to cast an entity to be this entity. * @@ -1883,9 +1875,9 @@ methodmap SF2_BaseBossEntity < CBaseCombatCharacter /** * Gets the boss's profile data. * - * @param data Data to be stored in. Note this takes in SF2BossProfileData + * @return Stored profile data, or null if it doesn't exist */ - public native void ProfileData(any data[sizeof(SF2BossProfileData)]); + public native SF2_BaseBossProfile ProfileData(); /** * Plays an animation on the boss from a specific animation section, even custom ones. Note this is limited to the main "animations" section. @@ -1930,9 +1922,9 @@ methodmap SF2_StatueBossEntity < SF2_BaseBossEntity /** * Gets the boss's profile data. * - * @param data Data to be stored in. Note this takes in SF2StatueBossProfileData + * @return Stored profile data, or null if it doesn't exist */ - public native void ProfileData(any data[sizeof(SF2StatueBossProfileData)]); + public native SF2_StatueBossProfile ProfileData(); /** * Attempts to cast an entity to be this entity. @@ -2052,9 +2044,9 @@ methodmap SF2_ChaserBossEntity < SF2_BaseBossEntity /** * Gets the boss's profile data. * - * @param data Data to be stored in. Note this takes in SF2ChaserBossProfileData + * @return Stored profile data, or null if it doesn't exist */ - public native void ProfileData(any data[sizeof(SF2ChaserBossProfileData)]); + public native SF2_ChaserBossProfile ProfileData(); /** * Forces the boss to perform a voice. Note custom sound sections will not work. @@ -2063,15 +2055,15 @@ methodmap SF2_ChaserBossEntity < SF2_BaseBossEntity * @param attackName Optional attack name to search for. * @return Whether or not the boss performed a voice. */ - public native bool PerformVoice(int soundType = -1, const char[] attackName = "") + public native bool PerformVoice(int soundType = -1, const char[] attackName = ""); /** * Forces the boss to perform a voice using a custom sound section. * - * @param soundInfo Sound section to use. + * @param soundInfo Sound data to use. * @return Whether or not the boss performed a voice. */ - public native bool PerformCustomVoice(any soundInfo[sizeof(SF2BossProfileSoundInfo)]) + public native bool PerformCustomVoice(SF2_ProfileSound soundInfo); /** * Gets the default posture of the boss. The default posture of a boss @@ -2086,10 +2078,11 @@ methodmap SF2_ChaserBossEntity < SF2_BaseBossEntity /** * Sets the default posture of the boss. * - * @param buffer Posture to set to - * @return True if successful, false otherwise + * @param buffer Posture to set to + * @param updateAnimations Optional bool to determine if the animations should update upon setting the posture. + * @return True if successful, false otherwise */ - public native void SetDefaultPosture(const char[] buffer); + public native bool SetDefaultPosture(const char[] buffer, bool updateAnimations = true); /** * Gets the current attack name of the boss. @@ -2148,6 +2141,25 @@ methodmap SF2_ChaserBossEntity < SF2_BaseBossEntity public native set(bool value); } + /** + * Sets/returns the boss's current movement type + */ + property SF2NPCMoveTypes MovementType + { + public native get(); + public native set(SF2NPCMoveTypes value); + } + + /** + * Prevents the plugin from setting the MovementType + * Note that any attempts to set MovementType via a sub plugin will work as normal + */ + property bool LockMovementType + { + public native get(); + public native set(bool value); + } + /** * Checks if an attack is possible the default way * This only includes FOV and range checks @@ -2156,12 +2168,12 @@ methodmap SF2_ChaserBossEntity < SF2_BaseBossEntity * And visibility checks are already handled in SF2_ChaserAttackLayerAction * You would use this primarily in SF2_OnIsBossCustomAttackPossible * - * @param attackName Name of the attack + * @param attack Attack data to use * @param includeDifficulties Whether or not to include the difficulty checks * @param includeHealth Whether or not to include target health checks * @return Whether or not the attack is possible with the distance and FOV checks */ - public bool IsAttackPossibleDefault(const char[] attackName, bool includeDifficulties = false, bool includeHealth = false) + public bool IsAttackPossibleDefault(SF2_ChaserBossProfileBaseAttack attackData, bool includeDifficulties = false, bool includeHealth = false) { if (!this.Target.IsValid()) { @@ -2172,10 +2184,6 @@ methodmap SF2_ChaserBossEntity < SF2_BaseBossEntity int difficulty = SF2_GetBossDifficulty(controller); INextBot bot = this.MyNextBotPointer(); - SF2ChaserBossProfileData data; - this.ProfileData(data); - SF2ChaserBossProfileAttackData attackData; - data.GetAttack(attackName, attackData); float eyePos[3], targetPos[3], direction[3], eyeAng[3]; this.GetAbsAngles(eyeAng); SF2_GetBossEyePosition(controller, eyePos); @@ -2187,12 +2195,12 @@ methodmap SF2_ChaserBossEntity < SF2_BaseBossEntity float distance = bot.GetRangeSquaredTo(this.Target.index); float fov = FloatAbs(AngleDiff(direction[1], eyeAng[1])); - if (distance > Pow(attackData.BeginRange[difficulty], 2.0)) + if (distance > Pow(attackData.GetBeginRange(difficulty), 2.0)) { return false; } - if (fov > attackData.BeginFOV[difficulty]) + if (fov > attackData.GetBeginFOV(difficulty)) { return false; } @@ -2213,11 +2221,12 @@ methodmap SF2_ChaserBossEntity < SF2_BaseBossEntity if (includeHealth) { float health = float(this.Target.GetProp(Prop_Send, "m_iHealth")); - if (attackData.UseOnHealth != -1.0 && health < attackData.UseOnHealth) + if (attackData.CanUseOnHealth(difficulty) != -1.0 && health < attackData.CanUseOnHealth(difficulty)) { return false; } - if (attackData.BlockOnHealth != -1.0 && health >= attackData.BlockOnHealth) + + if (attackData.CanBlockOnHealth(difficulty) != -1.0 && health >= attackData.CanBlockOnHealth(difficulty)) { return false; } @@ -2226,6 +2235,837 @@ methodmap SF2_ChaserBossEntity < SF2_BaseBossEntity } } +/** + * An object that contains data from a profile. + */ +methodmap SF2_ProfileObject < Handle +{ + /** + * Retrieve the parent section of this object. + */ + property SF2_ProfileObject Parent + { + public native get(); + } + + /** + * Retrieve the number of keys (not sections) that exist in this section. + */ + property int KeyLength + { + public native get(); + } + + /** + * Retrieve the number of sections (not keys) that exist in this section. + */ + property int SectionLength + { + public native get(); + } + + /** + * Retrieves an integer value from the given key. + * + * @param key Key name + * @param defaultValue Value to return as a fallback + * @return Value stored at key + */ + public native int GetInt(const char[] key, int defaultValue = 0); + + /** + * Sets an integer value with the given key. + * + * @param key Key name + * @param value Value to set + */ + public native void SetInt(const char[] key, int value); + + /** + * Retrieves a boolean value from the given key. + * + * @param key Key name + * @param defaultValue Value to return as a fallback + * @return Value stored at key + */ + public native bool GetBool(const char[] key, bool defaultValue = false); + + /** + * Sets an boolean value with the given key. + * + * @param key Key name + * @param value Value to set + */ + public native void SetBool(const char[] key, bool value); + + /** + * Retrieves a float value from the given key. + * + * @param key Key name + * @param defaultValue Value to return as a fallback + * @return Value stored at key + */ + public native float GetFloat(const char[] key, float defaultValue = 0.0); + + /** + * Sets an bool value with the given key. + * + * @param key Key name + * @param value Value to set + */ + public native void SetFloat(const char[] key, float value); + + /** + * Retrieves a section from the given key. + * + * @param key Key name + * @param defaultValue Value to return as a fallback + * @return Value stored at key + */ + public native SF2_ProfileObject GetSection(const char[] key, SF2_ProfileObject defaultValue = view_as(INVALID_HANDLE)); + + /** + * Retrieves an array from the given key. + * + * @param key Key name + * @param defaultValue Value to return as a fallback + * @return Value stored at key + */ + public native SF2_ProfileArray GetArray(const char[] key, SF2_ProfileArray defaultValue = view_as(INVALID_HANDLE)); + + /** + * Retrieves a string value from the given key. + * + * @param key Key name + * @param buffer String buffer + * @param bufferSize Size of string buffer + * @param defaultValue Value to return as a fallback + * @return Number of chars copied to buffer, excluding null terminator + */ + public native void GetString(const char[] key, char[] buffer, int bufferSize, const char[] defaultValue = ""); + + /** + * Sets an string value with the given key. + * + * @param key Key name + * @param value Value to set + */ + public native void SetString(const char[] key, const char[] value); + + /** + * Retrieves a Vector value from the given key. + * + * @param key Key name + * @param buffer Vector buffer + * @param defaultValue Value to return as a fallback + */ + public native void GetVector(const char[] key, float buffer[3], const float defaultValue[3] = { 0.0, 0.0, 0.0 }); + + /** + * Sets an Vector value with the given key. + * + * @param key Key name + * @param value Value to set + */ + public native void SetVector(const char[] key, float value[3]); + + /** + * Retrieves a Color value from the given key. + * + * @param key Key name + * @param buffer Color buffer + * @param defaultValue Value to return as a fallback + */ + public native void GetColor(const char[] key, int buffer[4], const int defaultValue[4] = { 0, 0, 0, 0 }); + + /** + * Sets an Color value with the given key. + * + * @param key Key name + * @param value Value to set + */ + public native void SetColor(const char[] key, int value[4]); + + /** + * Retrieves an integer value from the given difficulty key. + * + * @param key Key name + * @param difficulty Difficulty value + * @param defaultValue Value to return as a fallback + * @return Value stored at key + */ + public native int GetDifficultyInt(const char[] key, int difficulty, int defaultValue = 0); + + /** + * Sets an integer value with the given difficulty key. + * + * @param key Key name + * @param difficulty Difficulty value + * @param value Value to set + */ + public native void SetDifficultyInt(const char[] key, int difficulty, int value); + + /** + * Retrieves a boolean value from the given difficulty key. + * + * @param key Key name + * @param difficulty Difficulty value + * @param defaultValue Value to return as a fallback + * @return Value stored at key + */ + public native bool GetDifficultyBool(const char[] key, int difficulty, bool defaultValue = false); + + /** + * Sets an boolean value with the given difficulty key. + * + * @param key Key name + * @param difficulty Difficulty value + * @param value Value to set + */ + public native void SetDifficultyBool(const char[] key, int difficulty, bool value); + + /** + * Retrieves a float value from the given difficulty key. + * + * @param key Key name + * @param difficulty Difficulty value + * @param defaultValue Value to return as a fallback + * @return Value stored at key + */ + public native float GetDifficultyFloat(const char[] key, int difficulty, float defaultValue = 0.0); + + /** + * Sets an float value with the given difficulty key. + * + * @param key Key name + * @param difficulty Difficulty value + * @param value Value to set + */ + public native void SetDifficultyFloat(const char[] key, int difficulty, int value); + + /** + * Retrieves a section from the given difficulty key. + * + * @param key Key name + * @param difficulty Difficulty value + * @param defaultValue Value to return as a fallback + * @return Value stored at key + */ + public native SF2_ProfileObject GetDifficultySection(const char[] key, int difficulty, SF2_ProfileObject defaultValue = view_as(INVALID_HANDLE)); + + /** + * Retrieves a string value from the given difficulty key. + * + * @param key Key name + * @param difficulty Difficulty value + * @param buffer String buffer + * @param bufferSize Size of string buffer + * @param defaultValue Value to return as a fallback + */ + public native void GetDifficultyString(const char[] key, int difficulty, char[] buffer, int bufferSize, const char[] defaultValue = ""); + + /** + * Sets an string value with the given difficulty key. + * + * @param key Key name + * @param difficulty Difficulty value + * @param value Value to set + */ + public native void SetDifficultyString(const char[] key, int difficulty, const char[] value); + + /** + * Retrieves a Vector value from the given difficulty key. + * + * @param key Key name + * @param difficulty Difficulty value + * @param buffer Float buffer + * @param defaultValue Value to return as a fallback + * @return Value stored at key + */ + public native void GetDifficultyVector(const char[] key, int difficulty, float buffer[3], const float defaultValue[3] = { 0.0, 0.0, 0.0 }); + + /** + * Sets an Vector value with the given difficulty key. + * + * @param key Key name + * @param difficulty Difficulty value + * @param value Value to set + */ + public native void SetDifficultyVector(const char[] key, int difficulty, float value[3]); + + /** + * Retrieves a Color value from the given difficulty key. + * + * @param key Key name + * @param difficulty Difficulty value + * @param buffer Float buffer + * @param defaultValue Value to return as a fallback + * @return Value stored at key + */ + public native void GetDifficultyColor(const char[] key, int difficulty, int buffer[4], const int defaultValue[4] = { 0, 0, 0, 0 }); + + /** + * Sets an Color value with the given difficulty key. + * + * @param key Key name + * @param difficulty Difficulty value + * @param value Value to set + */ + public native void SetDifficultyColor(const char[] key, int difficulty, int value[4]); + + /** + * Helper function that converts a string index map to a string array. + * + * @param key Key name + */ + public native void ConvertValuesSectionToArray(const char[] key); + + /** + * Helper function that converts an object index map to a string array. + * + * @param key Key name + */ + public native void ConvertSectionsSectionToArray(const char[] key); +} + +methodmap SF2_ProfileArray < Handle +{ + /** + * Retrieve the size of the array. + */ + property int Length + { + public native get(); + } + + /** + * Retrieves an integer value from the given key. + * + * @param index Index number + * @param defaultValue Value to return as a fallback + * @return Value stored at key + */ + public native int GetInt(int index, int defaultValue = 0); + + /** + * Retrieves a boolean value from the given key. + * + * @param index Index number + * @param defaultValue Value to return as a fallback + * @return Value stored at key + */ + public native bool GetBool(int index, bool defaultValue = false); + + /** + * Retrieves a float value from the given key. + * + * @param index Index number + * @param defaultValue Value to return as a fallback + * @return Value stored at key + */ + public native float GetFloat(int index, float defaultValue = 0.0); + + /** + * Retrieves a section from the given key. + * + * @param index Index number + * @param defaultValue Value to return as a fallback + * @return Value stored at key + */ + public native SF2_ProfileObject GetSection(int index, SF2_ProfileObject defaultValue = view_as(INVALID_HANDLE)); + + /** + * Retrieves a string value from the given key. + * + * @param index Index number + * @param buffer String buffer + * @param bufferSize Size of string buffer + * @param defaultValue Value to return as a fallback + */ + public native void GetString(int index, char[] buffer, int bufferSize, const char[] defaultValue = ""); +} + +/** + * Profile object that stores sound data of an animation. + */ +methodmap SF2_ProfileSound < SF2_ProfileObject +{ + /** + * Returns the sound paths this object uses. + */ + property SF2_ProfileArray Paths + { + public native get(); + } + + /** + * Sets the default channel value of this sound object. + * + * @param channel Sound channel + */ + public native void SetDefaultChannel(int channel); + + /** + * Sets the default level value of this sound object. + * + * @param level Sound level + */ + public native void SetDefaultLevel(int level); + + /** + * Sets the default flags value of this sound object. + * + * @param flags Sound flags + */ + public native void SetDefaultFlags(int flags); + + /** + * Sets the default minimum cooldown value of this sound object. + * + * @param cooldown Sound cooldown + */ + public native void SetDefaultCooldownMin(float cooldown); + + /** + * Sets the default maximum cooldown value of this sound object. + * + * @param cooldown Sound cooldown + */ + public native void SetDefaultCooldownMax(float cooldown); + + /** + * Gets the channel. + * + * @param difficulty Difficulty value + * @return Sound channel + */ + public native int GetChannel(int difficulty); + + /** + * Gets the volume. + * + * @param difficulty Difficulty value + * @return Sound volume + */ + public native float GetVolume(int difficulty); + + /** + * Gets the flags. + * + * @param difficulty Difficulty value + * @return Sound flags + */ + public native int GetFlags(int difficulty); + + /** + * Gets the level. + * + * @param difficulty Difficulty value + * @return Sound level + */ + public native int GetLevel(int difficulty); + + /** + * Gets the pitch. + * + * @param difficulty Difficulty value + * @return Sound pitch + */ + public native int GetPitch(int difficulty); + + /** + * Gets the minimum cooldown. + * + * @param difficulty Difficulty value + * @return Sound min cooldown + */ + public native float GetCooldownMin(int difficulty); + + /** + * Gets the maximum cooldown. + * + * @param difficulty Difficulty value + * @return Sound max cooldown + */ + public native float GetCooldownMax(int difficulty); + + /** + * Precaches all sounds and adds to downloads. + */ + public native void Precache(); + + /** + * Helper function that calls EmitSoundToAll with the parameters given by this + * object. + * + * @param entIndex Entity index to emit sound from + * @param difficulty Difficulty value + */ + public native void EmitToAll(int entIndex = SOUND_FROM_PLAYER, int difficulty = Difficulty_Normal); + + /** + * Helper function that calls EmitSoundToClient with the parameters given by this + * object. + * + * @param client Client index + * @param entIndex Entity index to emit sound from + * @param difficulty Difficulty value + */ + public native void EmitToClient(int client, int entIndex = SOUND_FROM_PLAYER, int difficulty = Difficulty_Normal); + + /** + * Stops all sounds in this section from playing. + * + * @param entity Entity index to stop the sounds from + */ + public native void StopAllSounds(int entity); +} + +/** + * Profile object that stores data of an animation. + * Note this covers 1 animation index, not the whole animations section or an animation named section like "idle". + * Use this over SF2_ProfileMasterAnimation if you're for sure you're gonna only use 1 animation only. + */ +methodmap SF2_ProfileAnimation < SF2_ProfileObject +{ + /** + * Retrieves a sequence or activity name. + * + * @param difficulty Difficulty value + * @param buffer String buffer to store the animation name + * @param bufferSize Size of buffer + */ + public native void GetAnimationName(int difficulty, char[] buffer, int bufferSize); + + /** + * Retrieves a gesture sequence or activity name. + * + * @param difficulty Difficulty value + * @param buffer String buffer to store the gesture name + * @param bufferSize Size of buffer + */ + public native void GetGestureName(int difficulty, char[] buffer, int bufferSize); + + /** + * Gets the playback rate of the animation. + * + * @param difficulty Difficulty value + * @return Playback rate + */ + public native float GetAnimationPlaybackRate(int difficulty); + + /** + * Gets the playback rate of the gesture. + * + * @param difficulty Difficulty value + * @return Playback rate + */ + public native float GetGesturePlaybackRate(int difficulty); + + /** + * Gets the duration of the animation. + * + * @param difficulty Difficulty value + * @return Duration + */ + public native float GetDuration(int difficulty); + + /** + * Gets the starting cycle value of the animation. + * + * @param difficulty Difficulty value + * @return Cycle + */ + public native float GetAnimationCycle(int difficulty); + + /** + * Gets the starting cycle value of the gesture. + * + * @param difficulty Difficulty value + * @return Cycle + */ + public native float GetGestureCycle(int difficulty); + + /** + * Plays an animation on the entity using the parameters provided by the object. + * + * @param entIndex Entity index to play on + * @param difficulty Difficulty value + * @param loops Whether the animation should loop or not + * @return True if successful, false otherwise. + */ + public native bool PlayAnimation(int entIndex, int difficulty, bool loops = false); + + /** + * Plays an gesture/layered animation on the entity using the parameters provided by the object. + * + * @note Layered animations can only be used on entities derived from CBaseAnimatingOverlay. + * @param entIndex Entity index to play on + * @param difficulty Difficulty value + * @param loops Whether the animation should loop or not + * @param layer Value to store the layer ID of the animation. + * @return True if successful, false otherwise. + */ + public native bool PlayGesture(int entIndex, int difficulty, bool loops = false, int& layer = -1); +} + +/** + * Profile object that stores all animation sections + * Note this covers the "animations" section. + */ +methodmap SF2_ProfileMasterAnimation < SF2_ProfileObject +{ + /** + * Returns if an animation section exists + * + * @param animType Animation section to search for + */ + public native bool HasAnimationSection(const char[] animType); + + /** + * Returns an animation index section based off of the given animation section name + * + * @param animType Animation section to search for + * @param preDefinedIndex If greater than -1 will pick a specified animation in the animation section based off the order in the config + * @param preDefinedName If not an empty string will pick a specified animation in the animation section based off the animation section name + * @param index Value to store the animation index in. + * @return Animation indexed section or null if the section does not exist + */ + public native SF2_ProfileAnimation GetAnimation(const char[] animType, int preDefinedIndex = -1, const char[] preDefinedName = "", int& index = -1); +} + +/** + * A section that defines the properties of an entity or other special effect. + */ +methodmap SF2_ProfileEffect < SF2_ProfileObject +{ + /** + * The effect type. + */ + property EffectType Type + { + public native get(); + } + + /** + * Precaches all assets and adds them to the downloads. + */ + public native void Precache(); +} + +/** + * A section that contains `SF2_ProfileEffect` objects meant to be spawned + * together. + */ +methodmap SF2_ProfileEffectMaster < SF2_ProfileObject +{ + /** + * Precaches all assets and adds them to the downloads. + */ + public native void Precache(); + + /** + * Spawns boss effects based on the list of effects used. + * Note this will not spawn the extra effects like the festive lights and the disco ball + * Only use this best for spawning in temporary effects. + * + * @param bossIndex Boss to use + * @param overridePos Override the spawn position of the effects + * @param overrideAng Override the spawn angles of the effects + * @param output The ArrayList that will contain all of the outputted entities as entity references + * @param entityOverride If not INVALID_ENT_REFERENCE will attach all particles to the desired entity + */ + public native void Spawn(int bossIndex, float overridePos[3] = NULL_VECTOR, float overrideAng[3] = NULL_VECTOR, ArrayList &output = null, int entityOverride = INVALID_ENT_REFERENCE); +} + +methodmap SF2_BaseBossProfile < SF2_ProfileObject +{ + /** + * The boss type. + */ + property int Type + { + public native get(); + } + + /** + * Determines if the boss is for the PvE arenas. + */ + property bool IsPvEBoss + { + public native get(); + } +} + +methodmap SF2_StatueBossProfile < SF2_BaseBossProfile +{ + +} + +methodmap SF2_ChaserBossProfile < SF2_BaseBossProfile +{ + /** + * Gets the amount of attacks stored in the Chaser boss profile. + * + * @return Amount of attacks + * @error Profile data is null or is not a Chaser boss profile + */ + public native int GetAttackCount(); + + /** + * Gets a Chaser boss profile's attack data with the given name. + * + * @param name Attack name + * @return The attack data, or null if it doesn't exist + * @error Profile data is null or is not a Chaser boss profile + */ + public native SF2_ChaserBossProfileBaseAttack GetAttack(const char[] name); + + /** + * Gets a Chaser boss profile's attack data with the given index. + * + * @param index Attack index + * @return The attack data, or null if it doesn't exist + * @error Profile data is null or is not a Chaser boss profile + */ + public native SF2_ChaserBossProfileBaseAttack GetAttackFromIndex(int index); +} + +methodmap SF2_ChaserBossProfileBaseAttack < SF2_ProfileObject +{ + /** + * The type of the attack. + */ + property int Type + { + public native get(); + } + + /** + * How long to wait after starting the attack to damage targets. + * + * @param difficulty Difficulty value + * @return Time to delay + */ + public native float GetDamageDelay(int difficulty); + + /** + * The range of the attack, in Hammer units. + * + * @param difficulty Difficulty value + * @return Range of attack + */ + public native float GetRange(int difficulty); + + /** + * How much damage to inflict to players. + * + * @param difficulty Difficulty value + * @return Damage of attack + */ + public native float GetDamage(int difficulty); + + /** + * The bitflag type value of the damage. + * + * @param difficulty Difficulty value + * @return Bitflags + */ + public native int GetDamageType(int difficulty); + + /** + * How much damage force to inflict to players. + * + * @param difficulty Difficulty value + * @return Damage force of attack + */ + public native float GetDamageForce(int difficulty); + + /** + * How much viewpunch to inflict on players that get hit by the attack. + * + * @param difficulty Difficulty value + * @param viewPunch Vector buffer to store punch angles + */ + public native void GetViewPunchAngles(int difficulty, float viewPunch[3]); + + /** + * How long the attack should last. + * + * @param difficulty Difficulty value + * @return Time + */ + public native float GetDuration(int difficulty); + + /** + * How wide the attack is, in degrees. + * + * @param difficulty Difficulty value + * @return FOV of attack + */ + public native float GetFOV(int difficulty); + + /** + * The maximum distance where the boss should use the attack. + * + * @param difficulty Difficulty value + * @return Range of atack + */ + public native float GetBeginRange(int difficulty); + + /** + * How much the player must be within this FOV should the boss use the attack. + * + * @param difficulty Difficulty value + * @return FOV of attack + */ + public native float GetBeginFOV(int difficulty); + + /** + * How long to wait until the boss can use this attack again. + * + * @param difficulty Difficulty value + * @return Cooldown of attack + */ + public native float GetCooldown(int difficulty); + + property int UseOnDifficulty + { + public native get(); + } + + property int BlockOnDifficulty + { + public native get(); + } + + public native float CanUseOnHealth(int difficulty); + + public native float CanBlockOnHealth(int difficulty); +} + +/** + * The data of an attack with type `SF2BossAttackType_Custom`. + */ +methodmap SF2_ChaserBossProfileCustomAttack < SF2_ChaserBossProfileBaseAttack +{ + /** + * An identifier string of the custom attack. + * + * @param buffer Buffer to store the string + * @param bufferSize Size of buffer + */ + public native void GetSubType(char[] buffer, int bufferSize); + + /** + * Gets if the attack matches the given subtype string. + * + * @param subType String to check + * @return True if attack's subtype matches, false if not. + */ + public native bool IsSubType(const char[] subType); +} + /** * An action that plays a given sequence on the actor. This action exits when the * duration has elapsed. @@ -2375,6 +3215,7 @@ methodmap SF2_Player < CBaseCombatCharacter */ public native int GetDataEnt(int offset); + #if defined _tf2_included /** * Alias of TF2_GetPlayerClass() */ @@ -2382,6 +3223,7 @@ methodmap SF2_Player < CBaseCombatCharacter { public native get(); } + #endif /** * Alias of GetClientTeam() @@ -2401,6 +3243,7 @@ methodmap SF2_Player < CBaseCombatCharacter public native set(bool state); } + #if defined _tf2_included /** * Alias of TF2_IsPlayerInCondition() * Use this over TF2_IsPlayerInCondition() though as it has extra optimizations @@ -2418,6 +3261,7 @@ methodmap SF2_Player < CBaseCombatCharacter * @param inflictor Inflictor of the condition */ public native bool ChangeCondition(TFCond condition, bool remove = false, float duration = -1.0, int inflictor = 0); + #endif /** * Whether or not the client is crit boosted @@ -2462,6 +3306,7 @@ methodmap SF2_Player < CBaseCombatCharacter */ public native void Regenerate(); + #if defined _tf2_included /** * Alias of TF2_SetPlayerClass() * @@ -2470,6 +3315,7 @@ methodmap SF2_Player < CBaseCombatCharacter * @param persistent Whether or not the class change should remain after death */ public native void SetClass(TFClassType classType, bool weapons = true, bool persistent = true); + #endif /** * Alias of GetClientEyePosition() @@ -2919,13 +3765,6 @@ methodmap SF2_Player < CBaseCombatCharacter public native set(int value); } - /** - * Updates the player's music state - * - * @param initialize Unknown????? Nobody knows what this actually does. - */ - public native void UpdateMusicSystem(bool initialize = false); - /** * Whether or not the player has a glow active */ @@ -3657,7 +4496,6 @@ public void __pl_sf2_SetNTVOptional() MarkNativeAsOptional("SF2_Player.LatchCount.set"); MarkNativeAsOptional("SF2_Player.Latcher.get"); MarkNativeAsOptional("SF2_Player.Latcher.set"); - MarkNativeAsOptional("SF2_Player.UpdateMusicSystem"); MarkNativeAsOptional("SF2_Player.HasConstantGlow.get"); MarkNativeAsOptional("SF2_Player.SetPlayState"); MarkNativeAsOptional("SF2_Player.CanSeeSlender"); @@ -3730,9 +4568,6 @@ public void __pl_sf2_SetNTVOptional() MarkNativeAsOptional("SF2_GetBossAttributeName"); MarkNativeAsOptional("SF2_GetBossAttributeValue"); - MarkNativeAsOptional("SF2_GetBossProfileData"); - MarkNativeAsOptional("SF2_GetChaserBossProfileData"); - MarkNativeAsOptional("SF2_GetStatueBossProfileData"); MarkNativeAsOptional("SF2_TranslateProfileActivityFromName"); MarkNativeAsOptional("SF2_LookupProfileAnimation"); @@ -3906,6 +4741,8 @@ public void __pl_sf2_SetNTVOptional() MarkNativeAsOptional("SF2_BaseBossEntity.EyePosition"); MarkNativeAsOptional("SF2_BaseBossEntity.GetProfileName"); MarkNativeAsOptional("SF2_BaseBossEntity.GetName"); + MarkNativeAsOptional("SF2_BaseBossEntity.LockAnimations.get"); + MarkNativeAsOptional("SF2_BaseBossEntity.LockAnimations.set"); MarkNativeAsOptional("SF2_BaseBossEntity.ProfileData"); MarkNativeAsOptional("SF2_BaseBossEntity.ResetProfileAnimation"); @@ -3937,11 +4774,119 @@ public void __pl_sf2_SetNTVOptional() MarkNativeAsOptional("SF2_ChaserBossEntity.CreateSoundHint"); MarkNativeAsOptional("SF2_ChaserBossEntity.GroundSpeedOverride.get"); MarkNativeAsOptional("SF2_ChaserBossEntity.GroundSpeedOverride.set"); + MarkNativeAsOptional("SF2_ChaserBossEntity.MovementType.get"); + MarkNativeAsOptional("SF2_ChaserBossEntity.MovementType.set"); + MarkNativeAsOptional("SF2_ChaserBossEntity.LockMovementType.get"); + MarkNativeAsOptional("SF2_ChaserBossEntity.LockMovementType.set"); // npc/entities/statue/entity.sp MarkNativeAsOptional("SF2_StatueBossEntity.IsValid.get"); MarkNativeAsOptional("SF2_StatueBossEntity.IsMoving.get"); MarkNativeAsOptional("SF2_StatueBossEntity.LastKillTime.get"); MarkNativeAsOptional("SF2_StatueBossEntity.ProfileData"); + + MarkNativeAsOptional("SF2_ProfileObject.Parent.get"); + MarkNativeAsOptional("SF2_ProfileObject.KeyLength.get"); + MarkNativeAsOptional("SF2_ProfileObject.SectionLength.get"); + MarkNativeAsOptional("SF2_ProfileObject.GetInt"); + MarkNativeAsOptional("SF2_ProfileObject.SetInt"); + MarkNativeAsOptional("SF2_ProfileObject.GetBool"); + MarkNativeAsOptional("SF2_ProfileObject.SetBool"); + MarkNativeAsOptional("SF2_ProfileObject.GetFloat"); + MarkNativeAsOptional("SF2_ProfileObject.SetFloat"); + MarkNativeAsOptional("SF2_ProfileObject.GetSection"); + MarkNativeAsOptional("SF2_ProfileObject.GetArray"); + MarkNativeAsOptional("SF2_ProfileObject.GetString"); + MarkNativeAsOptional("SF2_ProfileObject.SetString"); + MarkNativeAsOptional("SF2_ProfileObject.GetVector"); + MarkNativeAsOptional("SF2_ProfileObject.SetVector"); + MarkNativeAsOptional("SF2_ProfileObject.GetColor"); + MarkNativeAsOptional("SF2_ProfileObject.SetColor"); + MarkNativeAsOptional("SF2_ProfileObject.GetDifficultyInt"); + MarkNativeAsOptional("SF2_ProfileObject.SetDifficultyInt"); + MarkNativeAsOptional("SF2_ProfileObject.GetDifficultyBool"); + MarkNativeAsOptional("SF2_ProfileObject.SetDifficultyBool"); + MarkNativeAsOptional("SF2_ProfileObject.GetDifficultyFloat"); + MarkNativeAsOptional("SF2_ProfileObject.SetDifficultyFloat"); + MarkNativeAsOptional("SF2_ProfileObject.GetDifficultySection"); + MarkNativeAsOptional("SF2_ProfileObject.GetDifficultyString"); + MarkNativeAsOptional("SF2_ProfileObject.SetDifficultyString"); + MarkNativeAsOptional("SF2_ProfileObject.GetDifficultyVector"); + MarkNativeAsOptional("SF2_ProfileObject.SetDifficultyVector"); + MarkNativeAsOptional("SF2_ProfileObject.GetDifficultyColor"); + MarkNativeAsOptional("SF2_ProfileObject.SetDifficultyColor"); + MarkNativeAsOptional("SF2_ProfileObject.ConvertValuesSectionToArray"); + MarkNativeAsOptional("SF2_ProfileObject.ConvertSectionsSectionToArray"); + + MarkNativeAsOptional("SF2_ProfileArray.Length.get"); + MarkNativeAsOptional("SF2_ProfileArray.GetInt"); + MarkNativeAsOptional("SF2_ProfileArray.GetBool"); + MarkNativeAsOptional("SF2_ProfileArray.GetFloat"); + MarkNativeAsOptional("SF2_ProfileArray.GetSection"); + MarkNativeAsOptional("SF2_ProfileArray.GetString"); + + MarkNativeAsOptional("SF2_ProfileSound.Paths.get"); + MarkNativeAsOptional("SF2_ProfileSound.SetDefaultChannel"); + MarkNativeAsOptional("SF2_ProfileSound.SetDefaultLevel"); + MarkNativeAsOptional("SF2_ProfileSound.SetDefaultFlags"); + MarkNativeAsOptional("SF2_ProfileSound.SetDefaultCooldownMin"); + MarkNativeAsOptional("SF2_ProfileSound.SetDefaultCooldownMax"); + MarkNativeAsOptional("SF2_ProfileSound.GetChannel"); + MarkNativeAsOptional("SF2_ProfileSound.GetVolume"); + MarkNativeAsOptional("SF2_ProfileSound.GetFlags"); + MarkNativeAsOptional("SF2_ProfileSound.GetLevel"); + MarkNativeAsOptional("SF2_ProfileSound.GetPitch"); + MarkNativeAsOptional("SF2_ProfileSound.GetCooldownMin"); + MarkNativeAsOptional("SF2_ProfileSound.GetCooldownMax"); + MarkNativeAsOptional("SF2_ProfileSound.Precache"); + MarkNativeAsOptional("SF2_ProfileSound.EmitToAll"); + MarkNativeAsOptional("SF2_ProfileSound.EmitToClient"); + MarkNativeAsOptional("SF2_ProfileSound.StopAllSounds"); + + MarkNativeAsOptional("SF2_ProfileAnimation.GetAnimationName"); + MarkNativeAsOptional("SF2_ProfileAnimation.GetGestureName"); + MarkNativeAsOptional("SF2_ProfileAnimation.GetAnimationPlaybackRate"); + MarkNativeAsOptional("SF2_ProfileAnimation.GetGesturePlaybackRate"); + MarkNativeAsOptional("SF2_ProfileAnimation.GetDuration"); + MarkNativeAsOptional("SF2_ProfileAnimation.GetAnimationCycle"); + MarkNativeAsOptional("SF2_ProfileAnimation.GetGestureCycle"); + MarkNativeAsOptional("SF2_ProfileAnimation.PlayAnimation"); + MarkNativeAsOptional("SF2_ProfileAnimation.PlayGesture"); + + MarkNativeAsOptional("SF2_ProfileMasterAnimation.HasAnimationSection"); + MarkNativeAsOptional("SF2_ProfileMasterAnimation.GetAnimation"); + + MarkNativeAsOptional("SF2_ProfileEffect.Type.get"); + MarkNativeAsOptional("SF2_ProfileEffect.Precache"); + + MarkNativeAsOptional("SF2_ProfileEffectMaster.Precache"); + MarkNativeAsOptional("SF2_ProfileEffectMaster.Spawn"); + + MarkNativeAsOptional("SF2_BaseBossProfile.Type.get"); + MarkNativeAsOptional("SF2_BaseBossProfile.IsPvEBoss.get"); + + MarkNativeAsOptional("SF2_ChaserBossProfile.GetAttackCount"); + MarkNativeAsOptional("SF2_ChaserBossProfile.GetAttack"); + MarkNativeAsOptional("SF2_ChaserBossProfile.GetAttackFromIndex"); + + MarkNativeAsOptional("SF2_ChaserBossProfileBaseAttack.Type.get"); + MarkNativeAsOptional("SF2_ChaserBossProfileBaseAttack.GetDamageDelay"); + MarkNativeAsOptional("SF2_ChaserBossProfileBaseAttack.GetRange"); + MarkNativeAsOptional("SF2_ChaserBossProfileBaseAttack.GetDamage"); + MarkNativeAsOptional("SF2_ChaserBossProfileBaseAttack.GetDamageType"); + MarkNativeAsOptional("SF2_ChaserBossProfileBaseAttack.GetDamageForce"); + MarkNativeAsOptional("SF2_ChaserBossProfileBaseAttack.GetViewPunchAngles"); + MarkNativeAsOptional("SF2_ChaserBossProfileBaseAttack.GetDuration"); + MarkNativeAsOptional("SF2_ChaserBossProfileBaseAttack.GetFOV"); + MarkNativeAsOptional("SF2_ChaserBossProfileBaseAttack.GetBeginRange"); + MarkNativeAsOptional("SF2_ChaserBossProfileBaseAttack.GetBeginFOV"); + MarkNativeAsOptional("SF2_ChaserBossProfileBaseAttack.GetCooldown"); + MarkNativeAsOptional("SF2_ChaserBossProfileBaseAttack.UseOnDifficulty.get"); + MarkNativeAsOptional("SF2_ChaserBossProfileBaseAttack.BlockOnDifficulty.get"); + MarkNativeAsOptional("SF2_ChaserBossProfileBaseAttack.CanUseOnHealth"); + MarkNativeAsOptional("SF2_ChaserBossProfileBaseAttack.CanBlockOnHealth"); + + MarkNativeAsOptional("SF2_ChaserBossProfileCustomAttack.GetSubType"); + MarkNativeAsOptional("SF2_ChaserBossProfileCustomAttack.IsSubType"); } #endif \ No newline at end of file diff --git a/addons/sourcemod/scripting/include/sf2/defines.inc b/addons/sourcemod/scripting/include/sf2/defines.inc index 801baafa..f0d011f0 100644 --- a/addons/sourcemod/scripting/include/sf2/defines.inc +++ b/addons/sourcemod/scripting/include/sf2/defines.inc @@ -17,6 +17,7 @@ #define FIREWORKSRED_PARTICLENAME "utaunt_firework_teamcolor_red" #define TELEPORTEDINBLU_PARTICLENAME "teleported_red" #define SOUND_THUNDER ")ambient/explosions/explode_9.wav" +#define DEBUG_PAGEREVEALSOUND "#ui/cyoa_node_activate.wav" #define SPECIAL1UPSOUND "mvm/mvm_revive.wav" diff --git a/addons/sourcemod/scripting/include/sf2/profiles/profiles.inc b/addons/sourcemod/scripting/include/sf2/profiles/profiles.inc index 7a09cc3a..8209c8ec 100644 --- a/addons/sourcemod/scripting/include/sf2/profiles/profiles.inc +++ b/addons/sourcemod/scripting/include/sf2/profiles/profiles.inc @@ -100,7 +100,7 @@ stock void TryPrecacheBossProfileSoundPath(const char[] soundPath, bool checkFil * @param xbox Determines if the .xbox file extension should be checked. * @param checkFile Determines if missing files should be checked. */ -stock int PrecacheModel2(const char[] path, bool phy = true, bool xbox = false, bool checkFile) +stock int PrecacheModel2(const char[] path, bool phy = true, bool xbox = false, bool checkFile = false) { if (path[0] == '\0') { @@ -117,6 +117,7 @@ stock int PrecacheModel2(const char[] path, bool phy = true, bool xbox = false, { strcopy(fixedPath, sizeof(fixedPath), path); } + ReplaceString(fixedPath, sizeof(fixedPath), "\\", "/", false); ReplaceString(fixedPath, sizeof(fixedPath), ".mdl", "", false); @@ -327,7 +328,7 @@ stock int PrecacheParticleSystem(const char[] particleSystem) return index; } -int FindStringIndex2(int tableidx, const char[] str) +stock int FindStringIndex2(int tableidx, const char[] str) { char buf[1024]; @@ -634,7 +635,7 @@ static const char g_DifficultyDefaultStringValues[Difficulty_Max][] = * @param maxStringLen Maximum length of strings in buffer array * @param defaultValueStrings Array of default values if no key with the base key name is found */ -void GetProfileDifficultyStringValues(KeyValues kv, const char[] baseKeyName, char[][] bufferArray, int maxStringLen, const char[][] defaultValueStrings = g_DifficultyDefaultStringValues) +stock void GetProfileDifficultyStringValues(KeyValues kv, const char[] baseKeyName, char[][] bufferArray, int maxStringLen, const char[][] defaultValueStrings = g_DifficultyDefaultStringValues) { for (int i = 0; i < Difficulty_Max; i++) { @@ -704,7 +705,7 @@ stock void SetProfileDifficultyStringArrayValues(KeyValues kv, const char[] base } } -bool GetProfileColorNoBacks(KeyValues kv, +stock bool GetProfileColorNoBacks(KeyValues kv, const char[] keyValue, int &r, int &g, @@ -749,7 +750,7 @@ static const int g_DifficultyDefaultColorValues[Difficulty_Max][4] = * @param buffer Array to store evaluated values * @param defaultValueStrings Array of default values if no key with the base key name is found */ -void GetProfileDifficultyColorValues(KeyValues kv, const char[] baseKeyName, int buffer[Difficulty_Max][4], const int defaultColorValues[Difficulty_Max][4] = g_DifficultyDefaultColorValues) +stock void GetProfileDifficultyColorValues(KeyValues kv, const char[] baseKeyName, int buffer[Difficulty_Max][4], const int defaultColorValues[Difficulty_Max][4] = g_DifficultyDefaultColorValues) { for (int i = 0; i < Difficulty_Max; i++) { @@ -791,11 +792,81 @@ void GetProfileDifficultyColorValues(KeyValues kv, const char[] baseKeyName, int } } +enum EffectEvent +{ + EffectEvent_Invalid = -1, + EffectEvent_Constant = 0, + EffectEvent_HitPlayer, + EffectEvent_PlayerSeesBoss +}; + +enum EffectType +{ + EffectType_Invalid = -1, + EffectType_Steam = 0, + EffectType_DynamicLight, + EffectType_Particle, + EffectType_Trail, + EffectType_PropDynamic, + EffectType_PointSpotlight, + EffectType_Sprite, + EffectType_TempEntBeamRing, + EffectType_TempEntParticle, + EffectType_Sound +}; + +enum +{ + SF2BossAttackType_Invalid = -1, + SF2BossAttackType_Melee = 0, + SF2BossAttackType_Ranged = 1, + SF2BossAttackType_Projectile = 2, + SF2BossAttackType_ExplosiveDance = 3, + SF2BossAttackType_LaserBeam = 4, + SF2BossAttackType_Custom = 5, + SF2BossAttackType_Tongue = 6 +}; + +enum +{ + SF2BossProjectileType_Invalid = -1, + SF2BossProjectileType_Fireball = 0, + SF2BossProjectileType_Iceball = 1, + SF2BossProjectileType_Rocket = 2, + SF2BossProjectileType_Grenade = 3, + SF2BossProjectileType_SentryRocket = 4, + SF2BossProjectileType_Arrow = 5, + SF2BossProjectileType_Mangler = 6, + SF2BossProjectileType_Baseball = 7, + SF2BossProjectileType_Custom +}; + +enum +{ + SF2BossTrapType_Invalid = -1, + SF2BossTrapType_BearTrap = 0, + SF2BossTrapType_Custom +}; + +enum +{ + SF2DamageType_Invalid = -1, + SF2DamageType_Jarate = 0, + SF2DamageType_Milk, + SF2DamageType_Gas, + SF2DamageType_Mark, + SF2DamageType_Ignite, + SF2DamageType_Stun, + SF2DamageType_Bleed, + SF2DamageType_Smite, + SF2DamageType_Random +} + // ====================================== // ENUM STRUCTS // ====================================== -enum struct SF2BossProfileSoundInfo +/*enum struct SF2BossProfileSoundInfo { char SectionName[64]; int Channel; @@ -1143,32 +1214,9 @@ enum struct SF2ParticleData } } } -} - -enum EffectEvent -{ - EffectEvent_Invalid = -1, - EffectEvent_Constant = 0, - EffectEvent_HitPlayer, - EffectEvent_PlayerSeesBoss -}; - -enum EffectType -{ - EffectType_Invalid = -1, - EffectType_Steam = 0, - EffectType_DynamicLight, - EffectType_Particle, - EffectType_Trail, - EffectType_PropDynamic, - EffectType_PointSpotlight, - EffectType_Sprite, - EffectType_TempEntBeamRing, - EffectType_TempEntParticle, - EffectType_Sound -}; +}*/ -enum struct SF2BossProfileBaseEffectInfo +/*enum struct SF2BossProfileBaseEffectInfo { char SectionName[64]; EffectEvent Event; @@ -3144,4 +3192,4 @@ enum struct SF2BossProfileData } #include -#include +#include */ diff --git a/addons/sourcemod/scripting/include/sf2/profiles/profiles_chaser.inc b/addons/sourcemod/scripting/include/sf2/profiles/profiles_chaser.inc index 8c301a9b..9de910cc 100644 --- a/addons/sourcemod/scripting/include/sf2/profiles/profiles_chaser.inc +++ b/addons/sourcemod/scripting/include/sf2/profiles/profiles_chaser.inc @@ -1,52 +1,5 @@ #include -enum -{ - SF2BossAttackType_Invalid = -1, - SF2BossAttackType_Melee = 0, - SF2BossAttackType_Ranged = 1, - SF2BossAttackType_Projectile = 2, - SF2BossAttackType_ExplosiveDance = 3, - SF2BossAttackType_LaserBeam = 4, - SF2BossAttackType_Custom = 5, - SF2BossAttackType_Tongue = 6 -}; - -enum -{ - SF2BossProjectileType_Invalid = -1, - SF2BossProjectileType_Fireball = 0, - SF2BossProjectileType_Iceball = 1, - SF2BossProjectileType_Rocket = 2, - SF2BossProjectileType_Grenade = 3, - SF2BossProjectileType_SentryRocket = 4, - SF2BossProjectileType_Arrow = 5, - SF2BossProjectileType_Mangler = 6, - SF2BossProjectileType_Baseball = 7, - SF2BossProjectileType_Custom -}; - -enum -{ - SF2BossTrapType_Invalid = -1, - SF2BossTrapType_BearTrap = 0, - SF2BossTrapType_Custom -}; - -enum -{ - SF2DamageType_Invalid = -1, - SF2DamageType_Jarate = 0, - SF2DamageType_Milk, - SF2DamageType_Gas, - SF2DamageType_Mark, - SF2DamageType_Ignite, - SF2DamageType_Stun, - SF2DamageType_Bleed, - SF2DamageType_Smite, - SF2DamageType_Random -} - enum struct SF2BossProfileAttackGestureData // This one covers the gestures { ArrayList Names; @@ -374,7 +327,7 @@ enum struct SF2ChaserBossProfileDamageEffectData // Can be any data this.Sounds.Destroy(); } - void Apply(CBaseCombatCharacter player, int difficulty, SF2_ChaserBossEntity chaser = SF2_ChaserBossEntity(-1)) + void Apply(CBaseCombatCharacter player, int difficulty, SF2_ChaserBossEntity chaser = view_as(-1)) { if (!this.Enabled[difficulty]) { @@ -600,7 +553,7 @@ enum struct SF2ChaserBossProfileShockwaveData } } - void ApplyDamageEffects(CBaseCombatCharacter player, int difficulty, SF2_ChaserBossEntity chaser = SF2_ChaserBossEntity(-1)) + void ApplyDamageEffects(CBaseCombatCharacter player, int difficulty, SF2_ChaserBossEntity chaser = view_as(-1)) { if (this.DamageEffects == null) { @@ -1061,7 +1014,7 @@ enum struct SF2ChaserBossProfileAttackData return strcmp(subType, this.SubType) == 0; } - void ApplyDamageEffects(CBaseCombatCharacter player, int difficulty, SF2_ChaserBossEntity chaser = SF2_ChaserBossEntity(-1)) + void ApplyDamageEffects(CBaseCombatCharacter player, int difficulty, SF2_ChaserBossEntity chaser = view_as(-1)) { if (this.DamageEffects == null) { diff --git a/addons/sourcemod/scripting/include/sf2/stocks.inc b/addons/sourcemod/scripting/include/sf2/stocks.inc index ffe87262..784f1ebf 100644 --- a/addons/sourcemod/scripting/include/sf2/stocks.inc +++ b/addons/sourcemod/scripting/include/sf2/stocks.inc @@ -1,6 +1,6 @@ #pragma semicolon 1 -bool DispatchParticleEffect(int entity, const char[] particle, float startPos[3], float angles[3], float endPos[3], +stock bool DispatchParticleEffect(int entity, const char[] particle, float startPos[3], float angles[3], float endPos[3], int attachmentPointIndex = 0, ParticleAttachment attachType = PATTACH_CUSTOMORIGIN, bool resetAllParticlesOnEntity = false) { char particleReal[PLATFORM_MAX_PATH]; @@ -55,7 +55,7 @@ bool DispatchParticleEffect(int entity, const char[] particle, float startPos[3] return true; } -bool DispatchParticleEffectBeam(int entity, const char[] particle, float startPos[3], float angles[3], float endPos[3], +stock bool DispatchParticleEffectBeam(int entity, const char[] particle, float startPos[3], float angles[3], float endPos[3], int attachmentPointIndex = 0, ParticleAttachment attachType = PATTACH_CUSTOMORIGIN, bool resetAllParticlesOnEntity = false) { char particleReal[PLATFORM_MAX_PATH]; diff --git a/addons/sourcemod/scripting/sf2.sp b/addons/sourcemod/scripting/sf2.sp index c16ff837..4c2106d8 100644 --- a/addons/sourcemod/scripting/sf2.sp +++ b/addons/sourcemod/scripting/sf2.sp @@ -1,3 +1,6 @@ +#pragma semicolon 1 +#pragma newdecls required + #include #include #include @@ -13,8 +16,6 @@ #include #include -#pragma semicolon 1 - #include #include #include @@ -36,7 +37,6 @@ bool steamworks; #define SF2 #include -#pragma newdecls required #pragma dynamic 131072 @@ -127,49 +127,17 @@ KeyValues g_RestrictedWeaponsConfig; KeyValues g_SpecialRoundsConfig; KeyValues g_ClassStatsConfig; -ArrayList g_PageMusicRanges; -int g_PageMusicActiveIndex[MAXTF2PLAYERS] = { -1, ... }; - int g_SlenderModel[MAX_BOSSES] = { INVALID_ENT_REFERENCE, ... }; int g_SlenderCopyMaster[MAX_BOSSES] = { -1, ... }; -int g_SlenderMaxCopies[MAX_BOSSES][Difficulty_Max]; int g_SlenderCompanionMaster[MAX_BOSSES] = { -1, ... }; -float g_SlenderEyePosOffset[MAX_BOSSES][3]; -float g_SlenderEyeAngOffset[MAX_BOSSES][3]; -float g_SlenderDetectMins[MAX_BOSSES][3]; -float g_SlenderDetectMaxs[MAX_BOSSES][3]; -int g_SlenderRenderColor[MAX_BOSSES][4]; -int g_SlenderRenderFX[MAX_BOSSES]; -int g_SlenderRenderMode[MAX_BOSSES]; Handle g_SlenderThink[MAX_BOSSES]; Handle g_SlenderEntityThink[MAX_BOSSES]; Handle g_SlenderFakeTimer[MAX_BOSSES]; Handle g_SlenderDeathCamTimer[MAX_BOSSES]; int g_SlenderDeathCamTarget[MAX_BOSSES]; -float g_SlenderStaticRadius[MAX_BOSSES][Difficulty_Max]; -float g_SlenderStaticRate[MAX_BOSSES][Difficulty_Max]; -float g_SlenderStaticRateDecay[MAX_BOSSES][Difficulty_Max]; -float g_SlenderStaticGraceTime[MAX_BOSSES][Difficulty_Max]; bool g_SlenderAddCompanionsOnDifficulty[MAX_BOSSES] = { false, ... }; float g_SlenderStatueIdleLifeTime[MAX_BOSSES]; -bool g_SlenderDeathCamScareSound[MAX_BOSSES]; -bool g_SlenderPublicDeathCam[MAX_BOSSES]; -float g_SlenderPublicDeathCamSpeed[MAX_BOSSES]; -float g_SlenderPublicDeathCamAcceleration[MAX_BOSSES]; -float g_SlenderPublicDeathCamDeceleration[MAX_BOSSES]; -float g_SlenderPublicDeathCamBackwardOffset[MAX_BOSSES]; -float g_SlenderPublicDeathCamDownwardOffset[MAX_BOSSES]; -bool g_SlenderDeathCamOverlay[MAX_BOSSES]; -float g_SlenderDeathCamOverlayTimeStart[MAX_BOSSES]; -float g_SlenderDeathCamTime[MAX_BOSSES]; - -//The Gaben's stuff -bool g_SlenderCustomOutroSong[MAX_BOSSES]; - -bool g_SlenderUseCustomOutlines[MAX_BOSSES]; -bool g_SlenderUseRainbowOutline[MAX_BOSSES]; - int g_TrapEntityCount; float g_RoundTimeMessage = 0.0; @@ -179,15 +147,9 @@ bool g_SlenderTeleportTargetIsCamping[MAX_BOSSES] = { false, ... }; float g_SlenderNextTeleportTime[MAX_BOSSES] = { -1.0, ... }; float g_SlenderTeleportTargetTime[MAX_BOSSES] = { -1.0, ... }; -float g_SlenderTeleportMinRange[MAX_BOSSES][Difficulty_Max]; -float g_SlenderTeleportMaxRange[MAX_BOSSES][Difficulty_Max]; float g_SlenderTeleportMaxTargetTime[MAX_BOSSES] = { -1.0, ... }; float g_SlenderTeleportMaxTargetStress[MAX_BOSSES] = { 0.0, ... }; float g_SlenderTeleportPlayersRestTime[MAX_BOSSES][MAXTF2PLAYERS]; -bool g_SlenderTeleportIgnoreChases[MAX_BOSSES]; -bool g_SlenderTeleportIgnoreVis[MAX_BOSSES]; - -bool g_SlenderProxiesAllowNormalVoices[MAX_BOSSES]; int g_SlenderBoxingBossCount = 0; int g_SlenderBoxingBossKilled = 0; @@ -208,14 +170,6 @@ float g_SlenderNextJumpScare[MAX_BOSSES] = { -1.0, ... }; float g_SlenderTimeUntilKill[MAX_BOSSES] = { -1.0, ... }; float g_SlenderTimeUntilNextProxy[MAX_BOSSES] = { -1.0, ... }; -float g_SlenderProxyDamageVsEnemy[MAX_BOSSES][Difficulty_Max]; -float g_SlenderProxyDamageVsBackstab[MAX_BOSSES][Difficulty_Max]; -float g_SlenderProxyDamageVsSelf[MAX_BOSSES][Difficulty_Max]; -int g_SlenderProxyControlGainHitEnemy[MAX_BOSSES][Difficulty_Max]; -int g_SlenderProxyControlGainHitByEnemy[MAX_BOSSES][Difficulty_Max]; -float g_SlenderProxyControlDrainRate[MAX_BOSSES][Difficulty_Max]; -int g_SlenderMaxProxies[MAX_BOSSES][Difficulty_Max]; - int g_NightVisionType = 0; //Healthbar @@ -358,42 +312,6 @@ Handle g_PlayerFireworkTimer[MAXTF2PLAYERS] = { null, ... }; bool g_PlayerGettingPageReward[MAXTF2PLAYERS] = { false, ... }; -// Music system. -int g_PlayerMusicFlags[MAXTF2PLAYERS]; -char g_PlayerMusicString[MAXTF2PLAYERS][PLATFORM_MAX_PATH]; -float g_PlayerMusicVolume[MAXTF2PLAYERS]; -float g_PlayerMusicTargetVolume[MAXTF2PLAYERS]; -Handle g_PlayerMusicTimer[MAXTF2PLAYERS]; -int g_PlayerPageMusicMaster[MAXTF2PLAYERS]; - -// Chase music system, which apparently also uses the alert song system. And the idle sound system. -char g_PlayerChaseMusicString[MAXTF2PLAYERS][MAX_BOSSES][PLATFORM_MAX_PATH]; -char g_PlayerChaseMusicSeeString[MAXTF2PLAYERS][MAX_BOSSES][PLATFORM_MAX_PATH]; -float g_PlayerChaseMusicVolumes[MAXTF2PLAYERS][MAX_BOSSES]; -float g_PlayerChaseMusicSeeVolumes[MAXTF2PLAYERS][MAX_BOSSES]; -Handle g_PlayerChaseMusicTimer[MAXTF2PLAYERS][MAX_BOSSES]; -Handle g_PlayerChaseMusicSeeTimer[MAXTF2PLAYERS][MAX_BOSSES]; -int g_PlayerChaseMusicMaster[MAXTF2PLAYERS] = { -1, ... }; -int g_PlayerChaseMusicSeeMaster[MAXTF2PLAYERS] = { -1, ... }; -int g_PlayerChaseMusicOldMaster[MAXTF2PLAYERS] = { -1, ... }; -int g_PlayerChaseMusicSeeOldMaster[MAXTF2PLAYERS] = { -1, ... }; - -char g_PlayerAlertMusicString[MAXTF2PLAYERS][MAX_BOSSES][PLATFORM_MAX_PATH]; -float g_PlayerAlertMusicVolumes[MAXTF2PLAYERS][MAX_BOSSES]; -Handle g_PlayerAlertMusicTimer[MAXTF2PLAYERS][MAX_BOSSES]; -int g_PlayerAlertMusicMaster[MAXTF2PLAYERS] = { -1, ... }; -int g_PlayerAlertMusicOldMaster[MAXTF2PLAYERS] = { -1, ... }; - -char g_PlayerIdleMusicString[MAXTF2PLAYERS][MAX_BOSSES][PLATFORM_MAX_PATH]; -float g_PlayerIdleMusicVolumes[MAXTF2PLAYERS][MAX_BOSSES]; -Handle g_PlayerIdleMusicTimer[MAXTF2PLAYERS][MAX_BOSSES]; -int g_PlayerIdleMusicMaster[MAXTF2PLAYERS] = { -1, ... }; -int g_PlayerIdleMusicOldMaster[MAXTF2PLAYERS] = { -1, ... }; - -char g_Player90sMusicString[MAXTF2PLAYERS][PLATFORM_MAX_PATH]; -float g_Player90sMusicVolumes[MAXTF2PLAYERS]; -Handle g_Player90sMusicTimer[MAXTF2PLAYERS]; - SF2RoundState g_RoundState = SF2RoundState_Invalid; float g_RoundDifficultyModifier = DIFFICULTYMODIFIER_NORMAL; bool g_RoundInfiniteFlashlight = false; @@ -437,7 +355,6 @@ static int g_RoundIntroText; char g_RoundIntroMusic[PLATFORM_MAX_PATH] = ""; static char g_PageCollectSound[PLATFORM_MAX_PATH] = ""; static int g_PageSoundPitch = 100; -char currentMusicTrack[PLATFORM_MAX_PATH], currentMusicTrackNormal[PLATFORM_MAX_PATH], currentMusicTrackHard[PLATFORM_MAX_PATH], currentMusicTrackInsane[PLATFORM_MAX_PATH], currentMusicTrackNightmare[PLATFORM_MAX_PATH], currentMusicTrackApollyon[PLATFORM_MAX_PATH]; int g_RoundWarmupRoundCount = 0; @@ -564,6 +481,7 @@ ConVar g_WeaponCriticalsConVar; ConVar g_PhysicsPushScaleConVar; ConVar g_DragonsFuryBurningBonusConVar; ConVar g_DragonsFuryBurnDurationConVar; +ConVar g_TFBotForceClassConVar; bool g_IsPlayerShakeEnabled; bool g_PlayerViewbobHurtEnabled; @@ -648,9 +566,13 @@ PrivateForward g_OnMapEndPFwd; PrivateForward g_OnGameFramePFwd; PrivateForward g_OnRoundStartPFwd; PrivateForward g_OnRoundEndPFwd; +PrivateForward g_OnConfigsExecutedPFwd; PrivateForward g_OnEntityCreatedPFwd; PrivateForward g_OnEntityDestroyedPFwd; PrivateForward g_OnEntityTeleportedPFwd; +PrivateForward g_OnPostInitMapEntitiesPFwd; +PrivateForward g_OnPostInitNewGamePFwd; +PrivateForward g_OnRoundStateChangePFwd; PrivateForward g_OnAdminMenuCreateOptionsPFwd; PrivateForward g_OnPlayerJumpPFwd; PrivateForward g_OnPlayerSpawnPFwd; @@ -672,7 +594,10 @@ PrivateForward g_OnPlayerTurnOnFlashlightPFwd; PrivateForward g_OnPlayerTurnOffFlashlightPFwd; PrivateForward g_OnPlayerFlashlightBreakPFwd; PrivateForward g_OnPlayerAverageUpdatePFwd; +PrivateForward g_OnPlayerPostWeaponsPFwd; +PrivateForward g_OnPageCountChangedPFwd; PrivateForward g_OnSpecialRoundStartPFwd; +PrivateForward g_OnBossAddedPFwd; PrivateForward g_OnBossSpawnPFwd; PrivateForward g_OnBossRemovedPFwd; PrivateForward g_OnChaserGetAttackActionPFwd; @@ -850,6 +775,9 @@ public void OnConfigsExecuted() PrecacheStuff(); ReloadBossProfiles(); NPCOnConfigsExecuted(); + Call_StartForward(g_OnConfigsExecutedPFwd); + Call_Finish(); + g_BossCountUpdateTimer = CreateTimer(2.0, Timer_BossCountUpdate, _, TIMER_REPEAT | TIMER_FLAG_NO_MAPCHANGE); int ent = -1; while ((ent = FindEntityByClassname(ent, "obj_sentrygun")) != -1) @@ -1065,6 +993,9 @@ static void StartPlugin() NPCOnConfigsExecuted(); + Call_StartForward(g_OnConfigsExecutedPFwd); + Call_Finish(); + InitializeBossPackVotes(); SetupTimeLimitTimerForBossPackVote(); @@ -1335,11 +1266,6 @@ static void StopPlugin() cvar.SetBool(false); } - if (MusicActive()) - { - NPCStopMusic(); - } - // Cleanup clients. for (int i = 1; i <= MaxClients; i++) { @@ -1501,17 +1427,17 @@ static Action Timer_GlobalGameFrame(Handle timer) } SF2NPC_Chaser controller = chaser.Controller; - if (!controller.GetProfileData().BoxingBoss) + if (!controller.GetProfileDataEx().BoxingBoss) { continue; } SF2NPC_BaseNPC baseNPC = view_as(controller); - if (baseNPC.GetProfileData().IsPvEBoss) + if (baseNPC.GetProfileDataEx().IsPvEBoss) { continue; } - NPCGetBossName(i, boxingBossName, sizeof(boxingBossName)); + baseNPC.GetProfileDataEx().GetName(1, boxingBossName, sizeof(boxingBossName)); float health = float(chaser.GetProp(Prop_Data, "m_iHealth")); float maxHealth = chaser.MaxHealth; if (chaser.GetProp(Prop_Data, "m_takedamage") == DAMAGE_EVENTS_ONLY) @@ -1550,7 +1476,10 @@ static Action Timer_GlobalGameFrame(Handle timer) continue; } - if (!(NPCGetFlags(bossIndex) & SFF_PROXIES)) + int difficulty = GetLocalGlobalDifficulty(bossIndex); + BossProfileProxyData proxyData = SF2NPC_BaseNPC(bossIndex).GetProfileDataEx().GetProxies(); + + if (!proxyData.IsEnabled(difficulty)) { continue; } @@ -1571,9 +1500,7 @@ static Action Timer_GlobalGameFrame(Handle timer) continue; // No teleport target. } - int difficulty = GetLocalGlobalDifficulty(bossIndex); - - int maxProxies = g_SlenderMaxProxies[bossIndex][difficulty]; + int maxProxies = proxyData.GetMaxProxies(difficulty); if (g_InProxySurvivalRageMode) { maxProxies += 5; @@ -1605,9 +1532,9 @@ static Action Timer_GlobalGameFrame(Handle timer) continue; } - float spawnChanceMin = NPCGetProxySpawnChanceMin(bossIndex, difficulty); - float spawnChanceMax = NPCGetProxySpawnChanceMax(bossIndex, difficulty); - float spawnChanceThreshold = NPCGetProxySpawnChanceThreshold(bossIndex, difficulty); + float spawnChanceMin = proxyData.GetMinSpawnChance(difficulty); + float spawnChanceMax = proxyData.GetMaxSpawnChance(difficulty); + float spawnChanceThreshold = proxyData.GetSpawnChanceThreshold(difficulty); float chance = GetRandomFloat(spawnChanceMin, spawnChanceMax); if (chance > spawnChanceThreshold && !g_InProxySurvivalRageMode) @@ -1620,8 +1547,8 @@ static Action Timer_GlobalGameFrame(Handle timer) int availableProxies = maxProxies - numActiveProxies; - int spawnNumMin = NPCGetProxySpawnNumMin(bossIndex, difficulty); - int spawnNumMax = NPCGetProxySpawnNumMax(bossIndex, difficulty); + int spawnNumMin = proxyData.GetMinSpawnedProxies(difficulty); + int spawnNumMax = proxyData.GetMaxSpawnedProxies(difficulty); int spawnNum = 0; @@ -1722,8 +1649,8 @@ static Action Timer_GlobalGameFrame(Handle timer) // Set the cooldown time! if (cooldown) { - float spawnCooldownMin = NPCGetProxySpawnCooldownMin(bossIndex, difficulty); - float spawnCooldownMax = NPCGetProxySpawnCooldownMax(bossIndex, difficulty); + float spawnCooldownMin = proxyData.GetMinSpawnCooldown(difficulty); + float spawnCooldownMax = proxyData.GetMaxSpawnCooldown(difficulty); g_SlenderTimeUntilNextProxy[bossIndex] = GetGameTime() + GetRandomFloat(spawnCooldownMin, spawnCooldownMax); } @@ -1821,11 +1748,6 @@ static Action Timer_BossCountUpdate(Handle timer) return Plugin_Stop; } - if (!g_Enabled) - { - return Plugin_Stop; - } - int bossCount = NPCGetCount(); int bossPreferredCount; @@ -1834,7 +1756,7 @@ static Action Timer_BossCountUpdate(Handle timer) SF2NPC_BaseNPC Npc = SF2NPC_BaseNPC(i); if (Npc.UniqueID == -1 || Npc.IsCopy || - (Npc.Flags & SFF_FAKE) || Npc.GetProfileData().IsPvEBoss) + (Npc.Flags & SFF_FAKE) || Npc.GetProfileDataEx().IsPvEBoss) { continue; } @@ -1842,14 +1764,13 @@ static Action Timer_BossCountUpdate(Handle timer) bossPreferredCount++; int difficulty = GetLocalGlobalDifficulty(Npc.Index); - SF2BossProfileData data; - data = Npc.GetProfileData(); - if (!data.CopiesInfo.Enabled[GetLocalGlobalDifficulty(i)] || (Npc.Flags & SFF_NOCOPIES) != 0) + BaseBossProfile data = Npc.GetProfileDataEx(); + if (!data.GetCopies().IsEnabled(GetLocalGlobalDifficulty(i)) || (Npc.Flags & SFF_NOCOPIES) != 0) { continue; } - int minCount = data.CopiesInfo.MinCopies[difficulty]; + int minCount = data.GetCopies().GetMinCopies(difficulty); if (minCount > 0) { for (int i2 = 0; i2 < MAX_BOSSES; i2++) @@ -1968,7 +1889,7 @@ static Action Timer_BossCountUpdate(Handle timer) { continue; } - if (Npc.GetProfileData().IsPvEBoss) + if (Npc.GetProfileDataEx().IsPvEBoss) { continue; } @@ -2001,6 +1922,11 @@ static Action Timer_BossCountUpdate(Handle timer) } } + if (!g_Enabled) + { + bossPreferredCount = MAX_BOSSES; + } + int diff = bossCount - bossPreferredCount; if (diff != 0) { @@ -2031,7 +1957,7 @@ static Action Timer_BossCountUpdate(Handle timer) continue; } - if (Npc.GetProfileData().IsPvEBoss) + if (Npc.GetProfileDataEx().IsPvEBoss) { continue; } @@ -2039,10 +1965,9 @@ static Action Timer_BossCountUpdate(Handle timer) if (Npc.CanRemove) { SF2NPC_BaseNPC master = Npc.CopyMaster; - SF2BossProfileData data; - data = master.GetProfileData(); + BaseBossProfile data = master.GetProfileDataEx(); int difficulty = GetLocalGlobalDifficulty(master.Index); - if (data.CopiesInfo.MinCopies[difficulty] > 0) + if (data.GetCopies().GetMinCopies(difficulty) > 0) { int copyCount = 0; for (int i2 = 0; i2 < MAX_BOSSES; i2++) @@ -2068,7 +1993,7 @@ static Action Timer_BossCountUpdate(Handle timer) } copyCount++; } - if (copyCount > data.CopiesInfo.MinCopies[difficulty]) + if (copyCount > data.GetCopies().GetMinCopies(difficulty)) { Npc.Remove(); count--; @@ -2106,9 +2031,8 @@ static Action Timer_BossCountUpdate(Handle timer) continue; } - SF2BossProfileData data; - data = Npc.GetProfileData(); - if (!data.CopiesInfo.Enabled[GetLocalGlobalDifficulty(i)] || (Npc.Flags & SFF_NOCOPIES) != 0) + BaseBossProfile data = Npc.GetProfileDataEx(); + if (!data.GetCopies().IsEnabled(GetLocalGlobalDifficulty(i)) || (Npc.Flags & SFF_NOCOPIES) != 0) { continue; } @@ -2142,7 +2066,7 @@ static Action Timer_BossCountUpdate(Handle timer) int difficulty = GetLocalGlobalDifficulty(Npc.Index); - int copyDifficulty = Npc.GetMaxCopies(difficulty); + int copyDifficulty = data.GetCopies().GetMaxCopies(difficulty); if (copyCount >= copyDifficulty) { continue; @@ -2861,6 +2785,7 @@ void SF_CollectTriggersMultiple() SDKHook(ent, SDKHook_EndTouch, Hook_FuncOnEndTouchEx); } } + static Action Hook_TriggerOnStartTouchEx(int trigger, int other) { if (MaxClients >= other >= 1 && IsClientInGhostMode(other)) @@ -3061,34 +2986,17 @@ void CollectPage(int page, int activator) char buffer[SF2_MAX_PROFILE_NAME_LENGTH], bossName[SF2_MAX_NAME_LENGTH]; if (NPCGetCount() < 63) { - if (g_DifficultyConVar.IntValue < 4 || GetSelectableAdminBossProfileList().Length <= 0) - { - ArrayList selectableBosses = GetSelectableBossProfileList().Clone(); - if (selectableBosses.Length > 0) - { - selectableBosses.GetString(GetRandomInt(0, selectableBosses.Length - 1), buffer, sizeof(buffer)); - AddProfile(buffer); - NPCGetBossName(_, bossName, sizeof(bossName), buffer); - EmitSoundToAll(SR_SOUND_SELECT_BR, _, SNDCHAN_AUTO, _, _, 0.75); - SpecialRoundGameText(bossName, "d_purgatory"); - CPrintToChatAll("{royalblue}%t {default}Next on the roulette: {valve}%s", "SF2 Prefix", bossName); //Minimized HUD - } - delete selectableBosses; - } - else + ArrayList selectableBosses = GetSelectableBossProfileList().Clone(); + if (selectableBosses.Length > 0) { - ArrayList selectableBosses = GetSelectableAdminBossProfileList().Clone(); - if (selectableBosses.Length > 0) - { - selectableBosses.GetString(GetRandomInt(0, selectableBosses.Length - 1), buffer, sizeof(buffer)); - AddProfile(buffer); - NPCGetBossName(_, bossName, sizeof(bossName), buffer); - EmitSoundToAll(SR_SOUND_SELECT_BR, _, SNDCHAN_AUTO, _, _, 0.75); - SpecialRoundGameText(bossName, "d_purgatory"); - CPrintToChatAll("{royalblue}%t {default}Next on the roulette: {valve}%s", "SF2 Prefix", bossName); - } - delete selectableBosses; + selectableBosses.GetString(GetRandomInt(0, selectableBosses.Length - 1), buffer, sizeof(buffer)); + AddProfile(buffer); + GetBossProfile(buffer).GetName(1, bossName, sizeof(bossName)); + EmitSoundToAll(SR_SOUND_SELECT_BR, _, SNDCHAN_AUTO, _, _, 0.75); + SpecialRoundGameText(bossName, "d_purgatory"); + CPrintToChatAll("{royalblue}%t {default}Next on the roulette: {valve}%s", "SF2 Prefix", bossName); //Minimized HUD } + delete selectableBosses; } else { @@ -4143,7 +4051,7 @@ void SetRoundState(SF2RoundState roundState) { continue; } - if (NPCChaserIsBoxingBoss(Npc.Index) && !Npc.GetProfileData().IsPvEBoss) + if (view_as(Npc).GetProfileDataEx().BoxingBoss && !Npc.GetProfileDataEx().IsPvEBoss) { g_SlenderBoxingBossCount++; } @@ -4208,6 +4116,11 @@ void SetRoundState(SF2RoundState roundState) Call_PushCell(oldRoundState); Call_PushCell(g_RoundState); Call_Finish(); + + Call_StartForward(g_OnRoundStateChangePFwd); + Call_PushCell(oldRoundState); + Call_PushCell(g_RoundState); + Call_Finish(); } bool IsRoundPlaying() @@ -4518,7 +4431,7 @@ void ForceInNextPlayersInQueue(int amount, bool showMessage = false) ClientSetGhostModeState(client, false); TF2_RespawnPlayer(client); TF2_RemoveCondition(client, TFCond_StealthedUserBuffFade); - g_LastCommandTime[client] = GetEngineTime()+0.5; + g_LastCommandTime[client] = GetEngineTime() + 0.5; CreateTimer(0.25, Timer_ForcePlayer, GetClientUserId(client), TIMER_FLAG_NO_MAPCHANGE); } else @@ -4667,6 +4580,7 @@ void SlenderOnClientStressUpdate(int client) } Npc.GetProfile(profile, sizeof(profile)); + BaseBossProfile profileData = Npc.GetProfileDataEx(); int teleportTarget = EntRefToEntIndex(g_SlenderProxyTarget[Npc.Index]); if (teleportTarget && teleportTarget != INVALID_ENT_REFERENCE) @@ -4681,11 +4595,11 @@ void SlenderOnClientStressUpdate(int client) if (teleportTarget && teleportTarget != INVALID_ENT_REFERENCE && !g_PlayerIsExitCamping[teleportTarget]) { if (g_PlayerEliminated[teleportTarget] || DidClientEscape(teleportTarget) || - (!SF_BossesChaseEndlessly() && !SF_IsRenevantMap() && !SF_IsSurvivalMap() && !g_SlenderTeleportIgnoreChases[Npc.Index] && stress >= g_SlenderTeleportMaxTargetStress[bossIndex]) || + (!SF_BossesChaseEndlessly() && !SF_IsRenevantMap() && !SF_IsSurvivalMap() && !profileData.TeleportIgnoreChases && stress >= g_SlenderTeleportMaxTargetStress[bossIndex]) || (g_SlenderTeleportMaxTargetTime[Npc.Index] > 0.0 && gameTime >= g_SlenderTeleportMaxTargetTime[Npc.Index])) { // Queue for a new target and mark the old target in the rest period. - float restPeriod = Npc.GetTeleportRestPeriod(difficulty); + float restPeriod = profileData.GetTeleportRestPeriod(difficulty); restPeriod = (restPeriod * GetRandomFloat(0.92, 1.08)) / (g_RoundDifficultyModifier); g_SlenderTeleportTarget[Npc.Index] = INVALID_ENT_REFERENCE; @@ -4703,8 +4617,8 @@ void SlenderOnClientStressUpdate(int client) { int preferredTeleportTarget = INVALID_ENT_REFERENCE; - float targetStressMin = Npc.GetTeleportStressMin(difficulty); - float targetStressMax = Npc.GetTeleportStressMax(difficulty); + float targetStressMin = profileData.GetMinTeleportStress(difficulty); + float targetStressMax = profileData.GetMaxTeleportStress(difficulty); float targetStress = targetStressMax - ((targetStressMax - targetStressMin) / (g_RoundDifficultyModifier)); @@ -4725,7 +4639,7 @@ void SlenderOnClientStressUpdate(int client) break; } } - if (g_PlayerStressAmount[i] < preferredTeleportTargetStress || g_RestartSessionEnabled || g_SlenderTeleportIgnoreChases[Npc.Index]) + if (g_PlayerStressAmount[i] < preferredTeleportTargetStress || g_RestartSessionEnabled || profileData.TeleportIgnoreChases || SF_BossesChaseEndlessly() || SF_IsRenevantMap() || SF_IsSurvivalMap()) { if (g_SlenderTeleportPlayersRestTime[Npc.Index][i] <= gameTime) { @@ -4781,83 +4695,6 @@ void GetPageEntities(ArrayList array) } } -static int GetPageMusicRanges() -{ - g_PageMusicRanges.Clear(); - - char name[64]; - - int ent = -1; - while ((ent = FindEntityByClassname(ent, "ambient_generic")) != -1) - { - GetEntPropString(ent, Prop_Data, "m_iName", name, sizeof(name)); - - if (name[0] != '\0' && !StrContains(name, "sf2_page_music_", false)) - { - ReplaceString(name, sizeof(name), "sf2_page_music_", "", false); - - char pageRanges[2][32]; - ExplodeString(name, "-", pageRanges, 2, 32); - - int index = g_PageMusicRanges.Push(EntIndexToEntRef(ent)); - if (index != -1) - { - int min = StringToInt(pageRanges[0]); - int max = StringToInt(pageRanges[1]); - - #if defined DEBUG - DebugMessage("Page range found: entity %d, min = %d, max = %d", ent, min, max); - #endif - g_PageMusicRanges.Set(index, min, 1); - g_PageMusicRanges.Set(index, max, 2); - } - } - } - - while ((ent = FindEntityByClassname(ent, "sf2_info_page_music")) != -1) - { - SF2PageMusicEntity pageMusic = SF2PageMusicEntity(ent); - if (!pageMusic.IsValid()) - { - continue; - } - - pageMusic.InsertRanges(g_PageMusicRanges); - } - - // precache - if (g_PageMusicRanges.Length > 0) - { - char path[PLATFORM_MAX_PATH]; - - for (int i = 0; i < g_PageMusicRanges.Length; i++) - { - ent = EntRefToEntIndex(g_PageMusicRanges.Get(i)); - if (!ent || ent == INVALID_ENT_REFERENCE) - { - continue; - } - - SF2PageMusicEntity pageMusic = SF2PageMusicEntity(ent); - if (pageMusic.IsValid()) - { - // Don't do anything; entity already precached its own music. - } - else - { - GetEntPropString(ent, Prop_Data, "m_iszSound", path, sizeof(path)); - if (path[0] != '\0') - { - PrecacheSound(path); - } - } - } - } - - LogSF2Message("Loaded page music ranges successfully!"); - return 0; -} - void SetPageCount(int num) { if (num > g_PageMax) @@ -5078,18 +4915,17 @@ void SetPageCount(int num) { continue; } - SF2BossProfileData data; - data = NPCGetProfileData(npcIndex); + BaseBossProfile data = SF2NPC_BaseNPC(npcIndex).GetProfileDataEx(); - if (data.SlaughterRunData.SpawnTime[difficulty] > 0.0) + if (data.GetSlaughterRunData() != null && data.GetSlaughterRunData().GetCustomSpawnTime(difficulty) > 0.0) { - times[bosses] = data.SlaughterRunData.SpawnTime[difficulty]; + times[bosses] = data.GetSlaughterRunData().GetCustomSpawnTime(difficulty); bosses++; continue; } float originalSpeed, speed, timerCheck; - originalSpeed = data.RunSpeed[difficulty] + NPCGetAddSpeed(npcIndex); + originalSpeed = data.GetRunSpeed(difficulty) + NPCGetAddSpeed(npcIndex); float slaughterSpeed = g_SlaughterRunMinimumBossRunSpeedConVar.FloatValue; if (originalSpeed < slaughterSpeed) { @@ -5129,6 +4965,11 @@ void SetPageCount(int num) SF2MapEntity_OnPageCountChanged(g_PageCount, oldPageCount); + Call_StartForward(g_OnPageCountChangedPFwd); + Call_PushCell(g_PageCount); + Call_PushCell(oldPageCount); + Call_Finish(); + // Notify logic entities. char targetName[64]; char findTargetName[64]; @@ -5720,6 +5561,15 @@ Action Timer_SwitchBot(Handle timer, any userid) return Plugin_Stop; } + char value[32]; + g_TFBotForceClassConVar.GetString(value, sizeof(value)); + + TFClassType forced = TFClass_Unknown; + if (value[0] != '\0') + { + forced = TF2_GetClassFromName(value); + } + int random = GetRandomInt(1, 9); TFClassType newClass; switch (random) @@ -5761,6 +5611,10 @@ Action Timer_SwitchBot(Handle timer, any userid) newClass = TFClass_Spy; } } + if (forced != TFClass_Unknown) + { + newClass = forced; + } TF2_SetPlayerClass(client, newClass); TF2_RegeneratePlayer(client); @@ -6362,8 +6216,13 @@ Action Timer_ModifyRagdoll(Handle timer, any userid) { return Plugin_Stop; } - SF2BossProfileData data; - data = NPCGetProfileData(bossIndex); + char profile[SF2_MAX_PROFILE_NAME_LENGTH]; + NPCGetProfile(bossIndex, profile, sizeof(profile)); + BaseBossProfile data = GetBossProfile(profile); + if (data == null) + { + return Plugin_Stop; + } int ragdoll = GetEntPropEnt(client, Prop_Send, "m_hRagdoll"); if (!IsValidEntity(ragdoll)) { @@ -6383,7 +6242,19 @@ Action Timer_ModifyRagdoll(Handle timer, any userid) SetEntPropVector(ent, Prop_Send, "m_vecRagdollOrigin", pos); if (data.PushRagdoll) { - force = data.PushRagdollForce; + data.GetPushRagdollForce(force); + int bossEnt = NPCGetEntIndex(bossIndex); + if (IsValidEntity(bossEnt)) + { + float myPos[3], direction[3]; + CBaseEntity(bossEnt).GetAbsOrigin(myPos); + SubtractVectors(pos, myPos, direction); + GetVectorAngles(direction, direction); + GetAngleVectors(direction, direction, NULL_VECTOR, NULL_VECTOR); + NormalizeVector(direction, direction); + force[0] *= direction[0]; + force[1] *= direction[1]; + } SetEntPropVector(ent, Prop_Send, "m_vecRagdollVelocity", force); SetEntPropVector(ent, Prop_Send, "m_vecForce", force); } @@ -6562,39 +6433,6 @@ Action Timer_PlayerSwitchToBlue(Handle timer, any userid) return Plugin_Stop; } -void CreateGeneralParticle(int entity, const char[] sectionName, float particleZPos = 0.0) -{ - if (entity == -1) - { - return; - } - - float slenderPosition[3], slenderAngles[3]; - GetEntPropVector(entity, Prop_Data, "m_vecAbsOrigin", slenderPosition); - GetEntPropVector(entity, Prop_Data, "m_angAbsRotation", slenderAngles); - slenderPosition[2] += particleZPos; - - if (!DispatchParticleEffect(entity, sectionName, slenderPosition, slenderAngles, slenderPosition)) - { - int particleEnt = CreateEntityByName("info_particle_system"); - - if (particleEnt != -1 && entity != -1) - { - TeleportEntity(particleEnt, slenderPosition, slenderAngles, NULL_VECTOR); - - DispatchKeyValue(particleEnt, "targetname", "tf2particle"); - DispatchKeyValue(particleEnt, "effect_name", sectionName); - - DispatchSpawn(particleEnt); - - ActivateEntity(particleEnt); - AcceptEntityInput(particleEnt, "start"); - - CreateTimer(0.1, Timer_KillEdict, particleEnt, TIMER_FLAG_NO_MAPCHANGE); - } - } -} - static Action Timer_RoundStart(Handle timer) { if (g_PageMax > 0) @@ -7295,9 +7133,11 @@ static void InitializeMapEntities() GetRoundIntroParameters(); GetRoundEscapeParameters(); - GetPageMusicRanges(); SpawnPages(); + Call_StartForward(g_OnPostInitMapEntitiesPFwd); + Call_Finish(); + #if defined DEBUG if (g_DebugDetailConVar.IntValue > 0) { @@ -8281,6 +8121,9 @@ void InitializeNewGame() } } + Call_StartForward(g_OnPostInitNewGamePFwd); + Call_Finish(); + #if defined DEBUG if (g_DebugDetailConVar.IntValue > 0) { diff --git a/addons/sourcemod/scripting/sf2/adminmenu.sp b/addons/sourcemod/scripting/sf2/adminmenu.sp index 90211f03..04fc8ced 100644 --- a/addons/sourcemod/scripting/sf2/adminmenu.sp +++ b/addons/sourcemod/scripting/sf2/adminmenu.sp @@ -4,6 +4,7 @@ #define _sf2_adminmenu_included #pragma semicolon 1 +#pragma newdecls required static Handle g_TopMenu = null; static int g_PlayerAdminMenuTargetUserId[MAXTF2PLAYERS] = { -1, ... }; @@ -404,13 +405,12 @@ static void AddAllBossesToMenu(Menu menu) for (int i = 0; i < bossList.Length; i++) { bossList.GetString(i, profile, sizeof(profile)); - NPCGetBossName(_, displayName, sizeof(displayName), profile); + GetBossProfile(profile).GetName(1, displayName, sizeof(displayName)); if (displayName[0] == '\0') { strcopy(displayName, sizeof(displayName), profile); } - SF2BossProfileData data; - g_BossProfileData.GetArray(profile, data, sizeof(data)); + BaseBossProfile data = GetBossProfile(profile); if (data.IsPvEBoss) { continue; @@ -529,7 +529,7 @@ static int AddBossTargetsToMenu(Menu menuHandle) NPCGetProfile(i, profile, sizeof(profile)); - NPCGetBossName(_, buffer, sizeof(buffer), profile); + GetBossProfile(profile).GetName(1, buffer, sizeof(buffer)); if (buffer[0] == '\0') { strcopy(buffer, sizeof(buffer), profile); @@ -547,10 +547,7 @@ static int AddBossTargetsToMenu(Menu menuHandle) StrCat(display, sizeof(display), " (fake)"); } - SF2BossProfileData data; - data = NPCGetProfileData(i); - - if (data.IsPvEBoss) + if (GetBossProfile(profile).IsPvEBoss) { continue; } @@ -726,7 +723,7 @@ static int AdminMenu_BossAttackWaiters(Menu menu, MenuAction action, int param1, NPCGetProfile(index, profile, sizeof(profile)); char name[SF2_MAX_NAME_LENGTH]; - NPCGetBossName(_, name, sizeof(name), profile); + GetBossProfile(profile).GetName(1, name, sizeof(name)); if (name[0] == '\0') { strcopy(name, sizeof(name), profile); @@ -840,7 +837,7 @@ static int AdminMenu_BossTeleport(Menu menu, MenuAction action, int param1, int NPCGetProfile(index, profile, sizeof(profile)); char name[SF2_MAX_NAME_LENGTH]; - NPCGetBossName(_, name, sizeof(name), profile); + GetBossProfile(profile).GetName(1, name, sizeof(name)); if (name[0] == '\0') { strcopy(name, sizeof(name), profile); @@ -915,17 +912,11 @@ static bool DisplayOverrideBossAdminMenu(int client) for (int i = 0; i < bossList.Length; i++) { bossList.GetString(i, profile, sizeof(profile)); - NPCGetBossName(_, displayName, sizeof(displayName), profile); + GetBossProfile(profile).GetName(1, displayName, sizeof(displayName)); if (displayName[0] == '\0') { strcopy(displayName, sizeof(displayName), profile); } - SF2BossProfileData data; - g_BossProfileData.GetArray(profile, data, sizeof(data)); - if (data.IsPvEBoss) - { - continue; - } menuHandle.AddItem(profile, displayName); } @@ -936,7 +927,7 @@ static bool DisplayOverrideBossAdminMenu(int client) if (profileOverride[0] != '\0' && IsProfileValid(profileOverride)) { - NPCGetBossName(_, profileDisplayName, sizeof(profileDisplayName), profileOverride); + GetBossProfile(profileOverride).GetName(1, profileDisplayName, sizeof(profileDisplayName)); if (profileDisplayName[0] == '\0') { @@ -979,9 +970,8 @@ static int AdminMenu_OverrideBoss(Menu menu, MenuAction action, int param1, int g_BossProfileOverrideConVar.SetString(profile); - ArrayList arrayNames; - arrayNames = GetBossProfileNames(profile); - arrayNames.GetString(Difficulty_Normal, name, sizeof(name)); + BaseBossProfile profileData = GetBossProfile(profile); + profileData.GetName(Difficulty_Normal, name, sizeof(name)); CPrintToChatAll("{royalblue}%t {collectors}%N {default}set the next boss to {valve}%s{default}.", "SF2 Prefix", param1, name); @@ -1045,7 +1035,7 @@ static int AdminMenu_BossWanderToPos(Menu menu, MenuAction action, int param1, i else { SF2NPC_BaseNPC npc = SF2NPC_BaseNPC(index); - switch (npc.Type) + switch (npc.GetProfileDataEx().Type) { case SF2BossType_Chaser: { @@ -1145,7 +1135,7 @@ static int AdminMenu_BossAlertToPos(Menu menu, MenuAction action, int param1, in else { SF2NPC_BaseNPC npc = SF2NPC_BaseNPC(index); - switch (npc.Type) + switch (npc.GetProfileDataEx().Type) { case SF2BossType_Chaser: { @@ -1209,21 +1199,21 @@ static bool DisplayBossAttackAdminMenu(int client) continue; } - if (NPCGetType(i) != SF2BossType_Chaser) + if (SF2NPC_BaseNPC(i).GetProfileDataEx().Type != SF2BossType_Chaser) { continue; } SF2NPC_Chaser controller = SF2NPC_Chaser(i); - SF2ChaserBossProfileData chaserData; - chaserData = controller.GetProfileData(); - if (chaserData.Attacks == null || chaserData.Attacks.Length == 0) + ChaserBossProfile chaserData = controller.GetProfileDataEx(); + ProfileObject attacks = chaserData.GetSection("attacks"); + if (attacks == null || attacks.Size == 0) { continue; } controller.GetProfile(profile, sizeof(profile)); - controller.GetName(buffer, sizeof(buffer)); + chaserData.GetName(1, buffer, sizeof(buffer)); if (buffer[0] == '\0') { strcopy(buffer, sizeof(buffer), profile); @@ -1241,8 +1231,7 @@ static bool DisplayBossAttackAdminMenu(int client) StrCat(display, sizeof(display), " (fake)"); } - SF2BossProfileData data; - data = NPCGetProfileData(i); + BaseBossProfile data = GetBossProfile(profile); if (data.IsPvEBoss) { @@ -1332,14 +1321,17 @@ static bool DisplayBossAttackListAdminMenu(int client) return false; } - SF2ChaserBossProfileData data; - data = g_SelectedBoss[client].GetProfileData(); + ChaserBossProfile data = g_SelectedBoss[client].GetProfileDataEx(); + ProfileObject attacks = data.GetSection("attacks"); Menu menuHandle = new Menu(AdminMenu_BossAttackList); - for (int i = 0; i < data.Attacks.Length; i++) + for (int i = 0; i < attacks.Size; i++) { - SF2ChaserBossProfileAttackData attackData; - data.GetAttackFromIndex(i, attackData); - menuHandle.AddItem(attackData.Name, attackData.Name); + char name[64]; + data.GetAttackName(i, name, sizeof(name)); + if (name[0] != '\0') + { + menuHandle.AddItem(name, name); + } } menuHandle.SetTitle("%t Make a boss use a attack\n \n", "SF2 Prefix"); diff --git a/addons/sourcemod/scripting/sf2/anticamping.sp b/addons/sourcemod/scripting/sf2/anticamping.sp index b7477de5..3cca34d9 100644 --- a/addons/sourcemod/scripting/sf2/anticamping.sp +++ b/addons/sourcemod/scripting/sf2/anticamping.sp @@ -1,4 +1,5 @@ #pragma semicolon 1 +#pragma newdecls required // Anti-camping data. int g_PlayerCampingStrikes[MAXTF2PLAYERS] = { 0, ... }; diff --git a/addons/sourcemod/scripting/sf2/changelog.sp b/addons/sourcemod/scripting/sf2/changelog.sp index 9be812cc..1bd97c99 100644 --- a/addons/sourcemod/scripting/sf2/changelog.sp +++ b/addons/sourcemod/scripting/sf2/changelog.sp @@ -1,4 +1,5 @@ #pragma semicolon 1 +#pragma newdecls required static Menu g_ChangelogUpdate; static KeyValues g_ChangelogConfig; diff --git a/addons/sourcemod/scripting/sf2/classconfigs.sp b/addons/sourcemod/scripting/sf2/classconfigs.sp index b2a8b1dd..74396e23 100644 --- a/addons/sourcemod/scripting/sf2/classconfigs.sp +++ b/addons/sourcemod/scripting/sf2/classconfigs.sp @@ -4,6 +4,7 @@ #define _sf2_client_classconfigs_included #pragma semicolon 1 +#pragma newdecls required float g_ClassRunSpeed[MAX_CLASSES + 1]; float g_ClassWalkSpeed[MAX_CLASSES + 1]; diff --git a/addons/sourcemod/scripting/sf2/client.sp b/addons/sourcemod/scripting/sf2/client.sp index fd42a215..c5df27d4 100644 --- a/addons/sourcemod/scripting/sf2/client.sp +++ b/addons/sourcemod/scripting/sf2/client.sp @@ -4,6 +4,7 @@ #define _sf2_client_included #pragma semicolon 1 +#pragma newdecls required #define SF2_OVERLAY_DEFAULT "overlays/slender/newcamerahud_3" #define SF2_OVERLAY_DEFAULT_NO_FILMGRAIN "overlays/slender/nofilmgrain" @@ -37,7 +38,7 @@ int g_ClientFrame[MAXTF2PLAYERS]; #include "client/sprint.sp" #include "client/breathing.sp" #include "client/ghostmode.sp" -#include "client/music.sp" +#include "client/new_music.sp" #include "client/proxy.sp" void Client_SetupAPI() @@ -454,12 +455,13 @@ void ClientProcessVisibility(int client) NPCGetProfile(i, profile, sizeof(profile)); + BaseBossProfile profileData = GetBossProfile(profile); + int boss = NPCGetEntIndex(i); if (boss && boss != INVALID_ENT_REFERENCE) { CBaseEntity(boss).GetAbsOrigin(slenderPos); - NPCGetEyePosition(i, slenderEyePos); float slenderMins[3], slenderMaxs[3]; GetEntPropVector(boss, Prop_Send, "m_vecMins", slenderMins); @@ -479,6 +481,7 @@ void ClientProcessVisibility(int client) if (boss && boss != INVALID_ENT_REFERENCE) { int copyMaster = NPCGetFromUniqueID(g_SlenderCopyMaster[i]); + NPCGetEyePosition(i, slenderEyePos); if (!IsPointVisibleToPlayer(client, slenderEyePos, true, SlenderUsesBlink(i))) { @@ -489,7 +492,7 @@ void ClientProcessVisibility(int client) g_PlayerSeesSlender[client][i] = true; } - if ((GetGameTime() - g_PlayerSeesSlenderLastTime[client][i]) > g_SlenderStaticGraceTime[i][difficulty] || + if ((GetGameTime() - g_PlayerSeesSlenderLastTime[client][i]) > profileData.GetStaticOnLookGraceTime(difficulty) || (oldStaticMode[i] == Static_Increase && g_PlayerStaticAmount[client] > 0.1)) { if ((NPCGetFlags(i) & SFF_STATICONLOOK) && @@ -505,7 +508,7 @@ void ClientProcessVisibility(int client) } } else if ((NPCGetFlags(i) & SFF_STATICONRADIUS) && - GetVectorSquareMagnitude(myPos, slenderPos) <= SquareFloat(g_SlenderStaticRadius[i][difficulty])) + GetVectorSquareMagnitude(myPos, slenderPos) <= SquareFloat(profileData.GetStaticRadius(difficulty))) { bool noObstacles = IsPointVisibleToPlayer(client, slenderEyePos, false, false); if (!noObstacles) @@ -542,6 +545,7 @@ void ClientProcessVisibility(int client) } NPCGetProfile(master, masterProfile, sizeof(masterProfile)); + BaseBossProfile masterData = GetBossProfile(masterProfile); // Boss visiblity. if (g_PlayerSeesSlender[client][i] && !wasSeeingSlender[i]) @@ -550,39 +554,36 @@ void ClientProcessVisibility(int client) if (GetGameTime() >= g_PlayerScareNextTime[client][master]) { - if (GetVectorSquareMagnitude(myPos, slenderPos) <= SquareFloat(NPCGetScareRadius(i))) + if (GetVectorSquareMagnitude(myPos, slenderPos) <= SquareFloat(masterData.ScareRadius)) { ClientPerformScare(client, master); - if (NPCGetSpeedBoostOnScare(master)) + if (masterData.ScareSpeedBoostDuration > 0.0) { - TF2_AddCondition(client, TFCond_SpeedBuffAlly, NPCGetScareSpeedBoostDuration(master), client); + TF2_AddCondition(client, TFCond_SpeedBuffAlly, masterData.ScareSpeedBoostDuration, client); } - if (NPCGetScareReactionState(master)) + switch (masterData.ScareReactionType) { - switch (NPCGetScareReactionType(master)) + case 1: { - case 1: - { - SpeakResponseConcept(client, "TLK_PLAYER_SPELL_METEOR_SWARM"); - } - case 2: - { - SpeakResponseConcept(client, "HalloweenLongFall"); - } - case 3: - { - char scareReactionCustom[PLATFORM_MAX_PATH]; - GetBossProfileScareReactionCustom(masterProfile, scareReactionCustom, sizeof(scareReactionCustom)); - SpeakResponseConcept(client, scareReactionCustom); - } + SpeakResponseConcept(client, "TLK_PLAYER_SPELL_METEOR_SWARM"); + } + case 2: + { + SpeakResponseConcept(client, "HalloweenLongFall"); + } + case 3: + { + char scareReactionCustom[PLATFORM_MAX_PATH]; + masterData.GetCustomScareReaction(scareReactionCustom, sizeof(scareReactionCustom)); + SpeakResponseConcept(client, scareReactionCustom); } } - if (NPCGetScareReplenishSprintState(master)) + if (masterData.ScareReplenishSprintAmount > 0.0) { - SF2_BasePlayer(client).Stamina += NPCGetScareReplenishSprintAmount(master); + SF2_BasePlayer(client).Stamina += masterData.ScareReplenishSprintAmount; } float value = NPCGetAttributeValue(master, SF2Attribute_IgnitePlayerOnScare); @@ -613,19 +614,18 @@ void ClientProcessVisibility(int client) } } - if (NPCGetJumpscareOnScare(master)) + if (masterData.JumpscareOnScare) { - float jumpScareDuration = NPCGetJumpscareDuration(master, difficulty); - ClientDoJumpScare(client, master, jumpScareDuration); + ClientDoJumpScare(client, master, masterData.GetJumpscareDuration(difficulty)); } } else { - g_PlayerScareNextTime[client][master] = GetGameTime() + NPCGetScareCooldown(master); + g_PlayerScareNextTime[client][master] = GetGameTime() + masterData.ScareCooldown; } } - if (NPCGetType(i) == SF2BossType_Static) + if (profileData.Type == SF2BossType_Static) { if (NPCGetFlags(i) & SFF_FAKE) { @@ -668,11 +668,11 @@ void ClientProcessVisibility(int client) if (NPCGetFlags(i) & SFF_HASSTATICLOOPLOCALSOUND) { char loopSound[PLATFORM_MAX_PATH]; - GetBossProfileStaticLocalSound(profile, loopSound, sizeof(loopSound)); + profileData.GetStaticLocalLoopSound(loopSound, sizeof(loopSound)); if (loopSound[0] != '\0') { - EmitSoundToClient(client, loopSound, boss, SNDCHAN_STATIC, GetBossProfileStaticShakeLocalLevel(profile), SND_CHANGEVOL, 1.0); + EmitSoundToClient(client, loopSound, boss, SNDCHAN_STATIC, profileData.StaticShakeLocalLevel, SND_CHANGEVOL, 1.0); ClientAddStress(client, 0.03); } } @@ -685,7 +685,7 @@ void ClientProcessVisibility(int client) if (boss && boss != INVALID_ENT_REFERENCE) { char loopSound[PLATFORM_MAX_PATH]; - GetBossProfileStaticLocalSound(profile, loopSound, sizeof(loopSound)); + profileData.GetStaticLocalLoopSound(loopSound, sizeof(loopSound)); if (loopSound[0] != '\0') { @@ -779,10 +779,12 @@ void ClientProcessVisibility(int client) { NPCGetProfile(bossNewStatic, profile, sizeof(profile)); + BaseBossProfile profileData = GetBossProfile(profile); + g_PlayerStaticSound[client][0] = '\0'; char staticSound[PLATFORM_MAX_PATH]; - GetBossProfileStaticSound(profile, staticSound, sizeof(staticSound)); + profileData.GetStaticSound(staticSound, sizeof(staticSound)); if (staticSound[0] != '\0') { @@ -801,8 +803,8 @@ void ClientProcessVisibility(int client) TriggerTimer(g_PlayerLastStaticTimer[client], true); // Start up our own static timer. - float staticIncreaseRate = (g_SlenderStaticRate[bossNewStatic][difficulty] - (g_SlenderStaticRate[bossNewStatic][difficulty] * GetDifficultyModifier(difficulty)) / 10); - float staticDecreaseRate = (g_SlenderStaticRateDecay[bossNewStatic][difficulty] + (g_SlenderStaticRateDecay[bossNewStatic][difficulty] * GetDifficultyModifier(difficulty)) / 10); + float staticIncreaseRate = (profileData.GetStaticRate(difficulty) - (profileData.GetStaticRate(difficulty) * GetDifficultyModifier(difficulty)) / 10); + float staticDecreaseRate = (profileData.GetStaticRateDecay(difficulty) + (profileData.GetStaticRateDecay(difficulty) * GetDifficultyModifier(difficulty)) / 10); if (!IsClassConfigsValid()) { if (class == TFClass_Heavy) @@ -1100,9 +1102,10 @@ void ClientDoJumpScare(int client, int bossIndex, float lifeTime) char profile[SF2_MAX_PROFILE_NAME_LENGTH]; NPCGetProfile(bossIndex, profile, sizeof(profile)); + BaseBossProfile profileData = GetBossProfile(profile); char buffer[PLATFORM_MAX_PATH]; - GetBossProfileJumpscareSound(profile, buffer, sizeof(buffer)); + profileData.GetJumpscareSound(buffer, sizeof(buffer)); if (buffer[0] != '\0') { @@ -1122,14 +1125,19 @@ void ClientPerformScare(int client, int bossIndex) return; } + float gameTime = GetGameTime(); + char profile[SF2_MAX_PROFILE_NAME_LENGTH]; NPCGetProfile(bossIndex, profile, sizeof(profile)); + BaseBossProfile profileData = GetBossProfile(profile); - g_PlayerScareLastTime[client][bossIndex] = GetGameTime(); - g_PlayerScareNextTime[client][bossIndex] = GetGameTime() + NPCGetScareCooldown(bossIndex); + int difficulty = GetLocalGlobalDifficulty(bossIndex); + + g_PlayerScareLastTime[client][bossIndex] = gameTime; + g_PlayerScareNextTime[client][bossIndex] = gameTime + profileData.ScareCooldown; // See how much Sanity should be drained from a scare. - float staticAmount = GetBossProfileStaticScareAmount(profile); + float staticAmount = profileData.GetScareStaticAmount(difficulty); g_PlayerStaticAmount[client] += staticAmount; if (g_PlayerStaticAmount[client] > 1.0) { @@ -1137,21 +1145,17 @@ void ClientPerformScare(int client, int bossIndex) } char scareSound[PLATFORM_MAX_PATH]; - ArrayList soundList; - SF2BossProfileSoundInfo soundInfo; - GetBossProfileScareSounds(profile, soundInfo); - soundList = soundInfo.Paths; - if (soundList != null && soundList.Length > 0) + ProfileSound soundInfo = profileData.GetScareSounds(); + if (soundInfo != null && soundInfo.Paths != null && soundInfo.Paths.Length > 0) { - soundList.GetString(GetRandomInt(0, soundList.Length - 1), scareSound, sizeof(scareSound)); + soundInfo.Paths.GetString(GetRandomInt(0, soundInfo.Paths.Length - 1), scareSound, sizeof(scareSound)); } - soundList = null; if (scareSound[0] != '\0') { soundInfo.EmitSound(true, client); - g_PlayerSightSoundNextTime[client][bossIndex] = GetGameTime() + GetRandomFloat(soundInfo.CooldownMin, soundInfo.CooldownMax); + g_PlayerSightSoundNextTime[client][bossIndex] = gameTime + profileData.ScareCooldown; if (g_PlayerStressAmount[client] > 0.4) { @@ -1196,15 +1200,15 @@ static void ClientPerformSightSound(int client, int bossIndex) char profile[SF2_MAX_PROFILE_NAME_LENGTH]; NPCGetProfile(bossIndex, profile, sizeof(profile)); + int difficulty = GetLocalGlobalDifficulty(bossIndex); - SF2BossProfileSoundInfo soundInfo; - GetBossProfileSightSounds(profile, soundInfo); + ProfileSound soundInfo = GetBossProfile(profile).GetSightSounds(); - if (soundInfo.Paths != null && soundInfo.Paths.Length > 0) + if (soundInfo != null && soundInfo.Paths != null && soundInfo.Paths.Length > 0) { soundInfo.EmitSound(true, client); - g_PlayerSightSoundNextTime[client][master] = GetGameTime() + GetRandomFloat(soundInfo.CooldownMin, soundInfo.CooldownMax); + g_PlayerSightSoundNextTime[client][master] = GetGameTime() + GetRandomFloat(soundInfo.GetCooldownMin(difficulty), soundInfo.GetCooldownMax(difficulty)); float bossPos[3], myPos[3]; int boss = NPCGetEntIndex(bossIndex); @@ -1300,11 +1304,6 @@ Action Timer_PlayerOverlayCheck(Handle timer, any userid) return Plugin_Stop; } - if (IsRoundInWarmup()) - { - return Plugin_Continue; - } - int deathCamBoss = NPCGetFromUniqueID(g_PlayerDeathCamBoss[client]); int jumpScareBoss = NPCGetFromUniqueID(g_PlayerJumpScareBoss[client]); @@ -1314,12 +1313,12 @@ Action Timer_PlayerOverlayCheck(Handle timer, any userid) if (IsClientInDeathCam(client) && deathCamBoss != -1 && g_PlayerDeathCamShowOverlay[client]) { NPCGetProfile(deathCamBoss, profile, sizeof(profile)); - GetBossProfileOverlayPlayerDeath(profile, material, sizeof(material)); + GetBossProfile(profile).GetPlayerDeathOverlay(material, sizeof(material)); } else if (jumpScareBoss != -1 && GetGameTime() <= g_PlayerJumpScareLifeTime[client]) { NPCGetProfile(jumpScareBoss, profile, sizeof(profile)); - GetBossProfileOverlayJumpscare(profile, material, sizeof(material)); + GetBossProfile(profile).GetJumpscareOverlay(material, sizeof(material)); } else if (IsClientInGhostMode(client) && !SF_IsBoxingMap()) { @@ -1670,6 +1669,47 @@ void TF2_GetClassName(TFClassType class, char[] buffer, int bufferLen, bool alt } } +TFClassType TF2_GetClassFromName(const char[] class) +{ + if (strcmp(class, "scout", false) == 0) + { + return TFClass_Scout; + } + else if (strcmp(class, "soldier", false) == 0) + { + return TFClass_Soldier; + } + else if (strcmp(class, "pyro", false) == 0) + { + return TFClass_Pyro; + } + else if (strcmp(class, "demoman", false) == 0) + { + return TFClass_DemoMan; + } + else if (strcmp(class, "heavyweapons", false) == 0 || strcmp(class, "heavy", false) == 0) + { + return TFClass_Heavy; + } + else if (strcmp(class, "engineer", false) == 0) + { + return TFClass_Engineer; + } + else if (strcmp(class, "medic", false) == 0) + { + return TFClass_Medic; + } + else if (strcmp(class, "sniper", false) == 0) + { + return TFClass_Sniper; + } + else if (strcmp(class, "spy", false) == 0) + { + return TFClass_Spy; + } + return TFClass_Unknown; +} + bool IsPointVisibleToAPlayer(const float pos[3], bool checkFOV = true, bool checkBlink = false, bool checkEliminated = true, bool ignoreFog = false) { for (int i = 1; i <= MaxClients; i++) @@ -1721,8 +1761,9 @@ bool IsPointVisibleToPlayer(int client, const float pos[3], bool checkFOV = true } } - TR_TraceRayFilter(eyePos, pos, MASK_PLAYERSOLID_BRUSHONLY | CONTENTS_WINDOW, RayType_EndPoint, TraceRayDontHitAnything, client); - bool hit = TR_DidHit(); + Handle trace = TR_TraceRayFilterEx(eyePos, pos, MASK_PLAYERSOLID_BRUSHONLY | CONTENTS_WINDOW, RayType_EndPoint, TraceRayDontHitAnything, client); + bool hit = TR_DidHit(trace); + delete trace; if (hit) { diff --git a/addons/sourcemod/scripting/sf2/client/blink.sp b/addons/sourcemod/scripting/sf2/client/blink.sp index e8e9935b..6b8edb3f 100644 --- a/addons/sourcemod/scripting/sf2/client/blink.sp +++ b/addons/sourcemod/scripting/sf2/client/blink.sp @@ -1,4 +1,5 @@ #pragma semicolon 1 +#pragma newdecls required // Blink data. static Handle g_PlayerBlinkTimer[MAXTF2PLAYERS] = { null, ... }; @@ -263,14 +264,16 @@ static float ClientGetBlinkRate(int client) continue; } + BaseBossProfile profileData = SF2NPC_BaseNPC(i).GetProfileDataEx(); + if (g_PlayerSeesSlender[client][i]) { - value *= NPCGetBlinkLookRate(i); + value *= profileData.BlinkLookRate; } else if (g_PlayerStaticMode[client][i] == Static_Increase) { - value *= NPCGetBlinkStaticRate(i); + value *= profileData.BlinkStaticRate; } } diff --git a/addons/sourcemod/scripting/sf2/client/breathing.sp b/addons/sourcemod/scripting/sf2/client/breathing.sp index 7e841929..9e251123 100644 --- a/addons/sourcemod/scripting/sf2/client/breathing.sp +++ b/addons/sourcemod/scripting/sf2/client/breathing.sp @@ -1,4 +1,5 @@ #pragma semicolon 1 +#pragma newdecls required #define SF2_PLAYER_BREATH_COOLDOWN_MIN 0.8 #define SF2_PLAYER_BREATH_COOLDOWN_MAX 2.0 diff --git a/addons/sourcemod/scripting/sf2/client/deathcam.sp b/addons/sourcemod/scripting/sf2/client/deathcam.sp index c169291c..f6da55ea 100644 --- a/addons/sourcemod/scripting/sf2/client/deathcam.sp +++ b/addons/sourcemod/scripting/sf2/client/deathcam.sp @@ -1,4 +1,216 @@ #pragma semicolon 1 +#pragma newdecls required + +methodmap BossProfileDeathCamData < ProfileObject +{ + property bool IsEnabled + { + public get() + { + return this.GetBool("death_cam", false); + } + } + + property bool PlayScareSound + { + public get() + { + return this.GetBool("death_cam_play_scare_sound", false); + } + } + + property bool Overlay + { + public get() + { + return this.GetBool("death_cam_overlay", false); + } + } + + property float OverlayStartTime + { + public get() + { + return this.GetFloat("death_cam_time_overlay_start", 0.0); + } + } + + property float Duration + { + public get() + { + return this.GetFloat("death_cam_time_death", 0.0); + } + } + + property bool ShouldLastForAnimationDuration + { + public get() + { + return this.GetBool("death_cam_hold_until_anim_duration", false); + } + } + + public void GetLookPosition(float buffer[3]) + { + this.GetVector("death_cam_pos", buffer); + } + + property BossProfilePublicDeathCamData PublicDeathCam + { + public get() + { + return view_as(this); + } + } +} + +methodmap BossProfilePublicDeathCamData < ProfileObject +{ + property bool IsEnabled + { + public get() + { + if (this.GetSection("public_death_cam") != null) + { + return true; + } + return this.GetBool("death_cam_public", false); + } + } + + property float Speed + { + public get() + { + return this.GetFloat("death_cam_speed", 1000.0); + } + } + + property float Acceleration + { + public get() + { + return this.GetFloat("death_cam_acceleration", 1000.0); + } + } + + property float Deceleration + { + public get() + { + return this.GetFloat("death_cam_deceleration", 1000.0); + } + } + + property float BackwardOffset + { + public get() + { + float def = 0.0; + ProfileObject obj = this.GetSection("public_death_cam"); + obj = obj != null ? obj.GetSection("offset") : null; + if (obj != null) + { + def = obj.GetFloat("backward", def); + } + else + { + def = this.GetFloat("deathcam_death_backward_offset", def); + } + return def; + } + } + + property float DownwardOffset + { + public get() + { + float def = 0.0; + ProfileObject obj = this.GetSection("public_death_cam"); + obj = obj != null ? obj.GetSection("offset") : null; + if (obj != null) + { + def = obj.GetFloat("backward", def); + } + else + { + def = this.GetFloat("deathcam_death_downward_offset", def); + } + return def; + } + } + + public void GetAttachment(char[] buffer, int bufferSize) + { + ProfileObject obj = this.GetSection("public_death_cam"); + if (obj != null) + { + obj.GetString("attachment", buffer, bufferSize); + } + else + { + this.GetString("death_cam_attachment_point", buffer, bufferSize); + this.GetString("death_cam_attachtment_point", buffer, bufferSize); + } + } + + public void GetTargetAttachment(char[] buffer, int bufferSize) + { + ProfileObject obj = this.GetSection("public_death_cam"); + if (obj != null) + { + obj.GetString("target_attachment", buffer, bufferSize); + } + else + { + this.GetString("death_cam_attachment_target_point", buffer, bufferSize); + } + } + + property bool Blackout + { + public get() + { + ProfileObject obj = this.GetSection("public_death_cam"); + if (obj != null) + { + return obj.GetBool("blackout", false); + } + return false; + } + } + + property ProfileSound ExecutionSounds + { + public get() + { + ProfileObject obj = this.GetSection("public_death_cam"); + obj = obj != null ? obj.GetSection("sounds") : null; + if (obj != null) + { + return view_as(obj.GetSection("execution")); + } + return null; + } + } + + property bool ShouldLastForAnimationDuration + { + public get() + { + return this.GetBool("death_cam_hold_until_anim_duration", false); + } + } + + public void Precache() + { + if (this.ExecutionSounds != null) + { + this.ExecutionSounds.Precache(); + } + } +} // Deathcam data. int g_PlayerDeathCamBoss[MAXTF2PLAYERS] = { -1, ... }; @@ -119,23 +331,22 @@ static void ClientResetDeathCam(int client) if (deathCamBoss != -1) { + char profile[SF2_MAX_PROFILE_NAME_LENGTH]; + NPCGetProfile(deathCamBoss, profile, sizeof(profile)); if ((NPCGetFlags(deathCamBoss) & SFF_FAKE) == 0) { - SF2BossProfileData data; - data = NPCGetProfileData(deathCamBoss); - if (data.DeathCamData.Enabled && data.DeathCamData.Blackout) + BossProfilePublicDeathCamData data = GetBossProfile(profile).GetDeathCamData().PublicDeathCam; + if (data.IsEnabled && data.Blackout) { UTIL_ScreenFade(client, 10, 0, 0x0002 | 0x0010 | 0x0008, 0, 0, 0, 255); CreateTimer(0.1, Timer_DeleteRagdoll, GetClientUserId(client), TIMER_FLAG_NO_MAPCHANGE); TeleportEntity(client, {16000.0, 16000.0, 16000.0}); - SF2BossProfileSoundInfo soundInfo; - soundInfo = data.DeathCamData.ExecutionSounds; - if (soundInfo.Paths != null && soundInfo.Paths.Length > 0) + if (data.ExecutionSounds != null) { - for (int i = 0; i < soundInfo.Paths.Length; i++) + for (int i = 0; i < data.ExecutionSounds.Paths.KeyLength; i++) { - soundInfo.EmitSound(true, client, SOUND_FROM_PLAYER, _, _, _, i); + data.ExecutionSounds.EmitSound(true, client, SOUND_FROM_PLAYER, _, _, _, i); } } @@ -216,29 +427,26 @@ void ClientStartDeathCam(int client, int bossIndex, const float lookPos[3], bool char profile[SF2_MAX_PROFILE_NAME_LENGTH]; NPCGetProfile(bossIndex, profile, sizeof(profile)); - SF2BossProfileData data; - data = NPCGetProfileData(bossIndex); + BaseBossProfile data = GetBossProfile(profile); + BossProfileDeathCamData deathCamData = data.GetDeathCamData(); + BossProfilePublicDeathCamData publicDeathCamData = deathCamData.PublicDeathCam; - SF2BossProfileSoundInfo soundInfo; - if (g_SlenderDeathCamScareSound[bossIndex]) + if (deathCamData.PlayScareSound) { - soundInfo = data.ScareSounds; - soundInfo.EmitSound(true, client, SOUND_FROM_PLAYER); + data.GetScareSounds().EmitSound(true, client, SOUND_FROM_PLAYER); } - soundInfo = data.ClientDeathCamSounds; - soundInfo.EmitSound(true, client, SOUND_FROM_PLAYER); + data.GetClientDeathCamSounds().EmitSound(true, client, SOUND_FROM_PLAYER); if ((NPCGetFlags(bossIndex) & SFF_FAKE) == 0) { - soundInfo = data.GlobalDeathCamSounds; - for (int i = 0; i <= MaxClients; i++) + for (int i = 1; i <= MaxClients; i++) { if (!IsValidClient(i)) { continue; } - soundInfo.EmitSound(true, i); + data.GetGlobalDeathCamSounds().EmitSound(true, i); } } @@ -250,7 +458,7 @@ void ClientStartDeathCam(int client, int bossIndex, const float lookPos[3], bool if ((NPCGetFlags(bossIndex) & SFF_FAKE) == 0) { - if ((!NPCHasDeathCamEnabled(bossIndex) || antiCamp)) + if ((!deathCamData.IsEnabled || antiCamp)) { SetEntProp(client, Prop_Data, "m_takedamage", 2); // We do this because the point_viewcontrol changes our lifestate. @@ -269,7 +477,7 @@ void ClientStartDeathCam(int client, int bossIndex, const float lookPos[3], bool } else { - if (!NPCHasDeathCamEnabled(bossIndex)) + if (!deathCamData.IsEnabled) { SlenderMarkAsFake(bossIndex); return; @@ -289,7 +497,7 @@ void ClientStartDeathCam(int client, int bossIndex, const float lookPos[3], bool // Create fake model. int slender = -1; - bool publicDeathcam = data.PublicDeathCam || data.DeathCamData.Enabled; + bool publicDeathcam = publicDeathCamData.IsEnabled; if (!publicDeathcam) { slender = SpawnSlenderModel(bossIndex, lookPos, true); @@ -304,6 +512,7 @@ void ClientStartDeathCam(int client, int bossIndex, const float lookPos[3], bool { SF2_BaseBoss(slender).IsKillingSomeone = true; SF2_BaseBoss(slender).KillTarget = CBaseEntity(client); + SF2_BaseBoss(slender).FullDeathCamDuration = publicDeathCamData.ShouldLastForAnimationDuration; } } g_PlayerDeathCamEnt2[client] = EntIndexToEntRef(slender); @@ -315,7 +524,7 @@ void ClientStartDeathCam(int client, int bossIndex, const float lookPos[3], bool int target = CreateEntityByName("info_target"); if (!publicDeathcam) { - offsetPos = data.DeathCamPos; + deathCamData.GetLookPosition(offsetPos); AddVectors(lookPos, offsetPos, offsetPos); TeleportEntity(target, offsetPos, NULL_VECTOR, NULL_VECTOR); DispatchKeyValue(target, "targetname", name); @@ -330,11 +539,7 @@ void ClientStartDeathCam(int client, int bossIndex, const float lookPos[3], bool DispatchKeyValue(target, "targetname", name); SetVariantString("!activator"); AcceptEntityInput(target, "SetParent", slender); - strcopy(boneName, sizeof(boneName), data.PublicDeathCamAttachment); - if (data.DeathCamData.Attachment[0] != '\0') - { - strcopy(boneName, sizeof(boneName), data.DeathCamData.Attachment); - } + publicDeathCamData.GetAttachment(boneName, sizeof(boneName)); if (boneName[0] != '\0') { SetVariantString(boneName); @@ -364,9 +569,9 @@ void ClientStartDeathCam(int client, int bossIndex, const float lookPos[3], bool { float camSpeed, camAcceleration, camDeceleration; - camSpeed = g_SlenderPublicDeathCamSpeed[bossIndex]; - camAcceleration = g_SlenderPublicDeathCamAcceleration[bossIndex]; - camDeceleration = g_SlenderPublicDeathCamDeceleration[bossIndex]; + camSpeed = publicDeathCamData.Speed; + camAcceleration = publicDeathCamData.Acceleration; + camDeceleration = publicDeathCamData.Deceleration; FloatToString(camSpeed, buffer, sizeof(buffer)); DispatchKeyValue(camera, "acceleration", buffer); FloatToString(camAcceleration, buffer, sizeof(buffer)); @@ -377,53 +582,50 @@ void ClientStartDeathCam(int client, int bossIndex, const float lookPos[3], bool SetVariantString("!activator"); AcceptEntityInput(camera, "SetParent", slender); char attachmentName[PLATFORM_MAX_PATH]; - strcopy(attachmentName, sizeof(attachmentName), data.PublicDeathCamAttachment); - if (data.DeathCamData.Attachment[0] != '\0') - { - strcopy(attachmentName, sizeof(attachmentName), data.DeathCamData.Attachment); - } + publicDeathCamData.GetAttachment(attachmentName, sizeof(attachmentName)); if (attachmentName[0] != '\0') { SetVariantString(attachmentName); AcceptEntityInput(camera, "SetParentAttachment"); } - strcopy(attachmentName, sizeof(attachmentName), data.PublicDeathCamAttachmentTarget); - if (data.DeathCamData.Attachment[0] != '\0') - { - strcopy(attachmentName, sizeof(attachmentName), data.DeathCamData.TargetAttachment); - } + publicDeathCamData.GetTargetAttachment(attachmentName, sizeof(attachmentName)); DispatchKeyValue(camera, "targetname", attachmentName); g_CameraInDeathCamAdvanced[camera] = true; - g_CameraPlayerOffsetBackward[camera] = g_SlenderPublicDeathCamBackwardOffset[bossIndex]; - g_CameraPlayerOffsetDownward[camera] = g_SlenderPublicDeathCamDownwardOffset[bossIndex]; + g_CameraPlayerOffsetBackward[camera] = publicDeathCamData.BackwardOffset; + g_CameraPlayerOffsetDownward[camera] = publicDeathCamData.DownwardOffset; RequestFrame(Frame_PublicDeathCam, camera); //Resend taunt sound to eliminated players only } - float duration = g_SlenderDeathCamTime[bossIndex]; - if (g_SlenderDeathCamOverlay[bossIndex] && g_SlenderDeathCamOverlayTimeStart[bossIndex] >= 0.0) + float duration = deathCamData.Duration; + if (deathCamData.Overlay && deathCamData.OverlayStartTime >= 0.0) { - duration = g_SlenderDeathCamOverlayTimeStart[bossIndex]; + duration = deathCamData.OverlayStartTime; } if (duration <= 0.0 && publicDeathcam) { char animation[64]; - SF2BossProfileMasterAnimationsData animData; - animData = data.AnimationData; float rate = 1.0, cycle = 0.0; - animData.GetAnimation(g_SlenderAnimationsList[SF2BossAnimation_DeathCam], difficulty, animation, sizeof(animation), rate, duration, cycle); - CBaseAnimating animator = CBaseAnimating(slender); - int sequence = animator.LookupSequence(animation); - if (duration <= 0.0 && sequence != -1) + ProfileAnimation section = data.GetAnimations().GetAnimation(g_SlenderAnimationsList[SF2BossAnimation_DeathCam]); + if (section != null) { - duration = animator.SequenceDuration(sequence) / rate; - duration *= (1.0 - cycle); + CBaseAnimating animator = CBaseAnimating(slender); + section.GetAnimationName(difficulty, animation, sizeof(animation)); + rate = section.GetAnimationPlaybackRate(difficulty); + cycle = section.GetAnimationCycle(difficulty); + duration = section.GetDuration(difficulty); + int sequence = animator.LookupSequence(animation); + if (duration <= 0.0 && sequence != -1) + { + duration = animator.SequenceDuration(sequence) / rate; + duration *= (1.0 - cycle); + } } } g_PlayerDeathCamTimer[client] = duration; - g_PlayerDeathCamMustDoOverlay[client] = g_SlenderDeathCamOverlay[bossIndex]; + g_PlayerDeathCamMustDoOverlay[client] = deathCamData.Overlay; g_PlayerDeathCam[client] = true; TeleportEntity(client, NULL_VECTOR, NULL_VECTOR, { 0.0, 0.0, 0.0 }); @@ -445,14 +647,14 @@ static void Frame_PublicDeathCam(int cameraRef) int client = GetEntPropEnt(camera, Prop_Data, "m_hPlayer"); if (IsValidEntity(slender) && IsValidClient(client)) { - float camPos[3], camAngs[3]; + float camPos[3], camAngs[3], newPos[3]; + newPos[0] -= g_CameraPlayerOffsetBackward[camera]; + newPos[2] -= g_CameraPlayerOffsetDownward[camera]; GetEntPropVector(camera, Prop_Data, "m_angAbsRotation", camAngs); GetEntPropVector(camera, Prop_Data, "m_vecAbsOrigin", camPos); + VectorTransform(newPos, camPos, camAngs, newPos); - camPos[0] -= g_CameraPlayerOffsetBackward[camera]; - camPos[2] -= g_CameraPlayerOffsetDownward[camera]; - - TeleportEntity(client, camPos, camAngs, NULL_VECTOR); + TeleportEntity(client, newPos, camAngs, NULL_VECTOR); RequestFrame(Frame_PublicDeathCam, EntIndexToEntRef(cameraRef)); } @@ -470,6 +672,7 @@ static void StopDeathCam(int client) SF2NPC_BaseNPC deathCamBoss = SF2NPC_BaseNPC(NPCGetFromUniqueID(g_PlayerDeathCamBoss[client])); if (deathCamBoss != SF2_INVALID_NPC) { + BossProfilePublicDeathCamData publicDeathCamData = deathCamBoss.GetProfileDataEx().GetDeathCamData().PublicDeathCam; if ((deathCamBoss.Flags & SFF_FAKE) == 0) { if (deathCamBoss.HasAttribute(SF2Attribute_IgnitePlayerOnDeath)) @@ -477,9 +680,7 @@ static void StopDeathCam(int client) TF2_IgnitePlayer(client, client); } - SF2BossProfileData data; - data = deathCamBoss.GetProfileData(); - if (data.DeathCamData.Enabled && data.DeathCamData.Blackout && !g_Hooked) + if (publicDeathCamData.IsEnabled && publicDeathCamData.Blackout && !g_Hooked) { AddNormalSoundHook(NoPlayerVoiceHook); g_Hooked = true; @@ -535,14 +736,15 @@ static void Hook_DeathCamThink(int client) CBaseEntity ent = CBaseEntity(EntRefToEntIndex(g_PlayerDeathCamEnt[client])); if (ent.IsValid() && g_CameraInDeathCamAdvanced[ent.index]) { - float camPos[3], camAngs[3]; + float camPos[3], camAngs[3], newPos[3]; ent.GetAbsAngles(camAngs); ent.GetAbsOrigin(camPos); - camPos[0] -= g_CameraPlayerOffsetBackward[ent.index]; - camPos[2] -= g_CameraPlayerOffsetDownward[ent.index]; + newPos[0] -= g_CameraPlayerOffsetBackward[ent.index]; + newPos[2] -= g_CameraPlayerOffsetDownward[ent.index]; + VectorTransform(newPos, camPos, camAngs, newPos); - player.SetLocalOrigin(camPos); + player.SetLocalOrigin(newPos); player.SetLocalAngles(camAngs); } @@ -556,12 +758,9 @@ static void Hook_DeathCamThink(int client) if (Npc.IsValid()) { g_PlayerDeathCamShowOverlay[player.index] = true; - SF2BossProfileData data; - data = Npc.GetProfileData(); - SF2BossProfileSoundInfo soundInfo; - soundInfo = data.PlayerDeathCamOverlaySounds; - soundInfo.EmitSound(true, player.index); - duration = g_SlenderDeathCamTime[Npc.Index]; + BaseBossProfile data = Npc.GetProfileDataEx(); + data.GetOverlayDeathCamSounds().EmitSound(true, player.index, SOUND_FROM_PLAYER); + duration = data.GetDeathCamData().Duration; } g_PlayerDeathCamTimer[player.index] = duration; g_PlayerDeathCamMustDoOverlay[player.index] = false; diff --git a/addons/sourcemod/scripting/sf2/client/flashlight.sp b/addons/sourcemod/scripting/sf2/client/flashlight.sp index 23b78234..bd3b5447 100644 --- a/addons/sourcemod/scripting/sf2/client/flashlight.sp +++ b/addons/sourcemod/scripting/sf2/client/flashlight.sp @@ -3,6 +3,9 @@ #endif #define _sf2_client_flashlight_included +#pragma semicolon 1 +#pragma newdecls required + #define SF2_FLASHLIGHT_WIDTH 512.0 // How wide the player's Flashlight should be in world units. #define SF2_FLASHLIGHT_BRIGHTNESS 0 // Intensity of the players' Flashlight. #define SF2_FLASHLIGHT_DRAIN_RATE 0.65 // How long (in seconds) each bar on the player's Flashlight meter lasts. @@ -11,8 +14,6 @@ #define SF2_FLASHLIGHT_ENABLEAT 0.3 // The percentage of the Flashlight battery where the Flashlight will be able to be used again (if the player shortens out the Flashlight from excessive use). #define SF2_FLASHLIGHT_COOLDOWN 0.4 // How much time players have to wait before being able to switch their flashlight on again after turning it off. -#pragma semicolon 1 - static bool g_PlayerHasFlashlight[MAXTF2PLAYERS] = { false, ... }; static bool g_PlayerFlashlightBroken[MAXTF2PLAYERS] = { false, ... }; static float g_PlayerFlashlightBatteryLife[MAXTF2PLAYERS] = { 1.0, ... }; @@ -664,10 +665,11 @@ void Hook_OnFlashlightThink(int client) CBaseEntity spotlightEnd = CBaseEntity(endEnt); if (spotlightEnd.IsValid()) { - TR_TraceRayFilter(entPos, endPos, MASK_SOLID_BRUSHONLY, RayType_EndPoint, TraceRayDontHitEntity, client); + Handle trace = TR_TraceRayFilterEx(entPos, endPos, MASK_SOLID_BRUSHONLY, RayType_EndPoint, TraceRayDontHitEntity, client); float hitPos[3]; - TR_GetEndPosition(hitPos); + TR_GetEndPosition(hitPos, trace); + delete trace; hitPos[2] += 20.0; diff --git a/addons/sourcemod/scripting/sf2/client/ghostmode.sp b/addons/sourcemod/scripting/sf2/client/ghostmode.sp index 6a387e9c..c3ef87f5 100644 --- a/addons/sourcemod/scripting/sf2/client/ghostmode.sp +++ b/addons/sourcemod/scripting/sf2/client/ghostmode.sp @@ -1,4 +1,5 @@ #pragma semicolon 1 +#pragma newdecls required #define SF2_OVERLAY_GHOST "overlays/slender/ghostcamera" @@ -16,6 +17,7 @@ void SetupGhost() g_OnPlayerDeathPFwd.AddFunction(null, OnPlayerDeath); g_OnPlayerEscapePFwd.AddFunction(null, OnPlayerEscape); g_OnPlayerTeamPFwd.AddFunction(null, OnPlayerTeam); + g_OnPlayerTakeDamagePFwd.AddFunction(null, OnPlayerTakeDamage); } static void OnPutInServer(SF2_BasePlayer client) @@ -25,6 +27,7 @@ static void OnPutInServer(SF2_BasePlayer client) return; } ClientSetGhostModeState(client.index, false); + SDKHook(client.index, SDKHook_PreThinkPost, GhostThink); } static void OnPlayerSpawn(SF2_BasePlayer client) @@ -67,6 +70,42 @@ static void OnPlayerTeam(SF2_BasePlayer client, int team) } } +static void GhostThink(int client) +{ + SF2_BasePlayer player = SF2_BasePlayer(client); + if (!player.IsInGhostMode) + { + return; + } + + player.SetPropFloat(Prop_Send, "m_flNextAttack", GetGameTime() + 2.0); + player.SetPropFloat(Prop_Send, "m_flMaxspeed", 520.0); + player.SetPropFloat(Prop_Send, "m_flModelScale", 1.0); + player.SetPropFloat(Prop_Send, "m_flHeadScale", 1.0); + player.SetPropFloat(Prop_Send, "m_flTorsoScale", 1.0); + player.SetPropFloat(Prop_Send, "m_flHandScale", 1.0); + if (IsClientInKart(player.index)) + { + player.ChangeCondition(TFCond_HalloweenKart, true); + player.ChangeCondition(TFCond_HalloweenKartDash, true); + player.ChangeCondition(TFCond_HalloweenKartNoTurn, true); + player.ChangeCondition(TFCond_HalloweenKartCage, true); + ClientHandleGhostMode(player.index, true); + } + player.ChangeCondition(TFCond_Taunting, true); +} + +static Action OnPlayerTakeDamage(SF2_BasePlayer client, int &attacker, int &inflictor, float &damage, int &damageType, int damageCustom) +{ + if (client.IsInGhostMode) + { + damage = 0.0; + return Plugin_Changed; + } + + return Plugin_Continue; +} + bool IsClientInGhostMode(int client) { return g_PlayerInGhostMode[client]; @@ -314,7 +353,7 @@ void ClientGhostModeNextTarget(int client, bool ignoreSetting = false) continue; } - if (NPCGetProfileData(bossIndex).IsPvEBoss) + if (SF2NPC_BaseNPC(bossIndex).GetProfileDataEx().IsPvEBoss) { continue; } diff --git a/addons/sourcemod/scripting/sf2/client/hints.sp b/addons/sourcemod/scripting/sf2/client/hints.sp index 71202ee4..f5e9b31b 100644 --- a/addons/sourcemod/scripting/sf2/client/hints.sp +++ b/addons/sourcemod/scripting/sf2/client/hints.sp @@ -3,6 +3,9 @@ #endif #define _sf2_client_hints_included +#pragma semicolon 1 +#pragma newdecls required + bool g_PlayerHints[MAXTF2PLAYERS][PlayerHint_MaxNum]; static Handle g_ShowHintTimer[MAXPLAYERS + 1]; diff --git a/addons/sourcemod/scripting/sf2/client/interactables.sp b/addons/sourcemod/scripting/sf2/client/interactables.sp index e9bbd7fb..33b84b8e 100644 --- a/addons/sourcemod/scripting/sf2/client/interactables.sp +++ b/addons/sourcemod/scripting/sf2/client/interactables.sp @@ -1,3 +1,6 @@ +#pragma semicolon 1 +#pragma newdecls required + static int g_PlayerInteractiveGlowEntity[MAXPLAYERS + 1] = { INVALID_ENT_REFERENCE, ... }; static int g_PlayerInteractiveGlowTargetEntity[MAXPLAYERS + 1] = { INVALID_ENT_REFERENCE, ... }; static float g_NextInteractiveThink[MAXPLAYERS + 1] = { 0.0, ... }; @@ -189,9 +192,10 @@ static void UpdateInteractiveGlow(SF2_BasePlayer client) ScaleVector(endPos, maxRange); AddVectors(startPos, endPos, endPos); - TR_TraceRayFilter(startPos, endPos, MASK_VISIBLE, RayType_EndPoint, TraceRayDontHitPlayers, -1); + Handle trace = TR_TraceRayFilterEx(startPos, endPos, MASK_VISIBLE, RayType_EndPoint, TraceRayDontHitPlayers, -1); int oldTargetEnt = EntRefToEntIndex(g_PlayerInteractiveGlowTargetEntity[client.index]); - int targetEnt = TR_GetEntityIndex(); + int targetEnt = TR_GetEntityIndex(trace); + delete trace; if (!IsEntityInteractable(targetEnt)) { targetEnt = -1; diff --git a/addons/sourcemod/scripting/sf2/client/music.sp b/addons/sourcemod/scripting/sf2/client/music.sp index d0d3458f..c2b9973d 100644 --- a/addons/sourcemod/scripting/sf2/client/music.sp +++ b/addons/sourcemod/scripting/sf2/client/music.sp @@ -4,6 +4,7 @@ #define _sf2_client_music_included #pragma semicolon 1 +#pragma newdecls required void SetupMusic() { @@ -73,74 +74,22 @@ static void OnPlayerEscape(SF2_BasePlayer client) static void OnBossRemoved(SF2NPC_BaseNPC npc) { - if (!MusicActive()) - { - for (int i = 1; i <= MaxClients; i++) - { - if (!IsValidClient(i)) - { - continue; - } - - // Remove chase music. - if (g_PlayerChaseMusicMaster[i] == npc.Index) - { - ClientChaseMusicReset(i); - } - - // Don't forget search theme - if (g_PlayerAlertMusicMaster[i] == npc.Index) - { - ClientAlertMusicReset(i); - } - if (g_PlayerChaseMusicSeeMaster[i] == npc.Index) - { - ClientChaseMusicSeeReset(i); - } - - if (g_PlayerIdleMusicMaster[i] == npc.Index) - { - ClientIdleMusicReset(i); - } - - ClientUpdateMusicSystem(i); - } - } } static void OnDifficultyChange(int oldDifficulty, int newDifficulty) { - CheckIfMusicValid(); - if (MusicActive()) - { - for (int i = 1; i <= MaxClients; i++) - { - SF2_BasePlayer client = SF2_BasePlayer(i); - if (!client.IsValid || client.IsSourceTV) - { - continue; - } - char path[PLATFORM_MAX_PATH]; - GetBossMusic(path, sizeof(path)); - if (path[0] != '\0') - { - StopSound(i, MUSIC_CHAN, path); - } - client.UpdateMusicSystem(); - } - } } void ClientResetChannels(int client) { - ClientChaseMusicReset(client); + /*ClientChaseMusicReset(client); ClientChaseMusicSeeReset(client); ClientAlertMusicReset(client); ClientIdleMusicReset(client); Client90sMusicReset(client); - ClientMusicReset(client); + ClientMusicReset(client);*/ } void ClientUpdateMusicSystem(int client, bool initialize = false) @@ -150,7 +99,7 @@ void ClientUpdateMusicSystem(int client, bool initialize = false) return; } - int oldPageMusicMaster = EntRefToEntIndex(g_PlayerPageMusicMaster[client]); + /*int oldPageMusicMaster = EntRefToEntIndex(g_PlayerPageMusicMaster[client]); int oldPageMusicActiveIndex = g_PageMusicActiveIndex[client]; int oldMusicFlags = g_PlayerMusicFlags[client]; int chasingBoss = -1; @@ -288,8 +237,7 @@ void ClientUpdateMusicSystem(int client, bool initialize = false) continue; } - SF2BossProfileData data; - data = NPCGetProfileData(i); + BaseBossProfile data = SF2NPC_BaseNPC(i).GetProfileDataEx(); if (data.IsPvEBoss) { continue; @@ -297,7 +245,7 @@ void ClientUpdateMusicSystem(int client, bool initialize = false) NPCGetProfile(i, profile, sizeof(profile)); - int bossType = NPCGetType(i); + int bossType = data.Type; switch (bossType) { @@ -310,8 +258,8 @@ void ClientUpdateMusicSystem(int client, bool initialize = false) continue; } - SF2BossProfileSoundInfo soundInfo; - ArrayList soundList; + ProfileSound soundInfo; + ChaserBossProfile chaserData = SF2NPC_Chaser(i).GetProfileDataEx(); GetClientAbsOrigin(client, buffer); chaser.GetAbsOrigin(buffer3); float pos[3]; @@ -329,16 +277,15 @@ void ClientUpdateMusicSystem(int client, bool initialize = false) { target.GetAbsOrigin(buffer2); - if ((chaser.State == STATE_CHASE || chaser.State == STATE_ATTACK || (chaser.State == STATE_STUN && (chaser.PreviousState == STATE_CHASE || chaser.PreviousState == STATE_ATTACK))) && + if ((chaser.State == STATE_CHASE || chaser.State == STATE_ATTACK || chaser.IsKillingSomeone || (chaser.State == STATE_STUN && (chaser.PreviousState == STATE_CHASE || chaser.PreviousState == STATE_ATTACK))) && !(NPCGetFlags(i) & SFF_MARKEDASFAKE)) { - GetChaserProfileChaseMusics(profile, soundInfo); + soundInfo = chaserData.GetChaseMusics(); - if ((target.index == client || GetVectorSquareMagnitude(buffer, buffer2) <= SquareFloat(soundInfo.Radius) || - GetVectorSquareMagnitude(buffer, buffer3) <= SquareFloat(soundInfo.Radius) || GetVectorSquareMagnitude(buffer, pos) <= SquareFloat(soundInfo.Radius))) + if (soundInfo != null && (target.index == client || GetVectorSquareMagnitude(buffer, buffer2) <= SquareFloat(soundInfo.GetMusicRadius(1)) || + GetVectorSquareMagnitude(buffer, buffer3) <= SquareFloat(soundInfo.GetMusicRadius(1)) || GetVectorSquareMagnitude(buffer, pos) <= SquareFloat(soundInfo.GetMusicRadius(1)))) { - soundList = soundInfo.Paths; - if (soundList != null && soundList.Length > 0) + if (soundInfo.Paths != null && soundInfo.Paths.Length > 0) { chasingBoss = i; } @@ -346,9 +293,8 @@ void ClientUpdateMusicSystem(int client, bool initialize = false) if ((chaser.State == STATE_CHASE || chaser.State == STATE_ATTACK || chaser.State == STATE_STUN) && PlayerCanSeeSlender(client, i, false)) { - GetChaserProfileChaseVisibleMusics(profile, soundInfo); - soundList = soundInfo.Paths; - if (soundList != null && soundList.Length > 0) + soundInfo = chaserData.GetVisibleChaseMusics(); + if (soundInfo != null && soundInfo.Paths != null && soundInfo.Paths.Length > 0) { chasingSeeBoss = i; } @@ -359,16 +305,15 @@ void ClientUpdateMusicSystem(int client, bool initialize = false) if (chaser.State == STATE_ALERT || (chaser.State == STATE_STUN && chaser.PreviousState == STATE_ALERT)) { - GetChaserProfileAlertMusics(profile, soundInfo); - soundList = soundInfo.Paths; - if (soundList == null || soundList.Length <= 0) + soundInfo = chaserData.GetAlertMusics(); + if (soundInfo == null || soundInfo.Paths == null || soundInfo.Paths.Length <= 0) { continue; } if (!(NPCGetFlags(i) & SFF_MARKEDASFAKE)) { - if (GetVectorSquareMagnitude(buffer, pos) <= SquareFloat(soundInfo.Radius) || GetVectorSquareMagnitude(buffer, buffer3) <= SquareFloat(soundInfo.Radius)) + if (GetVectorSquareMagnitude(buffer, pos) <= SquareFloat(soundInfo.GetMusicRadius(1)) || GetVectorSquareMagnitude(buffer, buffer3) <= SquareFloat(soundInfo.GetMusicRadius(1))) { alertBoss = i; } @@ -377,22 +322,20 @@ void ClientUpdateMusicSystem(int client, bool initialize = false) if (chaser.State == STATE_IDLE || (chaser.State == STATE_STUN && chaser.PreviousState == STATE_IDLE)) { - GetChaserProfileIdleMusics(profile, soundInfo); - soundList = soundInfo.Paths; - if (soundList == null || soundList.Length <= 0) + soundInfo = chaserData.GetIdleMusics(); + if (soundInfo == null || soundInfo.Paths == null || soundInfo.Paths.Length <= 0) { continue; } if (!(NPCGetFlags(i) & SFF_MARKEDASFAKE)) { - if (GetVectorSquareMagnitude(buffer, buffer3) <= SquareFloat(soundInfo.Radius) || GetVectorSquareMagnitude(buffer, pos) <= SquareFloat(soundInfo.Radius)) + if (GetVectorSquareMagnitude(buffer, buffer3) <= SquareFloat(soundInfo.GetMusicRadius(1)) || GetVectorSquareMagnitude(buffer, pos) <= SquareFloat(soundInfo.GetMusicRadius(1))) { idleBoss = i; } } } - soundList = null; } } } @@ -709,7 +652,7 @@ void ClientUpdateMusicSystem(int client, bool initialize = false) ClientAddStress(client, stressAdd); } } - } + }*/ } void ClientMusicReset(int client) @@ -750,10 +693,7 @@ void ClientMusicStart(int client, const char[] newMusic, float volume = -1.0, fl StopSound(client, MUSIC_CHAN, oldMusic); } strcopy(g_PlayerMusicString[client], sizeof(g_PlayerMusicString[]), newMusic); - if (MusicActive()) // A boss is overriding the music. - { - GetBossMusic(g_PlayerMusicString[client], sizeof(g_PlayerMusicString[])); - } + if (volume >= 0.0) { g_PlayerMusicVolume[client] = volume; @@ -791,23 +731,22 @@ void ClientAlertMusicReset(int client) g_PlayerAlertMusicOldMaster[client] = -1; ClientRemoveMusicFlag(client, MUSICF_ALERT); - char profile[SF2_MAX_PROFILE_NAME_LENGTH]; - for (int i = 0; i < MAX_BOSSES; i++) { g_PlayerAlertMusicTimer[client][i] = null; g_PlayerAlertMusicVolumes[client][i] = 0.0; g_PlayerAlertMusicString[client][i][0] = '\0'; + if (!SF2NPC_BaseNPC(i).IsValid()) + { + continue; + } + BaseBossProfile data = SF2NPC_BaseNPC(i).GetProfileDataEx(); - if (NPCGetUniqueID(i) != -1 && NPCGetType(i) == SF2BossType_Chaser) + if (data.Type != -1 && data.Type == SF2BossType_Chaser) { if (IsValidClient(client)) { - NPCGetProfile(i, profile, sizeof(profile)); - - SF2BossProfileSoundInfo soundInfo; - GetChaserProfileAlertMusics(profile, soundInfo); - soundInfo.StopAllSounds(client); + SF2NPC_Chaser(i).GetProfileDataEx().GetAlertMusics().StopAllSounds(1, client); } } } @@ -832,8 +771,7 @@ void ClientAlertMusicStart(int client,int bossIndex) NPCGetProfile(bossIndex, profile, sizeof(profile)); char buffer[PLATFORM_MAX_PATH]; - SF2BossProfileSoundInfo soundInfo; - GetChaserProfileAlertMusics(profile, soundInfo); + ProfileSound soundInfo = SF2NPC_Chaser(bossIndex).GetProfileDataEx().GetAlertMusics(); if (soundInfo.Paths != null && soundInfo.Paths.Length > 0) { soundInfo.Paths.GetString(GetRandomInt(0, soundInfo.Paths.Length - 1), buffer, sizeof(buffer)); @@ -895,23 +833,22 @@ void ClientIdleMusicReset(int client) g_PlayerIdleMusicOldMaster[client] = -1; ClientRemoveMusicFlag(client, MUSICF_IDLE); - char profile[SF2_MAX_PROFILE_NAME_LENGTH]; - for (int i = 0; i < MAX_BOSSES; i++) { g_PlayerIdleMusicTimer[client][i] = null; g_PlayerIdleMusicVolumes[client][i] = 0.0; g_PlayerIdleMusicString[client][i][0] = '\0'; + if (!SF2NPC_BaseNPC(i).IsValid()) + { + continue; + } + BaseBossProfile data = SF2NPC_BaseNPC(i).GetProfileDataEx(); - if (NPCGetUniqueID(i) != -1 && NPCGetType(i) == SF2BossType_Chaser) + if (data.Type != -1 && data.Type == SF2BossType_Chaser) { if (IsValidClient(client)) { - NPCGetProfile(i, profile, sizeof(profile)); - - SF2BossProfileSoundInfo soundInfo; - GetChaserProfileIdleMusics(profile, soundInfo); - soundInfo.StopAllSounds(client); + SF2NPC_Chaser(i).GetProfileDataEx().GetIdleMusics().StopAllSounds(1, client); } } } @@ -936,8 +873,7 @@ void ClientIdleMusicStart(int client,int bossIndex) NPCGetProfile(bossIndex, profile, sizeof(profile)); char buffer[PLATFORM_MAX_PATH]; - SF2BossProfileSoundInfo soundInfo; - GetChaserProfileIdleMusics(profile, soundInfo); + ProfileSound soundInfo = SF2NPC_Chaser(bossIndex).GetProfileDataEx().GetIdleMusics(); if (soundInfo.Paths != null && soundInfo.Paths.Length > 0) { soundInfo.Paths.GetString(GetRandomInt(0, soundInfo.Paths.Length - 1), buffer, sizeof(buffer)); @@ -999,23 +935,22 @@ void ClientChaseMusicReset(int client) g_PlayerChaseMusicOldMaster[client] = -1; ClientRemoveMusicFlag(client, MUSICF_CHASE); - char profile[SF2_MAX_PROFILE_NAME_LENGTH]; - for (int i = 0; i < MAX_BOSSES; i++) { g_PlayerChaseMusicVolumes[client][i] = 0.0; g_PlayerChaseMusicTimer[client][i] = null; g_PlayerChaseMusicString[client][i][0] = '\0'; + if (!SF2NPC_BaseNPC(i).IsValid()) + { + continue; + } + BaseBossProfile data = SF2NPC_BaseNPC(i).GetProfileDataEx(); - if (NPCGetUniqueID(i) != -1 && NPCGetType(i) == SF2BossType_Chaser) + if (data.Type != -1 && data.Type == SF2BossType_Chaser) { if (IsValidClient(client)) { - NPCGetProfile(i, profile, sizeof(profile)); - - SF2BossProfileSoundInfo soundInfo; - GetChaserProfileChaseMusics(profile, soundInfo); - soundInfo.StopAllSounds(client); + SF2NPC_Chaser(i).GetProfileDataEx().GetChaseMusics().StopAllSounds(1, client); } } } @@ -1040,8 +975,7 @@ void ClientMusicChaseStart(int client,int bossIndex) NPCGetProfile(bossIndex, profile, sizeof(profile)); char buffer[PLATFORM_MAX_PATH]; - SF2BossProfileSoundInfo soundInfo; - GetChaserProfileChaseMusics(profile, soundInfo); + ProfileSound soundInfo = SF2NPC_Chaser(bossIndex).GetProfileDataEx().GetChaseMusics(); if (soundInfo.Paths != null && soundInfo.Paths.Length > 0) { soundInfo.Paths.GetString(GetRandomInt(0, soundInfo.Paths.Length - 1), buffer, sizeof(buffer)); @@ -1068,10 +1002,7 @@ void ClientMusicChaseStart(int client,int bossIndex) } return; } - if (MusicActive()) // A boss is overriding the music. - { - GetBossMusic(g_PlayerChaseMusicString[client][bossIndex],sizeof(g_PlayerChaseMusicString[][])); - } + g_PlayerChaseMusicTimer[client][bossIndex] = CreateTimer(0.01, Timer_PlayerFadeInChaseMusic, GetClientUserId(client), TIMER_REPEAT|TIMER_FLAG_NO_MAPCHANGE); TriggerTimer(g_PlayerChaseMusicTimer[client][bossIndex], true); @@ -1107,29 +1038,28 @@ void ClientChaseMusicSeeReset(int client) g_PlayerChaseMusicSeeOldMaster[client] = -1; ClientRemoveMusicFlag(client, MUSICF_CHASEVISIBLE); - char profile[SF2_MAX_PROFILE_NAME_LENGTH]; - for (int i = 0; i < MAX_BOSSES; i++) { g_PlayerChaseMusicSeeTimer[client][i] = null; g_PlayerChaseMusicSeeVolumes[client][i] = 0.0; g_PlayerChaseMusicSeeString[client][i][0] = '\0'; + if (!SF2NPC_BaseNPC(i).IsValid()) + { + continue; + } + BaseBossProfile data = SF2NPC_BaseNPC(i).GetProfileDataEx(); - if (NPCGetUniqueID(i) != -1 && NPCGetType(i) == SF2BossType_Chaser) + if (data.Type != -1 && data.Type == SF2BossType_Chaser) { if (IsValidClient(client)) { - NPCGetProfile(i, profile, sizeof(profile)); - - SF2BossProfileSoundInfo soundInfo; - GetChaserProfileChaseVisibleMusics(profile, soundInfo); - soundInfo.StopAllSounds(client); + SF2NPC_Chaser(i).GetProfileDataEx().GetVisibleChaseMusics().StopAllSounds(1, client); } } } } -void ClientMusicChaseSeeStart(int client,int bossIndex) +void ClientMusicChaseSeeStart(int client, int bossIndex) { if (!IsValidClient(client) || !IsPlayerAlive(client)) { @@ -1148,8 +1078,7 @@ void ClientMusicChaseSeeStart(int client,int bossIndex) NPCGetProfile(bossIndex, profile, sizeof(profile)); char buffer[PLATFORM_MAX_PATH]; - SF2BossProfileSoundInfo soundInfo; - GetChaserProfileChaseVisibleMusics(profile, soundInfo); + ProfileSound soundInfo = SF2NPC_Chaser(bossIndex).GetProfileDataEx().GetVisibleChaseMusics(); if (soundInfo.Paths != null && soundInfo.Paths.Length > 0) { soundInfo.Paths.GetString(GetRandomInt(0, soundInfo.Paths.Length - 1), buffer, sizeof(buffer)); @@ -1205,65 +1134,6 @@ void ClientMusicChaseSeeStop(int client,int bossIndex) TriggerTimer(g_PlayerChaseMusicSeeTimer[client][bossIndex], true); } -void Client90sMusicReset(int client) -{ - char oldMusic[PLATFORM_MAX_PATH]; - strcopy(oldMusic, sizeof(oldMusic), g_Player90sMusicString[client]); - g_Player90sMusicString[client][0] = '\0'; - if (IsValidClient(client) && oldMusic[0] != '\0') - { - StopSound(client, MUSIC_CHAN, oldMusic); - } - - g_Player90sMusicTimer[client] = null; - g_Player90sMusicVolumes[client] = 0.0; - - if (IsValidClient(client)) - { - oldMusic = NINETYSMUSIC; - if (oldMusic[0] != '\0') - { - StopSound(client, MUSIC_CHAN, oldMusic); - } - } -} - -void Client90sMusicStart(int client) -{ - if (!IsValidClient(client) || !IsPlayerAlive(client)) - { - return; - } - - char buffer[PLATFORM_MAX_PATH]; - buffer = NINETYSMUSIC; - - if (buffer[0] == '\0') - { - return; - } - - strcopy(g_Player90sMusicString[client], sizeof(g_Player90sMusicString[]), buffer); - g_Player90sMusicTimer[client] = CreateTimer(0.01, Timer_PlayerFadeIn90sMusic, GetClientUserId(client), TIMER_REPEAT|TIMER_FLAG_NO_MAPCHANGE); - TriggerTimer(g_Player90sMusicTimer[client], true); -} - -void Client90sMusicStop(int client) -{ - if (!IsValidClient(client)) - { - return; - } - - if (!IsClientSprinting(client)) - { - g_Player90sMusicString[client][0] = '\0'; - } - - g_Player90sMusicTimer[client]= CreateTimer(0.01, Timer_PlayerFadeOut90sMusic, GetClientUserId(client), TIMER_REPEAT|TIMER_FLAG_NO_MAPCHANGE); - TriggerTimer(g_Player90sMusicTimer[client], true); -} - Action Timer_PlayerFadeInMusic(Handle timer, any userid) { int client = GetClientOfUserId(userid); @@ -1353,10 +1223,13 @@ Action Timer_PlayerFadeInAlertMusic(Handle timer, any userid) return Plugin_Stop; } - SF2ChaserBossProfileData data; - data = NPCChaserGetProfileData(bossIndex); - SF2BossProfileSoundInfo info; - info = data.AlertMusics; + ChaserBossProfile data = SF2NPC_Chaser(bossIndex).GetProfileDataEx(); + if (data == null) + { + StopSound(client, MUSIC_CHAN, g_PlayerAlertMusicString[client][bossIndex]); + return Plugin_Stop; + } + ProfileSound info = data.GetAlertMusics(); /*int oldBoss = g_PlayerAlertMusicOldMaster[client]; @@ -1375,7 +1248,7 @@ Action Timer_PlayerFadeInAlertMusic(Handle timer, any userid) if (g_PlayerAlertMusicString[client][bossIndex][0] != '\0') { - EmitSoundToClient(client, g_PlayerAlertMusicString[client][bossIndex], _, MUSIC_CHAN, _, SND_CHANGEVOL, g_PlayerAlertMusicVolumes[client][bossIndex] * info.Volume * g_PlayerPreferences[client].PlayerPreference_MusicVolume, info.Pitch); + EmitSoundToClient(client, g_PlayerAlertMusicString[client][bossIndex], _, MUSIC_CHAN, _, SND_CHANGEVOL, g_PlayerAlertMusicVolumes[client][bossIndex] * info.GetVolume(GetLocalGlobalDifficulty(bossIndex)) * g_PlayerPreferences[client].PlayerPreference_MusicVolume, info.GetPitch(GetLocalGlobalDifficulty(bossIndex))); } if (g_PlayerAlertMusicVolumes[client][bossIndex] >= 1.0) @@ -1410,10 +1283,13 @@ Action Timer_PlayerFadeOutAlertMusic(Handle timer, any userid) return Plugin_Stop; } - SF2ChaserBossProfileData data; - data = NPCChaserGetProfileData(bossIndex); - SF2BossProfileSoundInfo info; - info = data.AlertMusics; + ChaserBossProfile data = SF2NPC_Chaser(bossIndex).GetProfileDataEx(); + if (data == null) + { + StopSound(client, MUSIC_CHAN, g_PlayerAlertMusicString[client][bossIndex]); + return Plugin_Stop; + } + ProfileSound info = data.GetAlertMusics(); int oldBoss = g_PlayerAlertMusicOldMaster[client]; int newBoss = g_PlayerAlertMusicMaster[client]; @@ -1435,7 +1311,7 @@ Action Timer_PlayerFadeOutAlertMusic(Handle timer, any userid) if (g_PlayerAlertMusicString[client][bossIndex][0] != '\0') { - EmitSoundToClient(client, g_PlayerAlertMusicString[client][bossIndex], _, MUSIC_CHAN, _, SND_CHANGEVOL, g_PlayerAlertMusicVolumes[client][bossIndex] * info.Volume * g_PlayerPreferences[client].PlayerPreference_MusicVolume, info.Pitch); + EmitSoundToClient(client, g_PlayerAlertMusicString[client][bossIndex], _, MUSIC_CHAN, _, SND_CHANGEVOL, g_PlayerAlertMusicVolumes[client][bossIndex] * info.GetVolume(GetLocalGlobalDifficulty(bossIndex)) * g_PlayerPreferences[client].PlayerPreference_MusicVolume, info.GetPitch(GetLocalGlobalDifficulty(bossIndex))); } if (g_PlayerAlertMusicVolumes[client][bossIndex] <= 0.0) @@ -1472,10 +1348,13 @@ Action Timer_PlayerFadeInIdleMusic(Handle timer, any userid) return Plugin_Stop; } - SF2ChaserBossProfileData data; - data = NPCChaserGetProfileData(bossIndex); - SF2BossProfileSoundInfo info; - info = data.IdleMusics; + ChaserBossProfile data = SF2NPC_Chaser(bossIndex).GetProfileDataEx(); + if (data == null) + { + StopSound(client, MUSIC_CHAN, g_PlayerIdleMusicString[client][bossIndex]); + return Plugin_Stop; + } + ProfileSound info = data.GetIdleMusics(); /*int oldBoss = g_PlayerIdleMusicOldMaster[client]; @@ -1494,7 +1373,7 @@ Action Timer_PlayerFadeInIdleMusic(Handle timer, any userid) if (g_PlayerIdleMusicString[client][bossIndex][0] != '\0') { - EmitSoundToClient(client, g_PlayerIdleMusicString[client][bossIndex], _, MUSIC_CHAN, _, SND_CHANGEVOL, g_PlayerIdleMusicVolumes[client][bossIndex] * info.Volume * g_PlayerPreferences[client].PlayerPreference_MusicVolume, info.Pitch); + EmitSoundToClient(client, g_PlayerIdleMusicString[client][bossIndex], _, MUSIC_CHAN, _, SND_CHANGEVOL, g_PlayerIdleMusicVolumes[client][bossIndex] * info.GetVolume(GetLocalGlobalDifficulty(bossIndex)) * g_PlayerPreferences[client].PlayerPreference_MusicVolume, info.GetPitch(GetLocalGlobalDifficulty(bossIndex))); } if (g_PlayerIdleMusicVolumes[client][bossIndex] >= 1.0) @@ -1529,10 +1408,13 @@ Action Timer_PlayerFadeOutIdleMusic(Handle timer, any userid) return Plugin_Stop; } - SF2ChaserBossProfileData data; - data = NPCChaserGetProfileData(bossIndex); - SF2BossProfileSoundInfo info; - info = data.IdleMusics; + ChaserBossProfile data = SF2NPC_Chaser(bossIndex).GetProfileDataEx(); + if (data == null) + { + StopSound(client, MUSIC_CHAN, g_PlayerIdleMusicString[client][bossIndex]); + return Plugin_Stop; + } + ProfileSound info = data.GetIdleMusics(); int oldBoss = g_PlayerIdleMusicOldMaster[client]; int newBoss = g_PlayerIdleMusicMaster[client]; @@ -1554,7 +1436,7 @@ Action Timer_PlayerFadeOutIdleMusic(Handle timer, any userid) if (g_PlayerIdleMusicString[client][bossIndex][0] != '\0') { - EmitSoundToClient(client, g_PlayerIdleMusicString[client][bossIndex], _, MUSIC_CHAN, _, SND_CHANGEVOL, g_PlayerIdleMusicVolumes[client][bossIndex] * info.Volume * g_PlayerPreferences[client].PlayerPreference_MusicVolume, info.Pitch); + EmitSoundToClient(client, g_PlayerIdleMusicString[client][bossIndex], _, MUSIC_CHAN, _, SND_CHANGEVOL, g_PlayerIdleMusicVolumes[client][bossIndex] * info.GetVolume(GetLocalGlobalDifficulty(bossIndex)) * g_PlayerPreferences[client].PlayerPreference_MusicVolume, info.GetPitch(GetLocalGlobalDifficulty(bossIndex))); } if (g_PlayerIdleMusicVolumes[client][bossIndex] <= 0.0) @@ -1591,10 +1473,13 @@ Action Timer_PlayerFadeInChaseMusic(Handle timer, any userid) return Plugin_Stop; } - SF2ChaserBossProfileData data; - data = NPCChaserGetProfileData(bossIndex); - SF2BossProfileSoundInfo info; - info = data.ChaseMusics; + ChaserBossProfile data = SF2NPC_Chaser(bossIndex).GetProfileDataEx(); + if (data == null) + { + StopSound(client, MUSIC_CHAN, g_PlayerChaseMusicString[client][bossIndex]); + return Plugin_Stop; + } + ProfileSound info = data.GetChaseMusics(); /*int oldBoss = g_PlayerChaseMusicOldMaster[client]; @@ -1613,7 +1498,7 @@ Action Timer_PlayerFadeInChaseMusic(Handle timer, any userid) if (g_PlayerChaseMusicString[client][bossIndex][0] != '\0') { - EmitSoundToClient(client, g_PlayerChaseMusicString[client][bossIndex], _, MUSIC_CHAN, _, SND_CHANGEVOL, g_PlayerChaseMusicVolumes[client][bossIndex] * info.Volume * g_PlayerPreferences[client].PlayerPreference_MusicVolume, info.Pitch); + EmitSoundToClient(client, g_PlayerChaseMusicString[client][bossIndex], _, MUSIC_CHAN, _, SND_CHANGEVOL, g_PlayerChaseMusicVolumes[client][bossIndex] * info.GetVolume(GetLocalGlobalDifficulty(bossIndex)) * g_PlayerPreferences[client].PlayerPreference_MusicVolume, info.GetPitch(GetLocalGlobalDifficulty(bossIndex))); } if (g_PlayerChaseMusicVolumes[client][bossIndex] >= 1.0) @@ -1648,10 +1533,13 @@ Action Timer_PlayerFadeInChaseMusicSee(Handle timer, any userid) return Plugin_Stop; } - SF2ChaserBossProfileData data; - data = NPCChaserGetProfileData(bossIndex); - SF2BossProfileSoundInfo info; - info = data.ChaseVisibleMusics; + ChaserBossProfile data = SF2NPC_Chaser(bossIndex).GetProfileDataEx(); + if (data == null) + { + StopSound(client, MUSIC_CHAN, g_PlayerChaseMusicSeeString[client][bossIndex]); + return Plugin_Stop; + } + ProfileSound info = data.GetVisibleChaseMusics(); /*int oldBoss = g_PlayerChaseMusicSeeOldMaster[client]; @@ -1670,7 +1558,7 @@ Action Timer_PlayerFadeInChaseMusicSee(Handle timer, any userid) if (g_PlayerChaseMusicSeeString[client][bossIndex][0] != '\0') { - EmitSoundToClient(client, g_PlayerChaseMusicSeeString[client][bossIndex], _, MUSIC_CHAN, _, SND_CHANGEVOL, g_PlayerChaseMusicSeeVolumes[client][bossIndex] * info.Volume * g_PlayerPreferences[client].PlayerPreference_MusicVolume, info.Pitch); + EmitSoundToClient(client, g_PlayerChaseMusicSeeString[client][bossIndex], _, MUSIC_CHAN, _, SND_CHANGEVOL, g_PlayerChaseMusicSeeVolumes[client][bossIndex] * info.GetVolume(GetLocalGlobalDifficulty(bossIndex)) * g_PlayerPreferences[client].PlayerPreference_MusicVolume, info.GetPitch(GetLocalGlobalDifficulty(bossIndex))); } if (g_PlayerChaseMusicSeeVolumes[client][bossIndex] >= 1.0) @@ -1705,10 +1593,13 @@ Action Timer_PlayerFadeOutChaseMusic(Handle timer, any userid) return Plugin_Stop; } - SF2ChaserBossProfileData data; - data = NPCChaserGetProfileData(bossIndex); - SF2BossProfileSoundInfo info; - info = data.ChaseMusics; + ChaserBossProfile data = SF2NPC_Chaser(bossIndex).GetProfileDataEx(); + if (data == null) + { + StopSound(client, MUSIC_CHAN, g_PlayerChaseMusicString[client][bossIndex]); + return Plugin_Stop; + } + ProfileSound info = data.GetChaseMusics(); int oldBoss = g_PlayerChaseMusicOldMaster[client]; int newBoss = g_PlayerChaseMusicMaster[client]; @@ -1730,7 +1621,7 @@ Action Timer_PlayerFadeOutChaseMusic(Handle timer, any userid) if (g_PlayerChaseMusicString[client][bossIndex][0] != '\0') { - EmitSoundToClient(client, g_PlayerChaseMusicString[client][bossIndex], _, MUSIC_CHAN, _, SND_CHANGEVOL, g_PlayerChaseMusicVolumes[client][bossIndex] * info.Volume * g_PlayerPreferences[client].PlayerPreference_MusicVolume, info.Pitch); + EmitSoundToClient(client, g_PlayerChaseMusicString[client][bossIndex], _, MUSIC_CHAN, _, SND_CHANGEVOL, g_PlayerChaseMusicVolumes[client][bossIndex] * info.GetVolume(GetLocalGlobalDifficulty(bossIndex)) * g_PlayerPreferences[client].PlayerPreference_MusicVolume, info.GetPitch(GetLocalGlobalDifficulty(bossIndex))); } if (g_PlayerChaseMusicVolumes[client][bossIndex] <= 0.0) @@ -1767,10 +1658,13 @@ Action Timer_PlayerFadeOutChaseMusicSee(Handle timer, any userid) return Plugin_Stop; } - SF2ChaserBossProfileData data; - data = NPCChaserGetProfileData(bossIndex); - SF2BossProfileSoundInfo info; - info = data.ChaseVisibleMusics; + ChaserBossProfile data = SF2NPC_Chaser(bossIndex).GetProfileDataEx(); + if (data == null) + { + StopSound(client, MUSIC_CHAN, g_PlayerChaseMusicSeeString[client][bossIndex]); + return Plugin_Stop; + } + ProfileSound info = data.GetVisibleChaseMusics(); int oldBoss = g_PlayerChaseMusicSeeOldMaster[client]; int newBoss = g_PlayerChaseMusicSeeMaster[client]; @@ -1792,7 +1686,7 @@ Action Timer_PlayerFadeOutChaseMusicSee(Handle timer, any userid) if (g_PlayerChaseMusicSeeString[client][bossIndex][0] != '\0') { - EmitSoundToClient(client, g_PlayerChaseMusicSeeString[client][bossIndex], _, MUSIC_CHAN, _, SND_CHANGEVOL, g_PlayerChaseMusicSeeVolumes[client][bossIndex] * info.Volume * g_PlayerPreferences[client].PlayerPreference_MusicVolume, info.Pitch); + EmitSoundToClient(client, g_PlayerChaseMusicSeeString[client][bossIndex], _, MUSIC_CHAN, _, SND_CHANGEVOL, g_PlayerChaseMusicSeeVolumes[client][bossIndex] * info.GetVolume(GetLocalGlobalDifficulty(bossIndex)) * g_PlayerPreferences[client].PlayerPreference_MusicVolume, info.GetPitch(GetLocalGlobalDifficulty(bossIndex))); } if (g_PlayerChaseMusicSeeVolumes[client][bossIndex] <= 0.0) @@ -1806,81 +1700,6 @@ Action Timer_PlayerFadeOutChaseMusicSee(Handle timer, any userid) return Plugin_Continue; } -Action Timer_PlayerFadeIn90sMusic(Handle timer, any userid) -{ - int client = GetClientOfUserId(userid); - if (client <= 0) - { - return Plugin_Stop; - } - - if (g_Player90sMusicTimer[client] != timer) - { - return Plugin_Stop; - } - - g_Player90sMusicVolumes[client] += 0.28; - if (g_Player90sMusicVolumes[client] > 0.5) - { - g_Player90sMusicVolumes[client] = 0.5; - } - - if (g_Player90sMusicString[client][0] != '\0') - { - EmitSoundToClient(client, g_Player90sMusicString[client], _, MUSIC_CHAN, _, SND_CHANGEVOL, g_Player90sMusicVolumes[client] * g_PlayerPreferences[client].PlayerPreference_MusicVolume, 100); - } - - if (g_Player90sMusicVolumes[client] >= 0.5) - { - g_Player90sMusicTimer[client] = null; - return Plugin_Stop; - } - - return Plugin_Continue; -} - -Action Timer_PlayerFadeOut90sMusic(Handle timer, any userid) -{ - int client = GetClientOfUserId(userid); - if (client <= 0) - { - return Plugin_Stop; - } - - if (g_Player90sMusicTimer[client] != timer) - { - return Plugin_Stop; - } - - char buffer[PLATFORM_MAX_PATH]; - buffer = NINETYSMUSIC; - - if (strcmp(buffer, g_Player90sMusicString[client], false) == 0) - { - g_Player90sMusicTimer[client] = null; - return Plugin_Stop; - } - - g_Player90sMusicVolumes[client] -= 0.28; - if (g_Player90sMusicVolumes[client] < 0.0) - { - g_Player90sMusicVolumes[client] = 0.0; - } - - if (buffer[0] != '\0') - { - EmitSoundToClient(client, buffer, _, MUSIC_CHAN, _, SND_CHANGEVOL, g_Player90sMusicVolumes[client] * g_PlayerPreferences[client].PlayerPreference_MusicVolume, 100); - } - - if (g_Player90sMusicVolumes[client] <= 0.0) - { - g_Player90sMusicTimer[client] = null; - return Plugin_Stop; - } - - return Plugin_Continue; -} - bool ClientHasMusicFlag(int client, int flag) { return (g_PlayerMusicFlags[client] & flag) != 0; diff --git a/addons/sourcemod/scripting/sf2/client/peek.sp b/addons/sourcemod/scripting/sf2/client/peek.sp index b191ee64..39b6561a 100644 --- a/addons/sourcemod/scripting/sf2/client/peek.sp +++ b/addons/sourcemod/scripting/sf2/client/peek.sp @@ -1,4 +1,5 @@ #pragma semicolon 1 +#pragma newdecls required //Peeking Data bool g_PlayerPeeking[MAXTF2PLAYERS] = { false, ... }; diff --git a/addons/sourcemod/scripting/sf2/client/proxy.sp b/addons/sourcemod/scripting/sf2/client/proxy.sp index 495ed120..50c4850d 100644 --- a/addons/sourcemod/scripting/sf2/client/proxy.sp +++ b/addons/sourcemod/scripting/sf2/client/proxy.sp @@ -4,6 +4,580 @@ #define _sf2_client_proxy_functions_included #pragma semicolon 1 +#pragma newdecls required + +methodmap BossProfileProxyData < ProfileObject +{ + public bool IsEnabled(int difficulty) + { + if (this == null) + { + return false; + } + return this.GetDifficultyBool("enabled", difficulty, true); + } + + public int GetMaxProxies(int difficulty) + { + return this.GetDifficultyInt("__proxies_max", difficulty); + } + + public void SetMaxProxies(int difficulty, int value) + { + this.SetDifficultyInt("__proxies_max", difficulty, value); + } + + public float GetMinSpawnChance(int difficulty) + { + return this.GetDifficultyFloat("spawn_chance_min", difficulty, 0.0); + } + + public float GetMaxSpawnChance(int difficulty) + { + return this.GetDifficultyFloat("spawn_chance_max", difficulty, 0.0); + } + + public float GetSpawnChanceThreshold(int difficulty) + { + return this.GetDifficultyFloat("spawn_chance_threshold", difficulty, 0.25); + } + + public int GetMinSpawnedProxies(int difficulty) + { + return this.GetDifficultyInt("spawn_num_min", difficulty, 0); + } + + public int GetMaxSpawnedProxies(int difficulty) + { + return this.GetDifficultyInt("spawn_num_max", difficulty, 0); + } + + public float GetMinSpawnCooldown(int difficulty) + { + return this.GetDifficultyFloat("spawn_cooldown_min", difficulty, 4.0); + } + + public float GetMaxSpawnCooldown(int difficulty) + { + return this.GetDifficultyFloat("spawn_cooldown_max", difficulty, 8.0); + } + + public float GetMinTeleportRange(int difficulty) + { + return this.GetDifficultyFloat("spawn_range_min", difficulty, 500.0); + } + + public float GetMaxTeleportRange(int difficulty) + { + return this.GetDifficultyFloat("spawn_range_max", difficulty, 3200.0); + } + + public BossProfileProxyClass GetDefaultClassData() + { + ProfileObject obj = this.GetSection("classes"); + if (obj == null) + { + return null; + } + + return view_as(obj.GetSection("default")); + } + + public BossProfileProxyClass GetClassData(TFClassType class) + { + ProfileObject obj = this.GetSection("classes"); + if (obj == null) + { + return null; + } + + switch (class) + { + case TFClass_Scout: + { + return view_as(obj.GetSection("scout")); + } + case TFClass_Soldier: + { + return view_as(obj.GetSection("soldier")); + } + case TFClass_Pyro: + { + return view_as(obj.GetSection("pyro")); + } + case TFClass_DemoMan: + { + return view_as(obj.GetSection("demoman")); + } + case TFClass_Heavy: + { + return view_as(obj.GetSection("heavy")); + } + case TFClass_Engineer: + { + return view_as(obj.GetSection("engineer")); + } + case TFClass_Medic: + { + return view_as(obj.GetSection("medic")); + } + case TFClass_Sniper: + { + return view_as(obj.GetSection("sniper")); + } + case TFClass_Spy: + { + return view_as(obj.GetSection("spy")); + } + } + + return null; + } + + public void Precache() + { + BossProfileProxyClass classData = this.GetDefaultClassData(); + if (classData != null) + { + classData.Precache(); + } + + for (int i = view_as(TFClass_Scout); i <= view_as(TFClass_Engineer); i++) + { + TFClassType class = view_as(i); + classData = this.GetClassData(class); + if (classData != null) + { + classData.Precache(); + } + + for (int i2 = 0; i2 < Difficulty_Max; i2++) + { + int max = this.GetMaxProxies(i2); + if (classData.GetMax(i2) >= 0) + { + max += classData.GetMax(i2); + this.SetMaxProxies(i2, max); + } + } + } + } +} + +methodmap BossProfileProxyClass < ProfileObject +{ + public BossProfileProxyClass GetDefaultClassData() + { + BossProfileProxyData parent = view_as(this.Parent); + return parent.GetDefaultClassData(); + } + + public void GetModel(int difficulty, char[] buffer, int bufferSize, const char[] defaultValue = "") + { + BossProfileProxyClass def = this.GetDefaultClassData(); + if (def != null && def != this) + { + def.GetModel(difficulty, buffer, bufferSize, defaultValue); + } + + this.GetDifficultyString("model", difficulty, buffer, bufferSize, buffer); + } + + public int GetMax(int difficulty, int defValue = 8) + { + BossProfileProxyClass def = this.GetDefaultClassData(); + if (def != null && def != this) + { + defValue = def.GetDifficultyInt("max", difficulty, defValue); + } + + return this.GetDifficultyInt("max", difficulty, defValue); + } + + public float GetWeight(int difficulty, float defValue = 1.0) + { + BossProfileProxyClass def = this.GetDefaultClassData(); + if (def != null && def != this) + { + defValue = def.GetDifficultyFloat("weight", difficulty, defValue); + } + + return this.GetDifficultyFloat("weight", difficulty, defValue); + } + + public int GetHealth(int difficulty, int defValue = 0) + { + BossProfileProxyClass def = this.GetDefaultClassData(); + if (def != null && def != this) + { + defValue = def.GetDifficultyInt("health", difficulty, defValue); + } + + return this.GetDifficultyInt("health", difficulty, defValue); + } + + public float GetWalkSpeed(int difficulty, float defValue = 150.0) + { + BossProfileProxyClass def = this.GetDefaultClassData(); + if (def != null && def != this) + { + defValue = def.GetDifficultyFloat("walkspeed", difficulty, defValue); + } + + return this.GetDifficultyFloat("walkspeed", difficulty, defValue); + } + + public float GetRunSpeed(int difficulty, float defValue = 300.0) + { + BossProfileProxyClass def = this.GetDefaultClassData(); + if (def != null && def != this) + { + defValue = def.GetDifficultyFloat("runspeed", difficulty, defValue); + } + + return this.GetDifficultyFloat("runspeed", difficulty, defValue); + } + + public float GetDamageScale(int difficulty, float defValue = 1.0) + { + BossProfileProxyClass def = this.GetDefaultClassData(); + if (def != null && def != this) + { + defValue = def.GetDifficultyFloat("damage_scale", difficulty, defValue); + } + + return this.GetDifficultyFloat("damage_scale", difficulty, defValue); + } + + public float GetSelfDamageScale(int difficulty, float defValue = 1.0) + { + BossProfileProxyClass def = this.GetDefaultClassData(); + if (def != null && def != this) + { + defValue = def.GetDifficultyFloat("self_damage_scale", difficulty, defValue); + } + + return this.GetDifficultyFloat("self_damage_scale", difficulty, defValue); + } + + public float GetBackstabDamageScale(int difficulty, float defValue = 0.2) + { + BossProfileProxyClass def = this.GetDefaultClassData(); + if (def != null && def != this) + { + defValue = def.GetDifficultyFloat("backstab_damage_scale", difficulty, defValue); + } + + return this.GetDifficultyFloat("backstab_damage_scale", difficulty, defValue); + } + + public bool AllowVoices(bool defValue = false) + { + BossProfileProxyClass def = this.GetDefaultClassData(); + if (def != null && def != this) + { + defValue = def.GetBool("allow_voices", defValue); + } + + return this.GetBool("allow_voices", defValue); + } + + public bool Zombies(bool defValue = false) + { + BossProfileProxyClass def = this.GetDefaultClassData(); + if (def != null && def != this) + { + defValue = def.GetBool("zombie", defValue); + } + + return this.GetBool("zombie", defValue); + } + + public bool Robots(bool defValue = false) + { + BossProfileProxyClass def = this.GetDefaultClassData(); + if (def != null && def != this) + { + defValue = def.GetBool("robot", defValue); + } + + return this.GetBool("robot", defValue); + } + + public float GetControlDrainRate(int difficulty, float defValue = 0.0) + { + float value = defValue; + + BossProfileProxyClass def = this.GetDefaultClassData(); + if (def != null && def != this) + { + value = def.GetControlDrainRate(difficulty, value); + } + + ProfileObject obj = this.GetSection("control"); + if (obj != null) + { + value = obj.GetDifficultyFloat("level", difficulty, value); + } + + return value; + } + + public int GetControlGainHitEnemy(int difficulty, int defValue = 0) + { + int value = defValue; + + BossProfileProxyClass def = this.GetDefaultClassData(); + if (def != null && def != this) + { + value = def.GetControlGainHitEnemy(difficulty, value); + } + + ProfileObject obj = this.GetSection("control"); + if (obj != null) + { + value = obj.GetDifficultyInt("hit_enemy", difficulty, value); + } + + return value; + } + + public int GetControlGainHitByEnemy(int difficulty, int defValue = 0) + { + int value = defValue; + + BossProfileProxyClass def = this.GetDefaultClassData(); + if (def != null && def != this) + { + value = def.GetControlGainHitByEnemy(difficulty, value); + } + + ProfileObject obj = this.GetSection("control"); + if (obj != null) + { + value = obj.GetDifficultyInt("hit_by_enemy", difficulty, value); + } + + return value; + } + + public ProfileSound GetSpawnSounds() + { + ProfileSound value = null; + + BossProfileProxyClass def = this.GetDefaultClassData(); + if (def != null && def != this) + { + value = def.GetSpawnSounds(); + } + + ProfileObject obj = this.GetSection("sounds"); + if (obj != null) + { + value = view_as(obj.GetSection("spawn")); + } + + return value; + } + + public ProfileSound GetIdleSounds() + { + ProfileSound value = null; + + BossProfileProxyClass def = this.GetDefaultClassData(); + if (def != null && def != this) + { + value = def.GetIdleSounds(); + } + + ProfileObject obj = this.GetSection("sounds"); + if (obj != null) + { + value = view_as(obj.GetSection("idle")); + } + + return value; + } + + public ProfileSound GetHurtSounds() + { + ProfileSound value = null; + + BossProfileProxyClass def = this.GetDefaultClassData(); + if (def != null && def != this) + { + value = def.GetHurtSounds(); + } + + ProfileObject obj = this.GetSection("sounds"); + if (obj != null) + { + value = view_as(obj.GetSection("hurt")); + } + + return value; + } + + public ProfileSound GetDeathSounds() + { + ProfileSound value = null; + + BossProfileProxyClass def = this.GetDefaultClassData(); + if (def != null && def != this) + { + value = def.GetDeathSounds(); + } + + ProfileObject obj = this.GetSection("sounds"); + if (obj != null) + { + value = view_as(obj.GetSection("death")); + } + + return value; + } + + public KeyMap_Array GetDeathAnimations() + { + KeyMap_Array value = null; + BossProfileProxyClass def = this.GetDefaultClassData(); + if (def != null && def != this) + { + value = def.GetArray("death_animations", value); + } + + return this.GetArray("death_animations", value); + } + + public BossProfileProxyWeapon GetWeapon(int weaponSlot) + { + ProfileObject value = null; + + BossProfileProxyClass def = this.GetDefaultClassData(); + if (def != null && def != this) + { + value = def.GetWeapon(weaponSlot); + } + + ProfileObject obj = this.GetSection("weapons"); + if (obj != null) + { + value = obj.GetSection("death"); + switch (weaponSlot) + { + case TFWeaponSlot_Primary: + { + value = obj.GetSection("primary"); + } + + case TFWeaponSlot_Secondary: + { + value = obj.GetSection("secondary"); + } + + case TFWeaponSlot_Melee: + { + value = obj.GetSection("melee"); + } + + case TFWeaponSlot_Grenade: // Yes, this is the fucking building PDA and the disguise kit + { + value = obj.GetSection("pda_build"); + value = obj.GetSection("disguise", value); + } + + case TFWeaponSlot_Building: // Yes, this is the fucking destruction PDA and the invis watch + { + value = obj.GetSection("pda_destroy"); + value = obj.GetSection("invis_watch", value); + } + } + } + + return view_as(value); + } + + public KeyMap_Array GetSpawnEffects() + { + KeyMap_Array value = null; + BossProfileProxyClass def = this.GetDefaultClassData(); + if (def != null && def != this) + { + value = def.GetArray("spawn_effects", value); + } + + return this.GetArray("spawn_effects", value); + } + + public void Precache() + { + char path[PLATFORM_MAX_PATH]; + for (int i = 0; i < Difficulty_Max; i++) + { + this.GetModel(i, path, sizeof(path)); + if (path[0] != '\0') + { + PrecacheModel2(path, _, _, g_FileCheckConVar.BoolValue); + } + } + + this.ConvertSectionsSectionToArray("spawn_effects"); + this.ConvertSectionsSectionToArray("death_animations"); + + if (this.GetSpawnSounds() != null) + { + this.GetSpawnSounds().Precache(); + } + + if (this.GetIdleSounds() != null) + { + this.GetIdleSounds().Precache(); + } + + if (this.GetHurtSounds() != null) + { + this.GetHurtSounds().Precache(); + } + + if (this.GetDeathSounds() != null) + { + this.GetDeathSounds().Precache(); + } + } +} + +methodmap BossProfileProxyWeapon < ProfileObject +{ + public void GetClassname(int difficulty, char[] buffer, int bufferSize) + { + this.GetDifficultyString("classname", difficulty, buffer, bufferSize); + } + + public int GetIndex(int difficulty) + { + return this.GetDifficultyInt("index", difficulty, -1); + } + + public void GetAttributes(int difficulty, char[] buffer, int bufferSize) + { + this.GetDifficultyString("stats", difficulty, buffer, bufferSize); + } + + public int GetLevel(int difficulty) + { + return this.GetDifficultyInt("level", difficulty, 0); + } + + public int GetQuality(int difficulty) + { + return this.GetDifficultyInt("quality", difficulty, 0); + } + + public bool ShouldPreserveAttributes(int difficulty) + { + return this.GetDifficultyBool("preserve_default_attributes", difficulty, true); + } +} static int g_ActionItemIndexes[] = { 57, 231 }; @@ -22,6 +596,7 @@ void SetupProxy() g_OnPlayerSpawnPFwd.AddFunction(null, OnPlayerSpawn); g_OnPlayerDeathPFwd.AddFunction(null, OnPlayerDeath); g_OnPlayerEscapePFwd.AddFunction(null, OnPlayerEscape); + g_OnPlayerTakeDamagePFwd.AddFunction(null, OnPlayerTakeDamage); AddNormalSoundHook(Hook_ProxySoundHook); } @@ -44,6 +619,7 @@ static void OnPutInServer(SF2_BasePlayer client) } ClientResetProxy(client.index); ClientStartProxyAvailableTimer(client.index); + SDKHook(client.index, SDKHook_PreThinkPost, ProxyThink); } static void OnDisconnected(SF2_BasePlayer client) @@ -81,9 +657,9 @@ static void OnPlayerDeath(SF2_BasePlayer client) char profile[SF2_MAX_PROFILE_NAME_LENGTH]; NPCGetProfile(proxyMaster, profile, sizeof(profile)); - SF2BossProfileSoundInfo soundInfo; - GetBossProfileProxyDeathSounds(profile, soundInfo); - soundInfo.EmitSound(_, client.index); + BossProfileProxyData proxyData = GetBossProfile(profile).GetProxies(); + BossProfileProxyClass classData = proxyData.GetClassData(client.Class); + classData.GetDeathSounds().EmitSound(_, client.index); } CreateTimer(0.1, Timer_ResetProxy, client.UserID, TIMER_FLAG_NO_MAPCHANGE); @@ -106,6 +682,177 @@ static void OnPlayerEscape(SF2_BasePlayer client) ClientResetProxy(client.index); } +static Action OnPlayerTakeDamage(SF2_BasePlayer client, int &attacker, int &inflictor, float &damage, int &damageType, int damageCustom) +{ + SF2_BasePlayer attackerPlayer = SF2_BasePlayer(attacker); + if (!attackerPlayer.IsValid) + { + return Plugin_Continue; + } + + if (attackerPlayer.index == client.index) + { + return Plugin_Continue; + } + + if (client.IsProxy || attackerPlayer.IsProxy) + { + if (client.IsEliminated && attackerPlayer.IsEliminated) + { + damage = 0.0; + return Plugin_Changed; + } + + BossProfileProxyData proxyData; + BossProfileProxyClass classData; + if (attackerPlayer.IsProxy) + { + int maxHealth = attackerPlayer.MaxHealth; + SF2NPC_BaseNPC master = SF2NPC_BaseNPC(attackerPlayer.ProxyMaster); + if (master.IsValid()) + { + proxyData = master.GetProfileDataEx().GetProxies(); + classData = proxyData.GetClassData(attackerPlayer.Class); + int difficulty = master.Difficulty; + + if (damageCustom == TF_CUSTOM_TAUNT_GRAND_SLAM || + damageCustom == TF_CUSTOM_TAUNT_FENCING || + damageCustom == TF_CUSTOM_TAUNT_ARROW_STAB || + damageCustom == TF_CUSTOM_TAUNT_GRENADE || + damageCustom == TF_CUSTOM_TAUNT_BARBARIAN_SWING || + damageCustom == TF_CUSTOM_TAUNT_ENGINEER_ARM || + damageCustom == TF_CUSTOM_TAUNT_ARMAGEDDON) + { + if (damage >= float(maxHealth)) + { + damage = float(maxHealth) * 0.5; + } + else + { + damage = 0.0; + } + } + else if (damageCustom == TF_CUSTOM_BACKSTAB) // Modify backstab damage. + { + damage = float(maxHealth) * classData.GetBackstabDamageScale(difficulty); + if (damageType & DMG_ACID) + { + damage /= 2.0; + } + } + + attackerPlayer.ProxyControl += classData.GetControlGainHitEnemy(difficulty); + + float originalPercentage = classData.GetDamageScale(difficulty); + float additionPercentage = 0.15; + if (!IsClassConfigsValid()) + { + if (client.Class == TFClass_Medic) + { + damage *= (originalPercentage + additionPercentage); + } + else + { + damage *= originalPercentage; + } + } + else + { + damage *= originalPercentage + g_ClassProxyDamageVulnerability[view_as(client.Class)]; + } + } + return Plugin_Changed; + } + else if (client.IsProxy) + { + SF2NPC_BaseNPC master = SF2NPC_BaseNPC(client.ProxyMaster); + if (master.IsValid()) + { + proxyData = master.GetProfileDataEx().GetProxies(); + classData = proxyData.GetClassData(client.Class); + int difficulty = master.Difficulty; + + client.ProxyControl += classData.GetControlGainHitByEnemy(difficulty); + + damage *= classData.GetSelfDamageScale(difficulty); + if (classData.GetHurtSounds() != null) + { + classData.GetHurtSounds().EmitSound(_, client.index); + } + + if (damage * (damageType & DMG_CRIT ? 3.0 : 1.0) >= float(client.Health) && !client.InCondition(TFCond_FreezeInput)) // The proxy is about to die + { + char buffer[PLATFORM_MAX_PATH]; + KeyMap_Array array = classData.GetDeathAnimations(); + ProfileAnimation animation = null; + if (array != null && array.Length > 0) + { + animation = view_as(array.GetSection(GetRandomInt(0, array.Length - 1))); + } + if (animation != null) + { + animation.GetAnimationName(difficulty, buffer, sizeof(buffer)); + if (buffer[0] != '\0') + { + g_ClientMaxFrameDeathAnim[client.index] = animation.GetDifficultyInt("frames", difficulty, 0); + if (g_ClientMaxFrameDeathAnim[client.index] > 0) + { + // Cancel out any other taunts. + if (client.InCondition(TFCond_Taunting)) + { + client.ChangeCondition(TFCond_Taunting, true); + } + //The model has a death anim play it. + SDK_PlaySpecificSequence(client.index, buffer); + g_ClientFrame[client.index] = 0; + RequestFrame(ProxyDeathAnimation, client.index); + client.ChangeCondition(TFCond_FreezeInput, _, 5.0); + //Prevent death, and show the damage to the attacker. + client.ChangeCondition(TFCond_PreventDeath, _, 0.5); + return Plugin_Changed; + } + } + } + + // The player has no death anim leave him die. + } + } + return Plugin_Changed; + } + } + + return Plugin_Continue; +} + +static void ProxyThink(int client) +{ + SF2_BasePlayer player = SF2_BasePlayer(client); + if (!player.IsProxy) + { + return; + } + + SF2NPC_BaseNPC controller = SF2NPC_BaseNPC(player.ProxyMaster); + if (!controller.IsValid()) + { + return; + } + + int difficulty = controller.Difficulty; + TFClassType class = player.Class; + + BossProfileProxyData proxyData = controller.GetProfileDataEx().GetProxies(); + BossProfileProxyClass classData = proxyData.GetClassData(class); + + float speed = classData.GetRunSpeed(difficulty); + if (player.InCondition(TFCond_SpeedBuffAlly) || g_InProxySurvivalRageMode) + { + speed += 30.0; + } + + player.SetPropFloat(Prop_Send, "m_flMaxspeed", speed); +} + static Action Hook_ProxySoundHook(int clients[64], int &numClients, char sample[PLATFORM_MAX_PATH], int &entity, int &channel, float &volume, int &level, int &pitch, int &flags) { if (!g_Enabled) @@ -125,21 +872,23 @@ static Action Hook_ProxySoundHook(int clients[64], int &numClients, char sample[ return Plugin_Continue; } - SF2BossProfileData data; - data = NPCGetProfileData(master); + char profile[SF2_MAX_PROFILE_NAME_LENGTH]; + NPCGetProfile(master, profile, sizeof(profile)); + BossProfileProxyData proxyData = GetBossProfile(profile).GetProxies(); + BossProfileProxyClass classData = proxyData.GetClassData(client.Class); switch (channel) { case SNDCHAN_VOICE: { - if (!data.ProxyAllowVoices) + if (!classData.AllowVoices()) { return Plugin_Handled; } } } - if (data.ProxyRobots) + if (classData.Robots()) { switch (channel) { @@ -306,7 +1055,7 @@ Action Timer_ClientForceProxy(Handle timer, any userid) char profile[SF2_MAX_PROFILE_NAME_LENGTH]; NPCGetProfile(bossIndex, profile, sizeof(profile)); - int maxProxies = g_SlenderMaxProxies[bossIndex][difficulty]; + int maxProxies = GetBossProfile(profile).GetProxies().GetMaxProxies(difficulty); int numProxies = 0; for (int i = 1; i <= MaxClients; i++) @@ -404,7 +1153,7 @@ int Menu_ProxyAsk(Menu menu, MenuAction action, int param1, int param2) char profile[SF2_MAX_PROFILE_NAME_LENGTH]; NPCGetProfile(bossIndex, profile, sizeof(profile)); - int maxProxies = g_SlenderMaxProxies[bossIndex][difficulty]; + int maxProxies = GetBossProfile(profile).GetProxies().GetMaxProxies(difficulty); int numProxies; for (int client = 1; client <= MaxClients; client++) @@ -495,13 +1244,106 @@ Action Timer_ClientProxyAvailable(Handle timer, any userid) return Plugin_Stop; } +static TFClassType SelectProxyClass(SF2_BasePlayer client) +{ + SF2NPC_BaseNPC controller = SF2NPC_BaseNPC(client.ProxyMaster); + int difficulty = controller.Difficulty; + + BossProfileProxyData proxyData = controller.GetProfileDataEx().GetProxies(); + ArrayList allowed = new ArrayList(); + + int classCount[10] = { 0, ... }; + for (int otherIndex = 1; otherIndex <= MaxClients; otherIndex++) + { + SF2_BasePlayer other = SF2_BasePlayer(otherIndex); + if (other == client || !other.IsValid) + { + continue; + } + + if (other.IsProxy && other.ProxyMaster == controller.Index) + { + classCount[view_as(other.Class)]++; + } + } + + for (int classIndex = view_as(TFClass_Scout); classIndex <= view_as(TFClass_Engineer); classIndex++) + { + if (proxyData.GetClassData(view_as(classIndex)) == null) + { + continue; + } + + allowed.Push(view_as(classIndex)); + } + + if (allowed.Length == 0) + { + // If no classes specified then assume all classes. + // We really don't have a choice here anyway. + allowed.Push(TFClass_Scout); + allowed.Push(TFClass_Sniper); + allowed.Push(TFClass_Soldier); + allowed.Push(TFClass_DemoMan); + allowed.Push(TFClass_Medic); + allowed.Push(TFClass_Heavy); + allowed.Push(TFClass_Pyro); + allowed.Push(TFClass_Spy); + allowed.Push(TFClass_Engineer); + } + + float maxWeight = 0.0; + for (int i = 0; i < allowed.Length; i++) + { + TFClassType tfClass = allowed.Get(i); + BossProfileProxyClass classData = proxyData.GetClassData(tfClass); + + int classLimit = classData.GetMax(difficulty); + if (classCount[view_as(tfClass)] < classLimit) + { + allowed.Erase(i); + i--; + continue; + } + maxWeight += classData.GetWeight(difficulty); + } + + float randomWeight = GetRandomFloat(0.0, maxWeight); + TFClassType newClass = client.Class; + + for (int i = 0; i < allowed.Length; i++) + { + TFClassType tfClass = allowed.Get(i); + BossProfileProxyClass classData = proxyData.GetClassData(tfClass); + + float weight = classData.GetWeight(difficulty); + if (weight <= 0.0) + { + continue; + } + + randomWeight -= weight; + if (randomWeight >= 0.0) + { + continue; + } + + newClass = tfClass; + break; + } + + delete allowed; + return newClass; +} + /** * Respawns a player as a proxy. * * @noreturn */ -void ClientEnableProxy(int client, int bossIndex, const float pos[3], int spawnPointEnt=-1) +void ClientEnableProxy(int clientIndex, int bossIndex, const float pos[3], int spawnPointEnt=-1) { + SF2_BasePlayer client = SF2_BasePlayer(clientIndex); if (NPCGetUniqueID(bossIndex) == -1) { return; @@ -512,88 +1354,81 @@ void ClientEnableProxy(int client, int bossIndex, const float pos[3], int spawnP return; } - if (GetClientTeam(client) != TFTeam_Blue) + if (client.Team != TFTeam_Blue) { return; } - if (g_PlayerProxy[client]) + if (client.IsProxy) { return; } - TF2_RemovePlayerDisguise(client); + TF2_RemovePlayerDisguise(client.index); int difficulty = GetLocalGlobalDifficulty(bossIndex); char profile[SF2_MAX_PROFILE_NAME_LENGTH]; NPCGetProfile(bossIndex, profile, sizeof(profile)); + BossProfileProxyData proxyData = GetBossProfile(profile).GetProxies(); + TFClassType class = SelectProxyClass(client); + BossProfileProxyClass classData = proxyData.GetClassData(class); - ClientSetGhostModeState(client, false); + client.SetGhostState(false); - ClientStopProxyForce(client); + ClientStopProxyForce(client.index); - if (IsClientInKart(client)) + if (IsClientInKart(client.index)) { - TF2_RemoveCondition(client, TFCond_HalloweenKart); - TF2_RemoveCondition(client, TFCond_HalloweenKartDash); - TF2_RemoveCondition(client, TFCond_HalloweenKartNoTurn); - TF2_RemoveCondition(client, TFCond_HalloweenKartCage); + client.ChangeCondition(TFCond_HalloweenKart, true); + client.ChangeCondition(TFCond_HalloweenKartDash, true); + client.ChangeCondition(TFCond_HalloweenKartNoTurn, true); + client.ChangeCondition(TFCond_HalloweenKartCage, true); } - g_PlayerProxy[client] = true; + client.IsProxy = true; - ChangeClientTeamNoSuicide(client, TFTeam_Blue); - PvP_SetPlayerPvPState(client, false, true, false); - PvE_SetPlayerPvEState(client, false, false); - TF2_RespawnPlayer(client); + ChangeClientTeamNoSuicide(client.index, TFTeam_Blue); + PvP_SetPlayerPvPState(client.index, false, true, false); + PvE_SetPlayerPvEState(client.index, false, false); + client.Respawn(); // Speed recalculation. Props to the creators of FF2/VSH for this snippet. - TF2_AddCondition(client, TFCond_SpeedBuffAlly, 0.001); + client.ChangeCondition(TFCond_SpeedBuffAlly, _, 0.001); - g_PlayerProxy[client] = true; + client.ProxyMaster = NPCGetUniqueID(bossIndex); + client.ProxyControl = 100; + g_PlayerProxyControlRate[client.index] = classData.GetControlDrainRate(difficulty); + g_PlayerProxyControlTimer[client.index] = CreateTimer(g_PlayerProxyControlRate[client.index], Timer_ClientProxyControl, client.UserID, TIMER_FLAG_NO_MAPCHANGE); + g_PlayerProxyAvailable[client.index] = false; + g_PlayerProxyAvailableTimer[client.index] = null; - g_PlayerProxyMaster[client] = NPCGetUniqueID(bossIndex); - g_PlayerProxyControl[client] = 100; - g_PlayerProxyControlRate[client] = g_SlenderProxyControlDrainRate[bossIndex][difficulty]; - g_PlayerProxyControlTimer[client] = CreateTimer(g_PlayerProxyControlRate[client], Timer_ClientProxyControl, GetClientUserId(client), TIMER_FLAG_NO_MAPCHANGE); - g_PlayerProxyAvailable[client] = false; - g_PlayerProxyAvailableTimer[client] = null; - - char allowedClasses[512]; - GetBossProfileProxyClasses(profile, allowedClasses, sizeof(allowedClasses)); - - char className[64]; - TF2_GetClassName(TF2_GetPlayerClass(client), className, sizeof(className)); - if (allowedClasses[0] != '\0' && className[0] != '\0' && StrContains(allowedClasses, className, false) == -1) + int health = classData.GetHealth(difficulty); + if (health <= 0) { - // Pick the first class that's allowed. - char allowedClassesList[32][32]; - int classCount = ExplodeString(allowedClasses, " ", allowedClassesList, 32, 32); - if (classCount) - { - TF2_SetPlayerClass(client, TF2_GetClass(allowedClassesList[0]), _, false); - - int maxHealth = GetEntProp(client, Prop_Send, "m_iHealth"); - TF2_RegeneratePlayer(client); - SetEntProp(client, Prop_Data, "m_iHealth", maxHealth); - SetEntProp(client, Prop_Send, "m_iHealth", maxHealth); - } + health = client.Health; } - UTIL_ScreenFade(client, 200, 1, FFADE_IN, 255, 255, 255, 100); - EmitSoundToClient(client, "weapons/teleporter_send.wav", _, SNDCHAN_STATIC); + client.Regenerate(); + client.Health = health; + + client.ScreenFade(200, 1, FFADE_IN, 255, 255, 255, 100); + EmitSoundToClient(client.index, "weapons/teleporter_send.wav", _, SNDCHAN_STATIC); - ClientActivateUltravision(client); + ClientActivateUltravision(client.index); - TF2Attrib_SetByDefIndex(client, 28, 1.0); + TF2Attrib_SetByDefIndex(client.index, 28, 1.0); - CreateTimer(0.33, Timer_ApplyCustomModel, GetClientUserId(client), TIMER_FLAG_NO_MAPCHANGE); + char path[PLATFORM_MAX_PATH]; + classData.GetModel(difficulty, path, sizeof(path)); + SetVariantString(path); + client.AcceptInput("SetCustomModel"); + client.SetProp(Prop_Send, "m_bUseClassAnimations", true); - if (NPCHasProxyWeapons(bossIndex)) + /*if (proxyData.CustomWeapons) { CreateTimer(1.0, Timer_GiveWeaponAll, GetClientUserId(client), TIMER_FLAG_NO_MAPCHANGE); - } + }*/ //SDKHook(client, SDKHook_ShouldCollide, Hook_ClientProxyShouldCollide); @@ -603,27 +1438,27 @@ void ClientEnableProxy(int client, int bossIndex, const float pos[3], int spawnP float spawnPos[3]; float ang[3]; GetEntPropVector(spawnPointEnt, Prop_Data, "m_vecAbsOrigin", spawnPos); GetEntPropVector(spawnPointEnt, Prop_Data, "m_angAbsRotation", ang); - TeleportEntity(client, spawnPos, ang, view_as({ 0.0, 0.0, 0.0 })); - spawnPoint.FireOutput("OnSpawn", client); + TeleportEntity(client.index, spawnPos, ang, view_as({ 0.0, 0.0, 0.0 })); + spawnPoint.FireOutput("OnSpawn", client.index); } else { - TeleportEntity(client, pos, NULL_VECTOR, view_as({ 0.0, 0.0, 0.0 })); + TeleportEntity(client.index, pos, NULL_VECTOR, view_as({ 0.0, 0.0, 0.0 })); } - if (NPCGetProxySpawnEffectState(bossIndex)) + /*if (proxyData.SpawnEffect) { char spawnEffect[PLATFORM_MAX_PATH]; - GetBossProfileProxySpawnEffectName(profile, spawnEffect, sizeof(spawnEffect)); - CreateGeneralParticle(client, spawnEffect, NPCGetProxySpawnEffectZOffset(bossIndex)); - } + proxyData.GetSpawnEffectName(spawnEffect, sizeof(spawnEffect)); + CreateGeneralParticle(client, spawnEffect, proxyData.SpawnEffectZOffset); + }*/ Call_StartForward(g_OnClientSpawnedAsProxyFwd); Call_PushCell(client); Call_Finish(); Call_StartForward(g_OnPlayerChangeProxyStatePFwd); - Call_PushCell(SF2_BasePlayer(client)); + Call_PushCell(client); Call_PushCell(true); Call_Finish(); } @@ -641,35 +1476,30 @@ static Action Timer_GiveWeaponAll(Handle timer, any userid) return Plugin_Stop; } - int bossIndex = NPCGetFromUniqueID(g_PlayerProxyMaster[client]); + /*int bossIndex = NPCGetFromUniqueID(g_PlayerProxyMaster[client]); if (g_PlayerProxy[client] && bossIndex != -1) { - if (!NPCHasProxyWeapons(bossIndex)) + BossProfileProxyData proxyData = SF2NPC_BaseNPC(bossIndex).GetProfileDataEx().GetProxies(); + if (!proxyData.CustomWeapons) { return Plugin_Stop; } char profile[SF2_MAX_PROFILE_NAME_LENGTH]; NPCGetProfile(bossIndex, profile, sizeof(profile)); + BossProfileProxyClass classData = proxyData.GetClassData(); int weaponIndex, weaponSlot; char weaponName[PLATFORM_MAX_PATH], weaponStats[PLATFORM_MAX_PATH]; - int classIndex = view_as(TF2_GetPlayerClass(client)); - classIndex--; - ArrayList weaponArray = GetBossProfileProxyWeaponClassNames(profile); - if (weaponArray == null) + TFClassType class = TF2_GetPlayerClass(client); + classData.GetWeaponClassname(class, weaponName, sizeof(weaponName)); + if (weaponName[0] == '\0') { return Plugin_Stop; } - weaponArray.GetString(classIndex, weaponName, sizeof(weaponName)); - weaponArray = GetBossProfileProxyWeaponStats(profile); - if (weaponArray == null) - { - return Plugin_Stop; - } - weaponArray.GetString(classIndex, weaponStats, sizeof(weaponStats)); - weaponIndex = GetBossProfileProxyWeaponIndexes(profile, classIndex + 1); - weaponSlot = GetBossProfileProxyWeaponSlots(profile, classIndex + 1); + classData.GetWeaponClassname(class, weaponStats, sizeof(weaponStats)); + weaponIndex = classData.GetWeaponIndex(class); + weaponSlot = classData.GetWeaponSlot(class); switch (weaponSlot) { @@ -691,24 +1521,10 @@ static Action Timer_GiveWeaponAll(Handle timer, any userid) delete weaponHandle; EquipPlayerWeapon(client, entity); SetEntProp(entity, Prop_Send, "m_bValidatedAttachedEntity", 1); - } + }*/ return Plugin_Stop; } -bool Hook_ClientProxyShouldCollide(int ent, int collisiongroup, int contentsmask, bool originalResult) -{ - if (!g_Enabled || !g_PlayerProxy[ent] || IsClientInPvP(ent) || IsClientInPvE(ent)) - { - SDKUnhook(ent, SDKHook_ShouldCollide, Hook_ClientProxyShouldCollide); - return originalResult; - } - if ((contentsmask & MASK_RED)) - { - return true; - } - //To-do add no collision proxy-boss here, the collision boss-proxy is done, see npc_chaser.sp - return originalResult; -} //RequestFrame// void ProxyDeathAnimation(any client) { @@ -767,12 +1583,14 @@ Action Timer_ApplyCustomModel(Handle timer, any userid) SetEntProp(client, Prop_Send, "m_iAirDash", 99999); - int master = NPCGetFromUniqueID(g_PlayerProxyMaster[client]); + /*int master = NPCGetFromUniqueID(g_PlayerProxyMaster[client]); if (g_PlayerProxy[client] && master != -1) { char profile[SF2_MAX_PROFILE_NAME_LENGTH]; NPCGetProfile(master, profile, sizeof(profile)); + BossProfileProxyData proxyData = GetBossProfile(profile).GetProxies(); + BossProfileProxyClass classData = proxyData.GetClassData(); int difficulty = GetLocalGlobalDifficulty(master); @@ -781,95 +1599,97 @@ Action Timer_ApplyCustomModel(Handle timer, any userid) TF2_RegeneratePlayer(client); - char className[64]; + char className[64], keyName[64]; TFClassType playerClass = TF2_GetPlayerClass(client); - int classToInt = view_as(playerClass); TF2_GetClassName(playerClass, className, sizeof(className)); - ArrayList modelsArray; + ProfileObject modelsArray; - if (GetBossProfileProxyDifficultyModelsState(profile)) + if (proxyData.DifficultyModels) { switch (difficulty) { case Difficulty_Normal: { - modelsArray = GetBossProfileProxyModels(profile, classToInt, difficulty); + modelsArray = classData.GetModel(playerClass, difficulty); if (modelsArray == null) { - modelsArray = GetBossProfileProxyModels(profile, 0, difficulty); + modelsArray = proxyData.GetUniversalModel(difficulty); } - modelsArray.GetString(GetRandomInt(0, modelsArray.Length - 1), buffer, sizeof(buffer)); - strcopy(g_ClientProxyModel[client],sizeof(g_ClientProxyModel[]),buffer); + modelsArray.GetKeyNameFromIndex(GetRandomInt(0, modelsArray.Size - 1), keyName, sizeof(keyName)); + modelsArray.GetString(keyName, buffer, sizeof(buffer)); + strcopy(g_ClientProxyModel[client], sizeof(g_ClientProxyModel[]), buffer); } case Difficulty_Hard: { - modelsArray = GetBossProfileProxyModels(profile, classToInt, difficulty); + modelsArray = classData.GetModel(playerClass, difficulty); if (modelsArray == null) { - modelsArray = GetBossProfileProxyModels(profile, 0, difficulty); + modelsArray = proxyData.GetUniversalModel(difficulty); if (modelsArray == null) { - modelsArray = GetBossProfileProxyModels(profile, classToInt, 1); + modelsArray = classData.GetModel(playerClass, 1); if (modelsArray == null) { - modelsArray = GetBossProfileProxyModels(profile, 0, 1); + modelsArray = proxyData.GetUniversalModel(1); } } } - modelsArray.GetString(GetRandomInt(0, modelsArray.Length - 1), buffer, sizeof(buffer)); - strcopy(g_ClientProxyModelHard[client],sizeof(g_ClientProxyModelHard[]),buffer); + modelsArray.GetKeyNameFromIndex(GetRandomInt(0, modelsArray.Size - 1), keyName, sizeof(keyName)); + modelsArray.GetString(keyName, buffer, sizeof(buffer)); + strcopy(g_ClientProxyModelHard[client], sizeof(g_ClientProxyModelHard[]), buffer); } case Difficulty_Insane: { - modelsArray = GetBossProfileProxyModels(profile, classToInt, difficulty); + modelsArray = classData.GetModel(playerClass, difficulty); if (modelsArray == null) { - modelsArray = GetBossProfileProxyModels(profile, 0, difficulty); + modelsArray = proxyData.GetUniversalModel(difficulty); if (modelsArray == null) { - modelsArray = GetBossProfileProxyModels(profile, classToInt, 2); + modelsArray = classData.GetModel(playerClass, 2); if (modelsArray == null) { - modelsArray = GetBossProfileProxyModels(profile, 0, 2); + modelsArray = proxyData.GetUniversalModel(2); if (modelsArray == null) { - modelsArray = GetBossProfileProxyModels(profile, classToInt, 1); + modelsArray = classData.GetModel(playerClass, 1); if (modelsArray == null) { - modelsArray = GetBossProfileProxyModels(profile, 0, 1); + modelsArray = proxyData.GetUniversalModel(1); } } } } } - modelsArray.GetString(GetRandomInt(0, modelsArray.Length - 1), buffer, sizeof(buffer)); - strcopy(g_ClientProxyModelInsane[client],sizeof(g_ClientProxyModelInsane[]),buffer); + modelsArray.GetKeyNameFromIndex(GetRandomInt(0, modelsArray.Size - 1), keyName, sizeof(keyName)); + modelsArray.GetString(keyName, buffer, sizeof(buffer)); + strcopy(g_ClientProxyModelInsane[client], sizeof(g_ClientProxyModelInsane[]), buffer); } case Difficulty_Nightmare: { - modelsArray = GetBossProfileProxyModels(profile, classToInt, difficulty); + modelsArray = classData.GetModel(playerClass, difficulty); if (modelsArray == null) { - modelsArray = GetBossProfileProxyModels(profile, 0, difficulty); + modelsArray = proxyData.GetUniversalModel(difficulty); if (modelsArray == null) { - modelsArray = GetBossProfileProxyModels(profile, classToInt, 3); + modelsArray = classData.GetModel(playerClass, 3); if (modelsArray == null) { - modelsArray = GetBossProfileProxyModels(profile, 0, 3); + modelsArray = proxyData.GetUniversalModel(3); if (modelsArray == null) { - modelsArray = GetBossProfileProxyModels(profile, classToInt, 2); + modelsArray = classData.GetModel(playerClass, 2); if (modelsArray == null) { - modelsArray = GetBossProfileProxyModels(profile, 0, 2); + modelsArray = proxyData.GetUniversalModel(2); if (modelsArray == null) { - modelsArray = GetBossProfileProxyModels(profile, classToInt, 1); + modelsArray = classData.GetModel(playerClass, 1); if (modelsArray == null) { - modelsArray = GetBossProfileProxyModels(profile, 0, 1); + modelsArray = proxyData.GetUniversalModel(1); } } } @@ -877,39 +1697,40 @@ Action Timer_ApplyCustomModel(Handle timer, any userid) } } } - modelsArray.GetString(GetRandomInt(0, modelsArray.Length - 1), buffer, sizeof(buffer)); - strcopy(g_ClientProxyModelNightmare[client],sizeof(g_ClientProxyModelNightmare[]),buffer); + modelsArray.GetKeyNameFromIndex(GetRandomInt(0, modelsArray.Size - 1), keyName, sizeof(keyName)); + modelsArray.GetString(keyName, buffer, sizeof(buffer)); + strcopy(g_ClientProxyModelNightmare[client], sizeof(g_ClientProxyModelNightmare[]), buffer); } case Difficulty_Apollyon: { - modelsArray = GetBossProfileProxyModels(profile, classToInt, difficulty); + modelsArray = classData.GetModel(playerClass, difficulty); if (modelsArray == null) { - modelsArray = GetBossProfileProxyModels(profile, 0, difficulty); + modelsArray = proxyData.GetUniversalModel(difficulty); if (modelsArray == null) { - modelsArray = GetBossProfileProxyModels(profile, classToInt, 4); + modelsArray = classData.GetModel(playerClass, 4); if (modelsArray == null) { - modelsArray = GetBossProfileProxyModels(profile, 0, 4); + modelsArray = proxyData.GetUniversalModel(4); if (modelsArray == null) { - modelsArray = GetBossProfileProxyModels(profile, classToInt, 3); + modelsArray = classData.GetModel(playerClass, 3); if (modelsArray == null) { - modelsArray = GetBossProfileProxyModels(profile, 0, 3); + modelsArray = proxyData.GetUniversalModel(3); if (modelsArray == null) { - modelsArray = GetBossProfileProxyModels(profile, classToInt, 2); + modelsArray = classData.GetModel(playerClass, 2); if (modelsArray == null) { - modelsArray = GetBossProfileProxyModels(profile, 0, 2); + modelsArray = proxyData.GetUniversalModel(2); if (modelsArray == null) { - modelsArray = GetBossProfileProxyModels(profile, classToInt, 1); + modelsArray = classData.GetModel(playerClass, 1); if (modelsArray == null) { - modelsArray = GetBossProfileProxyModels(profile, 0, 1); + modelsArray = proxyData.GetUniversalModel(1); } } } @@ -919,8 +1740,9 @@ Action Timer_ApplyCustomModel(Handle timer, any userid) } } } - modelsArray.GetString(GetRandomInt(0, modelsArray.Length - 1), buffer, sizeof(buffer)); - strcopy(g_ClientProxyModelApollyon[client],sizeof(g_ClientProxyModelApollyon[]),buffer); + modelsArray.GetKeyNameFromIndex(GetRandomInt(0, modelsArray.Size - 1), keyName, sizeof(keyName)); + modelsArray.GetString(keyName, buffer, sizeof(buffer)); + strcopy(g_ClientProxyModelApollyon[client], sizeof(g_ClientProxyModelApollyon[]), buffer); } } @@ -935,24 +1757,25 @@ Action Timer_ApplyCustomModel(Handle timer, any userid) } else { - modelsArray = GetBossProfileProxyModels(profile, classToInt, 1); + modelsArray = classData.GetModel(playerClass, 1); if (modelsArray == null) { - modelsArray = GetBossProfileProxyModels(profile, 0, 1); + modelsArray = proxyData.GetUniversalModel(1); } if (modelsArray != null) { - modelsArray.GetString(GetRandomInt(0, modelsArray.Length - 1), buffer, sizeof(buffer)); + modelsArray.GetKeyNameFromIndex(GetRandomInt(0, modelsArray.Size - 1), keyName, sizeof(keyName)); + modelsArray.GetString(keyName, buffer, sizeof(buffer)); if (buffer[0] != '\0') { SetVariantString(buffer); AcceptEntityInput(client, "SetCustomModel"); SetEntProp(client, Prop_Send, "m_bUseClassAnimations", true); - strcopy(g_ClientProxyModel[client],sizeof(g_ClientProxyModel[]),buffer); - strcopy(g_ClientProxyModelHard[client],sizeof(g_ClientProxyModelHard[]),buffer); - strcopy(g_ClientProxyModelInsane[client],sizeof(g_ClientProxyModelInsane[]),buffer); - strcopy(g_ClientProxyModelNightmare[client],sizeof(g_ClientProxyModelNightmare[]),buffer); - strcopy(g_ClientProxyModelApollyon[client],sizeof(g_ClientProxyModelApollyon[]),buffer); + strcopy(g_ClientProxyModel[client], sizeof(g_ClientProxyModel[]), buffer); + strcopy(g_ClientProxyModelHard[client], sizeof(g_ClientProxyModelHard[]), buffer); + strcopy(g_ClientProxyModelInsane[client], sizeof(g_ClientProxyModelInsane[]), buffer); + strcopy(g_ClientProxyModelNightmare[client], sizeof(g_ClientProxyModelNightmare[]), buffer); + strcopy(g_ClientProxyModelApollyon[client], sizeof(g_ClientProxyModelApollyon[]), buffer); //Prevent plugins like Model manager to override proxy model. CreateTimer(0.5, ClientCheckProxyModel, GetClientUserId(client), TIMER_REPEAT|TIMER_FLAG_NO_MAPCHANGE); } @@ -962,12 +1785,10 @@ Action Timer_ApplyCustomModel(Handle timer, any userid) if (IsPlayerAlive(client)) { g_PlayerProxyNextVoiceSound[client] = GetGameTime(); - SF2BossProfileSoundInfo soundInfo; - GetBossProfileProxySpawnSounds(profile, soundInfo); // Play any sounds, if any. - soundInfo.EmitSound(_, client); + proxyData.GetSpawnSounds().EmitSound(_, client); - bool zombie = GetBossProfileProxyZombiesState(profile); + bool zombie = proxyData.Zombies; if (zombie) { int value = g_ForcedHolidayConVar.IntValue; @@ -1036,7 +1857,7 @@ Action Timer_ApplyCustomModel(Handle timer, any userid) ClientSwitchToWeaponSlot(client, TFWeaponSlot_Melee); } - } + }*/ return Plugin_Stop; } diff --git a/addons/sourcemod/scripting/sf2/client/sprint.sp b/addons/sourcemod/scripting/sf2/client/sprint.sp index 4b327ce8..6da53013 100644 --- a/addons/sourcemod/scripting/sf2/client/sprint.sp +++ b/addons/sourcemod/scripting/sf2/client/sprint.sp @@ -1,10 +1,15 @@ #pragma semicolon 1 +#pragma newdecls required static bool g_PlayerSprint[MAXTF2PLAYERS] = { false, ... }; static bool g_WantsToSprint[MAXTF2PLAYERS] = { false, ... }; static float g_Stamina[MAXTF2PLAYERS] = { 1.0, ... }; static float g_StaminaRechargeTime[MAXTF2PLAYERS] = { 1.0, ... }; +static char g_Player90sMusicString[MAXTF2PLAYERS][PLATFORM_MAX_PATH]; +static float g_Player90sMusicVolumes[MAXTF2PLAYERS]; +static Handle g_Player90sMusicTimer[MAXTF2PLAYERS]; + static ConVar g_PlayerScareSprintBoost; void SetupSprint() @@ -414,6 +419,8 @@ static void ClientResetSprint(SF2_BasePlayer client) DebugMessage("END ClientResetSprint(%d)", client.index); } #endif + + Client90sMusicReset(client.index); } /** @@ -517,7 +524,7 @@ static void Hook_SpeedThink(int client) continue; } - if (NPCGetType(i) == SF2BossType_Chaser) + if (SF2NPC_BaseNPC(i).GetProfileDataEx().Type == SF2BossType_Chaser) { SF2_ChaserEntity chaser = SF2_ChaserEntity(ent); bossTarget = chaser.Target; @@ -563,7 +570,7 @@ static void Hook_SpeedThink(int client) continue; } - if (NPCGetType(i) == SF2BossType_Chaser) + if (SF2NPC_BaseNPC(i).GetProfileDataEx().Type == SF2BossType_Chaser) { if (state == STATE_ALERT) { @@ -855,6 +862,140 @@ static void Hook_SpeedThink(int client) } } +static void Client90sMusicReset(int client) +{ + char oldMusic[PLATFORM_MAX_PATH]; + strcopy(oldMusic, sizeof(oldMusic), g_Player90sMusicString[client]); + g_Player90sMusicString[client][0] = '\0'; + if (IsValidClient(client) && oldMusic[0] != '\0') + { + StopSound(client, MUSIC_CHAN, oldMusic); + } + + g_Player90sMusicTimer[client] = null; + g_Player90sMusicVolumes[client] = 0.0; + + if (IsValidClient(client)) + { + oldMusic = NINETYSMUSIC; + if (oldMusic[0] != '\0') + { + StopSound(client, MUSIC_CHAN, oldMusic); + } + } +} + +static void Client90sMusicStart(int client) +{ + if (!IsValidClient(client) || !IsPlayerAlive(client)) + { + return; + } + + char buffer[PLATFORM_MAX_PATH]; + buffer = NINETYSMUSIC; + + if (buffer[0] == '\0') + { + return; + } + + strcopy(g_Player90sMusicString[client], sizeof(g_Player90sMusicString[]), buffer); + g_Player90sMusicTimer[client] = CreateTimer(0.01, Timer_PlayerFadeIn90sMusic, GetClientUserId(client), TIMER_REPEAT|TIMER_FLAG_NO_MAPCHANGE); + TriggerTimer(g_Player90sMusicTimer[client], true); +} + +static void Client90sMusicStop(int client) +{ + if (!IsValidClient(client)) + { + return; + } + + if (!IsClientSprinting(client)) + { + g_Player90sMusicString[client][0] = '\0'; + } + + g_Player90sMusicTimer[client]= CreateTimer(0.01, Timer_PlayerFadeOut90sMusic, GetClientUserId(client), TIMER_REPEAT|TIMER_FLAG_NO_MAPCHANGE); + TriggerTimer(g_Player90sMusicTimer[client], true); +} + +static Action Timer_PlayerFadeIn90sMusic(Handle timer, any userid) +{ + int client = GetClientOfUserId(userid); + if (client <= 0) + { + return Plugin_Stop; + } + + if (g_Player90sMusicTimer[client] != timer) + { + return Plugin_Stop; + } + + g_Player90sMusicVolumes[client] += 0.28; + if (g_Player90sMusicVolumes[client] > 0.5) + { + g_Player90sMusicVolumes[client] = 0.5; + } + + if (g_Player90sMusicString[client][0] != '\0') + { + EmitSoundToClient(client, g_Player90sMusicString[client], _, MUSIC_CHAN, _, SND_CHANGEVOL, g_Player90sMusicVolumes[client] * g_PlayerPreferences[client].PlayerPreference_MusicVolume, 100); + } + + if (g_Player90sMusicVolumes[client] >= 0.5) + { + g_Player90sMusicTimer[client] = null; + return Plugin_Stop; + } + + return Plugin_Continue; +} + +static Action Timer_PlayerFadeOut90sMusic(Handle timer, any userid) +{ + int client = GetClientOfUserId(userid); + if (client <= 0) + { + return Plugin_Stop; + } + + if (g_Player90sMusicTimer[client] != timer) + { + return Plugin_Stop; + } + + char buffer[PLATFORM_MAX_PATH]; + buffer = NINETYSMUSIC; + + if (strcmp(buffer, g_Player90sMusicString[client], false) == 0) + { + g_Player90sMusicTimer[client] = null; + return Plugin_Stop; + } + + g_Player90sMusicVolumes[client] -= 0.28; + if (g_Player90sMusicVolumes[client] < 0.0) + { + g_Player90sMusicVolumes[client] = 0.0; + } + + if (buffer[0] != '\0') + { + EmitSoundToClient(client, buffer, _, MUSIC_CHAN, _, SND_CHANGEVOL, g_Player90sMusicVolumes[client] * g_PlayerPreferences[client].PlayerPreference_MusicVolume, 100); + } + + if (g_Player90sMusicVolumes[client] <= 0.0) + { + g_Player90sMusicTimer[client] = null; + return Plugin_Stop; + } + + return Plugin_Continue; +} + void Sprint_SetupAPI() { CreateNative("SF2_GetClientSprintPoints", Native_GetSprintPoints); diff --git a/addons/sourcemod/scripting/sf2/client/static.sp b/addons/sourcemod/scripting/sf2/client/static.sp index 1bc02aac..1620d06c 100644 --- a/addons/sourcemod/scripting/sf2/client/static.sp +++ b/addons/sourcemod/scripting/sf2/client/static.sp @@ -1,4 +1,5 @@ #pragma semicolon 1 +#pragma newdecls required // Player static data. int g_PlayerStaticMode[MAXTF2PLAYERS][MAX_BOSSES]; @@ -154,31 +155,6 @@ void ClientProcessStaticShake(int client) newPunchAngVel[i] = oldPunchAngVel[i]; } - int staticMaster = NPCGetFromUniqueID(g_PlayerStaticMaster[client]); - if (staticMaster != -1 && NPCGetFlags(staticMaster) & SFF_HASSTATICSHAKE) - { - if (g_PlayerStaticMode[client][staticMaster] == Static_Increase) - { - newStaticShakeMaster = staticMaster; - } - } - for (int i = 0; i < MAX_BOSSES; i++) - { - if (NPCGetUniqueID(i) == -1) - { - continue; - } - - if (NPCGetFlags(i) & SFF_HASSTATICSHAKE) - { - int master = NPCGetFromUniqueID(g_SlenderCopyMaster[i]); - if (master == -1) - { - master = i; - } - } - } - if (newStaticShakeMaster != -1) { g_PlayerStaticShakeMaster[client] = NPCGetUniqueID(newStaticShakeMaster); @@ -187,17 +163,18 @@ void ClientProcessStaticShake(int client) { char profile[SF2_MAX_PROFILE_NAME_LENGTH]; NPCGetProfile(newStaticShakeMaster, profile, sizeof(profile)); + BaseBossProfile profileData = GetBossProfile(profile); if (g_PlayerStaticShakeSound[client][0] != '\0') { StopSound(client, SNDCHAN_STATIC, g_PlayerStaticShakeSound[client]); } - g_PlayerStaticShakeMinVolume[client] = GetBossProfileStaticShakeLocalVolumeMin(profile); - g_PlayerStaticShakeMaxVolume[client] = GetBossProfileStaticShakeLocalVolumeMax(profile); + g_PlayerStaticShakeMinVolume[client] = profileData.StaticShakeMinVolume; + g_PlayerStaticShakeMaxVolume[client] = profileData.StaticShakeMaxVolume; char staticSound[PLATFORM_MAX_PATH]; - GetBossProfileStaticShakeSound(profile, staticSound, sizeof(staticSound)); + profileData.GetStaticShakeLocalSound(staticSound, sizeof(staticSound)); if (staticSound[0] != '\0') { strcopy(g_PlayerStaticShakeSound[client], sizeof(g_PlayerStaticShakeSound[]), staticSound); @@ -292,9 +269,9 @@ void ClientProcessStaticShake(int client) NormalizeVector(newPunchAng, newPunchAng); float angVelocityScalar = 5.0 * g_PlayerStaticAmount[client]; - if (angVelocityScalar < 0.0) + if (angVelocityScalar < 1.0) { - angVelocityScalar = 0.0; + angVelocityScalar = 1.0; } ScaleVector(newPunchAng, angVelocityScalar); diff --git a/addons/sourcemod/scripting/sf2/client/think.sp b/addons/sourcemod/scripting/sf2/client/think.sp index e4cad356..694fb7da 100644 --- a/addons/sourcemod/scripting/sf2/client/think.sp +++ b/addons/sourcemod/scripting/sf2/client/think.sp @@ -4,6 +4,7 @@ #define _sf2_clients_think_included #pragma semicolon 1 +#pragma newdecls required void Hook_ClientPreThink(int client) { @@ -12,220 +13,98 @@ void Hook_ClientPreThink(int client) return; } - ClientProcessFlashlightAngles(client); - ClientProcessStaticShake(client); - ClientProcessViewAngles(client); + SF2_BasePlayer player = SF2_BasePlayer(client); + float gameTime = GetGameTime(); - if ((g_PlayerTrapped[client] || g_PlayerLatchedByTongue[client]) && !IsClientInGhostMode(client)) + ClientProcessFlashlightAngles(player.index); + ClientProcessStaticShake(player.index); + ClientProcessViewAngles(player.index); + + if ((player.IsTrapped || player.IsLatched) && !player.IsInGhostMode) { - TF2Attrib_SetByName(client, "increased jump height", 0.0); + TF2Attrib_SetByName(player.index, "increased jump height", 0.0); } else { - TF2Attrib_SetByName(client, "increased jump height", 1.0); + TF2Attrib_SetByName(player.index, "increased jump height", 1.0); } - if (IsClientInGhostMode(client)) - { - SetEntityFlags(client, GetEntityFlags(client) ^ FL_EDICT_ALWAYS); - SetEntPropFloat(client, Prop_Send, "m_flNextAttack", GetGameTime() + 2.0); - SetEntPropFloat(client, Prop_Send, "m_flMaxspeed", 520.0); - SetEntPropFloat(client, Prop_Send, "m_flModelScale", 1.0); - SetEntPropFloat(client, Prop_Send, "m_flHeadScale", 1.0); - SetEntPropFloat(client, Prop_Send, "m_flTorsoScale", 1.0); - SetEntPropFloat(client, Prop_Send, "m_flHandScale", 1.0); - if (IsClientInKart(client) || !TF2_IsPlayerInCondition(client, TFCond_Stealthed)) - { - TF2_RemoveCondition(client,TFCond_HalloweenKart); - TF2_RemoveCondition(client,TFCond_HalloweenKartDash); - TF2_RemoveCondition(client,TFCond_HalloweenKartNoTurn); - TF2_RemoveCondition(client,TFCond_HalloweenKartCage); - TF2_RemoveCondition(client, TFCond_Taunting); - ClientHandleGhostMode(client, true); - } - TF2_RemoveCondition(client, TFCond_Taunting); - } - else if (!g_PlayerEliminated[client] || g_PlayerProxy[client]) + if (!player.IsEliminated && !player.HasEscaped) { - if (!IsRoundEnding() && !IsRoundInWarmup() && !DidClientEscape(client)) + if (!IsRoundEnding() && !IsRoundInWarmup()) { - SetEntPropFloat(client, Prop_Send, "m_flModelScale", 1.0); - SetEntPropFloat(client, Prop_Send, "m_flHeadScale", 1.0); - SetEntPropFloat(client, Prop_Send, "m_flTorsoScale", 1.0); - SetEntPropFloat(client, Prop_Send, "m_flHandScale", 1.0); + player.SetPropFloat(Prop_Send, "m_flModelScale", 1.0); + player.SetPropFloat(Prop_Send, "m_flHeadScale", 1.0); + player.SetPropFloat(Prop_Send, "m_flTorsoScale", 1.0); + player.SetPropFloat(Prop_Send, "m_flHandScale", 1.0); - int roundState = view_as(GameRules_GetRoundState()); - TFClassType class = TF2_GetPlayerClass(client); - - if (!g_PlayerProxy[client] && GetClientTeam(client) == TFTeam_Red) + if (player.InCondition(TFCond_Disguised)) { - if (TF2_IsPlayerInCondition(client, TFCond_Disguised)) - { - TF2_RemoveCondition(client, TFCond_Disguised); - } - - if (TF2_IsPlayerInCondition(client, TFCond_Taunting) && (g_PlayerTrapped[client] || g_PlayerLatchedByTongue[client])) - { - TF2_RemoveCondition(client, TFCond_Taunting); - } - - if (TF2_IsPlayerInCondition(client, TFCond_Taunting) && class == TFClass_Soldier) - { - int weaponEnt = GetPlayerWeaponSlot(client, TFWeaponSlot_Melee); - if (weaponEnt && weaponEnt != INVALID_ENT_REFERENCE) - { - int itemDefInt = GetEntProp(weaponEnt, Prop_Send, "m_iItemDefinitionIndex"); - if ((itemDefInt == 775 || itemDefInt == 128) && GetEntProp(client, Prop_Send, "m_iTauntIndex") == 0) - { - TF2_RemoveCondition(client, TFCond_Taunting); //Stop suiciding... - } - } - } - - if (roundState == 4) - { - - } + player.ChangeCondition(TFCond_Disguised, true); } - else if (g_PlayerProxy[client] && GetClientTeam(client) == TFTeam_Blue) - { - int master = NPCGetFromUniqueID(g_PlayerProxyMaster[client]); - float maxSpeed; - bool override; + if (player.InCondition(TFCond_Taunting) && (player.IsTrapped || player.IsLatched)) + { + player.ChangeCondition(TFCond_Taunting, true); + } - if (master != -1) + if (player.InCondition(TFCond_Taunting) && (player.IsTrapped || player.IsLatched)) + { + int weaponEnt = player.GetWeaponSlot(TFWeaponSlot_Melee); + if (weaponEnt && weaponEnt != INVALID_ENT_REFERENCE) { - char profile[SF2_MAX_PROFILE_NAME_LENGTH]; - NPCGetProfile(master, profile, sizeof(profile)); - - override = GetBossProfileProxyOverrideMaxSpeed(profile); - if (override) + int itemDefInt = GetEntProp(weaponEnt, Prop_Send, "m_iItemDefinitionIndex"); + if ((itemDefInt == 775 || itemDefInt == 128) && GetEntProp(client, Prop_Send, "m_iTauntIndex") == 0) { - int difficulty = GetLocalGlobalDifficulty(master); - - maxSpeed = GetBossProfileProxyMaxSpeed(profile, difficulty); + player.ChangeCondition(TFCond_Taunting, true); //Stop suiciding... } } + } + } - bool speedup = TF2_IsPlayerInCondition(client, TFCond_SpeedBuffAlly); + if (gameTime >= g_PlayerStressNextUpdateTime[player.index]) + { + g_PlayerStressNextUpdateTime[player.index] = gameTime + 0.33; + ClientAddStress(player.index, -0.01); - if (override) - { - if (speedup || g_InProxySurvivalRageMode) - { - float rageSpeed = maxSpeed + 30.0; - SetEntPropFloat(client, Prop_Send, "m_flMaxspeed", rageSpeed); - } - else - { - SetEntPropFloat(client, Prop_Send, "m_flMaxspeed", maxSpeed); - } - } - else - { - switch (class) - { - case TFClass_Scout: - { - if (speedup || g_InProxySurvivalRageMode) - { - SetEntPropFloat(client, Prop_Send, "m_flMaxspeed", 390.0); - } - else - { - SetEntPropFloat(client, Prop_Send, "m_flMaxspeed", 300.0); - } - } - case TFClass_Medic: - { - if (speedup || g_InProxySurvivalRageMode) - { - SetEntPropFloat(client, Prop_Send, "m_flMaxspeed", 370.0); - } - else - { - SetEntPropFloat(client, Prop_Send, "m_flMaxspeed", 300.0); - } - } - case TFClass_Spy: - { - if (speedup || g_InProxySurvivalRageMode) - { - SetEntPropFloat(client, Prop_Send, "m_flMaxspeed", 370.0); - } - else - { - SetEntPropFloat(client, Prop_Send, "m_flMaxspeed", 300.0); - } - } - default: - { - if (g_InProxySurvivalRageMode) - { - float rageSpeed = ClientGetDefaultSprintSpeed(client) + 30.0; - SetEntPropFloat(client, Prop_Send, "m_flMaxspeed", rageSpeed); - } - } - } - } - } + #if defined DEBUG + SendDebugMessageToPlayer(player.index, DEBUG_PLAYER_STRESS, 1, "g_PlayerStressAmount[%d]: %0.1f", player.index, g_PlayerStressAmount[player.index]); + #endif } } - if (g_PlayerEliminated[client] && (IsClientInPvP(client) || IsClientInPvE(client))) + if (player.IsEliminated && (player.IsInPvP || player.IsInPvE)) { - SetEntPropFloat(client, Prop_Send, "m_flModelScale", 1.0); - SetEntPropFloat(client, Prop_Send, "m_flHeadScale", 1.0); - SetEntPropFloat(client, Prop_Send, "m_flTorsoScale", 1.0); - SetEntPropFloat(client, Prop_Send, "m_flHandScale", 1.0); - if (IsClientInKart(client)) + player.SetPropFloat(Prop_Send, "m_flModelScale", 1.0); + player.SetPropFloat(Prop_Send, "m_flHeadScale", 1.0); + player.SetPropFloat(Prop_Send, "m_flTorsoScale", 1.0); + player.SetPropFloat(Prop_Send, "m_flHandScale", 1.0); + if (IsClientInKart(player.index)) { - TF2_RemoveCondition(client, TFCond_HalloweenKart); - TF2_RemoveCondition(client, TFCond_HalloweenKartDash); - TF2_RemoveCondition(client, TFCond_HalloweenKartNoTurn); - TF2_RemoveCondition(client, TFCond_HalloweenKartCage); + player.ChangeCondition(TFCond_HalloweenKart, true); + player.ChangeCondition(TFCond_HalloweenKartDash, true); + player.ChangeCondition(TFCond_HalloweenKartNoTurn, true); + player.ChangeCondition(TFCond_HalloweenKartCage, true); } } - if (IsRoundInWarmup() || (IsRoundInIntro() && !g_PlayerEliminated[client]) || IsRoundEnding()) //I told you, stop breaking my plugin + if (IsRoundInWarmup() || (IsRoundInIntro() && !player.IsEliminated) || IsRoundEnding()) //I told you, stop breaking my plugin { - if (IsClientInKart(client)) + if (IsClientInKart(player.index)) { - TF2_RemoveCondition(client, TFCond_HalloweenKart); - TF2_RemoveCondition(client, TFCond_HalloweenKartDash); - TF2_RemoveCondition(client, TFCond_HalloweenKartNoTurn); - TF2_RemoveCondition(client, TFCond_HalloweenKartCage); + player.ChangeCondition(TFCond_HalloweenKart, true); + player.ChangeCondition(TFCond_HalloweenKartDash, true); + player.ChangeCondition(TFCond_HalloweenKartNoTurn, true); + player.ChangeCondition(TFCond_HalloweenKartCage, true); } } - // Calculate player stress levels. - if (!g_PlayerEliminated[client] && !DidClientEscape(client) && GetGameTime() >= g_PlayerStressNextUpdateTime[client]) - { - g_PlayerStressNextUpdateTime[client] = GetGameTime() + 0.33; - ClientAddStress(client, -0.01); - - #if defined DEBUG - SendDebugMessageToPlayer(client, DEBUG_PLAYER_STRESS, 1, "g_PlayerStressAmount[%d]: %0.1f", client, g_PlayerStressAmount[client]); - #endif - } - - if (g_LastVisibilityProcess[client] + 0.30 >= GetGameTime()) + if (g_LastVisibilityProcess[player.index] + 0.30 >= GetGameTime()) { return; } - /*if (!g_PlayerEliminated[client]) - { - CNavArea targetArea = SDK_GetLastKnownArea(client);//SDK_GetLastKnownArea(client) =/= g_lastNavArea[client], SDK_GetLastKnownArea() retrives the nav area stored by the server - if (targetArea != INVALID_NAV_AREA) - { - ClientNavAreaUpdate(client, g_lastNavArea[client], targetArea); - g_lastNavArea[client] = targetArea; - } - }*/ - - g_LastVisibilityProcess[client] = GetGameTime(); + g_LastVisibilityProcess[player.index] = GetGameTime(); - ClientProcessVisibility(client); + ClientProcessVisibility(player.index); } Action Hook_ClientOnTakeDamage(int victim, int &attacker, int &inflictor, float &damage, int &damagetype, int &weapon, float damageForce[3], float damagePosition[3], int damagecustom) @@ -263,6 +142,7 @@ Action Hook_ClientOnTakeDamage(int victim, int &attacker, int &inflictor, float Call_PushCellRef(inflictor); Call_PushFloatRef(damage2); Call_PushCellRef(damagetype); + Call_PushCell(damagecustom); Call_Finish(action); if (action == Plugin_Changed) @@ -272,7 +152,6 @@ Action Hook_ClientOnTakeDamage(int victim, int &attacker, int &inflictor, float } TFClassType class = victimPlayer.Class; - int classToInt = view_as(class); if (IsRoundInWarmup() && IsValidClient(attacker)) { @@ -287,7 +166,7 @@ Action Hook_ClientOnTakeDamage(int victim, int &attacker, int &inflictor, float } } - if (IsClientInKart(victim) && (attacker == -1 || inflictor == -1)) + if (IsClientInKart(victimPlayer.index) && (attacker == -1 || inflictor == -1)) { damage = 0.0; return Plugin_Changed; @@ -299,19 +178,19 @@ Action Hook_ClientOnTakeDamage(int victim, int &attacker, int &inflictor, float GetEdictClassname(inflictor, inflictorClass, sizeof(inflictorClass)); } - if (IsValidClient(attacker) && IsValidClient(victim) && g_PlayerProxy[attacker] && GetClientTeam(victim) == TFTeam_Red && TF2_IsPlayerInCondition(victim, TFCond_Gas)) + if (IsValidClient(attacker) && victimPlayer.IsValid && g_PlayerProxy[attacker] && victimPlayer.Team == TFTeam_Red && victimPlayer.InCondition(TFCond_Gas)) { - TF2_IgnitePlayer(victim, victim); - TF2_RemoveCondition(victim, TFCond_Gas); + victimPlayer.Ignite(true); + victimPlayer.ChangeCondition(TFCond_Gas, true); } - if (TF2_IsPlayerInCondition(victim, TFCond_Gas) && SF2_ChaserEntity(attacker).IsValid()) + if (victimPlayer.InCondition(TFCond_Gas) && SF2_ChaserEntity(attacker).IsValid()) { - TF2_IgnitePlayer(victim, victim); - TF2_RemoveCondition(victim, TFCond_Gas); + victimPlayer.Ignite(true); + victimPlayer.ChangeCondition(TFCond_Gas, true); } - if (IsValidClient(attacker) && IsValidClient(victim) && (IsClientInPvP(victim) || IsClientInPvE(victim)) && GetClientTeam(victim) == TFTeam_Red && GetClientTeam(attacker) == TFTeam_Red && victim != attacker) + if (IsValidClient(attacker) && victimPlayer.IsValid && (victimPlayer.IsInPvP || victimPlayer.IsInPvE) && victimPlayer.Team == TFTeam_Red && GetClientTeam(attacker) == TFTeam_Red && victim != attacker) { damage = 0.0; return Plugin_Changed; @@ -362,7 +241,7 @@ Action Hook_ClientOnTakeDamage(int victim, int &attacker, int &inflictor, float int itemDefInt = GetEntProp(weaponEnt, Prop_Send, "m_iItemDefinitionIndex"); float zVelocity[3]; GetEntPropVector(attacker, Prop_Data, "m_vecVelocity", zVelocity); - if (itemDefInt == 416 && zVelocity[2] < 0.0 && weaponEnt == GetEntPropEnt(attacker, Prop_Send, "m_hActiveWeapon")) //A soldier has the market gardener and is currently falling down, like Minecraft with it's critical hits. + if (itemDefInt == 416 && zVelocity[2] < 0.0 && weaponEnt == GetEntPropEnt(attacker, Prop_Send, "m_hActiveWeapon")) // A soldier has the market gardener and is currently falling down, like Minecraft with it's critical hits. { damagetype |= DMG_ACID; } @@ -502,141 +381,6 @@ Action Hook_ClientOnTakeDamage(int victim, int &attacker, int &inflictor, float } } } - else if (g_PlayerProxy[victim] || g_PlayerProxy[attacker]) - { - if (g_PlayerEliminated[attacker] == g_PlayerEliminated[victim]) - { - damage = 0.0; - return Plugin_Changed; - } - - if (attacker == victim)//Don't allow proxy to self regenerate control. - { - return Plugin_Continue; - } - - if (g_PlayerProxy[attacker]) - { - int maxHealth = SDKCall(g_SDKGetMaxHealth, victim); - int master = NPCGetFromUniqueID(g_PlayerProxyMaster[attacker]); - if (master != -1) - { - int difficulty = GetLocalGlobalDifficulty(master); - if (damagecustom == TF_CUSTOM_TAUNT_GRAND_SLAM || - damagecustom == TF_CUSTOM_TAUNT_FENCING || - damagecustom == TF_CUSTOM_TAUNT_ARROW_STAB || - damagecustom == TF_CUSTOM_TAUNT_GRENADE || - damagecustom == TF_CUSTOM_TAUNT_BARBARIAN_SWING || - damagecustom == TF_CUSTOM_TAUNT_ENGINEER_ARM || - damagecustom == TF_CUSTOM_TAUNT_ARMAGEDDON) - { - if (damage >= float(maxHealth)) - { - damage = float(maxHealth) * 0.5; - } - else - { - damage = 0.0; - } - } - else if (damagecustom == TF_CUSTOM_BACKSTAB) // Modify backstab damage. - { - damage = float(maxHealth) * g_SlenderProxyDamageVsBackstab[master][difficulty]; - if (damagetype & DMG_ACID) - { - damage /= 2.0; - } - } - - g_PlayerProxyControl[attacker] += g_SlenderProxyControlGainHitEnemy[master][difficulty]; - if (g_PlayerProxyControl[attacker] > 100) - { - g_PlayerProxyControl[attacker] = 100; - } - - float originalPercentage = g_SlenderProxyDamageVsEnemy[master][difficulty]; - float additionPercentage = 0.15; - if (!IsClassConfigsValid()) - { - if (class == TFClass_Medic) - { - damage *= (originalPercentage + additionPercentage); - } - else - { - damage *= originalPercentage; - } - } - else - { - damage *= originalPercentage + g_ClassProxyDamageVulnerability[classToInt]; - } - } - return Plugin_Changed; - } - else if (g_PlayerProxy[victim]) - { - char profile[SF2_MAX_PROFILE_NAME_LENGTH]; - int master = NPCGetFromUniqueID(g_PlayerProxyMaster[victim]); - if (master != -1) - { - NPCGetProfile(master, profile, sizeof(profile)); - int difficulty = GetLocalGlobalDifficulty(master); - g_PlayerProxyControl[attacker] += g_SlenderProxyControlGainHitByEnemy[master][difficulty]; - if (g_PlayerProxyControl[attacker] > 100) - { - g_PlayerProxyControl[attacker] = 100; - } - - damage *= g_SlenderProxyDamageVsSelf[master][difficulty]; - } - if (TF2_IsPlayerInCondition(victim, view_as(87))) - { - damage = 0.0; - } - if (damage * (damagetype & DMG_CRIT ? 3.0 : 1.0) >= float(GetClientHealth(victim)) && !TF2_IsPlayerInCondition(victim, view_as(87)))//The proxy is about to die - { - char buffer[PLATFORM_MAX_PATH]; - int classIndex = view_as(TF2_GetPlayerClass(victim)); - ArrayList deathAnims = GetBossProfileProxyDeathAnimations(profile); - if (deathAnims != null) - { - deathAnims.GetString(classIndex, buffer, sizeof(buffer)); - if (buffer[0] == '\0') - { - deathAnims.GetString(0, buffer, sizeof(buffer)); - } - if (buffer[0] != '\0') - { - g_ClientMaxFrameDeathAnim[victim]=GetBossProfileProxyDeathAnimFrames(profile, classIndex); - if (g_ClientMaxFrameDeathAnim[victim] == 0) - { - g_ClientMaxFrameDeathAnim[victim] = GetBossProfileProxyDeathAnimFrames(profile, 0); - } - if (g_ClientMaxFrameDeathAnim[victim] > 0) - { - // Cancel out any other taunts. - if (TF2_IsPlayerInCondition(victim, TFCond_Taunting)) - { - TF2_RemoveCondition(victim, TFCond_Taunting); - } - //The model has a death anim play it. - SDK_PlaySpecificSequence(victim,buffer); - g_ClientFrame[victim] = 0; - RequestFrame(ProxyDeathAnimation,victim); - TF2_AddCondition(victim, view_as(87), 5.0); - //Prevent death, and show the damage to the attacker. - TF2_AddCondition(victim, view_as(70), 0.5); - return Plugin_Changed; - } - } - } - - //the player has no death anim leave him die. - } - return Plugin_Changed; - } - } else { damage = 0.0; @@ -651,12 +395,6 @@ Action Hook_ClientOnTakeDamage(int victim, int &attacker, int &inflictor, float return Plugin_Changed; } } - - if (IsClientInGhostMode(victim)) - { - damage = 0.0; - return Plugin_Changed; - } } return Plugin_Continue; @@ -1061,7 +799,6 @@ Action Timer_ClientAverageUpdate(Handle timer) } } player.UpdateListeningFlags(); - player.UpdateMusicSystem(); Call_StartForward(g_OnPlayerAverageUpdatePFwd); Call_PushCell(player); diff --git a/addons/sourcemod/scripting/sf2/client/ultravision.sp b/addons/sourcemod/scripting/sf2/client/ultravision.sp index 53b1209e..bcc7a045 100644 --- a/addons/sourcemod/scripting/sf2/client/ultravision.sp +++ b/addons/sourcemod/scripting/sf2/client/ultravision.sp @@ -1,4 +1,5 @@ #pragma semicolon 1 +#pragma newdecls required #define SF2_ULTRAVISION_CONE 180.0 #define SF2_ULTRAVISION_WIDTH 800.0 diff --git a/addons/sourcemod/scripting/sf2/debug.sp b/addons/sourcemod/scripting/sf2/debug.sp index e08792a0..c398c898 100644 --- a/addons/sourcemod/scripting/sf2/debug.sp +++ b/addons/sourcemod/scripting/sf2/debug.sp @@ -4,6 +4,7 @@ #define _sf2_debug_included #pragma semicolon 1 +#pragma newdecls required #include diff --git a/addons/sourcemod/scripting/sf2/effects.sp b/addons/sourcemod/scripting/sf2/effects.sp index 4da83b6f..6382e797 100644 --- a/addons/sourcemod/scripting/sf2/effects.sp +++ b/addons/sourcemod/scripting/sf2/effects.sp @@ -4,11 +4,684 @@ #define _sf2_effects_included #pragma semicolon 1 +#pragma newdecls required static EffectEvent g_EntityEffectEvent[2049]; static EffectType g_EntityEffectType[2049]; static ArrayList g_NpcEffectsArray[MAX_BOSSES]; +methodmap ProfileEffectMaster < ProfileObject +{ + public void Precache() + { + for (int i = 0; i < this.SectionLength; i++) + { + char key[128]; + this.GetSectionNameFromIndex(i, key, sizeof(key)); + ProfileEffect effect = view_as(this.GetSection(key)); + if (effect != null) + { + effect.Precache(); + } + } + } +} + +methodmap ProfileEffect < ProfileObject +{ + property EffectType Type + { + public get() + { + char effectTypeString[64]; + this.GetString("type", effectTypeString, sizeof(effectTypeString)); + if (strcmp(effectTypeString, "steam", false) == 0) + { + return EffectType_Steam; + } + else if (strcmp(effectTypeString, "dynamiclight", false) == 0) + { + return EffectType_DynamicLight; + } + else if (strcmp(effectTypeString, "particle", false) == 0) + { + return EffectType_Particle; + } + else if (strcmp(effectTypeString, "trail", false) == 0) + { + return EffectType_Trail; + } + else if (strcmp(effectTypeString, "propdynamic", false) == 0) + { + return EffectType_PropDynamic; + } + else if (strcmp(effectTypeString, "pointspotlight", false) == 0) + { + return EffectType_PointSpotlight; + } + else if (strcmp(effectTypeString, "sprite", false) == 0) + { + return EffectType_Sprite; + } + else if (strcmp(effectTypeString, "te_beamring", false) == 0) + { + return EffectType_TempEntBeamRing; + } + else if (strcmp(effectTypeString, "te_particle", false) == 0) + { + return EffectType_TempEntParticle; + } + else if (strcmp(effectTypeString, "sound", false) == 0) + { + return EffectType_Sound; + } + } + } + + property EffectEvent Event + { + public get() + { + char effectTypeString[64]; + this.GetString("event", effectTypeString, sizeof(effectTypeString), "constant"); + if (strcmp(effectTypeString, "constant", false) == 0) + { + return EffectEvent_Constant; + } + if (strcmp(effectTypeString, "boss_hitplayer", false) == 0) + { + return EffectEvent_HitPlayer; + } + if (strcmp(effectTypeString, "boss_seenbyplayer", false) == 0) + { + return EffectEvent_PlayerSeesBoss; + } + } + } + + property int DifficultyIndexes + { + public get() + { + return this.GetInt("difficulty_indexes", 123456); + } + } + + property RenderMode RenderMode + { + public get() + { + RenderMode val = view_as(this.GetInt("rendermode", view_as(RENDER_TRANSCOLOR))); + if (this.Type == EffectType_PointSpotlight) + { + val = RENDER_TRANSCOLOR; + } + return val; + } + } + + property RenderFx RenderEffect + { + public get() + { + return view_as(this.GetInt("renderfx", view_as(RENDERFX_NONE))); + } + } + + property int SpawnFlags + { + public get() + { + return this.GetInt("spawnflags", 0); + } + } + + property int FadeAlpha + { + public get() + { + return this.GetInt("renderamt", 255); + } + } + + property float LifeTime + { + public get() + { + return this.GetFloat("lifetime", -1.0); + } + } + + property float Delay + { + public get() + { + return this.GetFloat("delay", 0.0); + } + } + + property bool AttachPlayer + { + public get() + { + return this.GetBool("attach_player", false); + } + } + + public void GetOrigin(float buffer[3]) + { + this.GetVector("origin", buffer); + } + + public void GetAngles(float buffer[3]) + { + this.GetVector("angles", buffer); + } + + public void GetAttachment(char[] buffer, int bufferSize) + { + this.GetString("attachment_point", buffer, bufferSize); + } + + public void GetRenderColor(int difficulty, int buffer[4]) + { + this.GetDifficultyColor("rendercolor", difficulty, buffer); + } + + public void Precache() + { + switch (this.Type) + { + case EffectType_PropDynamic: + { + view_as(this).Precache(); + } + + case EffectType_TempEntBeamRing: + { + view_as(this).Precache(); + } + + case EffectType_Sound: + { + view_as(this).Precache(); + } + } + } +} + +methodmap ProfileEffect_Steam < ProfileEffect +{ + property int SpreadSpeed + { + public get() + { + return this.GetInt("spreadspeed", 0); + } + } + + property int Speed + { + public get() + { + return this.GetInt("speed", 0); + } + } + + property int StartSize + { + public get() + { + return this.GetInt("startsize", 0); + } + } + + property int EndSize + { + public get() + { + return this.GetInt("endsize", 0); + } + } + + property int Rate + { + public get() + { + return this.GetInt("rate", 0); + } + } + + property int JetLength + { + public get() + { + return this.GetInt("jetlength", 0); + } + } + + property float RollSpeed + { + public get() + { + return this.GetFloat("rollspeed", 0.0); + } + } + + property int ParticleType + { + public get() + { + return this.GetInt("particletype", 0); + } + } +} + +methodmap ProfileEffect_DynamicLight < ProfileEffect +{ + property int Brightness + { + public get() + { + return this.GetInt("brightness", 0); + } + } + + property float Distance + { + public get() + { + return this.GetFloat("distance", 0.0); + } + } + + property int Cone + { + public get() + { + return this.GetInt("cone", 0); + } + } + + property int LightStyle + { + public get() + { + return this.GetInt("lightstyle", 0); + } + } +} + +methodmap ProfileEffect_Particle < ProfileEffect +{ + public void GetName(char[] buffer, int bufferSize) + { + this.GetString("particlename", buffer, bufferSize); + } +} + +methodmap ProfileEffect_Trail < ProfileEffect +{ + property float Time + { + public get() + { + return this.GetFloat("trailtime", 1.0); + } + } + + property float StartWidth + { + public get() + { + return this.GetFloat("startwidth", 6.0); + } + } + + property float EndWidth + { + public get() + { + return this.GetFloat("endwidth", 15.0); + } + } + + public void GetName(char[] buffer, int bufferSize) + { + this.GetString("spritename", buffer, bufferSize); + } +} + +methodmap ProfileEffect_PropDynamic < ProfileEffect +{ + property float Scale + { + public get() + { + return this.GetFloat("modelscale", 1.0); + } + } + + property int Skin + { + public get() + { + return this.GetInt("modelskin", 0); + } + } + + public void GetName(char[] buffer, int bufferSize) + { + this.GetString("modelname", buffer, bufferSize); + } + + public void GetAnimation(char[] buffer, int bufferSize) + { + this.GetString("modelanimation", buffer, bufferSize); + } + + public void Precache() + { + char path[PLATFORM_MAX_PATH]; + this.GetName(path, sizeof(path)); + if (path[0] != '\0') + { + PrecacheModel2(path, _, _, g_FileCheckConVar.BoolValue); + } + } +} + +methodmap ProfileEffect_PointSpotlight < ProfileEffect +{ + property float Width + { + public get() + { + return this.GetFloat("spotlightwidth", 40.0); + } + } + + property float Length + { + public get() + { + return this.GetFloat("spotlightlength", 512.0); + } + } + + property float HaloScale + { + public get() + { + return this.GetFloat("halo_scale", 40.0); + } + } + + property int Brightness + { + public get() + { + return this.GetInt("brightness", 0); + } + } + + property float Distance + { + public get() + { + return this.GetFloat("distance", 0.0); + } + } + + property int Cone + { + public get() + { + return this.GetInt("cone", 0); + } + } +} + +methodmap ProfileEffect_Sprite < ProfileEffect +{ + property float Scale + { + public get() + { + return this.GetFloat("spritescale", 1.0); + } + } + + public void GetName(char[] buffer, int bufferSize) + { + this.GetString("spritename", buffer, bufferSize); + } +} + +methodmap ProfileEffect_TEBeamRing < ProfileEffect +{ + property float StartRadius + { + public get() + { + return this.GetFloat("start_radius", 5.0); + } + } + + property float EndRadius + { + public get() + { + return this.GetFloat("end_radius", 10.0); + } + } + + property int StartFrame + { + public get() + { + return this.GetInt("start_frame", 0); + } + } + + property int FrameRate + { + public get() + { + return this.GetInt("framerate", 12); + } + } + + property float Width + { + public get() + { + return this.GetFloat("width", 100.0); + } + } + + property float Amplitude + { + public get() + { + return this.GetFloat("amplitude", 1.0); + } + } + + property int Speed + { + public get() + { + return this.GetInt("speed", 5); + } + } + + property int Flags + { + public get() + { + return this.GetInt("flags", 0); + } + } + + public void GetRingColor(int buffer[4]) + { + this.GetColor("color", buffer); + } + + public void GetBeamSprite(char[] buffer, int bufferSize) + { + this.GetString("beam_sprite", buffer, bufferSize, "sprites/laser.vmt"); + } + + public void GetHaloSprite(char[] buffer, int bufferSize) + { + this.GetString("halo_sprite", buffer, bufferSize, "sprites/halo01.vmt"); + } + + property int BeamModel + { + public get() + { + return this.GetInt("__beam_model", -1); + } + + public set(int value) + { + this.SetInt("__beam_model", value); + } + } + + property int HaloModel + { + public get() + { + return this.GetInt("__halo_model", -1); + } + + public set(int value) + { + this.SetInt("__halo_model", value); + } + } + + public void Precache() + { + char sprite[PLATFORM_MAX_PATH], buffer[PLATFORM_MAX_PATH]; + this.GetBeamSprite(sprite, sizeof(sprite)); + if (sprite[0] != '\0') + { + this.BeamModel = PrecacheModel(sprite, true); + FormatEx(buffer, sizeof(buffer), "materials/%s", sprite); + AddFileToDownloadsTable(buffer); + } + + this.GetHaloSprite(sprite, sizeof(sprite)); + if (sprite[0] != '\0') + { + this.HaloModel = PrecacheModel(sprite, true); + FormatEx(buffer, sizeof(buffer), "materials/%s", sprite); + AddFileToDownloadsTable(buffer); + } + } +} + +methodmap ProfileEffect_TEParticle < ProfileEffect +{ + property int AttachType + { + public get() + { + int val = 0; + char attachType[64]; + this.GetString("attach_type", attachType, sizeof(attachType)); + if (strcmp(attachType, "follow_origin", false) == 0) + { + val = 1; + } + else if (strcmp(attachType, "start_at_customorigin", false) == 0) + { + val = 2; + } + else if (strcmp(attachType, "start_at_attachment", false) == 0) + { + val = 3; + } + else if (strcmp(attachType, "follow_attachment", false) == 0) + { + val = 4; + } + else if (strcmp(attachType, "start_at_worldorigin", false) == 0) + { + val = 5; + } + else if (strcmp(attachType, "follow_rootbone", false) == 0) + { + val = 6; + } + return val; + } + } + + property bool ResetParticles + { + public get() + { + return this.GetBool("reset_particles", true); + } + } + + property bool HasControlPoint + { + public get() + { + return this.GetBool("control_point", false); + } + } + + property int ControlPointAttachType + { + public get() + { + return this.GetInt("control_point_attach_type", 0); + } + } + + public void GetName(char[] buffer, int bufferSize) + { + this.GetString("particlename", buffer, bufferSize); + } + + public void GetStartPos(float buffer[3]) + { + this.GetVector("start", buffer); + } + + public void GetControlPointOffset(float buffer[3]) + { + this.GetVector("control_point_offset", buffer); + } +} + +methodmap ProfileEffect_Sound < ProfileEffect +{ + property ProfileSound Sounds + { + public get() + { + return view_as(this); + } + } + + public void Precache() + { + if (this.Sounds != null) + { + this.Sounds.Precache(); + } + } +} + void InitializeEffects() { g_OnEntityDestroyedPFwd.AddFunction(null, EntityDestroyed); @@ -31,7 +704,7 @@ static void EntityDestroyed(CBaseEntity ent, const char[] classname) } } -void SlenderSpawnEffects(ArrayList effects, int bossIndex, bool nonEffects = true, const float overridePos[3] = { 0.0, 0.0, 0.0 }, const float overrideAng[3] = { 0.0, 0.0, 0.0 }, ArrayList &output = null, int entityOverride = INVALID_ENT_REFERENCE, bool noParenting = false) +void SlenderSpawnEffects(ProfileEffectMaster effects, int bossIndex, bool nonEffects = true, const float overridePos[3] = { 0.0, 0.0, 0.0 }, const float overrideAng[3] = { 0.0, 0.0, 0.0 }, ArrayList &output = null, int entityOverride = INVALID_ENT_REFERENCE, bool noParenting = false) { if (bossIndex < 0 || bossIndex >= MAX_BOSSES) { @@ -48,6 +721,7 @@ void SlenderSpawnEffects(ArrayList effects, int bossIndex, bool nonEffects = tru char profile[SF2_MAX_PROFILE_NAME_LENGTH]; NPCGetProfile(bossIndex, profile, sizeof(profile)); + BaseBossProfile profileData = GetBossProfile(profile); if (g_NpcEffectsArray[bossIndex] == null) { @@ -56,7 +730,7 @@ void SlenderSpawnEffects(ArrayList effects, int bossIndex, bool nonEffects = tru if (nonEffects) { - if (NPCGetDiscoModeState(bossIndex)) + if (profileData.DiscoMode) { int light = CreateEntityByName("light_dynamic"); int particle = CreateEntityByName("info_particle_system"); @@ -71,9 +745,9 @@ void SlenderSpawnEffects(ArrayList effects, int bossIndex, bool nonEffects = tru TeleportEntity(light, effectPos, effectAng, NULL_VECTOR); SetVariantInt(5); AcceptEntityInput(light, "Brightness"); - SetVariantFloat(GetRandomFloat(NPCGetDiscoModeRadiusMin(bossIndex), NPCGetDiscoModeRadiusMax(bossIndex))); + SetVariantFloat(GetRandomFloat(profileData.DiscoDistanceMin, profileData.DiscoDistanceMax)); AcceptEntityInput(light, "Distance"); - SetVariantFloat(GetRandomFloat(NPCGetDiscoModeRadiusMin(bossIndex), NPCGetDiscoModeRadiusMax(bossIndex))); + SetVariantFloat(GetRandomFloat(profileData.DiscoDistanceMin, profileData.DiscoDistanceMax)); AcceptEntityInput(light, "spotlight_radius"); SetVariantInt(1); AcceptEntityInput(light, "cone"); @@ -98,7 +772,7 @@ void SlenderSpawnEffects(ArrayList effects, int bossIndex, bool nonEffects = tru float effectPos[3], effectAng[3], basePosX[3], baseAngX[3]; GetEntPropVector(slenderEnt, Prop_Data, "m_vecAbsOrigin", basePosX); GetEntPropVector(slenderEnt, Prop_Data, "m_angAbsRotation", baseAngX); - CopyVector(NPCGetDiscoModePos(bossIndex), effectPos); + profileData.GetDiscoPos(effectPos); VectorTransform(effectPos, basePosX, baseAngX, effectPos); AddVectors(effectAng, baseAngX, effectAng); TeleportEntity(particle, effectPos, effectAng, NULL_VECTOR); @@ -114,7 +788,7 @@ void SlenderSpawnEffects(ArrayList effects, int bossIndex, bool nonEffects = tru g_NpcEffectsArray[bossIndex].Push(particle); } } - if (NPCGetFestiveLightState(bossIndex)) + if (profileData.FestiveLights) { int light = CreateEntityByName("light_dynamic"); if (light != -1) @@ -122,16 +796,16 @@ void SlenderSpawnEffects(ArrayList effects, int bossIndex, bool nonEffects = tru float effectPos[3], effectAng[3], basePosX[3], baseAngX[3]; GetEntPropVector(slenderEnt, Prop_Data, "m_vecAbsOrigin", basePosX); GetEntPropVector(slenderEnt, Prop_Data, "m_angAbsRotation", baseAngX); - CopyVector(NPCGetFestiveLightPosition(bossIndex), effectPos); - CopyVector(NPCGetFestiveLightAngle(bossIndex), effectAng); + profileData.GetFestiveLightPos(effectPos); + profileData.GetFestiveLightAng(effectPos); VectorTransform(effectPos, basePosX, baseAngX, effectPos); AddVectors(effectAng, baseAngX, effectAng); TeleportEntity(light, effectPos, effectAng, NULL_VECTOR); - SetVariantInt(NPCGetFestiveLightBrightness(bossIndex)); + SetVariantInt(profileData.FestiveLightBrightness); AcceptEntityInput(light, "Brightness"); - SetVariantFloat(NPCGetFestiveLightDistance(bossIndex)); + SetVariantFloat(profileData.FestiveLightDistance); AcceptEntityInput(light, "Distance"); - SetVariantFloat(NPCGetFestiveLightRadius(bossIndex)); + SetVariantFloat(profileData.FestiveLightRadius); AcceptEntityInput(light, "spotlight_radius"); SetVariantInt(1); AcceptEntityInput(light, "cone"); @@ -170,15 +844,22 @@ void SlenderSpawnEffects(ArrayList effects, int bossIndex, bool nonEffects = tru return; } - SF2BossProfileBaseEffectInfo effectsInfo; - for (int i = 0, size = effects.Length; i < size; i++) + ProfileEffect effect; + for (int i = 0, size = effects.SectionLength; i < size; i++) { - effects.GetArray(i, effectsInfo, sizeof(effectsInfo)); + char key[128]; + effects.GetSectionNameFromIndex(i, key, sizeof(key)); + effect = view_as(effects.GetSection(key)); + + if (effect == null) + { + continue; + } // Validate effect event and type. Check to see if it matches with ours. - if (effectsInfo.Event != EffectEvent_Invalid) + if (effect.Event != EffectEvent_Invalid) { - if (effectsInfo.Type != EffectType_Invalid) + if (effect.Type != EffectType_Invalid) { // Check base position behavior. if (!slenderEnt || slenderEnt == INVALID_ENT_REFERENCE) @@ -187,11 +868,11 @@ void SlenderSpawnEffects(ArrayList effects, int bossIndex, bool nonEffects = tru continue; } - if (effectsInfo.Delay > 0.0) + if (effect.Delay > 0.0) { DataPack pack; - CreateDataTimer(effectsInfo.Delay, Timer_SpawnEffect, pack, TIMER_FLAG_NO_MAPCHANGE); - pack.WriteCellArray(effectsInfo, sizeof(effectsInfo)); + CreateDataTimer(effect.Delay, Timer_SpawnEffect, pack, TIMER_FLAG_NO_MAPCHANGE); + pack.WriteCell(effect); pack.WriteCell(bossIndex); pack.WriteCellArray(overridePos, sizeof(overridePos)); pack.WriteCellArray(overrideAng, sizeof(overrideAng)); @@ -201,12 +882,14 @@ void SlenderSpawnEffects(ArrayList effects, int bossIndex, bool nonEffects = tru } else { - SpawnEffect(effectsInfo, bossIndex, overridePos, overrideAng, output, entityOverride, noParenting); + SpawnEffect(effect, bossIndex, overridePos, overrideAng, output, entityOverride, noParenting); } } else { - LogError("Could not spawn effect %s for boss %d: invalid type!", effectsInfo.SectionName, bossIndex); + char section[64]; + effect.GetSectionName(section, sizeof(section)); + LogError("Could not spawn effect %s for boss %d: invalid type!", section, bossIndex); } } } @@ -215,8 +898,7 @@ void SlenderSpawnEffects(ArrayList effects, int bossIndex, bool nonEffects = tru static Action Timer_SpawnEffect(Handle timer, DataPack pack) { pack.Reset(); - SF2BossProfileBaseEffectInfo effect; - pack.ReadCellArray(effect, sizeof(effect)); + ProfileEffect effect = pack.ReadCell(); int bossIndex = pack.ReadCell(); float overridePos[3], overrideAng[3]; pack.ReadCellArray(overridePos, sizeof(overridePos)); @@ -228,11 +910,11 @@ static Action Timer_SpawnEffect(Handle timer, DataPack pack) return Plugin_Stop; } -static void SpawnEffect(SF2BossProfileBaseEffectInfo effectsInfo, int bossIndex, const float overridePos[3] = { 0.0, 0.0, 0.0 }, const float overrideAng[3] = { 0.0, 0.0, 0.0 }, ArrayList &output = null, int entityOverride = INVALID_ENT_REFERENCE, bool noParenting = false) +static void SpawnEffect(ProfileEffect effect, int bossIndex, const float overridePos[3] = { 0.0, 0.0, 0.0 }, const float overrideAng[3] = { 0.0, 0.0, 0.0 }, ArrayList &output = null, int entityOverride = INVALID_ENT_REFERENCE, bool noParenting = false) { int slenderEnt = NPCGetEntIndex(bossIndex); int attacher = slenderEnt; - if (entityOverride != INVALID_ENT_REFERENCE && effectsInfo.AttachPlayer) + if (entityOverride != INVALID_ENT_REFERENCE && effect.AttachPlayer) { attacher = entityOverride; } @@ -255,7 +937,7 @@ static void SpawnEffect(SF2BossProfileBaseEffectInfo effectsInfo, int bossIndex, GetEntPropVector(attacher, Prop_Data, "m_angAbsRotation", baseAng); } - int difficultyIndex = effectsInfo.DifficultyIndexes; + int difficultyIndex = effect.DifficultyIndexes; char indexes[8], currentIndex[2]; FormatEx(indexes, sizeof(indexes), "%d", difficultyIndex); FormatEx(currentIndex, sizeof(currentIndex), "%d", g_DifficultyConVar.IntValue); @@ -277,7 +959,10 @@ static void SpawnEffect(SF2BossProfileBaseEffectInfo effectsInfo, int bossIndex, int entity = -1; bool isEntity = true; - switch (effectsInfo.Type) + char section[64]; + effect.GetSectionName(section, sizeof(section)); + + switch (effect.Type) { case EffectType_Steam: { @@ -315,8 +1000,8 @@ static void SpawnEffect(SF2BossProfileBaseEffectInfo effectsInfo, int bossIndex, float effectPos[3], effectAng[3]; - effectPos = effectsInfo.Origin; - effectAng = effectsInfo.Angles; + effect.GetOrigin(effectPos); + effect.GetAngles(effectAng); VectorTransform(effectPos, basePos, baseAng, effectPos); AddVectors(effectAng, baseAng, effectAng); @@ -324,62 +1009,69 @@ static void SpawnEffect(SF2BossProfileBaseEffectInfo effectsInfo, int bossIndex, if (entity != -1 && isEntity) { TeleportEntity(entity, effectPos, effectAng, NULL_VECTOR); - char value[PLATFORM_MAX_PATH]; - DispatchKeyValueInt(entity, "renderamt", effectsInfo.FadeAlpha); - DispatchKeyValueInt(entity, "rendermode", view_as(effectsInfo.RenderModes)); - DispatchKeyValueInt(entity, "renderfx", view_as(effectsInfo.RenderEffects)); - DispatchKeyValueInt(entity, "spawnflags", effectsInfo.SpawnFlags); + DispatchKeyValueInt(entity, "renderamt", effect.FadeAlpha); + DispatchKeyValueInt(entity, "rendermode", view_as(effect.RenderMode)); + DispatchKeyValueInt(entity, "renderfx", view_as(effect.RenderEffect)); + DispatchKeyValueInt(entity, "spawnflags", effect.SpawnFlags); - switch (effectsInfo.Type) + switch (effect.Type) { case EffectType_Steam: { - DispatchKeyValueInt(entity, "SpreadSpeed", effectsInfo.SteamSpreadSpeed); - DispatchKeyValueInt(entity, "Speed", effectsInfo.SteamSpeed); - DispatchKeyValueInt(entity, "StartSize", effectsInfo.SteamStartSize); - DispatchKeyValueInt(entity, "EndSize", effectsInfo.SteamEndSize); - DispatchKeyValueInt(entity, "Rate", effectsInfo.SteamRate); - DispatchKeyValueInt(entity, "Jetlength", effectsInfo.SteamJetLength); - DispatchKeyValueFloat(entity, "RollSpeed", effectsInfo.SteamRollSpeed); - DispatchKeyValueInt(entity, "type", effectsInfo.SteamType); + ProfileEffect_Steam steam = view_as(effect); + DispatchKeyValueInt(entity, "SpreadSpeed", steam.SpreadSpeed); + DispatchKeyValueInt(entity, "Speed", steam.Speed); + DispatchKeyValueInt(entity, "StartSize", steam.StartSize); + DispatchKeyValueInt(entity, "EndSize", steam.EndSize); + DispatchKeyValueInt(entity, "Rate", steam.Rate); + DispatchKeyValueInt(entity, "Jetlength", steam.JetLength); + DispatchKeyValueFloat(entity, "RollSpeed", steam.RollSpeed); + DispatchKeyValueInt(entity, "type", steam.ParticleType); DispatchSpawn(entity); ActivateEntity(entity); } case EffectType_DynamicLight: { - SetVariantInt(effectsInfo.LightBrightness); + ProfileEffect_DynamicLight light = view_as(effect); + SetVariantInt(light.Brightness); AcceptEntityInput(entity, "Brightness"); - SetVariantFloat(effectsInfo.LightMaxDistance); + SetVariantFloat(light.Distance); AcceptEntityInput(entity, "Distance"); - SetVariantFloat(effectsInfo.LightMaxDistance); + SetVariantFloat(light.Distance); AcceptEntityInput(entity, "spotlight_radius"); - SetVariantInt(effectsInfo.LightCone); + SetVariantInt(light.Cone); AcceptEntityInput(entity, "cone"); DispatchSpawn(entity); ActivateEntity(entity); int renderColor[4]; - effectsInfo.Colors.GetArray(difficulty, renderColor, sizeof(renderColor)); + light.GetRenderColor(difficulty, renderColor); SetEntityRenderColor(entity, renderColor[0], renderColor[1], renderColor[2], renderColor[3]); - SetEntProp(entity, Prop_Data, "m_LightStyle", effectsInfo.LightStyle); + SetEntProp(entity, Prop_Data, "m_LightStyle", light.LightStyle); } case EffectType_Particle: { - DispatchKeyValue(entity, "effect_name", effectsInfo.ParticleName); + ProfileEffect_Particle particle = view_as(effect); + char name[64]; + particle.GetName(name, sizeof(name)); + DispatchKeyValue(entity, "effect_name", name); DispatchSpawn(entity); ActivateEntity(entity); } case EffectType_Trail: { - DispatchKeyValueFloat(entity, "lifetime", effectsInfo.TrailTime); - DispatchKeyValueFloat(entity, "startwidth", effectsInfo.TrailStartWidth); - DispatchKeyValueFloat(entity, "endwidth", effectsInfo.TrailEndWidth); - DispatchKeyValue(entity, "spritename", effectsInfo.TrailName); + ProfileEffect_Trail trail = view_as(effect); + char name[64]; + trail.GetName(name, sizeof(name)); + DispatchKeyValueFloat(entity, "lifetime", trail.Time); + DispatchKeyValueFloat(entity, "startwidth", trail.StartWidth); + DispatchKeyValueFloat(entity, "endwidth", trail.EndWidth); + DispatchKeyValue(entity, "spritename", name); SetEntPropFloat(entity, Prop_Send, "m_flTextureRes", 0.05); int renderColor[4]; - effectsInfo.Colors.GetArray(difficulty, renderColor, sizeof(renderColor)); + trail.GetRenderColor(difficulty, renderColor); SetEntityRenderColor(entity, renderColor[0], renderColor[1], renderColor[2], renderColor[3]); DispatchSpawn(entity); @@ -387,23 +1079,28 @@ static void SpawnEffect(SF2BossProfileBaseEffectInfo effectsInfo, int bossIndex, } case EffectType_PropDynamic: { - DispatchKeyValue(entity, "model", effectsInfo.ModelName); - float modelScale = effectsInfo.ModelScale; - if (SF_SpecialRound(SPECIALROUND_TINYBOSSES) && modelScale != GetEntPropFloat(attacher, Prop_Send, "m_flModelScale") && !effectsInfo.AttachPlayer) + ProfileEffect_PropDynamic prop = view_as(effect); + char name[64]; + prop.GetName(name, sizeof(name)); + DispatchKeyValue(entity, "model", name); + float modelScale = prop.Scale; + if (SF_SpecialRound(SPECIALROUND_TINYBOSSES) && modelScale != GetEntPropFloat(attacher, Prop_Send, "m_flModelScale") && !prop.AttachPlayer) { modelScale *= 0.5; } DispatchKeyValueFloat(entity, "modelscale", modelScale); - SetEntProp(entity, Prop_Send, "m_nSkin", effectsInfo.ModelSkin); - SetEntProp(entity, Prop_Send, "m_fEffects", EF_BONEMERGE|EF_PARENT_ANIMATES); - if (effectsInfo.ModelAnimation[0] != '\0') + SetEntProp(entity, Prop_Send, "m_nSkin", prop.Skin); + SetEntProp(entity, Prop_Send, "m_fEffects", EF_BONEMERGE | EF_PARENT_ANIMATES); + char animation[64]; + prop.GetAnimation(animation, sizeof(animation)); + if (animation[0] != '\0') { - SetVariantString(value); + SetVariantString(animation); AcceptEntityInput(entity, "SetAnimation"); } int renderColor[4]; - effectsInfo.Colors.GetArray(difficulty, renderColor, sizeof(renderColor)); + prop.GetRenderColor(difficulty, renderColor); SetEntityRenderColor(entity, renderColor[0], renderColor[1], renderColor[2], renderColor[3]); DispatchSpawn(entity); @@ -411,34 +1108,38 @@ static void SpawnEffect(SF2BossProfileBaseEffectInfo effectsInfo, int bossIndex, } case EffectType_PointSpotlight: { + ProfileEffect_PointSpotlight light = view_as(effect); int renderColor[4]; - effectsInfo.Colors.GetArray(difficulty, renderColor, sizeof(renderColor)); + light.GetRenderColor(difficulty, renderColor); + + char attachment[64]; + light.GetAttachment(attachment, sizeof(attachment)); SF2PointSpotlightEntity spotlight = SF2PointSpotlightEntity(entity); - if (effectsInfo.AttachmentName[0] != '\0') + if (attachment[0] != '\0') { SetVariantString("!activator"); spotlight.Start.AcceptInput("ClearParent"); SetVariantString("!activator"); spotlight.Start.AcceptInput("SetParent", attacher); - SetVariantString(effectsInfo.AttachmentName); + SetVariantString(attachment); spotlight.Start.AcceptInput("SetParentAttachmentMaintainOffset"); SetVariantString("!activator"); spotlight.End.AcceptInput("ClearParent"); SetVariantString("!activator"); spotlight.End.AcceptInput("SetParent", attacher); - SetVariantString(effectsInfo.AttachmentName); + SetVariantString(attachment); spotlight.End.AcceptInput("SetParentAttachmentMaintainOffset"); } spotlight.SetRenderColor(renderColor[0], renderColor[1], renderColor[2], renderColor[3]); - spotlight.Length = effectsInfo.SpotlightLength; - spotlight.Width = effectsInfo.SpotlightWidth; + spotlight.Length = light.Length; + spotlight.Width = light.Width; spotlight.EndWidth = spotlight.Width * 2.0; - spotlight.Brightness = effectsInfo.LightBrightness; - spotlight.Distance = effectsInfo.LightMaxDistance; - spotlight.SpotlightRadius = effectsInfo.LightMaxDistance; - spotlight.Cone = effectsInfo.LightCone; - spotlight.HaloScale = effectsInfo.SpotlightHaloScale; + spotlight.Brightness = light.Brightness; + spotlight.Distance = light.Distance; + spotlight.SpotlightRadius = light.Distance; + spotlight.Cone = light.Cone; + spotlight.HaloScale = light.HaloScale; spotlight.Spawn(); spotlight.Activate(); @@ -449,12 +1150,15 @@ static void SpawnEffect(SF2BossProfileBaseEffectInfo effectsInfo, int bossIndex, } case EffectType_Sprite: { + ProfileEffect_Sprite sprite = view_as(effect); + char name[64]; + sprite.GetName(name, sizeof(name)); DispatchKeyValue(entity, "classname", "env_sprite"); - DispatchKeyValue(entity, "model", effectsInfo.SpriteName); - DispatchKeyValueFloat(entity, "scale", effectsInfo.SpriteScale); + DispatchKeyValue(entity, "model", name); + DispatchKeyValueFloat(entity, "scale", sprite.Scale); int renderColor[4]; - effectsInfo.Colors.GetArray(difficulty, renderColor, sizeof(renderColor)); + sprite.GetRenderColor(difficulty, renderColor); SetEntityRenderColor(entity, renderColor[0], renderColor[1], renderColor[2], renderColor[3]); @@ -463,7 +1167,7 @@ static void SpawnEffect(SF2BossProfileBaseEffectInfo effectsInfo, int bossIndex, } } - float lifeTime = effectsInfo.LifeTime; + float lifeTime = effect.LifeTime; if (lifeTime > 0.0) { CreateTimer(lifeTime, Timer_KillEntity, EntIndexToEntRef(entity), TIMER_FLAG_NO_MAPCHANGE); @@ -473,30 +1177,29 @@ static void SpawnEffect(SF2BossProfileBaseEffectInfo effectsInfo, int bossIndex, { if (!attacher || attacher == INVALID_ENT_REFERENCE) { - LogError("Could not parent effect %s of boss %d to itself: boss entity does not exist!", effectsInfo.SectionName, bossIndex); + LogError("Could not parent effect %s of boss %d to itself: boss entity does not exist!", section, bossIndex); return; } SetVariantString("!activator"); AcceptEntityInput(entity, "SetParent", attacher); - if (effectsInfo.Attachment) + char attachment[64]; + effect.GetAttachment(attachment, sizeof(attachment)); + if (attachment[0] != '\0') { - if (effectsInfo.AttachmentName[0] != '\0') + SetVariantString(attachment); + if (effect.Type != EffectType_PropDynamic && effect.Type != EffectType_PointSpotlight) { - SetVariantString(effectsInfo.AttachmentName); - if (effectsInfo.Type != EffectType_PropDynamic && effectsInfo.Type != EffectType_PointSpotlight) - { - AcceptEntityInput(entity, "SetParentAttachment"); - } - else - { - AcceptEntityInput(entity, "SetParentAttachmentMaintainOffset"); - } + AcceptEntityInput(entity, "SetParentAttachment"); + } + else + { + AcceptEntityInput(entity, "SetParentAttachmentMaintainOffset"); } } } - switch (effectsInfo.Type) + switch (effect.Type) { case EffectType_Steam, EffectType_DynamicLight: @@ -521,8 +1224,8 @@ static void SpawnEffect(SF2BossProfileBaseEffectInfo effectsInfo, int bossIndex, } } SDKHook(entity, SDKHook_SetTransmit, Hook_EffectTransmit); - g_EntityEffectType[entity] = effectsInfo.Type; - g_EntityEffectEvent[entity] = effectsInfo.Event; + g_EntityEffectType[entity] = effect.Type; + g_EntityEffectEvent[entity] = effect.Event; if (!noParenting) { g_NpcEffectsArray[bossIndex].Push(entity); @@ -535,41 +1238,41 @@ static void SpawnEffect(SF2BossProfileBaseEffectInfo effectsInfo, int bossIndex, } else { - switch (effectsInfo.Type) + switch (effect.Type) { case EffectType_TempEntBeamRing: { - char colorString[32]; - strcopy(colorString, sizeof(colorString), effectsInfo.BeamRingColor); - char keys[4][4]; - ExplodeString(colorString, " ", keys, sizeof(keys), sizeof(keys)); + ProfileEffect_TEBeamRing ring = view_as(effect); int color[4]; - for (int i2 = 0; i2 < 4; i2++) - { - color[i2] = StringToInt(keys[i2]); - } + ring.GetRingColor(color); - TE_SetupBeamRingPoint(effectPos, effectsInfo.BeamRingStartRadius, effectsInfo.BeamRingEndRadius, effectsInfo.BeamRingBeamModel, effectsInfo.BeamRingHaloModel, effectsInfo.BeamRingStartFrame, effectsInfo.BeamRingFrameRate, effectsInfo.LifeTime, effectsInfo.BeamRingWidth, effectsInfo.BeamRingAmplitude, color, effectsInfo.BeamRingSpeed, effectsInfo.BeamRingFlags); + TE_SetupBeamRingPoint(effectPos, ring.StartRadius, ring.EndRadius, ring.BeamModel, ring.HaloModel, ring.StartFrame, ring.FrameRate, ring.LifeTime, ring.Width, ring.Amplitude, color, ring.Speed, ring.Flags); TE_SendToAll(); } case EffectType_TempEntParticle: { - if (effectsInfo.ParticleName[0] == '\0') + ProfileEffect_TEParticle particle = view_as(effect); + char name[64]; + particle.GetName(name, sizeof(name)); + if (name[0] == '\0') { return; } - int particle = PrecacheParticleSystem(effectsInfo.ParticleName); - if (particle == -1) + int particleIndex = PrecacheParticleSystem(name); + if (particleIndex == -1) { return; } - int attachment = LookupEntityAttachment(attacher, effectsInfo.AttachmentName); + char attachment[64]; + particle.GetAttachment(attachment, sizeof(attachment)); + int attachmentIndex = LookupEntityAttachment(attacher, attachment); - float start[3], pos[3], ang[3]; - start = effectsInfo.TEParticleStartPos; - if (effectsInfo.TEParticleAttachType == 2) + float start[3], pos[3], ang[3], offset[3]; + particle.GetStartPos(start); + particle.GetControlPointOffset(offset); + if (particle.AttachType == 2) { VectorTransform(start, basePos, baseAng, start); pos = start; @@ -580,12 +1283,13 @@ static void SpawnEffect(SF2BossProfileBaseEffectInfo effectsInfo, int bossIndex, pos = effectPos; ang = effectAng; } - TE_Particle(particle, pos, start, ang, attacher, effectsInfo.TEParticleAttachType, attachment, effectsInfo.TEParticleReset, effectsInfo.TEParticleHasControlPoint, effectsInfo.TEParticleControlPointAttachType, effectsInfo.TEParticleControlPointOffset); + TE_Particle(particleIndex, pos, start, ang, attacher, particle.AttachType, attachmentIndex, particle.ResetParticles, particle.HasControlPoint, particle.ControlPointAttachType, offset); TE_SendToAll(); } case EffectType_Sound: { - effectsInfo.SoundSounds.EmitSound(_, attacher); + ProfileEffect_Sound sound = view_as(effect); + sound.Sounds.EmitSound(_, attacher); } } } @@ -615,7 +1319,7 @@ static Action Hook_EffectTransmit(int ent, int other) SF2_BasePlayer player = SF2_BasePlayer(other); if (player.IsValid && !player.IsEliminated && !player.IsInGhostMode && !player.HasEscaped) { - if (g_EntityEffectEvent[ent] == EffectEvent_PlayerSeesBoss && !controller.PlayerCanSee(player.index)) + if (g_EntityEffectEvent[ent] == EffectEvent_PlayerSeesBoss && !controller.PlayerCanSee(player.index) && !player.IsInDeathCam) { return Plugin_Handled; } @@ -741,12 +1445,16 @@ static Action Timer_DiscoLight(Handle timer, any effect) return Plugin_Stop; } + char profile[SF2_MAX_PROFILE_NAME_LENGTH]; + NPCGetProfile(bossIndex, profile, sizeof(profile)); + BaseBossProfile profileData = GetBossProfile(profile); + int rChase = GetRandomInt(75, 250); int gChase = GetRandomInt(75, 250); int bChase = GetRandomInt(75, 250); SetEntityRenderColor(effect, rChase, gChase, bChase, 255); - float distanceRNG = GetRandomFloat(NPCGetDiscoModeRadiusMin(bossIndex), NPCGetDiscoModeRadiusMax(bossIndex)); + float distanceRNG = GetRandomFloat(profileData.DiscoDistanceMin, profileData.DiscoDistanceMax); SetVariantFloat(distanceRNG); AcceptEntityInput(effect, "Distance"); @@ -788,3 +1496,63 @@ static Action Timer_FestiveLight(Handle timer, any effect) return Plugin_Continue; } + +void SetupNPCEffectsAPI() +{ + CreateNative("SF2_ProfileEffect.Type.get", Native_GetEffectType); + CreateNative("SF2_ProfileEffect.Precache", Native_EffectPrecache); + + CreateNative("SF2_ProfileEffectMaster.Precache", Native_MasterEffectPrecache); + CreateNative("SF2_ProfileEffectMaster.Spawn", Native_MasterEffectSpawn); +} + +static any Native_GetEffectType(Handle plugin, int numParams) +{ + ProfileEffect effect = GetNativeCell(1); + if (effect == null) + { + return ThrowNativeError(SP_ERROR_NATIVE, "Invalid Handle %x", effect); + } + + return effect.Type; +} + +static any Native_EffectPrecache(Handle plugin, int numParams) +{ + ProfileEffect effect = GetNativeCell(1); + if (effect == null) + { + return ThrowNativeError(SP_ERROR_NATIVE, "Invalid Handle %x", effect); + } + + effect.Precache(); + return 0; +} + +static any Native_MasterEffectPrecache(Handle plugin, int numParams) +{ + ProfileEffectMaster master = GetNativeCell(1); + if (master == null) + { + return ThrowNativeError(SP_ERROR_NATIVE, "Invalid Handle %x", master); + } + + master.Precache(); + return 0; +} + +static any Native_MasterEffectSpawn(Handle plugin, int numParams) +{ + ProfileEffectMaster master = GetNativeCell(1); + if (master == null) + { + return ThrowNativeError(SP_ERROR_NATIVE, "Invalid Handle %x", master); + } + + float pos[3], ang[3]; + GetNativeArray(3, pos, 3); + GetNativeArray(4, ang, 3); + ArrayList output = GetNativeCellRef(5); + SlenderSpawnEffects(master, GetNativeCell(2), false, pos, ang, output, GetNativeCell(6)); + return 0; +} diff --git a/addons/sourcemod/scripting/sf2/entities/initialize.sp b/addons/sourcemod/scripting/sf2/entities/initialize.sp index 87834773..d10d2cc9 100644 --- a/addons/sourcemod/scripting/sf2/entities/initialize.sp +++ b/addons/sourcemod/scripting/sf2/entities/initialize.sp @@ -1,3 +1,6 @@ +#pragma semicolon 1 +#pragma newdecls required + #include "sf2_base_projectile.sp" void InitializeCustomEntities() diff --git a/addons/sourcemod/scripting/sf2/entities/projectiles/sf2_arrow_projectile.sp b/addons/sourcemod/scripting/sf2/entities/projectiles/sf2_arrow_projectile.sp index 87d2464b..0ce8f11e 100644 --- a/addons/sourcemod/scripting/sf2/entities/projectiles/sf2_arrow_projectile.sp +++ b/addons/sourcemod/scripting/sf2/entities/projectiles/sf2_arrow_projectile.sp @@ -1,4 +1,5 @@ #pragma semicolon 1 +#pragma newdecls required static const char g_EntityClassname[] = "sf2_projectile_arrow"; diff --git a/addons/sourcemod/scripting/sf2/entities/projectiles/sf2_baseball_projectile.sp b/addons/sourcemod/scripting/sf2/entities/projectiles/sf2_baseball_projectile.sp index a9f6f33d..188d361c 100644 --- a/addons/sourcemod/scripting/sf2/entities/projectiles/sf2_baseball_projectile.sp +++ b/addons/sourcemod/scripting/sf2/entities/projectiles/sf2_baseball_projectile.sp @@ -1,4 +1,5 @@ #pragma semicolon 1 +#pragma newdecls required static const char g_EntityClassname[] = "sf2_projectile_baseball"; @@ -81,7 +82,7 @@ methodmap SF2_ProjectileBaseball < SF2_ProjectileGrenade ball.SetProp(Prop_Send, "m_usSolidFlags", 12); ball.KeyValue("solid", "2"); ball.KeyValue("spawnflags", "4"); - SetEntityCollisionGroup(ball.index, COLLISION_GROUP_DEBRIS_TRIGGER); + SetEntityCollisionGroup(ball.index, 13); ball.SetProp(Prop_Send, "m_usSolidFlags", 0); ball.Spawn(); @@ -117,9 +118,10 @@ static void Think(int entity) projectile.GetAbsOrigin(pos); projectile.GetPropVector(Prop_Send, "m_vecMins", mins); projectile.GetPropVector(Prop_Send, "m_vecMaxs", maxs); - TR_TraceHullFilter(pos, pos, mins, maxs, CONTENTS_SOLID | CONTENTS_MOVEABLE | CONTENTS_MIST | CONTENTS_MONSTERCLIP, TraceRayGrenade, projectile.index); + Handle trace = TR_TraceHullFilterEx(pos, pos, mins, maxs, CONTENTS_SOLID | CONTENTS_MOVEABLE | CONTENTS_MIST | CONTENTS_MONSTERCLIP, TraceRayGrenade, projectile.index); - int hitIndex = TR_GetEntityIndex(); + int hitIndex = TR_GetEntityIndex(trace); + delete trace; if (IsValidEntity(hitIndex)) { Call_StartForward(g_OnProjectileTouchFwd); diff --git a/addons/sourcemod/scripting/sf2/entities/projectiles/sf2_cow_mangler_projectile.sp b/addons/sourcemod/scripting/sf2/entities/projectiles/sf2_cow_mangler_projectile.sp index 44401841..593d6392 100644 --- a/addons/sourcemod/scripting/sf2/entities/projectiles/sf2_cow_mangler_projectile.sp +++ b/addons/sourcemod/scripting/sf2/entities/projectiles/sf2_cow_mangler_projectile.sp @@ -1,4 +1,5 @@ #pragma semicolon 1 +#pragma newdecls required static const char g_EntityClassname[] = "sf2_projectile_cowmangler"; diff --git a/addons/sourcemod/scripting/sf2/entities/projectiles/sf2_fireball_projectile.sp b/addons/sourcemod/scripting/sf2/entities/projectiles/sf2_fireball_projectile.sp index 3206cdbf..46b2f80c 100644 --- a/addons/sourcemod/scripting/sf2/entities/projectiles/sf2_fireball_projectile.sp +++ b/addons/sourcemod/scripting/sf2/entities/projectiles/sf2_fireball_projectile.sp @@ -1,4 +1,5 @@ #pragma semicolon 1 +#pragma newdecls required static const char g_EntityClassname[] = "sf2_projectile_fireball"; diff --git a/addons/sourcemod/scripting/sf2/entities/projectiles/sf2_grenade_projectile.sp b/addons/sourcemod/scripting/sf2/entities/projectiles/sf2_grenade_projectile.sp index 65dcb688..114338dc 100644 --- a/addons/sourcemod/scripting/sf2/entities/projectiles/sf2_grenade_projectile.sp +++ b/addons/sourcemod/scripting/sf2/entities/projectiles/sf2_grenade_projectile.sp @@ -1,4 +1,5 @@ #pragma semicolon 1 +#pragma newdecls required static const char g_EntityClassname[] = "sf2_projectile_grenade"; @@ -258,6 +259,7 @@ methodmap SF2_ProjectileGrenade < SF2_ProjectileBase grenade.Speed = speed; grenade.Damage = damage; grenade.BlastRadius = blastRadius; + grenade.IsCrits = isCrits; if (grenade.IsCrits) { CBaseEntity critParticle = grenade.CreateParticle("critical_grenade_blue"); @@ -272,7 +274,7 @@ methodmap SF2_ProjectileGrenade < SF2_ProjectileBase grenade.SetProp(Prop_Send, "m_nSkin", 1); grenade.KeyValue("solid", "2"); grenade.KeyValue("spawnflags", "4"); - SetEntityCollisionGroup(grenade.index, COLLISION_GROUP_DEBRIS_TRIGGER); + SetEntityCollisionGroup(grenade.index, 13); grenade.SetProp(Prop_Send, "m_usSolidFlags", 0); CBaseEntity particle = grenade.CreateParticle(grenade.GetTrailName()); @@ -287,39 +289,29 @@ methodmap SF2_ProjectileGrenade < SF2_ProjectileBase grenade.Timer = GetGameTime() + 2.0; CreateTimer(0.1, Timer_Think, EntIndexToEntRef(grenade.index), TIMER_FLAG_NO_MAPCHANGE | TIMER_REPEAT); + SDKHook(grenade.index, SDKHook_VPhysicsUpdate, OnVPhysicsUpdate); } } -static Action Timer_Think(Handle timer, any ref) +static void OnVPhysicsUpdate(int entity) { - int entity = EntRefToEntIndex(ref); - if (!entity || entity == INVALID_ENT_REFERENCE) - { - return Plugin_Stop; - } SF2_ProjectileGrenade projectile = SF2_ProjectileGrenade(entity); - if (projectile.Timer < GetGameTime()) - { - projectile.DoExplosion(); - if (projectile.IsValid()) - { - RemoveEdict(projectile.index); - } - } - if (projectile.Touched) { - return Plugin_Continue; + return; } float pos[3], mins[3], maxs[3]; projectile.GetAbsOrigin(pos); projectile.GetPropVector(Prop_Send, "m_vecMins", mins); projectile.GetPropVector(Prop_Send, "m_vecMaxs", maxs); - TR_TraceHullFilter(pos, pos, mins, maxs, CONTENTS_SOLID | CONTENTS_MOVEABLE | CONTENTS_MIST | CONTENTS_MONSTERCLIP, TraceRayGrenade, projectile.index); + ScaleVector(mins, 1.1); + ScaleVector(maxs, 1.1); + Handle trace = TR_TraceHullFilterEx(pos, pos, mins, maxs, CONTENTS_SOLID | CONTENTS_MOVEABLE | CONTENTS_MIST | CONTENTS_MONSTERCLIP, TraceRayGrenade, projectile.index); - int hitIndex = TR_GetEntityIndex(); + int hitIndex = TR_GetEntityIndex(trace); + delete trace; if (IsValidEntity(hitIndex)) { Call_StartForward(g_OnProjectileTouchFwd); @@ -330,7 +322,7 @@ static Action Timer_Think(Handle timer, any ref) if (hitIndex == 0) { projectile.Touched = true; - return Plugin_Continue; + return; } else { @@ -358,6 +350,30 @@ static Action Timer_Think(Handle timer, any ref) } } } +} + +static Action Timer_Think(Handle timer, any ref) +{ + int entity = EntRefToEntIndex(ref); + if (!entity || entity == INVALID_ENT_REFERENCE) + { + return Plugin_Stop; + } + SF2_ProjectileGrenade projectile = SF2_ProjectileGrenade(entity); + + if (projectile.Timer < GetGameTime()) + { + projectile.DoExplosion(); + if (projectile.IsValid()) + { + RemoveEdict(projectile.index); + } + } + + if (projectile.Touched) + { + return Plugin_Continue; + } return Plugin_Continue; } diff --git a/addons/sourcemod/scripting/sf2/entities/projectiles/sf2_iceball_projectile.sp b/addons/sourcemod/scripting/sf2/entities/projectiles/sf2_iceball_projectile.sp index 664e40b4..f996337d 100644 --- a/addons/sourcemod/scripting/sf2/entities/projectiles/sf2_iceball_projectile.sp +++ b/addons/sourcemod/scripting/sf2/entities/projectiles/sf2_iceball_projectile.sp @@ -1,4 +1,5 @@ #pragma semicolon 1 +#pragma newdecls required static const char g_EntityClassname[] = "sf2_projectile_iceball"; diff --git a/addons/sourcemod/scripting/sf2/entities/projectiles/sf2_rocket_projectile.sp b/addons/sourcemod/scripting/sf2/entities/projectiles/sf2_rocket_projectile.sp index 21ddebee..182aeade 100644 --- a/addons/sourcemod/scripting/sf2/entities/projectiles/sf2_rocket_projectile.sp +++ b/addons/sourcemod/scripting/sf2/entities/projectiles/sf2_rocket_projectile.sp @@ -1,4 +1,5 @@ #pragma semicolon 1 +#pragma newdecls required static const char g_EntityClassname[] = "sf2_projectile_rocket"; diff --git a/addons/sourcemod/scripting/sf2/entities/projectiles/sf2_sentry_rocket_projectile.sp b/addons/sourcemod/scripting/sf2/entities/projectiles/sf2_sentry_rocket_projectile.sp index 400c5ec4..c51999f3 100644 --- a/addons/sourcemod/scripting/sf2/entities/projectiles/sf2_sentry_rocket_projectile.sp +++ b/addons/sourcemod/scripting/sf2/entities/projectiles/sf2_sentry_rocket_projectile.sp @@ -1,4 +1,5 @@ #pragma semicolon 1 +#pragma newdecls required static const char g_EntityClassname[] = "sf2_projectile_sentryrocket"; diff --git a/addons/sourcemod/scripting/sf2/entities/sf2_base_projectile.sp b/addons/sourcemod/scripting/sf2/entities/sf2_base_projectile.sp index f6b6efde..0b203eee 100644 --- a/addons/sourcemod/scripting/sf2/entities/sf2_base_projectile.sp +++ b/addons/sourcemod/scripting/sf2/entities/sf2_base_projectile.sp @@ -1,4 +1,5 @@ #pragma semicolon 1 +#pragma newdecls required static CEntityFactory g_Factory; @@ -437,16 +438,18 @@ methodmap SF2_ProjectileBase < CBaseAnimating float targetPos[3]; valid.WorldSpaceCenter(targetPos); - TR_TraceRayFilter(pos, targetPos, + Handle trace = TR_TraceRayFilterEx(pos, targetPos, CONTENTS_SOLID | CONTENTS_MOVEABLE | CONTENTS_WINDOW | CONTENTS_MONSTER | CONTENTS_GRATE, RayType_EndPoint, TraceRayDontHitAnyEntity, this.index); - if (TR_DidHit() && TR_GetEntityIndex() != valid.index) + if (TR_DidHit(trace) && TR_GetEntityIndex(trace) != valid.index) { + delete trace; continue; } - TR_GetEndPosition(subtracted); + TR_GetEndPosition(subtracted, trace); + delete trace; SubtractVectors(pos, subtracted, subtracted); adjustedDamage = GetVectorLength(subtracted) * falloff; diff --git a/addons/sourcemod/scripting/sf2/extras/afk_mode.sp b/addons/sourcemod/scripting/sf2/extras/afk_mode.sp index b81d33b2..568e9bed 100644 --- a/addons/sourcemod/scripting/sf2/extras/afk_mode.sp +++ b/addons/sourcemod/scripting/sf2/extras/afk_mode.sp @@ -4,6 +4,7 @@ #define _sf2_afk_mode_included #pragma semicolon 1 +#pragma newdecls required static float g_AfkAtGameTime[MAXTF2PLAYERS]; diff --git a/addons/sourcemod/scripting/sf2/extras/commands.sp b/addons/sourcemod/scripting/sf2/extras/commands.sp index 8c0792a0..df394aad 100644 --- a/addons/sourcemod/scripting/sf2/extras/commands.sp +++ b/addons/sourcemod/scripting/sf2/extras/commands.sp @@ -4,6 +4,7 @@ #define _sf2_commands_included #pragma semicolon 1 +#pragma newdecls required public void OnPluginStart() { @@ -71,7 +72,6 @@ public void OnPluginStart() } g_Pages = new ArrayList(sizeof(SF2PageEntityData)); - g_PageMusicRanges = new ArrayList(3); g_EmptySpawnPagePoints = new ArrayList(); char valueToString[32]; @@ -112,6 +112,8 @@ public void OnPluginStart() g_DragonsFuryBurningBonusConVar = FindConVar("tf_fireball_burning_bonus"); g_DragonsFuryBurnDurationConVar = FindConVar("tf_fireball_burn_duration"); + g_TFBotForceClassConVar = FindConVar("tf_bot_force_class"); + g_PlayerShakeEnabledConVar = CreateConVar("sf2_player_shake_enabled", "1", "Enable/Disable player view shake during boss encounters.", _, true, 0.0, true, 1.0); g_PlayerShakeEnabledConVar.AddChangeHook(OnConVarChanged); g_PlayerShakeFrequencyMaxConVar = CreateConVar("sf2_player_shake_frequency_max", "255", "Maximum frequency value of the shake. Should be a value between 1-255.", _, true, 1.0, true, 255.0); @@ -351,6 +353,7 @@ public void OnPluginStart() RegAdminCmd("-alltalk", Command_AllTalkOff, ADMFLAG_SLAY); RegAdminCmd("+slalltalk", Command_AllTalkOn, ADMFLAG_SLAY, _, _, FCVAR_HIDDEN); RegAdminCmd("-slalltalk", Command_AllTalkOff, ADMFLAG_SLAY, _, _, FCVAR_HIDDEN); + RegAdminCmd("sm_sf2_do_trace", Command_DoTrace, ADMFLAG_CHEATS); RegServerCmd("load_itempreset", Command_BlockCommand); @@ -407,12 +410,16 @@ public void OnPluginStart() g_OnGameFramePFwd = new PrivateForward(ET_Ignore); g_OnRoundStartPFwd = new PrivateForward(ET_Ignore); g_OnRoundEndPFwd = new PrivateForward(ET_Ignore); + g_OnConfigsExecutedPFwd = new PrivateForward(ET_Ignore); g_OnEntityCreatedPFwd = new PrivateForward(ET_Ignore, Param_Cell, Param_String); g_OnEntityDestroyedPFwd = new PrivateForward(ET_Ignore, Param_Cell, Param_String); g_OnEntityTeleportedPFwd = new PrivateForward(ET_Ignore, Param_Cell, Param_Cell); + g_OnPostInitMapEntitiesPFwd = new PrivateForward(ET_Ignore); + g_OnPostInitNewGamePFwd = new PrivateForward(ET_Ignore); + g_OnRoundStateChangePFwd = new PrivateForward(ET_Ignore, Param_Cell, Param_Cell); g_OnPlayerJumpPFwd = new PrivateForward(ET_Ignore, Param_Cell); g_OnPlayerSpawnPFwd = new PrivateForward(ET_Ignore, Param_Cell); - g_OnPlayerTakeDamagePFwd = new PrivateForward(ET_Hook, Param_Cell, Param_CellByRef, Param_CellByRef, Param_FloatByRef, Param_CellByRef); + g_OnPlayerTakeDamagePFwd = new PrivateForward(ET_Hook, Param_Cell, Param_CellByRef, Param_CellByRef, Param_FloatByRef, Param_CellByRef, Param_Cell); g_OnPlayerDeathPrePFwd = new PrivateForward(ET_Ignore, Param_Cell, Param_Cell, Param_Cell, Param_Cell); g_OnPlayerDeathPFwd = new PrivateForward(ET_Ignore, Param_Cell, Param_Cell, Param_Cell, Param_Cell); g_OnPlayerPutInServerPFwd = new PrivateForward(ET_Ignore, Param_Cell); @@ -430,7 +437,10 @@ public void OnPluginStart() g_OnPlayerTurnOffFlashlightPFwd = new PrivateForward(ET_Ignore, Param_Cell); g_OnPlayerFlashlightBreakPFwd = new PrivateForward(ET_Ignore, Param_Cell); g_OnPlayerAverageUpdatePFwd = new PrivateForward(ET_Ignore, Param_Cell); + g_OnPlayerPostWeaponsPFwd = new PrivateForward(ET_Ignore, Param_Cell); + g_OnPageCountChangedPFwd = new PrivateForward(ET_Ignore, Param_Cell, Param_Cell); g_OnSpecialRoundStartPFwd = new PrivateForward(ET_Ignore, Param_Cell); + g_OnBossAddedPFwd = new PrivateForward(ET_Ignore, Param_Cell); g_OnBossSpawnPFwd = new PrivateForward(ET_Ignore, Param_Cell); g_OnBossRemovedPFwd = new PrivateForward(ET_Ignore, Param_Cell); g_OnChaserGetAttackActionPFwd = new PrivateForward(ET_Hook, Param_Cell, Param_String, Param_CellByRef); @@ -471,7 +481,7 @@ public void OnPluginStart() SetupHints(); SetupStatic(); SetupFlashlight(); - SetupMusic(); + SetupNewMusic(); SetupSprint(); SetupUltravision(); SetupPlayerGlows(); @@ -1128,14 +1138,14 @@ static Action Hook_CommandVoiceMenu(int client, const char[] command,int argc) int master = NPCGetFromUniqueID(g_PlayerProxyMaster[client]); if (master != -1) { - char profile[SF2_MAX_PROFILE_NAME_LENGTH]; - NPCGetProfile(master, profile, sizeof(profile)); - SF2BossProfileSoundInfo soundInfo; - GetBossProfileProxyIdleSounds(profile, soundInfo); + SF2NPC_BaseNPC npc = SF2NPC_BaseNPC(master); + BossProfileProxyData proxyData = npc.GetProfileDataEx().GetProxies(); + BossProfileProxyClass classData = proxyData.GetClassData(TF2_GetPlayerClass(client)); + ProfileSound soundInfo = classData.GetIdleSounds(); if (soundInfo.Paths != null && soundInfo.Paths.Length > 0 && GetGameTime() >= g_PlayerProxyNextVoiceSound[client]) { soundInfo.EmitSound(_, client); - g_PlayerProxyNextVoiceSound[client] = GetGameTime() + GetRandomFloat(soundInfo.CooldownMin, soundInfo.CooldownMax); + g_PlayerProxyNextVoiceSound[client] = GetGameTime() + GetRandomFloat(soundInfo.GetCooldownMin(npc.Difficulty), soundInfo.GetCooldownMax(npc.Difficulty)); } } } @@ -1181,7 +1191,22 @@ static Action Command_ClientKillDeathcam(int client, int args) for (int i = 0; i < target_count; i++) { int target = target_list[i]; - if (!IsValidClient(target) || !IsPlayerAlive(target) || g_PlayerEliminated[target] || IsClientInGhostMode(target)) + if (!IsValidClient(target) || !IsPlayerAlive(target) || IsClientInGhostMode(target)) + { + continue; + } + + bool eliminated = false; + SF2NPC_BaseNPC npc = SF2NPC_BaseNPC(StringToInt(arg2)); + if (npc.IsValid()) + { + if ((npc.Flags & SFF_ATTACKWAITERS) != 0 || npc.GetProfileDataEx().IsPvEBoss) + { + eliminated = true; + } + } + + if (!eliminated && g_PlayerEliminated[target]) { continue; } @@ -1263,9 +1288,7 @@ static Action Command_SpawnSlender(int client, int args) return Plugin_Handled; } - SF2BossProfileData data; - data = npc.GetProfileData(); - if (data.IsPvEBoss) + if (npc.GetProfileDataEx().IsPvEBoss) { ReplyToCommand(client, "You may not spawn PvE bosses!"); return Plugin_Handled; @@ -1329,9 +1352,7 @@ static Action Command_SpawnAllSlenders(int client, int args) npc = SF2NPC_BaseNPC(npcIndex); if (npc.IsValid()) { - SF2BossProfileData data; - data = npc.GetProfileData(); - if (data.IsPvEBoss) + if (npc.GetProfileDataEx().IsPvEBoss) { continue; } @@ -1386,9 +1407,7 @@ static Action Timer_SpawnAllSlenders(Handle timer, any userid) SF2NPC_BaseNPC npc = SF2NPC_BaseNPC(g_SpawnAllBossesCount); if (npc.IsValid()) { - SF2BossProfileData data; - data = npc.GetProfileData(); - if (!data.IsPvEBoss) + if (!npc.GetProfileDataEx().IsPvEBoss) { npc.Spawn(endPos); } @@ -1422,8 +1441,7 @@ static Action Command_RemoveSlender(int client, int args) char profile[SF2_MAX_PROFILE_NAME_LENGTH]; NPCGetProfile(bossIndex, profile, sizeof(profile)); - SF2BossProfileData data; - g_BossProfileData.GetArray(profile, data, sizeof(data)); + BaseBossProfile data = GetBossProfile(profile); if (data.IsPvEBoss) { ReplyToCommand(client, "You may not remove PvE bosses!"); @@ -1457,9 +1475,7 @@ static Action Command_RemoveAllSlenders(int client, int args) continue; } - SF2BossProfileData data; - data = npc.GetProfileData(); - if (data.IsPvEBoss) + if (npc.GetProfileDataEx().IsPvEBoss) { continue; } @@ -1478,11 +1494,6 @@ static Action Command_RemoveAllSlenders(int client, int args) } } - if (MusicActive()) - { - NPCStopMusic(); - } - return Plugin_Handled; } @@ -1770,34 +1781,6 @@ static Action Command_ReloadProfiles(int client, int args) ReloadClassConfigs(); } - for (int i = 0; i < MAX_BOSSES; i++) - { - SF2NPC_BaseNPC npc = SF2NPC_BaseNPC(i); - - if (!npc.IsValid()) - { - continue; - } - - char profile[SF2_MAX_PROFILE_NAME_LENGTH]; - npc.GetProfile(profile, sizeof(profile)); - SF2BossProfileData data; - g_BossProfileData.GetArray(profile, data, sizeof(data)); - NPCSetProfileData(npc.Index, data); - - if (npc.Type == SF2BossType_Chaser) - { - SF2ChaserBossProfileData chaserData; - g_ChaserBossProfileData.GetArray(profile, chaserData, sizeof(chaserData)); - NPCChaserSetProfileData(npc.Index, chaserData); - } - else if (npc.Type == SF2BossType_Statue) - { - SF2StatueBossProfileData statueData; - g_StatueBossProfileData.GetArray(profile, statueData, sizeof(statueData)); - NPCStatueSetProfileData(npc.Index, statueData); - } - } CPrintToChatAll("{royalblue}%t {default} Reloaded all profiles successfully.", "SF2 Prefix"); return Plugin_Handled; @@ -2272,8 +2255,7 @@ static Action Command_AddSlender(int client, int args) return Plugin_Handled; } - SF2BossProfileData data; - g_BossProfileData.GetArray(profile, data, sizeof(data)); + BaseBossProfile data = GetBossProfile(profile); if (data.IsPvEBoss) { ReplyToCommand(client, "You may not spawn PvE bosses!"); @@ -2283,7 +2265,7 @@ static Action Command_AddSlender(int client, int args) SF2NPC_BaseNPC npc = AddProfile(profile); if (npc.IsValid()) { - if (SF_IsBoxingMap() && (GetRoundState() == SF2RoundState_Escape) && NPCChaserIsBoxingBoss(npc.Index)) + if (SF_IsBoxingMap() && (GetRoundState() == SF2RoundState_Escape) && view_as(data).BoxingBoss) { g_SlenderBoxingBossCount++; } @@ -2390,8 +2372,7 @@ static Action Command_AddSlenderFake(int client, int args) return Plugin_Handled; } - SF2BossProfileData data; - g_BossProfileData.GetArray(profile, data, sizeof(data)); + BaseBossProfile data = GetBossProfile(profile); if (data.IsPvEBoss) { ReplyToCommand(client, "You may not spawn PvE bosses!"); @@ -2556,6 +2537,52 @@ static Action Command_AllTalkOff(int client, int args) return Plugin_Handled; } +static Action Command_DoTrace(int client, int args) +{ + if (!IsValidClient(client)) + { + return Plugin_Handled; + } + + float eyes[3], end[3], ang[3]; + end[0] = 5000.0; + GetClientEyePosition(client, eyes); + GetClientEyeAngles(client, ang); + VectorTransform(end, eyes, ang, end); + + Profiler profiler = new Profiler(); + + profiler.Start(); + Handle trace = TR_TraceHullFilterEx(eyes, end, { -16.0, -16.0, -16.0 }, { 16.0, 16.0, 16.0 }, MASK_NPCSOLID, TraceRayBossVisibility, client); + PrintToServer("%b %i", TR_DidHit(trace), TR_GetEntityIndex(trace)); + profiler.Stop(); + PrintToServer("Time it took to trace handle 1: %f", profiler.Time); + + profiler.Start(); + TR_TraceHullFilter(eyes, end, { -16.0, -16.0, -16.0 }, { 16.0, 16.0, 16.0 }, MASK_NPCSOLID, TraceRayBossVisibility, client); + PrintToServer("%b %i", TR_DidHit(), TR_GetEntityIndex()); + profiler.Stop(); + PrintToServer("Time it took to trace global 1: %f", profiler.Time); + + delete trace; + + profiler.Start(); + trace = TR_TraceHullFilterEx(eyes, end, { -16.0, -16.0, -16.0 }, { 16.0, 16.0, 16.0 }, MASK_NPCSOLID, TraceRayBossVisibility, client); + PrintToServer("%b %i", TR_DidHit(trace), TR_GetEntityIndex(trace)); + profiler.Stop(); + PrintToServer("Time it took to trace handle 2: %f", profiler.Time); + + profiler.Start(); + TR_TraceHullFilter(eyes, end, { -16.0, -16.0, -16.0 }, { 16.0, 16.0, 16.0 }, MASK_NPCSOLID, TraceRayBossVisibility, client); + PrintToServer("%b %i", TR_DidHit(), TR_GetEntityIndex()); + profiler.Stop(); + PrintToServer("Time it took to trace global 2: %f", profiler.Time); + + delete trace; + delete profiler; + return Plugin_Handled; +} + static Action Command_ConditionToggle(int client, int args) { g_IgnoreRoundWinConditionsConVar.BoolValue = !g_IgnoreRoundWinConditionsConVar.BoolValue; diff --git a/addons/sourcemod/scripting/sf2/extras/game_events.sp b/addons/sourcemod/scripting/sf2/extras/game_events.sp index e2e4d491..be64ce7e 100644 --- a/addons/sourcemod/scripting/sf2/extras/game_events.sp +++ b/addons/sourcemod/scripting/sf2/extras/game_events.sp @@ -4,6 +4,7 @@ #define _sf2_game_events_included #pragma semicolon 1 +#pragma newdecls required Action Event_RoundStart(Handle event, const char[] name, bool dB) { @@ -38,8 +39,6 @@ Action Event_RoundStart(Handle event, const char[] name, bool dB) g_PageMax = 0; g_VoteTimer = null; - //Stop the music if needed. - NPCStopMusic(); // Remove all bosses from the game. NPCRemoveAll(); // Collect trigger_multiple to prevent touch bug. @@ -145,7 +144,7 @@ Action Event_Audio(Event event, const char[] name, bool dB) { continue; } - if (!g_SlenderCustomOutroSong[bossIndex]) + if (!SF2NPC_BaseNPC(bossIndex).GetProfileDataEx().OutroMusic) { continue; } @@ -193,12 +192,12 @@ Action Event_RoundEnd(Handle event, const char[] name, bool dB) continue; } - if (g_SlenderCustomOutroSong[npcIndex]) + BaseBossProfile data = SF2NPC_BaseNPC(npcIndex).GetProfileDataEx(); + if (data.OutroMusic) { char profile[SF2_MAX_PROFILE_NAME_LENGTH]; NPCGetProfile(npcIndex, profile, sizeof(profile)); - SF2BossProfileSoundInfo soundInfo; - GetBossProfileOutroMusics(profile, soundInfo); + ProfileSound soundInfo = data.GetOutroMusics(); if (soundInfo.Paths != null && soundInfo.Paths.Length > 0) { soundInfo.Paths.GetString(GetRandomInt(0, soundInfo.Paths.Length - 1), music[npcIndex], sizeof(music[])); @@ -446,15 +445,6 @@ Action Event_PlayerSpawn(Handle event, const char[] name, bool dB) if (IsPlayerAlive(client) && IsClientParticipating(client)) { - if (MusicActive()) //A boss is overriding the music. - { - char path[PLATFORM_MAX_PATH]; - GetBossMusic(path, sizeof(path)); - if (path[0] != '\0') - { - StopSound(client, MUSIC_CHAN, path); - } - } g_PlayerBackStabbed[client] = false; TF2_RemoveCondition(client, TFCond_HalloweenKart); TF2_RemoveCondition(client, TFCond_HalloweenKartDash); @@ -530,12 +520,6 @@ Action Event_PlayerSpawn(Handle event, const char[] name, bool dB) CreateTimer(0.1, Timer_SwitchBot, GetClientUserId(client), TIMER_FLAG_NO_MAPCHANGE); } - // screen overlay timer - if (!SF_IsRaidMap() && !SF_IsBoxingMap()) - { - g_PlayerOverlayCheck[client] = CreateTimer(0.0, Timer_PlayerOverlayCheck, GetClientUserId(client), TIMER_REPEAT | TIMER_FLAG_NO_MAPCHANGE); - TriggerTimer(g_PlayerOverlayCheck[client], true); - } if (DidClientEscape(client)) { CreateTimer(0.1, Timer_TeleportPlayerToEscapePoint, GetClientUserId(client), TIMER_FLAG_NO_MAPCHANGE); @@ -548,6 +532,10 @@ Action Event_PlayerSpawn(Handle event, const char[] name, bool dB) TF2Attrib_RemoveByDefIndex(client, 49); TF2Attrib_RemoveByDefIndex(client, 28); } + + g_PlayerOverlayCheck[client] = CreateTimer(0.0, Timer_PlayerOverlayCheck, GetClientUserId(client), TIMER_REPEAT | TIMER_FLAG_NO_MAPCHANGE); + TriggerTimer(g_PlayerOverlayCheck[client], true); + ClientSwitchToWeaponSlot(client, TFWeaponSlot_Melee); g_PlayerPostWeaponsTimer[client] = CreateTimer(0.1, Timer_ClientPostWeapons, GetClientUserId(client), TIMER_FLAG_NO_MAPCHANGE); @@ -702,7 +690,8 @@ Action Event_PlayerDeathPre(Event event, const char[] name, bool dB) char bossName[SF2_MAX_NAME_LENGTH], profile[SF2_MAX_PROFILE_NAME_LENGTH]; NPCGetProfile(npcIndex, profile, sizeof(profile)); - NPCGetBossName(npcIndex, bossName, sizeof(bossName)); + BaseBossProfile data = GetBossProfile(profile); + data.GetName(GetLocalGlobalDifficulty(npcIndex), bossName, sizeof(bossName)); SetClientName(target, bossName); SetEntPropString(target, Prop_Data, "m_szNetname", bossName); @@ -710,22 +699,20 @@ Action Event_PlayerDeathPre(Event event, const char[] name, bool dB) event.SetString("assister_fallback", ""); if ((NPCGetFlags(npcIndex) & SFF_WEAPONKILLS) || (NPCGetFlags(npcIndex) & SFF_WEAPONKILLSONRADIUS)) { + char weaponType[64]; if (NPCGetFlags(npcIndex) & SFF_WEAPONKILLS && SF2_ChaserEntity(owner).IsValid()) { SF2_ChaserEntity chaser = SF2_ChaserEntity(owner); - SF2ChaserBossProfileData data; - data = NPCChaserGetProfileData(npcIndex); - SF2ChaserBossProfileAttackData attackData; - data.GetAttack(chaser.GetAttackName(), attackData); - event.SetString("weapon_logclassname", attackData.WeaponString); - event.SetString("weapon", attackData.WeaponString); + ChaserBossProfileBaseAttack attackData = SF2NPC_Chaser(npcIndex).GetProfileDataEx().GetAttack(chaser.GetAttackName()); + attackData.GetWeaponString(weaponType, sizeof(weaponType)); + event.SetString("weapon_logclassname", weaponType); + event.SetString("weapon", weaponType); event.SetInt("customkill", attackData.WeaponInt); } else if (NPCGetFlags(npcIndex) & SFF_WEAPONKILLSONRADIUS) { - char weaponType[PLATFORM_MAX_PATH]; - int weaponNum = GetBossProfileWeaponInt(profile); - GetBossProfileWeaponString(profile, weaponType, sizeof(weaponType)); + int weaponNum = data.WeaponInt; + data.GetWeaponString(weaponType, sizeof(weaponType)); event.SetString("weapon_logclassname", weaponType); event.SetString("weapon", weaponType); event.SetInt("customkill", weaponNum); @@ -777,8 +764,9 @@ Action Event_PlayerDeathPre(Event event, const char[] name, bool dB) if (npcIndex != -1) { - SF2BossProfileData data; - data = NPCGetProfileData(npcIndex); + char profile[SF2_MAX_PROFILE_NAME_LENGTH]; + NPCGetProfile(npcIndex, profile, sizeof(profile)); + BaseBossProfile data = GetBossProfile(profile); g_PlayerBossKillSubject[client] = npcIndex; if (!modify && (data.AshRagdoll || data.CloakRagdoll || data.DecapRagdoll || data.DeleteRagdoll || data.DissolveRagdoll || @@ -838,32 +826,6 @@ Action Event_PlayerHurt(Handle event, const char[] name, bool dB) } #endif - int attacker = GetClientOfUserId(GetEventInt(event, "attacker")); - if (attacker > 0) - { - if (g_PlayerProxy[attacker]) - { - g_PlayerProxyControl[attacker] = 100; - } - } - - // Play any sounds, if any. - if (g_PlayerProxy[client]) - { - int proxyMaster = NPCGetFromUniqueID(g_PlayerProxyMaster[client]); - if (proxyMaster != -1) - { - char profile[SF2_MAX_PROFILE_NAME_LENGTH]; - NPCGetProfile(proxyMaster, profile, sizeof(profile)); - - SF2BossProfileSoundInfo soundInfo; - GetBossProfileProxyHurtSounds(profile, soundInfo); - if (soundInfo.Paths != null && soundInfo.Paths.Length > 0) - { - soundInfo.EmitSound(_, client); - } - } - } delete event; #if defined DEBUG if (g_DebugDetailConVar.IntValue > 0) diff --git a/addons/sourcemod/scripting/sf2/extras/natives.sp b/addons/sourcemod/scripting/sf2/extras/natives.sp index 952821e9..e04f21c9 100644 --- a/addons/sourcemod/scripting/sf2/extras/natives.sp +++ b/addons/sourcemod/scripting/sf2/extras/natives.sp @@ -4,6 +4,7 @@ #define _sf2_natives_included #pragma semicolon 1 +#pragma newdecls required // ========================================================== // GENERAL PLUGIN HOOK FUNCTIONS @@ -57,8 +58,8 @@ public APLRes AskPluginLoad2(Handle myself, bool late, char[] error, int err_max g_OnGroupEnterGameFwd = new GlobalForward("SF2_OnGroupEnterGame", ET_Hook, Param_Cell); g_OnEverythingLoadedFwd = new GlobalForward("SF2_OnEverythingLoaded", ET_Ignore); g_OnDifficultyVoteFinishedFwd = new GlobalForward("SF2_OnDifficultyVoteFinished", ET_Ignore, Param_Cell, Param_Cell); - g_OnIsBossCustomAttackPossibleFwd = new GlobalForward("SF2_OnIsBossCustomAttackPossible", ET_Hook, Param_Cell, Param_String, Param_Array, Param_Cell); - g_OnBossGetCustomAttackActionFwd = new GlobalForward("SF2_OnBossGetCustomAttackAction", ET_Hook, Param_Cell, Param_String, Param_Array, Param_Cell, Param_CellByRef); + g_OnIsBossCustomAttackPossibleFwd = new GlobalForward("SF2_OnIsBossCustomAttackPossible", ET_Hook, Param_Cell, Param_String, Param_Cell, Param_Cell); + g_OnBossGetCustomAttackActionFwd = new GlobalForward("SF2_OnBossGetCustomAttackAction", ET_Hook, Param_Cell, Param_String, Param_Cell, Param_Cell, Param_CellByRef); g_OnProjectileTouchFwd = new GlobalForward("SF2_OnProjectileTouch", ET_Ignore, Param_Cell, Param_Cell); CreateNative("SF2_GetConfig", Native_GetConfig); @@ -677,14 +678,12 @@ static any Native_SetBossTarget(Handle plugin, int numParams) static any Native_IsBossStunnable(Handle plugin, int numParams) { - return SF2NPC_Chaser(GetNativeCell(1)).GetProfileData().StunData.Enabled[1]; + return SF2NPC_Chaser(GetNativeCell(1)).GetProfileDataEx().GetStunBehavior().IsEnabled(1); } static any Native_IsBossStunnableByFlashlight(Handle plugin, int numParams) { - SF2ChaserBossProfileData data; - data = NPCChaserGetProfileData(GetNativeCell(1)); - return data.StunData.FlashlightStun[1]; + return SF2NPC_Chaser(GetNativeCell(1)).GetProfileDataEx().GetStunBehavior().CanFlashlightStun(1); } static any Native_IsBossCloaked(Handle plugin, int numParams) diff --git a/addons/sourcemod/scripting/sf2/gamemodes/renevant.sp b/addons/sourcemod/scripting/sf2/gamemodes/renevant.sp index feb01335..12418e5d 100644 --- a/addons/sourcemod/scripting/sf2/gamemodes/renevant.sp +++ b/addons/sourcemod/scripting/sf2/gamemodes/renevant.sp @@ -4,6 +4,7 @@ #define _sf2_renevant_mode_included #pragma semicolon 1 +#pragma newdecls required static GlobalForward g_OnRenevantTriggerWaveFwd; @@ -76,7 +77,7 @@ static bool Renevant_TryAddBossProfile(char profile[SF2_MAX_PROFILE_NAME_LENGTH] return false; } - NPCGetBossName(_, name, nameLen, profile); + GetBossProfile(profile).GetName(1, name, nameLen); if (name[0] == '\0') { strcopy(name, nameLen, profile); @@ -105,7 +106,7 @@ static void ShowRenevantMessageToClient(int client, const char[] message, int pa ShowSyncHudText(client, g_HudSync3, messageDisplay); } -static void Renevant_BroadcastMessage(const char[] message, int params, ...) +static void Renevant_BroadcastMessage(const char[] message, int params, any ...) { char format[512]; VFormat(format, sizeof(format), message, params); @@ -383,7 +384,7 @@ static void Renevant_DoWaveAction(RenevantWave action) SF2NPC_BaseNPC Npc = AddProfile(buffer); if (Npc.IsValid()) { - NPCGetBossName(_, name, sizeof(name), buffer); + GetBossProfile(buffer).GetName(1, name, sizeof(name)); if (name[0] == '\0') { strcopy(name, sizeof(name), buffer); diff --git a/addons/sourcemod/scripting/sf2/glow.sp b/addons/sourcemod/scripting/sf2/glow.sp index 311d9290..0b9e8a09 100644 --- a/addons/sourcemod/scripting/sf2/glow.sp +++ b/addons/sourcemod/scripting/sf2/glow.sp @@ -1,3 +1,6 @@ +#pragma semicolon 1 +#pragma newdecls required + enum struct SF2GlowData { int Ref; diff --git a/addons/sourcemod/scripting/sf2/logging.sp b/addons/sourcemod/scripting/sf2/logging.sp index b57fd8ce..d4b978d4 100644 --- a/addons/sourcemod/scripting/sf2/logging.sp +++ b/addons/sourcemod/scripting/sf2/logging.sp @@ -4,6 +4,7 @@ #define _sf2_logging_included #pragma semicolon 1 +#pragma newdecls required static char g_LogFilePath[512] = ""; diff --git a/addons/sourcemod/scripting/sf2/mapentities.sp b/addons/sourcemod/scripting/sf2/mapentities.sp index 0c58b292..557e30c8 100644 --- a/addons/sourcemod/scripting/sf2/mapentities.sp +++ b/addons/sourcemod/scripting/sf2/mapentities.sp @@ -4,6 +4,7 @@ #define _sf2_mapentities_included #pragma semicolon 1 +#pragma newdecls required //#define DEBUG_MAPENTITIES diff --git a/addons/sourcemod/scripting/sf2/mapentities/base.sp b/addons/sourcemod/scripting/sf2/mapentities/base.sp index 8c6916cb..c0410980 100644 --- a/addons/sourcemod/scripting/sf2/mapentities/base.sp +++ b/addons/sourcemod/scripting/sf2/mapentities/base.sp @@ -6,6 +6,7 @@ // To initialize, call the SF2MapEntityBase.Initialize() function from SetupCustomMapEntities(). #pragma semicolon 1 +#pragma newdecls required static const char g_EntityClassname[] = ""; // The custom classname of the entity. Should be prefixed with "sf2_" diff --git a/addons/sourcemod/scripting/sf2/mapentities/base_spawnpoint.sp b/addons/sourcemod/scripting/sf2/mapentities/base_spawnpoint.sp index 0e2d2451..a4686b8a 100644 --- a/addons/sourcemod/scripting/sf2/mapentities/base_spawnpoint.sp +++ b/addons/sourcemod/scripting/sf2/mapentities/base_spawnpoint.sp @@ -1,4 +1,5 @@ #pragma semicolon 1 +#pragma newdecls required static CEntityFactory g_EntityFactory; diff --git a/addons/sourcemod/scripting/sf2/mapentities/sf2_boss_maker.sp b/addons/sourcemod/scripting/sf2/mapentities/sf2_boss_maker.sp index 6ceb00b2..ad38b48e 100644 --- a/addons/sourcemod/scripting/sf2/mapentities/sf2_boss_maker.sp +++ b/addons/sourcemod/scripting/sf2/mapentities/sf2_boss_maker.sp @@ -1,6 +1,7 @@ // sf2_boss_maker #pragma semicolon 1 +#pragma newdecls required static const char g_EntityClassname[] = "sf2_boss_maker"; // The custom classname of the entity. Should be prefixed with "sf2_" @@ -235,9 +236,10 @@ methodmap SF2BossMakerEntity < SF2SpawnPointBaseEntity endPos[1] = pos[1]; endPos[2] = pos[2] - 1024.0; - TR_TraceHullFilter(pos, endPos, mins, maxs, MASK_PLAYERSOLID_BRUSHONLY, TraceRayDontHitEntity, bossEntity.index); - bool traceHit = TR_DidHit(); - TR_GetEndPosition(endPos); + Handle trace = TR_TraceHullFilterEx(pos, endPos, mins, maxs, MASK_PLAYERSOLID_BRUSHONLY, TraceRayDontHitEntity, bossEntity.index); + bool traceHit = TR_DidHit(trace); + TR_GetEndPosition(endPos, trace); + delete trace; if (traceHit) { @@ -245,7 +247,7 @@ methodmap SF2BossMakerEntity < SF2SpawnPointBaseEntity } } - if (NPCGetType(bossIndex) == SF2BossType_Chaser) + if (SF2NPC_BaseNPC(bossIndex).GetProfileDataEx().Type == SF2BossType_Chaser) { char spawnAnim[64]; this.GetSpawnAnimation(spawnAnim, sizeof(spawnAnim)); diff --git a/addons/sourcemod/scripting/sf2/mapentities/sf2_game_text.sp b/addons/sourcemod/scripting/sf2/mapentities/sf2_game_text.sp index 7bc10f88..819f0e79 100644 --- a/addons/sourcemod/scripting/sf2/mapentities/sf2_game_text.sp +++ b/addons/sourcemod/scripting/sf2/mapentities/sf2_game_text.sp @@ -6,6 +6,7 @@ // constant displaying of HUD text by SF2, rendering the text unreadable and useless. #pragma semicolon 1 +#pragma newdecls required static const char g_EntityClassname[] = "sf2_game_text"; // The custom classname of the entity. Should be prefixed with "sf2_" diff --git a/addons/sourcemod/scripting/sf2/mapentities/sf2_gamerules.sp b/addons/sourcemod/scripting/sf2/mapentities/sf2_gamerules.sp index 715596be..0e656521 100644 --- a/addons/sourcemod/scripting/sf2/mapentities/sf2_gamerules.sp +++ b/addons/sourcemod/scripting/sf2/mapentities/sf2_gamerules.sp @@ -1,6 +1,7 @@ // sf2_gamerules #pragma semicolon 1 +#pragma newdecls required static const char g_EntityClassname[] = "sf2_gamerules"; diff --git a/addons/sourcemod/scripting/sf2/mapentities/sf2_info_boss_spawn.sp b/addons/sourcemod/scripting/sf2/mapentities/sf2_info_boss_spawn.sp index f181526b..fa86e076 100644 --- a/addons/sourcemod/scripting/sf2/mapentities/sf2_info_boss_spawn.sp +++ b/addons/sourcemod/scripting/sf2/mapentities/sf2_info_boss_spawn.sp @@ -1,6 +1,7 @@ // sf2_info_boss_spawn #pragma semicolon 1 +#pragma newdecls required static const char g_EntityClassname[] = "sf2_info_boss_spawn"; // The custom classname of the entity. Should be prefixed with "sf2_" diff --git a/addons/sourcemod/scripting/sf2/mapentities/sf2_info_page_music.sp b/addons/sourcemod/scripting/sf2/mapentities/sf2_info_page_music.sp index f52702fc..4f5998d5 100644 --- a/addons/sourcemod/scripting/sf2/mapentities/sf2_info_page_music.sp +++ b/addons/sourcemod/scripting/sf2/mapentities/sf2_info_page_music.sp @@ -1,6 +1,7 @@ // sf2_info_page_music #pragma semicolon 1 +#pragma newdecls required static const char g_EntityClassname[] = "sf2_info_page_music"; // The custom classname of the entity. Should be prefixed with "sf2_" diff --git a/addons/sourcemod/scripting/sf2/mapentities/sf2_info_page_spawn.sp b/addons/sourcemod/scripting/sf2/mapentities/sf2_info_page_spawn.sp index d63e840c..cc5c552d 100644 --- a/addons/sourcemod/scripting/sf2/mapentities/sf2_info_page_spawn.sp +++ b/addons/sourcemod/scripting/sf2/mapentities/sf2_info_page_spawn.sp @@ -1,6 +1,7 @@ // sf2_info_page_spawn #pragma semicolon 1 +#pragma newdecls required static CEntityFactory g_EntityFactory; diff --git a/addons/sourcemod/scripting/sf2/mapentities/sf2_info_player_escapespawn.sp b/addons/sourcemod/scripting/sf2/mapentities/sf2_info_player_escapespawn.sp index 4f9fe452..4c5c7972 100644 --- a/addons/sourcemod/scripting/sf2/mapentities/sf2_info_player_escapespawn.sp +++ b/addons/sourcemod/scripting/sf2/mapentities/sf2_info_player_escapespawn.sp @@ -1,6 +1,7 @@ // sf2_info_player_escapespawn #pragma semicolon 1 +#pragma newdecls required static CEntityFactory g_EntityFactory; diff --git a/addons/sourcemod/scripting/sf2/mapentities/sf2_info_player_proxyspawn.sp b/addons/sourcemod/scripting/sf2/mapentities/sf2_info_player_proxyspawn.sp index 2a1fbcbc..920ad81f 100644 --- a/addons/sourcemod/scripting/sf2/mapentities/sf2_info_player_proxyspawn.sp +++ b/addons/sourcemod/scripting/sf2/mapentities/sf2_info_player_proxyspawn.sp @@ -1,6 +1,7 @@ // sf2_info_player_proxyspawn #pragma semicolon 1 +#pragma newdecls required static CEntityFactory g_EntityFactory; diff --git a/addons/sourcemod/scripting/sf2/mapentities/sf2_info_player_pvpspawn.sp b/addons/sourcemod/scripting/sf2/mapentities/sf2_info_player_pvpspawn.sp index 3a39cf87..43794c1f 100644 --- a/addons/sourcemod/scripting/sf2/mapentities/sf2_info_player_pvpspawn.sp +++ b/addons/sourcemod/scripting/sf2/mapentities/sf2_info_player_pvpspawn.sp @@ -1,6 +1,7 @@ // sf2_info_player_pvpspawn #pragma semicolon 1 +#pragma newdecls required static CEntityFactory g_EntityFactory; diff --git a/addons/sourcemod/scripting/sf2/mapentities/sf2_logic_arena.sp b/addons/sourcemod/scripting/sf2/mapentities/sf2_logic_arena.sp index 2d3f7434..5b840e63 100644 --- a/addons/sourcemod/scripting/sf2/mapentities/sf2_logic_arena.sp +++ b/addons/sourcemod/scripting/sf2/mapentities/sf2_logic_arena.sp @@ -1,6 +1,7 @@ // sf2_logic_arena #pragma semicolon 1 +#pragma newdecls required static const char g_EntityClassname[] = "sf2_logic_arena"; // The custom classname of the entity. Should be prefixed with "sf2_" diff --git a/addons/sourcemod/scripting/sf2/mapentities/sf2_logic_boxing.sp b/addons/sourcemod/scripting/sf2/mapentities/sf2_logic_boxing.sp index 4a2bfc1d..31855331 100644 --- a/addons/sourcemod/scripting/sf2/mapentities/sf2_logic_boxing.sp +++ b/addons/sourcemod/scripting/sf2/mapentities/sf2_logic_boxing.sp @@ -1,6 +1,7 @@ // sf2_logic_boxing #pragma semicolon 1 +#pragma newdecls required static CEntityFactory g_EntityFactory; diff --git a/addons/sourcemod/scripting/sf2/mapentities/sf2_logic_proxy.sp b/addons/sourcemod/scripting/sf2/mapentities/sf2_logic_proxy.sp index 4c55c7b6..3a49eb63 100644 --- a/addons/sourcemod/scripting/sf2/mapentities/sf2_logic_proxy.sp +++ b/addons/sourcemod/scripting/sf2/mapentities/sf2_logic_proxy.sp @@ -1,6 +1,7 @@ // sf2_logic_proxy #pragma semicolon 1 +#pragma newdecls required static CEntityFactory g_EntityFactory; diff --git a/addons/sourcemod/scripting/sf2/mapentities/sf2_logic_raid.sp b/addons/sourcemod/scripting/sf2/mapentities/sf2_logic_raid.sp index 2bdce2e8..0176f247 100644 --- a/addons/sourcemod/scripting/sf2/mapentities/sf2_logic_raid.sp +++ b/addons/sourcemod/scripting/sf2/mapentities/sf2_logic_raid.sp @@ -1,6 +1,7 @@ // sf2_logic_raid #pragma semicolon 1 +#pragma newdecls required static CEntityFactory g_EntityFactory; diff --git a/addons/sourcemod/scripting/sf2/mapentities/sf2_logic_slaughter.sp b/addons/sourcemod/scripting/sf2/mapentities/sf2_logic_slaughter.sp index a6d5ad9f..1684d49a 100644 --- a/addons/sourcemod/scripting/sf2/mapentities/sf2_logic_slaughter.sp +++ b/addons/sourcemod/scripting/sf2/mapentities/sf2_logic_slaughter.sp @@ -1,6 +1,7 @@ // sf2_logic_slaughter #pragma semicolon 1 +#pragma newdecls required static CEntityFactory g_EntityFactory; diff --git a/addons/sourcemod/scripting/sf2/mapentities/sf2_point_spotlight.sp b/addons/sourcemod/scripting/sf2/mapentities/sf2_point_spotlight.sp index 3bff8c78..db29f815 100644 --- a/addons/sourcemod/scripting/sf2/mapentities/sf2_point_spotlight.sp +++ b/addons/sourcemod/scripting/sf2/mapentities/sf2_point_spotlight.sp @@ -1,3 +1,5 @@ +#pragma semicolon 1 +#pragma newdecls required static const char g_Classname[] = "sf2_point_spotlight"; @@ -289,10 +291,10 @@ static void UpdateSpotlight(SF2PointSpotlightEntity entity) endPos[0] = entity.Length; VectorTransform(endPos, pos, dir, endPos); - TR_TraceRayFilter(pos, endPos, MASK_SOLID_BRUSHONLY, RayType_EndPoint, Trace, entity.index); + Handle trace = TR_TraceRayFilterEx(pos, endPos, MASK_SOLID_BRUSHONLY, RayType_EndPoint, Trace, entity.index); float hitPos[3]; - TR_GetEndPosition(hitPos); + TR_GetEndPosition(hitPos, trace); /* int color[4] = { 255, 0, 0, 255 }; TE_SetupBeamPoints(pos, @@ -311,6 +313,7 @@ static void UpdateSpotlight(SF2PointSpotlightEntity entity) TE_SendToAll(); */ spotlightEnd.SetAbsOrigin(hitPos); + delete trace; } } @@ -336,7 +339,7 @@ static bool Trace(int entity, int mask, any data) { return false; } - if (IsValidEntity(entity) && NPCGetFromEntIndex(entity) != -1) + if (SF2_ChaserEntity(entity).IsValid() || SF2_StatueEntity(entity).IsValid()) { return false; } diff --git a/addons/sourcemod/scripting/sf2/mapentities/sf2_trigger_boss_despawn.sp b/addons/sourcemod/scripting/sf2/mapentities/sf2_trigger_boss_despawn.sp index 386bbaaf..2afed005 100644 --- a/addons/sourcemod/scripting/sf2/mapentities/sf2_trigger_boss_despawn.sp +++ b/addons/sourcemod/scripting/sf2/mapentities/sf2_trigger_boss_despawn.sp @@ -1,6 +1,7 @@ // sf2_trigger_boss_despawn #pragma semicolon 1 +#pragma newdecls required // A trigger that when touched by a boss will despawn the boss from the map. diff --git a/addons/sourcemod/scripting/sf2/mapentities/sf2_trigger_escape.sp b/addons/sourcemod/scripting/sf2/mapentities/sf2_trigger_escape.sp index 0a7a8b1f..38ae0858 100644 --- a/addons/sourcemod/scripting/sf2/mapentities/sf2_trigger_escape.sp +++ b/addons/sourcemod/scripting/sf2/mapentities/sf2_trigger_escape.sp @@ -1,6 +1,7 @@ // sf2_trigger_escape #pragma semicolon 1 +#pragma newdecls required // A trigger that when touched by a player on RED will let the player escape. // Escaping can only occur during the Escape phase. diff --git a/addons/sourcemod/scripting/sf2/mapentities/sf2_trigger_pve.sp b/addons/sourcemod/scripting/sf2/mapentities/sf2_trigger_pve.sp index b29ee97e..2aecfbd6 100644 --- a/addons/sourcemod/scripting/sf2/mapentities/sf2_trigger_pve.sp +++ b/addons/sourcemod/scripting/sf2/mapentities/sf2_trigger_pve.sp @@ -1,6 +1,7 @@ // sf2_trigger_pve #pragma semicolon 1 +#pragma newdecls required static CEntityFactory g_EntityFactory; diff --git a/addons/sourcemod/scripting/sf2/mapentities/sf2_trigger_pvp.sp b/addons/sourcemod/scripting/sf2/mapentities/sf2_trigger_pvp.sp index d08c8aae..14adcfe5 100644 --- a/addons/sourcemod/scripting/sf2/mapentities/sf2_trigger_pvp.sp +++ b/addons/sourcemod/scripting/sf2/mapentities/sf2_trigger_pvp.sp @@ -1,6 +1,7 @@ // sf2_trigger_pvp #pragma semicolon 1 +#pragma newdecls required static CEntityFactory g_EntityFactory; diff --git a/addons/sourcemod/scripting/sf2/menus.sp b/addons/sourcemod/scripting/sf2/menus.sp index 04b80690..6457ca15 100644 --- a/addons/sourcemod/scripting/sf2/menus.sp +++ b/addons/sourcemod/scripting/sf2/menus.sp @@ -5,6 +5,7 @@ #define _sf2_menus #pragma semicolon 1 +#pragma newdecls required Menu g_MenuMain; Menu g_MenuVoteDifficulty; @@ -1962,14 +1963,13 @@ void DisplayBossList(int client) for (int i = 0; i < bossList.Length; i++) { bossList.GetString(i, profile, sizeof(profile)); - NPCGetBossName(_, displayName, sizeof(displayName), profile); + BaseBossProfile data = GetBossProfile(profile); + data.GetName(1, displayName, sizeof(displayName)); if (displayName[0] == '\0') { strcopy(displayName, sizeof(displayName), profile); } - SF2BossProfileData data; - g_BossProfileData.GetArray(profile, data, sizeof(data)); - if (data.Description.Hidden) + if (data.GetDescription().Hidden) { continue; } @@ -2001,29 +2001,40 @@ static int Menu_BossList(Menu menu, MenuAction action, int param1, int param2) { char profile[SF2_MAX_PROFILE_NAME_LENGTH]; menu.GetItem(param2, profile, sizeof(profile)); - SF2BossProfileData data; - g_BossProfileData.GetArray(profile, data, sizeof(data)); + BaseBossProfile data = GetBossProfile(profile); Menu newMenu = new Menu(Menu_BossDisplay); - char buffer[256], buffer2[128]; - data.Names.GetString(Difficulty_Normal, buffer2, sizeof(buffer2)); + char buffer[256], buffer2[128], buffer3[128], def[32]; + data.GetName(Difficulty_Normal, buffer2, sizeof(buffer2)); FormatEx(buffer, sizeof(buffer), "%t %s\n \n", "SF2 Prefix", buffer2); - FormatEx(buffer2, sizeof(buffer2), "Type: %s\n \n", data.Description.Type); + switch (data.Type) + { + case SF2BossType_Chaser: + { + def = "Chaser"; + } + + case SF2BossType_Statue: + { + def = "Statue"; + } + } + data.GetDescription().GetType(buffer3, sizeof(buffer3), def); + FormatEx(buffer2, sizeof(buffer2), "Type: %s\n \n", buffer3); StrCat(buffer, sizeof(buffer), buffer2); - SF2ChaserBossProfileData chaserData; - if (g_ChaserBossProfileData.GetArray(profile, chaserData, sizeof(chaserData))) + if (data.Type == SF2BossType_Chaser) { - FormatEx(buffer2, sizeof(buffer2), "Walk speed: %s\n", ConvertWalkSpeedToDescription(chaserData.WalkSpeed[Difficulty_Normal])); + FormatEx(buffer2, sizeof(buffer2), "Walk speed: %s\n", ConvertWalkSpeedToDescription(view_as(data).GetWalkSpeed(Difficulty_Normal))); } StrCat(buffer, sizeof(buffer), buffer2); - float speed = data.RunSpeed[Difficulty_Normal]; - SF2StatueBossProfileData statueData; - if (g_StatueBossProfileData.GetArray(profile, statueData, sizeof(statueData))) + float speed = data.GetRunSpeed(Difficulty_Normal); + if (data.Type == SF2BossType_Statue) { speed *= 10.0; } FormatEx(buffer2, sizeof(buffer2), "Run speed: %s\n \n", ConvertRunSpeedToDescription(speed)); StrCat(buffer, sizeof(buffer), buffer2); - FormatEx(buffer2, sizeof(buffer2), "%s", data.Description.Information); + data.GetDescription().GetDescription(buffer3, sizeof(buffer3)); + FormatEx(buffer2, sizeof(buffer2), "%s", buffer3); ReplaceString(buffer2, sizeof(buffer2), "\\n", "\n"); StrCat(buffer, sizeof(buffer), buffer2); newMenu.SetTitle(buffer); diff --git a/addons/sourcemod/scripting/sf2/methodmaps.sp b/addons/sourcemod/scripting/sf2/methodmaps.sp index 68cb4d7c..b139c522 100644 --- a/addons/sourcemod/scripting/sf2/methodmaps.sp +++ b/addons/sourcemod/scripting/sf2/methodmaps.sp @@ -1,10 +1,11 @@ #if defined _sf2_methodmaps_included - #endinput +#endinput #endif #define _sf2_methodmaps_included #pragma semicolon 1 +#pragma newdecls required const SF2NPC_BaseNPC SF2_INVALID_NPC = view_as(-1); const SF2_BasePlayer SF2_INVALID_PLAYER = view_as(-1); @@ -21,14 +22,6 @@ methodmap SF2NPC_BaseNPC } } - property int Type - { - public get() - { - return NPCGetType(this.Index); - } - } - property PathFollower Path { public get() @@ -87,9 +80,11 @@ methodmap SF2NPC_BaseNPC } } - public SF2BossProfileData GetProfileData() + public BaseBossProfile GetProfileDataEx() { - return NPCGetProfileData(this.Index); + char profile[SF2_MAX_PROFILE_NAME_LENGTH]; + this.GetProfile(profile, sizeof(profile)); + return GetBossProfile(profile); } property int Difficulty @@ -108,29 +103,13 @@ methodmap SF2NPC_BaseNPC property int Flags { public get() - { - return NPCGetFlags(this.Index); - } - - public set(int flags) { - NPCSetFlags(this.Index, flags); + return NPCGetFlags(this.Index); } - } - - property float ModelScale - { - public get() - { - return NPCGetModelScale(this.Index); - } - } - property int Skin - { - public get() + public set(int flags) { - return NPCGetModelSkin(this.Index); + NPCSetFlags(this.Index, flags); } } @@ -139,35 +118,6 @@ methodmap SF2NPC_BaseNPC return GetSlenderModel(this.Index, modelState, buffer, bufferLen); } - public int GetMaxCopies(int difficulty) - { - return g_SlenderMaxCopies[this.Index][difficulty]; - } - - property bool RaidHitbox - { - public get() - { - return NPCGetRaidHitbox(this.Index); - } - } - - property float ScareRadius - { - public get() - { - return NPCGetScareRadius(this.Index); - } - } - - property float ScareCooldown - { - public get() - { - return NPCGetScareCooldown(this.Index); - } - } - property SF2NPC_BaseNPC CopyMaster { public get() @@ -202,34 +152,6 @@ methodmap SF2NPC_BaseNPC } } - property int TeleportType - { - public get() - { - return NPCGetTeleportType(this.Index); - } - } - - public float GetTeleportRestPeriod(int difficulty) - { - return NPCGetTeleportRestPeriod(this.Index, difficulty); - } - - public float GetTeleportStressMin(int difficulty) - { - return NPCGetTeleportStressMin(this.Index, difficulty); - } - - public float GetTeleportStressMax(int difficulty) - { - return NPCGetTeleportStressMax(this.Index, difficulty); - } - - public float GetTeleportPersistencyPeriod(int difficulty) - { - return NPCGetTeleportPersistencyPeriod(this.Index, difficulty); - } - public int GetTeleporter(int teleporterNumber) { return NPCGetTeleporter(this.Index, teleporterNumber); @@ -240,19 +162,6 @@ methodmap SF2NPC_BaseNPC NPCSetTeleporter(this.Index, teleporterNumber, entity); } - property bool DeathCamEnabled - { - public get() - { - return NPCHasDeathCamEnabled(this.Index); - } - - public set(bool state) - { - NPCSetDeathCamEnabled(this.Index, state); - } - } - public SF2NPC_BaseNPC(int index) { return view_as(index); @@ -292,10 +201,10 @@ methodmap SF2NPC_BaseNPC } } - public void MarkAsFake() - { - SlenderMarkAsFake(this.Index); - } + public void MarkAsFake() + { + SlenderMarkAsFake(this.Index); + } public bool IsValid() { @@ -312,11 +221,6 @@ methodmap SF2NPC_BaseNPC NPCSetProfile(this.Index, profileName); } - public void GetName(char[] buffer, int bufferLen) - { - NPCGetBossName(this.Index, buffer, bufferLen); - } - public void RemoveFromGame() { RemoveProfile(this.Index); @@ -365,32 +269,6 @@ methodmap SF2NPC_BaseNPC NPCGetEyePosition(this.Index, buffer, defaultValue); } - public void GetEyePositionOffset(float buffer[3]) - { - NPCGetEyePositionOffset(this.Index, buffer); - } - - public int GetRenderColor(int cell) - { - return g_SlenderRenderColor[this.Index][cell]; - } - - property int GetRenderMode - { - public get() - { - return g_SlenderRenderMode[this.Index]; - } - } - - property int GetRenderFX - { - public get() - { - return g_SlenderRenderFX[this.Index]; - } - } - public bool HasAttribute(int attributeIndex) { return NPCHasAttribute(this.Index, attributeIndex); @@ -1110,11 +988,6 @@ methodmap SF2_BasePlayer < CBaseCombatCharacter } } - public void UpdateMusicSystem(bool initialize = false) - { - ClientUpdateMusicSystem(this.index, initialize); - } - public void SetPlayState(bool state, bool enablePlay = true) { SetClientPlayState(this.index, state, enablePlay); @@ -1158,9 +1031,11 @@ methodmap SF2_BasePlayer < CBaseCombatCharacter methodmap SF2NPC_Chaser < SF2NPC_BaseNPC { - public SF2ChaserBossProfileData GetProfileData() + public ChaserBossProfile GetProfileDataEx() { - return NPCChaserGetProfileData(this.Index); + char profile[SF2_MAX_PROFILE_NAME_LENGTH]; + this.GetProfile(profile, sizeof(profile)); + return view_as(GetBossProfile(profile)); } public float GetInitialDeathHealth(int difficulty) @@ -1212,14 +1087,11 @@ methodmap SF2NPC_Statue < SF2NPC_BaseNPC return view_as(SF2NPC_BaseNPC(index)); } - public SF2StatueBossProfileData GetProfileData() - { - return NPCStatueGetProfileData(this.Index); - } - - public float GetIdleLifetime(int difficulty) + public StatueBossProfile GetProfileDataEx() { - return NPCStatueGetIdleLifetime(this.Index, difficulty); + char profile[SF2_MAX_PROFILE_NAME_LENGTH]; + this.GetProfile(profile, sizeof(profile)); + return view_as(GetBossProfile(profile)); } } @@ -1324,7 +1196,6 @@ void SetupMethodmapAPI() CreateNative("SF2_Player.LatchCount.set", Native_SetClientLatchCount); CreateNative("SF2_Player.Latcher.get", Native_GetClientLatcher); CreateNative("SF2_Player.Latcher.set", Native_SetClientLatcher); - CreateNative("SF2_Player.UpdateMusicSystem", Native_ClientUpdateMusicSystem); CreateNative("SF2_Player.HasConstantGlow.get", Native_GetClientHasConstantGlow); CreateNative("SF2_Player.SetPlayState", Native_SetClientPlayState); CreateNative("SF2_Player.CanSeeSlender", Native_GetClientCanSeeSlender); @@ -2584,19 +2455,6 @@ static any Native_SetClientLatcher(Handle plugin, int numParams) return 0; } -static any Native_ClientUpdateMusicSystem(Handle plugin, int numParams) -{ - int client = GetNativeCell(1); - if (!IsValidClient(client)) - { - return ThrowNativeError(SP_ERROR_NATIVE, "Invalid client index %d", client); - } - - SF2_BasePlayer player = SF2_BasePlayer(client); - player.UpdateMusicSystem(GetNativeCell(2)); - return 0; -} - static any Native_GetClientHasConstantGlow(Handle plugin, int numParams) { int client = GetNativeCell(1); diff --git a/addons/sourcemod/scripting/sf2/npc.sp b/addons/sourcemod/scripting/sf2/npc.sp index f6b5f452..0dddfb29 100644 --- a/addons/sourcemod/scripting/sf2/npc.sp +++ b/addons/sourcemod/scripting/sf2/npc.sp @@ -4,107 +4,24 @@ #define _sf2_npc_included #pragma semicolon 1 +#pragma newdecls required #define SF2_BOSS_PAGE_CALCULATION 512.0 -#define SF2_BOSS_COPY_SPAWN_MIN_DISTANCE 800.0 // The default minimum distance boss copies can spawn from each other. - -#define SF2_BOSS_ATTACK_MELEE 0 static int g_NpcGlobalUniqueID = 0; -static SF2BossProfileData g_NpcProfileData[MAX_BOSSES]; - static int g_NpcUniqueID[MAX_BOSSES] = { -1, ... }; static char g_SlenderProfile[MAX_BOSSES][SF2_MAX_PROFILE_NAME_LENGTH]; static int g_NpcProfileIndex[MAX_BOSSES] = { -1, ... }; static int g_NpcUniqueProfileIndex[MAX_BOSSES] = { -1, ... }; -static int g_NpcType[MAX_BOSSES] = { SF2BossType_Unknown, ... }; static int g_NpcFlags[MAX_BOSSES] = { 0, ... }; -static float g_NpcModelScale[MAX_BOSSES] = { 1.0, ... }; -static int g_NpcModelSkin[MAX_BOSSES] = { 0, ... }; -static int g_NpcModelSkinDifficulty[MAX_BOSSES][Difficulty_Max]; -static int g_NpcModelSkinMax[MAX_BOSSES] = { 0, ... }; -static int g_NpcModelBodyGroups[MAX_BOSSES] = { 0, ... }; -static int g_NpcModelBodyGroupsDifficulty[MAX_BOSSES][Difficulty_Max]; -static int g_NpcModelBodyGroupsMax[MAX_BOSSES] = { 0, ... }; -bool g_NpcRaidHitbox[MAX_BOSSES] = { false, ... }; -static float g_NpcSoundMusicLoop[MAX_BOSSES][Difficulty_Max]; -static int g_NpcAllowMusicOnDifficulty[MAX_BOSSES]; -static char g_NpcName[MAX_BOSSES][Difficulty_Max][SF2_MAX_PROFILE_NAME_LENGTH]; -static bool g_NpcHasFakeCopiesEnabled[MAX_BOSSES][Difficulty_Max]; -static float g_NpcBlinkLookRate[MAX_BOSSES]; -static float g_NpcBlinkStaticRate[MAX_BOSSES]; -static float g_NpcStepSize[MAX_BOSSES]; static int g_NpcTeleporters[MAX_BOSSES][MAX_NPCTELEPORTER]; static int g_NpcModelMaster[2049]; -static bool g_NpcHasDiscoMode[MAX_BOSSES]; -static float g_NpcDiscoRadiusMin[MAX_BOSSES]; -static float g_NpcDiscoRadiusMax[MAX_BOSSES]; -static float g_NpcDiscoModePos[MAX_BOSSES][3]; -static bool g_NpcHasFestiveLights[MAX_BOSSES]; -static int g_NpcFestiveLightBrightness[MAX_BOSSES]; -static float g_NpcFestiveLightDistance[MAX_BOSSES]; -static float g_NpcFestiveLightRadius[MAX_BOSSES]; -static float g_NpcFestiveLightPos[MAX_BOSSES][3]; -static float g_NpcFestiveLightAng[MAX_BOSSES][3]; - -static float g_NpcFieldOfView[MAX_BOSSES] = { 0.0, ... }; - -static bool g_NpcHasTeleportAllowed[MAX_BOSSES][Difficulty_Max]; -static float g_NpcTeleportTimeMin[MAX_BOSSES][Difficulty_Max]; -static float g_NpcTeleportTimeMax[MAX_BOSSES][Difficulty_Max]; -static float g_NpcTeleportRestPeriod[MAX_BOSSES][Difficulty_Max]; -static float g_NpcTeleportStressMin[MAX_BOSSES][Difficulty_Max]; -static float g_NpcTeleportStressMax[MAX_BOSSES][Difficulty_Max]; -static float g_NpcTeleportPersistencyPeriod[MAX_BOSSES][Difficulty_Max]; - -static float g_NpcJumpscareDistance[MAX_BOSSES][Difficulty_Max]; -static float g_NpcJumpscareDuration[MAX_BOSSES][Difficulty_Max]; -static float g_NpcJumpscareCooldown[MAX_BOSSES][Difficulty_Max]; -static bool g_NpcHasJumpscareOnScare[MAX_BOSSES]; - int g_SlenderEnt[MAX_BOSSES] = { INVALID_ENT_REFERENCE, ... }; static float g_NpcAddSpeed[MAX_BOSSES]; static float g_NpcAddAcceleration[MAX_BOSSES]; -static float g_NpcIdleLifetime[MAX_BOSSES][Difficulty_Max]; - -static float g_NpcScareRadius[MAX_BOSSES]; -static float g_NpcScareCooldown[MAX_BOSSES]; - -static bool g_NpcHasPlayerScareSpeedBoost[MAX_BOSSES]; -static float g_NpcPlayerSpeedBoostDuration[MAX_BOSSES]; - -static bool g_NpcHasPlayerScareReaction[MAX_BOSSES]; -static int g_NpcPlayerScareReactionType[MAX_BOSSES]; - -static bool g_NpcHasPlayerScareReplenishSprint[MAX_BOSSES]; -static float g_NpcPlayerScareReplenishSprintAmount[MAX_BOSSES]; - -static int g_NpcTeleportType[MAX_BOSSES] = { -1, ... }; - -static bool g_NpcHasDeathCamEnabled[MAX_BOSSES] = { false, ... }; - -static bool g_NpcHasProxyWeaponsEnabled[MAX_BOSSES] = { false, ... }; - -static float g_NpcProxySpawnChanceMin[MAX_BOSSES][Difficulty_Max]; -static float g_NpcProxySpawnChanceMax[MAX_BOSSES][Difficulty_Max]; -static float g_NpcProxySpawnChanceThreshold[MAX_BOSSES][Difficulty_Max]; -static int g_NpcProxySpawnNumMin[MAX_BOSSES][Difficulty_Max]; -static int g_NpcProxySpawnNumMax[MAX_BOSSES][Difficulty_Max]; -static float g_NpcProxySpawnCooldownMin[MAX_BOSSES][Difficulty_Max]; -static float g_NpcProxySpawnCooldownMax[MAX_BOSSES][Difficulty_Max]; - -static bool g_NpcHasIgnoreNavPrefer[MAX_BOSSES]; - -static int g_NpcDeathMessageDifficultyIndexes[MAX_BOSSES]; - -static bool g_NpcHasDrainCreditsState[MAX_BOSSES]; -static int g_NpcDrainCreditAmount[MAX_BOSSES][Difficulty_Max]; - -static bool g_NpcHasProxySpawnEffectEnabled[MAX_BOSSES]; -static float g_NpcProxySpawnEffectZOffset[MAX_BOSSES]; static bool g_NpcShouldBeAffectedBySight[MAX_BOSSES]; @@ -112,88 +29,6 @@ static int g_NpcDefaultTeam[MAX_BOSSES]; static bool g_NpcWasKilled[MAX_BOSSES]; -Handle timerMusic = null; //Planning to add a bosses array on. - -bool NPCGetBossName(int npcIndex = -1, char[] buffer, int bufferLen, char profile[SF2_MAX_PROFILE_NAME_LENGTH] = "") -{ - if (npcIndex == -1 && profile[0] == '\0') - { - return false; - } - int difficulty = g_DifficultyConVar.IntValue; - if (npcIndex != -1) - { - switch (difficulty) - { - case Difficulty_Normal: - { - strcopy(buffer, bufferLen, g_NpcName[npcIndex][1]); - } - case Difficulty_Hard: - { - strcopy(buffer, bufferLen, g_NpcName[npcIndex][2]); - } - case Difficulty_Insane: - { - strcopy(buffer, bufferLen, g_NpcName[npcIndex][3]); - } - case Difficulty_Nightmare: - { - strcopy(buffer, bufferLen, g_NpcName[npcIndex][4]); - } - case Difficulty_Apollyon: - { - strcopy(buffer, bufferLen, g_NpcName[npcIndex][5]); - } - } - } - else - { - ArrayList arrayNames; - arrayNames = GetBossProfileNames(profile); - switch (difficulty) - { - case Difficulty_Normal: - { - arrayNames.GetString(Difficulty_Normal, buffer, bufferLen); - } - case Difficulty_Hard: - { - arrayNames.GetString(Difficulty_Hard, buffer, bufferLen); - } - case Difficulty_Insane: - { - arrayNames.GetString(Difficulty_Insane, buffer, bufferLen); - } - case Difficulty_Nightmare: - { - arrayNames.GetString(Difficulty_Nightmare, buffer, bufferLen); - } - case Difficulty_Apollyon: - { - arrayNames.GetString(Difficulty_Apollyon, buffer, bufferLen); - } - } - arrayNames = null; - } - return true; -} - -bool NPCHasProxyWeapons(int npcIndex) -{ - return g_NpcHasProxyWeaponsEnabled[npcIndex]; -} - -bool NPCHasDeathCamEnabled(int npcIndex) -{ - return g_NpcHasDeathCamEnabled[npcIndex]; -} - -void NPCSetDeathCamEnabled(int npcIndex, bool state) -{ - g_NpcHasDeathCamEnabled[npcIndex] = state; -} - void NPCInitialize() { g_OnEntityDestroyedPFwd.AddFunction(null, EntityDestroyed); @@ -259,6 +94,8 @@ void NPC_InitializeAPI() CreateNative("SF2_SpawnBossEffects", Native_SpawnBossEffects); CreateNative("SF2_CanBossBeSeen", Native_CanBossBeSeen); + + SetupNPCEffectsAPI(); } static void EntityDestroyed(CBaseEntity ent, const char[] classname) @@ -339,9 +176,9 @@ static void EntityTeleported(CBaseEntity teleporter, CBaseEntity activator) controller.UnSpawn(); } - if (controller.Type == SF2BossType_Chaser) + if (controller.GetProfileDataEx().Type == SF2BossType_Chaser) { - if (view_as(controller).GetProfileData().ChasesEndlessly) + if (view_as(controller).GetProfileDataEx().ChasesEndlessly) { controller.UnSpawn(); } @@ -353,7 +190,7 @@ static void EntityTeleported(CBaseEntity teleporter, CBaseEntity activator) static void OnPlayerLookAtBoss(SF2_BasePlayer client, SF2NPC_BaseNPC boss) { - switch (boss.Type) + switch (boss.GetProfileDataEx().Type) { case SF2BossType_Statue: { @@ -370,8 +207,7 @@ void NPCOnDespawn(SF2NPC_BaseNPC controller, CBaseEntity entity, bool killed = f char profile[SF2_MAX_PROFILE_NAME_LENGTH]; controller.GetProfile(profile, sizeof(profile)); int bossIndex = controller.Index; - SF2BossProfileData data; - data = controller.GetProfileData(); + BaseBossProfile data = controller.GetProfileDataEx(); Call_StartForward(g_OnBossDespawnFwd); Call_PushCell(bossIndex); Call_Finish(); @@ -379,7 +215,7 @@ void NPCOnDespawn(SF2NPC_BaseNPC controller, CBaseEntity entity, bool killed = f //Turn off all slender's effects in order to prevent some bugs. SlenderRemoveEffects(bossIndex, true); - if (controller.Type == SF2BossType_Statue) + if (data.Type == SF2BossType_Statue) { Despawn_Statue(SF2NPC_Statue(bossIndex), entity); } @@ -393,7 +229,7 @@ void NPCOnDespawn(SF2NPC_BaseNPC controller, CBaseEntity entity, bool killed = f g_BossPathFollower[bossIndex].Invalidate(); } - if (data.DespawnEffects != null) + if (data.GetDespawnEffects() != null) { if (killed && data.HideDespawnEffectsOnDeath) { @@ -401,41 +237,42 @@ void NPCOnDespawn(SF2NPC_BaseNPC controller, CBaseEntity entity, bool killed = f } else { - StringMapSnapshot snapshot = data.DespawnEffects.Snapshot(); - char key[64]; - snapshot.GetKey(GetRandomInt(0, snapshot.Length - 1), key, sizeof(key)); - ArrayList effects; - data.DespawnEffects.GetValue(key, effects); - float pos[3], ang[3]; - CBaseEntity(NPCGetEntIndex(bossIndex)).GetAbsOrigin(pos); - CBaseEntity(NPCGetEntIndex(bossIndex)).GetAbsAngles(ang); - SlenderSpawnEffects(effects, bossIndex, false, pos, ang, _, _, true); - delete snapshot; + ProfileObject obj = view_as(data.GetDespawnEffects().GetSection(GetRandomInt(0, data.GetDespawnEffects().Length - 1))); + obj = obj != null ? obj.GetSection("effects") : null; + if (obj != null) + { + float pos[3], ang[3]; + CBaseEntity(NPCGetEntIndex(bossIndex)).GetAbsOrigin(pos); + CBaseEntity(NPCGetEntIndex(bossIndex)).GetAbsAngles(ang); + SlenderSpawnEffects(view_as(obj), bossIndex, false, pos, ang, _, _, true); + } } } - if (data.EngineSound[0] != '\0') + char sound[PLATFORM_MAX_PATH]; + data.GetConstantSound(sound, sizeof(sound)); + if (sound[0] != '\0') { - StopSound(entity.index, SNDCHAN_STATIC, data.EngineSound); + StopSound(entity.index, SNDCHAN_STATIC, sound); } if (NPCGetFlags(bossIndex) & SFF_HASSTATICLOOPLOCALSOUND) { char loopSound[PLATFORM_MAX_PATH]; - GetBossProfileStaticLocalSound(profile, loopSound, sizeof(loopSound)); + data.GetStaticLocalLoopSound(loopSound, sizeof(loopSound)); if (loopSound[0] != '\0') { StopSound(entity.index, SNDCHAN_STATIC, loopSound); } } - if (SF_IsRaidMap() || SF_BossesChaseEndlessly() || data.Healthbar) + if (SF_IsRaidMap() || SF_BossesChaseEndlessly() || view_as(data).Healthbar) { controller.Flags = controller.Flags & ~SFF_NOTELEPORT; } g_SlenderEnt[bossIndex] = INVALID_ENT_REFERENCE; - if (data.Healthbar && g_HealthBar != -1) + if (view_as(data).Healthbar && g_HealthBar != -1) { int npcIndex = 0; for (npcIndex = 0; npcIndex < MAX_BOSSES; npcIndex++) @@ -444,8 +281,8 @@ void NPCOnDespawn(SF2NPC_BaseNPC controller, CBaseEntity entity, bool killed = f { continue; } - data = NPCGetProfileData(npcIndex); - if (data.Healthbar) + data = SF2NPC_BaseNPC(npcIndex).GetProfileDataEx(); + if (view_as(data).Healthbar) { int tempSlender = NPCGetEntIndex(npcIndex); @@ -560,16 +397,6 @@ bool NPCGetProfile(int npcIndex, char[] buffer, int bufferLen) return true; } -SF2BossProfileData NPCGetProfileData(int npcIndex) -{ - return g_NpcProfileData[npcIndex]; -} - -void NPCSetProfileData(int npcIndex, SF2BossProfileData value) -{ - g_NpcProfileData[npcIndex] = value; -} - void NPCSetProfile(int npcIndex, const char[] profile) { strcopy(g_SlenderProfile[npcIndex], sizeof(g_SlenderProfile[]), profile); @@ -585,1041 +412,123 @@ void NPCRemove(int npcIndex) RemoveProfile(npcIndex); } -void NPCStopMusic() +void NPCRemoveAll() { - //Stop the music timer - if (timerMusic != null) - { - delete timerMusic; - } - //Stop the music for all players. - for (int i = 1; i <= MaxClients; i++) + for (int i = 0; i < MAX_BOSSES; i++) { - if (IsValidClient(i)) - { - if (currentMusicTrack[0] != '\0') - { - StopSound(i, MUSIC_CHAN, currentMusicTrack); - } - ClientUpdateMusicSystem(i); - } + NPCRemove(i); } } -void CheckIfMusicValid() +int NPCGetFlags(int npcIndex) { - int difficulty = g_DifficultyConVar.IntValue; - for (int i = 0; i < MAX_BOSSES; i++) - { - if (NPCGetUniqueID(i) == -1) - { - continue; - } - SF2BossProfileData data; - data = NPCGetProfileData(i); - if (data.IsPvEBoss) - { - continue; - } - if (g_NpcAllowMusicOnDifficulty[i] & difficulty) - { - currentMusicTrackNormal[0] = '\0'; - currentMusicTrackHard[0] = '\0'; - currentMusicTrackInsane[0] = '\0'; - currentMusicTrackNightmare[0] = '\0'; - currentMusicTrackApollyon[0] = '\0'; - char profile[SF2_MAX_PROFILE_NAME_LENGTH]; - NPCGetProfile(i, profile, sizeof(profile)); - for(int client = 1;client <= MaxClients; client++) - { - if (IsValidClient(client) && (!g_PlayerEliminated[client] || IsClientInGhostMode(client))) - { - SF2BossProfileSoundInfo soundInfo; - GetBossProfileMusicSounds(profile, soundInfo, 1); - ArrayList soundList = soundInfo.Paths; - if (soundList != null && soundList.Length > 0) - { - soundList.GetString(GetRandomInt(0, soundList.Length - 1), currentMusicTrackNormal, sizeof(currentMusicTrackNormal)); - } - soundList = null; + return g_NpcFlags[npcIndex]; +} - GetBossProfileMusicSounds(profile, soundInfo, 2); - soundList = soundInfo.Paths; - if (soundList != null && soundList.Length > 0) - { - soundList.GetString(GetRandomInt(0, soundList.Length - 1), currentMusicTrackHard, sizeof(currentMusicTrackHard)); - } - if (currentMusicTrackHard[0] == '\0') - { - GetBossProfileMusicSounds(profile, soundInfo, 1); - soundList = soundInfo.Paths; - if (soundList != null && soundList.Length > 0) - { - soundList.GetString(GetRandomInt(0, soundList.Length - 1), currentMusicTrackHard, sizeof(currentMusicTrackHard)); - } - } - soundList = null; +void NPCSetFlags(int npcIndex,int flags) +{ + g_NpcFlags[npcIndex] = flags; +} - GetBossProfileMusicSounds(profile, soundInfo, 3); - soundList = soundInfo.Paths; - if (soundList != null && soundList.Length > 0) - { - soundList.GetString(GetRandomInt(0, soundList.Length - 1), currentMusicTrackInsane, sizeof(currentMusicTrackInsane)); - } - if (currentMusicTrackInsane[0] == '\0') - { - GetBossProfileMusicSounds(profile, soundInfo, 2); - soundList = soundInfo.Paths; - if (soundList != null && soundList.Length > 0) - { - soundList.GetString(GetRandomInt(0, soundList.Length - 1), currentMusicTrackInsane, sizeof(currentMusicTrackInsane)); - } - if (currentMusicTrackInsane[0] == '\0') - { - GetBossProfileMusicSounds(profile, soundInfo, 1); - soundList = soundInfo.Paths; - if (soundList != null && soundList.Length > 0) - { - soundList.GetString(GetRandomInt(0, soundList.Length - 1), currentMusicTrackInsane, sizeof(currentMusicTrackInsane)); - } - } - } - soundList = null; +void NPCSetAddSpeed(int npcIndex, float amount) +{ + g_NpcAddSpeed[npcIndex] += amount; +} - GetBossProfileMusicSounds(profile, soundInfo, 4); - soundList = soundInfo.Paths; - if (soundList != null && soundList.Length > 0) - { - soundList.GetString(GetRandomInt(0, soundList.Length - 1), currentMusicTrackNightmare, sizeof(currentMusicTrackNightmare)); - } - if (currentMusicTrackNightmare[0] == '\0') - { - GetBossProfileMusicSounds(profile, soundInfo, 3); - soundList = soundInfo.Paths; - if (soundList != null && soundList.Length > 0) - { - soundList.GetString(GetRandomInt(0, soundList.Length - 1), currentMusicTrackNightmare, sizeof(currentMusicTrackNightmare)); - } - if (currentMusicTrackNightmare[0] == '\0') - { - GetBossProfileMusicSounds(profile, soundInfo, 2); - soundList = soundInfo.Paths; - if (soundList != null && soundList.Length > 0) - { - soundList.GetString(GetRandomInt(0, soundList.Length - 1), currentMusicTrackNightmare, sizeof(currentMusicTrackNightmare)); - } - if (currentMusicTrackNightmare[0] == '\0') - { - GetBossProfileMusicSounds(profile, soundInfo, 1); - soundList = soundInfo.Paths; - if (soundList != null && soundList.Length > 0) - { - soundList.GetString(GetRandomInt(0, soundList.Length - 1), currentMusicTrackNightmare, sizeof(currentMusicTrackNightmare)); - } - } - } - } - soundList = null; +void NPCSetAddAcceleration(int npcIndex, float amount) +{ + g_NpcAddAcceleration[npcIndex] += amount; +} - GetBossProfileMusicSounds(profile, soundInfo, 5); - soundList = soundInfo.Paths; - if (soundList != null && soundList.Length > 0) - { - soundList.GetString(GetRandomInt(0, soundList.Length - 1), currentMusicTrackApollyon, sizeof(currentMusicTrackApollyon)); - } - if (currentMusicTrackApollyon[0] == '\0') - { - GetBossProfileMusicSounds(profile, soundInfo, 4); - soundList = soundInfo.Paths; - if (soundList != null && soundList.Length > 0) - { - soundList.GetString(GetRandomInt(0, soundList.Length - 1), currentMusicTrackApollyon, sizeof(currentMusicTrackApollyon)); - } - if (currentMusicTrackApollyon[0] == '\0') - { - GetBossProfileMusicSounds(profile, soundInfo, 3); - soundList = soundInfo.Paths; - if (soundList != null && soundList.Length > 0) - { - soundList.GetString(GetRandomInt(0, soundList.Length - 1), currentMusicTrackApollyon, sizeof(currentMusicTrackApollyon)); - } - if (currentMusicTrackApollyon[0] == '\0') - { - GetBossProfileMusicSounds(profile, soundInfo, 2); - soundList = soundInfo.Paths; - if (soundList != null && soundList.Length > 0) - { - soundList.GetString(GetRandomInt(0, soundList.Length - 1), currentMusicTrackApollyon, sizeof(currentMusicTrackApollyon)); - } - if (currentMusicTrackApollyon[0] == '\0') - { - GetBossProfileMusicSounds(profile, soundInfo, 1); - soundList = soundInfo.Paths; - if (soundList != null && soundList.Length > 0) - { - soundList.GetString(GetRandomInt(0, soundList.Length - 1), currentMusicTrackApollyon, sizeof(currentMusicTrackApollyon)); - } - } - } - } - } - soundList = null; +float NPCGetAddSpeed(int npcIndex) +{ + return g_NpcAddSpeed[npcIndex]; +} - switch (g_DifficultyConVar.IntValue) - { - case Difficulty_Normal: - { - strcopy(currentMusicTrack, sizeof(currentMusicTrack), currentMusicTrackNormal); - } - case Difficulty_Hard: - { - strcopy(currentMusicTrack, sizeof(currentMusicTrack), currentMusicTrackHard); - } - case Difficulty_Insane: - { - strcopy(currentMusicTrack, sizeof(currentMusicTrack), currentMusicTrackInsane); - } - case Difficulty_Nightmare: - { - strcopy(currentMusicTrack, sizeof(currentMusicTrack), currentMusicTrackNightmare); - } - case Difficulty_Apollyon: - { - strcopy(currentMusicTrack, sizeof(currentMusicTrack), currentMusicTrackApollyon); - } - } - if (currentMusicTrack[0] != '\0') - { - timerMusic = CreateTimer(NPCGetSoundMusicLoop(i, difficulty), BossMusic, i, TIMER_FLAG_NO_MAPCHANGE); - StopSound(client, MUSIC_CHAN, currentMusicTrack); - ClientChaseMusicReset(client); - ClientChaseMusicSeeReset(client); - ClientAlertMusicReset(client); - ClientIdleMusicReset(client); - GetChaserProfileChaseMusics(profile, soundInfo); - soundInfo.StopAllSounds(client); - GetChaserProfileChaseVisibleMusics(profile, soundInfo); - soundInfo.StopAllSounds(client); - GetChaserProfileAlertMusics(profile, soundInfo); - soundInfo.StopAllSounds(client); - GetChaserProfileIdleMusics(profile, soundInfo); - soundInfo.StopAllSounds(client); - if (g_PlayerMusicString[client][0] != '\0') - { - EmitSoundToClient(client, g_PlayerMusicString[client], _, MUSIC_CHAN, SNDLEVEL_NONE, SND_CHANGEVOL, 0.0001); - } - ClientMusicStart(client, currentMusicTrack, _, MUSIC_PAGE_VOLUME,true); - ClientUpdateMusicSystem(client); - break; - } - } - } - break; - } - } +float NPCGetAddAcceleration(int npcIndex) +{ + return g_NpcAddAcceleration[npcIndex]; +} + +void NPCSetTeleporter(int bossIndex, int teleporterNumber, int entity) +{ + g_NpcTeleporters[bossIndex][teleporterNumber] = entity; } -bool MusicActive() +int NPCGetTeleporter(int bossIndex, int teleporterNumber) +{ + return g_NpcTeleporters[bossIndex][teleporterNumber]; +} + +SF2NPC_BaseNPC NPCGetCopyMaster(SF2NPC_BaseNPC controller) +{ + return SF2NPC_BaseNPC(g_SlenderCopyMaster[controller.Index]); +} + +SF2NPC_BaseNPC NPCGetCompanionMaster(SF2NPC_BaseNPC controller) +{ + return SF2NPC_BaseNPC(g_SlenderCompanionMaster[controller.Index]); +} + +bool NPCGetAffectedBySightState(int npcIndex) +{ + return g_NpcShouldBeAffectedBySight[npcIndex]; +} + +void NPCSetAffectedBySightState(int npcIndex, bool state) +{ + g_NpcShouldBeAffectedBySight[npcIndex] = state; +} + +int NPCGetDefaultTeam(int npcIndex) +{ + return g_NpcDefaultTeam[npcIndex]; +} + +void NPCSetDefaultTeam(int npcIndex, int team) +{ + g_NpcDefaultTeam[npcIndex] = team; +} + +bool NPCGetWasKilled(int npcIndex) +{ + return g_NpcWasKilled[npcIndex]; +} + +void NPCSetWasKilled(int npcIndex, bool state) +{ + g_NpcWasKilled[npcIndex] = state; +} + +bool NPCShouldSeeEntity(int npcIndex, int entity) { - if (timerMusic != null) + if (!IsValidEntity(entity)) { - return true; + return false; } - return false; + + Action result = Plugin_Continue; + Call_StartForward(g_OnBossSeeEntityFwd); + Call_PushCell(npcIndex); + Call_PushCell(entity); + Call_Finish(result); + + if (result != Plugin_Continue) + { + return false; + } + + return true; } -bool BossHasMusic(char[] profile) -{ - int difficulty = g_DifficultyConVar.IntValue; - char temp[512]; - ArrayList soundList; - SF2BossProfileSoundInfo soundInfo; - switch (difficulty) - { - case Difficulty_Normal: - { - GetBossProfileMusicSounds(profile, soundInfo, 1); - soundList = soundInfo.Paths; - if (soundList != null && soundList.Length > 0) - { - soundList.GetString(GetRandomInt(0, soundList.Length - 1), temp, sizeof(temp)); - } - if (temp[0] != '\0') - { - return true; - } - } - case Difficulty_Hard: - { - GetBossProfileMusicSounds(profile, soundInfo, 2); - soundList = soundInfo.Paths; - if (soundList != null && soundList.Length > 0) - { - soundList.GetString(GetRandomInt(0, soundList.Length - 1), temp, sizeof(temp)); - } - if (temp[0] != '\0') - { - return true; - } - else - { - GetBossProfileMusicSounds(profile, soundInfo, 1); - soundList = soundInfo.Paths; - if (soundList != null && soundList.Length > 0) - { - soundList.GetString(GetRandomInt(0, soundList.Length - 1), temp, sizeof(temp)); - } - if (temp[0] != '\0') - { - return true; - } - } - } - case Difficulty_Insane: - { - GetBossProfileMusicSounds(profile, soundInfo, 3); - soundList = soundInfo.Paths; - if (soundList != null && soundList.Length > 0) - { - soundList.GetString(GetRandomInt(0, soundList.Length - 1), temp, sizeof(temp)); - } - if (temp[0] != '\0') - { - return true; - } - else - { - GetBossProfileMusicSounds(profile, soundInfo, 2); - soundList = soundInfo.Paths; - if (soundList != null && soundList.Length > 0) - { - soundList.GetString(GetRandomInt(0, soundList.Length - 1), temp, sizeof(temp)); - } - if (temp[0] != '\0') - { - return true; - } - else - { - GetBossProfileMusicSounds(profile, soundInfo, 1); - soundList = soundInfo.Paths; - if (soundList != null && soundList.Length > 0) - { - soundList.GetString(GetRandomInt(0, soundList.Length - 1), temp, sizeof(temp)); - } - if (temp[0] != '\0') - { - return true; - } - } - } - } - case Difficulty_Nightmare: - { - GetBossProfileMusicSounds(profile, soundInfo, 4); - soundList = soundInfo.Paths; - if (soundList != null && soundList.Length > 0) - { - soundList.GetString(GetRandomInt(0, soundList.Length - 1), temp, sizeof(temp)); - } - if (temp[0] != '\0') - { - return true; - } - else - { - GetBossProfileMusicSounds(profile, soundInfo, 3); - soundList = soundInfo.Paths; - if (soundList != null && soundList.Length > 0) - { - soundList.GetString(GetRandomInt(0, soundList.Length - 1), temp, sizeof(temp)); - } - if (temp[0] != '\0') - { - return true; - } - else - { - GetBossProfileMusicSounds(profile, soundInfo, 2); - soundList = soundInfo.Paths; - if (soundList != null && soundList.Length > 0) - { - soundList.GetString(GetRandomInt(0, soundList.Length - 1), temp, sizeof(temp)); - } - if (temp[0] != '\0') - { - return true; - } - else - { - GetBossProfileMusicSounds(profile, soundInfo, 1); - soundList = soundInfo.Paths; - if (soundList != null && soundList.Length > 0) - { - soundList.GetString(GetRandomInt(0, soundList.Length - 1), temp, sizeof(temp)); - } - if (temp[0] != '\0') - { - return true; - } - } - } - } - } - case Difficulty_Apollyon: - { - GetBossProfileMusicSounds(profile, soundInfo, 5); - soundList = soundInfo.Paths; - if (soundList != null && soundList.Length > 0) - { - soundList.GetString(GetRandomInt(0, soundList.Length - 1), temp, sizeof(temp)); - } - if (temp[0] != '\0') - { - return true; - } - else - { - GetBossProfileMusicSounds(profile, soundInfo, 4); - soundList = soundInfo.Paths; - if (soundList != null && soundList.Length > 0) - { - soundList.GetString(GetRandomInt(0, soundList.Length - 1), temp, sizeof(temp)); - } - if (temp[0] != '\0') - { - return true; - } - else - { - GetBossProfileMusicSounds(profile, soundInfo, 3); - soundList = soundInfo.Paths; - if (soundList != null && soundList.Length > 0) - { - soundList.GetString(GetRandomInt(0, soundList.Length - 1), temp, sizeof(temp)); - } - if (temp[0] != '\0') - { - return true; - } - else - { - GetBossProfileMusicSounds(profile, soundInfo, 2); - soundList = soundInfo.Paths; - if (soundList != null && soundList.Length > 0) - { - soundList.GetString(GetRandomInt(0, soundList.Length - 1), temp, sizeof(temp)); - } - if (temp[0] != '\0') - { - return true; - } - else - { - GetBossProfileMusicSounds(profile, soundInfo, 1); - soundList = soundInfo.Paths; - if (soundList != null && soundList.Length > 0) - { - soundList.GetString(GetRandomInt(0, soundList.Length - 1), temp, sizeof(temp)); - } - if (temp[0] != '\0') - { - return true; - } - } - } - } - } - } - } - return false; -} - -bool BossMatchesCurrentMusic(char[] profile) -{ - if (!IsProfileValid(profile)) - { - return false; - } - - char buffer[PLATFORM_MAX_PATH], currentMusic[PLATFORM_MAX_PATH]; - int difficulty = g_DifficultyConVar.IntValue; - - GetBossMusic(currentMusic, sizeof(currentMusic)); - - ArrayList soundList; - SF2BossProfileSoundInfo soundInfo; - switch (difficulty) - { - case Difficulty_Normal: - { - GetBossProfileMusicSounds(profile, soundInfo, 1); - soundList = soundInfo.Paths; - if (soundList != null && soundList.Length > 0) - { - for (int i = 0; i < soundList.Length; i++) - { - soundList.GetString(i, buffer, sizeof(buffer)); - if (strcmp(buffer, currentMusic, false) == 0) - { - return true; - } - } - } - } - case Difficulty_Hard: - { - for (int section = 1; section <= Difficulty_Hard; section++) - { - GetBossProfileMusicSounds(profile, soundInfo, section); - soundList = soundInfo.Paths; - if (soundList != null && soundList.Length > 0) - { - for (int i = 0; i < soundList.Length; i++) - { - soundList.GetString(i, buffer, sizeof(buffer)); - if (strcmp(buffer, currentMusic, false) == 0) - { - return true; - } - } - } - } - } - case Difficulty_Insane: - { - for (int section = 1; section <= Difficulty_Insane; section++) - { - GetBossProfileMusicSounds(profile, soundInfo, section); - soundList = soundInfo.Paths; - if (soundList != null && soundList.Length > 0) - { - for (int i = 0; i < soundList.Length; i++) - { - soundList.GetString(i, buffer, sizeof(buffer)); - if (strcmp(buffer, currentMusic, false) == 0) - { - return true; - } - } - } - } - } - case Difficulty_Nightmare: - { - for (int section = 1; section <= Difficulty_Nightmare; section++) - { - GetBossProfileMusicSounds(profile, soundInfo, section); - soundList = soundInfo.Paths; - if (soundList != null && soundList.Length > 0) - { - for (int i = 0; i < soundList.Length; i++) - { - soundList.GetString(i, buffer, sizeof(buffer)); - if (strcmp(buffer, currentMusic, false) == 0) - { - return true; - } - } - } - } - } - case Difficulty_Apollyon: - { - for (int section = 1; section <= Difficulty_Apollyon; section++) - { - GetBossProfileMusicSounds(profile, soundInfo, section); - soundList = soundInfo.Paths; - if (soundList != null && soundList.Length > 0) - { - for (int i = 0; i < soundList.Length; i++) - { - soundList.GetString(i, buffer, sizeof(buffer)); - if (strcmp(buffer, currentMusic, false) == 0) - { - return true; - } - } - } - } - } - } - - return false; -} - -void GetBossMusic(char[] buffer,int bufferLen) -{ - int difficulty = g_DifficultyConVar.IntValue; - switch (difficulty) - { - case Difficulty_Normal: - { - strcopy(currentMusicTrack, sizeof(currentMusicTrack), currentMusicTrackNormal); - strcopy(buffer, bufferLen, currentMusicTrackNormal); - } - case Difficulty_Hard: - { - strcopy(currentMusicTrack, sizeof(currentMusicTrack), currentMusicTrackHard); - strcopy(buffer, bufferLen, currentMusicTrackHard); - } - case Difficulty_Insane: - { - strcopy(currentMusicTrack, sizeof(currentMusicTrack), currentMusicTrackInsane); - strcopy(buffer, bufferLen, currentMusicTrackInsane); - } - case Difficulty_Nightmare: - { - strcopy(currentMusicTrack, sizeof(currentMusicTrack), currentMusicTrackNightmare); - strcopy(buffer, bufferLen, currentMusicTrackNightmare); - } - case Difficulty_Apollyon: - { - strcopy(currentMusicTrack, sizeof(currentMusicTrack), currentMusicTrackApollyon); - strcopy(buffer, bufferLen, currentMusicTrackApollyon); - } - } -} - -static Action BossMusic(Handle timer, any bossIndex) -{ - int difficulty = g_DifficultyConVar.IntValue; - float time = NPCGetSoundMusicLoop(bossIndex, difficulty); - SF2BossProfileData data; - data = NPCGetProfileData(bossIndex); - if (!data.IsPvEBoss && time > 0.0 && (g_NpcAllowMusicOnDifficulty[bossIndex] & difficulty)) - { - if (bossIndex > -1) - { - char profile[SF2_MAX_PROFILE_NAME_LENGTH]; - NPCGetProfile(bossIndex, profile, sizeof(profile)); - for (int i = 1; i <= MaxClients; i++) - { - if (IsValidClient(i) && currentMusicTrack[0] != '\0') - { - StopSound(i, MUSIC_CHAN, currentMusicTrack); - } - } - timerMusic = CreateTimer(time, BossMusic, bossIndex, TIMER_FLAG_NO_MAPCHANGE); - return Plugin_Continue; - } - NPCStopMusic(); - } - timerMusic = null; - return Plugin_Continue; -} - -void NPCRemoveAll() -{ - for (int i = 0; i < MAX_BOSSES; i++) - { - NPCRemove(i); - } -} - -int NPCGetType(int npcIndex) -{ - return g_NpcType[npcIndex]; -} - -int NPCGetFlags(int npcIndex) -{ - return g_NpcFlags[npcIndex]; -} - -void NPCSetFlags(int npcIndex,int flags) -{ - g_NpcFlags[npcIndex] = flags; -} - -float NPCGetSoundMusicLoop(int npcIndex, int difficulty) -{ - return g_NpcSoundMusicLoop[npcIndex][difficulty]; -} - -float NPCGetModelScale(int npcIndex) -{ - return g_NpcModelScale[npcIndex]; -} - -int NPCGetModelSkin(int npcIndex) -{ - return g_NpcModelSkin[npcIndex]; -} - -int NPCGetModelSkinDifficulty(int npcIndex, int difficulty) -{ - return g_NpcModelSkinDifficulty[npcIndex][difficulty]; -} - -int NPCGetModelSkinMax(int npcIndex) -{ - return g_NpcModelSkinMax[npcIndex]; -} - -int NPCGetModelBodyGroups(int npcIndex) -{ - return g_NpcModelBodyGroups[npcIndex]; -} - -int NPCGetModelBodyGroupsDifficulty(int npcIndex, int difficulty) -{ - return g_NpcModelBodyGroupsDifficulty[npcIndex][difficulty]; -} - -int NPCGetModelBodyGroupsMax(int npcIndex) -{ - return g_NpcModelBodyGroupsMax[npcIndex]; -} - -bool NPCGetRaidHitbox(int npcIndex) -{ - return g_NpcRaidHitbox[npcIndex]; -} - -float NPCGetBlinkLookRate(int npcIndex) -{ - return g_NpcBlinkLookRate[npcIndex]; -} - -float NPCGetBlinkStaticRate(int npcIndex) -{ - return g_NpcBlinkStaticRate[npcIndex]; -} - -bool NPCGetDiscoModeState(int npcIndex) -{ - return g_NpcHasDiscoMode[npcIndex]; -} - -float NPCGetDiscoModeRadiusMin(int npcIndex) -{ - return g_NpcDiscoRadiusMin[npcIndex]; -} - -float NPCGetDiscoModeRadiusMax(int npcIndex) -{ - return g_NpcDiscoRadiusMax[npcIndex]; -} - -float[] NPCGetDiscoModePos(int npcIndex) -{ - return g_NpcDiscoModePos[npcIndex]; -} - -bool NPCGetFestiveLightState(int npcIndex) -{ - return g_NpcHasFestiveLights[npcIndex]; -} - -int NPCGetFestiveLightBrightness(int npcIndex) -{ - return g_NpcFestiveLightBrightness[npcIndex]; -} - -float NPCGetFestiveLightDistance(int npcIndex) -{ - return g_NpcFestiveLightDistance[npcIndex]; -} - -float NPCGetFestiveLightRadius(int npcIndex) -{ - return g_NpcFestiveLightRadius[npcIndex]; -} - -float[] NPCGetFestiveLightPosition(int npcIndex) -{ - return g_NpcFestiveLightPos[npcIndex]; -} - -float[] NPCGetFestiveLightAngle(int npcIndex) -{ - return g_NpcFestiveLightAng[npcIndex]; -} - -bool NPCGetCustomOutlinesState(int npcIndex) -{ - return g_SlenderUseCustomOutlines[npcIndex]; -} - -bool NPCGetRainbowOutlineState(int npcIndex) -{ - return g_SlenderUseRainbowOutline[npcIndex]; -} - -void NPCSetAddSpeed(int npcIndex, float amount) -{ - g_NpcAddSpeed[npcIndex] += amount; -} - -void NPCSetAddAcceleration(int npcIndex, float amount) -{ - g_NpcAddAcceleration[npcIndex] += amount; -} - -float NPCGetAddSpeed(int npcIndex) -{ - return g_NpcAddSpeed[npcIndex]; -} - -float NPCGetAddAcceleration(int npcIndex) -{ - return g_NpcAddAcceleration[npcIndex]; -} - -bool NPCIsTeleportAllowed(int npcIndex, int difficulty) -{ - return g_NpcHasTeleportAllowed[npcIndex][difficulty]; -} - -float NPCGetTeleportTimeMin(int npcIndex, int difficulty) -{ - return g_NpcTeleportTimeMin[npcIndex][difficulty]; -} - -float NPCGetTeleportTimeMax(int npcIndex, int difficulty) -{ - return g_NpcTeleportTimeMax[npcIndex][difficulty]; -} - -float NPCGetTeleportRestPeriod(int npcIndex, int difficulty) -{ - return g_NpcTeleportRestPeriod[npcIndex][difficulty]; -} - -float NPCGetTeleportStressMin(int npcIndex, int difficulty) -{ - return g_NpcTeleportStressMin[npcIndex][difficulty]; -} - -float NPCGetTeleportStressMax(int npcIndex, int difficulty) -{ - return g_NpcTeleportStressMax[npcIndex][difficulty]; -} - -float NPCGetTeleportPersistencyPeriod(int npcIndex, int difficulty) -{ - return g_NpcTeleportPersistencyPeriod[npcIndex][difficulty]; -} - -void NPCSetTeleporter(int bossIndex, int teleporterNumber, int entity) -{ - g_NpcTeleporters[bossIndex][teleporterNumber] = entity; -} - -int NPCGetTeleporter(int bossIndex, int teleporterNumber) -{ - return g_NpcTeleporters[bossIndex][teleporterNumber]; -} - -SF2NPC_BaseNPC NPCGetCopyMaster(SF2NPC_BaseNPC controller) -{ - return SF2NPC_BaseNPC(g_SlenderCopyMaster[controller.Index]); -} - -SF2NPC_BaseNPC NPCGetCompanionMaster(SF2NPC_BaseNPC controller) -{ - return SF2NPC_BaseNPC(g_SlenderCompanionMaster[controller.Index]); -} - -float NPCGetJumpscareDistance(int npcIndex, int difficulty) -{ - return g_NpcJumpscareDistance[npcIndex][difficulty]; -} - -float NPCGetJumpscareDuration(int npcIndex, int difficulty) -{ - return g_NpcJumpscareDuration[npcIndex][difficulty]; -} - -float NPCGetJumpscareCooldown(int npcIndex, int difficulty) -{ - return g_NpcJumpscareCooldown[npcIndex][difficulty]; -} - -bool NPCGetJumpscareOnScare(int npcIndex) -{ - return g_NpcHasJumpscareOnScare[npcIndex]; -} - -float NPCGetIdleLifetime(int npcIndex,int difficulty) -{ - return g_NpcIdleLifetime[npcIndex][difficulty]; -} - -void NPCGetEyePositionOffset(int npcIndex, float buffer[3]) -{ - buffer[0] = g_SlenderEyePosOffset[npcIndex][0]; - buffer[1] = g_SlenderEyePosOffset[npcIndex][1]; - buffer[2] = g_SlenderEyePosOffset[npcIndex][2]; -} - -float NPCGetScareRadius(int npcIndex) -{ - return g_NpcScareRadius[npcIndex]; -} - -float NPCGetScareCooldown(int npcIndex) -{ - return g_NpcScareCooldown[npcIndex]; -} - -bool NPCGetSpeedBoostOnScare(int npcIndex) -{ - return g_NpcHasPlayerScareSpeedBoost[npcIndex]; -} - -float NPCGetScareSpeedBoostDuration(int npcIndex) -{ - return g_NpcPlayerSpeedBoostDuration[npcIndex]; -} - -bool NPCGetScareReactionState(int npcIndex) -{ - return g_NpcHasPlayerScareReaction[npcIndex]; -} - -int NPCGetScareReactionType(int npcIndex) -{ - return g_NpcPlayerScareReactionType[npcIndex]; -} - -bool NPCGetScareReplenishSprintState(int npcIndex) -{ - return g_NpcHasPlayerScareReplenishSprint[npcIndex]; -} - -float NPCGetScareReplenishSprintAmount(int npcIndex) -{ - return g_NpcPlayerScareReplenishSprintAmount[npcIndex]; -} - -int NPCGetTeleportType(int npcIndex) -{ - return g_NpcTeleportType[npcIndex]; -} - -bool NPCGetFakeCopyState(int npcIndex, int difficulty) -{ - return g_NpcHasFakeCopiesEnabled[npcIndex][difficulty]; -} - -#if defined _store_included -bool NPCGetDrainCreditState(int npcIndex) -{ - return g_NpcHasDrainCreditsState[npcIndex]; -} - -int NPCGetDrainCreditAmount(int npcIndex, int difficulty) -{ - return g_NpcDrainCreditAmount[npcIndex][difficulty]; -} -#endif - -bool NPCGetProxySpawnEffectState(int npcIndex) -{ - return g_NpcHasProxySpawnEffectEnabled[npcIndex]; -} - -float NPCGetProxySpawnEffectZOffset(int npcIndex) -{ - return g_NpcProxySpawnEffectZOffset[npcIndex]; -} - -float NPCGetProxySpawnChanceMin(int npcIndex, int difficulty) -{ - return g_NpcProxySpawnChanceMin[npcIndex][difficulty]; -} - -float NPCGetProxySpawnChanceMax(int npcIndex, int difficulty) -{ - return g_NpcProxySpawnChanceMax[npcIndex][difficulty]; -} - -float NPCGetProxySpawnChanceThreshold(int npcIndex, int difficulty) -{ - return g_NpcProxySpawnChanceThreshold[npcIndex][difficulty]; -} - -int NPCGetProxySpawnNumMin(int npcIndex, int difficulty) -{ - return g_NpcProxySpawnNumMin[npcIndex][difficulty]; -} - -int NPCGetProxySpawnNumMax(int npcIndex, int difficulty) -{ - return g_NpcProxySpawnNumMax[npcIndex][difficulty]; -} - -float NPCGetProxySpawnCooldownMin(int npcIndex, int difficulty) -{ - return g_NpcProxySpawnCooldownMin[npcIndex][difficulty]; -} - -float NPCGetProxySpawnCooldownMax(int npcIndex, int difficulty) -{ - return g_NpcProxySpawnCooldownMax[npcIndex][difficulty]; -} - -bool NPCGetAffectedBySightState(int npcIndex) -{ - return g_NpcShouldBeAffectedBySight[npcIndex]; -} - -void NPCSetAffectedBySightState(int npcIndex, bool state) -{ - g_NpcShouldBeAffectedBySight[npcIndex] = state; -} - -int NPCGetDefaultTeam(int npcIndex) -{ - return g_NpcDefaultTeam[npcIndex]; -} - -void NPCSetDefaultTeam(int npcIndex, int team) -{ - g_NpcDefaultTeam[npcIndex] = team; -} - -bool NPCGetWasKilled(int npcIndex) -{ - return g_NpcWasKilled[npcIndex]; -} - -void NPCSetWasKilled(int npcIndex, bool state) -{ - g_NpcWasKilled[npcIndex] = state; -} - -bool NPCShouldSeeEntity(int npcIndex, int entity) -{ - if (!IsValidEntity(entity)) - { - return false; - } - - Action result = Plugin_Continue; - Call_StartForward(g_OnBossSeeEntityFwd); - Call_PushCell(npcIndex); - Call_PushCell(entity); - Call_Finish(result); - - if (result != Plugin_Continue) - { - return false; - } - - return true; -} - -bool NPCShouldHearEntity(int npcIndex, int entity, SoundType soundType) +bool NPCShouldHearEntity(int npcIndex, int entity, SoundType soundType) { if (!IsValidEntity(entity)) { return false; } - if (NPCGetType(npcIndex) == SF2BossType_Statue) + if (SF2NPC_BaseNPC(npcIndex).GetProfileDataEx().Type == SF2BossType_Statue) { return false; } @@ -1674,7 +583,7 @@ void NPCGetEyePosition(int npcIndex, float buffer[3], const float defaultValue[3 float pos[3], eyePosOffset[3]; CBaseEntity(npcEnt).GetAbsOrigin(pos); - NPCGetEyePositionOffset(npcIndex, eyePosOffset); + SF2NPC_BaseNPC(npcIndex).GetProfileDataEx().GetEyes().GetOffsetPos(eyePosOffset); AddVectors(pos, eyePosOffset, buffer); } @@ -1689,11 +598,14 @@ bool NPCHasAttribute(int npcIndex, int attribute) char profile[SF2_MAX_PROFILE_NAME_LENGTH]; NPCGetProfile(npcIndex, profile, sizeof(profile)); - SF2BossProfileAttributesInfo attributesInfo; - GetBossProfileAttributesInfo(profile, attributesInfo); + BossProfileAttributes attributesInfo = GetBossProfile(profile).GetAttributes(); + if (attributesInfo == null) + { + return false; + } bool returnValue = false; - if (attributesInfo.Value[attribute] >= 0.0) + if (attributesInfo.GetValue(attribute) >= 0.0) { returnValue = true; } @@ -1711,10 +623,14 @@ float NPCGetAttributeValue(int npcIndex, int attribute) char profile[SF2_MAX_PROFILE_NAME_LENGTH]; NPCGetProfile(npcIndex, profile, sizeof(profile)); - SF2BossProfileAttributesInfo attributesInfo; - GetBossProfileAttributesInfo(profile, attributesInfo); + BossProfileAttributes attributesInfo = GetBossProfile(profile).GetAttributes(); + + if (attributesInfo == null) + { + return 0.0; + } - return attributesInfo.Value[attribute]; + return attributesInfo.GetValue(attribute); } bool SlenderCanRemove(int bossIndex) @@ -1731,8 +647,9 @@ bool SlenderCanRemove(int bossIndex) char profile[SF2_MAX_PROFILE_NAME_LENGTH]; NPCGetProfile(bossIndex, profile, sizeof(profile)); + BaseBossProfile profileData = GetBossProfile(profile); - int teleportType = NPCGetTeleportType(bossIndex); + int teleportType = profileData.TeleportType; int difficulty = GetLocalGlobalDifficulty(bossIndex); @@ -1765,7 +682,7 @@ bool SlenderCanRemove(int bossIndex) } GetClientAbsOrigin(i, buffer); - if (GetVectorSquareMagnitude(buffer, slenderPos) <= SquareFloat(g_SlenderStaticRadius[bossIndex][difficulty])) + if (GetVectorSquareMagnitude(buffer, slenderPos) <= SquareFloat(profileData.GetStaticRadius(difficulty))) { return false; } @@ -1812,199 +729,47 @@ bool SlenderCanRemove(int bossIndex) } return true; -} - -bool SelectProfile(SF2NPC_BaseNPC npc, const char[] profile, int additionalBossFlags = 0, SF2NPC_BaseNPC npcCopyMaster = SF2_INVALID_NPC, bool spawnCompanions = true, bool playSpawnSound = true, bool showPvEMessage = true) -{ - if (!IsProfileValid(profile)) - { - if (!npcCopyMaster.IsValid()) - { - LogSF2Message("Could not select profile for boss %d: profile %s is invalid!", npc.Index, profile); - return false; - } - } - npc.Remove(); - - npc.SetProfile(profile); - - SF2BossProfileData profileData; - g_BossProfileData.GetArray(profile, profileData, sizeof(profileData)); - - int bossType = GetBossProfileType(profile); - - g_NpcUniqueID[npc.Index] = g_NpcGlobalUniqueID++; - g_NpcProfileData[npc.Index] = profileData; - g_NpcType[npc.Index] = bossType; - - g_NpcModelScale[npc.Index] = GetBossProfileModelScale(profile); - - g_NpcModelSkin[npc.Index] = GetBossProfileSkin(profile); - - g_NpcModelSkinMax[npc.Index] = GetBossProfileSkinMax(profile); - - g_NpcModelBodyGroups[npc.Index] = GetBossProfileBodyGroups(profile); - - g_NpcModelBodyGroupsMax[npc.Index] = GetBossProfileBodyGroupsMax(profile); - - g_NpcRaidHitbox[npc.Index] = GetBossProfileRaidHitbox(profile); - - g_NpcHasIgnoreNavPrefer[npc.Index] = GetBossProfileIgnoreNavPrefer(profile); - - g_NpcBlinkLookRate[npc.Index] = GetBossProfileBlinkLookRate(profile); - g_NpcBlinkStaticRate[npc.Index] = GetBossProfileBlinkStaticRate(profile); - - g_NpcStepSize[npc.Index] = GetBossProfileStepSize(profile); - - g_NpcHasDiscoMode[npc.Index] = GetBossProfileDiscoModeState(profile); - g_NpcDiscoRadiusMin[npc.Index] = GetBossProfileDiscoRadiusMin(profile); - g_NpcDiscoRadiusMax[npc.Index] = GetBossProfileDiscoRadiusMax(profile); - - g_NpcHasFestiveLights[npc.Index] = GetBossProfileFestiveLightState(profile); - g_NpcFestiveLightBrightness[npc.Index] = GetBossProfileFestiveLightBrightness(profile); - g_NpcFestiveLightDistance[npc.Index] = GetBossProfileFestiveLightDistance(profile); - g_NpcFestiveLightRadius[npc.Index] = GetBossProfileFestiveLightRadius(profile); - GetBossProfileDiscoPosition(profile, g_NpcDiscoModePos[npc.Index]); - GetBossProfileFestiveLightPosition(profile, g_NpcFestiveLightPos[npc.Index]); - GetBossProfileFestiveLightAngles(profile, g_NpcFestiveLightAng[npc.Index]); - - g_SlenderUseCustomOutlines[npc.Index] = GetBossProfileCustomOutlinesState(profile); - g_SlenderUseRainbowOutline[npc.Index] = GetBossProfileRainbowOutlineState(profile); - - g_NpcHasProxyWeaponsEnabled[npc.Index] = GetBossProfileProxyWeapons(profile); - - g_NpcHasDrainCreditsState[npc.Index] = GetBossProfileDrainCreditState(profile); - g_NpcHasProxySpawnEffectEnabled[npc.Index] = GetBossProfileProxySpawnEffectState(profile); - g_NpcProxySpawnEffectZOffset[npc.Index] = GetBossProfileProxySpawnEffectZOffset(profile); - - if (SF_IsSlaughterRunMap()) - { - NPCSetFlags(npc.Index, GetBossProfileFlags(profile) | additionalBossFlags | SFF_NOTELEPORT); - } - else - { - NPCSetFlags(npc.Index, GetBossProfileFlags(profile) | additionalBossFlags); - } - - GetBossProfileEyePositionOffset(profile, g_SlenderEyePosOffset[npc.Index]); - GetBossProfileEyeAngleOffset(profile, g_SlenderEyeAngOffset[npc.Index]); - - GetBossProfileHullMins(profile, g_SlenderDetectMins[npc.Index]); - GetBossProfileHullMaxs(profile, g_SlenderDetectMaxs[npc.Index]); - - GetBossProfileRenderColor(profile, g_SlenderRenderColor[npc.Index]); - - g_SlenderRenderFX[npc.Index] = GetBossProfileRenderFX(profile); - g_SlenderRenderMode[npc.Index] = GetBossProfileRenderMode(profile); - - npc.CopyMaster = SF2_INVALID_NPC; - npc.CompanionMaster = SF2_INVALID_NPC; - - g_NpcShouldBeAffectedBySight[npc.Index] = false; - - g_NpcDefaultTeam[npc.Index] = g_DefaultBossTeamConVar.IntValue; - - for (int difficulty = 0; difficulty < Difficulty_Max; difficulty++) - { - g_NpcHasFakeCopiesEnabled[npc.Index][difficulty] = GetBossProfileFakeCopies(profile, difficulty); - g_NpcSoundMusicLoop[npc.Index][difficulty] = GetBossProfileSoundMusicLoop(profile, difficulty); - g_NpcIdleLifetime[npc.Index][difficulty] = GetBossProfileIdleLifetime(profile, difficulty); - g_SlenderStaticRadius[npc.Index][difficulty] = GetBossProfileStaticRadius(profile, difficulty); - g_SlenderStaticRate[npc.Index][difficulty] = GetBossProfileStaticRate(profile, difficulty); - g_SlenderStaticRateDecay[npc.Index][difficulty] = GetBossProfileStaticRateDecay(profile, difficulty); - g_SlenderStaticGraceTime[npc.Index][difficulty] = GetBossProfileStaticGraceTime(profile, difficulty); - g_SlenderTeleportMinRange[npc.Index][difficulty] = GetBossProfileTeleportRangeMin(profile, difficulty); - g_SlenderTeleportMaxRange[npc.Index][difficulty] = GetBossProfileTeleportRangeMax(profile, difficulty); - g_NpcHasTeleportAllowed[npc.Index][difficulty] = GetBossProfileTeleportAllowed(profile, difficulty); - g_NpcTeleportTimeMin[npc.Index][difficulty] = GetBossProfileTeleportTimeMin(profile, difficulty); - g_NpcTeleportTimeMax[npc.Index][difficulty] = GetBossProfileTeleportTimeMax(profile, difficulty); - g_NpcTeleportRestPeriod[npc.Index][difficulty] = GetBossProfileTeleportTargetRestPeriod(profile, difficulty); - g_NpcTeleportStressMin[npc.Index][difficulty] = GetBossProfileTeleportTargetStressMin(profile, difficulty); - g_NpcTeleportStressMax[npc.Index][difficulty] = GetBossProfileTeleportTargetStressMax(profile, difficulty); - g_NpcTeleportPersistencyPeriod[npc.Index][difficulty] = GetBossProfileTeleportTargetPersistencyPeriod(profile, difficulty); - g_NpcJumpscareDistance[npc.Index][difficulty] = GetBossProfileJumpscareDistance(profile, difficulty); - g_NpcJumpscareDuration[npc.Index][difficulty] = GetBossProfileJumpscareDuration(profile, difficulty); - g_NpcJumpscareCooldown[npc.Index][difficulty] = GetBossProfileJumpscareCooldown(profile, difficulty); - g_NpcModelSkinDifficulty[npc.Index][difficulty] = GetBossProfileSkinDifficulty(profile, difficulty); - g_NpcModelBodyGroupsDifficulty[npc.Index][difficulty] = GetBossProfileBodyGroupsDifficulty(profile, difficulty); - g_SlenderMaxCopies[npc.Index][difficulty] = GetBossProfileMaxCopies(profile, difficulty); - - g_SlenderProxyDamageVsEnemy[npc.Index][difficulty] = GetBossProfileProxyDamageVsEnemy(profile, difficulty); - g_SlenderProxyDamageVsBackstab[npc.Index][difficulty] = GetBossProfileProxyDamageVsBackstab(profile, difficulty); - g_SlenderProxyDamageVsSelf[npc.Index][difficulty] = GetBossProfileProxyDamageVsSelf(profile, difficulty); - g_SlenderProxyControlGainHitEnemy[npc.Index][difficulty] = GetBossProfileProxyControlGainHitEnemy(profile, difficulty); - g_SlenderProxyControlGainHitByEnemy[npc.Index][difficulty] = GetBossProfileProxyControlGainHitByEnemy(profile, difficulty); - g_SlenderProxyControlDrainRate[npc.Index][difficulty] = GetBossProfileProxyControlDrainRate(profile, difficulty); - g_SlenderMaxProxies[npc.Index][difficulty] = GetBossProfileMaxProxies(profile, difficulty); - g_NpcProxySpawnChanceMin[npc.Index][difficulty] = GetBossProfileProxySpawnChanceMin(profile, difficulty); - g_NpcProxySpawnChanceMax[npc.Index][difficulty] = GetBossProfileProxySpawnChanceMax(profile, difficulty); - g_NpcProxySpawnChanceThreshold[npc.Index][difficulty] = GetBossProfileProxySpawnChanceThreshold(profile, difficulty); - g_NpcProxySpawnNumMin[npc.Index][difficulty] = GetBossProfileProxySpawnNumberMin(profile, difficulty); - g_NpcProxySpawnNumMax[npc.Index][difficulty] = GetBossProfileProxySpawnNumberMax(profile, difficulty); - g_NpcProxySpawnCooldownMin[npc.Index][difficulty] = GetBossProfileProxySpawnCooldownMin(profile, difficulty); - g_NpcProxySpawnCooldownMax[npc.Index][difficulty] = GetBossProfileProxySpawnCooldownMax(profile, difficulty); - g_SlenderProxyTeleportMinRange[npc.Index][difficulty] = GetBossProfileProxyTeleportRangeMin(profile, difficulty); - g_SlenderProxyTeleportMaxRange[npc.Index][difficulty] = GetBossProfileProxyTeleportRangeMax(profile, difficulty); - g_NpcDrainCreditAmount[npc.Index][difficulty] = GetBossProfileDrainCreditAmount(profile, difficulty); - } - - ArrayList arrayNames; - - arrayNames = GetBossProfileNames(profile); - arrayNames.GetString(Difficulty_Normal, g_NpcName[npc.Index][1], sizeof(g_NpcName[][])); - - strcopy(g_NpcName[npc.Index][0], sizeof(g_NpcName[][]), g_NpcName[npc.Index][1]); - - arrayNames.GetString(Difficulty_Hard, g_NpcName[npc.Index][2], sizeof(g_NpcName[][])); - - arrayNames.GetString(Difficulty_Insane, g_NpcName[npc.Index][3], sizeof(g_NpcName[][])); - - arrayNames.GetString(Difficulty_Nightmare, g_NpcName[npc.Index][4], sizeof(g_NpcName[][])); - - arrayNames.GetString(Difficulty_Apollyon, g_NpcName[npc.Index][5], sizeof(g_NpcName[][])); - - arrayNames = null; - - g_NpcHasJumpscareOnScare[npc.Index] = GetBossProfileJumpscareOnScare(profile); +} - g_NpcScareRadius[npc.Index] = GetBossProfileScareRadius(profile); - g_NpcScareCooldown[npc.Index] = GetBossProfileScareCooldown(profile); +bool SelectProfile(SF2NPC_BaseNPC npc, const char[] profile, int additionalBossFlags = 0, SF2NPC_BaseNPC npcCopyMaster = SF2_INVALID_NPC, bool spawnCompanions = true, bool playSpawnSound = true, bool showPvEMessage = true) +{ + if (!IsProfileValid(profile)) + { + if (!npcCopyMaster.IsValid()) + { + LogSF2Message("Could not select profile for boss %d: profile %s is invalid!", npc.Index, profile); + return false; + } + } + npc.Remove(); - g_NpcHasPlayerScareSpeedBoost[npc.Index] = GetBossProfileSpeedBoostOnScare(profile); - g_NpcPlayerSpeedBoostDuration[npc.Index] = GetBossProfileScareSpeedBoostDuration(profile); + npc.SetProfile(profile); - g_NpcHasPlayerScareReaction[npc.Index] = GetBossProfileScareReactionState(profile); - g_NpcPlayerScareReactionType[npc.Index] = GetBossProfileScareReactionType(profile); + BaseBossProfile profileData = GetBossProfile(profile); - g_NpcHasPlayerScareReplenishSprint[npc.Index] = GetBossProfileScareReplenishState(profile); - g_NpcPlayerScareReplenishSprintAmount[npc.Index] = GetBossProfileScareReplenishAmount(profile); + int bossType = profileData.Type; - g_NpcTeleportType[npc.Index] = GetBossProfileTeleportType(profile); + g_NpcUniqueID[npc.Index] = g_NpcGlobalUniqueID++; - g_SlenderTeleportIgnoreChases[npc.Index] = GetBossProfileTeleportIgnoreChases(profile); + if (SF_IsSlaughterRunMap()) + { + NPCSetFlags(npc.Index, profileData.Flags | additionalBossFlags | SFF_NOTELEPORT); + } + else + { + NPCSetFlags(npc.Index, profileData.Flags | additionalBossFlags); + } - g_SlenderTeleportIgnoreVis[npc.Index] = GetBossProfileTeleportIgnoreVis(profile); + npc.CopyMaster = SF2_INVALID_NPC; + npc.CompanionMaster = SF2_INVALID_NPC; - g_SlenderProxiesAllowNormalVoices[npc.Index] = GetBossProfileProxyAllowNormalVoices(profile); + g_NpcShouldBeAffectedBySight[npc.Index] = false; - g_NpcDeathMessageDifficultyIndexes[npc.Index] = GetBossProfileChatDeathMessageDifficultyIndexes(profile); + g_NpcDefaultTeam[npc.Index] = g_DefaultBossTeamConVar.IntValue; g_NpcAddSpeed[npc.Index] = 0.0; g_NpcAddAcceleration[npc.Index] = 0.0; - // Deathcam values. - npc.DeathCamEnabled = GetBossProfileDeathCamState(profile); - g_SlenderDeathCamScareSound[npc.Index] = GetBossProfileDeathCamScareSound(profile); - g_SlenderPublicDeathCam[npc.Index] = GetBossProfilePublicDeathCamState(profile); - g_SlenderPublicDeathCamSpeed[npc.Index] = GetBossProfilePublicDeathCamSpeed(profile); - g_SlenderPublicDeathCamAcceleration[npc.Index] = GetBossProfilePublicDeathCamAcceleration(profile); - g_SlenderPublicDeathCamDeceleration[npc.Index] = GetBossProfilePublicDeathCamDeceleration(profile); - g_SlenderPublicDeathCamBackwardOffset[npc.Index] = GetBossProfilePublicDeathCamBackwardOffset(profile); - g_SlenderPublicDeathCamDownwardOffset[npc.Index] = GetBossProfilePublicDeathCamDownwardOffset(profile); - g_SlenderDeathCamOverlay[npc.Index] = GetBossProfileDeathCamOverlayState(profile); - g_SlenderDeathCamOverlayTimeStart[npc.Index] = GetBossProfileDeathCamOverlayStartTime(profile); - g_SlenderDeathCamTime[npc.Index] = GetBossProfileDeathCamTime(profile); - g_SlenderFakeTimer[npc.Index] = null; g_SlenderEntityThink[npc.Index] = null; g_SlenderDeathCamTimer[npc.Index] = null; @@ -2014,8 +779,6 @@ bool SelectProfile(SF2NPC_BaseNPC npc, const char[] profile, int additionalBossF g_SlenderNextJumpScare[npc.Index] = -1.0; g_SlenderTimeUntilNextProxy[npc.Index] = -1.0; - g_SlenderCustomOutroSong[npc.Index] = profileData.OutroMusic; - for (int i = 1; i <= MaxClients; i++) { g_SlenderTeleportPlayersRestTime[npc.Index][i] = -1.0; @@ -2068,19 +831,21 @@ bool SelectProfile(SF2NPC_BaseNPC npc, const char[] profile, int additionalBossF } else { - if (profileData.IsPvEBoss && showPvEMessage && profileData.PvESpawnMessagesArray != null && profileData.PvESpawnMessagesArray.Length > 0) + if (profileData.IsPvEBoss && showPvEMessage && profileData.PvESpawnMessagesArray != null && profileData.PvESpawnMessagesArray.Size > 0) { - char prefix[PLATFORM_MAX_PATH], message[PLATFORM_MAX_PATH]; - strcopy(prefix, sizeof(prefix), profileData.PvESpawnMessagePrefix); + char prefix[PLATFORM_MAX_PATH], message[PLATFORM_MAX_PATH], name[SF2_MAX_NAME_LENGTH], keyName[64]; + profileData.GetPvESpawnMessagePrefix(prefix, sizeof(prefix)); if (prefix[0] == '\0') { prefix = "[SF2]"; } - int messageIndex = GetRandomInt(0, profileData.PvESpawnMessagesArray.Length - 1); - profileData.PvESpawnMessagesArray.GetString(messageIndex, message, sizeof(message)); + int messageIndex = GetRandomInt(0, profileData.PvESpawnMessagesArray.Size - 1); + profileData.PvESpawnMessagesArray.GetKeyNameFromIndex(messageIndex, keyName, sizeof(keyName)); + profileData.PvESpawnMessagesArray.GetString(keyName, message, sizeof(message)); if (StrContains(message, "[BOSS]", true) != -1) { - ReplaceString(message, sizeof(message), "[BOSS]", g_NpcName[npc.Index][1]); + profileData.GetName(1, name, sizeof(name)); + ReplaceString(message, sizeof(message), "[BOSS]", name); } int chatLength = strlen(prefix) + strlen(message); if (chatLength > 255) @@ -2101,8 +866,7 @@ bool SelectProfile(SF2NPC_BaseNPC npc, const char[] profile, int additionalBossF } if (playSpawnSound) { - SF2BossProfileSoundInfo soundInfo; - GetBossProfileIntroSounds(profile, soundInfo); + ProfileSound soundInfo = profileData.GetIntroSounds(); for (int i = 1; i <= MaxClients; i++) { if (!IsValidClient(i)) @@ -2119,226 +883,17 @@ bool SelectProfile(SF2NPC_BaseNPC npc, const char[] profile, int additionalBossF soundInfo.EmitSound(true, i); } } - if (g_Enabled && !profileData.IsPvEBoss && timerMusic == null) - { - bool allowMusic = false; - float time; - for (int difficulty = 0; difficulty < Difficulty_Max; difficulty++) - { - if (g_NpcSoundMusicLoop[npc.Index][difficulty] > 0.0) - { - allowMusic = true; - g_NpcAllowMusicOnDifficulty[npc.Index] |= difficulty; - } - } - if (allowMusic) - { - time = g_NpcSoundMusicLoop[npc.Index][g_DifficultyConVar.IntValue]; - currentMusicTrackNormal[0] = '\0'; - currentMusicTrackHard[0] = '\0'; - currentMusicTrackInsane[0] = '\0'; - currentMusicTrackNightmare[0] = '\0'; - currentMusicTrackApollyon[0] = '\0'; - ArrayList soundList; - SF2BossProfileSoundInfo soundInfo; - GetBossProfileMusicSounds(profile, soundInfo, 1); - soundList = soundInfo.Paths; - if (soundList != null && soundList.Length > 0) - { - soundList.GetString(GetRandomInt(0, soundList.Length - 1), currentMusicTrackNormal, sizeof(currentMusicTrackNormal)); - } - soundList = null; - - GetBossProfileMusicSounds(profile, soundInfo, 2); - soundList = soundInfo.Paths; - if (soundList != null && soundList.Length > 0) - { - soundList.GetString(GetRandomInt(0, soundList.Length - 1), currentMusicTrackHard, sizeof(currentMusicTrackHard)); - } - if (currentMusicTrackHard[0] == '\0') - { - GetBossProfileMusicSounds(profile, soundInfo, 1); - soundList = soundInfo.Paths; - if (soundList != null && soundList.Length > 0) - { - soundList.GetString(GetRandomInt(0, soundList.Length - 1), currentMusicTrackHard, sizeof(currentMusicTrackHard)); - } - } - soundList = null; - - GetBossProfileMusicSounds(profile, soundInfo, 3); - soundList = soundInfo.Paths; - if (soundList != null && soundList.Length > 0) - { - soundList.GetString(GetRandomInt(0, soundList.Length - 1), currentMusicTrackInsane, sizeof(currentMusicTrackInsane)); - } - if (currentMusicTrackInsane[0] == '\0') - { - GetBossProfileMusicSounds(profile, soundInfo, 2); - soundList = soundInfo.Paths; - if (soundList != null && soundList.Length > 0) - { - soundList.GetString(GetRandomInt(0, soundList.Length - 1), currentMusicTrackInsane, sizeof(currentMusicTrackInsane)); - } - if (currentMusicTrackInsane[0] == '\0') - { - GetBossProfileMusicSounds(profile, soundInfo, 1); - soundList = soundInfo.Paths; - if (soundList != null && soundList.Length > 0) - { - soundList.GetString(GetRandomInt(0, soundList.Length - 1), currentMusicTrackInsane, sizeof(currentMusicTrackInsane)); - } - } - } - soundList = null; - - GetBossProfileMusicSounds(profile, soundInfo, 4); - soundList = soundInfo.Paths; - if (soundList != null && soundList.Length > 0) - { - soundList.GetString(GetRandomInt(0, soundList.Length - 1), currentMusicTrackNightmare, sizeof(currentMusicTrackNightmare)); - } - if (currentMusicTrackNightmare[0] == '\0') - { - GetBossProfileMusicSounds(profile, soundInfo, 3); - soundList = soundInfo.Paths; - if (soundList != null && soundList.Length > 0) - { - soundList.GetString(GetRandomInt(0, soundList.Length - 1), currentMusicTrackNightmare, sizeof(currentMusicTrackNightmare)); - } - if (currentMusicTrackNightmare[0] == '\0') - { - GetBossProfileMusicSounds(profile, soundInfo, 2); - soundList = soundInfo.Paths; - if (soundList != null && soundList.Length > 0) - { - soundList.GetString(GetRandomInt(0, soundList.Length - 1), currentMusicTrackNightmare, sizeof(currentMusicTrackNightmare)); - } - if (currentMusicTrackNightmare[0] == '\0') - { - GetBossProfileMusicSounds(profile, soundInfo, 1); - soundList = soundInfo.Paths; - if (soundList != null && soundList.Length > 0) - { - soundList.GetString(GetRandomInt(0, soundList.Length - 1), currentMusicTrackNightmare, sizeof(currentMusicTrackNightmare)); - } - } - } - } - soundList = null; - - GetBossProfileMusicSounds(profile, soundInfo, 5); - soundList = soundInfo.Paths; - if (soundList != null && soundList.Length > 0) - { - soundList.GetString(GetRandomInt(0, soundList.Length - 1), currentMusicTrackApollyon, sizeof(currentMusicTrackApollyon)); - } - if (currentMusicTrackApollyon[0] == '\0') - { - GetBossProfileMusicSounds(profile, soundInfo, 4); - soundList = soundInfo.Paths; - if (soundList != null && soundList.Length > 0) - { - soundList.GetString(GetRandomInt(0, soundList.Length - 1), currentMusicTrackApollyon, sizeof(currentMusicTrackApollyon)); - } - if (currentMusicTrackApollyon[0] == '\0') - { - GetBossProfileMusicSounds(profile, soundInfo, 3); - soundList = soundInfo.Paths; - if (soundList != null && soundList.Length > 0) - { - soundList.GetString(GetRandomInt(0, soundList.Length - 1), currentMusicTrackApollyon, sizeof(currentMusicTrackApollyon)); - } - if (currentMusicTrackApollyon[0] == '\0') - { - GetBossProfileMusicSounds(profile, soundInfo, 2); - soundList = soundInfo.Paths; - if (soundList != null && soundList.Length > 0) - { - soundList.GetString(GetRandomInt(0, soundList.Length - 1), currentMusicTrackApollyon, sizeof(currentMusicTrackApollyon)); - } - if (currentMusicTrackApollyon[0] == '\0') - { - GetBossProfileMusicSounds(profile, soundInfo, 1); - soundList = soundInfo.Paths; - if (soundList != null && soundList.Length > 0) - { - soundList.GetString(GetRandomInt(0, soundList.Length - 1), currentMusicTrackApollyon, sizeof(currentMusicTrackApollyon)); - } - } - } - } - } - soundList = null; - - if ((g_NpcAllowMusicOnDifficulty[npc.Index] & g_DifficultyConVar.IntValue) && time > 0.0) - { - timerMusic = CreateTimer(time, BossMusic, npc.Index, TIMER_FLAG_NO_MAPCHANGE); - for(int client = 1; client <= MaxClients; client++) - { - if (IsValidClient(client) && (!g_PlayerEliminated[client] || IsClientInGhostMode(client))) - { - ClientChaseMusicReset(client); - ClientChaseMusicSeeReset(client); - ClientAlertMusicReset(client); - ClientIdleMusicReset(client); - GetChaserProfileChaseMusics(profile, soundInfo); - soundInfo.StopAllSounds(client); - GetChaserProfileChaseVisibleMusics(profile, soundInfo); - soundInfo.StopAllSounds(client); - GetChaserProfileAlertMusics(profile, soundInfo); - soundInfo.StopAllSounds(client); - GetChaserProfileIdleMusics(profile, soundInfo); - soundInfo.StopAllSounds(client); - if (g_PlayerMusicString[client][0] != '\0') - { - EmitSoundToClient(client, g_PlayerMusicString[client], _, MUSIC_CHAN, SNDLEVEL_NONE, SND_CHANGEVOL, 0.0001); - } - switch (g_DifficultyConVar.IntValue) - { - case Difficulty_Normal: - { - strcopy(currentMusicTrack, sizeof(currentMusicTrack), currentMusicTrackNormal); - } - case Difficulty_Hard: - { - strcopy(currentMusicTrack, sizeof(currentMusicTrack), currentMusicTrackHard); - } - case Difficulty_Insane: - { - strcopy(currentMusicTrack, sizeof(currentMusicTrack), currentMusicTrackInsane); - } - case Difficulty_Nightmare: - { - strcopy(currentMusicTrack, sizeof(currentMusicTrack), currentMusicTrackNightmare); - } - case Difficulty_Apollyon: - { - strcopy(currentMusicTrack, sizeof(currentMusicTrack), currentMusicTrackApollyon); - } - } - if (currentMusicTrack[0] != '\0') - { - StopSound(client, MUSIC_CHAN, currentMusicTrack); - } - ClientMusicStart(client, currentMusicTrack, _, MUSIC_PAGE_VOLUME,true); - ClientUpdateMusicSystem(client); - } - } - } - } - } if (spawnCompanions) { char compProfile[SF2_MAX_PROFILE_NAME_LENGTH]; - ArrayList companions = GetBossProfileCompanions(profile); + BossProfileCompanions companions = profileData.GetCompanions(); if (companions != null) { char spawnType[64]; - GetBossProfileCompanionsSpawnType(profile, spawnType, sizeof(spawnType)); + companions.GetSpawnType(spawnType, sizeof(spawnType)); if (spawnType[0] == '\0') // No random companions { - SF2BossProfileCompanionsInfo companionInfo; + /*SF2BossProfileCompanionsInfo companionInfo; companions.GetArray(0, companionInfo); if (companionInfo.Bosses != null && companionInfo.Bosses.Length > 0) { @@ -2358,7 +913,7 @@ bool SelectProfile(SF2NPC_BaseNPC npc, const char[] profile, int additionalBossF LogSF2Message("Companion boss profile %s is invalid, skipping boss...", compProfile); } } - } + }*/ } else { @@ -2379,6 +934,10 @@ bool SelectProfile(SF2NPC_BaseNPC npc, const char[] profile, int additionalBossF Call_PushCell(npc.Index); Call_Finish(); + Call_StartForward(g_OnBossAddedPFwd); + Call_PushCell(npc); + Call_Finish(); + if (!npc.IsCopy) { LogSF2Message("Boss profile %s has been added to the game.", profile); @@ -2414,7 +973,7 @@ void NPCAddCompanions(SF2NPC_BaseNPC npc) { char profile[SF2_MAX_PROFILE_NAME_LENGTH]; npc.GetProfile(profile, sizeof(profile)); - ArrayList companions = GetBossProfileCompanions(profile); + BossProfileCompanions companions = npc.GetProfileDataEx().GetCompanions(); if (companions == null) { return; @@ -2423,24 +982,20 @@ void NPCAddCompanions(SF2NPC_BaseNPC npc) ArrayList companionsToAdd = new ArrayList(SF2_MAX_PROFILE_NAME_LENGTH); char compProfile[SF2_MAX_PROFILE_NAME_LENGTH]; float maxWeight = 0.0; - for (int i = 0; i < companions.Length; i++) + for (int i = 0; i < companions.SectionLength; i++) { - SF2BossProfileCompanionsInfo companionInfo; - companions.GetArray(i, companionInfo, sizeof(companionInfo)); - maxWeight += companionInfo.Weight[npc.Difficulty]; + maxWeight += companions.GetWeightFromGroupEx(i, npc.Difficulty); } float randomWeight = GetRandomFloat(0.0, maxWeight); - for (int i = 0; i < companions.Length; i++) + for (int i = 0; i < companions.SectionLength; i++) { - SF2BossProfileCompanionsInfo companionInfo; - companions.GetArray(i, companionInfo, sizeof(companionInfo)); - if (companionInfo.Bosses == null) + if (companions.GetBossesFromGroupEx(i) == null) { continue; } - float weight = companionInfo.Weight[npc.Difficulty]; + float weight = companions.GetWeightFromGroupEx(i, npc.Difficulty); if (weight <= 0.0) { continue; @@ -2452,9 +1007,11 @@ void NPCAddCompanions(SF2NPC_BaseNPC npc) continue; } - for (int i2 = 0; i2 < companionInfo.Bosses.Length; i2++) + for (int i2 = 0; i2 < companions.GetBossesFromGroupEx(i).KeyLength; i2++) { - companionInfo.Bosses.GetString(i2, compProfile, sizeof(compProfile)); + char key[64]; + companions.GetBossesFromGroupEx(i).GetKeyNameFromIndex(i2, key, sizeof(key)); + companions.GetBossesFromGroupEx(i).GetString(key, compProfile, sizeof(compProfile)); companionsToAdd.PushString(compProfile); } break; @@ -2491,33 +1048,32 @@ bool GetSlenderModel(int bossIndex, int modelState = 0, char[] buffer, int buffe char profile[SF2_MAX_PROFILE_NAME_LENGTH]; NPCGetProfile(bossIndex, profile, sizeof(profile)); - ArrayList modelsArray; + BaseBossProfile profileData = GetBossProfile(profile); switch (modelState) { case 0: { - modelsArray = GetBossProfileModels(profile); switch (difficulty) { case Difficulty_Normal: { - modelsArray.GetString(Difficulty_Normal, buffer, bufferLen); + profileData.GetModel(Difficulty_Normal, buffer, bufferLen); } case Difficulty_Hard: { - modelsArray.GetString(Difficulty_Hard, buffer, bufferLen); + profileData.GetModel(Difficulty_Hard, buffer, bufferLen); } case Difficulty_Insane: { - modelsArray.GetString(Difficulty_Insane, buffer, bufferLen); + profileData.GetModel(Difficulty_Insane, buffer, bufferLen); } case Difficulty_Nightmare: { - modelsArray.GetString(Difficulty_Nightmare, buffer, bufferLen); + profileData.GetModel(Difficulty_Nightmare, buffer, bufferLen); } case Difficulty_Apollyon: { - modelsArray.GetString(Difficulty_Apollyon, buffer, bufferLen); + profileData.GetModel(Difficulty_Apollyon, buffer, bufferLen); } } } @@ -2528,6 +1084,7 @@ bool GetSlenderModel(int bossIndex, int modelState = 0, char[] buffer, int buffe bool NPCFindUnstuckPosition(SF2_BaseBoss boss, float lastPos[3], float destination[3]) { SF2NPC_BaseNPC controller = boss.Controller; + BaseBossProfile data = controller.GetProfileDataEx(); PathFollower path = controller.Path; CBaseNPC npc = TheNPCs.FindNPCByEntIndex(boss.index); CNavArea area = TheNavMesh.GetNearestNavArea(lastPos, _, _, _, false); @@ -2535,16 +1092,20 @@ bool NPCFindUnstuckPosition(SF2_BaseBoss boss, float lastPos[3], float destinati float tempMaxs[3]; npc.GetBodyMaxs(tempMaxs); float traceMins[3]; - traceMins[0] = g_SlenderDetectMins[controller.Index][0] - 5.0; - traceMins[1] = g_SlenderDetectMins[controller.Index][1] - 5.0; + data.GetHullMins(traceMins); + traceMins[0] -= 5.0; + traceMins[1] -= 5.0; traceMins[2] = 0.0; float traceMaxs[3]; - traceMaxs[0] = g_SlenderDetectMaxs[controller.Index][0] + 5.0; - traceMaxs[1] = g_SlenderDetectMaxs[controller.Index][1] + 5.0; + data.GetHullMaxs(traceMaxs); + traceMaxs[0] += 5.0; + traceMaxs[1] += 5.0; traceMaxs[2] = tempMaxs[2]; - TR_TraceHullFilter(destination, destination, traceMins, traceMaxs, MASK_NPCSOLID, TraceRayDontHitPlayersOrEntityEx); - if (GetVectorSquareMagnitude(destination, lastPos) <= SquareFloat(16.0) || TR_DidHit()) + Handle trace = TR_TraceHullFilterEx(destination, destination, traceMins, traceMaxs, MASK_NPCSOLID, TraceRayDontHitPlayersOrEntityEx); + bool hit = TR_DidHit(trace); + delete trace; + if (GetVectorSquareMagnitude(destination, lastPos) <= SquareFloat(16.0) || hit) { SurroundingAreasCollector collector = TheNavMesh.CollectSurroundingAreas(area, 400.0); int areaCount = collector.Count(); @@ -2566,8 +1127,10 @@ bool NPCFindUnstuckPosition(SF2_BaseBoss boss, float lastPos[3], float destinati area = collector.Get(randomArea); area.GetCenter(destination); - TR_TraceHullFilter(destination, destination, traceMins, traceMaxs, MASK_NPCSOLID, TraceRayDontHitPlayersOrEntityEx); - if (TR_DidHit()) + trace = TR_TraceHullFilterEx(destination, destination, traceMins, traceMaxs, MASK_NPCSOLID, TraceRayDontHitPlayersOrEntityEx); + hit = TR_DidHit(trace); + delete trace; + if (hit) { area = NULL_AREA; validAreaCount--; @@ -2617,12 +1180,9 @@ bool NPCFindUnstuckPosition(SF2_BaseBoss boss, float lastPos[3], float destinati } } - SF2BossProfileData data; - data = controller.GetProfileData(); - int ent = -1; char targetName[64]; - if (data.IsPvEBoss) + if (controller.GetProfileDataEx().IsPvEBoss) { ArrayList spawnPointList = new ArrayList(); @@ -2700,6 +1260,7 @@ void ChangeAllSlenderModels() } char profile[SF2_MAX_PROFILE_NAME_LENGTH]; NPCGetProfile(npcIndex, profile, sizeof(profile)); + BaseBossProfile data = GetBossProfile(profile); GetSlenderModel(npcIndex, _, buffer, sizeof(buffer)); SetEntityModel(slender, buffer); @@ -2708,59 +1269,46 @@ void ChangeAllSlenderModels() SF2_ChaserEntity(slender).UpdateMovementAnimation(); } SetGlowModel(slender, buffer); - if (NPCGetModelSkinMax(npcIndex) > 0) + if (data.SkinMax > 0) { - int randomSkin = GetRandomInt(0, NPCGetModelSkinMax(npcIndex)); + int randomSkin = GetRandomInt(0, data.SkinMax); SetEntProp(slender, Prop_Send, "m_nSkin", randomSkin); } else { - if (GetBossProfileSkinDifficultyState(profile)) - { - SetEntProp(slender, Prop_Send, "m_nSkin", NPCGetModelSkinDifficulty(npcIndex, difficulty)); - } - else - { - SetEntProp(slender, Prop_Send, "m_nSkin", NPCGetModelSkin(npcIndex)); - } + SetEntProp(slender, Prop_Send, "m_nSkin", data.GetSkin(difficulty)); } - if (NPCGetModelBodyGroupsMax(npcIndex) > 0) + if (data.BodyMax > 0) { - int randomBody = GetRandomInt(0, NPCGetModelBodyGroupsMax(npcIndex)); + int randomBody = GetRandomInt(0, data.BodyMax); SetEntProp(slender, Prop_Send, "m_nBody", randomBody); } else { - if (GetBossProfileBodyGroupsDifficultyState(profile)) - { - SetEntProp(slender, Prop_Send, "m_nBody", NPCGetModelBodyGroupsDifficulty(npcIndex, difficulty)); - } - else - { - SetEntProp(slender, Prop_Send, "m_nBody", NPCGetModelBodyGroups(npcIndex)); - } + SetEntProp(slender, Prop_Send, "m_nBody", data.GetBodyGroup(difficulty)); } - if (NPCGetType(npcIndex) == SF2BossType_Chaser) + if (data.Type == SF2BossType_Chaser) { - float tempHitboxMins[3]; - if (NPCGetRaidHitbox(npcIndex)) + float mins[3], maxs[3]; + if (data.RaidHitbox) { - CopyVector(g_SlenderDetectMins[npcIndex], tempHitboxMins); - tempHitboxMins[2] = 10.0; - SetEntPropVector(slender, Prop_Send, "m_vecMins", tempHitboxMins); - SetEntPropVector(slender, Prop_Send, "m_vecMaxs", g_SlenderDetectMaxs[npcIndex]); + data.GetHullMins(mins); + data.GetHullMaxs(maxs); + mins[2] = 10.0; + SetEntPropVector(slender, Prop_Send, "m_vecMins", mins); + SetEntPropVector(slender, Prop_Send, "m_vecMaxs", maxs); - SetEntPropVector(slender, Prop_Send, "m_vecMinsPreScaled", tempHitboxMins); - SetEntPropVector(slender, Prop_Send, "m_vecMaxsPreScaled", g_SlenderDetectMaxs[npcIndex]); + SetEntPropVector(slender, Prop_Send, "m_vecMinsPreScaled", mins); + SetEntPropVector(slender, Prop_Send, "m_vecMaxsPreScaled", maxs); } else { - CopyVector(HULL_HUMAN_MINS, tempHitboxMins); - tempHitboxMins[2] = 10.0; - SetEntPropVector(slender, Prop_Send, "m_vecMins", tempHitboxMins); + CopyVector(HULL_HUMAN_MINS, mins); + mins[2] = 10.0; + SetEntPropVector(slender, Prop_Send, "m_vecMins", mins); SetEntPropVector(slender, Prop_Send, "m_vecMaxs", HULL_HUMAN_MAXS); - SetEntPropVector(slender, Prop_Send, "m_vecMinsPreScaled", tempHitboxMins); + SetEntPropVector(slender, Prop_Send, "m_vecMinsPreScaled", mins); SetEntPropVector(slender, Prop_Send, "m_vecMaxsPreScaled", HULL_HUMAN_MAXS); } } @@ -2775,7 +1323,7 @@ void RemoveProfile(int bossIndex) KillPvEBoss(controller.EntIndex); } - if (SF_IsBoxingMap() && (GetRoundState() == SF2RoundState_Escape) && NPCChaserIsBoxingBoss(bossIndex)) + if (SF_IsBoxingMap() && (GetRoundState() == SF2RoundState_Escape) && view_as(controller).GetProfileDataEx().BoxingBoss) { g_SlenderBoxingBossCount -= 1; } @@ -2783,11 +1331,6 @@ void RemoveProfile(int bossIndex) char profile[SF2_MAX_PROFILE_NAME_LENGTH]; controller.GetProfile(profile, sizeof(profile)); - if (!controller.IsCopy && MusicActive() && BossHasMusic(profile) && BossMatchesCurrentMusic(profile)) - { - NPCStopMusic(); - } - controller.UnSpawn(true); // Call our forward. @@ -2805,7 +1348,6 @@ void RemoveProfile(int bossIndex) g_SlenderTeleportPlayersRestTime[bossIndex][i] = -1.0; } - g_NpcTeleportType[bossIndex] = -1; g_SlenderTeleportTarget[bossIndex] = INVALID_ENT_REFERENCE; g_SlenderProxyTarget[bossIndex] = INVALID_ENT_REFERENCE; g_SlenderTeleportMaxTargetStress[bossIndex] = 9999.0; @@ -2836,28 +1378,13 @@ void RemoveProfile(int bossIndex) g_SlenderProxyTeleportMaxRange[bossIndex][difficulty] = 0.0; } - g_NpcType[bossIndex] = -1; g_NpcProfileIndex[bossIndex] = -1; g_NpcUniqueProfileIndex[bossIndex] = -1; controller.Flags = 0; - g_NpcFieldOfView[bossIndex] = 0.0; - controller.SetAddSpeed(0.0); controller.SetAddAcceleration(0.0); - g_NpcStepSize[bossIndex] = 0.0; - - g_NpcHasDiscoMode[bossIndex] = false; - g_NpcDiscoRadiusMin[bossIndex] = 0.0; - g_NpcDiscoRadiusMax[bossIndex] = 0.0; - - g_NpcHasFestiveLights[bossIndex] = false; - g_NpcFestiveLightBrightness[bossIndex] = 0; - g_NpcFestiveLightDistance[bossIndex] = 0.0; - g_NpcFestiveLightRadius[bossIndex] = 0.0; - - NPCSetDeathCamEnabled(bossIndex, false); controller.CopyMaster = SF2_INVALID_NPC; controller.CompanionMaster = SF2_INVALID_NPC; @@ -2866,36 +1393,11 @@ void RemoveProfile(int bossIndex) g_SlenderDeathCamTarget[bossIndex] = INVALID_ENT_REFERENCE; g_SlenderThink[bossIndex] = null; g_SlenderEntityThink[bossIndex] = null; - g_SlenderCustomOutroSong[bossIndex] = false; g_SlenderFakeTimer[bossIndex] = null; g_SlenderModel[bossIndex] = INVALID_ENT_REFERENCE; g_SlenderBoxingBossIsKilled[bossIndex] = false; g_SlenderTimeUntilNextProxy[bossIndex] = -1.0; - g_NpcScareRadius[bossIndex] = 0.0; - g_NpcHasPlayerScareSpeedBoost[bossIndex] = false; - g_NpcPlayerSpeedBoostDuration[bossIndex] = 0.0; - g_NpcHasPlayerScareReaction[bossIndex] = false; - g_NpcPlayerScareReactionType[bossIndex] = 0; - g_NpcHasPlayerScareReplenishSprint[bossIndex] = false; - g_NpcPlayerScareReplenishSprintAmount[bossIndex] = 0.0; - g_SlenderRenderFX[bossIndex] = 0; - g_SlenderRenderMode[bossIndex] = 0; - - for (int i = 0; i < 3; i++) - { - g_SlenderDetectMins[bossIndex][i] = 0.0; - g_SlenderDetectMaxs[bossIndex][i] = 0.0; - g_SlenderEyePosOffset[bossIndex][i] = 0.0; - g_NpcDiscoModePos[bossIndex][i] = 0.0; - g_NpcFestiveLightPos[bossIndex][i] = 0.0; - g_NpcFestiveLightAng[bossIndex][i] = 0.0; - } - - for (int i = 0; i < 4; i++) - { - g_SlenderRenderColor[bossIndex][i] = 0; - } controller.SetProfile(""); } @@ -2914,8 +1416,9 @@ void SpawnSlender(SF2NPC_BaseNPC npc, const float pos[3]) char profile[SF2_MAX_PROFILE_NAME_LENGTH]; npc.UnSpawn(true); - npc.GetProfile(profile,sizeof(profile)); + npc.GetProfile(profile, sizeof(profile)); npc.WasKilled = false; + BaseBossProfile data = npc.GetProfileDataEx(); float truePos[3], trueAng[3]; trueAng[1] = GetRandomFloat(0.0, 360.0); @@ -2923,13 +1426,9 @@ void SpawnSlender(SF2NPC_BaseNPC npc, const float pos[3]) int bossIndex = npc.Index; - char buffer[PLATFORM_MAX_PATH]; - - GetSlenderModel(bossIndex, _, buffer, sizeof(buffer)); - CBaseCombatCharacter entity; - switch (NPCGetType(bossIndex)) + switch (data.Type) { case SF2BossType_Statue: { @@ -2938,227 +1437,9 @@ void SpawnSlender(SF2NPC_BaseNPC npc, const float pos[3]) case SF2BossType_Chaser: { entity = view_as(Spawn_Chaser(npc, truePos, trueAng)); - /*CBaseNPC npcBoss = CBaseNPC(); - CBaseCombatCharacter npcEntity = CBaseCombatCharacter(npcBoss.GetEntity()); - CBaseNPC_Locomotion locomotion = npcBoss.GetLocomotion(); - npcEntity.Hook_HandleAnimEvent(CBaseAnimating_HandleAnimEvent); - - npcEntity.Teleport(truePos, trueAng); - npcEntity.SetModel(buffer); - npcEntity.SetRenderMode(view_as(g_SlenderRenderMode[bossIndex])); - npcEntity.SetRenderFx(view_as(g_SlenderRenderFX[bossIndex])); - npcEntity.SetRenderColor(g_SlenderRenderColor[bossIndex][0], g_SlenderRenderColor[bossIndex][1], g_SlenderRenderColor[bossIndex][2], g_SlenderRenderColor[bossIndex][3]); - if (SF_SpecialRound(SPECIALROUND_TINYBOSSES)) - { - float scaleModel = NPCGetModelScale(bossIndex) * 0.5; - npcEntity.SetPropFloat(Prop_Send, "m_flModelScale", scaleModel); - } - else - { - npcEntity.SetPropFloat(Prop_Send, "m_flModelScale", NPCGetModelScale(bossIndex)); - } - npcEntity.Spawn(); - npcEntity.Activate(); - - npcBoss.flStepSize = 18.0; - npcBoss.flGravity = g_Gravity; - npcBoss.flAcceleration = g_SlenderCalculatedAcceleration[bossIndex]; - npcBoss.flDeathDropHeight = 99999.0; - npcBoss.flJumpHeight = 512.0; - npcBoss.flWalkSpeed = g_SlenderCalculatedWalkSpeed[bossIndex]; - npcBoss.flRunSpeed = g_SlenderCalculatedSpeed[bossIndex]; - - if (!SF_IsBoxingMap()) - { - locomotion.SetCallback(LocomotionCallback_IsAbleToJumpAcrossGaps, CanJumpAcrossGaps); - locomotion.SetCallback(LocomotionCallback_IsAbleToClimb, CanJumpAcrossGaps); - locomotion.SetCallback(LocomotionCallback_JumpAcrossGap, JumpAcrossGapsCBase); - locomotion.SetCallback(LocomotionCallback_ClimbUpToLedge, ClimbUpCBase); - } - - if (NPCGetRaidHitbox(bossIndex)) - { - npcBoss.SetBodyMins(g_SlenderDetectMins[bossIndex]); - npcBoss.SetBodyMaxs(g_SlenderDetectMaxs[bossIndex]); - - npcEntity.SetPropVector(Prop_Send, "m_vecMins", g_SlenderDetectMins[bossIndex]); - npcEntity.SetPropVector(Prop_Send, "m_vecMaxs", g_SlenderDetectMaxs[bossIndex]); - - npcEntity.SetPropVector(Prop_Send, "m_vecMinsPreScaled", g_SlenderDetectMins[bossIndex]); - npcEntity.SetPropVector(Prop_Send, "m_vecMaxsPreScaled", g_SlenderDetectMaxs[bossIndex]); - } - else - { - npcBoss.SetBodyMins(HULL_HUMAN_MINS); - npcBoss.SetBodyMaxs(HULL_HUMAN_MAXS); - - npcEntity.SetPropVector(Prop_Send, "m_vecMins", HULL_HUMAN_MINS); - npcEntity.SetPropVector(Prop_Send, "m_vecMaxs", HULL_HUMAN_MAXS); - - npcEntity.SetPropVector(Prop_Send, "m_vecMinsPreScaled", HULL_HUMAN_MINS); - npcEntity.SetPropVector(Prop_Send, "m_vecMaxsPreScaled", HULL_HUMAN_MAXS); - } - - if (SF_IsBoxingMap()) - { - npcEntity.SetProp(Prop_Send, "m_CollisionGroup", COLLISION_GROUP_DEBRIS_TRIGGER); - } - - SDKHook(npcEntity.iEnt, SDKHook_OnTakeDamageAlive, Hook_SlenderOnTakeDamage); - - // Reset stats. - g_SlenderInBacon[bossIndex] = false; - g_SlenderTarget[bossIndex] = INVALID_ENT_REFERENCE; - g_SlenderTargetIsVisible[bossIndex] = false; - g_SlenderState[bossIndex] = STATE_IDLE; - g_IsSlenderAttacking[bossIndex] = false; - g_SlenderGiveUp[bossIndex] = false; - g_SlenderAttackTimer[bossIndex] = null; - g_SlenderLaserTimer[bossIndex] = null; - g_SlenderBackupAtkTimer[bossIndex] = null; - g_SlenderChaseInitialTimer[bossIndex] = null; - g_SlenderRage1Timer[bossIndex] = null; - g_SlenderRage2Timer[bossIndex] = null; - g_SlenderRage3Timer[bossIndex] = null; - g_SlenderHealTimer[bossIndex] = null; - g_SlenderHealDelayTimer[bossIndex] = null; - g_SlenderHealEventTimer[bossIndex] = null; - g_SlenderStartFleeTimer[bossIndex] = null; - g_SlenderTargetSoundLastTime[bossIndex] = -1.0; - g_SlenderTargetSoundDiscardMasterPosTime[bossIndex] = -1.0; - g_SlenderTargetSoundType[bossIndex] = SoundType_None; - g_SlenderInvestigatingSound[bossIndex] = false; - g_SlenderNextStunTime[bossIndex] = -1.0; - g_NpcHasCloaked[bossIndex] = false; - g_SlenderLastHeardFootstep[bossIndex] = 0.0; - g_SlenderLastHeardVoice[bossIndex] = 0.0; - g_SlenderLastHeardWeapon[bossIndex] = 0.0; - g_SlenderNextVoiceSound[bossIndex] = 0.0; - g_SlenderNextFootstepSound[bossIndex] = 0.0; - g_SlenderNextMoanSound[bossIndex] = 0.0; - g_SlenderTauntAlertCount[bossIndex] = 0; - - for (int difficulty2 = 0; difficulty2 < Difficulty_Max; difficulty2++) - { - g_SlenderTimeUntilKill[bossIndex] = GetGameTime() + NPCGetIdleLifetime(bossIndex, difficulty2); - } - - g_SlenderTimeUntilRecover[bossIndex] = -1.0; - g_SlenderTimeUntilAlert[bossIndex] = -1.0; - g_SlenderTimeUntilIdle[bossIndex] = -1.0; - g_SlenderTimeUntilChase[bossIndex] = -1.0; - g_SlenderTimeUntilNoPersistence[bossIndex] = -1.0; - g_SlenderTimeUntilAttackEnd[bossIndex] = -1.0; - g_SlenderNextPathTime[bossIndex] = 0.0; - g_SlenderLastCalculPathTime[bossIndex] = -1.0; - g_LastStuckTime[bossIndex] = -1.0; - g_SlenderInterruptConditions[bossIndex] = 0; - g_SlenderChaseDeathPositionBool[bossIndex] = false; - g_NpcPlayerScareVictin[bossIndex] = INVALID_ENT_REFERENCE; - g_NpcChasingScareVictin[bossIndex] = false; - g_NpcLostChasingScareVictim[bossIndex] = false; - g_NpcVelocityCancel[bossIndex] = false; - g_SlenderBurnTimer[bossIndex] = null; - g_SlenderBleedTimer[bossIndex] = null; - g_SlenderMarkedTimer[bossIndex] = null; - g_SlenderDeathCamTimer[bossIndex] = null; - g_SlenderDeathCamTarget[bossIndex] = INVALID_ENT_REFERENCE; - g_SlenderStopBurningTimer[bossIndex] = 0.0; - g_SlenderStopBleedingTimer[bossIndex] = 0.0; - g_SlenderIsBurning[bossIndex] = false; - g_SlenderIsMarked[bossIndex] = false; - g_NpcAddSpeed[bossIndex] = 0.0; - g_NpcAddAcceleration[bossIndex] = 0.0; - g_SlenderAutoChaseCount[bossIndex] = 0; - g_SlenderAutoChaseCooldown[bossIndex] = 0.0; - g_SlenderSoundTarget[bossIndex] = INVALID_ENT_REFERENCE; - g_SlenderSeeTarget[bossIndex] = INVALID_ENT_REFERENCE; - g_SlenderIsAutoChasingLoudPlayer[bossIndex] = false; - g_SlenderInDeathcam[bossIndex] = false; - - Spawn_Chaser(bossIndex); - - NPCChaserResetAnimationInfo(bossIndex, 0); - - SDKHook(npcEntity.iEnt, SDKHook_ThinkPost, SlenderSetNextThink); - - if (GetChaserProfileSpawnAnimationState(profile) && !SF_IsSlaughterRunMap()) - { - g_SlenderSpawning[bossIndex] = true; - NPCChaserUpdateBossAnimation(bossIndex, npcEntity.iEnt, STATE_IDLE, true); - g_SlenderEntityThink[bossIndex] = null; - g_SlenderSpawnTimer[bossIndex] = CreateTimer(g_SlenderAnimationDuration[bossIndex], Timer_SlenderSpawnTimer, EntIndexToEntRef(npcEntity.iEnt), TIMER_FLAG_NO_MAPCHANGE); - } - else - { - SDKHook(npcEntity.iEnt, SDKHook_Think, SlenderChaseBossProcessMovement); - g_SlenderSpawning[bossIndex] = false; - NPCChaserUpdateBossAnimation(bossIndex, npcEntity.iEnt, STATE_IDLE); - g_SlenderEntityThink[bossIndex] = CreateTimer(BOSS_THINKRATE, Timer_SlenderChaseBossThink, EntIndexToEntRef(npcEntity.iEnt), TIMER_REPEAT|TIMER_FLAG_NO_MAPCHANGE); - } - - for (int i = 0; i < 3; i++) - { - g_SlenderGoalPos[bossIndex][i] = 0.0; - g_SlenderTargetSoundTempPos[bossIndex][i] = 0.0; - g_SlenderTargetSoundMasterPos[bossIndex][i] = 0.0; - g_SlenderChaseDeathPosition[bossIndex][i] = 0.0; - } - - for (int i = 1; i <= MaxClients; i++) - { - g_SlenderLastFoundPlayer[bossIndex][i] = -1.0; - - for (int i2 = 0; i2 < 3; i2++) - { - g_SlenderLastFoundPlayerPos[bossIndex][i][i2] = 0.0; - } - } - - //(Experimental) - if (NPCGetHealthbarState(bossIndex)) - { - //The boss spawned for the 1st time, block now its teleportation ability to prevent healthbar conflict. - NPCSetFlags(bossIndex,NPCGetFlags(bossIndex)|SFF_NOTELEPORT); - UpdateHealthBar(bossIndex); - } - - //Stun Health - float maxHealth = NPCChaserGetStunInitialHealth(bossIndex); - float health = 0.0; - for(int client=1; client<=MaxClients; client++) - { - if (IsValidClient(client) && !g_PlayerEliminated[client] && IsPlayerAlive(client) && !DidClientEscape(client)) - { - int classToInt = view_as(TF2_GetPlayerClass(client)); - health = GetChaserProfileStunHealthPerClass(profile, classToInt); - if (health > 0.0) - { - maxHealth += health; - } - else - { - health = GetChaserProfileStunHealthPerPlayer(profile); - maxHealth += health; - } - if (SF_IsBoxingMap() && TF2_GetPlayerClass(client) == TFClass_Scout) - { - NPCSetAddSpeed(bossIndex, 10.0); - } - } - } - NPCChaserSetStunInitialHealth(bossIndex, maxHealth); - int entHealth = RoundToCeil(maxHealth + 1500000000.0); - npcEntity.SetProp(Prop_Data, "m_iHealth", entHealth); - npcEntity.SetProp(Prop_Data, "m_iMaxHealth", entHealth); - - entity = npcEntity;*/ } } - SF2BossProfileData data; - data = npc.GetProfileData(); - if (g_Enabled) { if (!data.IsPvEBoss && (npc.Flags & SFF_ATTACKWAITERS) == 0) @@ -3182,39 +1463,25 @@ void SpawnSlender(SF2NPC_BaseNPC npc, const float pos[3]) g_BossPathFollower[bossIndex] = PathFollower(_, TraceRayDontHitAnyEntity_Pathing, Path_FilterOnlyActors); } - g_BossPathFollower[bossIndex].SetMinLookAheadDistance(GetBossProfileNodeDistanceLookAhead(profile)); + g_BossPathFollower[bossIndex].SetMinLookAheadDistance(data.NodeDistanceLookAhead); - if (NPCGetModelSkinMax(bossIndex) > 0) + if (data.SkinMax > 0) { - int randomSkin = GetRandomInt(0, NPCGetModelSkinMax(bossIndex)); + int randomSkin = GetRandomInt(0, data.SkinMax); entity.SetProp(Prop_Send, "m_nSkin", randomSkin); } else { - if (GetBossProfileSkinDifficultyState(profile)) - { - entity.SetProp(Prop_Send, "m_nSkin", NPCGetModelSkinDifficulty(bossIndex, difficulty)); - } - else - { - entity.SetProp(Prop_Send, "m_nSkin", NPCGetModelSkin(bossIndex)); - } + entity.SetProp(Prop_Send, "m_nSkin", data.GetSkin(difficulty)); } - if (NPCGetModelBodyGroupsMax(bossIndex) > 0) + if (data.BodyMax > 0) { - int randomBody = GetRandomInt(0, NPCGetModelBodyGroupsMax(bossIndex)); + int randomBody = GetRandomInt(0, data.BodyMax); entity.SetProp(Prop_Send, "m_nBody", randomBody); } else { - if (GetBossProfileBodyGroupsDifficultyState(profile)) - { - entity.SetProp(Prop_Send, "m_nBody", NPCGetModelBodyGroupsDifficulty(bossIndex, difficulty)); - } - else - { - entity.SetProp(Prop_Send, "m_nBody", NPCGetModelBodyGroups(bossIndex)); - } + entity.SetProp(Prop_Send, "m_nBody", data.GetBodyGroup(difficulty)); } entity.AddFlag(FL_NPC); @@ -3233,27 +1500,28 @@ void SpawnSlender(SF2NPC_BaseNPC npc, const float pos[3]) g_SlenderEnt[bossIndex] = EntIndexToEntRef(entity.index); - if (data.EngineSound[0] != '\0') + char buffer[PLATFORM_MAX_PATH]; + data.GetConstantSound(buffer, sizeof(buffer)); + if (buffer[0] != '\0') { - EmitSoundToAll(data.EngineSound, entity.index, SNDCHAN_STATIC, data.EngineSoundLevel, - _, data.EngineSoundVolume); + EmitSoundToAll(buffer, entity.index, SNDCHAN_STATIC, data.ConstantSoundLevel, + _, data.ConstantSoundVolume); } - if (data.SpawnEffects != null) + if (data.GetSpawnEffects() != null) { - StringMapSnapshot snapshot = data.SpawnEffects.Snapshot(); - char key[64]; - snapshot.GetKey(GetRandomInt(0, snapshot.Length - 1), key, sizeof(key)); - ArrayList effects; - data.SpawnEffects.GetValue(key, effects); - SlenderSpawnEffects(effects, bossIndex, false); - delete snapshot; + ProfileObject obj = view_as(data.GetSpawnEffects().GetSection(GetRandomInt(0, data.GetSpawnEffects().Length - 1))); + obj = obj != null ? obj.GetSection("effects") : null; + if (obj != null) + { + SlenderSpawnEffects(view_as(obj), bossIndex, false); + } } int master = g_SlenderCopyMaster[bossIndex]; int flags = NPCGetFlags(bossIndex); - if (MAX_BOSSES > master >= 0 && NPCGetFakeCopyState(bossIndex, difficulty)) + if (MAX_BOSSES > master >= 0 && data.GetCopies().GetFakes(difficulty)) { if (!SF_SpecialRound(SPECIALROUND_DREAMFAKEBOSSES)) { @@ -3261,16 +1529,16 @@ void SpawnSlender(SF2NPC_BaseNPC npc, const float pos[3]) } } - ArrayList effects = data.EffectsArray; - SlenderSpawnEffects(effects, bossIndex); + SlenderSpawnEffects(view_as(data.GetSection("effects")), bossIndex); if (entity.IsValid()) { - SF2BossProfileSoundInfo soundInfo; - GetBossProfileSpawnLocalSounds(profile, soundInfo); - soundInfo.EmitSound(_, entity.index); + data.GetLocalSpawnSounds().EmitSound(_, entity.index); } + float teleportTime = GetRandomFloat(data.GetMinTeleportTime(difficulty), data.GetMaxTeleportTime(difficulty)); + g_SlenderNextTeleportTime[bossIndex] = GetGameTime() + teleportTime; + // Call our forward. Call_StartForward(g_OnBossSpawnFwd); Call_PushCell(bossIndex); @@ -3517,7 +1785,7 @@ Action Timer_BossMarked(Handle timer, any entref) bool SlenderUsesBlink(int bossIndex) { - if (NPCGetType(bossIndex) == SF2BossType_Statue) + if (SF2NPC_BaseNPC(bossIndex).GetProfileDataEx().Type == SF2BossType_Statue) { return true; } @@ -3528,7 +1796,7 @@ void SlenderPrintChatMessage(int bossIndex, int player) { if (g_Enabled && GetClientTeam(player) != TFTeam_Red) { - return; + //return; } if (bossIndex == -1) @@ -3545,13 +1813,14 @@ void SlenderPrintChatMessage(int bossIndex, int player) char profile[SF2_MAX_PROFILE_NAME_LENGTH]; NPCGetProfile(bossIndex, profile, sizeof(profile)); - ArrayList deathMessages = GetBossProfileChatDeathMessages(profile); - if (deathMessages == null) + BaseBossProfile profileData = GetBossProfile(profile); + ProfileObject deathMessages = profileData.GetSection("chat_message_upon_death"); + if (deathMessages == null || deathMessages.Size <= 0) { return; } - int difficultyIndex = g_NpcDeathMessageDifficultyIndexes[bossIndex]; + int difficultyIndex = profileData.GetInt("chat_message_upon_death_difficulty_indexes", 123456); char indexes[8], currentIndex[2]; FormatEx(indexes, sizeof(indexes), "%d", difficultyIndex); @@ -3567,12 +1836,13 @@ void SlenderPrintChatMessage(int bossIndex, int player) int currentAtkIndex = StringToInt(currentIndex); if (difficultyNumber == currentAtkIndex) //WHOA, legacy system actually won't be legacy. { - char buffer[PLATFORM_MAX_PATH], prefix[PLATFORM_MAX_PATH], name[SF2_MAX_NAME_LENGTH], time[PLATFORM_MAX_PATH]; + char buffer[PLATFORM_MAX_PATH], prefix[PLATFORM_MAX_PATH], name[SF2_MAX_NAME_LENGTH], time[PLATFORM_MAX_PATH], keyName[64]; int roundTime = RoundToNearest(g_RoundTimeMessage); - int randomMessage = GetRandomInt(0, deathMessages.Length - 1); - GetBossProfileChatDeathMessagePrefix(profile, prefix, sizeof(prefix)); - deathMessages.GetString(randomMessage, buffer, sizeof(buffer)); - NPCGetBossName(bossIndex, name, sizeof(name)); + int randomMessage = GetRandomInt(0, deathMessages.Size - 1); + profileData.GetString("chat_message_upon_death_prefix", prefix, sizeof(prefix), "[SF2]"); + deathMessages.GetKeyNameFromIndex(randomMessage, keyName, sizeof(keyName)); + deathMessages.GetString(keyName, buffer, sizeof(buffer)); + profileData.GetName(GetLocalGlobalDifficulty(bossIndex), name, sizeof(name)); FormatEx(time, sizeof(time), "%d", roundTime); char playerName[32], replacePlayer[64]; FormatEx(playerName, sizeof(playerName), "%N", player); @@ -3635,25 +1905,11 @@ void SlenderCastFootstepAnimEvent(int bossIndex, int event, int slender) char profile[SF2_MAX_PROFILE_NAME_LENGTH]; NPCGetProfile(bossIndex, profile, sizeof(profile)); + BaseBossProfile profileData = GetBossProfile(profile); - ArrayList arraySounds = GetBossProfileFootstepEventSounds(profile); - ArrayList arrayIndexes = GetBossProfileFootstepEventIndexes(profile); - - if (arraySounds == null || arrayIndexes == null) - { - return; - } - - int foundIndex = arrayIndexes.FindValue(event); - if (foundIndex == -1) - { - return; - } - - SF2BossProfileSoundInfo soundInfo; - arraySounds.GetArray(foundIndex, soundInfo, sizeof(soundInfo)); + ProfileSound soundInfo = profileData.GetFootstepEventSounds(event); - ArrayList soundPaths = soundInfo.Paths; + KeyMap_Array soundPaths = soundInfo.Paths; if (soundPaths == null) { return; @@ -3663,8 +1919,7 @@ void SlenderCastFootstepAnimEvent(int bossIndex, int event, int slender) GetEntPropVector(slender, Prop_Data, "m_vecAbsOrigin", myPos); soundInfo.EmitSound(_, slender); - SF2ChaserBossProfileData data; - data = SF2NPC_Chaser(bossIndex).GetProfileData(); + ChaserBossProfile data = SF2NPC_Chaser(bossIndex).GetProfileDataEx(); if (data.EarthquakeFootsteps) { UTIL_ScreenShake(myPos, data.EarthquakeFootstepAmplitude, @@ -3687,25 +1942,11 @@ void SlenderCastAnimEvent(int bossIndex, int event, int slender) char profile[SF2_MAX_PROFILE_NAME_LENGTH]; NPCGetProfile(bossIndex, profile, sizeof(profile)); + BaseBossProfile profileData = GetBossProfile(profile); - ArrayList arraySounds = GetBossProfileEventSounds(profile); - ArrayList arrayIndexes = GetBossProfileEventIndexes(profile); - - if (!arraySounds || arrayIndexes == null) - { - return; - } - - int foundIndex = arrayIndexes.FindValue(event); - if (foundIndex == -1) - { - return; - } - - SF2BossProfileSoundInfo soundInfo; - arraySounds.GetArray(foundIndex, soundInfo, sizeof(soundInfo)); + ProfileSound soundInfo = profileData.GetEventSounds(event); - ArrayList soundPaths = soundInfo.Paths; + KeyMap_Array soundPaths = soundInfo.Paths; if (soundPaths == null) { return; @@ -3754,6 +1995,7 @@ static Action Timer_SlenderTeleportThink(Handle timer, any id) } float gameTime = GetGameTime(); + BaseBossProfile data = controller.GetProfileDataEx(); int difficulty = GetLocalGlobalDifficulty(bossIndex); @@ -3772,16 +2014,16 @@ static Action Timer_SlenderTeleportThink(Handle timer, any id) } } - if (!NPCIsTeleportAllowed(bossIndex, difficulty) && (!bossEnt || bossEnt == INVALID_ENT_REFERENCE)) + if (!data.IsTeleportAllowed(difficulty) && (!bossEnt || bossEnt == INVALID_ENT_REFERENCE)) { return Plugin_Continue; } - if (controller.TeleportType == 2) + if (data.TeleportType == 2) { if (bossEnt && bossEnt != INVALID_ENT_REFERENCE) { - if (NPCGetType(bossIndex) == SF2BossType_Chaser) + if (data.Type == SF2BossType_Chaser) { SF2_ChaserEntity chaser = SF2_ChaserEntity(bossEnt); // Check to see if it's a good time to teleport away. @@ -3797,12 +2039,12 @@ static Action Timer_SlenderTeleportThink(Handle timer, any id) { if (gameTime >= g_SlenderTimeUntilKill[bossIndex]) { - g_SlenderTimeUntilKill[bossIndex] = gameTime + NPCGetIdleLifetime(bossIndex, difficulty); + g_SlenderTimeUntilKill[bossIndex] = gameTime + data.GetIdleLifeTime(difficulty); } return Plugin_Continue; } } - else if (NPCGetType(bossIndex) == SF2BossType_Statue) + else if (data.Type == SF2BossType_Statue) { if (g_SlenderStatueIdleLifeTime[bossIndex] > gameTime) { @@ -3819,14 +2061,14 @@ static Action Timer_SlenderTeleportThink(Handle timer, any id) { if (gameTime >= g_SlenderNextTeleportTime[bossIndex]) { - if (!NPCIsTeleportAllowed(bossIndex, difficulty) && bossEnt && bossEnt != INVALID_ENT_REFERENCE) + if (!data.IsTeleportAllowed(difficulty) && bossEnt && bossEnt != INVALID_ENT_REFERENCE) { controller.UnSpawn(); return Plugin_Continue; } - float teleportTime = GetRandomFloat(NPCGetTeleportTimeMin(bossIndex, difficulty), NPCGetTeleportTimeMax(bossIndex, difficulty)); + float teleportTime = GetRandomFloat(data.GetMinTeleportTime(difficulty), data.GetMaxTeleportTime(difficulty)); g_SlenderNextTeleportTime[bossIndex] = gameTime + teleportTime; - bool ignoreFuncNavPrefer = g_NpcHasIgnoreNavPrefer[bossIndex]; + bool ignoreFuncNavPrefer = data.IgnoreNavPrefer; int teleportTarget = EntRefToEntIndex(g_SlenderTeleportTarget[bossIndex]); @@ -3853,14 +2095,14 @@ static Action Timer_SlenderTeleportThink(Handle timer, any id) } // Let's start the persistency timer here, so that way we won't have infinite looping impossible to spawn bosses - float targetDuration = controller.GetTeleportPersistencyPeriod(difficulty); + float targetDuration = data.GetTeleportPersistencyPeriod(difficulty); float deviation = GetRandomFloat(0.92, 1.08); targetDuration = Pow(deviation * targetDuration, ((g_RoundDifficultyModifier) / 2.0)) + ((deviation * targetDuration) - 1.0); g_SlenderTeleportMaxTargetTime[controller.Index] = gameTime + targetDuration; - float teleportMinRange = g_SlenderTeleportMinRange[bossIndex][difficulty]; + float teleportMinRange = data.GetMinTeleportRange(difficulty); bool shouldBeBehindObstruction = false; - if (NPCGetTeleportType(bossIndex) == 2) + if (data.TeleportType == 2) { shouldBeBehindObstruction = true; } @@ -3875,7 +2117,7 @@ static Action Timer_SlenderTeleportThink(Handle timer, any id) CNavArea area = TheNavMesh.GetNearestNavArea(navPos, false, _, false, false); if (area != NULL_AREA) { - SurroundingAreasCollector collector = TheNavMesh.CollectSurroundingAreas(area, g_SlenderTeleportMaxRange[bossIndex][difficulty]); + SurroundingAreasCollector collector = TheNavMesh.CollectSurroundingAreas(area, data.GetMaxTeleportRange(difficulty)); int areaCount = collector.Count(); ArrayList areaArray = new ArrayList(1, areaCount); int validAreaCount = 0; @@ -3910,7 +2152,7 @@ static Action Timer_SlenderTeleportThink(Handle timer, any id) randomArea = areaArray.Get(randomCell); area = collector.Get(randomArea); area.GetCenter(spawnPos); - /*float cornerPosition[3]; // Will revisit later + float cornerPosition[3]; ArrayList corners = new ArrayList(); for (int i = 0; i < 4; i++) { @@ -3942,23 +2184,22 @@ static Action Timer_SlenderTeleportThink(Handle timer, any id) NavCornerType cornerB = corners.Get(GetRandomInt(0, corners.Length - 1)); area.GetCorner(cornerA, spawnPos); area.GetCorner(cornerB, cornerPosition); - LerpVectors(spawnPos, cornerPosition, spawnPos, GetRandomFloat(0.3, 0.7)); + LerpVectors(spawnPos, cornerPosition, spawnPos, GetRandomFloat(0.35, 0.65)); area.GetCorner(invert, cornerPosition); - LerpVectors(spawnPos, cornerPosition, spawnPos, GetRandomFloat(0.3, 0.7)); - delete corners;*/ + LerpVectors(spawnPos, cornerPosition, spawnPos, GetRandomFloat(0.35, 0.65)); + delete corners; float traceMins[3]; - traceMins[0] = g_SlenderDetectMins[bossIndex][0]; - traceMins[1] = g_SlenderDetectMins[bossIndex][1]; + data.GetHullMins(traceMins); traceMins[2] = 0.0; float traceMaxs[3]; - traceMaxs[0] = g_SlenderDetectMaxs[bossIndex][0]; - traceMaxs[1] = g_SlenderDetectMaxs[bossIndex][1]; - traceMaxs[2] = g_SlenderDetectMaxs[bossIndex][2]; + data.GetHullMaxs(traceMaxs); - TR_TraceHullFilter(spawnPos, spawnPos, traceMins, traceMaxs, MASK_NPCSOLID, TraceRayDontHitEntity); - if (TR_DidHit()) + Handle trace = TR_TraceHullFilterEx(spawnPos, spawnPos, traceMins, traceMaxs, MASK_NPCSOLID, TraceRayDontHitEntity); + bool hit = TR_DidHit(trace); + delete trace; + if (hit) { area = NULL_AREA; validAreaCount--; @@ -4006,7 +2247,7 @@ static Action Timer_SlenderTeleportThink(Handle timer, any id) } // Check visibility. - if (!g_SlenderTeleportIgnoreVis[bossIndex] && IsPointVisibleToAPlayer(spawnPos, !shouldBeBehindObstruction, false, _, true)) + if (!data.TeleportIgnoreVis && IsPointVisibleToAPlayer(spawnPos, !shouldBeBehindObstruction, false, _, true)) { area = NULL_AREA; validAreaCount--; @@ -4021,9 +2262,11 @@ static Action Timer_SlenderTeleportThink(Handle timer, any id) canSpawn = false; } - AddVectors(spawnPos, g_SlenderEyePosOffset[bossIndex], spawnPos); + float offset[3]; + data.GetEyes().GetOffsetPos(offset); + AddVectors(spawnPos, offset, spawnPos); - if (!g_SlenderTeleportIgnoreVis[bossIndex] && IsPointVisibleToAPlayer(spawnPos, !shouldBeBehindObstruction, false, _, true)) + if (!data.TeleportIgnoreVis && IsPointVisibleToAPlayer(spawnPos, !shouldBeBehindObstruction, false, _, true)) { area = NULL_AREA; validAreaCount--; @@ -4035,12 +2278,12 @@ static Action Timer_SlenderTeleportThink(Handle timer, any id) canSpawn = false; } - SubtractVectors(spawnPos, g_SlenderEyePosOffset[bossIndex], spawnPos); + SubtractVectors(spawnPos, offset, spawnPos); // Look for copies - if (controller.GetProfileData().CopiesInfo.Enabled[difficulty] && canSpawn) + if (controller.GetProfileDataEx().GetCopies().IsEnabled(difficulty) && canSpawn) { - float minDistBetweenBosses = GetBossProfileTeleportCopyDistance(profile, difficulty); + float minDistBetweenBosses = data.GetCopies().GetTeleportDistanceSpacing(difficulty); for (int bossCheck = 0; bossCheck < MAX_BOSSES; bossCheck++) { @@ -4109,20 +2352,19 @@ static Action Timer_SlenderTeleportThink(Handle timer, any id) if (PlayerCanSeeSlender(i, bossIndex, false)) { - if ((NPCGetDistanceFromEntity(bossIndex, i) <= SquareFloat(NPCGetJumpscareDistance(bossIndex, difficulty)) && GetGameTime() >= g_SlenderNextJumpScare[bossIndex]) || - (PlayerCanSeeSlender(i, bossIndex) && !GetBossProfileJumpscareNoSight(profile))) + if ((NPCGetDistanceFromEntity(bossIndex, i) <= SquareFloat(data.GetJumpscareDistance(difficulty)) && GetGameTime() >= g_SlenderNextJumpScare[bossIndex]) || + (PlayerCanSeeSlender(i, bossIndex) && !data.JumpscareNoSight)) { didJumpScare = true; - float jumpScareDuration = NPCGetJumpscareDuration(bossIndex, difficulty); - ClientDoJumpScare(i, bossIndex, jumpScareDuration); + ClientDoJumpScare(i, bossIndex, data.GetJumpscareDuration(difficulty)); } } } if (didJumpScare) { - g_SlenderNextJumpScare[bossIndex] = GetGameTime() + NPCGetJumpscareCooldown(bossIndex, difficulty); + g_SlenderNextJumpScare[bossIndex] = GetGameTime() + data.GetJumpscareCooldown(difficulty); } } break; @@ -4155,7 +2397,7 @@ static Action Timer_SlenderTeleportThink(Handle timer, any id) } else { - float teleportTime = GetRandomFloat(NPCGetTeleportTimeMin(bossIndex, difficulty), NPCGetTeleportTimeMax(bossIndex, difficulty)); + float teleportTime = GetRandomFloat(data.GetMinTeleportTime(difficulty), data.GetMaxTeleportTime(difficulty)); g_SlenderNextTeleportTime[bossIndex] = gameTime + teleportTime; } @@ -4184,30 +2426,31 @@ static Action Timer_SlenderRespawnThink(Handle timer, any id) float gameTime = GetGameTime(); int difficulty = GetLocalGlobalDifficulty(bossIndex); + BaseBossProfile data = controller.GetProfileDataEx(); bool cont = false; int bossEnt = controller.EntIndex; - if (bossEnt && bossEnt != INVALID_ENT_REFERENCE && controller.TeleportType == 2) + if (bossEnt && bossEnt != INVALID_ENT_REFERENCE && data.TeleportType == 2) { cont = true; } - if (!NPCIsTeleportAllowed(bossIndex, difficulty) && (!bossEnt || bossEnt == INVALID_ENT_REFERENCE)) + if (!data.IsTeleportAllowed(difficulty) && (!bossEnt || bossEnt == INVALID_ENT_REFERENCE)) { cont = true; } if (cont) { - float teleportTime = GetRandomFloat(NPCGetTeleportTimeMin(bossIndex, difficulty), NPCGetTeleportTimeMax(bossIndex, difficulty)); + float teleportTime = GetRandomFloat(data.GetMinTeleportTime(difficulty), data.GetMaxTeleportTime(difficulty)); g_SlenderNextTeleportTime[bossIndex] = gameTime + teleportTime; return Plugin_Continue; } if (gameTime >= g_SlenderNextTeleportTime[bossIndex]) { - float teleportTime = GetRandomFloat(NPCGetTeleportTimeMin(bossIndex, difficulty), NPCGetTeleportTimeMax(bossIndex, difficulty)); + float teleportTime = GetRandomFloat(data.GetMinTeleportTime(difficulty), data.GetMaxTeleportTime(difficulty)); g_SlenderNextTeleportTime[bossIndex] = gameTime + teleportTime; if (bossEnt && bossEnt != INVALID_ENT_REFERENCE) // For teleport type 0 @@ -4260,8 +2503,7 @@ bool SlenderMarkAsFake(int bossIndex) NPCSetFlags(bossIndex, bossFlags | SFF_MARKEDASFAKE); - SF2BossProfileData data; - data = NPCGetProfileData(bossIndex); + BaseBossProfile data = SF2NPC_BaseNPC(bossIndex).GetProfileDataEx(); g_SlenderFakeTimer[bossIndex] = CreateTimer(3.0, Timer_SlenderMarkedAsFake, bossIndex, TIMER_FLAG_NO_MAPCHANGE); @@ -4280,9 +2522,11 @@ bool SlenderMarkAsFake(int bossIndex) } SetEntProp(slender, Prop_Send, "m_usSolidFlags", flags); - if (data.EngineSound[0] != '\0') + char sound[PLATFORM_MAX_PATH]; + data.GetConstantSound(sound, sizeof(sound)); + if (sound[0] != '\0') { - StopSound(slender, SNDCHAN_STATIC, data.EngineSound); + StopSound(slender, SNDCHAN_STATIC, sound); } SetEntPropFloat(slender, Prop_Send, "m_flPlaybackRate", 0.0); @@ -4315,6 +2559,8 @@ int SpawnSlenderModel(int bossIndex, const float pos[3], bool deathCam = false) char buffer[PLATFORM_MAX_PATH], profile[SF2_MAX_PROFILE_NAME_LENGTH]; NPCGetProfile(bossIndex, profile, sizeof(profile)); + BaseBossProfile profileData = GetBossProfile(profile); + float playbackRate, cycle; int difficulty = GetLocalGlobalDifficulty(bossIndex); @@ -4324,13 +2570,13 @@ int SpawnSlenderModel(int bossIndex, const float pos[3], bool deathCam = false) LogError("Could not spawn boss model: model is invalid!"); return -1; } - float modelScale = NPCGetModelScale(bossIndex); + float modelScale = profileData.ModelScale; if (modelScale <= 0.0) { LogError("Could not spawn boss model: model scale is less than or equal to 0.0!"); return -1; } - int modelSkin = NPCGetModelSkin(bossIndex); + int modelSkin = profileData.GetSkin(difficulty); if (modelSkin < 0) { LogError("Could not spawn boss model: model skin is less than 0!"); @@ -4345,18 +2591,29 @@ int SpawnSlenderModel(int bossIndex, const float pos[3], bool deathCam = false) slenderModel.Teleport(pos, NULL_VECTOR, NULL_VECTOR); slenderModel.Spawn(); slenderModel.Activate(); - SF2BossProfileMasterAnimationsData animData; - GetBossProfileAnimationsData(profile, animData); + ProfileMasterAnimations animData = profileData.GetAnimations(); + ProfileAnimation animSection = null; if (!deathCam) { - animData.GetAnimation(g_SlenderAnimationsList[SF2BossAnimation_Idle], difficulty, buffer, sizeof(buffer), playbackRate, _, cycle); + animSection = animData.GetAnimation(g_SlenderAnimationsList[SF2BossAnimation_Idle]); + if (animSection != null) + { + animSection.GetAnimationName(difficulty, buffer, sizeof(buffer)); + playbackRate = animSection.GetAnimationPlaybackRate(difficulty); + cycle = animSection.GetAnimationCycle(difficulty); + } } else { - bool animationFound = animData.GetAnimation(g_SlenderAnimationsList[SF2BossAnimation_DeathCam], difficulty, buffer, sizeof(buffer), playbackRate, _, cycle); - if (!animationFound || strcmp(buffer,"") <= 0) + animSection = animData.GetAnimation(g_SlenderAnimationsList[SF2BossAnimation_DeathCam]); + if (animSection == null) + { + animData.GetAnimation(g_SlenderAnimationsList[SF2BossAnimation_Idle]); + } + if (animSection != null) { - animData.GetAnimation(g_SlenderAnimationsList[SF2BossAnimation_Idle], difficulty, buffer, sizeof(buffer), playbackRate, _, cycle); + playbackRate = animSection.GetAnimationPlaybackRate(difficulty); + cycle = animSection.GetAnimationCycle(difficulty); } } if (buffer[0] != '\0') @@ -4381,45 +2638,31 @@ int SpawnSlenderModel(int bossIndex, const float pos[3], bool deathCam = false) { slenderModel.SetPropFloat(Prop_Send, "m_flModelScale", modelScale); } - if (NPCGetModelSkinMax(bossIndex) > 0) + if (profileData.SkinMax > 0) { - int randomSkin = GetRandomInt(0, NPCGetModelSkinMax(bossIndex)); + int randomSkin = GetRandomInt(0, profileData.SkinMax); slenderModel.SetProp(Prop_Send, "m_nSkin", randomSkin); } else { - if (GetBossProfileSkinDifficultyState(profile)) - { - slenderModel.SetProp(Prop_Send, "m_nSkin", NPCGetModelSkinDifficulty(bossIndex, difficulty)); - } - else - { - slenderModel.SetProp(Prop_Send, "m_nSkin", modelSkin); - } + slenderModel.SetProp(Prop_Send, "m_nSkin", modelSkin); } - if (NPCGetModelBodyGroupsMax(bossIndex) > 0) + if (profileData.BodyMax > 0) { - int randomBody = GetRandomInt(0, NPCGetModelBodyGroupsMax(bossIndex)); + int randomBody = GetRandomInt(0, profileData.BodyMax); slenderModel.SetProp(Prop_Send, "m_nBody", randomBody); } else { - if (GetBossProfileBodyGroupsDifficultyState(profile)) - { - slenderModel.SetProp(Prop_Send, "m_nBody", NPCGetModelBodyGroupsDifficulty(bossIndex, difficulty)); - } - else - { - slenderModel.SetProp(Prop_Send, "m_nBody", NPCGetModelBodyGroups(bossIndex)); - } + slenderModel.SetProp(Prop_Send, "m_nBody", profileData.GetBodyGroup(difficulty)); } - slenderModel.SetProp(Prop_Send, "m_nBody", GetBossProfileBodyGroups(profile)); - // Create special effects. - slenderModel.SetRenderMode(view_as(g_SlenderRenderMode[bossIndex])); - slenderModel.SetRenderFx(view_as(g_SlenderRenderFX[bossIndex])); - slenderModel.SetRenderColor(g_SlenderRenderColor[bossIndex][0], g_SlenderRenderColor[bossIndex][1], g_SlenderRenderColor[bossIndex][2], g_SlenderRenderColor[bossIndex][3]); + slenderModel.SetRenderMode(profileData.GetRenderMode(difficulty)); + slenderModel.SetRenderFx(profileData.GetRenderFx(difficulty)); + int color[4]; + profileData.GetRenderColor(difficulty, color); + slenderModel.SetRenderColor(color[0], color[1], color[2], color[3]); g_NpcModelMaster[slenderModel.index] = bossIndex; slenderModel.Hook_HandleAnimEvent(CBaseAnimating_HandleAnimEvent); @@ -4509,7 +2752,7 @@ bool TraceRayBossVisibility(int entity, int mask, any data) return false; } } - if (IsValidEntity(entity) && NPCGetFromEntIndex(entity) != -1) + if (SF2_ChaserEntity(entity).IsValid() || SF2_StatueEntity(entity).IsValid()) { return false; } @@ -4523,7 +2766,7 @@ bool TraceRayDontHitCharacters(int entity, int mask, any data) return false; } - if (IsValidEntity(entity) && NPCGetFromEntIndex(entity) != -1) + if (SF2_ChaserEntity(entity).IsValid() || SF2_StatueEntity(entity).IsValid()) { return false; } @@ -4544,7 +2787,7 @@ bool TraceRayDontHitAnyEntity(int entity, int mask, any data) return false; } } - if (IsValidEntity(entity) && NPCGetFromEntIndex(entity) != -1) + if (SF2_ChaserEntity(entity).IsValid() || SF2_StatueEntity(entity).IsValid()) { return false; } @@ -4560,7 +2803,7 @@ bool TraceRayDontHitAnyEntity_Pathing(int entity, int contentsMask, int desiredc return false; } } - if (IsValidEntity(entity) && NPCGetFromEntIndex(entity) != -1) + if (SF2_ChaserEntity(entity).IsValid() || SF2_StatueEntity(entity).IsValid()) { return false; } @@ -4579,7 +2822,7 @@ bool TraceRayDontHitCharactersOrEntity(int entity, int mask, any data) return false; } - if (IsValidEntity(entity) && NPCGetFromEntIndex(entity) != -1) + if (SF2_ChaserEntity(entity).IsValid() || SF2_StatueEntity(entity).IsValid()) { return false; } @@ -4989,7 +3232,7 @@ static any Native_GetBossName(Handle plugin, int numParams) static any Native_GetBossType(Handle plugin, int numParams) { - return NPCGetType(GetNativeCell(1)); + return SF2NPC_BaseNPC(GetNativeCell(1)).GetProfileDataEx().Type; } static any Native_GetBossFlags(Handle plugin, int numParams) @@ -5047,7 +3290,7 @@ static any Native_GetBossMaster(Handle plugin, int numParams) static any Native_GetBossIdleLifetime(Handle plugin, int numParams) { - return NPCGetIdleLifetime(GetNativeCell(1), GetNativeCell(2)); + return SF2NPC_BaseNPC(GetNativeCell(1)).GetProfileDataEx().GetIdleLifeTime(GetNativeCell(2)); } static any Native_GetBossState(Handle plugin, int numParams) @@ -5099,7 +3342,7 @@ static any Native_GetBossEyePositionOffset(Handle plugin, int numParams) } float eyePos[3]; - boss.GetEyePositionOffset(eyePos); + boss.GetProfileDataEx().GetEyes().GetOffsetPos(eyePos); SetNativeArray(2, eyePos, 3); return 0; @@ -5191,24 +3434,14 @@ static any Native_GetProfileData(Handle plugin, int numParams) return ThrowNativeError(SP_ERROR_NATIVE, "Invalid boss index %d", controller.Index); } - SF2BossProfileData data; - data = controller.GetProfileData(); - SetNativeArray(2, data, sizeof(data)); - return 0; + return controller.GetProfileDataEx(); } static any Native_GetProfileDataEx(Handle plugin, int numParams) { char profile[SF2_MAX_PROFILE_NAME_LENGTH]; GetNativeString(1, profile, sizeof(profile)); - SF2BossProfileData data; - if (!g_BossProfileData.GetArray(profile, data, sizeof(data))) - { - return false; - } - - SetNativeArray(2, data, sizeof(data)); - return true; + return GetBossProfile(profile); } static any Native_SpawnBossEffects(Handle plugin, int numParams) diff --git a/addons/sourcemod/scripting/sf2/npc/entities/base/actions/deathcam.sp b/addons/sourcemod/scripting/sf2/npc/entities/base/actions/deathcam.sp index 8cbc11ee..b860e7b2 100644 --- a/addons/sourcemod/scripting/sf2/npc/entities/base/actions/deathcam.sp +++ b/addons/sourcemod/scripting/sf2/npc/entities/base/actions/deathcam.sp @@ -1,4 +1,5 @@ #pragma semicolon 1 +#pragma newdecls required static NextBotActionFactory g_Factory; @@ -9,6 +10,9 @@ methodmap SF2_DeathCamAction < NextBotAction if (g_Factory == null) { g_Factory = new NextBotActionFactory("SF2_Deathcam"); + g_Factory.BeginDataMapDesc() + .DefineFloatField("m_Duration") + .EndDataMapDesc(); g_Factory.SetCallback(NextBotActionCallbackType_InitialContainedAction, InitialContainedAction); g_Factory.SetCallback(NextBotActionCallbackType_Update, Update); g_Factory.SetCallback(NextBotActionCallbackType_OnEnd, OnEnd); @@ -16,6 +20,19 @@ methodmap SF2_DeathCamAction < NextBotAction } return view_as(g_Factory.Create()); } + + property float Duration + { + public get() + { + return this.GetDataFloat("m_Duration"); + } + + public set(float value) + { + this.SetDataFloat("m_Duration", value); + } + } } static NextBotAction InitialContainedAction(SF2_DeathCamAction action, SF2_BaseBoss actor) @@ -26,23 +43,35 @@ static NextBotAction InitialContainedAction(SF2_DeathCamAction action, SF2_BaseB actor.IsKillingSomeone = true; float duration = 0.0, rate = 1.0, cycle = 0.0; SF2NPC_BaseNPC controller = actor.Controller; - SF2BossProfileData data; - data = controller.GetProfileData(); - SF2BossProfileSoundInfo info; - info = data.LocalDeathCamSounds; - info.EmitSound(_, actor.index); + BaseBossProfile data = controller.GetProfileDataEx(); + data.GetLocalDeathCamSounds().EmitSound(_, actor.index, .difficulty = controller.Difficulty); int sequence = actor.SelectProfileAnimation(g_SlenderAnimationsList[SF2BossAnimation_DeathCam], rate, duration, cycle); if (sequence != -1) { + if (duration <= 0.0) + { + duration = actor.SequenceDuration(sequence) / rate; + duration *= (1.0 - cycle); + } + action.Duration = duration; return SF2_PlaySequenceAndWait(sequence, duration, rate, cycle); } return NULL_ACTION; } -static int Update(SF2_DeathCamAction action, SF2_BaseBoss actor, NextBotAction priorAction) +static int Update(SF2_DeathCamAction action, SF2_BaseBoss actor, float interval) { + if (actor.FullDeathCamDuration) + { + action.Duration -= interval; + if (action.Duration > 0.0) + { + return action.Continue(); + } + } + if (!actor.KillTarget.IsValid()) { return action.Done(); @@ -60,6 +89,7 @@ static int Update(SF2_DeathCamAction action, SF2_BaseBoss actor, NextBotAction p static void OnEnd(SF2_DeathCamAction action, SF2_BaseBoss actor) { actor.IsKillingSomeone = false; + actor.FullDeathCamDuration = false; } static void OnOtherKilled(SF2_DeathCamAction action, SF2_BaseBoss actor, CBaseCombatCharacter victim, CBaseEntity attacker, CBaseEntity inflictor, float damage, int damagetype) diff --git a/addons/sourcemod/scripting/sf2/npc/entities/base/actions/playsequenceandwait.sp b/addons/sourcemod/scripting/sf2/npc/entities/base/actions/playsequenceandwait.sp index f4b96d1c..040ded21 100644 --- a/addons/sourcemod/scripting/sf2/npc/entities/base/actions/playsequenceandwait.sp +++ b/addons/sourcemod/scripting/sf2/npc/entities/base/actions/playsequenceandwait.sp @@ -1,4 +1,5 @@ #pragma semicolon 1 +#pragma newdecls required static NextBotActionFactory g_Factory; @@ -162,4 +163,4 @@ static any Native_Create(Handle plugin, int numParams) float cycle = GetNativeCell(4); return SF2_PlaySequenceAndWait(sequence, duration, rate, cycle); -} +} \ No newline at end of file diff --git a/addons/sourcemod/scripting/sf2/npc/entities/base/actions/playsequenceandwait_ex.sp b/addons/sourcemod/scripting/sf2/npc/entities/base/actions/playsequenceandwait_ex.sp new file mode 100644 index 00000000..821985ef --- /dev/null +++ b/addons/sourcemod/scripting/sf2/npc/entities/base/actions/playsequenceandwait_ex.sp @@ -0,0 +1,102 @@ +#pragma semicolon 1 +#pragma newdecls required + +static NextBotActionFactory g_Factory; + +methodmap SF2_PlaySequenceAndWaitEx < NextBotAction +{ + public SF2_PlaySequenceAndWaitEx(char[] section) + { + if (g_Factory == null) + { + g_Factory = new NextBotActionFactory("SF2_PlaySequenceAndWaitEx"); + g_Factory.SetCallback(NextBotActionCallbackType_OnStart, OnStart); + g_Factory.SetCallback(NextBotActionCallbackType_Update, Update); + g_Factory.SetCallback(NextBotActionCallbackType_OnSuspend, OnSuspend); + g_Factory.SetCallback(NextBotActionCallbackType_OnEnd, OnEnd); + g_Factory.BeginDataMapDesc() + .DefineStringField("m_Section") + .DefineFloatField("m_EndTime") + .EndDataMapDesc(); + } + + SF2_PlaySequenceAndWaitEx action = view_as(g_Factory.Create()); + + action.SetSection(section); + + return action; + } + + public char[] GetSection() + { + char name[128]; + this.GetDataString("m_Section", name, sizeof(name)); + return name; + } + + public void SetSection(const char[] name) + { + this.SetDataString("m_Section", name); + } + + property float EndTime + { + public get() + { + return this.GetDataFloat("m_EndTime"); + } + + public set(float value) + { + this.SetDataFloat("m_EndTime", value); + } + } +} + +static int OnStart(SF2_PlaySequenceAndWaitEx action, SF2_BaseBoss actor, NextBotAction priorAction) +{ + float duration = 0.0, cycle = 0.0, rate = 1.0; + int sequence = -1; + if (!actor.ResetProfileAnimation(action.GetSection(), .sequence = sequence, .duration = duration, .rate = rate, .cycle = cycle)) + { + return action.Done("Invalid section"); + } + + if (duration <= 0.0) + { + duration = actor.SequenceDuration(sequence) / rate; + duration *= (1.0 - cycle); + } + + if (SF2_ChaserEntity(actor.index).IsValid()) + { + SF2_ChaserEntity(actor.index).GroundSpeedOverride = true; + } + + action.EndTime = GetGameTime() + duration; + + return action.Continue(); +} + +static int Update(SF2_PlaySequenceAndWaitEx action, SF2_BaseBoss actor, float interval) +{ + if (GetGameTime() > action.EndTime) + { + return action.Done(); + } + + return action.Continue(); +} + +static int OnSuspend(SF2_PlaySequenceAndWaitEx action, SF2_BaseBoss actor, NextBotAction interruptingAction) +{ + return action.Done(); +} + +static void OnEnd(SF2_PlaySequenceAndWaitEx action, SF2_ChaserEntity actor) +{ + if (SF2_ChaserEntity(actor.index).IsValid()) + { + SF2_ChaserEntity(actor.index).GroundSpeedOverride = false; + } +} \ No newline at end of file diff --git a/addons/sourcemod/scripting/sf2/npc/entities/base/entity.sp b/addons/sourcemod/scripting/sf2/npc/entities/base/entity.sp index 21f1e8a5..bc89fe99 100644 --- a/addons/sourcemod/scripting/sf2/npc/entities/base/entity.sp +++ b/addons/sourcemod/scripting/sf2/npc/entities/base/entity.sp @@ -1,6 +1,8 @@ #pragma semicolon 1 +#pragma newdecls required #include "actions/playsequenceandwait.sp" +#include "actions/playsequenceandwait_ex.sp" #include "actions/deathcam.sp" static CEntityFactory g_Factory; @@ -62,10 +64,13 @@ methodmap SF2_BaseBoss < CBaseCombatCharacter .DefineVectorField("m_ForceWanderPos") .DefineBoolField("m_IsKillingSomeone") .DefineEntityField("m_KillTarget") + .DefineBoolField("m_FullDeathCamDuration") .DefineBoolField("m_IsAttemptingToMove") .DefineIntField("m_EyeBoneIndex") .DefineBoolField("m_VelocityCancel") .DefineIntField("m_Teleporters") + .DefineBoolField("m_ShouldAnimationSyncWithGround") + .DefineBoolField("m_LockAnimations") .EndDataMapDesc(); g_Factory.Install(); @@ -125,9 +130,9 @@ methodmap SF2_BaseBoss < CBaseCombatCharacter } } - public SF2BossProfileData GetProfileData() + public BaseBossProfile GetProfileData() { - return this.Controller.GetProfileData(); + return this.Controller.GetProfileDataEx(); } property CBaseEntity Target @@ -430,6 +435,19 @@ methodmap SF2_BaseBoss < CBaseCombatCharacter } } + property bool FullDeathCamDuration + { + public get() + { + return this.GetProp(Prop_Data, "m_FullDeathCamDuration") != 0; + } + + public set(bool value) + { + this.SetProp(Prop_Data, "m_FullDeathCamDuration", value); + } + } + property bool IsAttemptingToMove { public get() @@ -482,6 +500,32 @@ methodmap SF2_BaseBoss < CBaseCombatCharacter } } + property bool ShouldAnimationSyncWithGround + { + public get() + { + return this.GetProp(Prop_Data, "m_ShouldAnimationSyncWithGround") != 0; + } + + public set(bool value) + { + this.SetProp(Prop_Data, "m_ShouldAnimationSyncWithGround", value); + } + } + + property bool LockAnimations + { + public get() + { + return this.GetProp(Prop_Data, "m_LockAnimations") != 0; + } + + public set(bool value) + { + this.SetProp(Prop_Data, "m_LockAnimations", value); + } + } + public void EyePosition(float buffer[3], const float defaultValue[3] = { 0.0, 0.0, 0.0 }) { this.Controller.GetEyePosition(buffer, defaultValue); @@ -514,12 +558,14 @@ methodmap SF2_BaseBoss < CBaseCombatCharacter CreateNative("SF2_BaseBossEntity.EyePosition", Native_EyePosition); CreateNative("SF2_BaseBossEntity.GetProfileName", Native_GetProfileName); CreateNative("SF2_BaseBossEntity.GetName", Native_GetName); + CreateNative("SF2_BaseBossEntity.LockAnimations.get", Native_GetLockAnimations); + CreateNative("SF2_BaseBossEntity.LockAnimations.set", Native_SetLockAnimations); CreateNative("SF2_BaseBossEntity.ProfileData", Native_GetProfileData); CreateNative("SF2_BaseBossEntity.ResetProfileAnimation", Native_ResetProfileAnimation); } public int SelectProfileAnimation(const char[] animType, float &rate = 1.0, float &duration = 0.0, float &cycle = 0.0, float &footstepInterval = 0.0, - int &index = 0, int preDefinedIndex = -1, const char[] preDefinedName = "", const char[] posture = NULL_STRING, bool &overrideLoop = false, bool &loop = false, char[] returnAnimation = "", int rtnAnimationLength = 0) + int &index = 0, int preDefinedIndex = -1, const char[] preDefinedName = "", const char[] posture = NULL_STRING, bool &overrideLoop = false, bool &loop = false, char[] returnAnimation = "", int rtnAnimationLength = 0, bool &sync = false) { SF2NPC_BaseNPC controller = this.Controller; int difficulty = controller.Difficulty; @@ -527,31 +573,42 @@ methodmap SF2_BaseBoss < CBaseCombatCharacter char animation[64]; bool found = false; + ProfileAnimation section = null; - if (controller.Type == SF2BossType_Chaser && !IsNullString(posture) && strcmp(posture, SF2_PROFILE_CHASER_DEFAULT_POSTURE) != 0) + if (controller.GetProfileDataEx().Type == SF2BossType_Chaser && !IsNullString(posture) && strcmp(posture, SF2_PROFILE_CHASER_DEFAULT_POSTURE) != 0) { - SF2NPC_Chaser chaserController = view_as(controller); - SF2ChaserBossProfileData data; - data = chaserController.GetProfileData(); - SF2ChaserBossProfilePostureInfo postureInfo; - found = data.GetPosture(posture, postureInfo); + ChaserBossProfile data = view_as(this.GetProfileData()); + found = data.GetPosture(posture) != null; if (found) { - found = postureInfo.Animations.GetAnimation(animType, difficulty, animation, sizeof(animation), - rate, duration, cycle, footstepInterval, index, preDefinedIndex, preDefinedName, overrideLoop, loop); - if (found) + section = data.GetPostureAnimations(posture).GetAnimation(animType, preDefinedIndex, preDefinedName, index); + if (section != null) { + section.GetAnimationName(difficulty, animation, sizeof(animation)); + section.GetAnimationName(difficulty, returnAnimation, rtnAnimationLength); + rate = section.GetAnimationPlaybackRate(difficulty); + duration = section.GetDuration(difficulty); + cycle = section.GetAnimationCycle(difficulty); + footstepInterval = section.GetFootstepInterval(difficulty); + overrideLoop = section.CanOverrideLoop(difficulty); + loop = section.GetLoopState(difficulty); + sync = section.ShouldSyncWithGround(difficulty); this.AnimationPlaybackRate = rate; - return LookupProfileAnimation(this.index, animation); } } } - found = controller.GetProfileData().AnimationData.GetAnimation(animType, difficulty, animation, sizeof(animation), - rate, duration, cycle, footstepInterval, index, preDefinedIndex, preDefinedName, overrideLoop, loop); + section = controller.GetProfileDataEx().GetAnimations().GetAnimation(animType, preDefinedIndex, preDefinedName, index); + + if (section == null) + { + return -1; + } + + section.GetAnimationName(difficulty, animation, sizeof(animation)); - if (!found) + if (animation[0] == '\0') { return -1; } @@ -559,6 +616,13 @@ methodmap SF2_BaseBoss < CBaseCombatCharacter int sequence = LookupProfileAnimation(this.index, animation); strcopy(returnAnimation, rtnAnimationLength, animation); + rate = section.GetAnimationPlaybackRate(difficulty); + duration = section.GetDuration(difficulty); + cycle = section.GetAnimationCycle(difficulty); + footstepInterval = section.GetFootstepInterval(difficulty); + overrideLoop = section.CanOverrideLoop(difficulty); + loop = section.GetLoopState(difficulty); + sync = section.ShouldSyncWithGround(difficulty); this.AnimationPlaybackRate = rate; @@ -572,31 +636,39 @@ methodmap SF2_BaseBoss < CBaseCombatCharacter char gesture[64]; - bool found = controller.GetProfileData().AnimationData.GetGesture(definedIndex, definedName, animType, difficulty, gesture, sizeof(gesture), - rate, cycle); + ProfileAnimation section = controller.GetProfileDataEx().GetAnimations().GetAnimation(animType, definedIndex, definedName); - if (!found) + if (section == null) + { + return -1; + } + + section.GetGestureName(difficulty, gesture, sizeof(gesture)); + + if (gesture[0] == '\0') { return -1; } int sequence = LookupProfileAnimation(this.index, gesture); + rate = section.GetGesturePlaybackRate(difficulty); + cycle = section.GetGestureCycle(difficulty); return sequence; } - public bool ResetProfileAnimation(const char[] animType, int preDefinedIndex = -1, const char[] preDefinedName = "", float &duration = 0.0, const char[] posture = NULL_STRING) + public bool ResetProfileAnimation(const char[] animType, int preDefinedIndex = -1, const char[] preDefinedName = "", float &duration = 0.0, const char[] posture = NULL_STRING, int& sequence = -1, float &rate = 1.0, float &cycle = 0.0) { if (this.Controller.IsValid() && (this.Controller.Flags & SFF_MARKEDASFAKE) != 0) { return false; } - float rate = 1.0, cycle = 0.0, footstepInterval = 0.0; - bool overrideLoop, loop; + float footstepInterval = 0.0; + bool overrideLoop, loop, sync; int index = 0; char animation[64]; - int sequence = this.SelectProfileAnimation(animType, rate, duration, cycle, footstepInterval, index, preDefinedIndex, preDefinedName, posture, overrideLoop, loop, animation, sizeof(animation)); + sequence = this.SelectProfileAnimation(animType, rate, duration, cycle, footstepInterval, index, preDefinedIndex, preDefinedName, posture, overrideLoop, loop, animation, sizeof(animation), sync); if (sequence == -1) { return false; @@ -617,14 +689,17 @@ methodmap SF2_BaseBoss < CBaseCombatCharacter Call_PushString(animation); Call_Finish(result); - if (result != Plugin_Handled) + if (result != Plugin_Handled && !this.LockAnimations) { bool isMovement = strcmp(animType, g_SlenderAnimationsList[SF2BossAnimation_Walk]) == 0 || strcmp(animType, g_SlenderAnimationsList[SF2BossAnimation_Run]) == 0; bool shouldLoop = isMovement || strcmp(animType, g_SlenderAnimationsList[SF2BossAnimation_Idle]) == 0; - this.ResetSequence(sequence); - this.SetPropFloat(Prop_Send, "m_flCycle", cycle); + if (sequence != this.GetProp(Prop_Send, "m_nSequence")) + { + this.ResetSequence(sequence); + this.SetPropFloat(Prop_Send, "m_flCycle", cycle); + } if (strcmp(animType, g_SlenderAnimationsList[SF2BossAnimation_Attack]) == 0 && this.MovementType == SF2NPCMoveType_Attack) { shouldLoop = true; @@ -638,8 +713,9 @@ methodmap SF2_BaseBoss < CBaseCombatCharacter this.SetProp(Prop_Data, "m_bSequenceLoops", shouldLoop); } this.SetPropFloat(Prop_Send, "m_flPlaybackRate", rate); - + this.LegacyFootstepTime = 0.0; this.LegacyFootstepInterval = footstepInterval; + this.ShouldAnimationSyncWithGround = sync; } return true; @@ -720,8 +796,7 @@ methodmap SF2_BaseBoss < CBaseCombatCharacter public void ProcessRainbowOutline() { SF2NPC_BaseNPC controller = this.Controller; - SF2BossProfileData data; - data = controller.GetProfileData(); + BaseBossProfile data = controller.GetProfileDataEx(); int color[4]; color[0] = RoundToNearest(Cosine((GetGameTime() * data.RainbowOutlineCycle) + controller.Index + 0) * 127.5 + 127.5); color[1] = RoundToNearest(Cosine((GetGameTime() * data.RainbowOutlineCycle) + controller.Index + 2) * 127.5 + 127.5); @@ -1011,12 +1086,37 @@ static any Native_GetName(Handle plugin, int numParams) } char buffer[SF2_MAX_PROFILE_NAME_LENGTH]; - controller.GetName(buffer, sizeof(buffer)); + controller.GetProfileDataEx().GetName(controller.Difficulty, buffer, sizeof(buffer)); SetNativeString(2, buffer, sizeof(buffer)); return 0; } +static any Native_GetLockAnimations(Handle plugin, int numParams) +{ + int entity = GetNativeCell(1); + if (!IsValidEntity(entity)) + { + return ThrowNativeError(SP_ERROR_NATIVE, "Invalid entity index %d", entity); + } + + SF2_BaseBoss bossEntity = SF2_BaseBoss(entity); + return bossEntity.LockAnimations; +} + +static any Native_SetLockAnimations(Handle plugin, int numParams) +{ + int entity = GetNativeCell(1); + if (!IsValidEntity(entity)) + { + return ThrowNativeError(SP_ERROR_NATIVE, "Invalid entity index %d", entity); + } + + SF2_BaseBoss bossEntity = SF2_BaseBoss(entity); + bossEntity.LockAnimations = GetNativeCell(2); + return 0; +} + static any Native_GetProfileData(Handle plugin, int numParams) { int entity = GetNativeCell(1); @@ -1032,10 +1132,7 @@ static any Native_GetProfileData(Handle plugin, int numParams) return 0; } - SF2BossProfileData data; - data = bossEntity.Controller.GetProfileData(); - SetNativeArray(2, data, sizeof(data)); - return 0; + return bossEntity.Controller.GetProfileDataEx(); } static any Native_ResetProfileAnimation(Handle plugin, int numParams) diff --git a/addons/sourcemod/scripting/sf2/npc/entities/chaser/actions/alert.sp b/addons/sourcemod/scripting/sf2/npc/entities/chaser/actions/alert.sp index c16faa3d..7639d0af 100644 --- a/addons/sourcemod/scripting/sf2/npc/entities/chaser/actions/alert.sp +++ b/addons/sourcemod/scripting/sf2/npc/entities/chaser/actions/alert.sp @@ -1,4 +1,5 @@ #pragma semicolon 1 +#pragma newdecls required static NextBotActionFactory g_Factory; @@ -172,8 +173,8 @@ methodmap SF2_ChaserAlertAction < NextBotAction static int OnStart(SF2_ChaserAlertAction action, SF2_ChaserEntity actor, NextBotAction priorAction) { SF2NPC_Chaser controller = actor.Controller; - SF2ChaserBossProfileData data; - data = controller.GetProfileData(); + ChaserBossProfile data = controller.GetProfileDataEx(); + ChaserBossProfileAlertData alertData = data.GetAlertBehavior(); int difficulty = controller.Difficulty; float gameTime = GetGameTime(); if (!action.IsRunning) @@ -185,11 +186,11 @@ static int OnStart(SF2_ChaserAlertAction action, SF2_ChaserEntity actor, NextBot actor.MovementType = SF2NPCMoveType_Run; } - action.EndTime = gameTime + data.AlertData.Duration[difficulty]; - action.TimeUntilChase = gameTime + data.AlertData.GraceTime[difficulty]; + action.EndTime = gameTime + alertData.GetDuration(difficulty); + action.TimeUntilChase = gameTime + alertData.GetGraceTime(difficulty); action.InitialState = true; - if (data.AlertOnAlertInfo.OnChangeState[difficulty]) + if (alertData.GetAlertSyncData().IsEnabled(difficulty) && alertData.GetAlertSyncData().ShouldStartOnStateChange(difficulty)) { actor.ForceAlertOtherBosses(); } @@ -221,12 +222,10 @@ static int Update(SF2_ChaserAlertAction action, SF2_ChaserEntity actor, float in return action.Continue(); } - SF2ChaserBossProfileData data; - data = controller.GetProfileData(); - SF2BossProfileData originalData; - originalData = view_as(controller).GetProfileData(); + ChaserBossProfile data = controller.GetProfileDataEx(); + ChaserBossProfileAlertData alertData = data.GetAlertBehavior(); - if (!originalData.IsPvEBoss && IsBeatBoxBeating(2)) + if (!data.IsPvEBoss && IsBeatBoxBeating(2)) { return action.SuspendFor(SF2_ChaserBeatBoxFreezeAction(actor.IsAttemptingToMove)); } @@ -239,7 +238,7 @@ static int Update(SF2_ChaserAlertAction action, SF2_ChaserEntity actor, float in PathFollower path = controller.Path; - if (data.ChaseOnLookData.Enabled[difficulty] && controller.ChaseOnLookTargets.Length > 0) + if (data.GetChaseOnLookData().IsEnabled(difficulty) && controller.ChaseOnLookTargets.Length > 0) { SF2_BasePlayer lookTarget = controller.ChaseOnLookTargets.Get(0); if (lookTarget.IsValid && !lookTarget.IsEliminated && lookTarget.IsAlive && !lookTarget.IsInGhostMode && !lookTarget.HasEscaped) @@ -265,7 +264,7 @@ static int Update(SF2_ChaserAlertAction action, SF2_ChaserEntity actor, float in } if (actor.FollowedCompanionAlert && actor.Controller.IsValid()) { - actor.FollowCooldownAlert = GetGameTime() + data.AlertOnAlertInfo.FollowCooldown[difficulty]; + actor.FollowCooldownAlert = GetGameTime() + alertData.GetAlertSyncData().GetFollowCooldown(difficulty); actor.FollowedCompanionAlert = false; } actor.AlertWithBoss = false; @@ -317,7 +316,7 @@ static int Update(SF2_ChaserAlertAction action, SF2_ChaserEntity actor, float in float pos[3]; actor.GetAlertTriggerPosition(alertTarget, pos); - UpdateAlertPosition(action, actor, pos, data.AlertData.RunOnSuspect[difficulty]); + UpdateAlertPosition(action, actor, pos, alertData.ShouldRunOnSuspect(difficulty)); } } else if ((interruptConditions & COND_ALERT_TRIGGER_POS) != 0 || actor.QueueForAlertState) @@ -325,7 +324,7 @@ static int Update(SF2_ChaserAlertAction action, SF2_ChaserEntity actor, float in float pos[3]; actor.GetAlertTriggerPositionEx(pos); - UpdateAlertPosition(action, actor, pos, data.AlertData.RunOnSuspect[difficulty]); + UpdateAlertPosition(action, actor, pos, alertData.ShouldRunOnSuspect(difficulty)); actor.QueueForAlertState = false; } @@ -334,10 +333,10 @@ static int Update(SF2_ChaserAlertAction action, SF2_ChaserEntity actor, float in float pos[3]; actor.GetForceWanderPosition(pos); - UpdateAlertPosition(action, actor, pos, data.AlertData.RunOnWander[difficulty]); + UpdateAlertPosition(action, actor, pos, alertData.ShouldRunOnWander(difficulty)); } - bool isAbleToWander = action.HasReachedAlertPosition && data.CanWander[difficulty]; + bool isAbleToWander = action.HasReachedAlertPosition && data.CanWander(difficulty); if (controller.HasAttribute(SF2Attribute_BlockWalkSpeedUnderDifficulty)) { int value = RoundToNearest(controller.GetAttributeValue(SF2Attribute_BlockWalkSpeedUnderDifficulty)); @@ -351,13 +350,13 @@ static int Update(SF2_ChaserAlertAction action, SF2_ChaserEntity actor, float in { if (gameTime >= action.NextWanderTime) { - float min = data.WanderTimeMin[difficulty]; - float max = data.WanderTimeMax[difficulty]; + float min = data.GetWanderMinTime(difficulty); + float max = data.GetWanderMaxTime(difficulty); action.NextWanderTime = gameTime + GetRandomFloat(min, max); - float rangeMin = data.WanderRangeMin[difficulty]; - float rangeMax = data.WanderRangeMax[difficulty]; + float rangeMin = data.GetWanderMinRange(difficulty); + float rangeMax = data.GetWanderMaxRange(difficulty); float range = GetRandomFloat(rangeMin, rangeMax); CNavArea area = actor.GetLastKnownArea(); @@ -388,7 +387,7 @@ static int Update(SF2_ChaserAlertAction action, SF2_ChaserEntity actor, float in { wanderArea.GetCenter(wanderPos); - UpdateAlertPosition(action, actor, wanderPos, data.AlertData.RunOnWander[difficulty]); + UpdateAlertPosition(action, actor, wanderPos, alertData.ShouldRunOnWander(difficulty)); } } @@ -414,7 +413,7 @@ static int Update(SF2_ChaserAlertAction action, SF2_ChaserEntity actor, float in } else { - if (data.AlertData.TurnEnabled[difficulty]) + if (alertData.IsTurnEnabled(difficulty)) { if (!action.InitialState) { @@ -424,22 +423,22 @@ static int Update(SF2_ChaserAlertAction action, SF2_ChaserEntity actor, float in } if (action.NextTurnTime <= 0.0) { - action.NextTurnTime = gameTime + GetRandomFloat(data.AlertData.TurnMinTime[difficulty], data.AlertData.TurnMaxTime[difficulty]); + action.NextTurnTime = gameTime + GetRandomFloat(alertData.GetTurnMinCooldown(difficulty), alertData.GetTurnMaxCooldown(difficulty)); } } } - if (data.AlertData.TurnEnabled[difficulty] && action.NextTurnTime > 0.0 && action.NextTurnTime <= gameTime) + if (action.NextTurnTime > 0.0 && action.NextTurnTime <= gameTime && alertData.IsTurnEnabled(difficulty)) { float myPos[3], myAng[3]; actor.GetAbsOrigin(myPos); actor.GetAbsAngles(myAng); - myAng[1] += GetRandomFloat(-data.AlertData.TurnAngle[difficulty], data.AlertData.TurnAngle[difficulty]); + myAng[1] += GetRandomFloat(-alertData.GetTurnAngle(difficulty), alertData.GetTurnAngle(difficulty)); float lookAt[3]; lookAt[0] = 50.0; VectorTransform(lookAt, myPos, myAng, lookAt); action.SetLookPosition(lookAt); - action.NextTurnTime = gameTime + GetRandomFloat(data.AlertData.TurnMinTime[difficulty], data.AlertData.TurnMaxTime[difficulty]); + action.NextTurnTime = gameTime + GetRandomFloat(alertData.GetTurnMinCooldown(difficulty), alertData.GetTurnMaxCooldown(difficulty)); action.InitialState = false; } @@ -514,13 +513,13 @@ static void OnResume(SF2_ChaserAlertAction action, SF2_ChaserEntity actor, NextB static void OnReachedAlertPosition(SF2_ChaserAlertAction action, SF2_ChaserEntity actor) { SF2NPC_Chaser controller = actor.Controller; - SF2ChaserBossProfileData data; - data = controller.GetProfileData(); + ChaserBossProfile data = controller.GetProfileDataEx(); + ChaserBossProfileAlertData alertData = data.GetAlertBehavior(); int difficulty = controller.Difficulty; float gameTime = GetGameTime(); - action.NextTurnTime = gameTime + GetRandomFloat(data.AlertData.TurnMinTime[difficulty], data.AlertData.TurnMaxTime[difficulty]); - action.NextWanderTime = gameTime + GetRandomFloat(data.WanderEnterTimeMin[difficulty], data.WanderEnterTimeMax[difficulty]); + action.NextTurnTime = gameTime + GetRandomFloat(alertData.GetTurnMinCooldown(difficulty), alertData.GetTurnMaxCooldown(difficulty)); + action.NextWanderTime = gameTime + GetRandomFloat(data.GetWanderEnterMinTime(difficulty), data.GetWanderEnterMaxTime(difficulty)); } static void OnMoveToSuccess(SF2_ChaserAlertAction action, SF2_ChaserEntity actor, Path path) diff --git a/addons/sourcemod/scripting/sf2/npc/entities/chaser/actions/attack.sp b/addons/sourcemod/scripting/sf2/npc/entities/chaser/actions/attack.sp index 0b5e620f..1476ba3a 100644 --- a/addons/sourcemod/scripting/sf2/npc/entities/chaser/actions/attack.sp +++ b/addons/sourcemod/scripting/sf2/npc/entities/chaser/actions/attack.sp @@ -1,5 +1,1195 @@ #pragma semicolon 1 -// This manages the end time and getting a attack +#pragma newdecls required + +methodmap ChaserBossProfileBaseAttack < ProfileObject +{ + property int Type + { + public get() + { + return this.GetInt("type", view_as(SF2BossAttackType_Melee)); + } + } + + property int Index + { + public get() + { + int val = 0; + this.GetValue("__index", val); + return val; + } + + public set(int value) + { + this.SetValue("__index", value); + } + } + + public bool CanUseWithPosture(const char[] posture) + { + bool ret = true; + + ProfileObject arr = this.GetSection("use_with_posture"); + if (arr != null) + { + ret = false; + + if (posture[0] == '\0') + { + ret = arr.ContainsString(SF2_PROFILE_CHASER_DEFAULT_POSTURE); + } + else + { + ret = arr.ContainsString(posture); + } + } + + return ret; + } + + property bool CanUseAgainstProps + { + public get() + { + bool def = false; + def = this.GetBool("props", def); + def = this.GetBool("attack_props", def); + return def; + } + } + + property int UseOnDifficulty + { + public get() + { + int def = 0; + def = this.GetInt("use_on_difficulty", def); + def = this.GetInt("attack_use_on_difficulty", def); + return def; + } + } + + property int BlockOnDifficulty + { + public get() + { + int def = 6; + def = this.GetInt("block_on_difficulty", def); + def = this.GetInt("attack_block_on_difficulty", def); + return def; + } + } + + public float CanUseOnHealth(int difficulty) + { + float def = -1.0; + def = this.GetDifficultyFloat("use_on_health", difficulty, def); + def = this.GetDifficultyFloat("attack_use_on_health", difficulty, def); + return def; + } + + public float CanBlockOnHealth(int difficulty) + { + float def = -1.0; + def = this.GetDifficultyFloat("block_on_health", difficulty, def); + def = this.GetDifficultyFloat("attack_block_on_health", difficulty, def); + return def; + } + + public float GetDamage(int difficulty) + { + float defaultValue; + + switch (this.Type) + { + case SF2BossAttackType_Melee: + { + defaultValue = 50.0; + } + + case SF2BossAttackType_Ranged: + { + defaultValue = 8.0; + defaultValue = this.GetDifficultyFloat("bullet_damage", difficulty, defaultValue); + defaultValue = this.GetDifficultyFloat("attack_bullet_damage", difficulty, defaultValue); + } + + case SF2BossAttackType_Projectile: + { + defaultValue = 60.0; + defaultValue = this.GetDifficultyFloat("projectile_damage", difficulty, defaultValue); + defaultValue = this.GetDifficultyFloat("attack_projectile_damage", difficulty, defaultValue); + } + + case SF2BossAttackType_LaserBeam: + { + defaultValue = 25.0; + defaultValue = this.GetDifficultyFloat("laser_damage", difficulty, defaultValue); + defaultValue = this.GetDifficultyFloat("attack_laser_damage", difficulty, defaultValue); + } + + case SF2BossAttackType_ExplosiveDance: + { + defaultValue = 25.0; + } + + case SF2BossAttackType_Tongue: + { + defaultValue = 10.0; + } + } + + defaultValue = this.GetDifficultyFloat("damage", difficulty, defaultValue); + defaultValue = this.GetDifficultyFloat("attack_damage", difficulty, defaultValue); + + return defaultValue; + } + + public float GetDamagePercent(int difficulty) + { + return this.GetDifficultyFloat("damage_percent", difficulty); + } + + public float GetDamageFallOff(int difficulty) + { + float def = 1.0; + ProfileObject obj = this.GetSection("fall_off"); + if (obj != null) + { + return obj.GetDifficultyFloat("percent", difficulty, def); + } + return def; + } + + public float GetDamageFallOffRange(int difficulty) + { + float def = 1024.0; + ProfileObject obj = this.GetSection("fall_off"); + if (obj != null) + { + return obj.GetDifficultyFloat("range", difficulty, def); + } + return def; + } + + public float GetDamageRampUp(int difficulty) + { + float def = 1.0; + ProfileObject obj = this.GetSection("ramp_up"); + if (obj != null) + { + return obj.GetDifficultyFloat("percent", difficulty, def); + } + return def; + } + + public float GetDamageRampUpRange(int difficulty) + { + float def = 512.0; + ProfileObject obj = this.GetSection("ramp_up"); + if (obj != null) + { + return obj.GetDifficultyFloat("range", difficulty, def); + } + return def; + } + + public int GetDamageType(int difficulty) + { + int defaultValue; + + switch (this.Type) + { + case SF2BossAttackType_Melee: + { + defaultValue = DMG_CLUB; + } + + case SF2BossAttackType_Ranged: + { + defaultValue = DMG_BULLET; + } + + case SF2BossAttackType_Projectile, SF2BossAttackType_ExplosiveDance: + { + defaultValue = DMG_BLAST; + } + + case SF2BossAttackType_LaserBeam: + { + defaultValue = DMG_SHOCK | DMG_ALWAYSGIB; + } + + case SF2BossAttackType_Tongue: + { + defaultValue = DMG_BULLET | DMG_PREVENT_PHYSICS_FORCE; + } + } + defaultValue = this.GetDifficultyInt("damagetype", difficulty, defaultValue); + defaultValue = this.GetDifficultyInt("attack_damagetype", difficulty, defaultValue); + + return defaultValue; + } + + public float GetDelay(int difficulty) + { + float def = 0.0; + def = this.GetDifficultyFloat("delay", difficulty, def); + def = this.GetDifficultyFloat("attack_delay", difficulty, def); + return def; + } + + public float GetDuration(int difficulty) + { + float value = this.GetDifficultyFloat("duration", difficulty); + float endAfter = this.GetDifficultyFloat("endafter", difficulty); + value = this.GetDifficultyFloat("attack_duration", difficulty, value); + endAfter = this.GetDifficultyFloat("attack_endafter", difficulty, endAfter); + + if (value <= 0.0) + { + value = this.GetDelay(difficulty) + endAfter; + } + + return value; + } + + public float GetBeginRange(int difficulty) + { + float def = 80.0; + def = this.GetDifficultyFloat("begin_range", difficulty, def); + def = this.GetDifficultyFloat("attack_begin_range", difficulty, def); + return def; + } + + public float GetBeginFOV(int difficulty) + { + float def = this.GetFOV(difficulty); + def = this.GetDifficultyFloat("begin_fov", difficulty, def); + def = this.GetDifficultyFloat("attack_begin_fov", difficulty, def); + return def; + } + + public float GetFOV(int difficulty) + { + float def = 45.0; + def = this.GetDifficultyFloat("spread", difficulty, def); + def = this.GetDifficultyFloat("attack_spread", difficulty, def); + return def; + } + + public float GetRange(int difficulty) + { + float def = 180.0; + def = this.GetDifficultyFloat("range", difficulty, def); + def = this.GetDifficultyFloat("attack_range", difficulty, def); + return def; + } + + public float GetCooldown(int difficulty) + { + float def = 0.0; + def = this.GetDifficultyFloat("cooldown", difficulty, def); + def = this.GetDifficultyFloat("attack_cooldown", difficulty, def); + return def; + } + + public bool GetDisappearAfterAttack(int difficulty) + { + bool def = false; + def = this.GetDifficultyBool("disappear", difficulty, def); + def = this.GetDifficultyBool("attack_disappear_upon_damaging", difficulty, def); + return def; + } + + public bool GetDisappearAfterHit(int difficulty) + { + return this.GetDifficultyBool("disappear_upon_damaging", difficulty); + } + + public void GetViewPunchAngles(int difficulty, float viewPunch[3]) + { + this.GetDifficultyVector("punchvel", difficulty, viewPunch, viewPunch); + this.GetDifficultyVector("attack_punchvel", difficulty, viewPunch, viewPunch); + } + + public float GetDamageForce(int difficulty) + { + float def = 0.0; + def = this.GetDifficultyFloat("damageforce", difficulty); + def = this.GetDifficultyFloat("attack_damageforce", difficulty); + return def; + } + + public int GetEventNumber(int difficulty) + { + return this.GetDifficultyInt("event", difficulty, -1); + } + + public bool GetStartThroughWalls(int difficulty) + { + return this.GetDifficultyBool("start_through_walls", difficulty); + } + + public bool GetHitThroughWalls(int difficulty) + { + return this.GetDifficultyBool("hit_through_walls", difficulty); + } + + public int GetRepeatState(int difficulty) + { + int def = 0; + def = this.GetDifficultyInt("repeat", difficulty, def); + def = this.GetDifficultyInt("attack_repeat", difficulty, def); + return def; + } + + public float GetRepeatTimer(int difficulty, int index) + { + float def = -1.0; + char key[64]; + FormatEx(key, sizeof(key), "repeat_%i_delay", index); + def = this.GetDifficultyFloat(key, difficulty, def); + FormatEx(key, sizeof(key), "attack_repeat_%i_delay", index); + def = this.GetDifficultyFloat(key, difficulty, def); + return def; + } + + public float GetRunSpeed(int difficulty) + { + float def = 0.0; + def = this.GetDifficultyFloat("run_speed", difficulty, def); + def = this.GetDifficultyFloat("attack_run_speed", difficulty, def); + return def; + } + + public float GetAcceleration(int difficulty) + { + return this.GetDifficultyFloat("run_acceleration", difficulty, 4000.0); + } + + public float GetRunDuration(int difficulty) + { + float def = 0.0; + def = this.GetDifficultyFloat("run_duration", difficulty, def); + def = this.GetDifficultyFloat("attack_run_duration", difficulty, def); + return def; + } + + public float GetRunDelay(int difficulty) + { + float def = 0.0; + def = this.GetDifficultyFloat("run_delay", difficulty, def); + def = this.GetDifficultyFloat("attack_run_delay", difficulty, def); + return def; + } + + public bool GetGroundSpeedOverride(int difficulty) + { + return this.GetDifficultyBool("run_ground_speed", difficulty); + } + + public float GetMinCancelDistance(int difficulty) + { + return this.GetDifficultyFloat("cancel_distance_min", difficulty, -1.0); + } + + public float GetMaxCancelDistance(int difficulty) + { + return this.GetDifficultyFloat("cancel_distance_max", difficulty, -1.0); + } + + public bool GetCancelLOS(int difficulty) + { + return this.GetDifficultyBool("cancel_los", difficulty, false); + } + + property bool DeathCamLowHealth + { + public get() + { + bool def = false; + def = this.GetBool("deathcam_on_low_health", def); + def = this.GetBool("attack_deathcam_on_low_health", def); + return def; + } + } + + public bool IsImmuneToDamage(int difficulty) + { + return this.GetDifficultyBool("invulnerable", difficulty, false); + } + + public bool ShouldNotAlwaysLook(int difficulty) + { + bool def = false; + def = this.GetDifficultyBool("ignore_always_looking", difficulty, def); + def = this.GetDifficultyBool("attack_ignore_always_looking", difficulty, def); + return def; + } + + public bool ShouldNotInterruptChaseInitial(int difficulty) + { + return this.GetDifficultyBool("dont_interrupt_chaseinitial", difficulty, false); + } + + public ProfileSound GetBeginSounds() + { + ProfileObject obj = this.GetSection("sounds"); + if (obj == null) + { + return null; + } + + ProfileSound sound = view_as(obj.GetSection("begin")); + if (sound == null) + { + return null; + } + + return sound; + } + + public ProfileSound GetStartSounds() + { + ProfileObject obj = this.GetSection("sounds"); + if (obj == null) + { + return null; + } + + ProfileSound sound = view_as(obj.GetSection("attack")); + if (sound == null) + { + return null; + } + + return sound; + } + + public ProfileSound GetHitSounds() + { + ProfileObject obj = this.GetSection("sounds"); + if (obj == null) + { + return null; + } + + ProfileSound sound = view_as(obj.GetSection("hit")); + if (sound == null) + { + return null; + } + + return sound; + } + + public ProfileSound GetMissSounds() + { + ProfileObject obj = this.GetSection("sounds"); + if (obj == null) + { + return null; + } + + ProfileSound sound = view_as(obj.GetSection("miss")); + if (sound == null) + { + return null; + } + + return sound; + } + + public ProfileSound GetLoopSounds() + { + ProfileObject obj = this.GetSection("sounds"); + if (obj == null) + { + return null; + } + + ProfileSound sound = view_as(obj.GetSection("loop")); + if (sound == null) + { + return null; + } + + return sound; + } + + public ProfileSound GetEndSounds() + { + ProfileObject obj = this.GetSection("sounds"); + if (obj == null) + { + return null; + } + + ProfileSound sound = view_as(obj.GetSection("end")); + if (sound == null) + { + return null; + } + + return sound; + } + + public ProfileMasterAnimations GetAnimations() + { + return view_as(this.GetSection("animations")); + } + + public void GetWeaponString(char[] buffer, int bufferSize) + { + this.GetString("weapontype", buffer, bufferSize, buffer); + this.GetString("attack_weapontype", buffer, bufferSize, buffer); + } + + property int WeaponInt + { + public get() + { + int def = 0; + def = this.GetInt("weapontypeint", def); + def = this.GetInt("attack_weapontypeint", def); + return def; + } + } + + public ProfileEffectMaster GetStartEffects() + { + ProfileObject obj = this.GetSection("effects"); + obj = obj != null ? obj.GetSection("start") : null; + if (obj != null) + { + return view_as(obj); + } + + return null; + } + + public ProfileEffectMaster GetHitEffects() + { + ProfileObject obj = this.GetSection("effects"); + obj = obj != null ? obj.GetSection("hit") : null; + if (obj != null) + { + return view_as(obj); + } + + return null; + } + + public ProfileEffectMaster GetMissEffects() + { + ProfileObject obj = this.GetSection("effects"); + obj = obj != null ? obj.GetSection("miss") : null; + if (obj != null) + { + return view_as(obj); + } + + return null; + } + + public ProfileEffectMaster GetOnKillEffects() + { + ProfileObject obj = this.GetSection("effects"); + obj = obj != null ? obj.GetSection("on_kill") : null; + if (obj != null) + { + return view_as(obj); + } + + return null; + } + + public KeyMap_Array GetDamageEffects() + { + return this.GetArray("apply_conditions"); + } + + public void ApplyDamageEffects(CBaseCombatCharacter player, int difficulty, SF2_ChaserEntity chaser = view_as(-1)) + { + if (this.GetDamageEffects() == null) + { + return; + } + + if (!player.IsValid()) + { + return; + } + + for (int i = 0; i < this.GetDamageEffects().Length; i++) + { + KeyMap obj = this.GetDamageEffects().GetSection(i); + if (obj == null) + { + continue; + } + BossProfileDamageEffect effect = view_as(obj); + effect.Apply(player, difficulty, chaser); + } + } + + public BossProfileShockwave GetShockwave() + { + return view_as(this.GetSection("shockwave")); + } + + public void Precache() + { + this.ConvertSectionsSectionToArray("apply_conditions"); + + if (this.GetBeginSounds() != null) + { + this.GetBeginSounds().Precache(); + } + + if (this.GetStartSounds() != null) + { + this.GetStartSounds().Precache(); + } + + if (this.GetHitSounds() != null) + { + this.GetHitSounds().Precache(); + } + + if (this.GetMissSounds() != null) + { + this.GetMissSounds().Precache(); + } + + if (this.GetEndSounds() != null) + { + this.GetEndSounds().Precache(); + } + + if (this.GetLoopSounds() != null) + { + this.GetLoopSounds().Precache(); + } + + if (this.GetStartEffects() != null) + { + this.GetStartEffects().Precache(); + } + + if (this.GetHitEffects() != null) + { + this.GetHitEffects().Precache(); + } + + if (this.GetMissEffects() != null) + { + this.GetMissEffects().Precache(); + } + + if (this.GetOnKillEffects() != null) + { + this.GetOnKillEffects().Precache(); + } + + if (this.GetShockwave() != null) + { + this.GetShockwave().Precache(); + } + + if (this.GetDamageEffects() != null) + { + for (int i = 0; i < this.GetDamageEffects().Length; i++) + { + BossProfileDamageEffect effect = view_as(this.GetDamageEffects().GetSection(i)); + if (effect != null) + { + effect.Precache(); + } + } + } + } +} + +methodmap BossProfileDamageEffect < ProfileObject +{ + property int Type + { + public get() + { + char section[64]; + this.GetSectionName(section, sizeof(section)); + if (strcmp(section, "ignite", false) == 0) + { + return SF2DamageType_Ignite; + } + else if (strcmp(section, "gas", false) == 0) + { + return SF2DamageType_Gas; + } + else if (strcmp(section, "bleed", false) == 0) + { + return SF2DamageType_Bleed; + } + else if (strcmp(section, "mark", false) == 0) + { + return SF2DamageType_Mark; + } + else if (strcmp(section, "jarate", false) == 0) + { + return SF2DamageType_Jarate; + } + else if (strcmp(section, "milk", false) == 0) + { + return SF2DamageType_Milk; + } + else if (strcmp(section, "stun", false) == 0) + { + return SF2DamageType_Stun; + } + else if (strcmp(section, "smite", false) == 0) + { + return SF2DamageType_Smite; + } + else if (strcmp(section, "random", false) == 0) + { + return SF2DamageType_Random; + } + + return SF2DamageType_Invalid; + } + } + + public bool IsEnabled(int difficulty) + { + if (this.Type == SF2DamageType_Invalid) + { + return false; + } + return this.GetDifficultyBool("enabled", difficulty, true); + } + + public float GetDuration(int difficulty) + { + float def = 8.0; + if (this.Type == SF2DamageType_Invalid) + { + return def; + } + return this.GetDifficultyFloat("duration", difficulty, def); + } + + public ProfileSound GetSounds() + { + return view_as(this.GetSection("sounds")); + } + + public ProfileObject GetParticles() + { + return this.GetSection("particles"); + } + + public void Apply(CBaseCombatCharacter player, int difficulty, SF2_ChaserEntity chaser = view_as(-1)) + { + if (!this.IsEnabled(difficulty)) + { + return; + } + this.GetSounds().EmitSound(_, chaser.index); + if (this.GetParticles() != null) + { + char name[64]; + this.GetParticles().GetSectionNameFromIndex(GetRandomInt(0, this.GetParticles().SectionLength - 1), name, sizeof(name)); + ProfileObject obj = this.GetParticles().GetSection(name); + if (obj != null) + { + view_as(obj).Apply(player, chaser); + } + } + int type = this.Type; + if (type == SF2DamageType_Random) + { + type = view_as(this).GetRandomType(); + } + + switch (type) + { + case SF2DamageType_Ignite: + { + TF2_IgnitePlayer(player.index, player.index, this.GetDuration(difficulty)); + } + case SF2DamageType_Gas: + { + TF2_AddCondition(player.index, TFCond_Gas, this.GetDuration(difficulty), player.index); + } + case SF2DamageType_Mark: + { + TF2_AddCondition(player.index, view_as(this).GetSilentMark(difficulty) ? TFCond_MarkedForDeathSilent : TFCond_MarkedForDeath, this.GetDuration(difficulty), player.index); + } + case SF2DamageType_Bleed: + { + TF2_MakeBleed(player.index, player.index, this.GetDuration(difficulty)); + } + case SF2DamageType_Milk: + { + TF2_AddCondition(player.index, TFCond_Milked, this.GetDuration(difficulty), player.index); + } + case SF2DamageType_Jarate: + { + TF2_AddCondition(player.index, TFCond_Jarated, this.GetDuration(difficulty), player.index); + } + case SF2DamageType_Stun: + { + TF2_StunPlayer(player.index, this.GetDuration(difficulty), view_as(this).GetSlowdown(difficulty), view_as(this).GetFlags(difficulty)); + } + case SF2DamageType_Smite: + { + BossProfileDamageEffect_Smite smiteData = view_as(this); + float targetPos[3]; + player.GetAbsOrigin(targetPos); + targetPos[2] -= 26.0; + + int randomX = GetRandomInt(-500, 500); + int randomY = GetRandomInt(-500, 500); + + float startPos[3]; + startPos[0] = targetPos[0] + randomX; + startPos[1] = targetPos[1] + randomY; + startPos[2] = targetPos[2] + 800.0; + + float origin[3]; + int color[4]; + smiteData.GetSmiteColor(color); + TE_SetupBeamPoints(startPos, targetPos, smiteData.SmiteSprite, 0, 0, 0, 0.2, 20.0, 10.0, 0, 1.0, color, 3); + TE_SendToAll(); + + TE_SetupSparks(targetPos, origin, 5000, 1000); + TE_SendToAll(); + + TE_SetupEnergySplash(targetPos, origin, false); + TE_SendToAll(); + + TE_SetupSmoke(targetPos, smiteData.SmiteSmokeSprite, 5.0, 10); + TE_SendToAll(); + + char sound[PLATFORM_MAX_PATH]; + smiteData.GetHitSound(sound, sizeof(sound)); + EmitAmbientSound(sound, startPos, player.index, SNDLEVEL_SCREAMING); + SDKHooks_TakeDamage(player.index, chaser.index, chaser.index, smiteData.GetDamage(difficulty), smiteData.GetDamageType(difficulty)); + + SF2NPC_Chaser controller = chaser.Controller; + if (smiteData.SmiteMessage && controller.IsValid() && GetClientTeam(player.index) == 2) + { + char playerName[32], bossName[SF2_MAX_NAME_LENGTH]; + GetClientName(player.index, playerName, sizeof(playerName)); + controller.GetProfileDataEx().GetName(controller.Difficulty, bossName, sizeof(bossName)); + CPrintToChatAll("{royalblue}%t {default}%t", "SF2 Prefix", "SF2 Smote target", bossName, playerName); + } + } + } + } + + public void Precache() + { + if (this.GetSounds() != null) + { + this.GetSounds().Precache(); + } + } +} + +methodmap BossProfileDamageEffect_Mark < BossProfileDamageEffect +{ + public bool GetSilentMark(int difficulty) + { + bool def = false; + if (this.Type == SF2DamageType_Invalid) + { + return def; + } + return this.GetDifficultyBool("silent", difficulty, def); + } +} + +methodmap BossProfileDamageEffect_Stun < BossProfileDamageEffect +{ + public float GetSlowdown(int difficulty) + { + float def = 0.5; + if (this.Type == SF2DamageType_Invalid) + { + return def; + } + return this.GetDifficultyFloat("slow_multiplier", difficulty, def); + } + + public int GetFlags(int difficulty) + { + char flag[256]; + this.GetDifficultyString("flags", difficulty, flag, sizeof(flag), "slow"); + char flags[32][64]; + int nums = ExplodeString(flag, " ", flags, sizeof(flags), sizeof(flags[])); + int value = 0; + + for (int i = 0; i < nums; i++) + { + if (strcmp(flags[i], "slow", false) == 0) + { + value |= (1 << 0); + } + else if (strcmp(flags[i], "stuck", false) == 0) + { + value |= (1 << 1); + } + else if (strcmp(flags[i], "cheer_fx", false) == 0) + { + value |= (1 << 3); + } + else if (strcmp(flags[i], "no_fx", false) == 0) + { + value |= (1 << 5); + } + else if (strcmp(flags[i], "thirdperson", false) == 0) + { + value |= (1 << 6); + } + else if (strcmp(flags[i], "ghost_fx", false) == 0) + { + value |= (1 << 7); + } + else if (strcmp(flags[i], "loser", false) == 0) + { + value |= (1 << 0) | (1 << 5) | (1 << 6); + } + else if (strcmp(flags[i], "boo", false) == 0) + { + value |= (1 << 7) | (1 << 6); + } + } + + return value; + } +} + +methodmap BossProfileDamageEffect_Smite < BossProfileDamageEffect +{ + property int SmiteSprite + { + public get() + { + int val = 0; + this.GetValue("__smite_sprite", val); + return val; + } + + public set(int value) + { + this.SetValue("__smite_sprite", value); + } + } + + property int SmiteSmokeSprite + { + public get() + { + int val = 0; + this.GetValue("__smite_smoke_sprite", val); + return val; + } + + public set(int value) + { + this.SetValue("__smite_smoke_sprite", value); + } + } + + public float GetDamage(int difficulty) + { + float def = 9001.0; + if (this.Type == SF2DamageType_Invalid) + { + return def; + } + return this.GetDifficultyFloat("damage", difficulty, def); + } + + public int GetDamageType(int difficulty) + { + int def = (1 << 20); + if (this.Type == SF2DamageType_Invalid) + { + return def; + } + return this.GetDifficultyInt("damagetype", difficulty, def); + } + + public void GetSmiteColor(int buffer[4]) + { + this.GetColor("color", buffer, { 255, 255, 255, 255 }); + } + + property bool SmiteMessage + { + public get() + { + bool def = false; + if (this.Type == SF2DamageType_Invalid) + { + return def; + } + return this.GetBool("message", def); + } + } + + public void GetHitSound(char[] buffer, int bufferSize) + { + if (this.Type == SF2DamageType_Invalid) + { + return; + } + this.GetString("hit_sound", buffer, bufferSize); + } +} + +methodmap BossProfileDamageEffect_Random < BossProfileDamageEffect +{ + public int GetRandomType() + { + if (this.Type == SF2DamageType_Invalid) + { + return SF2DamageType_Invalid; + } + char type[256]; + this.GetString("random_types", type, sizeof(type)); + ArrayList random = new ArrayList(); + char types[32][32]; + int nums = ExplodeString(type, " ", types, sizeof(types), sizeof(types[])); + for (int i = 0; i < nums; i++) + { + if (strcmp(types[i], "ignite", false) == 0) + { + random.Push(SF2DamageType_Ignite); + } + else if (strcmp(types[i], "gas", false) == 0) + { + random.Push(SF2DamageType_Gas); + } + else if (strcmp(types[i], "bleed", false) == 0) + { + random.Push(SF2DamageType_Bleed); + } + else if (strcmp(types[i], "mark", false) == 0) + { + random.Push(SF2DamageType_Mark); + } + else if (strcmp(types[i], "jarate", false) == 0) + { + random.Push(SF2DamageType_Jarate); + } + else if (strcmp(types[i], "milk", false) == 0) + { + random.Push(SF2DamageType_Milk); + } + else if (strcmp(types[i], "stun", false) == 0) + { + random.Push(SF2DamageType_Stun); + } + else if (strcmp(types[i], "smite", false) == 0) + { + random.Push(SF2DamageType_Smite); + } + } + int val = random.Get(GetRandomInt(0, random.Length - 1)); + delete random; + return val; + } +} + +methodmap BossProfileShockwave < ProfileObject +{ + public float GetHeight(int difficulty) + { + return this.GetDifficultyFloat("height", difficulty, 80.0); + } + + public float GetRadius(int difficulty) + { + return this.GetDifficultyFloat("radius", difficulty, 200.0); + } + + public float GetForce(int difficulty) + { + return this.GetDifficultyFloat("force", difficulty, 600.0); + } + + public float GetBatteryDrainPercent(int difficulty) + { + return this.GetDifficultyFloat("battery_drain", difficulty, 0.0); + } + + public float GetStaminaDrainPercent(int difficulty) + { + return this.GetDifficultyFloat("stamina_drain", difficulty, 0.0); + } + + public ProfileEffectMaster GetEffects() + { + return view_as(this.GetSection("effects")); + } + + public KeyMap_Array GetDamageEffects() + { + return this.GetArray("apply_conditions"); + } + + public void ApplyDamageEffects(CBaseCombatCharacter player, int difficulty, SF2_ChaserEntity chaser = view_as(-1)) + { + if (this.GetDamageEffects() == null) + { + return; + } + + if (!player.IsValid()) + { + return; + } + + for (int i = 0; i < this.GetDamageEffects().Length; i++) + { + KeyMap obj = this.GetDamageEffects().GetSection(i); + if (obj == null) + { + continue; + } + BossProfileDamageEffect effect = view_as(obj); + effect.Apply(player, difficulty, chaser); + } + } + + public void Precache() + { + this.ConvertSectionsSectionToArray("apply_conditions"); + if (this.GetDamageEffects() != null) + { + for (int i = 0; i < this.GetDamageEffects().Length; i++) + { + BossProfileDamageEffect obj = view_as(this.GetDamageEffects().GetSection(i)); + if (obj == null) + { + continue; + } + obj.Precache(); + } + } + + if (this.GetEffects() != null) + { + this.GetEffects().Precache(); + } + } +} #include "attacks/melee.sp" #include "attacks/bullet.sp" @@ -14,7 +1204,7 @@ static NextBotActionFactory g_Factory; methodmap SF2_ChaserAttackAction < NextBotAction { - public SF2_ChaserAttackAction(const char[] attackName, int attackIndex, float endTime) + public SF2_ChaserAttackAction(ChaserBossProfile profileData, const char[] attackName, int attackIndex, float endTime) { if (g_Factory == null) { @@ -27,6 +1217,7 @@ methodmap SF2_ChaserAttackAction < NextBotAction g_Factory.SetCallback(NextBotActionCallbackType_OnEnd, OnEnd); g_Factory.SetEventCallback(EventResponderType_OnOtherKilled, OnOtherKilled); g_Factory.BeginDataMapDesc() + .DefineIntField("m_ProfileData") .DefineIntField("m_OldState") .DefineIntField("m_OldMovementType") .DefineStringField("m_AttackName") @@ -41,7 +1232,9 @@ methodmap SF2_ChaserAttackAction < NextBotAction SF2_ChaserAttackAction action = view_as(g_Factory.Create()); action.SetAttackName(attackName); + action.ProfileData = profileData.GetAttack(attackName); action.EndTime = endTime; + action.AttackIndex = attackIndex; return action; } @@ -58,6 +1251,40 @@ methodmap SF2_ChaserAttackAction < NextBotAction SF2_ChaserAttackAction_ForwardBased.Initialize(); } + public static void SetupAPI() + { + CreateNative("SF2_ChaserBossProfileBaseAttack.Type.get", Native_GetType); + CreateNative("SF2_ChaserBossProfileBaseAttack.GetDamageDelay", Native_GetDamageDelay); + CreateNative("SF2_ChaserBossProfileBaseAttack.GetRange", Native_GetRange); + CreateNative("SF2_ChaserBossProfileBaseAttack.GetDamage", Native_GetDamage); + CreateNative("SF2_ChaserBossProfileBaseAttack.GetDamageType", Native_GetDamageType); + CreateNative("SF2_ChaserBossProfileBaseAttack.GetDamageForce", Native_GetDamageForce); + CreateNative("SF2_ChaserBossProfileBaseAttack.GetViewPunchAngles", Native_GetViewPunchAngles); + CreateNative("SF2_ChaserBossProfileBaseAttack.GetDuration", Native_GetDuration); + CreateNative("SF2_ChaserBossProfileBaseAttack.GetFOV", Native_GetFOV); + CreateNative("SF2_ChaserBossProfileBaseAttack.GetBeginRange", Native_GetBeginRange); + CreateNative("SF2_ChaserBossProfileBaseAttack.GetBeginFOV", Native_GetBeginFOV); + CreateNative("SF2_ChaserBossProfileBaseAttack.GetCooldown", Native_GetCooldown); + CreateNative("SF2_ChaserBossProfileBaseAttack.UseOnDifficulty.get", Native_GetUseOnDifficulty); + CreateNative("SF2_ChaserBossProfileBaseAttack.BlockOnDifficulty.get", Native_GetBlockOnDifficulty); + CreateNative("SF2_ChaserBossProfileBaseAttack.CanUseOnHealth", Native_GetCanUseOnHealth); + CreateNative("SF2_ChaserBossProfileBaseAttack.CanBlockOnHealth", Native_GetCanBlockOnHealth); + ChaserBossProfileCustomAttack.SetupAPI(); + } + + property ChaserBossProfileBaseAttack ProfileData + { + public get() + { + return this.GetData("m_ProfileData"); + } + + public set(ChaserBossProfileBaseAttack value) + { + this.SetData("m_ProfileData", value); + } + } + property int OldState { public get() @@ -176,9 +1403,6 @@ methodmap SF2_ChaserAttackAction < NextBotAction static NextBotAction InitialContainedAction(SF2_ChaserAttackAction action, SF2_ChaserEntity actor) { - actor.MyNextBotPointer().GetLocomotionInterface().Stop(); - actor.Controller.Path.Invalidate(); - NextBotAction attackAction = NULL_ACTION; Action result = Plugin_Continue; @@ -213,42 +1437,46 @@ static int OnStart(SF2_ChaserAttackAction action, SF2_ChaserEntity actor, NextBo actor.SetAttackName(action.GetAttackName()); actor.AttackIndex = action.AttackIndex; actor.IsAttacking = true; + actor.EndCloak(); actor.RemoveAllGestures(); CBaseNPC_RemoveAllLayers(actor.index); int difficulty = controller.Difficulty; float gameTime = GetGameTime(); - SF2ChaserBossProfileData data; - SF2ChaserBossProfileAttackData attackData; - data = controller.GetProfileData(); - data.GetAttack(actor.GetAttackName(), attackData); - actor.AttackRunDelay = gameTime + attackData.RunDelay[difficulty]; - actor.AttackRunDuration = gameTime + attackData.RunDuration[difficulty]; - actor.MyNextBotPointer().GetLocomotionInterface().Stop(); - controller.Path.Invalidate(); + ChaserBossProfile data = controller.GetProfileDataEx(); + ChaserBossProfileChaseData chaseData = data.GetChaseBehavior(); + ChaserBossProfileBaseAttack attackData = action.ProfileData; + actor.AttackRunDelay = gameTime + attackData.GetRunDelay(difficulty); + actor.AttackRunDuration = gameTime + attackData.GetRunDuration(difficulty); if (actor.State == STATE_CHASE) { - actor.CurrentChaseDuration += data.ChaseDurationAddOnAttack[difficulty]; - if (actor.CurrentChaseDuration > data.ChaseDuration[difficulty]) + actor.CurrentChaseDuration += chaseData.GetDurationAddOnAttack(difficulty); + if (actor.CurrentChaseDuration > chaseData.GetMaxChaseDuration(difficulty)) { - actor.CurrentChaseDuration = data.ChaseDuration[difficulty]; + actor.CurrentChaseDuration = chaseData.GetMaxChaseDuration(difficulty); } } action.OldState = actor.State; - action.OldMovementType = actor.MovementType; actor.State = STATE_ATTACK; + action.OldMovementType = actor.MovementType; actor.InvokeOnStartAttack(action.GetAttackName()); - if (attackData.StartEffects != null) + if (attackData.GetStartEffects() != null) { - SlenderSpawnEffects(attackData.StartEffects, controller.Index, false); + SlenderSpawnEffects(attackData.GetStartEffects(), controller.Index, false); } - if (attackData.RunSpeed[difficulty] > 0.0) + if (attackData.GetRunSpeed(difficulty) <= 0.0) + { + actor.MyNextBotPointer().GetLocomotionInterface().Stop(); + controller.Path.Invalidate(); + actor.IsAttemptingToMove = false; + } + else { actor.MovementType = SF2NPCMoveType_Attack; } @@ -261,8 +1489,8 @@ static int OnStart(SF2_ChaserAttackAction action, SF2_ChaserEntity actor, NextBo actor.ResetProfileAnimation(g_SlenderAnimationsList[SF2BossAnimation_Attack], _, action.GetAttackName()); actor.AddGesture(g_SlenderAnimationsList[SF2BossAnimation_Attack], _, action.GetAttackName()); - SF2BossProfileSoundInfo info; - if (actor.SearchSoundsWithSectionName(data.AttackBeginSounds, action.GetAttackName(), info)) + ProfileSound info; + if (actor.SearchSoundsWithSectionName(data.GetAttackBeginSounds(), action.GetAttackName(), info, "attack_begin")) { action.PlayedBeginVoice = actor.PerformVoice(SF2BossSound_AttackBegin, action.GetAttackName()); } @@ -296,11 +1524,9 @@ static int Update(SF2_ChaserAttackAction action, SF2_ChaserEntity actor, float i return action.Done(); } - SF2ChaserBossProfileData data; - SF2ChaserBossProfileAttackData attackData; + ChaserBossProfile data = controller.GetProfileDataEx(); + ChaserBossProfileBaseAttack attackData = action.ProfileData; int interrputConditions = actor.InterruptConditions; - data = controller.GetProfileData(); - data.GetAttack(actor.GetAttackName(), attackData); bool end = false; INextBot bot = actor.MyNextBotPointer(); PathFollower path = controller.Path; @@ -315,34 +1541,32 @@ static int Update(SF2_ChaserAttackAction action, SF2_ChaserEntity actor, float i actor.GetAbsOrigin(myPos); target.GetAbsOrigin(targetPos); float distance = GetVectorSquareMagnitude(myPos, targetPos); - if (attackData.CancelDistance[difficulty] >= 0.0 && distance > Pow(attackData.CancelDistance[difficulty], 2.0)) + if (attackData.GetMaxCancelDistance(difficulty) > 0.0 && distance > Pow(attackData.GetMaxCancelDistance(difficulty), 2.0)) { end = true; } - if (attackData.MinCancelDistance[difficulty] >= 0.0 && distance < Pow(attackData.MinCancelDistance[difficulty], 2.0)) + if (attackData.GetMinCancelDistance(difficulty) > 0.0 && distance < Pow(attackData.GetMinCancelDistance(difficulty), 2.0)) { end = true; } - if (attackData.CancelLos[difficulty] && (actor.InterruptConditions & COND_ENEMYVISIBLE) == 0) + if (attackData.GetCancelLOS(difficulty) && (actor.InterruptConditions & COND_ENEMYVISIBLE_NOGLASS) == 0) { end = true; } if (actor.MovementType == SF2NPCMoveType_Attack) { + int pathTo = target.index; if (actor.Teleporters.Length > 0) { - CBaseEntity(actor.Teleporters.Get(0)).GetAbsOrigin(targetPos); + pathTo = actor.Teleporters.Get(0); } - if (!bot.IsRangeLessThanEx(targetPos, 8.0)) + if ((interrputConditions & COND_NEWENEMY) != 0 || path.GetAge() > 0.3 || (path.IsValid() && (path.GetLength() - path.GetCursorPosition()) < 256.0)) { - if ((interrputConditions & COND_NEWENEMY) != 0 || path.GetAge() > 0.3 || (path.IsValid() && (path.GetLength() - path.GetCursorPosition()) < 256.0)) - { - path.ComputeToPos(bot, targetPos); - } + path.ComputeToTarget(bot, pathTo); } } } @@ -367,12 +1591,12 @@ static int Update(SF2_ChaserAttackAction action, SF2_ChaserEntity actor, float i return action.Continue(); } - SF2BossProfileSoundInfo info; + ProfileSound info; char value[PLATFORM_MAX_PATH]; value = action.GetLoopSound(); if (value[0] == '\0') { - if (actor.SearchSoundsWithSectionName(data.AttackLoopSounds, action.GetAttackName(), info)) + if (actor.SearchSoundsWithSectionName(data.GetAttackLoopSounds(), action.GetAttackName(), info, "attack_loop")) { char sound[PLATFORM_MAX_PATH]; info.EmitSound(_, actor.index, _, _, _, sound); @@ -461,10 +1685,8 @@ static void OnEnd(SF2_ChaserAttackAction action, SF2_ChaserEntity actor) if (controller.IsValid()) { float gameTime = GetGameTime(); - SF2ChaserBossProfileData data; - SF2ChaserBossProfileAttackData attackData; - data = controller.GetProfileData(); - data.GetAttack(actor.GetAttackName(), attackData); + ChaserBossProfile data = controller.GetProfileDataEx(); + ChaserBossProfileBaseAttack attackData = action.ProfileData; int difficulty = controller.Difficulty; if (data.NormalSoundHook) @@ -472,7 +1694,7 @@ static void OnEnd(SF2_ChaserAttackAction action, SF2_ChaserEntity actor) actor.NextVoiceTime = 0.0; } - actor.SetNextAttackTime(actor.GetAttackName(), gameTime + attackData.Cooldown[difficulty]); + actor.SetNextAttackTime(actor.GetAttackName(), gameTime + attackData.GetCooldown(difficulty)); actor.InvokeOnEndAttack(actor.GetAttackName()); } @@ -486,4 +1708,208 @@ static void OnEnd(SF2_ChaserAttackAction action, SF2_ChaserEntity actor) static void OnOtherKilled(SF2_ChaserMainAction action, SF2_ChaserEntity actor, CBaseCombatCharacter victim, CBaseEntity attacker, CBaseEntity inflictor, float damage, int damagetype) { actor.CheckTauntKill(SF2_BasePlayer(victim.index)); -} \ No newline at end of file +} + +static any Native_GetType(Handle plugin, int numParams) +{ + ChaserBossProfileBaseAttack attackData = GetNativeCell(1); + if (attackData == null) + { + return ThrowNativeError(SP_ERROR_NATIVE, "Invalid profile object handle %x", attackData); + } + + return attackData.Type; +} + +static any Native_GetDamageDelay(Handle plugin, int numParams) +{ + ChaserBossProfileBaseAttack attackData = GetNativeCell(1); + if (attackData == null) + { + return ThrowNativeError(SP_ERROR_NATIVE, "Invalid profile object handle %x", attackData); + } + + int difficulty = GetNativeCell(2); + + return attackData.GetDelay(difficulty); +} + +static any Native_GetRange(Handle plugin, int numParams) +{ + ChaserBossProfileBaseAttack attackData = GetNativeCell(1); + if (attackData == null) + { + return ThrowNativeError(SP_ERROR_NATIVE, "Invalid profile object handle %x", attackData); + } + + int difficulty = GetNativeCell(2); + + return attackData.GetRange(difficulty); +} + +static any Native_GetDamage(Handle plugin, int numParams) +{ + ChaserBossProfileBaseAttack attackData = GetNativeCell(1); + if (attackData == null) + { + return ThrowNativeError(SP_ERROR_NATIVE, "Invalid profile object handle %x", attackData); + } + + int difficulty = GetNativeCell(2); + + return attackData.GetDamage(difficulty); +} + +static any Native_GetDamageType(Handle plugin, int numParams) +{ + ChaserBossProfileBaseAttack attackData = GetNativeCell(1); + if (attackData == null) + { + return ThrowNativeError(SP_ERROR_NATIVE, "Invalid profile object handle %x", attackData); + } + + int difficulty = GetNativeCell(2); + + return attackData.GetDamageType(difficulty); +} + +static any Native_GetDamageForce(Handle plugin, int numParams) +{ + ChaserBossProfileBaseAttack attackData = GetNativeCell(1); + if (attackData == null) + { + return ThrowNativeError(SP_ERROR_NATIVE, "Invalid profile object handle %x", attackData); + } + + int difficulty = GetNativeCell(2); + + return attackData.GetDamageForce(difficulty); +} + +static any Native_GetViewPunchAngles(Handle plugin, int numParams) +{ + ChaserBossProfileBaseAttack attackData = GetNativeCell(1); + if (attackData == null) + { + return ThrowNativeError(SP_ERROR_NATIVE, "Invalid profile object handle %x", attackData); + } + + int difficulty = GetNativeCell(2); + float vec[3]; + attackData.GetViewPunchAngles(difficulty, vec); + SetNativeArray(3, vec, 3); + return 0; +} + +static any Native_GetDuration(Handle plugin, int numParams) +{ + ChaserBossProfileBaseAttack attackData = GetNativeCell(1); + if (attackData == null) + { + return ThrowNativeError(SP_ERROR_NATIVE, "Invalid profile object handle %x", attackData); + } + + int difficulty = GetNativeCell(2); + + return attackData.GetDuration(difficulty); +} + +static any Native_GetFOV(Handle plugin, int numParams) +{ + ChaserBossProfileBaseAttack attackData = GetNativeCell(1); + if (attackData == null) + { + return ThrowNativeError(SP_ERROR_NATIVE, "Invalid profile object handle %x", attackData); + } + + int difficulty = GetNativeCell(2); + + return attackData.GetFOV(difficulty); +} + +static any Native_GetBeginRange(Handle plugin, int numParams) +{ + ChaserBossProfileBaseAttack attackData = GetNativeCell(1); + if (attackData == null) + { + return ThrowNativeError(SP_ERROR_NATIVE, "Invalid profile object handle %x", attackData); + } + + int difficulty = GetNativeCell(2); + + return attackData.GetBeginRange(difficulty); +} + +static any Native_GetBeginFOV(Handle plugin, int numParams) +{ + ChaserBossProfileBaseAttack attackData = GetNativeCell(1); + if (attackData == null) + { + return ThrowNativeError(SP_ERROR_NATIVE, "Invalid profile object handle %x", attackData); + } + + int difficulty = GetNativeCell(2); + + return attackData.GetBeginFOV(difficulty); +} + +static any Native_GetCooldown(Handle plugin, int numParams) +{ + ChaserBossProfileBaseAttack attackData = GetNativeCell(1); + if (attackData == null) + { + return ThrowNativeError(SP_ERROR_NATIVE, "Invalid profile object handle %x", attackData); + } + + int difficulty = GetNativeCell(2); + + return attackData.GetCooldown(difficulty); +} + +static any Native_GetUseOnDifficulty(Handle plugin, int numParams) +{ + ChaserBossProfileBaseAttack attackData = GetNativeCell(1); + if (attackData == null) + { + return ThrowNativeError(SP_ERROR_NATIVE, "Invalid profile object handle %x", attackData); + } + + return attackData.UseOnDifficulty; +} + +static any Native_GetBlockOnDifficulty(Handle plugin, int numParams) +{ + ChaserBossProfileBaseAttack attackData = GetNativeCell(1); + if (attackData == null) + { + return ThrowNativeError(SP_ERROR_NATIVE, "Invalid profile object handle %x", attackData); + } + + return attackData.BlockOnDifficulty; +} + +static any Native_GetCanUseOnHealth(Handle plugin, int numParams) +{ + ChaserBossProfileBaseAttack attackData = GetNativeCell(1); + if (attackData == null) + { + return ThrowNativeError(SP_ERROR_NATIVE, "Invalid profile object handle %x", attackData); + } + + int difficulty = GetNativeCell(2); + + return attackData.CanUseOnHealth(difficulty); +} + +static any Native_GetCanBlockOnHealth(Handle plugin, int numParams) +{ + ChaserBossProfileBaseAttack attackData = GetNativeCell(1); + if (attackData == null) + { + return ThrowNativeError(SP_ERROR_NATIVE, "Invalid profile object handle %x", attackData); + } + + int difficulty = GetNativeCell(2); + + return attackData.CanBlockOnHealth(difficulty); +} diff --git a/addons/sourcemod/scripting/sf2/npc/entities/chaser/actions/attacklayer.sp b/addons/sourcemod/scripting/sf2/npc/entities/chaser/actions/attacklayer.sp index d038b3d6..99a83ec4 100644 --- a/addons/sourcemod/scripting/sf2/npc/entities/chaser/actions/attacklayer.sp +++ b/addons/sourcemod/scripting/sf2/npc/entities/chaser/actions/attacklayer.sp @@ -1,4 +1,5 @@ #pragma semicolon 1 +#pragma newdecls required // This is for detecting attacks static NextBotActionFactory g_Factory; @@ -32,7 +33,6 @@ static int Update(SF2_ChaserAttackLayerAction action, SF2_ChaserEntity actor) NextBotAction attackAction = actor.GetAttackAction(target); if (attackAction != NULL_ACTION) { - actor.EndCloak(); return action.SuspendFor(attackAction, "Time to die!"); } } diff --git a/addons/sourcemod/scripting/sf2/npc/entities/chaser/actions/attacks/bullet.sp b/addons/sourcemod/scripting/sf2/npc/entities/chaser/actions/attacks/bullet.sp index b48d9ad4..4434f042 100644 --- a/addons/sourcemod/scripting/sf2/npc/entities/chaser/actions/attacks/bullet.sp +++ b/addons/sourcemod/scripting/sf2/npc/entities/chaser/actions/attacks/bullet.sp @@ -1,10 +1,43 @@ #pragma semicolon 1 +#pragma newdecls required + +methodmap ChaserBossProfileBulletAttack < ChaserBossProfileBaseAttack +{ + public int GetBulletCount(int difficulty) + { + int def = 4; + def = this.GetDifficultyInt("attack_bullet_count", difficulty, def); + def = this.GetDifficultyInt("bullet_count", difficulty, def); + return def; + } + + public float GetBulletSpread(int difficulty) + { + float def = 0.1; + def = this.GetDifficultyFloat("bullet_spread", difficulty, def); + def = this.GetDifficultyFloat("attack_bullet_spread", difficulty, def); + return def; + } + + public void GetBulletTrace(char[] buffer, int bufferSize) + { + FormatEx(buffer, bufferSize, "bullet_tracer02_blue"); + this.GetString("bullet_tracer", buffer, bufferSize, buffer); + this.GetString("attack_bullet_tracer", buffer, bufferSize, buffer); + } + + public void GetBulletOffset(float buffer[3]) + { + this.GetVector("bullet_offset", buffer, buffer); + this.GetVector("attack_bullet_offset", buffer, buffer); + } +} static NextBotActionFactory g_Factory; methodmap SF2_ChaserAttackAction_Bullet < NextBotAction { - public SF2_ChaserAttackAction_Bullet(int attackIndex, const char[] attackName, float fireDelay) + public SF2_ChaserAttackAction_Bullet(const char[] attackName, ChaserBossProfileBulletAttack data, float fireDelay) { if (g_Factory == null) { @@ -13,8 +46,8 @@ methodmap SF2_ChaserAttackAction_Bullet < NextBotAction g_Factory.SetCallback(NextBotActionCallbackType_Update, Update); g_Factory.SetEventCallback(EventResponderType_OnAnimationEvent, OnAnimationEvent); g_Factory.BeginDataMapDesc() - .DefineIntField("m_AttackIndex") .DefineStringField("m_AttackName") + .DefineIntField("m_ProfileData") .DefineFloatField("m_NextFireTime") .DefineIntField("m_RepeatIndex") .EndDataMapDesc(); @@ -22,25 +55,12 @@ methodmap SF2_ChaserAttackAction_Bullet < NextBotAction SF2_ChaserAttackAction_Bullet action = view_as(g_Factory.Create()); action.NextFireTime = fireDelay; - action.AttackIndex = attackIndex; action.SetAttackName(attackName); + action.ProfileData = data; return action; } - property int AttackIndex - { - public get() - { - return this.GetData("m_AttackIndex"); - } - - public set(int value) - { - this.SetData("m_AttackIndex", value); - } - } - public static void Initialize() { g_OnChaserGetAttackActionPFwd.AddFunction(null, OnChaserGetAttackAction); @@ -58,6 +78,19 @@ methodmap SF2_ChaserAttackAction_Bullet < NextBotAction this.SetDataString("m_AttackName", name); } + property ChaserBossProfileBulletAttack ProfileData + { + public get() + { + return this.GetData("m_ProfileData"); + } + + public set(ChaserBossProfileBulletAttack value) + { + this.SetData("m_ProfileData", value); + } + } + property float NextFireTime { public get() @@ -92,10 +125,8 @@ static Action OnChaserGetAttackAction(SF2_ChaserEntity chaser, const char[] atta return Plugin_Continue; } - SF2ChaserBossProfileData data; - data = chaser.Controller.GetProfileData(); - SF2ChaserBossProfileAttackData attackData; - data.GetAttack(attackName, attackData); + ChaserBossProfile data = chaser.Controller.GetProfileDataEx(); + ChaserBossProfileBulletAttack attackData = view_as(data.GetAttack(attackName)); int difficulty = chaser.Controller.Difficulty; if (attackData.Type != SF2BossAttackType_Ranged) @@ -103,7 +134,7 @@ static Action OnChaserGetAttackAction(SF2_ChaserEntity chaser, const char[] atta return Plugin_Continue; } - result = SF2_ChaserAttackAction_Bullet(attackData.Index, attackData.Name, attackData.DamageDelay[difficulty] + GetGameTime()); + result = SF2_ChaserAttackAction_Bullet(attackName, attackData, attackData.GetDelay(difficulty) + GetGameTime()); return Plugin_Changed; } @@ -125,36 +156,32 @@ static int Update(SF2_ChaserAttackAction_Bullet action, SF2_ChaserEntity actor, } SF2NPC_Chaser controller = actor.Controller; - SF2ChaserBossProfileData data; - data = controller.GetProfileData(); - SF2ChaserBossProfileAttackData attackData; - data.GetAttack(action.GetAttackName(), attackData); + ChaserBossProfileBulletAttack attackData = action.ProfileData; float gameTime = GetGameTime(); int difficulty = controller.Difficulty; - if (action.NextFireTime >= 0.0 && gameTime > action.NextFireTime && attackData.EventNumber == -1) + if (action.NextFireTime >= 0.0 && gameTime > action.NextFireTime && attackData.GetEventNumber(difficulty) == -1) { - DoBulletAttack(actor, action.GetAttackName()); + DoBulletAttack(action, actor, action.GetAttackName()); - int repeatState = attackData.Repeat; + int repeatState = attackData.GetRepeatState(difficulty); if (repeatState > 0) { switch (repeatState) { case 1: { - action.NextFireTime = gameTime + attackData.DamageDelay[difficulty]; + action.NextFireTime = gameTime + attackData.GetDelay(difficulty); } case 2: { - if (action.RepeatIndex >= attackData.RepeatTimers.Length) + if (attackData.GetRepeatTimer(difficulty, action.RepeatIndex) < 0.0) { action.NextFireTime = -1.0; } else { - float next = attackData.RepeatTimers.Get(action.RepeatIndex); - action.NextFireTime = next + gameTime; + action.NextFireTime = attackData.GetRepeatTimer(difficulty, action.RepeatIndex) + gameTime; action.RepeatIndex++; } } @@ -168,22 +195,19 @@ static int Update(SF2_ChaserAttackAction_Bullet action, SF2_ChaserEntity actor, return action.Continue(); } -static void DoBulletAttack(SF2_ChaserEntity actor, const char[] attackName) +static void DoBulletAttack(SF2_ChaserAttackAction_Bullet action, SF2_ChaserEntity actor, const char[] attackName) { SF2NPC_Chaser controller = actor.Controller; CBaseEntity target = actor.Target; int difficulty = controller.Difficulty; - SF2ChaserBossProfileData data; - data = controller.GetProfileData(); - SF2ChaserBossProfileAttackData attackData; - data.GetAttack(attackName, attackData); + ChaserBossProfile data = controller.GetProfileDataEx(); + ChaserBossProfileBulletAttack attackData = action.ProfileData; - float spread = attackData.BulletSpread[difficulty]; - ArrayList bulletSounds = data.BulletShootSounds; - SF2BossProfileSoundInfo soundInfo; - if (actor.SearchSoundsWithSectionName(bulletSounds, attackName, soundInfo)) + float spread = attackData.GetBulletSpread(difficulty); + ProfileSound soundInfo; + if (actor.SearchSoundsWithSectionName(data.GetBulletShootSounds(), attackName, soundInfo, "bulletshoot")) { soundInfo.EmitSound(_, actor.index); } @@ -206,7 +230,7 @@ static void DoBulletAttack(SF2_ChaserEntity actor, const char[] attackName) targetPos[1] = eyePos[1] + fwd[1] * 9001.0; targetPos[2] = eyePos[2] + fwd[2] * 9001.0; } - effectPos = attackData.BulletOffset; + attackData.GetBulletOffset(effectPos); VectorTransform(effectPos, basePos, baseAng, effectPos); AddVectors(effectAng, baseAng, effectAng); @@ -225,7 +249,8 @@ static void DoBulletAttack(SF2_ChaserEntity actor, const char[] attackName) float dir[3], end[3]; float x, y; - for (int i = 0; i < attackData.BulletCount[difficulty]; i++) + ArrayList hitTargets = null; + for (int i = 0; i < attackData.GetBulletCount(difficulty); i++) { x = GetRandomFloat(-0.5, 0.5) + GetRandomFloat(-0.5, 0.5); y = GetRandomFloat(-0.5, 0.5) + GetRandomFloat(-0.5, 0.5); @@ -256,21 +281,29 @@ static void DoBulletAttack(SF2_ChaserEntity actor, const char[] attackName) TE_SetupEffectDispatch(GetEffectDispatchStringTableIndex("Impact"), .origin = endPos, .start = effectPos, - .damageType = DMG_BULLET, + .damageType = attackData.GetDamageType(difficulty), .surfaceProp = TR_GetSurfaceProps(trace), .hitbox = TR_GetHitGroup(trace), .entindex = TR_GetEntityIndex(trace)); TE_SendToAll(); + delete trace; - SDKHooks_TakeDamage(hitTarget, actor.index, actor.index, attackData.BulletDamage[difficulty], DMG_BULLET, _, CalculateBulletDamageForce(dir, 1.0), endPos); - if (SF2_BasePlayer(hitTarget).IsValid) + if (hitTargets == null) + { + hitTargets = new ArrayList(2); + } + int hitIndex = hitTargets.FindValue(hitTarget); + if (hitIndex == -1) { - attackData.ApplyDamageEffects(SF2_BasePlayer(hitTarget), difficulty, SF2_ChaserBossEntity(actor.index)); + hitIndex = hitTargets.Push(hitTarget); + hitTargets.Set(hitIndex, 0, 1); } + hitTargets.Set(hitIndex, hitTargets.Get(hitIndex, 1) + 1, 1); - if (attackData.BulletTrace[0] == '\0') + char traceParticle[64]; + attackData.GetBulletTrace(traceParticle, sizeof(traceParticle)); + if (traceParticle[0] == '\0') { - delete trace; continue; } @@ -281,7 +314,7 @@ static void DoBulletAttack(SF2_ChaserEntity actor, const char[] attackName) for (int i2 = 0; i2 < count; i2++) { ReadStringTable(table, i2, tmp, sizeof(tmp)); - if (strcmp(tmp, attackData.BulletTrace, false) == 0) + if (strcmp(tmp, traceParticle, false) == 0) { index = i2; break; @@ -290,8 +323,7 @@ static void DoBulletAttack(SF2_ChaserEntity actor, const char[] attackName) if (index == INVALID_STRING_INDEX) { - LogError("Could not find particle: %s", attackData.BulletTrace); - delete trace; + LogError("Could not find particle: %s", traceParticle); continue; } TE_Particle(index, effectPos, effectPos, dir, actor.index, view_as(PATTACH_CUSTOMORIGIN), _, _, true, view_as(PATTACH_CUSTOMORIGIN), endPos); @@ -299,6 +331,26 @@ static void DoBulletAttack(SF2_ChaserEntity actor, const char[] attackName) } delete trace; } + + if (hitTargets != null) + { + for (int i = 0; i < hitTargets.Length; i++) + { + int hitTarget = hitTargets.Get(i); + float damage = attackData.GetDamage(difficulty) * float(hitTargets.Get(i, 1)); + CBaseEntity(hitTargets.Get(i)).GetAbsOrigin(targetPos); + damage = GetDamageDistance(basePos, targetPos, damage, + attackData.GetDamageRampUpRange(difficulty), attackData.GetDamageFallOffRange(difficulty), + attackData.GetDamageRampUp(difficulty), attackData.GetDamageFallOff(difficulty)); + + SDKHooks_TakeDamage(hitTarget, actor.index, actor.index, damage, attackData.GetDamageType(difficulty), _, CalculateBulletDamageForce(dir, 1.0), basePos); + if (SF2_BasePlayer(hitTarget).IsValid) + { + attackData.ApplyDamageEffects(SF2_BasePlayer(hitTarget), difficulty, actor); + } + } + delete hitTargets; + } } static float[] CalculateBulletDamageForce(const float bulletDir[3], float scale) @@ -319,13 +371,11 @@ static void OnAnimationEvent(SF2_ChaserAttackAction_Bullet action, SF2_ChaserEnt } SF2NPC_Chaser controller = actor.Controller; - SF2ChaserBossProfileData data; - data = controller.GetProfileData(); - SF2ChaserBossProfileAttackData attackData; - data.GetAttack(action.GetAttackName(), attackData); + int difficulty = controller.Difficulty; + ChaserBossProfileBulletAttack attackData = action.ProfileData; - if (event == attackData.EventNumber) + if (event == attackData.GetEventNumber(difficulty)) { - DoBulletAttack(actor, action.GetAttackName()); + DoBulletAttack(action, actor, action.GetAttackName()); } } \ No newline at end of file diff --git a/addons/sourcemod/scripting/sf2/npc/entities/chaser/actions/attacks/custom.sp b/addons/sourcemod/scripting/sf2/npc/entities/chaser/actions/attacks/custom.sp index 4c5a0aba..b99ff761 100644 --- a/addons/sourcemod/scripting/sf2/npc/entities/chaser/actions/attacks/custom.sp +++ b/addons/sourcemod/scripting/sf2/npc/entities/chaser/actions/attacks/custom.sp @@ -1,4 +1,19 @@ #pragma semicolon 1 +#pragma newdecls required + +methodmap ChaserBossProfileCustomAttack < ChaserBossProfileBaseAttack +{ + public void GetSubType(char[] buffer, int bufferSize) + { + this.GetString("subtype", buffer, bufferSize); + } + + public static void SetupAPI() + { + CreateNative("SF2_ChaserBossProfileCustomAttack.GetSubType", Native_GetSubType); + CreateNative("SF2_ChaserBossProfileCustomAttack.IsSubType", Native_GetIsSubType); + } +} methodmap SF2_ChaserAttackAction_Custom < NextBotAction { @@ -16,10 +31,8 @@ static Action OnChaserGetAttackAction(SF2_ChaserEntity chaser, const char[] atta return Plugin_Continue; } - SF2ChaserBossProfileData data; - data = chaser.Controller.GetProfileData(); - SF2ChaserBossProfileAttackData attackData; - data.GetAttack(attackName, attackData); + ChaserBossProfile data = chaser.Controller.GetProfileDataEx(); + ChaserBossProfileCustomAttack attackData = view_as(data.GetAttack(attackName)); if (attackData.Type != SF2BossAttackType_Custom) { @@ -38,4 +51,39 @@ static Action OnChaserGetCustomAttackPossibleState(SF2_ChaserEntity chaser, cons } return Plugin_Handled; -} \ No newline at end of file +} + +static any Native_GetSubType(Handle plugin, int numParams) +{ + ChaserBossProfileCustomAttack attackData = GetNativeCell(1); + if (attackData == null) + { + return ThrowNativeError(SP_ERROR_NATIVE, "Invalid profile object handle %x", attackData); + } + + int bufferSize = GetNativeCell(3); + char[] buffer = new char[bufferSize]; + attackData.GetSubType(buffer, bufferSize); + SetNativeString(2, buffer, bufferSize); + return 0; +} + +static any Native_GetIsSubType(Handle plugin, int numParams) +{ + ChaserBossProfileCustomAttack attackData = GetNativeCell(1); + if (attackData == null) + { + return ThrowNativeError(SP_ERROR_NATIVE, "Invalid profile object handle %x", attackData); + } + + int subTypeSize; + GetNativeStringLength(2, subTypeSize); + subTypeSize++; + char[] subType = new char[subTypeSize]; + GetNativeString(2, subType, subTypeSize); + + char attackSubType[128]; + attackData.GetSubType(attackSubType, sizeof(attackSubType)); + + return strcmp(subType, attackSubType) == 0; +} diff --git a/addons/sourcemod/scripting/sf2/npc/entities/chaser/actions/attacks/explosive_dance.sp b/addons/sourcemod/scripting/sf2/npc/entities/chaser/actions/attacks/explosive_dance.sp index 8bd5d9c5..1787aba0 100644 --- a/addons/sourcemod/scripting/sf2/npc/entities/chaser/actions/attacks/explosive_dance.sp +++ b/addons/sourcemod/scripting/sf2/npc/entities/chaser/actions/attacks/explosive_dance.sp @@ -1,4 +1,21 @@ #pragma semicolon 1 +#pragma newdecls required + +methodmap ChaserBossProfileExplosiveDanceAttack < ChaserBossProfileBaseAttack +{ + public float GetBlastRadius(int difficulty) + { + float def = 350.0; + def = this.GetDifficultyFloat("explosivedance_radius", difficulty, def); + def = this.GetDifficultyFloat("attack_explosivedance_radius", difficulty, def); + return def; + } + + public float GetBlastSpread(int difficulty) + { + return this.GetDifficultyFloat("explosivedance_spread", difficulty, 350.0); + } +} static char g_ExplosionSounds[][] = { @@ -11,7 +28,7 @@ static NextBotActionFactory g_Factory; methodmap SF2_ChaserAttackAction_ExplosiveDance < NextBotAction { - public SF2_ChaserAttackAction_ExplosiveDance(int attackIndex, const char[] attackName, float damageDelay) + public SF2_ChaserAttackAction_ExplosiveDance(const char[] attackName, ChaserBossProfileExplosiveDanceAttack data, float damageDelay) { if (g_Factory == null) { @@ -20,8 +37,8 @@ methodmap SF2_ChaserAttackAction_ExplosiveDance < NextBotAction g_Factory.SetCallback(NextBotActionCallbackType_Update, Update); g_Factory.SetEventCallback(EventResponderType_OnAnimationEvent, OnAnimationEvent); g_Factory.BeginDataMapDesc() - .DefineIntField("m_AttackIndex") .DefineStringField("m_AttackName") + .DefineIntField("m_ProfileData") .DefineFloatField("m_NextDamageTime") .DefineIntField("m_ExplosionCount") .EndDataMapDesc(); @@ -29,9 +46,9 @@ methodmap SF2_ChaserAttackAction_ExplosiveDance < NextBotAction SF2_ChaserAttackAction_ExplosiveDance action = view_as(g_Factory.Create()); action.NextDamageTime = damageDelay; - action.AttackIndex = attackIndex; action.SetAttackName(attackName); action.ExplosionCount = 0; + action.ProfileData = data; return action; } @@ -42,19 +59,6 @@ methodmap SF2_ChaserAttackAction_ExplosiveDance < NextBotAction g_OnGamemodeStartPFwd.AddFunction(null, OnGamemodeStart); } - property int AttackIndex - { - public get() - { - return this.GetData("m_AttackIndex"); - } - - public set(int value) - { - this.SetData("m_AttackIndex", value); - } - } - public char[] GetAttackName() { char name[128]; @@ -67,6 +71,19 @@ methodmap SF2_ChaserAttackAction_ExplosiveDance < NextBotAction this.SetDataString("m_AttackName", name); } + property ChaserBossProfileExplosiveDanceAttack ProfileData + { + public get() + { + return this.GetData("m_ProfileData"); + } + + public set(ChaserBossProfileExplosiveDanceAttack value) + { + this.SetData("m_ProfileData", value); + } + } + property float NextDamageTime { public get() @@ -109,10 +126,8 @@ static Action OnChaserGetAttackAction(SF2_ChaserEntity chaser, const char[] atta return Plugin_Continue; } - SF2ChaserBossProfileData data; - data = chaser.Controller.GetProfileData(); - SF2ChaserBossProfileAttackData attackData; - data.GetAttack(attackName, attackData); + ChaserBossProfile data = chaser.Controller.GetProfileDataEx(); + ChaserBossProfileExplosiveDanceAttack attackData = view_as(data.GetAttack(attackName)); int difficulty = chaser.Controller.Difficulty; if (attackData.Type != SF2BossAttackType_ExplosiveDance) @@ -120,7 +135,7 @@ static Action OnChaserGetAttackAction(SF2_ChaserEntity chaser, const char[] atta return Plugin_Continue; } - result = SF2_ChaserAttackAction_ExplosiveDance(attackData.Index, attackData.Name, attackData.DamageDelay[difficulty] + GetGameTime()); + result = SF2_ChaserAttackAction_ExplosiveDance(attackName, attackData, attackData.GetDelay(difficulty) + GetGameTime()); return Plugin_Changed; } @@ -142,14 +157,11 @@ static int Update(SF2_ChaserAttackAction_ExplosiveDance action, SF2_ChaserEntity } SF2NPC_Chaser controller = actor.Controller; - SF2ChaserBossProfileData data; - data = controller.GetProfileData(); - SF2ChaserBossProfileAttackData attackData; - data.GetAttack(action.GetAttackName(), attackData); + ChaserBossProfileExplosiveDanceAttack attackData = action.ProfileData; float gameTime = GetGameTime(); - if (action.NextDamageTime >= 0.0 && gameTime > action.NextDamageTime && attackData.EventNumber == -1) + if (action.NextDamageTime >= 0.0 && gameTime > action.NextDamageTime && attackData.GetEventNumber(controller.Difficulty) == -1) { DoExplosion(action, actor); } @@ -162,12 +174,9 @@ static void DoExplosion(SF2_ChaserAttackAction_ExplosiveDance action, SF2_Chaser int difficulty = controller.Difficulty; - SF2ChaserBossProfileData data; - data = controller.GetProfileData(); - SF2ChaserBossProfileAttackData attackData; - data.GetAttack(action.GetAttackName(), attackData); - float damage = attackData.Damage[difficulty]; - float radius = attackData.ExplosiveDanceRadius[difficulty]; + ChaserBossProfileExplosiveDanceAttack attackData = action.ProfileData; + float damage = attackData.GetDamage(difficulty); + float radius = attackData.GetBlastRadius(difficulty); if (SF_SpecialRound(SPECIALROUND_TINYBOSSES)) { damage *= 0.5; @@ -187,8 +196,8 @@ static void DoExplosion(SF2_ChaserAttackAction_ExplosiveDance action, SF2_Chaser float explosionPos[3]; explosionPos = worldPos; - explosionPos[0] = worldPos[0] + GetRandomFloat(-350.0, 350.0); - explosionPos[1] = worldPos[1] + GetRandomFloat(-350.0, 350.0); + explosionPos[0] = worldPos[0] + GetRandomFloat(-attackData.GetBlastSpread(difficulty), attackData.GetBlastSpread(difficulty)); + explosionPos[1] = worldPos[1] + GetRandomFloat(-attackData.GetBlastSpread(difficulty), attackData.GetBlastSpread(difficulty)); Explode(explosionPos, damage, radius, actor.index); EmitSoundToAll(g_ExplosionSounds[GetRandomInt(0, sizeof(g_ExplosionSounds) - 1)], actor.index, SNDCHAN_AUTO, SNDLEVEL_SCREAMING); @@ -203,12 +212,9 @@ static void OnAnimationEvent(SF2_ChaserAttackAction_ExplosiveDance action, SF2_C } SF2NPC_Chaser controller = actor.Controller; - SF2ChaserBossProfileData data; - data = controller.GetProfileData(); - SF2ChaserBossProfileAttackData attackData; - data.GetAttack(action.GetAttackName(), attackData); + ChaserBossProfileExplosiveDanceAttack attackData = action.ProfileData; - if (event == attackData.EventNumber) + if (event == attackData.GetEventNumber(controller.Difficulty)) { DoExplosion(action, actor); } diff --git a/addons/sourcemod/scripting/sf2/npc/entities/chaser/actions/attacks/forward_based.sp b/addons/sourcemod/scripting/sf2/npc/entities/chaser/actions/attacks/forward_based.sp index cc78288e..5696d264 100644 --- a/addons/sourcemod/scripting/sf2/npc/entities/chaser/actions/attacks/forward_based.sp +++ b/addons/sourcemod/scripting/sf2/npc/entities/chaser/actions/attacks/forward_based.sp @@ -1,10 +1,11 @@ #pragma semicolon 1 +#pragma newdecls required static NextBotActionFactory g_Factory; methodmap SF2_ChaserAttackAction_ForwardBased < NextBotAction { - public SF2_ChaserAttackAction_ForwardBased(int attackIndex, const char[] attackName, float damageDelay) + public SF2_ChaserAttackAction_ForwardBased(const char[] attackName, ChaserBossProfileBaseAttack data, float damageDelay) { if (g_Factory == null) { @@ -12,8 +13,8 @@ methodmap SF2_ChaserAttackAction_ForwardBased < NextBotAction g_Factory.SetCallback(NextBotActionCallbackType_Update, Update); g_Factory.SetEventCallback(EventResponderType_OnAnimationEvent, OnAnimationEvent); g_Factory.BeginDataMapDesc() - .DefineIntField("m_AttackIndex") .DefineStringField("m_AttackName") + .DefineIntField("m_ProfileData") .DefineFloatField("m_NextDamageTime") .DefineIntField("m_RepeatIndex") .EndDataMapDesc(); @@ -21,25 +22,12 @@ methodmap SF2_ChaserAttackAction_ForwardBased < NextBotAction SF2_ChaserAttackAction_ForwardBased action = view_as(g_Factory.Create()); action.NextDamageTime = damageDelay; - action.AttackIndex = attackIndex; action.SetAttackName(attackName); + action.ProfileData = data; return action; } - property int AttackIndex - { - public get() - { - return this.GetData("m_AttackIndex"); - } - - public set(int value) - { - this.SetData("m_AttackIndex", value); - } - } - public static void Initialize() { g_OnChaserGetAttackActionPFwd.AddFunction(null, OnChaserGetAttackAction); @@ -57,6 +45,19 @@ methodmap SF2_ChaserAttackAction_ForwardBased < NextBotAction this.SetDataString("m_AttackName", name); } + property ChaserBossProfileBaseAttack ProfileData + { + public get() + { + return this.GetData("m_ProfileData"); + } + + public set(ChaserBossProfileBaseAttack value) + { + this.SetData("m_ProfileData", value); + } + } + property float NextDamageTime { public get() @@ -91,10 +92,8 @@ static Action OnChaserGetAttackAction(SF2_ChaserEntity chaser, const char[] atta return Plugin_Continue; } - SF2ChaserBossProfileData data; - data = chaser.Controller.GetProfileData(); - SF2ChaserBossProfileAttackData attackData; - data.GetAttack(attackName, attackData); + ChaserBossProfile data = chaser.Controller.GetProfileDataEx(); + ChaserBossProfileBaseAttack attackData = data.GetAttack(attackName); int difficulty = chaser.Controller.Difficulty; if (attackData.Type >= SF2BossAttackType_Melee && attackData.Type <= SF2BossAttackType_Tongue) @@ -102,7 +101,7 @@ static Action OnChaserGetAttackAction(SF2_ChaserEntity chaser, const char[] atta return Plugin_Continue; } - result = SF2_ChaserAttackAction_ForwardBased(attackData.Index, attackData.Name, attackData.DamageDelay[difficulty] + GetGameTime()); + result = SF2_ChaserAttackAction_ForwardBased(attackName, attackData, attackData.GetDelay(difficulty) + GetGameTime()); return Plugin_Changed; } @@ -119,36 +118,32 @@ static int Update(SF2_ChaserAttackAction_ForwardBased action, SF2_ChaserEntity a } SF2NPC_Chaser controller = actor.Controller; - SF2ChaserBossProfileData data; - data = controller.GetProfileData(); - SF2ChaserBossProfileAttackData attackData; - data.GetAttack(action.GetAttackName(), attackData); + ChaserBossProfileBaseAttack attackData = action.ProfileData; int difficulty = controller.Difficulty; float gameTime = GetGameTime(); - if (action.NextDamageTime >= 0.0 && gameTime > action.NextDamageTime && attackData.EventNumber == -1) + if (action.NextDamageTime >= 0.0 && gameTime > action.NextDamageTime && attackData.GetEventNumber(difficulty) == -1) { - RegisterForward(action, actor); + RegisterForward(actor); - int repeatState = attackData.Repeat; + int repeatState = attackData.GetRepeatState(difficulty); if (repeatState > 0) { switch (repeatState) { case 1: { - action.NextDamageTime = gameTime + attackData.DamageDelay[difficulty]; + action.NextDamageTime = gameTime + attackData.GetDelay(difficulty); } case 2: { - if (action.RepeatIndex >= attackData.RepeatTimers.Length) + if (attackData.GetRepeatTimer(difficulty, action.RepeatIndex) < 0.0) { action.NextDamageTime = -1.0; } else { - float next = attackData.RepeatTimers.Get(action.RepeatIndex); - action.NextDamageTime = next + gameTime; + action.NextDamageTime = attackData.GetRepeatTimer(difficulty, action.RepeatIndex) + gameTime; action.RepeatIndex++; } } @@ -162,11 +157,11 @@ static int Update(SF2_ChaserAttackAction_ForwardBased action, SF2_ChaserEntity a return action.Continue(); } -static void RegisterForward(SF2_ChaserAttackAction_ForwardBased action, SF2_ChaserEntity actor) +static void RegisterForward(SF2_ChaserEntity actor) { Call_StartForward(g_OnBossAttackedFwd); Call_PushCell(actor.Controller.Index); - Call_PushCell(action.AttackIndex); + Call_PushCell(actor.AttackIndex); Call_Finish(); } @@ -178,13 +173,10 @@ static void OnAnimationEvent(SF2_ChaserAttackAction_ForwardBased action, SF2_Cha } SF2NPC_Chaser controller = actor.Controller; - SF2ChaserBossProfileData data; - data = controller.GetProfileData(); - SF2ChaserBossProfileAttackData attackData; - data.GetAttack(action.GetAttackName(), attackData); + ChaserBossProfileBaseAttack attackData = action.ProfileData; - if (event == attackData.EventNumber) + if (event == attackData.GetEventNumber(controller.Difficulty)) { - RegisterForward(action, actor); + RegisterForward(actor); } } diff --git a/addons/sourcemod/scripting/sf2/npc/entities/chaser/actions/attacks/laser_beam.sp b/addons/sourcemod/scripting/sf2/npc/entities/chaser/actions/attacks/laser_beam.sp index 82504be0..c0aa15b6 100644 --- a/addons/sourcemod/scripting/sf2/npc/entities/chaser/actions/attacks/laser_beam.sp +++ b/addons/sourcemod/scripting/sf2/npc/entities/chaser/actions/attacks/laser_beam.sp @@ -1,10 +1,73 @@ #pragma semicolon 1 +#pragma newdecls required + +methodmap ChaserBossProfileLaserAttack < ChaserBossProfileBaseAttack +{ + property float LaserSize + { + public get() + { + float def = 12.0; + def = this.GetFloat("laser_size", def); + def = this.GetFloat("attack_laser_size", def); + return def; + } + } + + public void GetLaserColor(int buffer[3]) + { + buffer[0] = this.GetInt("laser_color_r"); + buffer[0] = this.GetInt("attack_laser_color_r"); + buffer[1] = this.GetInt("laser_color_g"); + buffer[1] = this.GetInt("attack_laser_color_g"); + buffer[2] = this.GetInt("laser_color_b"); + buffer[2] = this.GetInt("attack_laser_color_b"); + } + + public void GetAttachment(char[] buffer, int bufferSize) + { + this.GetString("laser_attachment_name", buffer, bufferSize, buffer); + this.GetString("attack_laser_attachment_name", buffer, bufferSize, buffer); + } + + public float GetLaserDuration(int difficulty) + { + float def = this.GetDuration(difficulty); + def = this.GetDifficultyFloat("laser_duration", difficulty, def); + def = this.GetDifficultyFloat("attack_laser_duration", difficulty, def); + return def; + } + + property float LaserNoise + { + public get() + { + float def = 1.0; + def = this.GetFloat("laser_noise", def); + def = this.GetFloat("attack_laser_noise", def); + return def; + } + } + + public void GetOffset(float buffer[3]) + { + this.GetVector("laser_offset", buffer, buffer); + this.GetVector("attack_laser_offset", buffer, buffer); + } + + public float GetLaserTickRate(int difficulty) + { + float def = 0.1; + def = this.GetDifficultyFloat("laser_tick_delay", difficulty, def); + return def; + } +} static NextBotActionFactory g_Factory; methodmap SF2_ChaserAttackAction_Laser < NextBotAction { - public SF2_ChaserAttackAction_Laser(int attackIndex, const char[] attackName, float fireDelay, float duration) + public SF2_ChaserAttackAction_Laser(const char[] attackName, ChaserBossProfileLaserAttack data, float fireDelay, float duration) { if (g_Factory == null) { @@ -13,8 +76,8 @@ methodmap SF2_ChaserAttackAction_Laser < NextBotAction g_Factory.SetCallback(NextBotActionCallbackType_Update, Update); g_Factory.SetEventCallback(EventResponderType_OnAnimationEvent, OnAnimationEvent); g_Factory.BeginDataMapDesc() - .DefineIntField("m_AttackIndex") .DefineStringField("m_AttackName") + .DefineIntField("m_ProfileData") .DefineFloatField("m_NextFireTime") .DefineFloatField("m_LaserDuration") .DefineFloatField("m_LaserCooldown") @@ -23,26 +86,13 @@ methodmap SF2_ChaserAttackAction_Laser < NextBotAction SF2_ChaserAttackAction_Laser action = view_as(g_Factory.Create()); action.NextFireTime = fireDelay; - action.AttackIndex = attackIndex; action.LaserDuration = duration; action.SetAttackName(attackName); + action.ProfileData = data; return action; } - property int AttackIndex - { - public get() - { - return this.GetData("m_AttackIndex"); - } - - public set(int value) - { - this.SetData("m_AttackIndex", value); - } - } - public static void Initialize() { g_OnChaserGetAttackActionPFwd.AddFunction(null, OnChaserGetAttackAction); @@ -60,6 +110,19 @@ methodmap SF2_ChaserAttackAction_Laser < NextBotAction this.SetDataString("m_AttackName", name); } + property ChaserBossProfileLaserAttack ProfileData + { + public get() + { + return this.GetData("m_ProfileData"); + } + + public set(ChaserBossProfileLaserAttack value) + { + this.SetData("m_ProfileData", value); + } + } + property float NextFireTime { public get() @@ -108,10 +171,8 @@ static Action OnChaserGetAttackAction(SF2_ChaserEntity chaser, const char[] atta return Plugin_Continue; } - SF2ChaserBossProfileData data; - data = chaser.Controller.GetProfileData(); - SF2ChaserBossProfileAttackData attackData; - data.GetAttack(attackName, attackData); + ChaserBossProfile data = chaser.Controller.GetProfileDataEx(); + ChaserBossProfileLaserAttack attackData = view_as(data.GetAttack(attackName)); int difficulty = chaser.Controller.Difficulty; if (attackData.Type != SF2BossAttackType_LaserBeam) @@ -119,7 +180,7 @@ static Action OnChaserGetAttackAction(SF2_ChaserEntity chaser, const char[] atta return Plugin_Continue; } - result = SF2_ChaserAttackAction_Laser(attackData.Index, attackData.Name, attackData.DamageDelay[difficulty] + GetGameTime(), attackData.LaserDuration[difficulty] + GetGameTime() + attackData.DamageDelay[difficulty]); + result = SF2_ChaserAttackAction_Laser(attackName, attackData, attackData.GetDelay(difficulty) + GetGameTime(), attackData.GetLaserDuration(difficulty) + GetGameTime() + attackData.GetDelay(difficulty)); return Plugin_Changed; } @@ -141,20 +202,17 @@ static int Update(SF2_ChaserAttackAction_Laser action, SF2_ChaserEntity actor, f } SF2NPC_Chaser controller = actor.Controller; - SF2ChaserBossProfileData data; - data = controller.GetProfileData(); - SF2ChaserBossProfileAttackData attackData; - data.GetAttack(action.GetAttackName(), attackData); + ChaserBossProfileLaserAttack attackData = action.ProfileData; int difficulty = controller.Difficulty; float gameTime = GetGameTime(); - if (action.NextFireTime >= 0.0 && gameTime > action.NextFireTime && attackData.EventNumber == -1) + if (action.NextFireTime >= 0.0 && gameTime > action.NextFireTime && attackData.GetEventNumber(difficulty) == -1) { if (action.LaserCooldown < gameTime) { - action.LaserCooldown = gameTime + attackData.LaserTicks[difficulty]; - FireLaser(action, actor, attackData.LaserTicks[difficulty]); + action.LaserCooldown = gameTime + attackData.GetLaserTickRate(difficulty); + FireLaser(action, actor, attackData.GetLaserTickRate(difficulty)); } if (action.LaserDuration < gameTime) @@ -181,10 +239,7 @@ static void FireLaser(SF2_ChaserAttackAction_Laser action, SF2_ChaserEntity acto int difficulty = controller.Difficulty; - SF2ChaserBossProfileData data; - data = controller.GetProfileData(); - SF2ChaserBossProfileAttackData attackData; - data.GetAttack(action.GetAttackName(), attackData); + ChaserBossProfileLaserAttack attackData = action.ProfileData; if (!target.IsValid()) { @@ -197,7 +252,7 @@ static void FireLaser(SF2_ChaserAttackAction_Laser action, SF2_ChaserEntity acto float basePos[3], baseAng[3], effectAng[3], effectPos[3]; actor.GetAbsOrigin(basePos); actor.GetAbsAngles(baseAng); - effectPos = attackData.LaserOffset; + attackData.GetOffset(effectPos); VectorTransform(effectPos, basePos, baseAng, effectPos); AddVectors(effectAng, baseAng, effectAng); @@ -232,16 +287,18 @@ static void FireLaser(SF2_ChaserAttackAction_Laser action, SF2_ChaserEntity acto TR_GetEndPosition(endPos, trace); int color[3]; - color = attackData.LaserColor; + attackData.GetLaserColor(color); int actualColor[4]; actualColor[0] = color[0]; actualColor[1] = color[1]; actualColor[2] = color[2]; actualColor[3] = 255; - if (attackData.LaserAttachment) + char attachment[64]; + attackData.GetAttachment(attachment, sizeof(attachment)); + if (attachment[0] != '\0') { - int attachmentIndex = actor.LookupAttachment(attackData.LaserAttachmentName); + int attachmentIndex = actor.LookupAttachment(attachment); float targetEntPos[3], tempAng[3]; actor.GetAttachment(attachmentIndex, targetEntPos, tempAng); TE_SetupBeamPoints(targetEntPos, endPos, g_ShockwaveBeam, g_ShockwaveHalo, 0, 30, interval, attackData.LaserSize, attackData.LaserSize, 5, attackData.LaserNoise, actualColor, 1); @@ -253,10 +310,11 @@ static void FireLaser(SF2_ChaserAttackAction_Laser action, SF2_ChaserEntity acto TE_SendToAll(); } - SDKHooks_TakeDamage(hitTarget, actor.index, actor.index, attackData.LaserDamage[difficulty], DMG_SHOCK | DMG_ALWAYSGIB, _, _, endPos); + SDKHooks_TakeDamage(hitTarget, actor.index, actor.index, attackData.GetDamage(difficulty), attackData.GetDamageType(difficulty), _, _, endPos); - attackData.ApplyDamageEffects(SF2_BasePlayer(hitTarget), difficulty, SF2_ChaserBossEntity(actor.index)); + attackData.ApplyDamageEffects(SF2_BasePlayer(hitTarget), difficulty, actor); } + delete trace; } static void OnAnimationEvent(SF2_ChaserAttackAction_Laser action, SF2_ChaserEntity actor, int event) @@ -267,12 +325,9 @@ static void OnAnimationEvent(SF2_ChaserAttackAction_Laser action, SF2_ChaserEnti } SF2NPC_Chaser controller = actor.Controller; - SF2ChaserBossProfileData data; - data = controller.GetProfileData(); - SF2ChaserBossProfileAttackData attackData; - data.GetAttack(action.GetAttackName(), attackData); + ChaserBossProfileLaserAttack attackData = action.ProfileData; - if (event == attackData.EventNumber) + if (event == attackData.GetEventNumber(controller.Difficulty)) { FireLaser(action, actor, 0.1); } diff --git a/addons/sourcemod/scripting/sf2/npc/entities/chaser/actions/attacks/melee.sp b/addons/sourcemod/scripting/sf2/npc/entities/chaser/actions/attacks/melee.sp index a5da6338..54f44dde 100644 --- a/addons/sourcemod/scripting/sf2/npc/entities/chaser/actions/attacks/melee.sp +++ b/addons/sourcemod/scripting/sf2/npc/entities/chaser/actions/attacks/melee.sp @@ -1,10 +1,11 @@ #pragma semicolon 1 +#pragma newdecls required static NextBotActionFactory g_Factory; methodmap SF2_ChaserAttackAction_Melee < NextBotAction { - public SF2_ChaserAttackAction_Melee(int attackIndex, const char[] attackName, float damageDelay) + public SF2_ChaserAttackAction_Melee(const char[] attackName, ChaserBossProfileBaseAttack data, float damageDelay) { if (g_Factory == null) { @@ -13,8 +14,8 @@ methodmap SF2_ChaserAttackAction_Melee < NextBotAction g_Factory.SetCallback(NextBotActionCallbackType_Update, Update); g_Factory.SetEventCallback(EventResponderType_OnAnimationEvent, OnAnimationEvent); g_Factory.BeginDataMapDesc() - .DefineIntField("m_AttackIndex") .DefineStringField("m_AttackName") + .DefineIntField("m_ProfileData") .DefineFloatField("m_NextDamageTime") .DefineIntField("m_RepeatIndex") .EndDataMapDesc(); @@ -22,25 +23,12 @@ methodmap SF2_ChaserAttackAction_Melee < NextBotAction SF2_ChaserAttackAction_Melee action = view_as(g_Factory.Create()); action.NextDamageTime = damageDelay; - action.AttackIndex = attackIndex; action.SetAttackName(attackName); + action.ProfileData = data; return action; } - property int AttackIndex - { - public get() - { - return this.GetData("m_AttackIndex"); - } - - public set(int value) - { - this.SetData("m_AttackIndex", value); - } - } - public static void Initialize() { g_OnChaserGetAttackActionPFwd.AddFunction(null, OnChaserGetAttackAction); @@ -58,6 +46,19 @@ methodmap SF2_ChaserAttackAction_Melee < NextBotAction this.SetDataString("m_AttackName", name); } + property ChaserBossProfileBaseAttack ProfileData + { + public get() + { + return this.GetData("m_ProfileData"); + } + + public set(ChaserBossProfileBaseAttack value) + { + this.SetData("m_ProfileData", value); + } + } + property float NextDamageTime { public get() @@ -92,10 +93,8 @@ static Action OnChaserGetAttackAction(SF2_ChaserEntity chaser, const char[] atta return Plugin_Continue; } - SF2ChaserBossProfileData data; - data = chaser.Controller.GetProfileData(); - SF2ChaserBossProfileAttackData attackData; - data.GetAttack(attackName, attackData); + ChaserBossProfile data = chaser.Controller.GetProfileDataEx(); + ChaserBossProfileBaseAttack attackData = data.GetAttack(attackName); int difficulty = chaser.Controller.Difficulty; if (attackData.Type != SF2BossAttackType_Melee) @@ -103,7 +102,7 @@ static Action OnChaserGetAttackAction(SF2_ChaserEntity chaser, const char[] atta return Plugin_Continue; } - result = SF2_ChaserAttackAction_Melee(attackData.Index, attackData.Name, attackData.DamageDelay[difficulty] + GetGameTime()); + result = SF2_ChaserAttackAction_Melee(attackName, attackData, attackData.GetDelay(difficulty) + GetGameTime()); return Plugin_Changed; } @@ -125,36 +124,32 @@ static int Update(SF2_ChaserAttackAction_Melee action, SF2_ChaserEntity actor, f } SF2NPC_Chaser controller = actor.Controller; - SF2ChaserBossProfileData data; - data = controller.GetProfileData(); - SF2ChaserBossProfileAttackData attackData; - data.GetAttack(action.GetAttackName(), attackData); + ChaserBossProfileBaseAttack attackData = action.ProfileData; int difficulty = controller.Difficulty; float gameTime = GetGameTime(); - if (action.NextDamageTime >= 0.0 && gameTime > action.NextDamageTime && attackData.EventNumber == -1) + if (action.NextDamageTime >= 0.0 && gameTime >= action.NextDamageTime && attackData.GetEventNumber(difficulty) == -1) { DoMeleeAttack(action, actor); - int repeatState = attackData.Repeat; + int repeatState = attackData.GetRepeatState(difficulty); if (repeatState > 0) { switch (repeatState) { case 1: { - action.NextDamageTime = gameTime + attackData.DamageDelay[difficulty]; + action.NextDamageTime = gameTime + attackData.GetDelay(difficulty); } case 2: { - if (action.RepeatIndex >= attackData.RepeatTimers.Length) + if (attackData.GetRepeatTimer(difficulty, action.RepeatIndex) < 0.0) { action.NextDamageTime = -1.0; } else { - float next = attackData.RepeatTimers.Get(action.RepeatIndex); - action.NextDamageTime = next + gameTime; + action.NextDamageTime = attackData.GetRepeatTimer(difficulty, action.RepeatIndex) + gameTime; action.RepeatIndex++; } } @@ -175,36 +170,33 @@ static void DoMeleeAttack(SF2_ChaserAttackAction_Melee action, SF2_ChaserEntity int difficulty = controller.Difficulty; bool attackEliminated = (controller.Flags & SFF_ATTACKWAITERS) != 0; - SF2ChaserBossProfileData data; - data = controller.GetProfileData(); - SF2ChaserBossProfileAttackData attackData; - data.GetAttack(action.GetAttackName(), attackData); - SF2BossProfileData originalData; - originalData = view_as(controller).GetProfileData(); - if (originalData.IsPvEBoss) + ChaserBossProfile data = controller.GetProfileDataEx(); + ChaserBossProfileBaseAttack attackData = action.ProfileData; + if (data.IsPvEBoss) { attackEliminated = true; } - float damage = attackData.Damage[difficulty]; + float damage = attackData.GetDamage(difficulty); if (SF_SpecialRound(SPECIALROUND_TINYBOSSES)) { damage *= 0.5; } - int damageType = attackData.DamageType[difficulty]; + int damageType = attackData.GetDamageType(difficulty); - float myPos[3], myEyePos[3], myEyeAng[3]; + float myPos[3], myEyePos[3], myEyeAng[3], offset[3]; actor.GetAbsOrigin(myPos); controller.GetEyePosition(myEyePos); actor.GetAbsAngles(myEyeAng); + data.GetEyes().GetOffsetPos(offset); - AddVectors(g_SlenderEyePosOffset[controller.Index], myEyeAng, myEyeAng); + AddVectors(offset, myEyeAng, myEyeAng); float viewPunch[3]; - viewPunch = attackData.PunchVelocity; + attackData.GetViewPunchAngles(difficulty, viewPunch); - float range = attackData.Range[difficulty]; - float spread = attackData.Spread[difficulty]; - float force = attackData.DamageForce[difficulty]; + float range = attackData.GetRange(difficulty); + float spread = attackData.GetFOV(difficulty); + float force = attackData.GetDamageForce(difficulty); bool hit = false; @@ -219,12 +211,12 @@ static void DoMeleeAttack(SF2_ChaserAttackAction_Melee action, SF2_ChaserEntity continue; } - if (!originalData.IsPvEBoss && !IsTargetValidForSlender(actor, building, attackEliminated)) + if (!data.IsPvEBoss && !IsTargetValidForSlender(actor, building, attackEliminated)) { continue; } - if (originalData.IsPvEBoss && !IsPvETargetValid(building)) + if (data.IsPvEBoss && !IsPvETargetValid(building)) { continue; } @@ -245,12 +237,12 @@ static void DoMeleeAttack(SF2_ChaserAttackAction_Melee action, SF2_ChaserEntity continue; } - if (!originalData.IsPvEBoss && !IsTargetValidForSlender(actor, building, attackEliminated)) + if (!data.IsPvEBoss && !IsTargetValidForSlender(actor, building, attackEliminated)) { continue; } - if (originalData.IsPvEBoss && !IsPvETargetValid(building)) + if (data.IsPvEBoss && !IsPvETargetValid(building)) { continue; } @@ -271,12 +263,12 @@ static void DoMeleeAttack(SF2_ChaserAttackAction_Melee action, SF2_ChaserEntity continue; } - if (!originalData.IsPvEBoss && !IsTargetValidForSlender(actor, building, attackEliminated)) + if (!data.IsPvEBoss && !IsTargetValidForSlender(actor, building, attackEliminated)) { continue; } - if (originalData.IsPvEBoss && !IsPvETargetValid(building)) + if (data.IsPvEBoss && !IsPvETargetValid(building)) { continue; } @@ -303,10 +295,10 @@ static void DoMeleeAttack(SF2_ChaserAttackAction_Melee action, SF2_ChaserEntity prop.GetClassname(class, sizeof(class)); float realDamage = damage; - if (attackData.DamagePercent[difficulty] > 0.0) + if (attackData.GetDamagePercent(difficulty) > 0.0) { realDamage = strcmp(class, "tank_boss", false) != 0 ? float(prop.GetProp(Prop_Send, "m_iMaxHealth")) : float(prop.GetProp(Prop_Data, "m_iMaxHealth")); - realDamage *= attackData.DamagePercent[difficulty]; + realDamage *= attackData.GetDamagePercent(difficulty); } SDKHooks_TakeDamage(prop.index, actor.index, actor.index, realDamage, 64, _, _, myEyePos, false); } @@ -317,12 +309,12 @@ static void DoMeleeAttack(SF2_ChaserAttackAction_Melee action, SF2_ChaserEntity { SF2_BasePlayer player = SF2_BasePlayer(i); - if (!originalData.IsPvEBoss && !IsTargetValidForSlender(actor, player, attackEliminated)) + if (!data.IsPvEBoss && !IsTargetValidForSlender(actor, player, attackEliminated)) { continue; } - if (originalData.IsPvEBoss && !IsPvETargetValid(player)) + if (data.IsPvEBoss && !IsPvETargetValid(player)) { continue; } @@ -343,9 +335,9 @@ static void DoMeleeAttack(SF2_ChaserAttackAction_Melee action, SF2_ChaserEntity ScaleVector(direction, force); float realDamage = damage; - if (attackData.DamagePercent[difficulty] > 0.0) + if (attackData.GetDamagePercent(difficulty) > 0.0) { - realDamage = float(player.GetProp(Prop_Data, "m_iMaxHealth")) * attackData.DamagePercent[difficulty]; + realDamage = float(player.GetProp(Prop_Data, "m_iMaxHealth")) * attackData.GetDamagePercent(difficulty); } if (controller.HasAttribute(SF2Attribute_DeathCamOnLowHealth) || attackData.DeathCamLowHealth) @@ -385,7 +377,7 @@ static void DoMeleeAttack(SF2_ChaserAttackAction_Melee action, SF2_ChaserEntity TF2_SetPlayerPowerPlay(player.index, false); } - attackData.ApplyDamageEffects(player, difficulty, SF2_ChaserBossEntity(actor.index)); + attackData.ApplyDamageEffects(player, difficulty, actor); // Add stress float stressScalar = damage / 125.0; @@ -396,9 +388,9 @@ static void DoMeleeAttack(SF2_ChaserAttackAction_Melee action, SF2_ChaserEntity ClientAddStress(player.index, 0.33 * stressScalar); } - ArrayList hitSounds = hit ? data.HitSounds : data.MissSounds; - SF2BossProfileSoundInfo info; - if (actor.SearchSoundsWithSectionName(hitSounds, action.GetAttackName(), info)) + ProfileObject hitSounds = hit ? data.GetHitSounds() : data.GetMissSounds(); + ProfileSound info; + if (actor.SearchSoundsWithSectionName(hitSounds, action.GetAttackName(), info, hit ? "hitenemy" : "missenemy")) { info.EmitSound(_, actor.index); } @@ -424,21 +416,21 @@ static void DoMeleeAttack(SF2_ChaserAttackAction_Melee action, SF2_ChaserEntity } else { - if (attackData.MissEffects != null) + if (attackData.GetMissEffects() != null) { - SlenderSpawnEffects(attackData.MissEffects, controller.Index, false); + SlenderSpawnEffects(attackData.GetMissEffects(), controller.Index, false); } } if (!SF_IsSlaughterRunMap()) { - if (attackData.Disappear[difficulty]) + if (attackData.GetDisappearAfterAttack(difficulty)) { controller.UnSpawn(true); } else { - if (hit && attackData.DisappearOnHit[difficulty]) + if (hit && attackData.GetDisappearAfterHit(difficulty)) { controller.UnSpawn(true); } @@ -454,30 +446,28 @@ static void OnAnimationEvent(SF2_ChaserAttackAction_Melee action, SF2_ChaserEnti } SF2NPC_Chaser controller = actor.Controller; - SF2ChaserBossProfileData data; - data = controller.GetProfileData(); - SF2ChaserBossProfileAttackData attackData; - data.GetAttack(action.GetAttackName(), attackData); + int difficulty = controller.Difficulty; - if (event == attackData.EventNumber) + if (event == action.ProfileData.GetEventNumber(difficulty)) { DoMeleeAttack(action, actor); } } -static bool IsTargetInMeleeChecks(SF2_ChaserEntity actor, SF2ChaserBossProfileAttackData data, CBaseEntity target, float range, float fov) +static bool IsTargetInMeleeChecks(SF2_ChaserEntity actor, ChaserBossProfileBaseAttack attack, CBaseEntity target, float range, float fov) { if (!target.IsValid()) { return false; } - float myPos[3], myEyePos[3], myEyeAng[3]; + float myPos[3], myEyePos[3], myEyeAng[3], offset[3]; actor.GetAbsOrigin(myPos); actor.Controller.GetEyePosition(myEyePos); actor.GetAbsAngles(myEyeAng); + actor.Controller.GetProfileDataEx().GetEyes().GetOffsetPos(offset); - AddVectors(g_SlenderEyePosOffset[actor.Controller.Index], myEyeAng, myEyeAng); + AddVectors(offset, myEyeAng, myEyeAng); float targetPos[3]; target.WorldSpaceCenter(targetPos); @@ -497,16 +487,18 @@ static bool IsTargetInMeleeChecks(SF2_ChaserEntity actor, SF2ChaserBossProfileAt return false; } - if (!data.HitThroughWalls[actor.Controller.Difficulty]) + if (!attack.GetHitThroughWalls(actor.Controller.Difficulty)) { - TR_TraceRayFilter(myEyePos, targetPos, + Handle trace = TR_TraceRayFilterEx(myEyePos, targetPos, CONTENTS_SOLID | CONTENTS_MOVEABLE | CONTENTS_MIST | CONTENTS_MONSTERCLIP | CONTENTS_GRATE | CONTENTS_WINDOW, RayType_EndPoint, TraceRayDontHitAnyEntity, actor.index); - if (TR_DidHit() && TR_GetEntityIndex() != target.index) + if (TR_DidHit(trace) && TR_GetEntityIndex(trace) != target.index) { + delete trace; return false; } + delete trace; } return true; diff --git a/addons/sourcemod/scripting/sf2/npc/entities/chaser/actions/attacks/projectile.sp b/addons/sourcemod/scripting/sf2/npc/entities/chaser/actions/attacks/projectile.sp index cf079605..b785171f 100644 --- a/addons/sourcemod/scripting/sf2/npc/entities/chaser/actions/attacks/projectile.sp +++ b/addons/sourcemod/scripting/sf2/npc/entities/chaser/actions/attacks/projectile.sp @@ -1,10 +1,102 @@ #pragma semicolon 1 +#pragma newdecls required + +methodmap ChaserBossProfileProjectileAttack < ChaserBossProfileBaseAttack +{ + public float GetSpeed(int difficulty) + { + float def = 1100.0; + def = this.GetDifficultyFloat("projectile_speed", difficulty, def); + def = this.GetDifficultyFloat("attack_projectile_speed", difficulty, def); + return def; + } + + public float GetBlastRadius(int difficulty) + { + float def = 128.0; + def = this.GetDifficultyFloat("projectile_radius", difficulty, def); + def = this.GetDifficultyFloat("attack_projectile_radius", difficulty, def); + return def; + } + + public float GetDeviation(int difficulty) + { + float def = 0.0; + def = this.GetDifficultyFloat("projectile_deviation", difficulty, def); + def = this.GetDifficultyFloat("attack_projectile_deviation", difficulty, def); + return def; + } + + public int GetProjectileCount(int difficulty) + { + int def = 1; + def = this.GetDifficultyInt("projectile_count", difficulty, def); + def = this.GetDifficultyInt("attack_projectile_count", difficulty, def); + return def; + } + + public bool GetCrits(int difficulty) + { + bool def = false; + def = this.GetDifficultyBool("projectile_crits", difficulty, def); + def = this.GetDifficultyBool("attack_projectile_crits", difficulty, def); + return def; + } + + property int ProjectileType + { + public get() + { + int def = SF2BossProjectileType_Fireball; + def = this.GetInt("projectiletype", def); + def = this.GetInt("attack_projectiletype", def); + return def; + } + } + + public void GetOffset(float buffer[3]) + { + this.GetVector("projectile_offset", buffer, buffer); + this.GetVector("attack_projectile_offset", buffer, buffer); + } + + public void GetFireballTrail(char[] buffer, int bufferSize) + { + this.GetString("fire_trail", buffer, bufferSize, FIREBALL_TRAIL); + } + + public void GetRocketModel(char[] buffer, int bufferSize) + { + this.GetString("rocket_model", buffer, bufferSize, ROCKET_MODEL); + } + + public float GetIceballSlowPercent(int difficulty) + { + float def = 0.55; + def = this.GetDifficultyFloat("projectile_iceslow_percent", difficulty, def); + def = this.GetDifficultyFloat("attack_projectile_iceslow_percent", difficulty, def); + return def; + } + + public float GetIceballSlowDuration(int difficulty) + { + float def = 2.0; + def = this.GetDifficultyFloat("projectile_iceslow_duration", difficulty, def); + def = this.GetDifficultyFloat("attack_projectile_iceslow_duration", difficulty, def); + return def; + } + + public void GetIceballTrail(char[] buffer, int bufferSize) + { + this.GetString("fire_iceball_trail", buffer, bufferSize, ICEBALL_TRAIL); + } +} static NextBotActionFactory g_Factory; methodmap SF2_ChaserAttackAction_Projectile < NextBotAction { - public SF2_ChaserAttackAction_Projectile(int attackIndex, const char[] attackName, float fireDelay) + public SF2_ChaserAttackAction_Projectile(const char[] attackName, ChaserBossProfileProjectileAttack data, float fireDelay) { if (g_Factory == null) { @@ -13,8 +105,8 @@ methodmap SF2_ChaserAttackAction_Projectile < NextBotAction g_Factory.SetCallback(NextBotActionCallbackType_Update, Update); g_Factory.SetEventCallback(EventResponderType_OnAnimationEvent, OnAnimationEvent); g_Factory.BeginDataMapDesc() - .DefineIntField("m_AttackIndex") .DefineStringField("m_AttackName") + .DefineIntField("m_ProfileData") .DefineFloatField("m_NextFireTime") .DefineIntField("m_RepeatIndex") .EndDataMapDesc(); @@ -22,25 +114,12 @@ methodmap SF2_ChaserAttackAction_Projectile < NextBotAction SF2_ChaserAttackAction_Projectile action = view_as(g_Factory.Create()); action.NextFireTime = fireDelay; - action.AttackIndex = attackIndex; action.SetAttackName(attackName); + action.ProfileData = data; return action; } - property int AttackIndex - { - public get() - { - return this.GetData("m_AttackIndex"); - } - - public set(int value) - { - this.SetData("m_AttackIndex", value); - } - } - public static void Initialize() { g_OnChaserGetAttackActionPFwd.AddFunction(null, OnChaserGetAttackAction); @@ -58,6 +137,19 @@ methodmap SF2_ChaserAttackAction_Projectile < NextBotAction this.SetDataString("m_AttackName", name); } + property ChaserBossProfileProjectileAttack ProfileData + { + public get() + { + return this.GetData("m_ProfileData"); + } + + public set(ChaserBossProfileProjectileAttack value) + { + this.SetData("m_ProfileData", value); + } + } + property float NextFireTime { public get() @@ -92,10 +184,8 @@ static Action OnChaserGetAttackAction(SF2_ChaserEntity chaser, const char[] atta return Plugin_Continue; } - SF2ChaserBossProfileData data; - data = chaser.Controller.GetProfileData(); - SF2ChaserBossProfileAttackData attackData; - data.GetAttack(attackName, attackData); + ChaserBossProfile data = chaser.Controller.GetProfileDataEx(); + ChaserBossProfileProjectileAttack attackData = view_as(data.GetAttack(attackName)); int difficulty = chaser.Controller.Difficulty; if (attackData.Type != SF2BossAttackType_Projectile) @@ -103,7 +193,7 @@ static Action OnChaserGetAttackAction(SF2_ChaserEntity chaser, const char[] atta return Plugin_Continue; } - result = SF2_ChaserAttackAction_Projectile(attackData.Index, attackData.Name, attackData.DamageDelay[difficulty] + GetGameTime()); + result = SF2_ChaserAttackAction_Projectile(attackName, attackData, attackData.GetDelay(difficulty) + GetGameTime()); return Plugin_Changed; } @@ -125,38 +215,34 @@ static int Update(SF2_ChaserAttackAction_Projectile action, SF2_ChaserEntity act } SF2NPC_Chaser controller = actor.Controller; - SF2ChaserBossProfileData data; - data = controller.GetProfileData(); - SF2ChaserBossProfileAttackData attackData; - data.GetAttack(action.GetAttackName(), attackData); + ChaserBossProfileProjectileAttack attackData = action.ProfileData; int difficulty = controller.Difficulty; float gameTime = GetGameTime(); - if (action.NextFireTime >= 0.0 && gameTime > action.NextFireTime && attackData.EventNumber == -1) + if (action.NextFireTime >= 0.0 && gameTime > action.NextFireTime && attackData.GetEventNumber(difficulty) == -1) { - FireProjectile(actor, action.GetAttackName()); + FireProjectile(actor, action, action.GetAttackName()); actor.ResetProfileAnimation(g_SlenderAnimationsList[SF2BossAnimation_ProjectileShoot], _, action.GetAttackName()); - int repeatState = attackData.Repeat; + int repeatState = attackData.GetRepeatState(difficulty); if (repeatState > 0) { switch (repeatState) { case 1: { - action.NextFireTime = gameTime + attackData.DamageDelay[difficulty]; + action.NextFireTime = gameTime + attackData.GetDelay(difficulty); } case 2: { - if (action.RepeatIndex >= attackData.RepeatTimers.Length) + if (attackData.GetRepeatTimer(difficulty, action.RepeatIndex) < 0.0) { action.NextFireTime = -1.0; } else { - float next = attackData.RepeatTimers.Get(action.RepeatIndex); - action.NextFireTime = next + gameTime; + action.NextFireTime = attackData.GetRepeatTimer(difficulty, action.RepeatIndex) + gameTime; action.RepeatIndex++; } } @@ -170,7 +256,7 @@ static int Update(SF2_ChaserAttackAction_Projectile action, SF2_ChaserEntity act return action.Continue(); } -static void FireProjectile(SF2_ChaserEntity actor, const char[] attackName) +static void FireProjectile(SF2_ChaserEntity actor, SF2_ChaserAttackAction_Projectile action, const char[] attackName) { SF2NPC_Chaser controller = actor.Controller; float targetPos[3], myPos[3], myAng[3]; @@ -191,86 +277,94 @@ static void FireProjectile(SF2_ChaserEntity actor, const char[] attackName) targetPos[2] = eyePos[2] + fwd[2] * 9001.0; } int difficulty = controller.Difficulty; - SF2ChaserBossProfileData data; - data = controller.GetProfileData(); - SF2ChaserBossProfileAttackData attackData; - data.GetAttack(attackName, attackData); - SF2BossProfileData originalData; - originalData = view_as(controller).GetProfileData(); + ChaserBossProfile data = controller.GetProfileDataEx(); + ChaserBossProfileProjectileAttack attackData = action.ProfileData; + ChaserBossProjectileData projectileData = data.GetProjectiles(); bool attackWaiters = (controller.Flags & SFF_ATTACKWAITERS) != 0; - if (originalData.IsPvEBoss) + if (data.IsPvEBoss) { attackWaiters = true; } - ArrayList projectileSounds = data.ProjectileShootSounds; - SF2BossProfileSoundInfo soundInfo; - if (actor.SearchSoundsWithSectionName(projectileSounds, attackName, soundInfo)) + ProfileSound soundInfo; + if (actor.SearchSoundsWithSectionName(data.GetProjectileShootSounds(), attackName, soundInfo, "attackshootprojectile")) { soundInfo.EmitSound(_, actor.index); } float effectPos[3]; - effectPos = attackData.ProjectileOffset; + attackData.GetOffset(effectPos); VectorTransform(effectPos, myPos, myAng, effectPos); - for (int i = 0; i < attackData.ProjectileCount[difficulty]; i++) + for (int i = 0; i < attackData.GetProjectileCount(difficulty); i++) { float direction[3], angle[3]; SubtractVectors(targetPos, effectPos, direction); - float deviation = attackData.ProjectileDeviation[difficulty]; + float deviation = attackData.GetDeviation(difficulty); - if (deviation != 0) - { - direction[0] += GetRandomFloat(-deviation, deviation); - direction[1] += GetRandomFloat(-deviation, deviation); - direction[2] += GetRandomFloat(-deviation, deviation); - } NormalizeVector(direction, direction); GetVectorAngles(direction, angle); + if (deviation != 0.0) + { + angle[0] += GetRandomFloat(-deviation, deviation); + angle[1] += GetRandomFloat(-deviation, deviation); + angle[2] += GetRandomFloat(-deviation, deviation); + } switch (attackData.ProjectileType) { case SF2BossProjectileType_Fireball: { - SF2_ProjectileFireball.Create(actor, effectPos, angle, attackData.ProjectileSpeed[difficulty], attackData.ProjectileDamage[difficulty], - attackData.ProjectileRadius[difficulty], data.FireballExplodeSound, attackData.FireballTrail, attackWaiters); + char trail[PLATFORM_MAX_PATH], explode[PLATFORM_MAX_PATH]; + attackData.GetFireballTrail(trail, sizeof(trail)); + projectileData.GetFireballExplodeSound(explode, sizeof(explode)); + SF2_ProjectileFireball.Create(actor, effectPos, angle, attackData.GetSpeed(difficulty), attackData.GetDamage(difficulty), + attackData.GetBlastRadius(difficulty), explode, trail, attackWaiters); } case SF2BossProjectileType_Iceball: { - SF2_ProjectileIceball.Create(actor, effectPos, angle, attackData.ProjectileSpeed[difficulty], attackData.ProjectileDamage[difficulty], - attackData.ProjectileRadius[difficulty], data.FireballExplodeSound, attackData.IceballTrail, attackData.IceballSlowdownDuration[difficulty], attackData.IceballSlowdownPercent[difficulty], data.IceballSlowSound, attackWaiters); + char trail[PLATFORM_MAX_PATH], explode[PLATFORM_MAX_PATH], slow[PLATFORM_MAX_PATH]; + attackData.GetFireballTrail(trail, sizeof(trail)); + projectileData.GetFireballExplodeSound(explode, sizeof(explode)); + projectileData.GetIceballSlowSound(explode, sizeof(explode)); + SF2_ProjectileIceball.Create(actor, effectPos, angle, attackData.GetSpeed(difficulty), attackData.GetDamage(difficulty), + attackData.GetBlastRadius(difficulty), explode, trail, attackData.GetIceballSlowDuration(difficulty), attackData.GetIceballSlowPercent(difficulty), slow, attackWaiters); } case SF2BossProjectileType_Rocket: { - SF2_ProjectileRocket.Create(actor, effectPos, angle, attackData.ProjectileSpeed[difficulty], attackData.ProjectileDamage[difficulty], - attackData.ProjectileRadius[difficulty], attackData.CritProjectiles[difficulty], data.RocketTrail, data.RocketExplodeParticle, data.RocketExplodeSound, attackData.RocketModel, attackWaiters); + char model[PLATFORM_MAX_PATH], trail[PLATFORM_MAX_PATH], explodeSound[PLATFORM_MAX_PATH], explodeParticle[64]; + attackData.GetRocketModel(model, sizeof(model)); + projectileData.GetRocketTrail(trail, sizeof(trail)); + projectileData.GetRocketExplodeSound(explodeSound, sizeof(explodeSound)); + projectileData.GetRocketExplodeParticle(explodeParticle, sizeof(explodeParticle)); + SF2_ProjectileRocket.Create(actor, effectPos, angle, attackData.GetSpeed(difficulty), attackData.GetDamage(difficulty), + attackData.GetBlastRadius(difficulty), attackData.GetCrits(difficulty), trail, explodeParticle, explodeSound, model, attackWaiters); } case SF2BossProjectileType_SentryRocket: { - SF2_ProjectileSentryRocket.Create(actor, effectPos, angle, attackData.ProjectileSpeed[difficulty], attackData.ProjectileDamage[difficulty], - attackData.ProjectileRadius[difficulty], attackData.CritProjectiles[difficulty], attackWaiters); + SF2_ProjectileSentryRocket.Create(actor, effectPos, angle, attackData.GetSpeed(difficulty), attackData.GetDamage(difficulty), + attackData.GetBlastRadius(difficulty), attackData.GetCrits(difficulty), attackWaiters); } case SF2BossProjectileType_Mangler: { - SF2_ProjectileCowMangler.Create(actor, effectPos, angle, attackData.ProjectileSpeed[difficulty], attackData.ProjectileDamage[difficulty], - attackData.ProjectileRadius[difficulty], attackWaiters); + SF2_ProjectileCowMangler.Create(actor, effectPos, angle, attackData.GetSpeed(difficulty), attackData.GetDamage(difficulty), + attackData.GetBlastRadius(difficulty), attackWaiters); } case SF2BossProjectileType_Grenade: { - SF2_ProjectileGrenade.Create(actor, effectPos, angle, attackData.ProjectileSpeed[difficulty], attackData.ProjectileDamage[difficulty], - attackData.ProjectileRadius[difficulty], attackData.CritProjectiles[difficulty], "pipebombtrail_blue", ROCKET_EXPLODE_PARTICLE, ROCKET_IMPACT, "models/weapons/w_models/w_grenade_grenadelauncher.mdl", attackWaiters); + SF2_ProjectileGrenade.Create(actor, effectPos, angle, attackData.GetSpeed(difficulty), attackData.GetDamage(difficulty), + attackData.GetBlastRadius(difficulty), attackData.GetCrits(difficulty), "pipebombtrail_blue", ROCKET_EXPLODE_PARTICLE, ROCKET_IMPACT, "models/weapons/w_models/w_grenade_grenadelauncher.mdl", attackWaiters); } case SF2BossProjectileType_Arrow: { - SF2_ProjectileArrow.Create(actor, effectPos, angle, attackData.ProjectileSpeed[difficulty], attackData.ProjectileDamage[difficulty], - attackData.CritProjectiles[difficulty], "pipebombtrail_blue", "weapons/fx/rics/arrow_impact_flesh2.wav", "models/weapons/w_models/w_arrow.mdl", attackWaiters); + SF2_ProjectileArrow.Create(actor, effectPos, angle, attackData.GetSpeed(difficulty), attackData.GetDamage(difficulty), + attackData.GetCrits(difficulty), "pipebombtrail_blue", "weapons/fx/rics/arrow_impact_flesh2.wav", "models/weapons/w_models/w_arrow.mdl", attackWaiters); } case SF2BossProjectileType_Baseball: { - SF2_ProjectileBaseball.Create(actor, effectPos, angle, attackData.ProjectileSpeed[difficulty], attackData.ProjectileDamage[difficulty], - attackData.CritProjectiles[difficulty], "models/weapons/w_models/w_baseball.mdl", attackWaiters); + SF2_ProjectileBaseball.Create(actor, effectPos, angle, attackData.GetSpeed(difficulty), attackData.GetDamage(difficulty), + attackData.GetCrits(difficulty), "models/weapons/w_models/w_baseball.mdl", attackWaiters); } } } @@ -284,13 +378,10 @@ static void OnAnimationEvent(SF2_ChaserAttackAction_Projectile action, SF2_Chase } SF2NPC_Chaser controller = actor.Controller; - SF2ChaserBossProfileData data; - data = controller.GetProfileData(); - SF2ChaserBossProfileAttackData attackData; - data.GetAttack(action.GetAttackName(), attackData); + ChaserBossProfileProjectileAttack attackData = action.ProfileData; - if (event == attackData.EventNumber) + if (event == attackData.GetEventNumber(controller.Difficulty)) { - FireProjectile(actor, action.GetAttackName()); + FireProjectile(actor, action, action.GetAttackName()); } } \ No newline at end of file diff --git a/addons/sourcemod/scripting/sf2/npc/entities/chaser/actions/attacks/tongue.sp b/addons/sourcemod/scripting/sf2/npc/entities/chaser/actions/attacks/tongue.sp index a4286682..669402bf 100644 --- a/addons/sourcemod/scripting/sf2/npc/entities/chaser/actions/attacks/tongue.sp +++ b/addons/sourcemod/scripting/sf2/npc/entities/chaser/actions/attacks/tongue.sp @@ -1,10 +1,126 @@ #pragma semicolon 1 +#pragma newdecls required + +methodmap ChaserBossProfileTongueAttack < ChaserBossProfileBaseAttack +{ + public float GetSpeed(int difficulty) + { + float def = 900.0; + ProfileObject obj = this.GetSection("tongue"); + if (obj != null) + { + def = obj.GetDifficultyFloat("speed", difficulty, def); + } + return def; + } + + public float GetPullScale(int difficulty) + { + float def = 6.0; + ProfileObject obj = this.GetSection("tongue"); + if (obj != null) + { + def = obj.GetDifficultyFloat("pull_scale", difficulty, def); + } + return def; + } + + public bool CanEscape(int difficulty) + { + bool def = true; + ProfileObject obj = this.GetSection("tongue"); + if (obj != null) + { + def = obj.GetDifficultyBool("can_escape", difficulty, def); + } + return def; + } + + public void GetMaterial(char[] buffer, int bufferSize) + { + ProfileObject obj = this.GetSection("tongue"); + if (obj != null) + { + obj.GetString("material", buffer, bufferSize); + } + } + + public void GetAttachment(char[] buffer, int bufferSize) + { + ProfileObject obj = this.GetSection("tongue"); + if (obj != null) + { + obj.GetString("attachment", buffer, bufferSize); + } + } + + public void GetOffset(float buffer[3]) + { + ProfileObject obj = this.GetSection("tongue"); + if (obj != null) + { + obj.GetVector("offset", buffer); + } + } + + public ProfileSound GetLaunchSounds() + { + ProfileSound def = null; + ProfileObject obj = this.GetSection("tongue"); + obj = obj != null ? obj.GetSection("sounds") : null; + if (obj != null) + { + def = view_as(obj.GetSection("launch")); + } + return def; + } + + public ProfileSound GetTongueHitSounds() + { + ProfileSound def = null; + ProfileObject obj = this.GetSection("tongue"); + obj = obj != null ? obj.GetSection("sounds") : null; + if (obj != null) + { + def = view_as(obj.GetSection("hit")); + } + return def; + } + + public ProfileSound GetTiedSounds() + { + ProfileSound def = null; + ProfileObject obj = this.GetSection("tongue"); + obj = obj != null ? obj.GetSection("sounds") : null; + if (obj != null) + { + def = view_as(obj.GetSection("tied")); + } + return def; + } + + public ProfileMasterAnimations GetTongueAnimations() + { + ProfileMasterAnimations def = null; + ProfileObject obj = this.GetSection("tongue"); + if (obj != null) + { + def = view_as(obj.GetSection("animations")); + } + return def; + } + + public void Precache() + { + + } +} static NextBotActionFactory g_Factory; methodmap SF2_ChaserAttackAction_Tongue < NextBotAction { - public SF2_ChaserAttackAction_Tongue(int attackIndex, const char[] attackName, float fireDelay) + public SF2_ChaserAttackAction_Tongue(const char[] attackName, ChaserBossProfileTongueAttack data, float fireDelay) { if (g_Factory == null) { @@ -15,8 +131,8 @@ methodmap SF2_ChaserAttackAction_Tongue < NextBotAction g_Factory.SetEventCallback(EventResponderType_OnCommandString, OnCommandString); g_Factory.SetEventCallback(EventResponderType_OnAnimationEvent, OnAnimationEvent); g_Factory.BeginDataMapDesc() - .DefineIntField("m_AttackIndex") .DefineStringField("m_AttackName") + .DefineIntField("m_ProfileData") .DefineFloatField("m_NextFireTime") .DefineEntityField("m_TongueEntity") .DefineEntityField("m_TongueEntityEnd") @@ -30,25 +146,12 @@ methodmap SF2_ChaserAttackAction_Tongue < NextBotAction SF2_ChaserAttackAction_Tongue action = view_as(g_Factory.Create()); action.NextFireTime = fireDelay; - action.AttackIndex = attackIndex; action.SetAttackName(attackName); + action.ProfileData = data; return action; } - property int AttackIndex - { - public get() - { - return this.GetData("m_AttackIndex"); - } - - public set(int value) - { - this.SetData("m_AttackIndex", value); - } - } - public static void Initialize() { g_OnPlayerJumpPFwd.AddFunction(null, OnJump); @@ -67,6 +170,19 @@ methodmap SF2_ChaserAttackAction_Tongue < NextBotAction this.SetDataString("m_AttackName", name); } + property ChaserBossProfileTongueAttack ProfileData + { + public get() + { + return this.GetData("m_ProfileData"); + } + + public set(ChaserBossProfileTongueAttack value) + { + this.SetData("m_ProfileData", value); + } + } + property float NextFireTime { public get() @@ -179,10 +295,8 @@ static Action OnChaserGetAttackAction(SF2_ChaserEntity chaser, const char[] atta return Plugin_Continue; } - SF2ChaserBossProfileData data; - data = chaser.Controller.GetProfileData(); - SF2ChaserBossProfileAttackData attackData; - data.GetAttack(attackName, attackData); + ChaserBossProfile data = chaser.Controller.GetProfileDataEx(); + ChaserBossProfileTongueAttack attackData = view_as(data.GetAttack(attackName)); int difficulty = chaser.Controller.Difficulty; if (attackData.Type != SF2BossAttackType_Tongue) @@ -190,7 +304,7 @@ static Action OnChaserGetAttackAction(SF2_ChaserEntity chaser, const char[] atta return Plugin_Continue; } - result = SF2_ChaserAttackAction_Tongue(attackData.Index, attackData.Name, attackData.DamageDelay[difficulty] + GetGameTime()); + result = SF2_ChaserAttackAction_Tongue(attackName, attackData, attackData.GetDelay(difficulty) + GetGameTime()); return Plugin_Changed; } @@ -262,13 +376,9 @@ static int Update(SF2_ChaserAttackAction_Tongue action, SF2_ChaserEntity actor, SF2NPC_Chaser controller = actor.Controller; bool attackEliminated = (controller.Flags & SFF_ATTACKWAITERS) != 0; - SF2ChaserBossProfileData data; - data = controller.GetProfileData(); - SF2ChaserBossProfileAttackData attackData; - data.GetAttack(action.GetAttackName(), attackData); - SF2BossProfileData originalData; - originalData = view_as(controller).GetProfileData(); - if (originalData.IsPvEBoss) + ChaserBossProfile data = controller.GetProfileDataEx(); + ChaserBossProfileTongueAttack attackData = action.ProfileData; + if (data.IsPvEBoss) { attackEliminated = true; } @@ -276,7 +386,7 @@ static int Update(SF2_ChaserAttackAction_Tongue action, SF2_ChaserEntity actor, float gameTime = GetGameTime(); - if (action.NextFireTime >= 0.0 && gameTime > action.NextFireTime && attackData.EventNumber == -1) + if (action.NextFireTime >= 0.0 && gameTime > action.NextFireTime && attackData.GetEventNumber(difficulty) == -1) { FireTongue(actor, action); @@ -310,16 +420,19 @@ static int Update(SF2_ChaserAttackAction_Tongue action, SF2_ChaserEntity actor, float worldSpace[3]; player.WorldSpaceCenter(worldSpace); - TR_TraceRayFilter(tonguePos, worldSpace, + Handle trace = TR_TraceRayFilterEx(tonguePos, worldSpace, CONTENTS_SOLID | CONTENTS_MOVEABLE | CONTENTS_MIST | CONTENTS_MONSTERCLIP | CONTENTS_GRATE | CONTENTS_WINDOW, RayType_EndPoint, TraceRayDontHitAnyEntity, tongueEnd.index); - if (TR_DidHit() && TR_GetEntityIndex() != player.index) + if (TR_DidHit(trace) && TR_GetEntityIndex(trace) != player.index) { + delete trace; continue; } - if (!attackData.TongueCanEscape[difficulty]) + delete trace; + + if (!attackData.CanEscape(difficulty)) { player.Stun(1.0, 1.0, TF_STUNFLAG_NOSOUNDOREFFECT | TF_STUNFLAG_BONKSTUCK); } @@ -327,7 +440,7 @@ static int Update(SF2_ChaserAttackAction_Tongue action, SF2_ChaserEntity actor, { player.Stun(2.0, 1.0, TF_STUNFLAG_SLOWDOWN); } - player.TakeDamage(_, actor.index, actor.index, attackData.Damage[difficulty], DMG_BULLET | DMG_PREVENT_PHYSICS_FORCE); + player.TakeDamage(_, actor.index, actor.index, attackData.GetDamage(difficulty), attackData.GetDamageType(difficulty)); tongueEnd.AcceptInput("ClearParent"); tongueEnd.Teleport(worldSpace, NULL_VECTOR, NULL_VECTOR); @@ -337,11 +450,11 @@ static int Update(SF2_ChaserAttackAction_Tongue action, SF2_ChaserEntity actor, action.TongueTime = 0.5 + gameTime; action.LatchedTarget = player; action.CaughtTarget = true; - attackData.TongueTiedSound.EmitSound(_, tongueEnd.index); - attackData.TongueHitSound.EmitSound(_, tongueEnd.index); + attackData.GetTiedSounds().EmitSound(_, tongueEnd.index); + attackData.GetTongueHitSounds().EmitSound(_, tongueEnd.index); player.IsLatched = true; player.LatchCount = GetRandomInt(6, 10); - if (!attackData.TongueCanEscape[difficulty]) + if (!attackData.CanEscape(difficulty)) { player.LatchCount = 999999; // I'm lazy } @@ -377,10 +490,7 @@ static void TongueThink(SF2_ChaserAttackAction_Tongue action, SF2_ChaserEntity a float gameTime = GetGameTime(); SF2NPC_Chaser controller = actor.Controller; int difficulty = controller.Difficulty; - SF2ChaserBossProfileData data; - data = controller.GetProfileData(); - SF2ChaserBossProfileAttackData attackData; - data.GetAttack(action.GetAttackName(), attackData); + ChaserBossProfileTongueAttack attackData = action.ProfileData; SF2_BasePlayer player = action.LatchedTarget; if (!player.IsValid || !player.IsAlive) @@ -394,16 +504,19 @@ static void TongueThink(SF2_ChaserAttackAction_Tongue action, SF2_ChaserEntity a tongueStart.GetAbsOrigin(tonguePos); player.WorldSpaceCenter(worldSpace); - TR_TraceRayFilter(tonguePos, worldSpace, + Handle trace = TR_TraceRayFilterEx(tonguePos, worldSpace, CONTENTS_SOLID | CONTENTS_MOVEABLE | CONTENTS_MIST | CONTENTS_MONSTERCLIP | CONTENTS_GRATE | CONTENTS_WINDOW, RayType_EndPoint, TraceRayDontHitAnyEntity, tongueStart.index); - if (TR_DidHit() && TR_GetEntityIndex() != player.index) + if (TR_DidHit(trace) && TR_GetEntityIndex(trace) != player.index) { Unlatch(action, true); + delete trace; return; } + delete trace; + INextBot bot = actor.MyNextBotPointer(); ILocomotion loco = bot.GetLocomotionInterface(); float myPos[3], targetPos[3]; @@ -413,7 +526,7 @@ static void TongueThink(SF2_ChaserAttackAction_Tongue action, SF2_ChaserEntity a if (action.TongueTime > -1.0 && action.TongueTime <= gameTime) { SF2_BasePlayer latched = action.LatchedTarget; - if (!attackData.TongueCanEscape[difficulty]) + if (!attackData.CanEscape(difficulty)) { latched.Stun(1.0, 1.0, TF_STUNFLAG_BONKSTUCK|TF_STUNFLAG_NOSOUNDOREFFECT); } @@ -427,10 +540,10 @@ static void TongueThink(SF2_ChaserAttackAction_Tongue action, SF2_ChaserEntity a SubtractVectors(myPos, targetPos, velocity); velocity[2] = 0.0; - ScaleVector(velocity, attackData.TonguePullScale[difficulty]); + ScaleVector(velocity, attackData.GetPullScale(difficulty)); player.SetPropVector(Prop_Data, "m_vecBaseVelocity", velocity); - player.TakeDamage(_, actor.index, actor.index, attackData.Damage[difficulty], DMG_BULLET | DMG_PREVENT_PHYSICS_FORCE); + player.TakeDamage(_, actor.index, actor.index, attackData.GetDamage(difficulty), attackData.GetDamageType(difficulty)); } loco.FaceTowards(targetPos); @@ -479,12 +592,9 @@ static void FireTongue(SF2_ChaserEntity actor, SF2_ChaserAttackAction_Tongue act actor.GetAbsOrigin(myPos); actor.GetAbsAngles(myAng); int difficulty = controller.Difficulty; - SF2ChaserBossProfileData data; - data = controller.GetProfileData(); - SF2ChaserBossProfileAttackData attackData; - data.GetAttack(action.GetAttackName(), attackData); + ChaserBossProfileTongueAttack attackData = action.ProfileData; - effectPos = attackData.TongueOffset; + attackData.GetOffset(effectPos); VectorTransform(effectPos, myPos, myAng, effectPos); CBaseEntity tongue = CBaseEntity(CreateEntityByName("move_rope")); @@ -502,14 +612,16 @@ static void FireTongue(SF2_ChaserEntity actor, SF2_ChaserAttackAction_Tongue act char buffer[PLATFORM_MAX_PATH]; tongue.KeyValue("Slack", "50"); - tongue.KeyValue("RopeMaterial", attackData.TongueMaterial); + attackData.GetMaterial(buffer, sizeof(buffer)); + tongue.KeyValue("RopeMaterial", buffer); FormatEx(buffer, sizeof(buffer), "rope_%i", controller.Index); tongue.KeyValue("NextKey", buffer); CBaseEntity tongueEnd = CBaseEntity(CreateEntityByName("move_rope")); tongueEnd.KeyValue("targetname", buffer); tongueEnd.KeyValue("Slack", "50"); - tongueEnd.KeyValue("RopeMaterial", attackData.TongueMaterial); + attackData.GetMaterial(buffer, sizeof(buffer)); + tongueEnd.KeyValue("RopeMaterial", buffer); tongueEnd.Teleport(effectPos, myAng, NULL_VECTOR); tongueEnd.SetMoveType(MOVETYPE_FLY); @@ -527,9 +639,9 @@ static void FireTongue(SF2_ChaserEntity actor, SF2_ChaserAttackAction_Tongue act NormalizeVector(shootAng, shootAng); GetVectorAngles(shootAng, shootAng); GetAngleVectors(shootAng, velocity, NULL_VECTOR, NULL_VECTOR); - ScaleVector(velocity, attackData.TongueSpeed[difficulty]); + ScaleVector(velocity, attackData.GetSpeed(difficulty)); - attackData.TongueLaunchSound.EmitSound(_, actor.index); + attackData.GetLaunchSounds().EmitSound(_, actor.index); CBaseEntity trail = CBaseEntity(CreateEntityByName("tf_projectile_grapplinghook")); trail.SetModel("models/roller.mdl"); @@ -567,18 +679,21 @@ static Action Timer_Think(Handle timer, any ref) } float pos[3], mins[3] = {-8.0, ... }, maxs[3] = {8.0, ... }; trail.GetAbsOrigin(pos); - TR_TraceHullFilter(pos, pos, mins, maxs, CONTENTS_SOLID | CONTENTS_MOVEABLE | CONTENTS_MIST | CONTENTS_MONSTERCLIP, TraceRayGrenade, trail.index); + Handle trace = TR_TraceHullFilterEx(pos, pos, mins, maxs, CONTENTS_SOLID | CONTENTS_MOVEABLE | CONTENTS_MIST | CONTENTS_MONSTERCLIP, TraceRayGrenade, trail.index); - if (TR_GetEntityIndex() == 0) + if (TR_GetEntityIndex(trace) == 0) { if (IsValidEntity(owner)) { RemoveEntity(owner); } RemoveEntity(trail.index); + delete trace; return Plugin_Stop; } + delete trace; + return Plugin_Continue; } @@ -588,15 +703,18 @@ static int OnCommandString(SF2_ChaserAttackAction_Tongue action, SF2_ChaserEntit int difficulty = controller.Difficulty; char animName[64]; float rate = 1.0, duration = 0.0, cycle = 0.0; - SF2ChaserBossProfileData data; - data = controller.GetProfileData(); - SF2ChaserBossProfileAttackData attackData; - data.GetAttack(action.GetAttackName(), attackData); + ChaserBossProfileTongueAttack attackData = action.ProfileData; + ProfileAnimation section = null; if (strcmp(command, "break tongue") == 0) { Unlatch(action, true); - if (attackData.Animations.GetAnimation("break", difficulty, animName, sizeof(animName), rate, duration, cycle)) + section = attackData.GetTongueAnimations().GetAnimation("break"); + if (section != null) { + section.GetAnimationName(difficulty, animName, sizeof(animName)); + rate = section.GetAnimationPlaybackRate(difficulty); + duration = section.GetDuration(difficulty); + cycle = section.GetAnimationCycle(difficulty); int sequence = LookupProfileAnimation(actor.index, animName); if (sequence != -1) { @@ -607,8 +725,13 @@ static int OnCommandString(SF2_ChaserAttackAction_Tongue action, SF2_ChaserEntit if (strcmp(command, "latch tongue") == 0 && !action.InPullAnimation) { - if (attackData.Animations.GetAnimation("pull", difficulty, animName, sizeof(animName), rate, duration, cycle)) + section = attackData.GetTongueAnimations().GetAnimation("break"); + if (section != null) { + section.GetAnimationName(difficulty, animName, sizeof(animName)); + rate = section.GetAnimationPlaybackRate(difficulty); + duration = section.GetDuration(difficulty); + cycle = section.GetAnimationCycle(difficulty); int sequence = LookupProfileAnimation(actor.index, animName); if (sequence != -1) { @@ -631,12 +754,9 @@ static void OnAnimationEvent(SF2_ChaserAttackAction_Tongue action, SF2_ChaserEnt } SF2NPC_Chaser controller = actor.Controller; - SF2ChaserBossProfileData data; - data = controller.GetProfileData(); - SF2ChaserBossProfileAttackData attackData; - data.GetAttack(action.GetAttackName(), attackData); + ChaserBossProfileTongueAttack attackData = action.ProfileData; - if (event == attackData.EventNumber) + if (event == attackData.GetEventNumber(controller.Difficulty)) { FireTongue(actor, action); } diff --git a/addons/sourcemod/scripting/sf2/npc/entities/chaser/actions/beatbox_freeze.sp b/addons/sourcemod/scripting/sf2/npc/entities/chaser/actions/beatbox_freeze.sp index 8ec201b0..9ff1ade0 100644 --- a/addons/sourcemod/scripting/sf2/npc/entities/chaser/actions/beatbox_freeze.sp +++ b/addons/sourcemod/scripting/sf2/npc/entities/chaser/actions/beatbox_freeze.sp @@ -1,4 +1,5 @@ #pragma semicolon 1 +#pragma newdecls required static NextBotActionFactory g_Factory; diff --git a/addons/sourcemod/scripting/sf2/npc/entities/chaser/actions/chase.sp b/addons/sourcemod/scripting/sf2/npc/entities/chaser/actions/chase.sp index c4b697e4..75999961 100644 --- a/addons/sourcemod/scripting/sf2/npc/entities/chaser/actions/chase.sp +++ b/addons/sourcemod/scripting/sf2/npc/entities/chaser/actions/chase.sp @@ -1,4 +1,5 @@ #pragma semicolon 1 +#pragma newdecls required static NextBotActionFactory g_Factory; @@ -38,10 +39,10 @@ static int OnStart(SF2_ChaserChaseAction action, SF2_ChaserEntity actor, NextBot return action.ChangeTo(SF2_ChaserIdleAction(), "My target is no longer valid!"); } - SF2ChaserBossProfileData data; - data = controller.GetProfileData(); + ChaserBossProfile data = controller.GetProfileDataEx(); + ChaserBossProfileChaseData chaseData = data.GetChaseBehavior(); - actor.CurrentChaseDuration = data.ChaseDuration[difficulty]; + actor.CurrentChaseDuration = chaseData.GetMaxChaseDuration(difficulty); if (actor.InitialChaseDuration > 0.0) { @@ -49,7 +50,7 @@ static int OnStart(SF2_ChaserChaseAction action, SF2_ChaserEntity actor, NextBot actor.InitialChaseDuration = 0.0; } - if (data.AlertOnChaseInfo.OnChangeState[difficulty]) + if (chaseData.GetChaseTogetherData().IsEnabled(difficulty) && chaseData.GetChaseTogetherData().ShouldStartOnStateChange(difficulty)) { actor.ForceChaseOtherBosses(); } @@ -67,12 +68,11 @@ static int Update(SF2_ChaserChaseAction action, SF2_ChaserEntity actor) return action.Continue(); } - SF2ChaserBossProfileData data; - data = controller.GetProfileData(); - SF2BossProfileData originalData; - originalData = view_as(controller).GetProfileData(); + ChaserBossProfile data = controller.GetProfileDataEx(); + ChaserBossProfileAlertData alertData = data.GetAlertBehavior(); + ChaserBossProfileChaseData chaseData = data.GetChaseBehavior(); - if (!originalData.IsPvEBoss && IsBeatBoxBeating(2) && actor.State != STATE_ATTACK && !actor.IsInChaseInitial) + if (!data.IsPvEBoss && IsBeatBoxBeating(2) && actor.State != STATE_ATTACK && !actor.IsInChaseInitial) { return action.SuspendFor(SF2_ChaserBeatBoxFreezeAction(actor.IsAttemptingToMove)); } @@ -82,7 +82,7 @@ static int Update(SF2_ChaserChaseAction action, SF2_ChaserEntity actor) int difficulty = controller.Difficulty; INextBot bot = actor.MyNextBotPointer(); bool attackEliminated = (controller.Flags & SFF_ATTACKWAITERS) != 0; - if (originalData.IsPvEBoss) + if (data.IsPvEBoss) { attackEliminated = true; } @@ -105,14 +105,14 @@ static int Update(SF2_ChaserChaseAction action, SF2_ChaserEntity actor) if (actor.CurrentChaseDuration <= 0.0) { actor.State = STATE_ALERT; - return action.ChangeTo(SF2_ChaserAlertAction(_, data.AlertData.RunOnSuspect[difficulty]), "Oh he got away..."); + return action.ChangeTo(SF2_ChaserAlertAction(_, alertData.ShouldRunOnSuspect(difficulty)), "Oh he got away..."); } } actor.RegisterProjectiles(); SF2_BasePlayer player = SF2_BasePlayer(target.index); - if (!originalData.IsPvEBoss && player.IsValid && player.HasEscaped) + if (!data.IsPvEBoss && player.IsValid && player.HasEscaped) { actor.State = STATE_IDLE; return action.ChangeTo(SF2_ChaserIdleAction(), "Our target escaped, that is no good!"); @@ -120,18 +120,18 @@ static int Update(SF2_ChaserChaseAction action, SF2_ChaserEntity actor) if (player.IsValid && player.CanSeeSlender(controller.Index, false, _, !attackEliminated)) { - float maxRange = data.ChaseDurationAddMaxRange[difficulty]; + float maxRange = chaseData.GetDurationTargetRange(difficulty); float distanceRatio = bot.GetRangeTo(player.index) / maxRange; if (maxRange > 0.0 && distanceRatio < 1.0) { - float durationTimeAddMin = data.ChaseDurationAddVisibleMin[difficulty]; - float durationTimeAddMax = data.ChaseDurationAddVisibleMax[difficulty]; - float durationAdd = durationTimeAddMin + ((durationTimeAddMax - durationTimeAddMin) * distanceRatio); + float addNear = chaseData.GetDurationAddVisibleTargetNear(difficulty); + float addFar = chaseData.GetDurationAddVisibleTargetFar(difficulty); + float durationAdd = addNear + ((addFar - addNear) * distanceRatio); actor.CurrentChaseDuration += durationAdd * GetGameFrameTime(); - if (actor.CurrentChaseDuration > data.ChaseDuration[difficulty]) + if (actor.CurrentChaseDuration > chaseData.GetMaxChaseDuration(difficulty)) { - actor.CurrentChaseDuration = data.ChaseDuration[difficulty]; + actor.CurrentChaseDuration = chaseData.GetMaxChaseDuration(difficulty); } } } @@ -153,9 +153,9 @@ static int Update(SF2_ChaserChaseAction action, SF2_ChaserEntity actor) } } - if (data.ChaseOnLookData.Enabled[difficulty] && controller.ChaseOnLookTargets.FindValue(target.index) != -1) + if (data.GetChaseOnLookData().IsEnabled(difficulty) && controller.ChaseOnLookTargets.FindValue(target.index) != -1) { - actor.CurrentChaseDuration = data.ChaseDuration[difficulty]; + actor.CurrentChaseDuration = chaseData.GetMaxChaseDuration(difficulty); } if (gameTime >= actor.NextVoiceTime && !actor.IsAttacking) @@ -177,7 +177,7 @@ static void OnResume(SF2_ChaserChaseAction action, SF2_ChaserEntity actor) SF2NPC_Chaser controller = actor.Controller; if (controller.IsValid()) { - if (controller.GetProfileData().StunData.ChaseInitialOnEnd[controller.Difficulty]) + if (controller.GetProfileDataEx().GetStunBehavior().CanChaseInitialOnEnd(controller.Difficulty)) { actor.PerformVoice(SF2BossSound_ChaseInitial); } @@ -192,6 +192,7 @@ static void OnEnd(SF2_ChaserChaseAction action, SF2_ChaserEntity actor) return; } SF2NPC_Chaser controller = actor.Controller; + ChaserBossProfile data = controller.GetProfileDataEx(); actor.EndCloak(); PathFollower path = actor.Controller.Path; float gameTime = GetGameTime(); @@ -204,18 +205,14 @@ static void OnEnd(SF2_ChaserChaseAction action, SF2_ChaserEntity actor) int difficulty = actor.Controller.Difficulty; if (actor.FollowedCompanionChase) { - SF2ChaserBossProfileData data; - data = actor.Controller.GetProfileData(); - actor.FollowCooldownChase = GetGameTime() + data.AlertOnChaseInfo.FollowCooldown[difficulty]; + actor.FollowCooldownChase = GetGameTime() + data.GetChaseBehavior().GetChaseTogetherData().GetFollowCooldown(difficulty); } if (actor.Teleporters != null) { actor.Teleporters.Clear(); } - SF2ChaserBossProfileData chaserData; - chaserData = actor.Controller.GetProfileData(); - float cooldown = chaserData.AutoChaseAfterChaseCooldown[difficulty]; + float cooldown = data.GetAutoChaseData().GetCooldownAfterChase(difficulty); if (cooldown > 0.0) { float nextTime = gameTime + cooldown; diff --git a/addons/sourcemod/scripting/sf2/npc/entities/chaser/actions/chaseinitial.sp b/addons/sourcemod/scripting/sf2/npc/entities/chaser/actions/chaseinitial.sp index 2f249f60..cd200811 100644 --- a/addons/sourcemod/scripting/sf2/npc/entities/chaser/actions/chaseinitial.sp +++ b/addons/sourcemod/scripting/sf2/npc/entities/chaser/actions/chaseinitial.sp @@ -1,4 +1,5 @@ #pragma semicolon 1 +#pragma newdecls required static NextBotActionFactory g_Factory; @@ -25,10 +26,8 @@ methodmap SF2_ChaserChaseInitialAction < NextBotAction return false; } - SF2NPC_BaseNPC baseController = view_as(actor.Controller); - SF2BossProfileData data; - data = baseController.GetProfileData(); - if (!data.AnimationData.HasAnimationSection(g_SlenderAnimationsList[SF2BossAnimation_ChaseInitial])) + ChaserBossProfile data = actor.Controller.GetProfileDataEx(); + if (!data.GetAnimations().HasAnimationSection(g_SlenderAnimationsList[SF2BossAnimation_ChaseInitial])) { return false; } @@ -39,21 +38,14 @@ methodmap SF2_ChaserChaseInitialAction < NextBotAction static NextBotAction InitialContainedAction(SF2_ChaserChaseInitialAction action, SF2_ChaserEntity actor) { - SF2NPC_BaseNPC baseController = view_as(actor.Controller); - SF2BossProfileData data; - data = baseController.GetProfileData(); - char animName[64]; - float rate = 1.0, duration = 0.0, cycle = 0.0; - int difficulty = baseController.Difficulty; + SF2NPC_Chaser controller = actor.Controller; + ChaserBossProfile data = controller.GetProfileDataEx(); actor.IsInChaseInitial = true; - if (data.AnimationData.GetAnimation(g_SlenderAnimationsList[SF2BossAnimation_ChaseInitial], difficulty, animName, sizeof(animName), rate, duration, cycle)) + ProfileAnimation section = data.GetAnimations().GetAnimation(g_SlenderAnimationsList[SF2BossAnimation_ChaseInitial]); + if (section != null) { - int sequence = LookupProfileAnimation(actor.index, animName); - if (sequence != -1) - { - return SF2_PlaySequenceAndWait(sequence, duration, rate, cycle); - } + return SF2_PlaySequenceAndWaitEx(g_SlenderAnimationsList[SF2BossAnimation_ChaseInitial]); } return NULL_ACTION; diff --git a/addons/sourcemod/scripting/sf2/npc/entities/chaser/actions/chaselayer.sp b/addons/sourcemod/scripting/sf2/npc/entities/chaser/actions/chaselayer.sp index f6086962..aa872956 100644 --- a/addons/sourcemod/scripting/sf2/npc/entities/chaser/actions/chaselayer.sp +++ b/addons/sourcemod/scripting/sf2/npc/entities/chaser/actions/chaselayer.sp @@ -1,4 +1,5 @@ #pragma semicolon 1 +#pragma newdecls required static NextBotActionFactory g_Factory; @@ -47,8 +48,8 @@ static int Update(SF2_ChaserChaseLayerAction action, SF2_ChaserEntity actor, flo ILocomotion loco = bot.GetLocomotionInterface(); bool tooClose = target.IsValid() && - (interrputConditions & COND_ENEMYVISIBLE) != 0 && - bot.IsRangeLessThan(target.index, 8.0); + (interrputConditions & COND_ENEMYVISIBLE_NOGLASS) != 0 && + bot.GetRangeSquaredTo(target.index) <= 32.0; if (tooClose && path.IsValid()) { @@ -56,19 +57,15 @@ static int Update(SF2_ChaserChaseLayerAction action, SF2_ChaserEntity actor, flo } else if (target.IsValid()) { - float pos[3]; - target.GetAbsOrigin(pos); + int pathTo = target.index; if (actor.Teleporters.Length > 0) { - CBaseEntity(actor.Teleporters.Get(0)).GetAbsOrigin(pos); + pathTo = actor.Teleporters.Get(0); } - if (!bot.IsRangeLessThanEx(pos, 8.0)) + if ((interrputConditions & COND_NEWENEMY) != 0 || path.GetAge() > 0.3 || (path.IsValid() && (path.GetLength() - path.GetCursorPosition()) < 256.0)) { - if ((interrputConditions & COND_NEWENEMY) != 0 || path.GetAge() > 0.3 || (path.IsValid() && (path.GetLength() - path.GetCursorPosition()) < 256.0)) - { - path.ComputeToPos(bot, pos); - } + path.ComputeToTarget(bot, pathTo); } } @@ -83,6 +80,32 @@ static int Update(SF2_ChaserChaseLayerAction action, SF2_ChaserEntity actor, flo actor.IsAttemptingToMove = true; } + if (target.IsValid()) + { + bool lookAt = false; + if (tooClose || controller.HasAttribute(SF2Attribute_AlwaysLookAtTarget) || controller.HasAttribute(SF2Attribute_AlwaysLookAtTargetWhileChasing)) + { + lookAt = true; + } + + if ((interrputConditions & COND_ENEMYVISIBLE) == 0) + { + lookAt = false; + } + + if (actor.IsKillingSomeone) + { + lookAt = false; + } + + if (lookAt) + { + float pos[3]; + target.GetAbsOrigin(pos); + loco.FaceTowards(pos); + } + } + return action.Continue(); } @@ -101,7 +124,7 @@ static int OnResume(SF2_ChaserChaseLayerAction action, SF2_ChaserEntity actor, N SF2NPC_Chaser controller = actor.Controller; if (controller.IsValid()) { - if (controller.GetProfileData().StunData.ChaseInitialOnEnd[controller.Difficulty] && SF2_ChaserChaseInitialAction.IsPossible(actor)) + if (controller.GetProfileDataEx().GetStunBehavior().CanChaseInitialOnEnd(controller.Difficulty) && SF2_ChaserChaseInitialAction.IsPossible(actor)) { return action.SuspendFor(SF2_ChaserChaseInitialAction()); } diff --git a/addons/sourcemod/scripting/sf2/npc/entities/chaser/actions/death.sp b/addons/sourcemod/scripting/sf2/npc/entities/chaser/actions/death.sp index 1d0942d1..4c6ff7e7 100644 --- a/addons/sourcemod/scripting/sf2/npc/entities/chaser/actions/death.sp +++ b/addons/sourcemod/scripting/sf2/npc/entities/chaser/actions/death.sp @@ -1,4 +1,5 @@ #pragma semicolon 1 +#pragma newdecls required static NextBotActionFactory g_Factory; @@ -41,9 +42,7 @@ methodmap SF2_ChaserDeathAction < NextBotAction static NextBotAction InitialContainedAction(SF2_ChaserDeathAction action, SF2_ChaserEntity actor) { SF2NPC_Chaser controller = actor.Controller; - SF2BossProfileData originalData; - originalData = view_as(controller).GetProfileData(); - int difficulty = controller.Difficulty; + ChaserBossProfile data = controller.GetProfileDataEx(); INextBot bot = actor.MyNextBotPointer(); ILocomotion loco = bot.GetLocomotionInterface(); @@ -54,24 +53,18 @@ static NextBotAction InitialContainedAction(SF2_ChaserDeathAction action, SF2_Ch actor.EndCloak(); - char animName[64]; - float rate = 1.0, duration = 0.0, cycle = 0.0; actor.PerformVoice(SF2BossSound_Death); actor.State = STATE_DEATH; - if (originalData.IsPvEBoss) + if (data.IsPvEBoss) { KillPvEBoss(actor.index); } - if (originalData.AnimationData.GetAnimation(g_SlenderAnimationsList[SF2BossAnimation_Death], difficulty, animName, sizeof(animName), rate, duration, cycle)) + if (data.GetAnimations().HasAnimationSection(g_SlenderAnimationsList[SF2BossAnimation_Death])) { - int sequence = actor.SelectProfileAnimation(g_SlenderAnimationsList[SF2BossAnimation_Death], rate, duration, cycle); - if (sequence != -1) - { - return SF2_PlaySequenceAndWait(sequence, duration, rate, cycle); - } + return SF2_PlaySequenceAndWaitEx(g_SlenderAnimationsList[SF2BossAnimation_Death]); } return NULL_ACTION; @@ -80,33 +73,36 @@ static NextBotAction InitialContainedAction(SF2_ChaserDeathAction action, SF2_Ch static int OnStart(SF2_ChaserDeathAction action, SF2_ChaserEntity actor, NextBotAction priorAction) { SF2NPC_Chaser controller = actor.Controller; - SF2ChaserBossProfileData data; - data = controller.GetProfileData(); + ChaserBossProfile data = controller.GetProfileDataEx(); + ChaserBossProfileDeathData deathData = data.GetDeathBehavior(); actor.GroundSpeedOverride = true; int difficulty = controller.Difficulty; - if (data.DeathData.StartEffects != null) + if (deathData.GetOnStartEffects() != null) { float pos[3], ang[3]; actor.GetAbsOrigin(pos); actor.GetAbsAngles(ang); - SlenderSpawnEffects(data.DeathData.StartEffects, controller.Index, false, pos, ang, _, _, true); + SlenderSpawnEffects(deathData.GetOnStartEffects(), controller.Index, false, pos, ang, _, _, true); } - if (data.DeathData.KeyDrop) + if (deathData.KeyDrop) { - if (SF_IsBoxingMap() && data.BoxingBoss && !g_SlenderBoxingBossIsKilled[controller.Index] && !view_as(controller).GetProfileData().IsPvEBoss) + char model[PLATFORM_MAX_PATH], trigger[64]; + deathData.GetKeyModel(model, sizeof(model)); + deathData.GetKeyTrigger(trigger, sizeof(trigger)); + if (SF_IsBoxingMap() && data.BoxingBoss && !g_SlenderBoxingBossIsKilled[controller.Index] && data.IsPvEBoss) { g_SlenderBoxingBossKilled++; if ((g_SlenderBoxingBossKilled == g_SlenderBoxingBossCount)) { - NPC_DropKey(controller.Index, data.DeathData.KeyModel, data.DeathData.KeyTrigger); + NPC_DropKey(controller.Index, model, trigger); } g_SlenderBoxingBossIsKilled[controller.Index] = true; } else { - NPC_DropKey(controller.Index, data.DeathData.KeyModel, data.DeathData.KeyTrigger); + NPC_DropKey(controller.Index, model, trigger); } } @@ -115,11 +111,14 @@ static int OnStart(SF2_ChaserDeathAction action, SF2_ChaserEntity actor, NextBot actor.RemoveAllGestures(); CBaseNPC_RemoveAllLayers(actor.index); - if (data.DeathData.AddHealthPerDeath[difficulty] > 0.0) + if (deathData.GetAddHealthPerDeath(difficulty) > 0.0) { - controller.SetDeathHealth(difficulty, controller.GetDeathHealth(difficulty) + data.DeathData.AddHealthPerDeath[difficulty]); + controller.SetDeathHealth(difficulty, controller.GetDeathHealth(difficulty) + deathData.GetAddHealthPerDeath(difficulty)); } + controller.SetAddSpeed(deathData.GetAddRunSpeed(difficulty)); + controller.SetAddAcceleration(deathData.GetAddAcceleration(difficulty)); + return action.Continue(); } @@ -142,21 +141,21 @@ static void OnEnd(SF2_ChaserDeathAction action, SF2_ChaserEntity actor) return; } - SF2ChaserBossProfileData data; - data = controller.GetProfileData(); + ChaserBossProfile data = controller.GetProfileDataEx(); + ChaserBossProfileDeathData deathData = data.GetDeathBehavior(); - if (data.DeathData.EndEffects != null) + if (deathData.GetOnEndEffects() != null) { float pos[3], ang[3]; actor.GetAbsOrigin(pos); actor.GetAbsAngles(ang); - SlenderSpawnEffects(data.DeathData.EndEffects, controller.Index, false, pos, ang, _, _, true); + SlenderSpawnEffects(deathData.GetOnEndEffects(), controller.Index, false, pos, ang, _, _, true); } - if (data.DeathData.RemoveOnDeath) + if (deathData.RemoveOnDeath) { SpawnGibs(actor); - if (data.DeathData.RagdollOnDeath) + if (deathData.RagdollOnDeath) { actor.AcceptInput("BecomeRagdoll"); } @@ -224,12 +223,12 @@ static void OnEnd(SF2_ChaserDeathAction action, SF2_ChaserEntity actor) controller.Remove(); } } - else if (data.DeathData.DisappearOnDeath) + else if (deathData.DisappearOnDeath) { SpawnGibs(actor); controller.UnSpawn(true); } - else if (data.DeathData.RagdollOnDeath) + else if (deathData.RagdollOnDeath) { actor.AcceptInput("BecomeRagdoll"); } @@ -249,9 +248,9 @@ static void OnAnimationEvent(SF2_ChaserDeathAction action, SF2_ChaserEntity acto static void SpawnGibs(SF2_ChaserEntity actor) { SF2NPC_Chaser controller = actor.Controller; - SF2ChaserBossProfileData data; - data = controller.GetProfileData(); - if (data.DeathData.Gibs == null) + ChaserBossProfile data = controller.GetProfileDataEx(); + ChaserBossProfileDeathData deathData = data.GetDeathBehavior(); + if (deathData.GetGibs() == null) { return; } @@ -259,7 +258,7 @@ static void SpawnGibs(SF2_ChaserEntity actor) char model[PLATFORM_MAX_PATH]; actor.WorldSpaceCenter(pos); actor.GetAbsAngles(ang); - for (int i = 0; i < data.DeathData.Gibs.Length; i++) + for (int i = 0; i < deathData.GetGibs().Size; i++) { ang[1] = GetRandomFloat(-180.0, 180.0); @@ -269,7 +268,13 @@ static void SpawnGibs(SF2_ChaserEntity actor) } vel[2] = GetRandomFloat(-300.0, 300.0); - data.DeathData.Gibs.GetString(i, model, sizeof(model)); + char name[64]; + data.GetRages().GetKeyNameFromIndex(i, name, sizeof(name)); + if (strcmp(name, "skin") == 0) + { + continue; + } + deathData.GetGibs().GetString(name, model, sizeof(model)); if (strlen(model) > 0) { @@ -284,7 +289,7 @@ static void SpawnGibs(SF2_ChaserEntity actor) SetEntityCollisionGroup(gib.index, 1); gib.SetProp(Prop_Send, "m_usSolidFlags", 0); gib.SetProp(Prop_Send, "m_nSolidType", 2); - gib.SetProp(Prop_Send, "m_nSkin", data.DeathData.GibSkin); + gib.SetProp(Prop_Send, "m_nSkin", deathData.GibSkin); int effects = 16 | 64; gib.SetProp(Prop_Send, "m_fEffects", effects); diff --git a/addons/sourcemod/scripting/sf2/npc/entities/chaser/actions/despawn.sp b/addons/sourcemod/scripting/sf2/npc/entities/chaser/actions/despawn.sp index 85ba7791..cd4c37e6 100644 --- a/addons/sourcemod/scripting/sf2/npc/entities/chaser/actions/despawn.sp +++ b/addons/sourcemod/scripting/sf2/npc/entities/chaser/actions/despawn.sp @@ -1,4 +1,5 @@ #pragma semicolon 1 +#pragma newdecls required static NextBotActionFactory g_Factory; diff --git a/addons/sourcemod/scripting/sf2/npc/entities/chaser/actions/flee_to_heal.sp b/addons/sourcemod/scripting/sf2/npc/entities/chaser/actions/flee_to_heal.sp index 40bc5c64..11caa21c 100644 --- a/addons/sourcemod/scripting/sf2/npc/entities/chaser/actions/flee_to_heal.sp +++ b/addons/sourcemod/scripting/sf2/npc/entities/chaser/actions/flee_to_heal.sp @@ -1,4 +1,5 @@ #pragma semicolon 1 +#pragma newdecls required static NextBotActionFactory g_Factory; @@ -135,20 +136,25 @@ methodmap SF2_ChaserFleeToHealAction < NextBotAction static NextBotAction InitialContainedAction(SF2_ChaserFleeToHealAction action, SF2_ChaserEntity actor) { SF2NPC_Chaser controller = actor.Controller; - SF2ChaserBossProfileData data; - data = controller.GetProfileData(); - SF2ChaserRageInfo rageInfo; - data.Rages.GetArray(actor.RageIndex, rageInfo, sizeof(rageInfo)); - action.HealDuration = rageInfo.HealDuration; - action.HealTime = rageInfo.HealDelay; + ChaserBossProfile data = controller.GetProfileDataEx(); + char name[64]; + data.GetRages().GetSectionNameFromIndex(actor.RageIndex, name, sizeof(name)); + ChaserBossProfileRageData rageData = view_as(data.GetRages().GetSection(name)); + action.HealDuration = rageData.HealDuration; + action.HealTime = rageData.HealDelay; char animName[64]; float rate = 1.0, duration = 0.0, cycle = 0.0; int difficulty = controller.Difficulty; action.IsHealing = false; action.HasPath = false; action.FleeTime = GetRandomFloat(5.0, 10.0); - if (rageInfo.Animations.GetAnimation("start", difficulty, animName, sizeof(animName), rate, duration, cycle)) + ProfileAnimation section = rageData.GetAnimations().GetAnimation("start"); + if (section != null) { + section.GetAnimationName(difficulty, animName, sizeof(animName)); + rate = section.GetAnimationPlaybackRate(difficulty); + duration = section.GetDuration(difficulty); + cycle = section.GetAnimationCycle(difficulty); int sequence = LookupProfileAnimation(actor.index, animName); if (sequence != -1) { @@ -169,12 +175,10 @@ static int Update(SF2_ChaserFleeToHealAction action, SF2_ChaserEntity actor, flo INextBot bot = actor.MyNextBotPointer(); ILocomotion loco = bot.GetLocomotionInterface(); SF2NPC_Chaser controller = actor.Controller; - SF2ChaserBossProfileData data; - data = controller.GetProfileData(); - SF2BossProfileData originalData; - originalData = view_as(controller).GetProfileData(); - SF2ChaserRageInfo rageInfo; - data.Rages.GetArray(actor.RageIndex, rageInfo, sizeof(rageInfo)); + ChaserBossProfile data = controller.GetProfileDataEx(); + char name[64]; + data.GetRages().GetSectionNameFromIndex(actor.RageIndex, name, sizeof(name)); + ChaserBossProfileRageData rageData = view_as(data.GetRages().GetSection(name)); PathFollower path = controller.Path; int difficulty = controller.Difficulty; float gameTime = GetGameTime(); @@ -182,12 +186,12 @@ static int Update(SF2_ChaserFleeToHealAction action, SF2_ChaserEntity actor, flo if (!action.IsHealing && !action.HasPath) { actor.IsRunningAway = true; - if (rageInfo.HealCloak) + if (rageData.HealCloak) { actor.StartCloak(); } CNavArea area = actor.GetLastKnownArea(); - SurroundingAreasCollector collector = TheNavMesh.CollectSurroundingAreas(area, GetRandomFloat(rageInfo.FleeRange[0], rageInfo.FleeRange[1])); + SurroundingAreasCollector collector = TheNavMesh.CollectSurroundingAreas(area, GetRandomFloat(rageData.FleeMinRange, rageData.FleeMaxRange)); int areaCount = collector.Count(); ArrayList areaArray = new ArrayList(1, areaCount); int validAreaCount = 0; @@ -239,10 +243,14 @@ static int Update(SF2_ChaserFleeToHealAction action, SF2_ChaserEntity actor, flo if (!action.PlayedAnimation) { char animName[64]; - float rate = 1.0, duration = 0.0, cycle = 0.0; - if (rageInfo.Animations.GetAnimation("healing", difficulty, animName, sizeof(animName), rate, duration, cycle)) + float rate = 1.0, cycle = 0.0; + ProfileAnimation section = rageData.GetAnimations().GetAnimation("healing"); + if (section != null) { - action.HealAnimationDuration = duration; + section.GetAnimationName(difficulty, animName, sizeof(animName)); + action.HealAnimationDuration = section.GetDuration(difficulty); + rate = section.GetAnimationPlaybackRate(difficulty); + cycle = section.GetAnimationCycle(difficulty); int sequence = LookupProfileAnimation(actor.index, animName); if (sequence != -1) { @@ -262,16 +270,16 @@ static int Update(SF2_ChaserFleeToHealAction action, SF2_ChaserEntity actor, flo { if (!action.PlayedSound) { - actor.PerformVoiceEx(_, _, rageInfo.HealSounds, true); + actor.PerformVoiceEx(_, _, rageData.GetHealSounds(), true); action.PlayedSound = true; } - float amount = actor.MaxHealth * rageInfo.HealAmount; - if (!data.DeathData.Enabled[difficulty]) + float amount = actor.MaxHealth * rageData.HealAmount; + if (!data.GetDeathBehavior().IsEnabled(difficulty)) { - amount = actor.MaxStunHealth * rageInfo.HealAmount; + amount = actor.MaxStunHealth * rageData.HealAmount; } - float increase = LerpFloats(0.0, amount, GetGameFrameTime() * (1.0 / rageInfo.HealDuration)); - if (data.DeathData.Enabled[difficulty]) + float increase = LerpFloats(0.0, amount, GetGameFrameTime() * (1.0 / rageData.HealDuration)); + if (data.GetDeathBehavior().IsEnabled(difficulty)) { actor.SetProp(Prop_Data, "m_iHealth", RoundToFloor(increase + actor.GetProp(Prop_Data, "m_iHealth"))); if (float(actor.GetProp(Prop_Data, "m_iHealth")) > actor.MaxHealth) @@ -287,7 +295,7 @@ static int Update(SF2_ChaserFleeToHealAction action, SF2_ChaserEntity actor, flo actor.StunHealth = actor.MaxStunHealth; } } - if (originalData.Healthbar) + if (data.Healthbar) { UpdateHealthBar(controller.Index); SetHealthBarColor(true); diff --git a/addons/sourcemod/scripting/sf2/npc/entities/chaser/actions/idle.sp b/addons/sourcemod/scripting/sf2/npc/entities/chaser/actions/idle.sp index b8c2d8b9..95ef612f 100644 --- a/addons/sourcemod/scripting/sf2/npc/entities/chaser/actions/idle.sp +++ b/addons/sourcemod/scripting/sf2/npc/entities/chaser/actions/idle.sp @@ -1,4 +1,5 @@ #pragma semicolon 1 +#pragma newdecls required static NextBotActionFactory g_Factory; @@ -75,13 +76,14 @@ static int OnStart(SF2_ChaserIdleAction action, SF2_ChaserEntity actor, NextBotA { INextBot bot = actor.MyNextBotPointer(); SF2NPC_Chaser controller = actor.Controller; - SF2ChaserBossProfileData data; - data = controller.GetProfileData(); + ChaserBossProfile data = controller.GetProfileDataEx(); + ChaserBossProfileIdleData idleData = data.GetIdleBehavior(); + ChaserBossProfileSmellData smellData = data.GetSmellData(); int difficulty = controller.Difficulty; float gameTime = GetGameTime(); - action.NextTurnTime = gameTime + GetRandomFloat(data.IdleData.TurnMinTime[difficulty], data.IdleData.TurnMaxTime[difficulty]); - action.NextWanderTime = gameTime + GetRandomFloat(data.WanderEnterTimeMin[difficulty], data.WanderEnterTimeMax[difficulty]); + action.NextTurnTime = gameTime + GetRandomFloat(idleData.GetTurnMinCooldown(difficulty), idleData.GetTurnMaxCooldown(difficulty)); + action.NextWanderTime = gameTime + GetRandomFloat(data.GetWanderEnterMinTime(difficulty), data.GetWanderEnterMaxTime(difficulty)); action.InitialState = true; bot.GetLocomotionInterface().Stop(); @@ -98,16 +100,19 @@ static int OnStart(SF2_ChaserIdleAction action, SF2_ChaserEntity actor, NextBotA } } - if (!actor.HasSmelled) + if (data.GetSmellData() != null) { - actor.SmellCooldown = gameTime + GetRandomFloat(data.SmellData.CooldownMin[difficulty], data.SmellData.CooldownMax[difficulty]); - } - else - { - actor.SmellCooldown = gameTime + GetRandomFloat(data.SmellData.CooldownAfterStateMin[difficulty], data.SmellData.CooldownAfterStateMax[difficulty]); + if (!actor.HasSmelled) + { + actor.SmellCooldown = gameTime + GetRandomFloat(smellData.GetMinCooldown(difficulty), smellData.GetMaxCooldown(difficulty)); + } + else + { + actor.SmellCooldown = gameTime + GetRandomFloat(smellData.GetMinCooldownAfterState(difficulty), smellData.GetMaxCooldownAfterState(difficulty)); + } } - g_SlenderTimeUntilKill[controller.Index] = GetGameTime() + NPCGetIdleLifetime(controller.Index, difficulty); + g_SlenderTimeUntilKill[controller.Index] = GetGameTime() + data.GetIdleLifeTime(difficulty); return action.Continue(); } @@ -120,12 +125,12 @@ static int Update(SF2_ChaserIdleAction action, SF2_ChaserEntity actor, float int return action.Continue(); } - SF2ChaserBossProfileData data; - data = controller.GetProfileData(); - SF2BossProfileData originalData; - originalData = view_as(controller).GetProfileData(); + ChaserBossProfile data = controller.GetProfileDataEx(); + ChaserBossProfileIdleData idleData = data.GetIdleBehavior(); + ChaserBossProfileAlertData alertData = data.GetAlertBehavior(); + ChaserBossProfileSmellData smellData = data.GetSmellData(); - if (!originalData.IsPvEBoss && IsBeatBoxBeating(2)) + if (!data.IsPvEBoss && IsBeatBoxBeating(2)) { return action.SuspendFor(SF2_ChaserBeatBoxFreezeAction(actor.IsAttemptingToMove)); } @@ -138,7 +143,7 @@ static int Update(SF2_ChaserIdleAction action, SF2_ChaserEntity actor, float int PathFollower path = controller.Path; - if (data.ChaseOnLookData.Enabled[difficulty] && controller.ChaseOnLookTargets.Length > 0) + if (data.GetChaseOnLookData().IsEnabled(difficulty) && controller.ChaseOnLookTargets.Length > 0) { SF2_BasePlayer lookTarget = SF2_BasePlayer(controller.ChaseOnLookTargets.Get(0)); if (lookTarget.IsValid && !lookTarget.IsEliminated && lookTarget.IsAlive && !lookTarget.IsInGhostMode && !lookTarget.HasEscaped) @@ -158,7 +163,7 @@ static int Update(SF2_ChaserIdleAction action, SF2_ChaserEntity actor, float int if (target.IsValid()) { if (SF_IsRaidMap() || SF_BossesChaseEndlessly() || SF_IsProxyMap() || SF_IsBoxingMap() || SF_IsSlaughterRunMap() || data.ChasesEndlessly || - view_as(controller).GetProfileData().IsPvEBoss) + data.IsPvEBoss) { actor.State = STATE_CHASE; path.Invalidate(); @@ -199,7 +204,7 @@ static int Update(SF2_ChaserIdleAction action, SF2_ChaserEntity actor, float int { actor.NextVoiceTime = 0.0; } - return action.ChangeTo(SF2_ChaserAlertAction(pos, data.AlertData.RunOnSuspect[difficulty]), "I saw someone!"); + return action.ChangeTo(SF2_ChaserAlertAction(pos, alertData.ShouldRunOnSuspect(difficulty)), "I saw someone!"); } } @@ -215,7 +220,7 @@ static int Update(SF2_ChaserIdleAction action, SF2_ChaserEntity actor, float int { actor.NextVoiceTime = 0.0; } - return action.ChangeTo(SF2_ChaserAlertAction(pos, data.AlertData.RunOnSuspect[difficulty]), "Someone made noise, let's go!"); + return action.ChangeTo(SF2_ChaserAlertAction(pos, alertData.ShouldRunOnSuspect(difficulty)), "Someone made noise, let's go!"); } else if ((interruptConditions & COND_ALERT_TRIGGER_POS) != 0 || actor.QueueForAlertState) { @@ -229,7 +234,7 @@ static int Update(SF2_ChaserIdleAction action, SF2_ChaserEntity actor, float int actor.NextVoiceTime = 0.0; } actor.QueueForAlertState = false; - return action.ChangeTo(SF2_ChaserAlertAction(pos, data.AlertData.RunOnSuspect[difficulty]), "We got a sound hint, let's go!"); + return action.ChangeTo(SF2_ChaserAlertAction(pos, alertData.ShouldRunOnSuspect(difficulty)), "We got a sound hint, let's go!"); } if ((interruptConditions & COND_DEBUG) != 0) @@ -243,7 +248,7 @@ static int Update(SF2_ChaserIdleAction action, SF2_ChaserEntity actor, float int { actor.NextVoiceTime = 0.0; } - return action.ChangeTo(SF2_ChaserAlertAction(pos, data.AlertData.RunOnWander[difficulty]), "An admin told me to go here!"); + return action.ChangeTo(SF2_ChaserAlertAction(pos, alertData.ShouldRunOnWander(difficulty)), "An admin told me to go here!"); } if (actor.FollowedCompanionAlert || actor.AlertWithBoss) @@ -262,13 +267,13 @@ static int Update(SF2_ChaserIdleAction action, SF2_ChaserEntity actor, float int { actor.NextVoiceTime = 0.0; } - return action.ChangeTo(SF2_ChaserAlertAction(pos, data.AlertData.RunOnWander[difficulty]), "One of my mates found something!"); + return action.ChangeTo(SF2_ChaserAlertAction(pos, alertData.ShouldRunOnWander(difficulty)), "One of my mates found something!"); } } - if (data.SmellData.Enabled[difficulty] && actor.SmellCooldown <= gameTime && actor.SmellPlayerList != null) + if (smellData.IsEnabled(difficulty) && actor.SmellCooldown <= gameTime && actor.SmellPlayerList != null) { - if (actor.SmellPlayerList.Length >= data.SmellData.PlayerCount[difficulty]) + if (actor.SmellPlayerList.Length >= smellData.GetRequiredPlayers(difficulty)) { actor.State = STATE_ALERT; path.Invalidate(); @@ -276,7 +281,7 @@ static int Update(SF2_ChaserIdleAction action, SF2_ChaserEntity actor, float int } } - bool isAbleToWander = data.CanWander[difficulty]; + bool isAbleToWander = data.CanWander(difficulty); bool canWalk = true; if (controller.HasAttribute(SF2Attribute_BlockWalkSpeedUnderDifficulty)) { @@ -293,8 +298,8 @@ static int Update(SF2_ChaserIdleAction action, SF2_ChaserEntity actor, float int float debugPos[3]; actor.GetForceWanderPosition(debugPos); path.Invalidate(); - float min = data.WanderTimeMin[difficulty]; - float max = data.WanderTimeMax[difficulty]; + float min = data.GetWanderMinTime(difficulty); + float max = data.GetWanderMaxTime(difficulty); action.NextWanderTime = gameTime + GetRandomFloat(min, max); path.ComputeToPos(bot, debugPos); @@ -315,7 +320,7 @@ static int Update(SF2_ChaserIdleAction action, SF2_ChaserEntity actor, float int actor.NextVoiceTime = 0.0; } actor.WasInBacon = true; - return action.ChangeTo(SF2_ChaserAlertAction(pos, data.AlertData.RunOnSuspect[difficulty]), "What is this smell of bacon?"); + return action.ChangeTo(SF2_ChaserAlertAction(pos, alertData.ShouldRunOnSuspect(difficulty)), "What is this smell of bacon?"); } } @@ -323,13 +328,13 @@ static int Update(SF2_ChaserIdleAction action, SF2_ChaserEntity actor, float int { if (gameTime >= action.NextWanderTime && GetRandomFloat(0.0, 1.0) <= 0.25) { - float min = data.WanderTimeMin[difficulty]; - float max = data.WanderTimeMax[difficulty]; + float min = data.GetWanderMinTime(difficulty); + float max = data.GetWanderMaxTime(difficulty); action.NextWanderTime = gameTime + GetRandomFloat(min, max); - float rangeMin = data.WanderRangeMin[difficulty]; - float rangeMax = data.WanderRangeMax[difficulty]; + float rangeMin = data.GetWanderMinRange(difficulty); + float rangeMax = data.GetWanderMaxRange(difficulty); float range = GetRandomFloat(rangeMin, rangeMax); CNavArea area = actor.GetLastKnownArea(); @@ -386,7 +391,7 @@ static int Update(SF2_ChaserIdleAction action, SF2_ChaserEntity actor, float int } else { - if (data.IdleData.TurnEnabled[difficulty]) + if (idleData.IsTurnEnabled(difficulty)) { if (!action.InitialState) { @@ -396,22 +401,22 @@ static int Update(SF2_ChaserIdleAction action, SF2_ChaserEntity actor, float int } if (action.NextTurnTime <= 0.0) { - action.NextTurnTime = gameTime + GetRandomFloat(data.IdleData.TurnMinTime[difficulty], data.IdleData.TurnMaxTime[difficulty]); + action.NextTurnTime = gameTime + GetRandomFloat(idleData.GetTurnMinCooldown(difficulty), idleData.GetTurnMaxCooldown(difficulty)); } } } - if (data.IdleData.TurnEnabled[difficulty] && action.NextTurnTime > 0.0 && action.NextTurnTime <= gameTime) + if (action.NextTurnTime > 0.0 && action.NextTurnTime <= gameTime && idleData.IsTurnEnabled(difficulty)) { float myPos[3], myAng[3]; actor.GetAbsOrigin(myPos); actor.GetAbsAngles(myAng); - myAng[1] += GetRandomFloat(-data.IdleData.TurnAngle[difficulty], data.IdleData.TurnAngle[difficulty]); + myAng[1] += GetRandomFloat(-idleData.GetTurnAngle(difficulty), idleData.GetTurnAngle(difficulty)); float lookAt[3]; lookAt[0] = 50.0; VectorTransform(lookAt, myPos, myAng, lookAt); action.SetLookPosition(lookAt); - action.NextTurnTime = gameTime + GetRandomFloat(data.IdleData.TurnMinTime[difficulty], data.IdleData.TurnMaxTime[difficulty]); + action.NextTurnTime = gameTime + GetRandomFloat(idleData.GetTurnMinCooldown(difficulty), idleData.GetTurnMaxCooldown(difficulty)); action.InitialState = false; } diff --git a/addons/sourcemod/scripting/sf2/npc/entities/chaser/actions/mainlayer.sp b/addons/sourcemod/scripting/sf2/npc/entities/chaser/actions/mainlayer.sp index bf7dca70..400b508c 100644 --- a/addons/sourcemod/scripting/sf2/npc/entities/chaser/actions/mainlayer.sp +++ b/addons/sourcemod/scripting/sf2/npc/entities/chaser/actions/mainlayer.sp @@ -1,4 +1,5 @@ #pragma semicolon 1 +#pragma newdecls required // The purpose of this action is to be the master action static NextBotActionFactory g_Factory; @@ -112,11 +113,9 @@ static int Update(SF2_ChaserMainAction action, SF2_ChaserEntity actor) actor.DoAttackMiscConditions(actor.GetAttackName()); } - SF2ChaserBossProfileData data; - data = controller.GetProfileData(); - SF2BossProfileData originalData; - originalData = view_as(controller).GetProfileData(); - if (data.StunData.FlashlightStun[difficulty] && actor.CanBeStunned() && actor.CanTakeDamage() && actor.FlashlightTick < gameTime && + ChaserBossProfile data = controller.GetProfileDataEx(); + ChaserBossProfileStunData stunData = data.GetStunBehavior(); + if (stunData != null && stunData.CanFlashlightStun(difficulty) && actor.CanBeStunned() && actor.CanTakeDamage() && actor.FlashlightTick < gameTime && !IsNightVisionEnabled()) { bool inFlashlight = false; @@ -189,7 +188,7 @@ static int Update(SF2_ChaserMainAction action, SF2_ChaserEntity actor) if (inFlashlight) { - actor.StunHealth -= data.StunData.FlashlightStunDamage[difficulty] * customDamage; + actor.StunHealth -= stunData.GetFlashlightDamage(difficulty) * customDamage; actor.FlashlightTick = gameTime + 0.1; Event event = CreateEvent("npc_hurt"); @@ -197,7 +196,7 @@ static int Update(SF2_ChaserMainAction action, SF2_ChaserEntity actor) { event.SetInt("entindex", actor.index); event.SetInt("health", actor.GetProp(Prop_Data, "m_iHealth")); - event.SetInt("damageamount", RoundToFloor(data.StunData.FlashlightStunDamage[difficulty] * customDamage)); + event.SetInt("damageamount", RoundToFloor(stunData.GetFlashlightDamage(difficulty) * customDamage)); event.SetBool("crit", false); if (IsValidClient(attacker)) @@ -221,7 +220,7 @@ static int Update(SF2_ChaserMainAction action, SF2_ChaserEntity actor) } } - if (originalData.InstantKillRadius > 0.0) + if (data.InstantKillRadius > 0.0) { if (gameTime >= actor.LastKillTime && !actor.IsKillingSomeone) { @@ -229,7 +228,7 @@ static int Update(SF2_ChaserMainAction action, SF2_ChaserEntity actor) actor.WorldSpaceCenter(worldSpace); actor.GetAbsOrigin(myPos); bool attackEliminated = (controller.Flags & SFF_ATTACKWAITERS) != 0; - if (view_as(controller).GetProfileData().IsPvEBoss) + if (controller.GetProfileDataEx().IsPvEBoss) { attackEliminated = true; } @@ -246,13 +245,13 @@ static int Update(SF2_ChaserMainAction action, SF2_ChaserEntity actor) continue; } - if (actor.MyNextBotPointer().GetRangeSquaredTo(client.index) > Pow(originalData.InstantKillRadius, 2.0) || + if (actor.MyNextBotPointer().GetRangeSquaredTo(client.index) > Pow(data.InstantKillRadius, 2.0) || !client.CanSeeSlender(controller.Index, false, _, !attackEliminated)) { continue; } - actor.LastKillTime = gameTime + originalData.InstantKillCooldown[difficulty]; + actor.LastKillTime = gameTime + data.GetInstantKillCooldown(difficulty); client.StartDeathCam(controller.Index, myPos); actor.CheckTauntKill(SF2_BasePlayer(client.index)); } @@ -261,6 +260,7 @@ static int Update(SF2_ChaserMainAction action, SF2_ChaserEntity actor) if (actor.IsKillingSomeone) { + actor.EndCloak(); return action.SuspendFor(SF2_DeathCamAction()); } @@ -387,17 +387,17 @@ static int OnInjured(SF2_ChaserMainAction action, SF2_ChaserEntity actor, CBaseE } SF2NPC_Chaser controller = actor.Controller; - SF2ChaserBossProfileData data; - data = controller.GetProfileData(); + ChaserBossProfile data = controller.GetProfileDataEx(); int search = actor.RageIndex + 1; - if ((data.BoxingBoss || view_as(controller).GetProfileData().IsPvEBoss) && - actor.CanTakeDamage(attacker, inflictor, damage) && data.Rages != null && search < data.Rages.Length && !actor.IsRaging) + if ((data.BoxingBoss || data.IsPvEBoss) && + actor.CanTakeDamage(attacker, inflictor, damage) && data.GetRages() != null && search < data.GetRages().Size && !actor.IsRaging) { - SF2ChaserRageInfo rageInfo; - data.Rages.GetArray(search, rageInfo, sizeof(rageInfo)); + char name[64]; + data.GetRages().GetSectionNameFromIndex(search, name, sizeof(name)); + ChaserBossProfileRageData rageInfo = view_as(data.GetRages().GetSection(name)); float maxHealth = actor.MaxHealth; float health = float(actor.GetProp(Prop_Data, "m_iHealth")); - if (!data.DeathData.Enabled[controller.Difficulty]) + if (!data.GetDeathBehavior().IsEnabled(controller.Difficulty)) { maxHealth = actor.MaxStunHealth; health = actor.StunHealth; @@ -545,11 +545,9 @@ static int OnCommandString(SF2_ChaserMainAction action, SF2_ChaserEntity actor, char attack[128]; strcopy(attack, sizeof(attack), command); ReplaceString(attack, sizeof(attack), "debug attack ", ""); - SF2ChaserBossProfileData data; - data = controller.GetProfileData(); - SF2ChaserBossProfileAttackData attackData; - data.GetAttack(attack, attackData); - return action.TrySuspendFor(SF2_ChaserAttackAction(attack, attackData.Index, attackData.Duration[difficulty] + GetGameTime()), RESULT_IMPORTANT); + ChaserBossProfile data = controller.GetProfileDataEx(); + ChaserBossProfileBaseAttack attackData = data.GetAttack(attack); + return action.TrySuspendFor(SF2_ChaserAttackAction(data, attack, data.IndexOfSection(attackData), attackData.GetDuration(difficulty) + GetGameTime()), RESULT_IMPORTANT); } if (strcmp(command, "suspend for action") == 0) diff --git a/addons/sourcemod/scripting/sf2/npc/entities/chaser/actions/rage.sp b/addons/sourcemod/scripting/sf2/npc/entities/chaser/actions/rage.sp index 558ff469..88c797d8 100644 --- a/addons/sourcemod/scripting/sf2/npc/entities/chaser/actions/rage.sp +++ b/addons/sourcemod/scripting/sf2/npc/entities/chaser/actions/rage.sp @@ -1,4 +1,5 @@ #pragma semicolon 1 +#pragma newdecls required static NextBotActionFactory g_Factory; @@ -51,12 +52,12 @@ static NextBotAction InitialContainedAction(SF2_ChaserRageAction action, SF2_Cha { actor.RageIndex++; SF2NPC_Chaser controller = actor.Controller; - SF2ChaserBossProfileData data; + ChaserBossProfile data = controller.GetProfileDataEx(); + char name[64]; + data.GetRages().GetSectionNameFromIndex(actor.RageIndex, name, sizeof(name)); + ChaserBossProfileRageData rageData = view_as(data.GetRages().GetSection(name)); INextBot bot = actor.MyNextBotPointer(); ILocomotion loco = bot.GetLocomotionInterface(); - data = controller.GetProfileData(); - SF2ChaserRageInfo rageInfo; - data.Rages.GetArray(actor.RageIndex, rageInfo, sizeof(rageInfo)); char animName[64]; float rate = 1.0, duration = 0.0, cycle = 0.0; int difficulty = controller.Difficulty; @@ -66,9 +67,9 @@ static NextBotAction InitialContainedAction(SF2_ChaserRageAction action, SF2_Cha actor.IsRaging = true; - actor.OverrideInvincible = rageInfo.Invincible; + actor.OverrideInvincible = rageData.Invincible; - actor.PerformVoiceEx(_, _, rageInfo.StartSounds, true); + actor.PerformVoiceEx(_, _, rageData.GetStartSounds(), true); actor.EndCloak(); @@ -77,7 +78,7 @@ static NextBotAction InitialContainedAction(SF2_ChaserRageAction action, SF2_Cha actor.CancelAttack = true; } - if (rageInfo.IsHealing) + if (rageData.IsHealing) { SetHealthBarColor(true); action.IsHealing = true; @@ -85,8 +86,13 @@ static NextBotAction InitialContainedAction(SF2_ChaserRageAction action, SF2_Cha return SF2_ChaserFleeToHealAction(); } - if (rageInfo.Animations.GetAnimation("start", difficulty, animName, sizeof(animName), rate, duration, cycle)) + ProfileAnimation section = rageData.GetAnimations().GetAnimation("start"); + if (section != null) { + section.GetAnimationName(difficulty, animName, sizeof(animName)); + duration = section.GetDuration(difficulty); + rate = section.GetAnimationPlaybackRate(difficulty); + cycle = section.GetAnimationCycle(difficulty); int sequence = LookupProfileAnimation(actor.index, animName); if (sequence != -1) { @@ -124,11 +130,11 @@ static void OnEnd(SF2_ChaserRageAction action, SF2_ChaserEntity actor) actor.IsGoingToHeal = false; if (actor.Controller.IsValid()) { - SF2ChaserBossProfileData data; - data = actor.Controller.GetProfileData(); - SF2ChaserRageInfo rageInfo; - data.Rages.GetArray(actor.RageIndex, rageInfo, sizeof(rageInfo)); - if (rageInfo.IncreaseDifficulty) + ChaserBossProfile data = actor.Controller.GetProfileDataEx(); + char name[64]; + data.GetRages().GetSectionNameFromIndex(actor.RageIndex, name, sizeof(name)); + ChaserBossProfileRageData rageData = view_as(data.GetRages().GetSection(name)); + if (rageData.IncreaseDifficulty) { actor.Controller.Difficulty += 1; if (actor.Controller.Difficulty > Difficulty_Apollyon) diff --git a/addons/sourcemod/scripting/sf2/npc/entities/chaser/actions/smell.sp b/addons/sourcemod/scripting/sf2/npc/entities/chaser/actions/smell.sp index 1501333f..6c6c46a2 100644 --- a/addons/sourcemod/scripting/sf2/npc/entities/chaser/actions/smell.sp +++ b/addons/sourcemod/scripting/sf2/npc/entities/chaser/actions/smell.sp @@ -1,4 +1,5 @@ #pragma semicolon 1 +#pragma newdecls required static NextBotActionFactory g_Factory; @@ -20,10 +21,8 @@ methodmap SF2_ChaserSmellAction < NextBotAction public static bool IsPossible(SF2_ChaserEntity actor) { - SF2NPC_BaseNPC baseController = view_as(actor.Controller); - SF2BossProfileData data; - data = baseController.GetProfileData(); - if (!data.AnimationData.HasAnimationSection(g_SlenderAnimationsList[SF2BossAnimation_Smell])) + ChaserBossProfile data = actor.Controller.GetProfileDataEx(); + if (!data.GetAnimations().HasAnimationSection(g_SlenderAnimationsList[SF2BossAnimation_Smell])) { return false; } @@ -34,23 +33,15 @@ methodmap SF2_ChaserSmellAction < NextBotAction static NextBotAction InitialContainedAction(SF2_ChaserSmellAction action, SF2_ChaserEntity actor) { - SF2NPC_BaseNPC baseController = view_as(actor.Controller); - SF2BossProfileData data; - data = baseController.GetProfileData(); - char animName[64]; float rate = 1.0, duration = 0.0, cycle = 0.0; - int difficulty = baseController.Difficulty; actor.IsAttemptingToMove = false; actor.PerformVoice(SF2BossSound_Smell); - if (data.AnimationData.GetAnimation(g_SlenderAnimationsList[SF2BossAnimation_Smell], difficulty, animName, sizeof(animName), rate, duration, cycle)) + int sequence = actor.SelectProfileAnimation(g_SlenderAnimationsList[SF2BossAnimation_Smell], rate, duration, cycle); + if (sequence != -1) { - int sequence = actor.SelectProfileAnimation(g_SlenderAnimationsList[SF2BossAnimation_Smell], rate, duration, cycle); - if (sequence != -1) - { - return SF2_PlaySequenceAndWait(sequence, duration, rate, cycle); - } + return SF2_PlaySequenceAndWait(sequence, duration, rate, cycle); } return NULL_ACTION; @@ -67,13 +58,14 @@ static int Update(SF2_ChaserSmellAction action, SF2_ChaserEntity actor, NextBotA { SF2NPC_Chaser controller = actor.Controller; int difficulty = controller.Difficulty; - SF2ChaserBossProfileData data; - data = controller.GetProfileData(); + ChaserBossProfile data = controller.GetProfileDataEx(); + ChaserBossProfileSmellData smellData = data.GetSmellData(); + ChaserBossProfileAlertData alertData = data.GetAlertBehavior(); PathFollower path = controller.Path; - g_SlenderTimeUntilKill[controller.Index] = GetGameTime() + NPCGetIdleLifetime(controller.Index, difficulty); + g_SlenderTimeUntilKill[controller.Index] = GetGameTime() + data.GetIdleLifeTime(difficulty); if (action.ActiveChild == NULL_ACTION) { - float bestDistance = Pow(data.SmellData.SmellRange[difficulty], 2.0); + float bestDistance = Pow(smellData.GetSmellRange(difficulty), 2.0); bool found = false; float pos[3], myPos[3], bestPos[3]; actor.GetAbsOrigin(myPos); @@ -98,7 +90,7 @@ static int Update(SF2_ChaserSmellAction action, SF2_ChaserEntity actor, NextBotA } if (found) { - if (!data.SmellData.ShouldChase[difficulty]) + if (!smellData.GetShouldChaseState(difficulty)) { actor.State = STATE_ALERT; path.Invalidate(); @@ -106,7 +98,7 @@ static int Update(SF2_ChaserSmellAction action, SF2_ChaserEntity actor, NextBotA { actor.NextVoiceTime = 0.0; } - return action.ChangeTo(SF2_ChaserAlertAction(bestPos, data.AlertData.RunOnSuspect[difficulty]), "I smelled someone, what is it?"); + return action.ChangeTo(SF2_ChaserAlertAction(bestPos, alertData.ShouldRunOnSuspect(difficulty)), "I smelled someone, what is it?"); } else { @@ -144,7 +136,7 @@ static int Update(SF2_ChaserSmellAction action, SF2_ChaserEntity actor, NextBotA { actor.NextVoiceTime = 0.0; } - return action.ChangeTo(SF2_ChaserAlertAction(pos, data.AlertData.RunOnSuspect[difficulty]), "Abort abort, I saw someone!"); + return action.ChangeTo(SF2_ChaserAlertAction(pos, alertData.ShouldRunOnSuspect(difficulty)), "Abort abort, I saw someone!"); } } @@ -160,7 +152,7 @@ static int Update(SF2_ChaserSmellAction action, SF2_ChaserEntity actor, NextBotA { actor.NextVoiceTime = 0.0; } - return action.ChangeTo(SF2_ChaserAlertAction(pos, data.AlertData.RunOnSuspect[difficulty]), "Stop! I heard someone!"); + return action.ChangeTo(SF2_ChaserAlertAction(pos, alertData.ShouldRunOnSuspect(difficulty)), "Stop! I heard someone!"); } else if ((interruptConditions & COND_ALERT_TRIGGER_POS) != 0) { @@ -173,7 +165,7 @@ static int Update(SF2_ChaserSmellAction action, SF2_ChaserEntity actor, NextBotA { actor.NextVoiceTime = 0.0; } - return action.ChangeTo(SF2_ChaserAlertAction(pos, data.AlertData.RunOnSuspect[difficulty]), "Stop! I got a sound hint!"); + return action.ChangeTo(SF2_ChaserAlertAction(pos, alertData.ShouldRunOnSuspect(difficulty)), "Stop! I got a sound hint!"); } return action.Continue(); diff --git a/addons/sourcemod/scripting/sf2/npc/entities/chaser/actions/spawn.sp b/addons/sourcemod/scripting/sf2/npc/entities/chaser/actions/spawn.sp index 48bcc11d..16d460af 100644 --- a/addons/sourcemod/scripting/sf2/npc/entities/chaser/actions/spawn.sp +++ b/addons/sourcemod/scripting/sf2/npc/entities/chaser/actions/spawn.sp @@ -1,4 +1,5 @@ #pragma semicolon 1 +#pragma newdecls required static NextBotActionFactory g_Factory; diff --git a/addons/sourcemod/scripting/sf2/npc/entities/chaser/actions/stun.sp b/addons/sourcemod/scripting/sf2/npc/entities/chaser/actions/stun.sp index 27ff1590..c772d02d 100644 --- a/addons/sourcemod/scripting/sf2/npc/entities/chaser/actions/stun.sp +++ b/addons/sourcemod/scripting/sf2/npc/entities/chaser/actions/stun.sp @@ -1,4 +1,5 @@ #pragma semicolon 1 +#pragma newdecls required static NextBotActionFactory g_Factory; @@ -54,14 +55,8 @@ methodmap SF2_ChaserStunnedAction < NextBotAction static NextBotAction InitialContainedAction(SF2_ChaserStunnedAction action, SF2_ChaserEntity actor) { - SF2NPC_BaseNPC baseController = view_as(actor.Controller); - SF2BossProfileData data; INextBot bot = actor.MyNextBotPointer(); ILocomotion loco = bot.GetLocomotionInterface(); - data = baseController.GetProfileData(); - char animName[64]; - float rate = 1.0, duration = 0.0, cycle = 0.0; - int difficulty = baseController.Difficulty; actor.IsAttemptingToMove = false; loco.Stop(); @@ -78,14 +73,13 @@ static NextBotAction InitialContainedAction(SF2_ChaserStunnedAction action, SF2_ actor.PerformVoice(SF2BossSound_Stun); actor.EndCloak(); + char posture[64]; + actor.GetPosture(posture, sizeof(posture)); - if (data.AnimationData.GetAnimation(g_SlenderAnimationsList[SF2BossAnimation_Stun], difficulty, animName, sizeof(animName), rate, duration, cycle)) + ChaserBossProfile data = actor.Controller.GetProfileDataEx(); + if (data.GetAnimations().HasAnimationSection(g_SlenderAnimationsList[SF2BossAnimation_Stun])) { - int sequence = actor.SelectProfileAnimation(g_SlenderAnimationsList[SF2BossAnimation_Stun], rate, duration, cycle); - if (sequence != -1) - { - return SF2_PlaySequenceAndWait(sequence, duration, rate, cycle); - } + return SF2_PlaySequenceAndWaitEx(g_SlenderAnimationsList[SF2BossAnimation_Stun]); } return NULL_ACTION; @@ -94,32 +88,36 @@ static NextBotAction InitialContainedAction(SF2_ChaserStunnedAction action, SF2_ static int OnStart(SF2_ChaserStunnedAction action, SF2_ChaserEntity actor, NextBotAction priorAction) { SF2NPC_Chaser controller = actor.Controller; - SF2ChaserBossProfileData data; + ChaserBossProfile data = controller.GetProfileDataEx(); + ChaserBossProfileChaseData chaseData = data.GetChaseBehavior(); + ChaserBossProfileStunData stunData = data.GetStunBehavior(); int difficulty = controller.Difficulty; - data = controller.GetProfileData(); - if (data.StunData.StartEffects != null) + if (stunData.GetOnStartEffects() != null) { float pos[3], ang[3]; actor.GetAbsOrigin(pos); actor.GetAbsAngles(ang); - SlenderSpawnEffects(data.StunData.StartEffects, controller.Index, false, pos, ang, _, _, true); + SlenderSpawnEffects(stunData.GetOnStartEffects(), controller.Index, false, pos, ang, _, _, true); } - if (data.KeyDrop) + if (stunData.KeyDrop) { - if (SF_IsBoxingMap() && data.StunData.Disappear[difficulty] && data.BoxingBoss && !g_SlenderBoxingBossIsKilled[controller.Index] && !view_as(controller).GetProfileData().IsPvEBoss) + char model[PLATFORM_MAX_PATH], trigger[64]; + stunData.GetKeyModel(model, sizeof(model)); + stunData.GetKeyTrigger(trigger, sizeof(trigger)); + if (SF_IsBoxingMap() && stunData.ShouldDisappear(difficulty) && data.BoxingBoss && !g_SlenderBoxingBossIsKilled[controller.Index] && data.IsPvEBoss) { g_SlenderBoxingBossKilled++; if ((g_SlenderBoxingBossKilled == g_SlenderBoxingBossCount)) { - NPC_DropKey(controller.Index, data.KeyModel, data.KeyTrigger); + NPC_DropKey(controller.Index, model, trigger); } g_SlenderBoxingBossIsKilled[controller.Index] = true; } else { - NPC_DropKey(controller.Index, data.KeyModel, data.KeyTrigger); + NPC_DropKey(controller.Index, model, trigger); } } @@ -130,10 +128,10 @@ static int OnStart(SF2_ChaserStunnedAction action, SF2_ChaserEntity actor, NextB if (actor.State == STATE_CHASE) { - actor.CurrentChaseDuration += data.ChaseDurationAddOnStun[difficulty]; - if (actor.CurrentChaseDuration > data.ChaseDuration[difficulty]) + actor.CurrentChaseDuration += chaseData.GetDurationAddOnStunned(difficulty); + if (actor.CurrentChaseDuration > chaseData.GetMaxChaseDuration(difficulty)) { - actor.CurrentChaseDuration = data.ChaseDuration[difficulty]; + actor.CurrentChaseDuration = chaseData.GetMaxChaseDuration(difficulty); } } @@ -145,7 +143,7 @@ static int OnStart(SF2_ChaserStunnedAction action, SF2_ChaserEntity actor, NextB } else { - actor.MaxStunHealth += data.StunData.AddHealthPerStun[difficulty]; + actor.MaxStunHealth += stunData.GetAddHealthPerStun(difficulty); } if (controller.HasAttribute(SF2Attribute_AddSpeedOnStun)) @@ -154,7 +152,7 @@ static int OnStart(SF2_ChaserStunnedAction action, SF2_ChaserEntity actor, NextB } else { - controller.SetAddSpeed(data.StunData.AddSpeedPerStun[difficulty]); + controller.SetAddSpeed(stunData.GetAddRunSpeed(difficulty)); } if (controller.HasAttribute(SF2Attribute_AddAccelerationOnStun)) @@ -163,7 +161,7 @@ static int OnStart(SF2_ChaserStunnedAction action, SF2_ChaserEntity actor, NextB } else { - controller.SetAddAcceleration(data.StunData.AddAccelerationPerStun[difficulty]); + controller.SetAddAcceleration(stunData.GetAddAcceleration(difficulty)); } actor.GroundSpeedOverride = true; @@ -183,7 +181,7 @@ static int Update(SF2_ChaserStunnedAction action, SF2_ChaserEntity actor, float return action.Continue(); } - if (actor.Controller.GetProfileData().StunData.Disappear[actor.Controller.Difficulty]) + if (actor.Controller.GetProfileDataEx().GetStunBehavior().ShouldDisappear(actor.Controller.Difficulty)) { actor.Controller.UnSpawn(true); } @@ -204,22 +202,22 @@ static void OnEnd(SF2_ChaserStunnedAction action, SF2_ChaserEntity actor) return; } - SF2ChaserBossProfileData data; - data = controller.GetProfileData(); + ChaserBossProfile data = controller.GetProfileDataEx(); + ChaserBossProfileStunData stunData = data.GetStunBehavior(); - if (data.StunData.EndEffects != null) + if (stunData.GetOnEndEffects() != null) { float pos[3], ang[3]; actor.GetAbsOrigin(pos); actor.GetAbsAngles(ang); - SlenderSpawnEffects(data.StunData.EndEffects, controller.Index, false, pos, ang, _, _, true); + SlenderSpawnEffects(stunData.GetOnEndEffects(), controller.Index, false, pos, ang, _, _, true); } actor.IsStunned = false; actor.GroundSpeedOverride = false; actor.StunHealth = actor.MaxStunHealth; - actor.NextStunTime = GetGameTime() + data.StunData.Cooldown[actor.Controller.Difficulty]; + actor.NextStunTime = GetGameTime() + stunData.GetCooldown(actor.Controller.Difficulty); actor.UpdateMovementAnimation(); diff --git a/addons/sourcemod/scripting/sf2/npc/entities/chaser/actions/tauntkill.sp b/addons/sourcemod/scripting/sf2/npc/entities/chaser/actions/tauntkill.sp index f4a2b7aa..8b58319b 100644 --- a/addons/sourcemod/scripting/sf2/npc/entities/chaser/actions/tauntkill.sp +++ b/addons/sourcemod/scripting/sf2/npc/entities/chaser/actions/tauntkill.sp @@ -1,4 +1,5 @@ #pragma semicolon 1 +#pragma newdecls required static NextBotActionFactory g_Factory; @@ -17,10 +18,8 @@ methodmap SF2_ChaserTauntKillAction < NextBotAction public static bool IsPossible(SF2_ChaserEntity actor) { - SF2NPC_BaseNPC baseController = view_as(actor.Controller); - SF2BossProfileData data; - data = baseController.GetProfileData(); - if (!data.AnimationData.HasAnimationSection(g_SlenderAnimationsList[SF2BossAnimation_TauntKill])) + ChaserBossProfile data = actor.Controller.GetProfileDataEx(); + if (!data.GetAnimations().HasAnimationSection(g_SlenderAnimationsList[SF2BossAnimation_TauntKill])) { return false; } @@ -46,8 +45,7 @@ static int OnStart(SF2_ChaserTauntKillAction action, SF2_ChaserEntity actor, Nex SF2NPC_Chaser controller = actor.Controller; if (controller.IsValid()) { - SF2ChaserBossProfileData data; - data = controller.GetProfileData(); + ChaserBossProfile data = controller.GetProfileDataEx(); if (data.NormalSoundHook) { actor.NextVoiceTime = 0.0; @@ -62,8 +60,7 @@ static int OnResume(SF2_ChaserTauntKillAction action, SF2_ChaserEntity actor, Ne SF2NPC_Chaser controller = actor.Controller; if (controller.IsValid()) { - SF2ChaserBossProfileData data; - data = controller.GetProfileData(); + ChaserBossProfile data = controller.GetProfileDataEx(); if (data.NormalSoundHook) { actor.NextVoiceTime = 0.0; diff --git a/addons/sourcemod/scripting/sf2/npc/entities/chaser/entity.sp b/addons/sourcemod/scripting/sf2/npc/entities/chaser/entity.sp index 6bc4c68b..e0fadd6d 100644 --- a/addons/sourcemod/scripting/sf2/npc/entities/chaser/entity.sp +++ b/addons/sourcemod/scripting/sf2/npc/entities/chaser/entity.sp @@ -1,4 +1,5 @@ #pragma semicolon 1 +#pragma newdecls required #include "actions/mainlayer.sp" #include "actions/idle.sp" @@ -73,7 +74,9 @@ methodmap SF2_ChaserEntity < SF2_BaseBoss .DefineFloatField("m_AttackRunDuration") .DefineFloatField("m_AttackRunDelay") .DefineFloatField("m_NextVoiceTime") + .DefineFloatField("m_NextHurtVoiceTime") .DefineIntField("m_MovementType") + .DefineBoolField("m_LockMovementType") .DefineIntField("m_AlertTriggerCount", MAXTF2PLAYERS) .DefineVectorField("m_AlertTriggerPosition", MAXTF2PLAYERS) .DefineEntityField("m_AlertTriggerTarget") @@ -175,7 +178,7 @@ methodmap SF2_ChaserEntity < SF2_BaseBoss public bool CanBeStunned() { - if (SF_IsSlaughterRunMap() && !view_as(this.Controller).GetProfileData().IsPvEBoss) + if (SF_IsSlaughterRunMap() && !this.Controller.GetProfileDataEx().IsPvEBoss) { return false; } @@ -185,7 +188,7 @@ methodmap SF2_ChaserEntity < SF2_BaseBoss return false; } - if (!this.Controller.GetProfileData().StunData.Enabled[this.Controller.Difficulty]) + if (!this.Controller.GetProfileDataEx().GetStunBehavior().IsEnabled(this.Controller.Difficulty)) { return false; } @@ -220,7 +223,7 @@ methodmap SF2_ChaserEntity < SF2_BaseBoss public bool CanTakeDamage(CBaseEntity attacker = view_as(-1), CBaseEntity inflictor = view_as(-1), float damage = 0.0) { - if (SF_IsSlaughterRunMap() && !view_as(this.Controller).GetProfileData().IsPvEBoss) + if (SF_IsSlaughterRunMap() && !this.Controller.GetProfileDataEx().IsPvEBoss) { return false; } @@ -251,12 +254,8 @@ methodmap SF2_ChaserEntity < SF2_BaseBoss } int difficulty = this.Controller.Difficulty; - SF2ChaserBossProfileData data; - data = this.Controller.GetProfileData(); - SF2ChaserBossProfileAttackData attackData; - data.GetAttack(this.GetAttackName(), attackData); - return !attackData.ImmuneToDamage[difficulty]; + return !this.Controller.GetProfileDataEx().GetAttack(this.GetAttackName()).IsImmuneToDamage(difficulty); } property bool IsStunned @@ -367,7 +366,7 @@ methodmap SF2_ChaserEntity < SF2_BaseBoss this.SetPropString(Prop_Data, "m_Posture", posture); - if (this.Controller.IsValid() && strcmp(currentPosture, posture) != 0 && this.IsAttemptingToMove) + if (this.Controller.IsValid() && strcmp(currentPosture, posture) != 0) { this.UpdateMovementAnimation(); } @@ -378,7 +377,7 @@ methodmap SF2_ChaserEntity < SF2_BaseBoss return this.GetPropString(Prop_Data, "m_DefaultPosture", buffer, bufferSize); } - public void SetDefaultPosture(const char[] posture) + public void SetDefaultPosture(const char[] posture, bool update = true) { if (posture[0] == '\0') { @@ -392,17 +391,23 @@ methodmap SF2_ChaserEntity < SF2_BaseBoss return; } - SF2ChaserBossProfileData data; - data = this.Controller.GetProfileData(); - SF2ChaserBossProfilePostureInfo postureInfo; + ChaserBossProfile data = this.Controller.GetProfileDataEx(); - if (!data.GetPosture(posture, postureInfo)) + if (data.GetPosture(posture) == null) { return; } } + char currentPosture[64]; + this.GetDefaultPosture(currentPosture, sizeof(currentPosture)); + this.SetPropString(Prop_Data, "m_DefaultPosture", posture); + + if (this.Controller.IsValid() && strcmp(currentPosture, posture) != 0 && update) + { + this.UpdateMovementAnimation(); + } } public bool CanUpdatePosture() @@ -559,6 +564,19 @@ methodmap SF2_ChaserEntity < SF2_BaseBoss } } + property float NextHurtVoiceTime + { + public get() + { + return this.GetPropFloat(Prop_Data, "m_NextHurtVoiceTime"); + } + + public set(float value) + { + this.SetPropFloat(Prop_Data, "m_NextHurtVoiceTime", value); + } + } + property bool IsAttemptingToMove { public get() @@ -587,6 +605,11 @@ methodmap SF2_ChaserEntity < SF2_BaseBoss public set(SF2NPCMoveTypes value) { + if (this.LockMovementType) + { + return; + } + SF2NPCMoveTypes oldType = this.MovementType; this.SetProp(Prop_Data, "m_MovementType", value); @@ -597,6 +620,19 @@ methodmap SF2_ChaserEntity < SF2_BaseBoss } } + property bool LockMovementType + { + public get() + { + return this.GetProp(Prop_Data, "m_LockMovementType") != 0; + } + + public set(bool value) + { + this.SetProp(Prop_Data, "m_LockMovementType", value); + } + } + public int GetAlertTriggerCount(SF2_BasePlayer player) { return this.GetProp(Prop_Data, "m_AlertTriggerCount", _, player.index); @@ -1094,11 +1130,10 @@ methodmap SF2_ChaserEntity < SF2_BaseBoss int difficulty = controller.Difficulty; float myPos[3]; this.GetAbsOrigin(myPos); - SF2BossProfileData data; - data = view_as(controller).GetProfileData(); + ChaserBossProfile data = controller.GetProfileDataEx(); SF2_BasePlayer closest = SF2_INVALID_PLAYER; - float range = Pow(data.SearchRange[difficulty], 2.0); + float range = Pow(data.GetSearchRange(difficulty), 2.0); for (int i = 1; i <= MaxClients; i++) { @@ -1140,6 +1175,11 @@ methodmap SF2_ChaserEntity < SF2_BaseBoss return; } + if (this.MovementType == SF2NPCMoveType_Attack) + { + return; + } + char animation[64]; strcopy(animation, sizeof(animation), g_SlenderAnimationsList[SF2BossAnimation_Idle]); @@ -1155,10 +1195,6 @@ methodmap SF2_ChaserEntity < SF2_BaseBoss { strcopy(animation, sizeof(animation), g_SlenderAnimationsList[SF2BossAnimation_Run]); } - case SF2NPCMoveType_Attack: - { - return; - } } } if (this.IsKillingSomeone) @@ -1173,94 +1209,103 @@ methodmap SF2_ChaserEntity < SF2_BaseBoss public bool PerformVoice(int soundType = -1, const char[] attackName = "") { - SF2BossProfileSoundInfo soundInfo; + ProfileSound soundInfo; return this.PerformVoiceEx(soundType, attackName, soundInfo); } - public bool PerformVoiceEx(int soundType = -1, const char[] attackName = "", SF2BossProfileSoundInfo soundInfo, bool isSet = false) + public bool PerformVoiceEx(int soundType = -1, const char[] attackName = "", ProfileSound soundInfo, bool isSet = false) { if (soundType == -1 && !isSet) { return false; } - SF2ChaserBossProfileData data; - data = this.Controller.GetProfileData(); - ArrayList soundList; + ChaserBossProfile data = this.Controller.GetProfileDataEx(); + KeyMap_Array soundList; if (!isSet) { switch (soundType) { case SF2BossSound_Idle: { - soundInfo = data.IdleSounds; + soundInfo = data.GetIdleSounds(); } case SF2BossSound_Alert: { - soundInfo = data.AlertSounds; + soundInfo = data.GetAlertSounds(); } case SF2BossSound_Chasing: { - soundInfo = data.ChasingSounds; + soundInfo = data.GetChasingSounds(); } case SF2BossSound_ChaseInitial: { - soundInfo = data.ChaseInitialSounds; + soundInfo = data.GetChaseInitialSounds(); } case SF2BossSound_Stun: { - soundInfo = data.StunnedSounds; + soundInfo = data.GetStunSounds(); } case SF2BossSound_Death: { - soundInfo = data.DeathSounds; + soundInfo = data.GetDeathSounds(); } case SF2BossSound_Attack: { - return this.CheckNestedSoundSection(data.AttackSounds, attackName, soundInfo, soundList); + return this.CheckNestedSoundSection(data.GetAttackSounds(), attackName, soundInfo, soundList, "attack"); } case SF2BossSound_AttackKilled: { - soundInfo = data.AttackKilledSounds; + soundInfo = data.GetAttackKilledSounds(); } case SF2BossSound_TauntKill: { - soundInfo = data.TauntKillSounds; + soundInfo = data.GetTauntKillSounds(); } case SF2BossSound_Smell: { - soundInfo = data.SmellSounds; + soundInfo = data.GetSmellSounds(); } case SF2BossSound_AttackBegin: { - return this.CheckNestedSoundSection(data.AttackBeginSounds, attackName, soundInfo, soundList); + return this.CheckNestedSoundSection(data.GetAttackBeginSounds(), attackName, soundInfo, soundList, "attack_begin"); } case SF2BossSound_AttackEnd: { - return this.CheckNestedSoundSection(data.AttackEndSounds, attackName, soundInfo, soundList); + return this.CheckNestedSoundSection(data.GetAttackEndSounds(), attackName, soundInfo, soundList, "attack_end"); } case SF2BossSound_SelfHeal: { - soundInfo = data.SelfHealSounds; + soundInfo = data.GetSelfHealSounds(); } case SF2BossSound_RageAll: { - soundInfo = data.RageSounds1; + soundInfo = data.GetRageAllSounds(); } case SF2BossSound_RageTwo: { - soundInfo = data.RageSounds2; + soundInfo = data.GetRageTwoSounds(); } case SF2BossSound_RageThree: { - soundInfo = data.RageSounds3; + soundInfo = data.GetRageThreeSounds(); } case SF2BossSound_Despawn: { - soundInfo = data.DespawnSounds; + soundInfo = data.GetDespawnSounds(); + } + case SF2BossSound_Hurt: + { + soundInfo = data.GetHurtSounds(); } } } + + if (soundInfo == null) + { + return false; + } + soundList = soundInfo.Paths; if (soundList != null && soundList.Length > 0) { @@ -1269,9 +1314,9 @@ methodmap SF2_ChaserEntity < SF2_BaseBoss return false; } - public bool CheckNestedSoundSection(ArrayList list, const char[] attackName, SF2BossProfileSoundInfo soundInfo, ArrayList soundList) + public bool CheckNestedSoundSection(ProfileObject list, const char[] attackName, ProfileSound soundInfo, KeyMap_Array soundList, char[] section) { - if (this.SearchSoundsWithSectionName(list, attackName, soundInfo)) + if (this.SearchSoundsWithSectionName(list, attackName, soundInfo, section)) { soundList = soundInfo.Paths; if (soundList != null && soundList.Length > 0) @@ -1282,71 +1327,45 @@ methodmap SF2_ChaserEntity < SF2_BaseBoss return false; } - public bool PerformVoiceCooldown(SF2BossProfileSoundInfo soundInfo, ArrayList soundList) + public bool PerformVoiceCooldown(ProfileSound soundInfo, KeyMap_Array soundList) { char buffer[PLATFORM_MAX_PATH]; float gameTime = GetGameTime(); soundList.GetString(GetRandomInt(0, soundList.Length - 1), buffer, sizeof(buffer)); if (buffer[0] != '\0') { - float threshold = GetRandomFloat(0.0, 1.0); - float cooldown = GetRandomFloat(soundInfo.CooldownMin, soundInfo.CooldownMax); - if (threshold > soundInfo.Chance) - { - this.NextVoiceTime = gameTime + cooldown; - return false; - } - soundInfo.EmitSound(_, this.index, _, _, SF_SpecialRound(SPECIALROUND_TINYBOSSES) ? 25 : 0); + float cooldown = GetRandomFloat(soundInfo.GetCooldownMin(this.Controller.Difficulty), soundInfo.GetCooldownMax(this.Controller.Difficulty)); this.NextVoiceTime = gameTime + cooldown; - return true; + return soundInfo.EmitSound(_, this.index, _, _, SF_SpecialRound(SPECIALROUND_TINYBOSSES) ? 25 : 0); } return false; } public void CastAnimEvent(int event, bool footstep = false) { - SF2BossProfileData data; - data = view_as(this.Controller).GetProfileData(); + ChaserBossProfile data = this.Controller.GetProfileDataEx(); - ArrayList arraySounds = data.EventSounds; - ArrayList arrayEvents = data.EventIndexes; + ProfileSound soundInfo = data.GetEventSounds(event); if (footstep) { - arraySounds = data.FootstepEventSounds; - arrayEvents = data.FootstepEventIndexes; + soundInfo = data.GetFootstepEventSounds(event); } - if (arraySounds == null || arrayEvents == null) - { - return; - } - - int foundIndex = arrayEvents.FindValue(event); - if (foundIndex == -1) - { - return; - } - - SF2BossProfileSoundInfo soundInfo; - arraySounds.GetArray(foundIndex, soundInfo, sizeof(soundInfo)); - - if (soundInfo.Paths == null) + if (soundInfo == null || soundInfo.Paths == null) { return; } soundInfo.EmitSound(_, this.index); - SF2ChaserBossProfileData chaserData; - chaserData = this.Controller.GetProfileData(); - if (footstep && chaserData.EarthquakeFootsteps) + if (footstep && data.EarthquakeFootsteps) { float myPos[3]; this.GetAbsOrigin(myPos); - UTIL_ScreenShake(myPos, chaserData.EarthquakeFootstepAmplitude, - chaserData.EarthquakeFootstepFrequency, chaserData.EarthquakeFootstepDuration, - chaserData.EarthquakeFootstepRadius, 0, chaserData.EarthquakeFootstepAirShake); + UTIL_ScreenShake(myPos, data.EarthquakeFootstepAmplitude, + data.EarthquakeFootstepFrequency, data.EarthquakeFootstepDuration, + data.EarthquakeFootstepRadius, 0, data.EarthquakeFootstepAirShake); } } @@ -1357,10 +1376,8 @@ methodmap SF2_ChaserEntity < SF2_BaseBoss { return; } - SF2ChaserBossProfileData data; - data = controller.GetProfileData(); - SF2BossProfileSoundInfo info; - info = data.FootstepSounds; + ChaserBossProfile data = controller.GetProfileDataEx(); + ProfileSound info = data.GetFootstepSounds(); info.EmitSound(_, this.index); this.LegacyFootstepTime = this.LegacyFootstepInterval + GetGameTime(); @@ -1379,9 +1396,7 @@ methodmap SF2_ChaserEntity < SF2_BaseBoss } int difficulty = this.Controller.Difficulty; - SF2ChaserBossProfileData data; - data = this.Controller.GetProfileData(); - int threshold = data.SoundCountToAlert[difficulty]; + int threshold = this.Controller.GetProfileDataEx().GetSoundSenseData().GetThreshold(difficulty); if (threshold <= 0) { @@ -1444,17 +1459,16 @@ methodmap SF2_ChaserEntity < SF2_BaseBoss } int difficulty = this.Controller.Difficulty; - SF2ChaserBossProfileData data; - data = this.Controller.GetProfileData(); + ChaserBossProfile data = this.Controller.GetProfileDataEx(); - if (data.AutoChaseCount[difficulty] <= 0) + if (data.GetAutoChaseData().GetThreshold(difficulty) <= 0) { return; } this.SetAutoChaseCount(player, amount); - if (this.GetAutoChaseCount(player) >= data.AutoChaseCount[difficulty]) + if (this.GetAutoChaseCount(player) >= data.GetAutoChaseData().GetThreshold(difficulty)) { player.SetForceChaseState(this.Controller, true); SetTargetMarkState(this.Controller, player, true); @@ -1476,6 +1490,13 @@ methodmap SF2_ChaserEntity < SF2_BaseBoss canAttack = false; } + ChaserBossProfile data = controller.GetProfileDataEx(); + ProfileObject attacks = data.GetSection("attacks"); + if (attacks == null || attacks.Size == 0) + { + canAttack = false; + } + if (!canAttack) { return NULL_ACTION; @@ -1486,21 +1507,26 @@ methodmap SF2_ChaserEntity < SF2_BaseBoss float gameTime = GetGameTime(); char attackName[64], posture[64]; this.GetPosture(posture, sizeof(posture)); - SF2ChaserBossProfileData data; - data = controller.GetProfileData(); int difficulty = controller.Difficulty; ArrayList arrayAttacks = new ArrayList(); - SF2ChaserBossProfileAttackData attackData; - for (int index = 0; index < data.Attacks.Length; index++) + ChaserBossProfileBaseAttack attackData; + for (int index = 0; index < data.GetAttackCount(); index++) { - data.GetAttackFromIndex(index, attackData); + attackData = data.GetAttackFromIndex(index); + if (attackData == null) + { + continue; + } + + attackData.Index = index; if (attackData.Type == SF2BossAttackType_Invalid) { continue; } - if (gameTime < this.GetNextAttackTime(attackData.Name)) + attackData.GetSectionName(attackName, sizeof(attackName)); + if (gameTime < this.GetNextAttackTime(attackName)) { continue; } @@ -1510,17 +1536,17 @@ methodmap SF2_ChaserEntity < SF2_BaseBoss continue; } - if (attackData.DontInterruptChaseInitial[difficulty] && this.IsInChaseInitial) + if (attackData.ShouldNotInterruptChaseInitial(difficulty) && this.IsInChaseInitial) { continue; } - if (!attackData.CanBeUsedWithPosture(posture)) + if (!attackData.CanUseWithPosture(posture)) { continue; } - if (!attackData.StartThroughWalls[difficulty] && (this.InterruptConditions & COND_ENEMYVISIBLE) == 0) + if (!attackData.GetStartThroughWalls(difficulty) && (this.InterruptConditions & COND_ENEMYVISIBLE_NOGLASS) == 0) { continue; } @@ -1530,7 +1556,7 @@ methodmap SF2_ChaserEntity < SF2_BaseBoss Action result = Plugin_Continue; Call_StartForward(g_OnChaserGetCustomAttackPossibleStatePFwd); Call_PushCell(this); - Call_PushString(attackData.Name); + Call_PushString(attackName); Call_PushCell(target); Call_Finish(result); @@ -1555,18 +1581,16 @@ methodmap SF2_ChaserEntity < SF2_BaseBoss { // Why must tanks use a different prop data, WHY? float health = strcmp(class, "tank_boss", false) != 0 ? float(target.GetProp(Prop_Send, "m_iHealth")) : float(target.GetProp(Prop_Data, "m_iHealth")); - if (attackData.UseOnHealth != -1.0 && health < attackData.UseOnHealth) + if (attackData.CanUseOnHealth(difficulty) != -1.0 && health < attackData.CanUseOnHealth(difficulty)) { continue; } - if (attackData.BlockOnHealth != -1.0 && health >= attackData.BlockOnHealth) + if (attackData.CanBlockOnHealth(difficulty) != -1.0 && health >= attackData.CanBlockOnHealth(difficulty)) { continue; } } - attackName = attackData.Name; - arrayAttacks.Push(index); } @@ -1595,11 +1619,12 @@ methodmap SF2_ChaserEntity < SF2_BaseBoss arrayAttacks.Sort(Sort_Random, Sort_Integer); for (int i = 0; i < arrayAttacks.Length; i++) { - data.GetAttackFromIndex(arrayAttacks.Get(i), attackData); + data.GetAttackName(arrayAttacks.Get(i), attackName, sizeof(attackName)); + attackData = data.GetAttack(attackName); if (attackData.Type != SF2BossAttackType_Custom) { - float beginRange = attackData.BeginRange[difficulty]; - float beginFOV = attackData.BeginFOV[difficulty]; + float beginRange = attackData.GetBeginRange(difficulty); + float beginFOV = attackData.GetBeginFOV(difficulty); if (distance > Pow(beginRange, 2.0)) { continue; @@ -1610,9 +1635,9 @@ methodmap SF2_ChaserEntity < SF2_BaseBoss } } - attackName = attackData.Name; + attackData.GetSectionName(attackName, sizeof(attackName)); - return SF2_ChaserAttackAction(attackName, attackData.Index, attackData.Duration[difficulty] + gameTime); + return SF2_ChaserAttackAction(data, attackName, attackData.Index, attackData.GetDuration(difficulty) + gameTime); } delete arrayAttacks; @@ -1623,15 +1648,12 @@ methodmap SF2_ChaserEntity < SF2_BaseBoss { NextBotAction nbAction = NULL_ACTION; Action action = Plugin_Continue; - SF2ChaserBossProfileData data; - data = this.Controller.GetProfileData(); - SF2ChaserBossProfileAttackData attackData; - data.GetAttack(attackName, attackData); + ChaserBossProfileBaseAttack attackData = this.Controller.GetProfileDataEx().GetAttack(attackName); Call_StartForward(g_OnBossGetCustomAttackActionFwd); Call_PushCell(this); Call_PushString(attackName); - Call_PushArrayEx(attackData, sizeof(SF2ChaserBossProfileAttackData), SM_PARAM_COPYBACK); + Call_PushCell(attackData); Call_PushCell(target); Call_PushCellRef(nbAction); Call_Finish(action); @@ -1647,15 +1669,12 @@ methodmap SF2_ChaserEntity < SF2_BaseBoss public bool IsCustomAttackPossible(const char[] attackName, CBaseEntity target) { Action action = Plugin_Continue; - SF2ChaserBossProfileData data; - data = this.Controller.GetProfileData(); - SF2ChaserBossProfileAttackData attackData; - data.GetAttack(attackName, attackData); + ChaserBossProfileBaseAttack attackData = this.Controller.GetProfileDataEx().GetAttack(attackName); Call_StartForward(g_OnIsBossCustomAttackPossibleFwd); Call_PushCell(this); Call_PushString(attackName); - Call_PushArrayEx(attackData, sizeof(SF2ChaserBossProfileAttackData), SM_PARAM_COPYBACK); + Call_PushCell(attackData); Call_PushCell(target); Call_Finish(action); @@ -1664,9 +1683,8 @@ methodmap SF2_ChaserEntity < SF2_BaseBoss public NextBotAction IsAttackTransitionPossible(const char[] attackName, bool end = false, float& duration = 0.0) { - SF2NPC_BaseNPC baseController = view_as(this.Controller); - SF2BossProfileData data; - data = baseController.GetProfileData(); + SF2NPC_Chaser controller = this.Controller; + ChaserBossProfile data = controller.GetProfileDataEx(); char section[32]; if (!end) { @@ -1676,32 +1694,18 @@ methodmap SF2_ChaserEntity < SF2_BaseBoss { strcopy(section, sizeof(section), g_SlenderAnimationsList[SF2BossAnimation_AttackEnd]); } - if (!data.AnimationData.HasAnimationSection(section)) + if (!data.GetAnimations().HasAnimationSection(section)) { return NULL_ACTION; } - char animName[64]; - float rate = 1.0, cycle = 0.0; - int difficulty = baseController.Difficulty; - if (!data.AnimationData.GetAnimation(section, difficulty, animName, sizeof(animName), rate, duration, cycle, _, _, _, attackName)) + ProfileAnimation animSection = data.GetAnimations().GetAnimation(section, .preDefinedName = attackName); + if (animSection == null) { return NULL_ACTION; } - int sequence = this.SelectProfileAnimation(section, rate, duration, cycle, _, _, _, attackName); - if (sequence == -1) - { - return NULL_ACTION; - } - - if (duration <= 0.0) - { - duration = this.SequenceDuration(sequence) / rate; - duration *= (1.0 - cycle); - } - - return SF2_PlaySequenceAndWait(sequence, duration, rate, cycle); + return SF2_PlaySequenceAndWaitEx(section); } public void DoAttackMiscConditions(const char[] attackName) @@ -1713,10 +1717,7 @@ methodmap SF2_ChaserEntity < SF2_BaseBoss { return; } - SF2ChaserBossProfileData data; - data = controller.GetProfileData(); - SF2ChaserBossProfileAttackData attackData; - data.GetAttack(attackName, attackData); + ChaserBossProfileBaseAttack attackData = controller.GetProfileDataEx().GetAttack(attackName); CBaseEntity target = this.Target; int difficulty = controller.Difficulty; @@ -1725,7 +1726,7 @@ methodmap SF2_ChaserEntity < SF2_BaseBoss bool aimAtTarget = false; if ((controller.HasAttribute(SF2Attribute_AlwaysLookAtTarget) || controller.HasAttribute(SF2Attribute_AlwaysLookAtTargetWhileAttacking)) - && !attackData.IgnoreAlwaysLooking[difficulty]) + && !attackData.ShouldNotAlwaysLook(difficulty)) { aimAtTarget = true; } @@ -1769,39 +1770,34 @@ methodmap SF2_ChaserEntity < SF2_BaseBoss return; } - SF2BossProfileData originalData; - originalData = view_as(controller).GetProfileData(); - SF2ChaserBossProfileData data; - data = controller.GetProfileData(); - SF2ChaserBossProfileAttackData attackData; - data.GetAttack(attackName, attackData); - SF2ChaserBossProfileShockwaveData shockwaveData; - shockwaveData = attackData.Shockwave; + ChaserBossProfile data = controller.GetProfileDataEx(); + ChaserBossProfileBaseAttack attackData = data.GetAttack(attackName); + BossProfileShockwave shockwaveData = attackData.GetShockwave(); - if (!shockwaveData.Enabled) + if (shockwaveData == null) { return; } int difficulty = controller.Difficulty; - float radius = shockwaveData.Radius[difficulty]; + float radius = shockwaveData.GetRadius(difficulty); if (radius <= 0.0) { return; } - if (shockwaveData.Effects != null) + if (shockwaveData.GetEffects() != null) { - SlenderSpawnEffects(shockwaveData.Effects, controller.Index, false); + SlenderSpawnEffects(shockwaveData.GetEffects(), controller.Index, false); } - float force = shockwaveData.Force[difficulty]; + float force = shockwaveData.GetForce(difficulty); float myWorldSpace[3], myPos[3]; this.WorldSpaceCenter(myWorldSpace); this.GetAbsOrigin(myPos); bool eliminated = (controller.Flags & SFF_ATTACKWAITERS) != 0; - if (originalData.IsPvEBoss) + if (data.IsPvEBoss) { eliminated = true; } @@ -1823,16 +1819,17 @@ methodmap SF2_ChaserEntity < SF2_BaseBoss continue; } - TR_TraceRayFilter(myWorldSpace, clientWorldSpace, + Handle trace = TR_TraceRayFilterEx(myWorldSpace, clientWorldSpace, CONTENTS_SOLID | CONTENTS_MOVEABLE | CONTENTS_MIST | CONTENTS_MONSTERCLIP, RayType_EndPoint, TraceRayDontHitAnyEntity, this.index); - if (!TR_DidHit() || TR_GetEntityIndex() == player.index) + if (!TR_DidHit(trace) || TR_GetEntityIndex(trace) == player.index) { float targetPos[3]; player.GetAbsOrigin(targetPos); - if (targetPos[2] > myPos[2] + shockwaveData.Height[difficulty]) + if (targetPos[2] > myPos[2] + shockwaveData.GetHeight(difficulty)) { + delete trace; continue; } @@ -1849,84 +1846,53 @@ methodmap SF2_ChaserEntity < SF2_BaseBoss player.SetPropVector(Prop_Data, "m_vecBaseVelocity", velocity); } - float amount = shockwaveData.BatteryDrainPercent[difficulty]; + float amount = shockwaveData.GetBatteryDrainPercent(difficulty); if (!IsInfiniteFlashlightEnabled() && amount > 0.0) { player.FlashlightBatteryLife -= amount; } - float sprintAmount = shockwaveData.StaminaDrainPercent[difficulty]; + float sprintAmount = shockwaveData.GetStaminaDrainPercent(difficulty); if (!IsInfiniteSprintEnabled() && sprintAmount > 0.0) { player.Stamina -= sprintAmount; } - shockwaveData.ApplyDamageEffects(player, difficulty, SF2_ChaserBossEntity(this.index)); + shockwaveData.ApplyDamageEffects(player, difficulty, this); } + + delete trace; } } - public bool SearchSoundsWithSectionName(ArrayList base, const char[] name, SF2BossProfileSoundInfo output) + public bool SearchSoundsWithSectionName(ProfileObject base, const char[] name, ProfileSound& output, char[] section) { - if (base == null || base.Length <= 0) + if (base == null) { return false; } - if (base.Length == 1) + ChaserBossProfile data = this.Controller.GetProfileDataEx(); + char arrayName[64]; + FormatEx(arrayName, sizeof(arrayName), "__chaser_%s_sounds", section); + KeyMap_Array array = data.GetArray(arrayName); + if (array == null) { - base.GetArray(0, output, sizeof(output)); - if (output.SectionName[0] == '\0') - { - return true; - } + output = view_as(base); + return true; } - for (int i = 0; i < base.Length; i++) + for (int i = 0; i < array.Length; i++) { - base.GetArray(i, output, sizeof(output)); - if (strcmp(output.SectionName, name) == 0) + char keyName[64]; + array.GetString(i, keyName, sizeof(keyName)); + if (keyName[0] != '\0' && strcmp(keyName, name) == 0) { + output = view_as(base.GetSection(keyName)); return true; } } return false; } - public void DoAlwaysLookAt(CBaseEntity target) - { - if (!target.IsValid()) - { - return; - } - - SF2_BasePlayer player = SF2_BasePlayer(target.index); - if (player.IsValid && !player.IsAlive) - { - return; - } - - INextBot bot = this.MyNextBotPointer(); - ILocomotion loco = bot.GetLocomotionInterface(); - bool tooClose = this.GetIsVisible(player) && bot.IsRangeLessThan(target.index, 16.0) && this.State != STATE_STUN && this.State != STATE_DEATH && !this.IsKillingSomeone; - SF2NPC_Chaser controller = this.Controller; - if (!controller.IsValid()) - { - return; - } - if (!tooClose && !controller.HasAttribute(SF2Attribute_AlwaysLookAtTarget) && !controller.HasAttribute(SF2Attribute_AlwaysLookAtTargetWhileChasing)) - { - return; - } - - if ((this.InterruptConditions & COND_ENEMYVISIBLE) == 0) - { - return; - } - - float pos[3]; - target.GetAbsOrigin(pos); - loco.FaceTowards(pos); - } - public void RegisterProjectiles(bool &isFake = false) { if (g_RestartSessionEnabled) @@ -1938,15 +1904,14 @@ methodmap SF2_ChaserEntity < SF2_BaseBoss { return; } - SF2ChaserBossProfileData data; - data = controller.GetProfileData(); - if (!data.ProjectilesEnabled) + ChaserBossProfile data = controller.GetProfileDataEx(); + ChaserBossProjectileData projectileData = data.GetProjectiles(); + int difficulty = controller.Difficulty; + if (!projectileData.IsEnabled(difficulty)) { return; } - int difficulty = controller.Difficulty; - float gameTime = GetGameTime(); if (this.ProjectileCooldown > gameTime) @@ -1954,12 +1919,12 @@ methodmap SF2_ChaserEntity < SF2_BaseBoss return; } - if ((this.InterruptConditions & COND_ENEMYVISIBLE) == 0) + if ((this.InterruptConditions & COND_ENEMYVISIBLE_NOGLASS) == 0) { return; } - if (!data.ProjectileClips) + if (!projectileData.ProjectileClips) { if (controller.Flags & SFF_FAKE) { @@ -1980,12 +1945,12 @@ methodmap SF2_ChaserEntity < SF2_BaseBoss { if (!this.IsReloadingProjectiles) { - this.ProjectileReloadTime = gameTime + data.ProjectileReloadTime[difficulty]; + this.ProjectileReloadTime = gameTime + projectileData.GetReloadTime(difficulty); this.IsReloadingProjectiles = true; } if (this.ProjectileReloadTime <= gameTime && this.IsReloadingProjectiles) { - this.ProjectileAmmo = data.ProjectileClipSize[difficulty]; + this.ProjectileAmmo = projectileData.GetClipSize(difficulty); this.IsReloadingProjectiles = false; } } @@ -2004,16 +1969,13 @@ methodmap SF2_ChaserEntity < SF2_BaseBoss this.GetAbsAngles(myAng); this.Target.WorldSpaceCenter(targetPos); int difficulty = controller.Difficulty; - SF2ChaserBossProfileData data; - data = controller.GetProfileData(); - SF2BossProfileData originalData; - originalData = view_as(controller).GetProfileData(); - int randomPosMin = data.ProjectileRandomPosMin; - int randomPosMax = data.ProjectileRandomPosMax; - ArrayList array = data.ProjectilePosOffsets; + ChaserBossProfile data = controller.GetProfileDataEx(); + ChaserBossProjectileData projectileData = data.GetProjectiles(); + int randomPosMin = projectileData.MinRandomPos; + int randomPosMax = projectileData.MaxRandomPos; bool attackWaiters = (controller.Flags & SFF_ATTACKWAITERS) != 0; - if (originalData.IsPvEBoss) + if (data.IsPvEBoss) { attackWaiters = true; } @@ -2022,121 +1984,142 @@ methodmap SF2_ChaserEntity < SF2_BaseBoss if (randomPosMin == randomPosMax) { - array.GetArray(0, effectPos); + projectileData.GetOffset(1, effectPos); } else { - array.GetArray(GetRandomInt(randomPosMin, randomPosMax), effectPos); + projectileData.GetOffset(GetRandomInt(randomPosMin, randomPosMax), effectPos); } VectorTransform(effectPos, myPos, myAng, effectPos); - for (int i = 0; i < data.ProjectileCount[difficulty]; i++) + for (int i = 0; i < projectileData.GetCount(difficulty); i++) { float direction[3], angle[3]; SubtractVectors(targetPos, effectPos, direction); - float deviation = data.ProjectileDeviation[difficulty]; + float deviation = projectileData.GetDeviation(difficulty); + NormalizeVector(direction, direction); + GetVectorAngles(direction, angle); if (deviation != 0) { - direction[0] += GetRandomFloat(-deviation, deviation); - direction[1] += GetRandomFloat(-deviation, deviation); - direction[2] += GetRandomFloat(-deviation, deviation); + angle[0] += GetRandomFloat(-deviation, deviation); + angle[1] += GetRandomFloat(-deviation, deviation); + angle[2] += GetRandomFloat(-deviation, deviation); } - NormalizeVector(direction, direction); - GetVectorAngles(direction, angle); - switch (data.ProjectileType) + char sound[PLATFORM_MAX_PATH]; + + switch (projectileData.Type) { case SF2BossProjectileType_Fireball: { - SF2_ProjectileFireball.Create(this, effectPos, angle, data.ProjectileSpeed[difficulty], data.ProjectileDamage[difficulty], - data.ProjectileRadius[difficulty], data.FireballExplodeSound, data.FireballTrail, attackWaiters); + char trail[PLATFORM_MAX_PATH]; + projectileData.GetFireballExplodeSound(sound, sizeof(sound)); + projectileData.GetFireballTrail(trail, sizeof(trail)); + SF2_ProjectileFireball.Create(this, effectPos, angle, projectileData.GetSpeed(difficulty), projectileData.GetDamage(difficulty), + projectileData.GetRadius(difficulty), sound, trail, attackWaiters); + projectileData.GetFireballShootSound(sound, sizeof(sound)); if (i == 0) { - EmitSoundToAll(data.FireballShootSound, this.index, SNDCHAN_ITEM, SNDLEVEL_SCREAMING); + EmitSoundToAll(sound, this.index, SNDCHAN_ITEM, SNDLEVEL_SCREAMING); } } case SF2BossProjectileType_Iceball: { - SF2_ProjectileIceball.Create(this, effectPos, angle, data.ProjectileSpeed[difficulty], data.ProjectileDamage[difficulty], - data.ProjectileRadius[difficulty], data.FireballExplodeSound, data.IceballTrail, data.IceballSlowDuration[difficulty], data.IceballSlowPercent[difficulty], data.IceballSlowSound, attackWaiters); + char trail[PLATFORM_MAX_PATH], slow[PLATFORM_MAX_PATH]; + projectileData.GetFireballExplodeSound(sound, sizeof(sound)); + projectileData.GetIceballTrail(trail, sizeof(trail)); + projectileData.GetIceballSlowSound(slow, sizeof(slow)); + SF2_ProjectileIceball.Create(this, effectPos, angle, projectileData.GetSpeed(difficulty), projectileData.GetDamage(difficulty), + projectileData.GetRadius(difficulty), sound, trail, projectileData.GetIceballSlowDuration(difficulty), projectileData.GetIceballSlowPercent(difficulty), slow, attackWaiters); + projectileData.GetIceballSlowSound(sound, sizeof(sound)); if (i == 0) { - EmitSoundToAll(data.FireballShootSound, this.index, SNDCHAN_ITEM, SNDLEVEL_SCREAMING); + EmitSoundToAll(sound, this.index, SNDCHAN_ITEM, SNDLEVEL_SCREAMING); } } case SF2BossProjectileType_Rocket: { - SF2_ProjectileRocket.Create(this, effectPos, angle, data.ProjectileSpeed[difficulty], data.ProjectileDamage[difficulty], - data.ProjectileRadius[difficulty], data.CriticalProjectiles, data.RocketTrail, data.RocketExplodeParticle, data.RocketExplodeSound, data.RocketModel, attackWaiters); + char trail[PLATFORM_MAX_PATH], particle[PLATFORM_MAX_PATH], model[PLATFORM_MAX_PATH]; + projectileData.GetRocketExplodeSound(sound, sizeof(sound)); + projectileData.GetRocketTrail(trail, sizeof(trail)); + projectileData.GetRocketExplodeParticle(particle, sizeof(particle)); + projectileData.GetRocketModel(model, sizeof(model)); + SF2_ProjectileRocket.Create(this, effectPos, angle, projectileData.GetSpeed(difficulty), projectileData.GetDamage(difficulty), + projectileData.GetRadius(difficulty), projectileData.GetCritState(difficulty), trail, particle, sound, model, attackWaiters); + projectileData.GetRocketShootSound(sound, sizeof(sound)); if (i == 0) { - EmitSoundToAll(data.RocketShootSound, this.index, SNDCHAN_ITEM, SNDLEVEL_SCREAMING); + EmitSoundToAll(sound, this.index, SNDCHAN_ITEM, SNDLEVEL_SCREAMING); } } case SF2BossProjectileType_SentryRocket: { - SF2_ProjectileSentryRocket.Create(this, effectPos, angle, data.ProjectileSpeed[difficulty], data.ProjectileDamage[difficulty], - data.ProjectileRadius[difficulty], data.CriticalProjectiles, attackWaiters); + projectileData.GetSentryRocketShootSound(sound, sizeof(sound)); + SF2_ProjectileSentryRocket.Create(this, effectPos, angle, projectileData.GetSpeed(difficulty), projectileData.GetDamage(difficulty), + projectileData.GetRadius(difficulty), projectileData.GetCritState(difficulty), attackWaiters); if (i == 0) { - EmitSoundToAll(data.SentryRocketShootSound, this.index, SNDCHAN_ITEM, SNDLEVEL_SCREAMING); + EmitSoundToAll(sound, this.index, SNDCHAN_ITEM, SNDLEVEL_SCREAMING); } } case SF2BossProjectileType_Mangler: { - SF2_ProjectileCowMangler.Create(this, effectPos, angle, data.ProjectileSpeed[difficulty], data.ProjectileDamage[difficulty], - data.ProjectileRadius[difficulty], attackWaiters); + projectileData.GetManglerShootSound(sound, sizeof(sound)); + SF2_ProjectileCowMangler.Create(this, effectPos, angle, projectileData.GetSpeed(difficulty), projectileData.GetDamage(difficulty), + projectileData.GetRadius(difficulty), attackWaiters); if (i == 0) { - EmitSoundToAll(data.ManglerShootSound, this.index, SNDCHAN_ITEM, SNDLEVEL_SCREAMING); + EmitSoundToAll(sound, this.index, SNDCHAN_ITEM, SNDLEVEL_SCREAMING); } } case SF2BossProjectileType_Grenade: { - SF2_ProjectileGrenade.Create(this, effectPos, angle, data.ProjectileSpeed[difficulty], data.ProjectileDamage[difficulty], - data.ProjectileRadius[difficulty], data.CriticalProjectiles, "pipebombtrail_blue", ROCKET_EXPLODE_PARTICLE, ROCKET_IMPACT, "models/weapons/w_models/w_grenade_grenadelauncher.mdl", attackWaiters); + projectileData.GetGrenadeShootSound(sound, sizeof(sound)); + SF2_ProjectileGrenade.Create(this, effectPos, angle, projectileData.GetSpeed(difficulty), projectileData.GetDamage(difficulty), + projectileData.GetRadius(difficulty), projectileData.GetCritState(difficulty), "pipebombtrail_blue", ROCKET_EXPLODE_PARTICLE, ROCKET_IMPACT, "models/weapons/w_models/w_grenade_grenadelauncher.mdl", attackWaiters); if (i == 0) { - EmitSoundToAll(data.GrenadeShootSound, this.index, SNDCHAN_ITEM, SNDLEVEL_SCREAMING); + EmitSoundToAll(sound, this.index, SNDCHAN_ITEM, SNDLEVEL_SCREAMING); } } case SF2BossProjectileType_Arrow: { - SF2_ProjectileArrow.Create(this, effectPos, angle, data.ProjectileSpeed[difficulty], data.ProjectileDamage[difficulty], - data.CriticalProjectiles, "pipebombtrail_blue", "weapons/fx/rics/arrow_impact_flesh2.wav", "models/weapons/w_models/w_arrow.mdl", attackWaiters); + projectileData.GetArrowShootSound(sound, sizeof(sound)); + SF2_ProjectileArrow.Create(this, effectPos, angle, projectileData.GetSpeed(difficulty), projectileData.GetDamage(difficulty), + projectileData.GetCritState(difficulty), "pipebombtrail_blue", "weapons/fx/rics/arrow_impact_flesh2.wav", "models/weapons/w_models/w_arrow.mdl", attackWaiters); if (i == 0) { - EmitSoundToAll(data.ArrowShootSound, this.index, SNDCHAN_ITEM, SNDLEVEL_SCREAMING); + EmitSoundToAll(sound, this.index, SNDCHAN_ITEM, SNDLEVEL_SCREAMING); } } case SF2BossProjectileType_Baseball: { - SF2_ProjectileBaseball.Create(this, effectPos, angle, data.ProjectileSpeed[difficulty], data.ProjectileDamage[difficulty], - data.CriticalProjectiles, "models/weapons/w_models/w_baseball.mdl", attackWaiters); + projectileData.GetBaseballShootSound(sound, sizeof(sound)); + SF2_ProjectileBaseball.Create(this, effectPos, angle, projectileData.GetSpeed(difficulty), projectileData.GetDamage(difficulty), + projectileData.GetCritState(difficulty), "models/weapons/w_models/w_baseball.mdl", attackWaiters); if (i == 0) { - EmitSoundToAll(data.BaseballShootSound, this.index, SNDCHAN_ITEM, SNDLEVEL_SCREAMING); + EmitSoundToAll(sound, this.index, SNDCHAN_ITEM, SNDLEVEL_SCREAMING); } } } } - if (data.ShootGestures) + char gesture[64]; + projectileData.GetShootGesture(gesture, sizeof(gesture)); + if (gesture[0] != '\0') { - this.RemoveAllGestures(); - char gesture[64]; - strcopy(gesture, sizeof(gesture), data.ShootGestureName); - int sequence = this.LookupSequence(gesture); if (sequence != -1) { + this.RemoveAllGestures(); this.AddGestureSequence(sequence); } } - this.ProjectileCooldown = GetRandomFloat(data.ProjectileCooldownMin[difficulty], data.ProjectileCooldownMax[difficulty]) + GetGameTime(); + this.ProjectileCooldown = GetRandomFloat(projectileData.GetMinCooldown(difficulty), projectileData.GetMaxCooldown(difficulty)) + GetGameTime(); } public void CheckTauntKill(SF2_BasePlayer player) @@ -2157,15 +2140,21 @@ methodmap SF2_ChaserEntity < SF2_BaseBoss int difficulty = controller.Difficulty; SF2NPC_BaseNPC copyMaster = controller.CopyMaster; SF2NPC_BaseNPC companionMaster = controller.CompanionMaster; - SF2ChaserBossProfileData data, otherData; - data = controller.GetProfileData(); + ChaserBossProfile data, otherData; + data = controller.GetProfileDataEx(); + ChaserBossAlertOnStateData alertStateData, otherAlertStateData; + if (data.GetAlertBehavior() == null) + { + return; + } + alertStateData = data.GetAlertBehavior().GetAlertSyncData(); - if (!data.AlertOnAlertInfo.Enabled[difficulty]) + if (!alertStateData.IsEnabled(difficulty)) { return; } - if (!data.AlertOnAlertInfo.Copies[difficulty] && !data.AlertOnAlertInfo.Companions[difficulty]) + if (!alertStateData.GetCopies(difficulty) && !alertStateData.GetCompanions(difficulty)) { return; } @@ -2188,12 +2177,17 @@ methodmap SF2_ChaserEntity < SF2_BaseBoss } SF2NPC_BaseNPC otherController = SF2NPC_BaseNPC(index); - if (!otherController.IsValid() || otherController.Type != SF2BossType_Chaser || otherController.EntIndex == INVALID_ENT_REFERENCE) + if (!otherController.IsValid() || otherController.GetProfileDataEx().Type != SF2BossType_Chaser || otherController.EntIndex == INVALID_ENT_REFERENCE) { continue; } - otherData = view_as(otherController).GetProfileData(); + otherData = view_as(otherController).GetProfileDataEx(); + if (otherData.GetAlertBehavior() == null) + { + continue; + } + otherAlertStateData = otherData.GetAlertBehavior().GetAlertSyncData(); SF2_ChaserEntity otherChaser = SF2_ChaserEntity(otherController.EntIndex); if (!otherChaser.IsValid()) { @@ -2208,7 +2202,7 @@ methodmap SF2_ChaserEntity < SF2_BaseBoss SF2NPC_BaseNPC otherCopyMaster = otherController.CopyMaster; SF2NPC_BaseNPC otherCompanionMaster = otherController.CompanionMaster; bool doContinue = false; - if (data.AlertOnAlertInfo.Copies[difficulty]) + if (alertStateData.GetCopies(difficulty)) { if (copyMaster != otherController && otherCopyMaster != copyMaster && otherCopyMaster != controller) { @@ -2216,7 +2210,7 @@ methodmap SF2_ChaserEntity < SF2_BaseBoss } } - if (data.AlertOnAlertInfo.Companions[difficulty]) + if (alertStateData.GetCompanions(difficulty)) { SF2NPC_BaseNPC tempCompanionMaster = companionMaster, tempOtherCompanionMaster = otherCompanionMaster; if (otherController.IsCopy) @@ -2265,12 +2259,12 @@ methodmap SF2_ChaserEntity < SF2_BaseBoss } float distance = this.MyNextBotPointer().GetRangeSquaredTo(otherController.EntIndex); - if (distance > Pow(otherData.AlertOnAlertInfo.Radius[difficulty], 2.0)) + if (distance > Pow(otherAlertStateData.GetRadius(difficulty), 2.0)) { continue; } - if (otherData.AlertOnAlertInfo.ShouldBeVisible[difficulty] && !otherChaser.IsLOSClearFromTarget(this)) + if (otherAlertStateData.ShouldBeVisible(difficulty) && !otherChaser.IsLOSClearFromTarget(this)) { continue; } @@ -2290,21 +2284,27 @@ methodmap SF2_ChaserEntity < SF2_BaseBoss int difficulty = controller.Difficulty; SF2NPC_BaseNPC copyMaster = controller.CopyMaster; SF2NPC_BaseNPC companionMaster = controller.CompanionMaster; - SF2ChaserBossProfileData data, otherData; - data = controller.GetProfileData(); + ChaserBossProfile data, otherData; + data = controller.GetProfileDataEx(); + ChaserBossAlertOnStateData alertStateData, otherAlertStateData; + if (data.GetAlertBehavior() == null) + { + return; + } + alertStateData = data.GetAlertBehavior().GetAlertSyncData(); float gameTime = GetGameTime(); - if (!data.AlertOnAlertInfo.Enabled[difficulty]) + if (!alertStateData.IsEnabled(difficulty)) { return; } - if (!data.AlertOnAlertInfo.Copies[difficulty] && !data.AlertOnAlertInfo.Companions[difficulty]) + if (!alertStateData.GetCopies(difficulty) && !alertStateData.GetCompanions(difficulty)) { return; } - if (!data.AlertOnAlertInfo.Follow[difficulty] || this.FollowedCompanionAlert || gameTime < this.FollowCooldownAlert) + if (!alertStateData.ShouldFollow(difficulty) || this.FollowedCompanionAlert || gameTime < this.FollowCooldownAlert) { return; } @@ -2322,7 +2322,7 @@ methodmap SF2_ChaserEntity < SF2_BaseBoss } SF2NPC_BaseNPC otherController = SF2NPC_BaseNPC(index); - if (!otherController.IsValid() || otherController.Type != SF2BossType_Chaser || otherController.EntIndex == INVALID_ENT_REFERENCE) + if (!otherController.IsValid() || otherController.GetProfileDataEx().Type != SF2BossType_Chaser || otherController.EntIndex == INVALID_ENT_REFERENCE) { continue; } @@ -2333,9 +2333,14 @@ methodmap SF2_ChaserEntity < SF2_BaseBoss continue; } - otherData = view_as(otherController).GetProfileData(); + otherData = view_as(otherController).GetProfileDataEx(); + if (otherData.GetAlertBehavior() == null) + { + continue; + } + otherAlertStateData = otherData.GetAlertBehavior().GetAlertSyncData(); - if (!otherData.AlertOnAlertInfo.Copies[difficulty] && !otherData.AlertOnAlertInfo.Companions[difficulty]) + if (!otherAlertStateData.GetCopies(difficulty) && !otherAlertStateData.GetCompanions(difficulty)) { continue; } @@ -2343,7 +2348,7 @@ methodmap SF2_ChaserEntity < SF2_BaseBoss SF2NPC_BaseNPC otherCopyMaster = otherController.CopyMaster; SF2NPC_BaseNPC otherCompanionMaster = otherController.CompanionMaster; bool doContinue = false; - if (data.AlertOnAlertInfo.Copies[difficulty]) + if (alertStateData.GetCopies(difficulty)) { if (copyMaster != otherController && otherCopyMaster != copyMaster && otherCopyMaster != controller) { @@ -2351,7 +2356,7 @@ methodmap SF2_ChaserEntity < SF2_BaseBoss } } - if (data.AlertOnAlertInfo.Companions[difficulty]) + if (alertStateData.GetCompanions(difficulty)) { SF2NPC_BaseNPC tempCompanionMaster = companionMaster, tempOtherCompanionMaster = otherCompanionMaster; if (otherController.IsCopy) @@ -2400,12 +2405,12 @@ methodmap SF2_ChaserEntity < SF2_BaseBoss } float distance = this.MyNextBotPointer().GetRangeSquaredTo(otherController.EntIndex); - if (distance > Pow(otherData.AlertOnAlertInfo.Radius[difficulty], 2.0)) + if (distance > Pow(otherAlertStateData.GetRadius(difficulty), 2.0)) { continue; } - if (otherData.AlertOnAlertInfo.ShouldBeVisible[difficulty] && !otherChaser.IsLOSClearFromTarget(this)) + if (otherAlertStateData.ShouldBeVisible(difficulty) && !otherChaser.IsLOSClearFromTarget(this)) { continue; } @@ -2442,15 +2447,21 @@ methodmap SF2_ChaserEntity < SF2_BaseBoss int difficulty = controller.Difficulty; SF2NPC_BaseNPC copyMaster = controller.CopyMaster; SF2NPC_BaseNPC companionMaster = controller.CompanionMaster; - SF2ChaserBossProfileData data, otherData; - data = controller.GetProfileData(); + ChaserBossProfile data, otherData; + data = controller.GetProfileDataEx(); + ChaserBossAlertOnStateData alertStateData, otherAlertStateData; + if (data.GetChaseBehavior() == null) + { + return; + } + alertStateData = data.GetChaseBehavior().GetChaseTogetherData(); - if (!data.AlertOnChaseInfo.Enabled[difficulty]) + if (!alertStateData.IsEnabled(difficulty)) { return; } - if (!data.AlertOnChaseInfo.Copies[difficulty] && !data.AlertOnChaseInfo.Companions[difficulty]) + if (!alertStateData.GetCopies(difficulty) && !alertStateData.GetCompanions(difficulty)) { return; } @@ -2463,12 +2474,17 @@ methodmap SF2_ChaserEntity < SF2_BaseBoss } SF2NPC_BaseNPC otherController = SF2NPC_BaseNPC(index); - if (!otherController.IsValid() || otherController.Type != SF2BossType_Chaser || otherController.EntIndex == INVALID_ENT_REFERENCE) + if (!otherController.IsValid() || otherController.GetProfileDataEx().Type != SF2BossType_Chaser || otherController.EntIndex == INVALID_ENT_REFERENCE) { continue; } - otherData = view_as(otherController).GetProfileData(); + otherData = view_as(otherController).GetProfileDataEx(); + if (otherData.GetChaseBehavior() == null) + { + continue; + } + otherAlertStateData = otherData.GetChaseBehavior().GetChaseTogetherData(); SF2_ChaserEntity otherChaser = SF2_ChaserEntity(otherController.EntIndex); if (!otherChaser.IsValid()) { @@ -2483,7 +2499,7 @@ methodmap SF2_ChaserEntity < SF2_BaseBoss SF2NPC_BaseNPC otherCopyMaster = otherController.CopyMaster; SF2NPC_BaseNPC otherCompanionMaster = otherController.CompanionMaster; bool doContinue = false; - if (data.AlertOnChaseInfo.Copies[difficulty]) + if (alertStateData.GetCopies(difficulty)) { if (copyMaster != otherController && otherCopyMaster != copyMaster && otherCopyMaster != controller) { @@ -2491,7 +2507,7 @@ methodmap SF2_ChaserEntity < SF2_BaseBoss } } - if (data.AlertOnChaseInfo.Companions[difficulty]) + if (alertStateData.GetCompanions(difficulty)) { SF2NPC_BaseNPC tempCompanionMaster = companionMaster, tempOtherCompanionMaster = otherCompanionMaster; if (otherController.IsCopy) @@ -2540,12 +2556,12 @@ methodmap SF2_ChaserEntity < SF2_BaseBoss } float distance = this.MyNextBotPointer().GetRangeSquaredTo(otherController.EntIndex); - if (distance > Pow(otherData.AlertOnChaseInfo.Radius[difficulty], 2.0)) + if (distance > Pow(otherAlertStateData.GetRadius(difficulty), 2.0)) { continue; } - if (otherData.AlertOnChaseInfo.ShouldBeVisible[difficulty] && !otherChaser.IsLOSClearFromTarget(this)) + if (otherAlertStateData.ShouldBeVisible(difficulty) && !otherChaser.IsLOSClearFromTarget(this)) { continue; } @@ -2568,16 +2584,22 @@ methodmap SF2_ChaserEntity < SF2_BaseBoss int difficulty = controller.Difficulty; SF2NPC_BaseNPC copyMaster = controller.CopyMaster; SF2NPC_BaseNPC companionMaster = controller.CompanionMaster; - SF2ChaserBossProfileData data, otherData; - data = controller.GetProfileData(); + ChaserBossProfile data, otherData; + data = controller.GetProfileDataEx(); + ChaserBossAlertOnStateData alertStateData, otherAlertStateData; + if (data.GetChaseBehavior() == null) + { + return; + } + alertStateData = data.GetChaseBehavior().GetChaseTogetherData(); float gameTime = GetGameTime(); - if (!data.AlertOnChaseInfo.Enabled[difficulty] || !data.AlertOnChaseInfo.Follow[difficulty]) + if (!alertStateData.IsEnabled(difficulty) || !alertStateData.ShouldFollow(difficulty)) { return; } - if (!data.AlertOnChaseInfo.Copies[difficulty] && !data.AlertOnChaseInfo.Companions[difficulty]) + if (!alertStateData.GetCopies(difficulty) && !alertStateData.GetCompanions(difficulty)) { return; } @@ -2600,7 +2622,7 @@ methodmap SF2_ChaserEntity < SF2_BaseBoss } SF2NPC_BaseNPC otherController = SF2NPC_BaseNPC(index); - if (!otherController.IsValid() || otherController.Type != SF2BossType_Chaser || otherController.EntIndex == INVALID_ENT_REFERENCE) + if (!otherController.IsValid() || otherController.GetProfileDataEx().Type != SF2BossType_Chaser || otherController.EntIndex == INVALID_ENT_REFERENCE) { continue; } @@ -2611,9 +2633,14 @@ methodmap SF2_ChaserEntity < SF2_BaseBoss continue; } - otherData = view_as(otherController).GetProfileData(); + otherData = view_as(otherController).GetProfileDataEx(); + if (otherData.GetChaseBehavior() == null) + { + continue; + } + otherAlertStateData = otherData.GetChaseBehavior().GetChaseTogetherData(); - if (!otherData.AlertOnChaseInfo.Copies[difficulty] && !otherData.AlertOnChaseInfo.Companions[difficulty]) + if (!otherAlertStateData.GetCopies(difficulty) && !otherAlertStateData.GetCompanions(difficulty)) { continue; } @@ -2621,7 +2648,7 @@ methodmap SF2_ChaserEntity < SF2_BaseBoss SF2NPC_BaseNPC otherCopyMaster = otherController.CopyMaster; SF2NPC_BaseNPC otherCompanionMaster = otherController.CompanionMaster; bool doContinue = false; - if (data.AlertOnChaseInfo.Copies[difficulty]) + if (alertStateData.GetCopies(difficulty)) { if (copyMaster != otherController && otherCopyMaster != copyMaster && otherCopyMaster != controller) { @@ -2629,7 +2656,7 @@ methodmap SF2_ChaserEntity < SF2_BaseBoss } } - if (data.AlertOnChaseInfo.Companions[difficulty]) + if (alertStateData.GetCompanions(difficulty)) { SF2NPC_BaseNPC tempCompanionMaster = companionMaster, tempOtherCompanionMaster = otherCompanionMaster; if (otherController.IsCopy) @@ -2678,12 +2705,12 @@ methodmap SF2_ChaserEntity < SF2_BaseBoss } float distance = this.MyNextBotPointer().GetRangeSquaredTo(otherController.EntIndex); - if (distance > Pow(otherData.AlertOnChaseInfo.Radius[difficulty], 2.0)) + if (distance > Pow(otherAlertStateData.GetRadius(difficulty), 2.0)) { continue; } - if (otherData.AlertOnChaseInfo.ShouldBeVisible[difficulty] && !otherChaser.IsLOSClearFromTarget(this)) + if (otherAlertStateData.ShouldBeVisible(difficulty) && !otherChaser.IsLOSClearFromTarget(this)) { continue; } @@ -2706,11 +2733,11 @@ methodmap SF2_ChaserEntity < SF2_BaseBoss { return; } - SF2ChaserBossProfileData data; - data = controller.GetProfileData(); + ChaserBossProfile data = controller.GetProfileDataEx(); + ChaserBossProfileCloakData cloakData = data.GetCloakData(); int difficulty = controller.Difficulty; float gameTime = GetGameTime(); - if (!data.CloakData.Enabled[difficulty]) + if (!cloakData.IsEnabled(difficulty)) { return; } @@ -2733,13 +2760,13 @@ methodmap SF2_ChaserEntity < SF2_BaseBoss float targetPos[3], myPos[3]; target.GetAbsOrigin(targetPos); this.GetAbsOrigin(myPos); - if (this.HasCloaked && GetVectorSquareMagnitude(targetPos, myPos) <= Pow(data.CloakData.DecloakRange[difficulty], 2.0)) + if (this.HasCloaked && GetVectorSquareMagnitude(targetPos, myPos) <= Pow(cloakData.GetDecloakRange(difficulty), 2.0)) { this.EndCloak(); return; } - if (!this.HasCloaked && GetVectorSquareMagnitude(targetPos, myPos) > Pow(data.CloakData.CloakRange[difficulty], 2.0)) + if (!this.HasCloaked && GetVectorSquareMagnitude(targetPos, myPos) > Pow(cloakData.GetCloakRange(difficulty), 2.0)) { return; } @@ -2765,22 +2792,28 @@ methodmap SF2_ChaserEntity < SF2_BaseBoss } SF2NPC_Chaser controller = this.Controller; - SF2ChaserBossProfileData data; - data = controller.GetProfileData(); + ChaserBossProfile data = controller.GetProfileDataEx(); + ChaserBossProfileCloakData cloakData = data.GetCloakData(); int difficulty = controller.Difficulty; - if (!data.CloakData.Enabled[difficulty]) + if (!cloakData.IsEnabled(difficulty)) { return; } - this.SetRenderMode(view_as(data.CloakData.CloakRenderMode)); - this.SetRenderColor(data.CloakData.CloakRenderColor[0], data.CloakData.CloakRenderColor[1], data.CloakData.CloakRenderColor[2], data.CloakData.CloakRenderColor[3]); + this.SetRenderMode(cloakData.GetRenderMode(difficulty)); + this.SetRenderFx(cloakData.GetRenderFx(difficulty)); + int color[4]; + cloakData.GetRenderColor(color); + this.SetRenderColor(color[0], color[1], color[2], color[3]); this.HasCloaked = true; - this.CloakTime = GetGameTime() + data.CloakData.Duration[difficulty]; + this.CloakTime = GetGameTime() + cloakData.GetDuration(difficulty); float worldPos[3]; this.WorldSpaceCenter(worldPos); SlenderToggleParticleEffects(this.index); - SlenderSpawnEffects(data.CloakData.CloakEffects, controller.Index, false); + if (cloakData.GetCloakEffects() != null) + { + SlenderSpawnEffects(cloakData.GetCloakEffects(), controller.Index, false); + } Call_StartForward(g_OnBossCloakedFwd); Call_PushCell(controller.Index); Call_Finish(); @@ -2793,22 +2826,28 @@ methodmap SF2_ChaserEntity < SF2_BaseBoss return; } SF2NPC_Chaser controller = this.Controller; - SF2ChaserBossProfileData data; - data = controller.GetProfileData(); + ChaserBossProfile data = controller.GetProfileDataEx(); + ChaserBossProfileCloakData cloakData = data.GetCloakData(); int difficulty = controller.Difficulty; - if (!data.CloakData.Enabled[difficulty]) + if (!cloakData.IsEnabled(difficulty)) { return; } - this.SetRenderMode(view_as(controller.GetRenderMode)); - this.SetRenderColor(controller.GetRenderColor(0), controller.GetRenderColor(1), controller.GetRenderColor(2), controller.GetRenderColor(3)); + this.SetRenderMode(data.GetRenderMode(difficulty)); + this.SetRenderFx(data.GetRenderFx(difficulty)); + int color[4]; + data.GetRenderColor(difficulty, color); + this.SetRenderColor(color[0], color[1], color[2], color[3]); this.HasCloaked = false; - this.CloakTime = GetGameTime() + data.CloakData.Cooldown[difficulty]; + this.CloakTime = GetGameTime() + cloakData.GetCooldown(difficulty); float worldPos[3]; this.WorldSpaceCenter(worldPos); SlenderToggleParticleEffects(this.index, true); - SlenderSpawnEffects(data.CloakData.DecloakEffects, controller.Index, false); + if (cloakData.GetDecloakEffects() != null) + { + SlenderSpawnEffects(cloakData.GetDecloakEffects(), controller.Index, false); + } Call_StartForward(g_OnBossDecloakedFwd); Call_PushCell(controller.Index); Call_Finish(); @@ -2817,16 +2856,17 @@ methodmap SF2_ChaserEntity < SF2_BaseBoss public void DropItem(bool death = false) { SF2NPC_Chaser controller = this.Controller; - SF2ChaserBossProfileData data; - data = controller.GetProfileData(); + ChaserBossProfile data = controller.GetProfileDataEx(); + ChaserBossProfileStunData stunData = data.GetStunBehavior(); + ChaserBossProfileDeathData deathData = data.GetDeathBehavior(); int difficulty = controller.Difficulty; - bool check = !death ? data.StunData.ItemDrop[difficulty] : data.DeathData.ItemDrop[difficulty]; + bool check = !death ? stunData.CanDropItem(difficulty) : deathData.CanDropItem(difficulty); if (!check) { return; } - int type = !death ? data.StunData.ItemDropType[difficulty] : data.DeathData.ItemDropType[difficulty]; + int type = !death ? stunData.GetItemDropType(difficulty) : deathData.GetItemDropType(difficulty); char class[64]; switch (type) { @@ -2878,10 +2918,9 @@ methodmap SF2_ChaserEntity < SF2_BaseBoss public void ProcessTraps() { SF2NPC_Chaser controller = this.Controller; - SF2ChaserBossProfileData data; - data = controller.GetProfileData(); + ChaserBossProfile data = controller.GetProfileDataEx(); int difficulty = controller.Difficulty; - if (!data.Traps[difficulty]) + if (!data.HasTraps(difficulty)) { return; } @@ -2901,7 +2940,7 @@ methodmap SF2_ChaserEntity < SF2_BaseBoss this.GetAbsOrigin(myPos); this.GetAbsAngles(myAng); Trap_SpawnTrap(myPos, myAng, controller); - this.TrapCooldown = gameTime + data.TrapCooldown[difficulty]; + this.TrapCooldown = gameTime + data.GetTrapCooldown(difficulty); } public static SF2_ChaserEntity Create(SF2NPC_BaseNPC controller, const float pos[3], const float ang[3]) @@ -2920,10 +2959,8 @@ methodmap SF2_ChaserEntity < SF2_BaseBoss controller.GetProfile(profile, sizeof(profile)); chaser.Controller = view_as(controller); - SF2ChaserBossProfileData data; - data = chaser.Controller.GetProfileData(); - SF2BossProfileData originalData; - originalData = view_as(chaser.Controller).GetProfileData(); + ChaserBossProfile data = chaser.Controller.GetProfileDataEx(); + ChaserBossProfileStunData stunData = data.GetStunBehavior(); char buffer[PLATFORM_MAX_PATH]; @@ -2931,22 +2968,23 @@ methodmap SF2_ChaserEntity < SF2_BaseBoss GetSlenderModel(controller.Index, _, buffer, sizeof(buffer)); chaser.SetModel(buffer); - chaser.SetRenderMode(view_as(g_SlenderRenderMode[controller.Index])); - chaser.SetRenderFx(view_as(g_SlenderRenderFX[controller.Index])); - chaser.SetRenderColor(g_SlenderRenderColor[controller.Index][0], g_SlenderRenderColor[controller.Index][1], - g_SlenderRenderColor[controller.Index][2], g_SlenderRenderColor[controller.Index][3]); + chaser.SetRenderMode(data.GetRenderMode(difficulty)); + chaser.SetRenderFx(data.GetRenderFx(difficulty)); + int color[4]; + data.GetRenderColor(difficulty, color); + chaser.SetRenderColor(color[0], color[1], color[2], color[3]); chaser.SetDefaultPosture(SF2_PROFILE_CHASER_DEFAULT_POSTURE); chaser.SetPosture(SF2_PROFILE_CHASER_DEFAULT_POSTURE); if (SF_SpecialRound(SPECIALROUND_TINYBOSSES)) { - float scaleModel = controller.ModelScale * 0.5; + float scaleModel = data.ModelScale * 0.5; chaser.SetPropFloat(Prop_Send, "m_flModelScale", scaleModel); } else { - chaser.SetPropFloat(Prop_Send, "m_flModelScale", controller.ModelScale); + chaser.SetPropFloat(Prop_Send, "m_flModelScale", data.ModelScale); } CBaseNPC npc = TheNPCs.FindNPCByEntIndex(chaser.index); @@ -2956,84 +2994,41 @@ methodmap SF2_ChaserEntity < SF2_BaseBoss npc.flGravity = 800.0; npc.flDeathDropHeight = 99999.0; npc.flJumpHeight = 512.0; - npc.flFrictionForward = 0.0; - npc.flFrictionSideways = 3.0; + npc.flFrictionForward = data.GetForwardFriction(difficulty); + npc.flFrictionSideways = data.GetSidewaysFriction(difficulty); - npc.flMaxYawRate = originalData.TurnRate; + npc.flMaxYawRate = data.TurnRate; - float addStunHealth = data.StunData.AddHealthPerPlayer[difficulty]; + float addStunHealth = 0.0; float classAdd; int count; - for (int i = 1; i <= MaxClients; i++) + if (stunData != null) { - SF2_BasePlayer player = SF2_BasePlayer(i); - if (!player.IsValid) + addStunHealth = stunData.GetAddHealthPerPlayer(difficulty); + for (int i = 1; i <= MaxClients; i++) { - continue; - } - - if (originalData.IsPvEBoss && !player.IsEliminated) - { - continue; - } - - if (!originalData.IsPvEBoss && (player.IsEliminated || player.HasEscaped)) - { - continue; - } - count++; - - switch (player.Class) - { - case TFClass_Scout: - { - classAdd += data.StunData.AddHealthPerScout[difficulty]; - } - - case TFClass_Soldier: - { - classAdd += data.StunData.AddHealthPerSoldier[difficulty]; - } - - case TFClass_Pyro: - { - classAdd += data.StunData.AddHealthPerPyro[difficulty]; - } - - case TFClass_DemoMan: - { - classAdd += data.StunData.AddHealthPerDemoman[difficulty]; - } - - case TFClass_Heavy: + SF2_BasePlayer player = SF2_BasePlayer(i); + if (!player.IsValid) { - classAdd += data.StunData.AddHealthPerHeavy[difficulty]; - } - - case TFClass_Engineer: - { - classAdd += data.StunData.AddHealthPerEngineer[difficulty]; - } - - case TFClass_Medic: - { - classAdd += data.StunData.AddHealthPerMedic[difficulty]; + continue; } - case TFClass_Sniper: + if (data.IsPvEBoss && !player.IsEliminated) { - classAdd += data.StunData.AddHealthPerSniper[difficulty]; + continue; } - case TFClass_Spy: + if (!data.IsPvEBoss && (player.IsEliminated || player.HasEscaped)) { - classAdd += data.StunData.AddHealthPerSpy[difficulty]; + continue; } + count++; + classAdd += stunData.GetAddHealthPerClass(difficulty, player.Class); } } addStunHealth *= float(count); - chaser.StunHealth = data.StunData.Health[controller.Difficulty] + addStunHealth + classAdd; + chaser.StunHealth = stunData.GetHealth(difficulty) + addStunHealth + classAdd; chaser.MaxStunHealth = chaser.StunHealth; locomotion.SetCallback(LocomotionCallback_ShouldCollideWith, LocoCollideWith); @@ -3041,16 +3036,16 @@ methodmap SF2_ChaserEntity < SF2_BaseBoss float pathingMins[3], pathingMaxs[3]; - if (controller.RaidHitbox) + if (data.RaidHitbox) { - pathingMins = g_SlenderDetectMins[controller.Index]; - pathingMaxs = g_SlenderDetectMaxs[controller.Index]; + data.GetHullMins(pathingMins); + data.GetHullMaxs(pathingMaxs); - chaser.SetPropVector(Prop_Send, "m_vecMins", g_SlenderDetectMins[controller.Index]); - chaser.SetPropVector(Prop_Send, "m_vecMaxs", g_SlenderDetectMaxs[controller.Index]); + chaser.SetPropVector(Prop_Send, "m_vecMins", pathingMins); + chaser.SetPropVector(Prop_Send, "m_vecMaxs", pathingMaxs); - chaser.SetPropVector(Prop_Send, "m_vecMinsPreScaled", g_SlenderDetectMins[controller.Index]); - chaser.SetPropVector(Prop_Send, "m_vecMaxsPreScaled", g_SlenderDetectMaxs[controller.Index]); + chaser.SetPropVector(Prop_Send, "m_vecMinsPreScaled", pathingMins); + chaser.SetPropVector(Prop_Send, "m_vecMaxsPreScaled", pathingMaxs); } else { @@ -3067,23 +3062,20 @@ methodmap SF2_ChaserEntity < SF2_BaseBoss npc.SetBodyMins(pathingMins); npc.SetBodyMaxs(pathingMaxs); - if (SF_IsBoxingMap() || originalData.IsPvEBoss) + if (SF_IsBoxingMap() || data.IsPvEBoss) { SetEntityCollisionGroup(chaser.index, COLLISION_GROUP_DEBRIS_TRIGGER); } - for (int difficulty2 = 0; difficulty2 < Difficulty_Max; difficulty2++) - { - g_SlenderTimeUntilKill[controller.Index] = GetGameTime() + NPCGetIdleLifetime(controller.Index, difficulty2); - } + g_SlenderTimeUntilKill[controller.Index] = GetGameTime() + data.GetIdleLifeTime(difficulty); IVision vision = chaser.MyNextBotPointer().GetVisionInterface(); - vision.SetFieldOfView(originalData.FOV); + vision.SetFieldOfView(data.FOV); vision.ForgetAllKnownEntities(); chaser.NextAttackTime = new StringMap(); - chaser.TrapCooldown = GetGameTime() + data.TrapCooldown[controller.Difficulty]; + chaser.TrapCooldown = GetGameTime() + data.GetTrapCooldown(difficulty); chaser.Teleport(pos, ang, NULL_VECTOR); @@ -3135,6 +3127,12 @@ methodmap SF2_ChaserEntity < SF2_BaseBoss CreateNative("SF2_ChaserBossEntity.CreateSoundHint", Native_CreateSoundHint); CreateNative("SF2_ChaserBossEntity.GroundSpeedOverride.get", Native_GetGroundSpeedOverride); CreateNative("SF2_ChaserBossEntity.GroundSpeedOverride.set", Native_SetGroundSpeedOverride); + CreateNative("SF2_ChaserBossEntity.MovementType.get", Native_GetMovementType); + CreateNative("SF2_ChaserBossEntity.MovementType.set", Native_SetMovementType); + CreateNative("SF2_ChaserBossEntity.LockMovementType.get", Native_GetLockMovementType); + CreateNative("SF2_ChaserBossEntity.LockMovementType.set", Native_SetLockMovementType); + + SF2_ChaserAttackAction.SetupAPI(); } } @@ -3197,7 +3195,7 @@ static void OnPlayerSpawn(SF2_BasePlayer client) } } -static Action OnPlayerTakeDamage(SF2_BasePlayer client, int &attacker, int &inflictor, float &damage, int &damageType) +static Action OnPlayerTakeDamage(SF2_BasePlayer client, int &attacker, int &inflictor, float &damage, int &damageType, int damageCustom) { SF2_ChaserEntity boss = SF2_ChaserEntity(inflictor); if (!boss.IsValid()) @@ -3219,19 +3217,17 @@ static Action OnPlayerTakeDamage(SF2_BasePlayer client, int &attacker, int &infl Call_PushCell(damageType); Call_Finish(); - SF2ChaserBossProfileData data; - data = controller.GetProfileData(); + ChaserBossProfile data = controller.GetProfileDataEx(); char attack[64]; strcopy(attack, sizeof(attack), boss.GetAttackName()); if (attack[0] != '\0') { - SF2ChaserBossProfileAttackData attackData; - data.GetAttack(attack, attackData); + ChaserBossProfileBaseAttack attackData = data.GetAttack(attack); - if (attackData.HitEffects != null) + if (attackData.GetHitEffects() != null) { - SlenderSpawnEffects(attackData.HitEffects, controller.Index, false, _, _, _, client.index); + SlenderSpawnEffects(attackData.GetHitEffects(), controller.Index, false, _, _, _, client.index); } } @@ -3283,19 +3279,17 @@ static void OnPlayerDeathPre(SF2_BasePlayer client, int attacker, int inflictor, return; } - SF2ChaserBossProfileData data; - data = controller.GetProfileData(); + ChaserBossProfile data = controller.GetProfileDataEx(); char attack[64]; strcopy(attack, sizeof(attack), boss.GetAttackName()); if (attack[0] != '\0') { - SF2ChaserBossProfileAttackData attackData; - data.GetAttack(attack, attackData); + ChaserBossProfileBaseAttack attackData = data.GetAttack(attack); - if (attackData.KillEffects != null) + if (attackData.GetOnKillEffects() != null) { - SlenderSpawnEffects(attackData.KillEffects, controller.Index, false, _, _, _, client.index); + SlenderSpawnEffects(attackData.GetOnKillEffects(), controller.Index, false, _, _, _, client.index); } } } @@ -3346,20 +3340,45 @@ static void OnPlayerDeath(SF2_BasePlayer client, int attacker, int inflictor, bo boss.PerformVoice(SF2BossSound_AttackKilled); - SF2BossProfileSoundInfo info; - SF2ChaserBossProfileData data; - data = controller.GetProfileData(); - info = data.AttackKilledClientSounds; + ChaserBossProfile data = controller.GetProfileDataEx(); + ProfileSound info = data.GetAttackKilledClientSounds(); info.EmitSound(true, client.index); - info = data.AttackKilledAllSounds; - for (int i = 1; i <= MaxClients; i++) + info = data.GetAttackKilledAllSounds(); + info.EmitToAllPlayers(); + + bool played = false; + TFClassType class = client.Class; + + if (data.GetLocalKillSounds() != null) { - if (!IsValidClient(i)) + info = data.GetLocalKillSounds().GetKilledClassSounds(class); + if (!info.EmitSound(_, boss.index)) { - continue; + info = data.GetLocalKillSounds().GetKilledAllSounds(); + info.EmitSound(_, boss.index); + } + } + + if (data.GetGlobalKillSounds() != null) + { + info = data.GetGlobalKillSounds().GetKilledClassSounds(class); + played = info.EmitToAllPlayers(); + if (!played) + { + info = data.GetGlobalKillSounds().GetKilledAllSounds(); + info.EmitToAllPlayers(); + } + } + + if (data.GetClientKillSounds() != null) + { + info = data.GetClientKillSounds().GetKilledClassSounds(class); + if (!info.EmitSound(true, client.index)) + { + info = data.GetClientKillSounds().GetKilledAllSounds(); + info.EmitSound(true, client.index); } - info.EmitSound(true, i); } } @@ -3399,18 +3418,13 @@ static Action Think(int entIndex) chaser.InterruptConditions |= interruptConditions; chaser.Target = target; - if (chaser.State == STATE_CHASE && !chaser.IsRaging) - { - chaser.DoAlwaysLookAt(chaser.Target); - } - float gameTime = GetGameTime(); if (chaser.LegacyFootstepInterval > 0.0 && chaser.LegacyFootstepTime < gameTime) { chaser.CastFootstep(); } - chaser.CheckVelocityCancel(); + //chaser.CheckVelocityCancel(); return Plugin_Continue; } @@ -3419,8 +3433,7 @@ static void ThinkPost(int entIndex) { SF2_ChaserEntity chaser = SF2_ChaserEntity(entIndex); SF2NPC_Chaser controller = chaser.Controller; - SF2BossProfileData data; - data = view_as(controller).GetProfileData(); + ChaserBossProfile data = controller.GetProfileDataEx(); ProcessSpeed(chaser); @@ -3431,13 +3444,8 @@ static void ThinkPost(int entIndex) chaser.ProcessRainbowOutline(); } - if (chaser.State == STATE_CHASE && !chaser.IsRaging) - { - chaser.DoAlwaysLookAt(chaser.Target); - } - chaser.InterruptConditions = 0; - chaser.SetNextThink(GetGameTime()); + chaser.SetNextThink(GetGameTime() + data.TickRate); #if defined DEBUG CBaseNPC npc = TheNPCs.FindNPCByEntIndex(chaser.index); @@ -3462,19 +3470,17 @@ static void SpawnPost(int entIndex) { SF2_ChaserEntity chaser = SF2_ChaserEntity(entIndex); SF2NPC_Chaser controller = chaser.Controller; - SF2ChaserBossProfileData data; - data = controller.GetProfileData(); - SF2BossProfileData originalData; - originalData = view_as(controller).GetProfileData(); + ChaserBossProfile data = controller.GetProfileDataEx(); + ChaserBossProfileDeathData deathData = data.GetDeathBehavior(); int difficulty = controller.Difficulty; - if (!data.DeathData.Enabled[difficulty]) + if (!deathData.IsEnabled(difficulty)) { chaser.SetProp(Prop_Data, "m_iHealth", 2000000000); chaser.SetProp(Prop_Data, "m_takedamage", DAMAGE_EVENTS_ONLY); } else { - float addDeathHealth = data.DeathData.AddHealthPerPlayer[difficulty]; + float addDeathHealth = deathData.GetAddHealthPerPlayer(difficulty); int count; float add = 0.0; float result = controller.GetDeathHealth(difficulty); @@ -3485,7 +3491,7 @@ static void SpawnPost(int entIndex) { continue; } - if (originalData.IsPvEBoss) + if (data.IsPvEBoss) { if (!player.IsEliminated) { @@ -3500,54 +3506,7 @@ static void SpawnPost(int entIndex) } } count++; - - switch (player.Class) - { - case TFClass_Scout: - { - add += data.DeathData.AddHealthPerScout[difficulty]; - } - - case TFClass_Soldier: - { - add += data.DeathData.AddHealthPerSoldier[difficulty]; - } - - case TFClass_Pyro: - { - add += data.DeathData.AddHealthPerPyro[difficulty]; - } - - case TFClass_DemoMan: - { - add += data.DeathData.AddHealthPerDemoman[difficulty]; - } - - case TFClass_Heavy: - { - add += data.DeathData.AddHealthPerHeavy[difficulty]; - } - - case TFClass_Engineer: - { - add += data.DeathData.AddHealthPerEngineer[difficulty]; - } - - case TFClass_Medic: - { - add += data.DeathData.AddHealthPerMedic[difficulty]; - } - - case TFClass_Sniper: - { - add += data.DeathData.AddHealthPerSniper[difficulty]; - } - - case TFClass_Spy: - { - add += data.DeathData.AddHealthPerSpy[difficulty]; - } - } + add += deathData.GetAddHealthPerClass(difficulty, player.Class); } addDeathHealth *= float(count); result += addDeathHealth + add; @@ -3566,7 +3525,7 @@ static void SpawnPost(int entIndex) } chaser.RageIndex = -1; - if (originalData.Healthbar) + if (data.Healthbar) { controller.Flags |= SFF_NOTELEPORT; UpdateHealthBar(controller.Index); @@ -3577,8 +3536,9 @@ static Action OnTakeDamage(int victim, int &attacker, int &inflictor, float &dam { SF2_ChaserEntity chaser = SF2_ChaserEntity(victim); SF2_BasePlayer player = SF2_BasePlayer(attacker); - SF2BossProfileData data; - data = view_as(chaser.Controller).GetProfileData(); + ChaserBossProfile data = chaser.Controller.GetProfileDataEx(); + float gameTime = GetGameTime(); + int difficulty = chaser.Controller.Difficulty; if (player.IsValid && player.IsProxy) { @@ -3604,28 +3564,28 @@ static Action OnTakeDamage(int victim, int &attacker, int &inflictor, float &dam } } - SF2ChaserBossProfileData chaserData; - chaserData = chaser.Controller.GetProfileData(); - int difficulty = chaser.Controller.Difficulty; bool changed = false; - if (chaserData.DamageResistances != null) + if (data.GetResistances() != null) { - SF2ChaserBossProfileResistanceData resistanceData; - for (int i = 0; i < chaserData.DamageResistances.Length; i++) + ChaserBossResistanceData resistanceData; + for (int i = 0; i < data.GetResistances().Size; i++) { - chaserData.DamageResistances.GetArray(i, resistanceData, sizeof(resistanceData)); - if (resistanceData.DamageTypes == null) + char name[64]; + data.GetResistances().GetSectionNameFromIndex(i, name, sizeof(name)); + resistanceData = view_as(data.GetResistances().GetSection(name)); + if (resistanceData.GetDamageTypes() == null) { continue; } - for (int i2 = 0; i2 < resistanceData.DamageTypes.Length; i++) + for (int i2 = 0; i2 < resistanceData.GetDamageTypes().Size; i++) { - int type = resistanceData.DamageTypes.Get(i); + resistanceData.GetDamageTypes().GetKeyNameFromIndex(i2, name, sizeof(name)); + int type = resistanceData.GetDamageTypes().GetInt(name); if (damageType & type || damageType == type) { - damage *= resistanceData.Multiplier[difficulty]; + damage *= resistanceData.GetMultiplier(difficulty); changed = true; break; } @@ -3641,24 +3601,28 @@ static Action OnTakeDamage(int victim, int &attacker, int &inflictor, float &dam if (player.IsValid) { CBaseEntity activeWeapon = CBaseEntity(player.GetPropEnt(Prop_Send, "m_hActiveWeapon")); - if (activeWeapon.IsValid() && chaserData.DamageResistances != null) + if (activeWeapon.IsValid() && data.GetResistances() != null) { - SF2ChaserBossProfileResistanceData resistanceData; + ChaserBossResistanceData resistanceData; int itemIndex = activeWeapon.GetProp(Prop_Send, "m_iItemDefinitionIndex"); - for (int i = 0; i < chaserData.DamageResistances.Length; i++) + for (int i = 0; i < data.GetResistances().Size; i++) { - chaserData.DamageResistances.GetArray(i, resistanceData, sizeof(resistanceData)); - if (resistanceData.Weapons == null) + char name[64]; + data.GetResistances().GetSectionNameFromIndex(i, name, sizeof(name)); + resistanceData = view_as(data.GetResistances().GetSection(name)); + if (resistanceData.GetWeapons() == null) { continue; } - if (resistanceData.Weapons.FindValue(itemIndex) == -1) + char itemIndexString[8]; + IntToString(itemIndex, itemIndexString, sizeof(itemIndexString)); + if (!resistanceData.GetWeapons().ContainsString(itemIndexString)) { continue; } - damage *= resistanceData.Multiplier[difficulty]; + damage *= resistanceData.GetMultiplier(difficulty); changed = true; break; } @@ -3697,7 +3661,7 @@ static Action OnTakeDamage(int victim, int &attacker, int &inflictor, float &dam if (player.Class == TFClass_Spy && (data.IsPvEBoss || SF_IsBoxingMap()) && chaser.State != STATE_DEATH) { - if (FloatAbs(AngleDiff(myAng[1], buffer[1])) >= 75.0 && chaserData.BackstabDamageScale > 0.0) + if (FloatAbs(AngleDiff(myAng[1], buffer[1])) >= 75.0 && data.BackstabDamageScale > 0.0) { damageType = DMG_CRIT; EmitSoundToClient(player.index, "player/spy_shield_break.wav", _, _, SNDLEVEL_TRAFFIC, SND_NOFLAGS, 0.7, 100); @@ -3730,10 +3694,10 @@ static Action OnTakeDamage(int victim, int &attacker, int &inflictor, float &dam model.SetProp(Prop_Send, "m_nSequence", sequence); } - damage = chaser.MaxHealth * chaserData.BackstabDamageScale; - if (!chaserData.DeathData.Enabled[difficulty]) + damage = chaser.MaxHealth * data.BackstabDamageScale; + if (!data.GetDeathBehavior().IsEnabled(difficulty)) { - damage = chaser.MaxStunHealth * chaserData.BackstabDamageScale; + damage = chaser.MaxStunHealth * data.BackstabDamageScale; } switch (weaponEnt.GetProp(Prop_Send, "m_iItemDefinitionIndex")) { @@ -3773,7 +3737,7 @@ static Action OnTakeDamage(int victim, int &attacker, int &inflictor, float &dam case 40, 1146: // Backburner { - if (FloatAbs(AngleDiff(myAng[1], buffer[1])) >= 60.0 && chaserData.BackstabDamageScale > 0.0) + if (FloatAbs(AngleDiff(myAng[1], buffer[1])) >= 60.0 && data.BackstabDamageScale > 0.0) { damageType |= DMG_CRIT; changed = true; @@ -3783,6 +3747,12 @@ static Action OnTakeDamage(int victim, int &attacker, int &inflictor, float &dam } } + if (damage > 0.0 && chaser.GetProp(Prop_Data, "m_iHealth") > damage && data.GetHurtSounds() != null && gameTime >= chaser.NextHurtVoiceTime) + { + chaser.NextHurtVoiceTime = gameTime + GetRandomFloat(data.GetHurtSounds().GetHurtCooldownMin(difficulty), data.GetHurtSounds().GetHurtCooldownMax(difficulty)); + chaser.PerformVoice(SF2BossSound_Hurt); + } + return changed ? Plugin_Changed : Plugin_Continue; } @@ -3790,8 +3760,7 @@ static void OnTakeDamageAlivePost(int victim, int attacker, int inflictor, float { SF2_ChaserEntity chaser = SF2_ChaserEntity(victim); SF2_BasePlayer player = SF2_BasePlayer(attacker); - SF2BossProfileData data; - data = view_as(chaser.Controller).GetProfileData(); + ChaserBossProfile data = chaser.Controller.GetProfileDataEx(); bool broadcastDamage = false; @@ -4070,25 +4039,28 @@ static Action TraceOnHit(int victim, int& attacker, int& inflictor, float& damag int difficulty = controller.Difficulty; - SF2ChaserBossProfileData data; - data = controller.GetProfileData(); - if (data.DamageResistances != null) + ChaserBossProfile data = controller.GetProfileDataEx(); + if (data.GetResistances() != null) { - SF2ChaserBossProfileResistanceData resistanceData; - for (int i = 0; i < data.DamageResistances.Length; i++) + ChaserBossResistanceData resistanceData; + for (int i = 0; i < data.GetResistances().Size; i++) { - data.DamageResistances.GetArray(i, resistanceData, sizeof(resistanceData)); - if (resistanceData.HitboxGroups == null) + char name[64]; + data.GetResistances().GetSectionNameFromIndex(i, name, sizeof(name)); + resistanceData = view_as(data.GetResistances().GetSection(name)); + if (resistanceData.GetHitboxes() == null) { continue; } - if (resistanceData.HitboxGroups.FindValue(hitgroup) == -1) + char hitgroupString[8]; + IntToString(hitgroup, hitgroupString, sizeof(hitgroupString)); + if (!resistanceData.GetHitboxes().ContainsString(hitgroupString)) { continue; } - damage *= resistanceData.Multiplier[difficulty]; + damage *= resistanceData.GetMultiplier(difficulty); changed = true; break; } @@ -4128,13 +4100,10 @@ static CBaseEntity ProcessVision(SF2_ChaserEntity chaser, int &interruptConditio return CBaseEntity(-1); } bool attackEliminated = (controller.Flags & SFF_ATTACKWAITERS) != 0; - SF2ChaserBossProfileData data; - data = controller.GetProfileData(); - SF2BossProfileData originalData; - originalData = view_as(controller).GetProfileData(); - if (originalData.IsPvEBoss) + ChaserBossProfile data = controller.GetProfileDataEx(); + if (data.IsPvEBoss) { - attackEliminated = originalData.IsPvEBoss; + attackEliminated = data.IsPvEBoss; } float gameTime = GetGameTime(); @@ -4155,26 +4124,29 @@ static CBaseEntity ProcessVision(SF2_ChaserEntity chaser, int &interruptConditio int state = chaser.State; - if (originalData.EyeData.Type == 1) + if (data.GetEyes().Type == 1) { if (chaser.EyeBoneIndex <= 0) { - chaser.EyeBoneIndex = LookupBone(chaser.index, originalData.EyeData.Bone); + char bone[128]; + data.GetEyes().GetBone(bone, sizeof(bone)); + chaser.EyeBoneIndex = LookupBone(chaser.index, bone); } GetBonePosition(chaser.index, chaser.EyeBoneIndex, traceStartPos, myEyeAng); - float offset[3]; - controller.GetEyePositionOffset(offset); - AddVectors(originalData.EyeData.OffsetAng, myEyeAng, myEyeAng); + float offset[3], angOffset[3]; + data.GetEyes().GetOffsetPos(offset); + data.GetEyes().GetOffsetAng(angOffset); + AddVectors(angOffset, myEyeAng, myEyeAng); VectorTransform(offset, traceStartPos, myEyeAng, traceStartPos); } int oldTarget = chaser.OldTarget.index; - if (!originalData.IsPvEBoss && !IsTargetValidForSlender(chaser, CBaseEntity(oldTarget), attackEliminated)) + if (!data.IsPvEBoss && !IsTargetValidForSlender(chaser, CBaseEntity(oldTarget), attackEliminated)) { chaser.OldTarget = CBaseEntity(INVALID_ENT_REFERENCE); oldTarget = INVALID_ENT_REFERENCE; } - if (originalData.IsPvEBoss && !IsPvETargetValid(CBaseEntity(oldTarget))) + if (data.IsPvEBoss && !IsPvETargetValid(CBaseEntity(oldTarget))) { chaser.OldTarget = CBaseEntity(INVALID_ENT_REFERENCE); oldTarget = INVALID_ENT_REFERENCE; @@ -4197,7 +4169,7 @@ static CBaseEntity ProcessVision(SF2_ChaserEntity chaser, int &interruptConditio } int bestNewTarget = oldTarget; - float searchRange = originalData.SearchRange[difficulty]; + float searchRange = data.GetSearchRange(difficulty); float bestNewTargetDist = Pow(searchRange, 2.0); if (IsValidEntity(bestNewTarget)) { @@ -4219,11 +4191,11 @@ static CBaseEntity ProcessVision(SF2_ChaserEntity chaser, int &interruptConditio { SF2_BasePlayer client = SF2_BasePlayer(i); - if (!originalData.IsPvEBoss && !IsTargetValidForSlender(chaser, client, attackEliminated)) + if (!data.IsPvEBoss && !IsTargetValidForSlender(chaser, client, attackEliminated)) { continue; } - if (originalData.IsPvEBoss && !IsPvETargetValid(client)) + if (data.IsPvEBoss && !IsPvETargetValid(client)) { continue; } @@ -4231,34 +4203,37 @@ static CBaseEntity ProcessVision(SF2_ChaserEntity chaser, int &interruptConditio valids.Push(EntIndexToEntRef(client.index)); } - for (int i = 0; i < g_Buildings.Length; i++) + if (!g_Enabled || data.IsPvEBoss) { - CBaseEntity entity = CBaseEntity(EntRefToEntIndex(g_Buildings.Get(i))); - if (!originalData.IsPvEBoss && !IsTargetValidForSlender(chaser, entity, attackEliminated)) + for (int i = 0; i < g_Buildings.Length; i++) { - continue; - } - if (originalData.IsPvEBoss && !IsPvETargetValid(entity)) - { - continue; - } - - valids.Push(EntIndexToEntRef(entity.index)); - } + CBaseEntity entity = CBaseEntity(EntRefToEntIndex(g_Buildings.Get(i))); + if (!data.IsPvEBoss && !IsTargetValidForSlender(chaser, entity, attackEliminated)) + { + continue; + } + if (data.IsPvEBoss && !IsPvETargetValid(entity)) + { + continue; + } - for (int i = 0; i < g_WhitelistedEntities.Length; i++) - { - CBaseEntity entity = CBaseEntity(EntRefToEntIndex(g_WhitelistedEntities.Get(i))); - if (!originalData.IsPvEBoss && !IsTargetValidForSlender(chaser, entity, attackEliminated)) - { - continue; + valids.Push(EntIndexToEntRef(entity.index)); } - if (originalData.IsPvEBoss && !IsPvETargetValid(entity)) + + for (int i = 0; i < g_WhitelistedEntities.Length; i++) { - continue; - } + CBaseEntity entity = CBaseEntity(EntRefToEntIndex(g_WhitelistedEntities.Get(i))); + if (!data.IsPvEBoss && !IsTargetValidForSlender(chaser, entity, attackEliminated)) + { + continue; + } + if (data.IsPvEBoss && !IsPvETargetValid(entity)) + { + continue; + } - valids.Push(EntIndexToEntRef(entity.index)); + valids.Push(EntIndexToEntRef(entity.index)); + } } for (int i = 0; i < valids.Length; i++) @@ -4297,9 +4272,9 @@ static CBaseEntity ProcessVision(SF2_ChaserEntity chaser, int &interruptConditio entity.GetAbsOrigin(targetPos); - bool isVisible, isTraceVisible; - int traceHitEntity; - TR_TraceHullFilter(traceStartPos, + bool isVisible, isTraceVisible, isGlasslessVisible, isGlasslessTraceVisible; + int traceHitEntity, glasslesTraceHitEntity; + Handle trace = TR_TraceHullFilterEx(traceStartPos, traceEndPos, traceMins, traceMaxs, @@ -4307,8 +4282,21 @@ static CBaseEntity ProcessVision(SF2_ChaserEntity chaser, int &interruptConditio TraceRayBossVisibility, chaser.index); - isVisible = !TR_DidHit(); - traceHitEntity = TR_GetEntityIndex(); + isVisible = !TR_DidHit(trace); + traceHitEntity = TR_GetEntityIndex(trace); + delete trace; + + trace = TR_TraceHullFilterEx(traceStartPos, + traceEndPos, + traceMins, + traceMaxs, + CONTENTS_SOLID | CONTENTS_MOVEABLE | CONTENTS_MIST | CONTENTS_MONSTERCLIP | CONTENTS_GRATE | CONTENTS_WINDOW, + TraceRayBossVisibility, + chaser.index); + + isGlasslessVisible = !TR_DidHit(trace); + glasslesTraceHitEntity = TR_GetEntityIndex(trace); + delete trace; if (!isVisible && traceHitEntity == entity.index) { @@ -4316,6 +4304,12 @@ static CBaseEntity ProcessVision(SF2_ChaserEntity chaser, int &interruptConditio isTraceVisible = true; } + if (!isGlasslessVisible && glasslesTraceHitEntity == entity.index) + { + isGlasslessVisible = true; + isGlasslessTraceVisible = true; + } + if (isVisible) { isVisible = NPCShouldSeeEntity(controller.Index, entity.index); @@ -4337,7 +4331,7 @@ static CBaseEntity ProcessVision(SF2_ChaserEntity chaser, int &interruptConditio } } - if (dist > Pow(originalData.SearchRange[difficulty], 2.0)) + if (dist > Pow(data.GetSearchRange(difficulty), 2.0)) { isVisible = false; } @@ -4348,12 +4342,12 @@ static CBaseEntity ProcessVision(SF2_ChaserEntity chaser, int &interruptConditio // Near radius check. if (chaser.GetIsVisible(entity) && - dist <= SquareFloat(data.WakeRadius)) + dist <= SquareFloat(data.GetWakeRadius(difficulty))) { chaser.SetIsNear(entity, true); playerInterruptFlags[entity.index] |= COND_ENEMYNEAR; } - if (player.IsValid && chaser.GetIsVisible(player) && SF_SpecialRound(SPECIALROUND_BOO) && GetVectorSquareMagnitude(traceEndPos, traceStartPos) < SquareFloat(SPECIALROUND_BOO_DISTANCE)) + if (!data.IsPvEBoss && player.IsValid && chaser.GetIsVisible(player) && SF_SpecialRound(SPECIALROUND_BOO) && GetVectorSquareMagnitude(traceEndPos, traceStartPos) < SquareFloat(SPECIALROUND_BOO_DISTANCE)) { TF2_StunPlayer(player.index, SPECIALROUND_BOO_DURATION, _, TF_STUNFLAGS_GHOSTSCARE); } @@ -4380,57 +4374,60 @@ static CBaseEntity ProcessVision(SF2_ChaserEntity chaser, int &interruptConditio playerInterruptFlags[entity.index] |= COND_ENEMYVISIBLE; } + if (isGlasslessTraceVisible) + { + playerInterruptFlags[entity.index] |= COND_ENEMYVISIBLE_NOGLASS; + } + playerDists[entity.index] = dist; - if (chaser.SmellPlayerList != null && data.SmellData.Enabled[difficulty]) + if (chaser.SmellPlayerList != null && data.GetSmellData() != null && data.GetSmellData().IsEnabled(difficulty)) { - if (player.IsValid && dist < Pow(data.SmellData.PlayerRange[difficulty], 2.0)) + if (player.IsValid && dist < Pow(data.GetSmellData().GetRequiredPlayerRange(difficulty), 2.0)) { chaser.SmellPlayerList.Push(player.index); } } - if (player.IsValid && (player.IsTrapped || (player.IsReallySprinting && data.AutoChaseSprinters[difficulty] && chaser.GetAutoChaseCooldown(player) < gameTime)) + if (player.IsValid && (player.IsTrapped || (player.IsReallySprinting && data.GetAutoChaseData().ShouldChaseSprinters(difficulty) && chaser.GetAutoChaseCooldown(player) < gameTime)) && (chaser.State == STATE_IDLE || chaser.State == STATE_ALERT) && dist <= SquareFloat(searchRange)) { player.SetForceChaseState(controller, true); SetTargetMarkState(controller, player, true); } - if (data.ChaseOnLookData.Enabled[difficulty] && isTraceVisible && player.IsValid && controller.ChaseOnLookTargets.FindValue(player.index) == -1) + if (data.GetChaseOnLookData().IsEnabled(difficulty) && isTraceVisible && player.IsValid && controller.ChaseOnLookTargets.FindValue(player.index) == -1) { bool shouldCalculate = false; - if (data.ChaseOnLookData.RequiredFOV[difficulty] <= 0.0) + if (data.GetChaseOnLookData().GetRequiredFOV(difficulty) <= 0.0) { shouldCalculate = chaser.GetInFOV(player); } else { - shouldCalculate = FloatAbs(AngleDiff(myEyeAng[1], buffer[1])) <= (data.ChaseOnLookData.RequiredFOV[difficulty] * 0.5); + shouldCalculate = FloatAbs(AngleDiff(myEyeAng[1], buffer[1])) <= (data.GetChaseOnLookData().GetRequiredFOV(difficulty) * 0.5); } if (shouldCalculate) { float eyeAng[3], expectedAng[3], lookPos[3]; player.GetEyeAngles(eyeAng); chaser.GetAbsOrigin(myPos); - lookPos = data.ChaseOnLookData.RequiredLookPosition; + data.GetChaseOnLookData().GetRequiredLookPosition(lookPos); VectorTransform(lookPos, myPos, myEyeAng, lookPos); SubtractVectors(lookPos, traceEndPos, expectedAng); GetVectorAngles(expectedAng, expectedAng); - float minimumXAng = data.ChaseOnLookData.MinimumXAngle[difficulty] * 0.5; - float maximumXAng = data.ChaseOnLookData.MaximumXAngle[difficulty] * 0.5; - float minimumYAng = data.ChaseOnLookData.MinimumYAngle[difficulty] * 0.5; - float maximumYAng = data.ChaseOnLookData.MaximumYAngle[difficulty] * 0.5; + float minimumXAng = data.GetChaseOnLookData().GetMinXAngle(difficulty) * 0.5; + float maximumXAng = data.GetChaseOnLookData().GetMaxXAngle(difficulty) * 0.5; + float minimumYAng = data.GetChaseOnLookData().GetMinYAngle(difficulty) * 0.5; + float maximumYAng = data.GetChaseOnLookData().GetMaxYAngle(difficulty) * 0.5; float xAng, yAng; xAng = AngleDiff(eyeAng[0], expectedAng[0]); yAng = FloatAbs(AngleDiff(eyeAng[1], expectedAng[1])); if ((xAng >= minimumXAng && xAng < maximumXAng) && (yAng >= minimumYAng && yAng < maximumYAng) && - ((data.ChaseOnLookData.AddTargets[difficulty]) || (!data.ChaseOnLookData.AddTargets[difficulty] && controller.ChaseOnLookTargets.Length == 0))) + ((data.GetChaseOnLookData().ShouldAddTargets(difficulty)) || (!data.GetChaseOnLookData().ShouldAddTargets(difficulty) && controller.ChaseOnLookTargets.Length == 0))) { controller.ChaseOnLookTargets.Push(player.index); - SF2BossProfileSoundInfo soundInfo; - soundInfo = originalData.ScareSounds; - soundInfo.EmitSound(true, player.index); + data.GetScareSounds().EmitSound(true, player.index); player.ChangeCondition(TFCond_MarkedForDeathSilent); player.SetForceChaseState(controller, true); SetTargetMarkState(controller, player, true); @@ -4508,11 +4505,11 @@ static CBaseEntity ProcessVision(SF2_ChaserEntity chaser, int &interruptConditio delete valids; - if (!originalData.IsPvEBoss && (SF_IsRaidMap() || SF_BossesChaseEndlessly() || SF_IsProxyMap() || SF_IsBoxingMap() || SF_IsSlaughterRunMap() || data.ChasesEndlessly || g_RenevantBossesChaseEndlessly)) + if (!data.IsPvEBoss && (SF_IsRaidMap() || SF_BossesChaseEndlessly() || SF_IsProxyMap() || SF_IsBoxingMap() || SF_IsSlaughterRunMap() || data.ChasesEndlessly || g_RenevantBossesChaseEndlessly)) { if (!IsTargetValidForSlender(chaser, CBaseEntity(bestNewTarget), attackEliminated)) { - if (state != STATE_CHASE && (NPCAreAvailablePlayersAlive() || g_Buildings.Length > 0 || g_WhitelistedEntities.Length > 0)) + if (state != STATE_CHASE) { ArrayList arrayRaidTargets = new ArrayList(); @@ -4556,27 +4553,16 @@ static CBaseEntity ProcessVision(SF2_ChaserEntity chaser, int &interruptConditio if (arrayRaidTargets.Length > 0) { int raidTarget = EntRefToEntIndex(arrayRaidTargets.Get(GetRandomInt(0, arrayRaidTargets.Length - 1))); - if (IsValidClient(raidTarget)) - { - if (!g_PlayerEliminated[raidTarget]) - { - bestNewTarget = raidTarget; - SetClientForceChaseState(controller, CBaseEntity(bestNewTarget), true); - } - } - else - { - bestNewTarget = raidTarget; - SetClientForceChaseState(controller, CBaseEntity(bestNewTarget), true); - } + bestNewTarget = raidTarget; + SetClientForceChaseState(controller, CBaseEntity(bestNewTarget), true); } delete arrayRaidTargets; } } - chaser.CurrentChaseDuration = data.ChaseDuration[difficulty] + GetGameTime(); + chaser.CurrentChaseDuration = data.GetChaseBehavior().GetMaxChaseDuration(difficulty) + GetGameTime(); } - if (originalData.IsPvEBoss) + if (data.IsPvEBoss) { if (!IsPvETargetValid(SF2_BasePlayer(bestNewTarget))) { @@ -4605,7 +4591,7 @@ static CBaseEntity ProcessVision(SF2_ChaserEntity chaser, int &interruptConditio delete arrayRaidTargets; } } - chaser.CurrentChaseDuration = data.ChaseDuration[difficulty] + GetGameTime(); + chaser.CurrentChaseDuration = data.GetChaseBehavior().GetMaxChaseDuration(difficulty) + GetGameTime(); } if (bestNewTarget != INVALID_ENT_REFERENCE) @@ -4632,24 +4618,25 @@ static void ProcessSpeed(SF2_ChaserEntity chaser) int difficulty = controller.Difficulty; SF2NPCMoveTypes moveType = chaser.MovementType; CBaseNPC npc = TheNPCs.FindNPCByEntIndex(chaser.index); + char profile[SF2_MAX_PROFILE_NAME_LENGTH]; + controller.GetProfile(profile, sizeof(profile)); + ChaserBossProfile profileData = controller.GetProfileDataEx(); + float gameTime = GetGameTime(); - SF2ChaserBossProfileData data; - data = controller.GetProfileData(); - SF2BossProfileData originalData; - originalData = baseController.GetProfileData(); - SF2ChaserBossProfilePostureInfo postureInfo; + ChaserBossProfile data = controller.GetProfileDataEx(); + char posture[64]; - if (data.Postures != null) + if (data.GetSection("postures") != null) { chaser.GetPosture(posture, sizeof(posture)); } float speed, acceleration; - acceleration = originalData.Acceleration[difficulty]; - if (!IsNullString(posture) && data.GetPosture(posture, postureInfo)) + acceleration = profileData.GetAcceleration(difficulty); + if (!IsNullString(posture) && data.GetPosture(posture) != null) { - speed = postureInfo.Acceleration[difficulty]; + acceleration = data.GetPostureAcceleration(posture, difficulty); } if (controller.HasAttribute(SF2Attribute_ReducedAccelerationOnLook) && controller.CanBeSeen(_, true)) @@ -4664,10 +4651,10 @@ static void ProcessSpeed(SF2_ChaserEntity chaser) { case SF2NPCMoveType_Walk: { - speed = data.WalkSpeed[difficulty]; - if (!IsNullString(posture) && data.GetPosture(posture, postureInfo)) + speed = profileData.GetWalkSpeed(difficulty); + if (!IsNullString(posture) && data.GetPosture(posture) != null) { - speed = postureInfo.WalkSpeed[difficulty]; + speed = data.GetPostureWalkSpeed(posture, difficulty); } if (controller.HasAttribute(SF2Attribute_ReducedWalkSpeedOnLook) && controller.CanBeSeen(_, true)) @@ -4687,10 +4674,10 @@ static void ProcessSpeed(SF2_ChaserEntity chaser) } case SF2NPCMoveType_Run: { - speed = originalData.RunSpeed[difficulty]; - if (!IsNullString(posture) && data.GetPosture(posture, postureInfo)) + speed = profileData.GetRunSpeed(difficulty); + if (!IsNullString(posture) && data.GetPosture(posture) != null) { - speed = postureInfo.Speed[difficulty]; + speed = data.GetPostureRunSpeed(posture, difficulty); } if (controller.HasAttribute(SF2Attribute_ReducedSpeedOnLook) && controller.CanBeSeen(_, true)) @@ -4712,23 +4699,22 @@ static void ProcessSpeed(SF2_ChaserEntity chaser) } case SF2NPCMoveType_Attack: { - SF2ChaserBossProfileAttackData attackData; - data.GetAttack(chaser.GetAttackName(), attackData); - float attackSpeed = attackData.RunSpeed[difficulty]; - if (attackData.RunDelay[difficulty] > 0.0 && chaser.AttackRunDelay > gameTime) + ChaserBossProfileBaseAttack attackData = data.GetAttack(chaser.GetAttackName()); + float attackSpeed = attackData.GetRunSpeed(difficulty); + if (attackData.GetRunDelay(difficulty) > 0.0 && chaser.AttackRunDelay > gameTime) { attackSpeed = 0.0; } - if (attackData.RunDuration[difficulty] > 0.0 && chaser.AttackRunDuration < gameTime) + if (attackData.GetRunDuration(difficulty) > 0.0 && chaser.AttackRunDuration < gameTime) { attackSpeed = 0.0; } - if (attackData.RunGroundSpeed[difficulty]) + if (attackData.GetGroundSpeedOverride(difficulty)) { chaser.GroundSpeedOverride = true; } speed = attackSpeed; - acceleration = attackData.RunAcceleration[difficulty]; + acceleration = attackData.GetAcceleration(difficulty); } } @@ -4756,7 +4742,7 @@ static void ProcessSpeed(SF2_ChaserEntity chaser) if (SF_IsSlaughterRunMap()) { float slaughterSpeed = g_SlaughterRunMinimumBossRunSpeedConVar.FloatValue; - if (!originalData.SlaughterRunData.CustomMinimumSpeed[difficulty] && speed < slaughterSpeed) + if (!data.GetSlaughterRunData().ShouldUseCustomMinSpeed(difficulty) && speed < slaughterSpeed) { speed = slaughterSpeed; } @@ -4764,7 +4750,7 @@ static void ProcessSpeed(SF2_ChaserEntity chaser) } } - if ((!originalData.IsPvEBoss && IsBeatBoxBeating(2)) || chaser.IsKillingSomeone) + if ((!data.IsPvEBoss && IsBeatBoxBeating(2)) || chaser.IsKillingSomeone) { speed = 0.0; } @@ -4819,10 +4805,9 @@ static void ProcessBody(SF2_ChaserEntity chaser) return; } - SF2ChaserBossProfileData data; - data = controller.GetProfileData(); + ChaserBossProfile data = controller.GetProfileDataEx(); - if (data.Postures != null && chaser.CanUpdatePosture()) + if (data.GetSection("postures") != null && chaser.CanUpdatePosture()) { char posture[64], resultPosture[64]; chaser.GetDefaultPosture(posture, sizeof(posture)); @@ -4872,6 +4857,48 @@ static void ProcessBody(SF2_ChaserEntity chaser) return; } + if (chaser.ShouldAnimationSyncWithGround) + { + float velocity, returnFloat, groundSpeed; + velocity = loco.GetGroundSpeed(); + groundSpeed = chaser.GetPropFloat(Prop_Data, "m_flGroundSpeed"); + if (groundSpeed != 0.0 && groundSpeed > 10.0) + { + returnFloat = (velocity / groundSpeed) * chaser.AnimationPlaybackRate; + + if (loco.IsOnGround() && chaser.IsAttemptingToMove) + { + if (returnFloat > 12.0) + { + returnFloat = 12.0; + } + if (returnFloat < -4.0) + { + returnFloat = -4.0; + } + chaser.SetPropFloat(Prop_Send, "m_flPlaybackRate", returnFloat); + } + } + else + { + velocity = (velocity + ((npc.flRunSpeed * GetDifficultyModifier(controller.Difficulty)) / 15.0)) / npc.flRunSpeed; + + if (loco.IsOnGround() && chaser.IsAttemptingToMove) + { + float playbackSpeed = velocity * chaser.AnimationPlaybackRate; + if (playbackSpeed > 12.0) + { + playbackSpeed = 12.0; + } + if (playbackSpeed < -4.0) + { + playbackSpeed = -4.0; + } + chaser.SetPropFloat(Prop_Send, "m_flPlaybackRate", playbackSpeed); + } + } + } + switch (chaser.MoveParameterType) { case SF2NPCMoveParameter_XY: @@ -4951,48 +4978,6 @@ static void ProcessBody(SF2_ChaserEntity chaser) float scale = npc.flRunSpeed / speed; chaser.SetPoseParameter(chaser.MoveScaleParameter, scale); } - - if (data.OldAnimationAI) - { - float velocity, returnFloat, groundSpeed; - velocity = loco.GetGroundSpeed(); - groundSpeed = chaser.GetPropFloat(Prop_Data, "m_flGroundSpeed"); - if (groundSpeed != 0.0 && groundSpeed > 10.0) - { - returnFloat = (velocity / groundSpeed) * chaser.AnimationPlaybackRate; - - if (loco.IsOnGround() && chaser.IsAttemptingToMove && chaser.State != STATE_ATTACK) - { - if (returnFloat > 12.0) - { - returnFloat = 12.0; - } - if (returnFloat < -4.0) - { - returnFloat = -4.0; - } - chaser.SetPropFloat(Prop_Send, "m_flPlaybackRate", returnFloat); - } - } - else - { - velocity = (velocity + ((npc.flRunSpeed * GetDifficultyModifier(controller.Difficulty)) / 15.0)) / npc.flRunSpeed; - - if (loco.IsOnGround() && chaser.IsAttemptingToMove && chaser.State != STATE_ATTACK) - { - float playbackSpeed = velocity * chaser.AnimationPlaybackRate; - if (playbackSpeed > 12.0) - { - playbackSpeed = 12.0; - } - if (playbackSpeed < -4.0) - { - playbackSpeed = -4.0; - } - chaser.SetPropFloat(Prop_Send, "m_flPlaybackRate", playbackSpeed); - } - } - } } static bool LocoCollideWith(CBaseNPC_Locomotion loco, int other) @@ -5029,9 +5014,8 @@ static bool LocoCollideWith(CBaseNPC_Locomotion loco, int other) if (chaser.IsValid() && chaser.Controller.IsValid()) { - SF2BossProfileData data; SF2NPC_BaseNPC controller = view_as(chaser.Controller); - data = controller.GetProfileData(); + BaseBossProfile data = controller.GetProfileDataEx(); if ((data.IsPvEBoss && player.IsInPvE) || (controller.Flags & SFF_ATTACKWAITERS) != 0) { return true; @@ -5051,9 +5035,7 @@ static bool LocoCollideWith(CBaseNPC_Locomotion loco, int other) if (chaser.IsValid() && chaser.Controller.IsValid()) { - SF2BossProfileData data; - SF2NPC_BaseNPC controller = view_as(chaser.Controller); - data = controller.GetProfileData(); + ChaserBossProfile data = chaser.Controller.GetProfileDataEx(); if (data.IsPvEBoss && SF2_ChaserEntity(other).IsValid()) { return false; @@ -5138,27 +5120,58 @@ static Action Hook_ChaserSoundHook(int clients[64], int &numClients, char sample OnPlayerEmitSound(client, soundType); } - case SNDCHAN_ITEM, SNDCHAN_WEAPON: + case SNDCHAN_ITEM, SNDCHAN_WEAPON, SNDCHAN_STATIC: { - if (StrContains(sample, "swing", false) == -1 && StrContains(sample, "impact", false) == -1 && - StrContains(sample, "hit", false) == -1 && StrContains(sample, "slice", false) == -1 && - StrContains(sample, "reload", false) == -1 && StrContains(sample, "woosh", false) == -1 && - StrContains(sample, "eviction", false) == -1 && StrContains(sample, "holy", false) == -1 && - StrContains(sample, "flashlight", false) == -1) + static char matchSoundStrings[][] = { + "tf", + "flashlight", + "impact", + "hit", + "swing", + "slice", + "crit", + "shot", + "shoot", + "fire", + "doom", + "single", + "tf2", + "heal", + "break", + "diamond", + "start", + "loop", + "minigun", + "reload", + "woosh", + "eviction", + "holy", + "cbar", + "jingle_bells_nm", + "happy_birthday_tf" + }; + + bool isWeaponSound = false; + + for (int i = 0; !isWeaponSound && i < sizeof(matchSoundStrings); i++) { - return Plugin_Continue; + if (StrContains(sample, matchSoundStrings[i], false) != -1) + { + isWeaponSound = true; + } } - OnPlayerEmitSound(client, StrContains(sample, "flashlight", false) != -1 ? SoundType_Flashlight : SoundType_Weapon); - } - case SNDCHAN_STATIC: - { - if (StrContains(sample, "happy_birthday_tf", false) == -1 && StrContains(sample, "jingle_bells_nm", false) == -1) + bool voice = false; + if (StrContains(sample, "flashlight", false) != -1 || StrContains(sample, "happy_birthday_tf", false) != -1 || + StrContains(sample, "jingle_bells_nm", false) != -1) { - return Plugin_Continue; + voice = true; } - OnPlayerEmitSound(client, SoundType_Voice); + if (isWeaponSound) + { + OnPlayerEmitSound(client, voice ? SoundType_Flashlight : SoundType_Weapon); + } } } @@ -5192,8 +5205,15 @@ static void OnPlayerEmitSound(SF2_BasePlayer client, SoundType soundType) { continue; } - SF2ChaserBossProfileData data; - data = controller.GetProfileData(); + + if (chaser.State != STATE_IDLE && chaser.State != STATE_ALERT) + { + continue; + } + + ChaserBossProfile data = controller.GetProfileDataEx(); + ChaserBossSoundSenseData senseData = data.GetSoundSenseData(); + ChaserBossAutoChaseData autoChaseData = data.GetAutoChaseData(); TFClassType class = client.Class; int classToInt = view_as(class); @@ -5204,7 +5224,7 @@ static void OnPlayerEmitSound(SF2_BasePlayer client, SoundType soundType) int difficulty = controller.Difficulty; - float hearRadius = view_as(controller).GetProfileData().SearchSoundRange[difficulty]; + float hearRadius = data.GetHearingRange(difficulty); if (hearRadius <= 0.0) { continue; @@ -5232,32 +5252,32 @@ static void OnPlayerEmitSound(SF2_BasePlayer client, SoundType soundType) if (soundType == SoundType_QuietFootstep) { - addThreshold = data.QuietFootstepSenses.AddCount[difficulty]; + addThreshold = senseData.GetQuietFootstepAdd(difficulty); if (addThreshold <= 0) { continue; } - cooldown = data.QuietFootstepSenses.Cooldown[difficulty]; + cooldown = senseData.GetQuietFootstepCooldown(difficulty); distance *= 1.85; } else if (soundType == SoundType_LoudFootstep) { - addThreshold = data.LoudFootstepSenses.AddCount[difficulty]; + addThreshold = senseData.GetLoudFootstepAdd(difficulty); if (addThreshold <= 0) { continue; } - cooldown = data.LoudFootstepSenses.Cooldown[difficulty]; + cooldown = senseData.GetLoudFootstepCooldown(difficulty); distance *= 0.66; } else { - addThreshold = data.FootstepSenses.AddCount[difficulty]; + addThreshold = senseData.GetFootstepAdd(difficulty); if (addThreshold <= 0) { continue; } - cooldown = data.FootstepSenses.Cooldown[difficulty]; + cooldown = senseData.GetFootstepCooldown(difficulty); } trace = TR_TraceRayFilterEx(myPos, hisPos, CONTENTS_SOLID | CONTENTS_MOVEABLE | CONTENTS_MIST | CONTENTS_GRATE | CONTENTS_WINDOW, RayType_EndPoint, TraceRayDontHitCharactersOrEntity, chaser.index); @@ -5284,26 +5304,26 @@ static void OnPlayerEmitSound(SF2_BasePlayer client, SoundType soundType) if (soundType == SoundType_Voice) { - addThreshold = data.VoiceSenses.AddCount[difficulty]; + addThreshold = senseData.GetVoiceAdd(difficulty); if (addThreshold <= 0) { continue; } - cooldown = data.VoiceSenses.Cooldown[difficulty]; + cooldown = senseData.GetVoiceCooldown(difficulty); } else if (soundType == SoundType_Flashlight) { - addThreshold = data.FlashlightSenses.AddCount[difficulty]; + addThreshold = senseData.GetFlashlightAdd(difficulty); if (addThreshold <= 0) { continue; } - cooldown = data.FlashlightSenses.Cooldown[difficulty]; + cooldown = senseData.GetFlashlightCooldown(difficulty); } } case SoundType_Weapon: { - addThreshold = data.WeaponSenses.AddCount[difficulty]; + addThreshold = senseData.GetWeaponAdd(difficulty); if (addThreshold <= 0) { continue; @@ -5329,7 +5349,7 @@ static void OnPlayerEmitSound(SF2_BasePlayer client, SoundType soundType) distance *= 0.66; - cooldown = data.WeaponSenses.Cooldown[difficulty]; + cooldown = senseData.GetWeaponCooldown(difficulty); } } @@ -5360,38 +5380,51 @@ static void OnPlayerEmitSound(SF2_BasePlayer client, SoundType soundType) continue; } - if (chaser.GetAlertSoundTriggerCooldown(client) > gameTime && cooldown > 0.0) + if (!data.ShouldIgnoreHearingPathChecking(difficulty)) { - continue; + CNavArea myArea = chaser.GetLastKnownArea(); + CNavArea theirArea = client.GetLastKnownArea(); + if (myArea != NULL_AREA && theirArea != NULL_AREA && myArea != theirArea) + { + CNavArea closestArea = NULL_AREA; + TheNavMesh.BuildPath(myArea, NULL_AREA, hisPos, .closestArea = closestArea, .maxPathLength = hearRadius * 1.5); + if (closestArea != theirArea) + { + continue; + } + } } - chaser.SetAlertSoundTriggerCooldown(client, gameTime + cooldown); - chaser.UpdateAlertTriggerCount(client, addThreshold); + if (gameTime > chaser.GetAlertSoundTriggerCooldown(client)) + { + chaser.SetAlertSoundTriggerCooldown(client, gameTime + cooldown); + chaser.UpdateAlertTriggerCount(client, addThreshold); + } - if (data.AutoChaseEnabled[difficulty] && chaser.GetAutoChaseAddCooldown(client) < gameTime) + if (autoChaseData.IsEnabled(difficulty) && chaser.GetAutoChaseAddCooldown(client) < gameTime) { int count = 0; switch (soundType) { case SoundType_Footstep: { - count = data.AutoChaseAddFootstep[difficulty]; + count = autoChaseData.GetAddFootsteps(difficulty); } case SoundType_QuietFootstep: { - count = data.AutoChaseAddQuietFootstep[difficulty]; + count = autoChaseData.GetAddQuietFootsteps(difficulty); } case SoundType_LoudFootstep: { - count = data.AutoChaseAddLoudFootstep[difficulty]; + count = autoChaseData.GetAddLoudFootsteps(difficulty); } case SoundType_Voice: { - count = data.AutoChaseAddVoice[difficulty]; + count = autoChaseData.GetAddVoice(difficulty); } case SoundType_Flashlight, SoundType_Weapon: { - count = data.AutoChaseAddWeapon[difficulty]; + count = autoChaseData.GetAddWeapon(difficulty); } } if (count > 0) @@ -5550,10 +5583,7 @@ static any Native_GetProfileData(Handle plugin, int numParams) SF2_ChaserEntity bossEntity = SF2_ChaserEntity(entity); - SF2ChaserBossProfileData data; - data = bossEntity.Controller.GetProfileData(); - SetNativeArray(2, data, sizeof(data)); - return 0; + return bossEntity.Controller.GetProfileDataEx(); } static any Native_PerformVoice(Handle plugin, int numParams) @@ -5581,8 +5611,7 @@ static any Native_PerformCustomVoice(Handle plugin, int numParams) SF2_ChaserEntity bossEntity = SF2_ChaserEntity(entity); - SF2BossProfileSoundInfo soundInfo; - GetNativeArray(2, soundInfo, sizeof(soundInfo)); + ProfileSound soundInfo = GetNativeCell(2); return bossEntity.PerformVoiceCooldown(soundInfo, soundInfo.Paths); } @@ -5617,7 +5646,7 @@ static any Native_SetDefaultPosture(Handle plugin, int numParams) bufferSize++; char[] buffer = new char[bufferSize]; GetNativeString(2, buffer, bufferSize); - bossEntity.SetDefaultPosture(buffer); + bossEntity.SetDefaultPosture(buffer, GetNativeCell(3)); return 0; } @@ -5748,3 +5777,56 @@ static any Native_SetGroundSpeedOverride(Handle plugin, int numParams) bossEntity.GroundSpeedOverride = GetNativeCell(2); return 0; } + +static any Native_GetMovementType(Handle plugin, int numParams) +{ + int entity = GetNativeCell(1); + if (!IsValidEntity(entity)) + { + return ThrowNativeError(SP_ERROR_NATIVE, "Invalid entity index %d", entity); + } + + SF2_ChaserEntity bossEntity = SF2_ChaserEntity(entity); + return bossEntity.MovementType; +} + +static any Native_SetMovementType(Handle plugin, int numParams) +{ + int entity = GetNativeCell(1); + if (!IsValidEntity(entity)) + { + return ThrowNativeError(SP_ERROR_NATIVE, "Invalid entity index %d", entity); + } + + SF2_ChaserEntity bossEntity = SF2_ChaserEntity(entity); + bool old = bossEntity.LockMovementType; + bossEntity.LockMovementType = false; + bossEntity.MovementType = GetNativeCell(2); + bossEntity.LockMovementType = old; + return 0; +} + +static any Native_GetLockMovementType(Handle plugin, int numParams) +{ + int entity = GetNativeCell(1); + if (!IsValidEntity(entity)) + { + return ThrowNativeError(SP_ERROR_NATIVE, "Invalid entity index %d", entity); + } + + SF2_ChaserEntity bossEntity = SF2_ChaserEntity(entity); + return bossEntity.LockMovementType; +} + +static any Native_SetLockMovementType(Handle plugin, int numParams) +{ + int entity = GetNativeCell(1); + if (!IsValidEntity(entity)) + { + return ThrowNativeError(SP_ERROR_NATIVE, "Invalid entity index %d", entity); + } + + SF2_ChaserEntity bossEntity = SF2_ChaserEntity(entity); + bossEntity.LockMovementType = GetNativeCell(2); + return 0; +} diff --git a/addons/sourcemod/scripting/sf2/npc/entities/chaser/postures/on_alert.sp b/addons/sourcemod/scripting/sf2/npc/entities/chaser/postures/on_alert.sp index 8717a3cd..07922cf5 100644 --- a/addons/sourcemod/scripting/sf2/npc/entities/chaser/postures/on_alert.sp +++ b/addons/sourcemod/scripting/sf2/npc/entities/chaser/postures/on_alert.sp @@ -1,4 +1,5 @@ #pragma semicolon 1 +#pragma newdecls required void InitializePostureOnAlert() { @@ -7,41 +8,58 @@ void InitializePostureOnAlert() static Action OnChaserUpdatePosture(SF2NPC_Chaser controller, char[] buffer, int bufferSize) { - SF2ChaserBossProfileData data; - data = controller.GetProfileData(); - StringMap postures = data.Postures; - if (postures == null) + SF2_ChaserEntity chaser = SF2_ChaserEntity(controller.EntIndex); + if (!chaser.IsValid()) { return Plugin_Continue; } - SF2ChaserBossProfilePostureInfo postureInfo; - StringMapSnapshot snapshot = postures.Snapshot(); - for (int i = 0; i < snapshot.Length; i++) + int difficulty = controller.Difficulty; + + ChaserBossProfile data = controller.GetProfileDataEx(); + ProfileObject obj = data.GetSection("postures"); + if (obj == null) + { + return Plugin_Continue; + } + + for (int i = 0; i < obj.SectionLength; i++) { - if (!data.GetPostureFromIndex(i, postureInfo)) + ProfileObject posture = data.GetPostureFromIndex(i); + if (posture == null) { continue; } - int difficulty = controller.Difficulty; - - SF2PostureConditionAlertInfo alertInfo; - alertInfo = postureInfo.AlertInfo; - if (!alertInfo.Enabled[difficulty]) + ProfileObject conditions = posture.GetSection("conditions"); + if (conditions == null || conditions.SectionLength == 0) { continue; } - SF2_ChaserEntity chaser = SF2_ChaserEntity(controller.EntIndex); - if (chaser.IsValid() && chaser.State == STATE_ALERT) + for (int j = 0; j < conditions.SectionLength; j++) { - strcopy(buffer, bufferSize, postureInfo.Name); - delete snapshot; - return Plugin_Changed; + char name[64]; + conditions.GetSectionNameFromIndex(j, name, sizeof(name)); + if (strcmp(name, "on_alert") != 0) + { + continue; + } + + ChaserBossPostureCondition condition = view_as(conditions.GetSection(name)); + if (condition == null || !condition.GetEnabled(difficulty)) + { + continue; + } + + if (chaser.State == STATE_ALERT) + { + posture.GetSectionName(name, sizeof(name)); + strcopy(buffer, bufferSize, name); + return Plugin_Changed; + } } } - delete snapshot; return Plugin_Continue; } \ No newline at end of file diff --git a/addons/sourcemod/scripting/sf2/npc/entities/chaser/postures/on_cloak.sp b/addons/sourcemod/scripting/sf2/npc/entities/chaser/postures/on_cloak.sp index 83e0c159..0befa1bc 100644 --- a/addons/sourcemod/scripting/sf2/npc/entities/chaser/postures/on_cloak.sp +++ b/addons/sourcemod/scripting/sf2/npc/entities/chaser/postures/on_cloak.sp @@ -1,4 +1,5 @@ #pragma semicolon 1 +#pragma newdecls required void InitializePostureOnCloak() { @@ -7,41 +8,58 @@ void InitializePostureOnCloak() static Action OnChaserUpdatePosture(SF2NPC_Chaser controller, char[] buffer, int bufferSize) { - SF2ChaserBossProfileData data; - data = controller.GetProfileData(); - StringMap postures = data.Postures; - if (postures == null) + SF2_ChaserEntity chaser = SF2_ChaserEntity(controller.EntIndex); + if (!chaser.IsValid()) { return Plugin_Continue; } - SF2ChaserBossProfilePostureInfo postureInfo; - StringMapSnapshot snapshot = postures.Snapshot(); - for (int i = 0; i < snapshot.Length; i++) + int difficulty = controller.Difficulty; + + ChaserBossProfile data = controller.GetProfileDataEx(); + ProfileObject obj = data.GetSection("postures"); + if (obj == null) + { + return Plugin_Continue; + } + + for (int i = 0; i < obj.SectionLength; i++) { - if (!data.GetPostureFromIndex(i, postureInfo)) + ProfileObject posture = data.GetPostureFromIndex(i); + if (posture == null) { continue; } - int difficulty = controller.Difficulty; - - SF2PostureConditionCloakInfo cloakInfo; - cloakInfo = postureInfo.CloakInfo; - if (!cloakInfo.Enabled[difficulty]) + ProfileObject conditions = posture.GetSection("conditions"); + if (conditions == null || conditions.SectionLength == 0) { continue; } - SF2_ChaserEntity chaser = SF2_ChaserEntity(controller.EntIndex); - if (chaser.IsValid() && chaser.HasCloaked) + for (int j = 0; j < conditions.SectionLength; j++) { - strcopy(buffer, bufferSize, postureInfo.Name); - delete snapshot; - return Plugin_Changed; + char name[64]; + conditions.GetSectionNameFromIndex(j, name, sizeof(name)); + if (strcmp(name, "on_cloak") != 0) + { + continue; + } + + ChaserBossPostureCondition condition = view_as(conditions.GetSection(name)); + if (condition == null || !condition.GetEnabled(difficulty)) + { + continue; + } + + if (chaser.HasCloaked) + { + posture.GetSectionName(name, sizeof(name)); + strcopy(buffer, bufferSize, name); + return Plugin_Changed; + } } } - delete snapshot; return Plugin_Continue; } \ No newline at end of file diff --git a/addons/sourcemod/scripting/sf2/npc/entities/chaser/postures/on_look.sp b/addons/sourcemod/scripting/sf2/npc/entities/chaser/postures/on_look.sp index 556d917a..cdbac40e 100644 --- a/addons/sourcemod/scripting/sf2/npc/entities/chaser/postures/on_look.sp +++ b/addons/sourcemod/scripting/sf2/npc/entities/chaser/postures/on_look.sp @@ -1,4 +1,5 @@ #pragma semicolon 1 +#pragma newdecls required void InitializePostureOnLook() { @@ -7,40 +8,58 @@ void InitializePostureOnLook() static Action OnChaserUpdatePosture(SF2NPC_Chaser controller, char[] buffer, int bufferSize) { - SF2ChaserBossProfileData data; - data = controller.GetProfileData(); - StringMap postures = data.Postures; - if (postures == null) + SF2_ChaserEntity chaser = SF2_ChaserEntity(controller.EntIndex); + if (!chaser.IsValid()) { return Plugin_Continue; } - SF2ChaserBossProfilePostureInfo postureInfo; - StringMapSnapshot snapshot = postures.Snapshot(); - for (int i = 0; i < snapshot.Length; i++) + int difficulty = controller.Difficulty; + + ChaserBossProfile data = controller.GetProfileDataEx(); + ProfileObject obj = data.GetSection("postures"); + if (obj == null) + { + return Plugin_Continue; + } + + for (int i = 0; i < obj.SectionLength; i++) { - if (!data.GetPostureFromIndex(i, postureInfo)) + ProfileObject posture = data.GetPostureFromIndex(i); + if (posture == null) { continue; } - int difficulty = controller.Difficulty; - - SF2PostureConditionLookAtInfo lookAtInfo; - lookAtInfo = postureInfo.LookAtInfo; - if (!lookAtInfo.Enabled[difficulty]) + ProfileObject conditions = posture.GetSection("conditions"); + if (conditions == null || conditions.SectionLength == 0) { continue; } - if (controller.CanBeSeen(_, true)) + for (int j = 0; j < conditions.SectionLength; j++) { - strcopy(buffer, bufferSize, postureInfo.Name); - delete snapshot; - return Plugin_Changed; + char name[64]; + conditions.GetSectionNameFromIndex(j, name, sizeof(name)); + if (strcmp(name, "on_look") != 0) + { + continue; + } + + ChaserBossPostureCondition condition = view_as(conditions.GetSection(name)); + if (condition == null || !condition.GetEnabled(difficulty)) + { + continue; + } + + if (controller.CanBeSeen(_, true)) + { + posture.GetSectionName(name, sizeof(name)); + strcopy(buffer, bufferSize, name); + return Plugin_Changed; + } } } - delete snapshot; return Plugin_Continue; } \ No newline at end of file diff --git a/addons/sourcemod/scripting/sf2/npc/entities/chaser/postures/rage_phase.sp b/addons/sourcemod/scripting/sf2/npc/entities/chaser/postures/rage_phase.sp index 46ead006..19aad2a4 100644 --- a/addons/sourcemod/scripting/sf2/npc/entities/chaser/postures/rage_phase.sp +++ b/addons/sourcemod/scripting/sf2/npc/entities/chaser/postures/rage_phase.sp @@ -1,4 +1,24 @@ #pragma semicolon 1 +#pragma newdecls required + +methodmap ChaserBossPostureCondition_RagePhase < ChaserBossPostureCondition +{ + public bool IsPhaseValid(const char[] buffer) + { + char phases[1024]; + this.GetString("phases", phases, sizeof(phases)); + char phase[64][64]; + int maxLength = ExplodeString(phases, " ", phase, sizeof(phase), sizeof(phase)); + for (int i = 0; i < maxLength; i++) + { + if (strcmp(buffer, phase[i]) == 0) + { + return true; + } + } + return false; + } +} void InitializePostureRagePhase() { @@ -7,48 +27,64 @@ void InitializePostureRagePhase() static Action OnChaserUpdatePosture(SF2NPC_Chaser controller, char[] buffer, int bufferSize) { - SF2ChaserBossProfileData data; - data = controller.GetProfileData(); - StringMap postures = data.Postures; - if (postures == null) + SF2_ChaserEntity chaser = SF2_ChaserEntity(controller.EntIndex); + if (!chaser.IsValid()) + { + return Plugin_Continue; + } + + int difficulty = controller.Difficulty; + + ChaserBossProfile data = controller.GetProfileDataEx(); + ProfileObject obj = data.GetSection("postures"); + if (obj == null) { return Plugin_Continue; } - SF2ChaserBossProfilePostureInfo postureInfo; - StringMapSnapshot snapshot = postures.Snapshot(); - for (int i = 0; i < snapshot.Length; i++) + for (int i = 0; i < obj.SectionLength; i++) { - if (!data.GetPostureFromIndex(i, postureInfo)) + ProfileObject posture = data.GetPostureFromIndex(i); + if (posture == null) { continue; } - SF2PostureConditionRagePhase ragePhaseInfo; - ragePhaseInfo = postureInfo.RagePhaseInfo; - if (!ragePhaseInfo.Enabled) + ProfileObject conditions = posture.GetSection("conditions"); + if (conditions == null || conditions.SectionLength == 0) { continue; } - SF2_ChaserEntity chaser = SF2_ChaserEntity(controller.EntIndex); - if (!chaser.IsValid() || chaser.RageIndex == -1) + for (int j = 0; j < conditions.SectionLength; j++) { - continue; - } + char name[64]; + conditions.GetSectionNameFromIndex(j, name, sizeof(name)); + if (strcmp(name, "in_phases") != 0) + { + continue; + } - SF2ChaserRageInfo rageInfo; - data.Rages.GetArray(chaser.RageIndex, rageInfo, sizeof(rageInfo)); - int index = ragePhaseInfo.Names.FindString(rageInfo.Name); + ChaserBossPostureCondition_RagePhase condition = view_as(conditions.GetSection(name)); + if (condition == null || !condition.GetEnabled(difficulty)) + { + continue; + } - if (index != -1) - { - strcopy(buffer, bufferSize, postureInfo.Name); - delete snapshot; - return Plugin_Changed; + if (chaser.RageIndex == -1) + { + continue; + } + + data.GetRages().GetSectionNameFromIndex(chaser.RageIndex, name, sizeof(name)); + if (condition.IsPhaseValid(name)) + { + posture.GetSectionName(name, sizeof(name)); + strcopy(buffer, bufferSize, name); + return Plugin_Changed; + } } } - delete snapshot; return Plugin_Continue; } \ No newline at end of file diff --git a/addons/sourcemod/scripting/sf2/npc/entities/chaser/postures/running_away.sp b/addons/sourcemod/scripting/sf2/npc/entities/chaser/postures/running_away.sp index c9532dd0..fc92e00e 100644 --- a/addons/sourcemod/scripting/sf2/npc/entities/chaser/postures/running_away.sp +++ b/addons/sourcemod/scripting/sf2/npc/entities/chaser/postures/running_away.sp @@ -1,4 +1,5 @@ #pragma semicolon 1 +#pragma newdecls required void InitializePostureRunningAway() { @@ -7,38 +8,58 @@ void InitializePostureRunningAway() static Action OnChaserUpdatePosture(SF2NPC_Chaser controller, char[] buffer, int bufferSize) { - SF2ChaserBossProfileData data; - data = controller.GetProfileData(); - StringMap postures = data.Postures; - if (postures == null) + SF2_ChaserEntity chaser = SF2_ChaserEntity(controller.EntIndex); + if (!chaser.IsValid()) { return Plugin_Continue; } - SF2ChaserBossProfilePostureInfo postureInfo; - StringMapSnapshot snapshot = postures.Snapshot(); - for (int i = 0; i < snapshot.Length; i++) + int difficulty = controller.Difficulty; + + ChaserBossProfile data = controller.GetProfileDataEx(); + ProfileObject obj = data.GetSection("postures"); + if (obj == null) + { + return Plugin_Continue; + } + + for (int i = 0; i < obj.SectionLength; i++) { - if (!data.GetPostureFromIndex(i, postureInfo)) + ProfileObject posture = data.GetPostureFromIndex(i); + if (posture == null) { continue; } - SF2PostureConditionRunAwayInfo runAwayInfo; - runAwayInfo = postureInfo.RunAwayInfo; - if (!runAwayInfo.Enabled) + ProfileObject conditions = posture.GetSection("conditions"); + if (conditions == null || conditions.SectionLength == 0) { continue; } - SF2_ChaserEntity chaser = SF2_ChaserEntity(controller.EntIndex); - if (chaser.IsValid() && chaser.IsRunningAway) + for (int j = 0; j < conditions.SectionLength; j++) { - strcopy(buffer, bufferSize, postureInfo.Name); - delete snapshot; - return Plugin_Changed; + char name[64]; + conditions.GetSectionNameFromIndex(j, name, sizeof(name)); + if (strcmp(name, "running_away") != 0) + { + continue; + } + + ChaserBossPostureCondition condition = view_as(conditions.GetSection(name)); + if (condition == null || !condition.GetEnabled(difficulty)) + { + continue; + } + + if (chaser.IsRunningAway) + { + posture.GetSectionName(name, sizeof(name)); + strcopy(buffer, bufferSize, name); + return Plugin_Changed; + } } } - delete snapshot; + return Plugin_Continue; } \ No newline at end of file diff --git a/addons/sourcemod/scripting/sf2/npc/entities/chaser/postures/within_bounds.sp b/addons/sourcemod/scripting/sf2/npc/entities/chaser/postures/within_bounds.sp index 1ae3d000..33f9e0d2 100644 --- a/addons/sourcemod/scripting/sf2/npc/entities/chaser/postures/within_bounds.sp +++ b/addons/sourcemod/scripting/sf2/npc/entities/chaser/postures/within_bounds.sp @@ -1,4 +1,18 @@ #pragma semicolon 1 +#pragma newdecls required + +methodmap ChaserBossPostureCondition_WithinBounds < ChaserBossPostureCondition +{ + public void GetMins(int difficulty, float buffer[3]) + { + this.GetDifficultyVector("mins", difficulty, buffer); + } + + public void GetMaxs(int difficulty, float buffer[3]) + { + this.GetDifficultyVector("maxs", difficulty, buffer); + } +} void InitializePostureWithinBounds() { @@ -7,45 +21,62 @@ void InitializePostureWithinBounds() static Action OnChaserUpdatePosture(SF2NPC_Chaser controller, char[] buffer, int bufferSize) { - SF2ChaserBossProfileData data; - data = controller.GetProfileData(); - StringMap postures = data.Postures; - if (postures == null) + SF2_ChaserEntity chaser = SF2_ChaserEntity(controller.EntIndex); + if (!chaser.IsValid()) + { + return Plugin_Continue; + } + + int difficulty = controller.Difficulty; + + ChaserBossProfile data = controller.GetProfileDataEx(); + ProfileObject obj = data.GetSection("postures"); + if (obj == null) { return Plugin_Continue; } - SF2ChaserBossProfilePostureInfo postureInfo; - StringMapSnapshot snapshot = postures.Snapshot(); - for (int i = 0; i < snapshot.Length; i++) + for (int i = 0; i < obj.SectionLength; i++) { - if (!data.GetPostureFromIndex(i, postureInfo)) + ProfileObject posture = data.GetPostureFromIndex(i); + if (posture == null) { continue; } - SF2PostureConditionWithinBoundsInfo boundsInfo; - boundsInfo = postureInfo.BoundsInfo; - if (!boundsInfo.Enabled) + ProfileObject conditions = posture.GetSection("conditions"); + if (conditions == null || conditions.SectionLength == 0) { continue; } - SF2_ChaserEntity chaser = SF2_ChaserEntity(controller.EntIndex); - if (!chaser.IsValid()) + for (int j = 0; j < conditions.SectionLength; j++) { - continue; - } - float myPos[3]; - chaser.GetAbsOrigin(myPos); - if (IsSpaceOccupiedIgnorePlayersAndEnts(myPos, boundsInfo.Mins, boundsInfo.Maxs, chaser.index)) - { - strcopy(buffer, bufferSize, postureInfo.Name); - delete snapshot; - return Plugin_Changed; + char name[64]; + conditions.GetSectionNameFromIndex(j, name, sizeof(name)); + if (strcmp(name, "within_bounds") != 0) + { + continue; + } + + ChaserBossPostureCondition_WithinBounds condition = view_as(conditions.GetSection(name)); + if (condition == null || !condition.GetEnabled(difficulty)) + { + continue; + } + + float mins[3], maxs[3], myPos[3]; + condition.GetMins(difficulty, mins); + condition.GetMaxs(difficulty, maxs); + chaser.GetAbsOrigin(myPos); + if (IsSpaceOccupiedIgnorePlayersAndEnts(myPos, mins, maxs, chaser.index)) + { + posture.GetSectionName(name, sizeof(name)); + strcopy(buffer, bufferSize, name); + return Plugin_Changed; + } } } - delete snapshot; return Plugin_Continue; } \ No newline at end of file diff --git a/addons/sourcemod/scripting/sf2/npc/entities/chaser/postures/within_range.sp b/addons/sourcemod/scripting/sf2/npc/entities/chaser/postures/within_range.sp index 1beadd3d..45de3303 100644 --- a/addons/sourcemod/scripting/sf2/npc/entities/chaser/postures/within_range.sp +++ b/addons/sourcemod/scripting/sf2/npc/entities/chaser/postures/within_range.sp @@ -1,4 +1,38 @@ #pragma semicolon 1 +#pragma newdecls required + +methodmap ChaserBossPostureCondition_WithinRange < ChaserBossPostureCondition +{ + public float GetMinRange(int difficulty) + { + return this.GetDifficultyFloat("min_range", difficulty, 0.0); + } + + public float GetMaxRange(int difficulty) + { + return this.GetDifficultyFloat("max_range", difficulty, 512.0); + } + + public float GetCooldown(int difficulty) + { + return this.GetDifficultyFloat("cooldown", difficulty, 1.0); + } + + property float CurrentCooldown + { + public get() + { + float value = 0.0; + this.GetValue("__current_cooldown", value); + return value; + } + + public set(float value) + { + this.SetValue("__current_cooldown", value); + } + } +} void InitializePostureWithinRange() { @@ -7,70 +41,86 @@ void InitializePostureWithinRange() static Action OnChaserUpdatePosture(SF2NPC_Chaser controller, char[] buffer, int bufferSize) { - SF2ChaserBossProfileData data; - data = controller.GetProfileData(); - StringMap postures = data.Postures; - if (postures == null) + SF2_ChaserEntity chaser = SF2_ChaserEntity(controller.EntIndex); + if (!chaser.IsValid()) { return Plugin_Continue; } + int difficulty = controller.Difficulty; float gameTime = GetGameTime(); - SF2ChaserBossProfilePostureInfo postureInfo; - StringMapSnapshot snapshot = postures.Snapshot(); - for (int i = 0; i < snapshot.Length; i++) + ChaserBossProfile data = controller.GetProfileDataEx(); + ProfileObject obj = data.GetSection("postures"); + if (obj == null) { - if (!data.GetPostureFromIndex(i, postureInfo)) - { - continue; - } - - int difficulty = controller.Difficulty; + return Plugin_Continue; + } - SF2PostureConditionWithinRangeInfo rangeInfo; - rangeInfo = postureInfo.RangeInfo; - if (!rangeInfo.Enabled[difficulty]) + for (int i = 0; i < obj.SectionLength; i++) + { + ProfileObject posture = data.GetPostureFromIndex(i); + if (posture == null) { continue; } - if (rangeInfo.CurrentCooldown > gameTime) + ProfileObject conditions = posture.GetSection("conditions"); + if (conditions == null || conditions.SectionLength == 0) { continue; } - SF2_ChaserEntity chaser = SF2_ChaserEntity(controller.EntIndex); - if (!chaser.IsValid() || chaser.State != STATE_CHASE) + for (int j = 0; j < conditions.SectionLength; j++) { - continue; - } + char name[64]; + conditions.GetSectionNameFromIndex(j, name, sizeof(name)); + if (strcmp(name, "within_range") != 0) + { + continue; + } - if (chaser.MyNextBotPointer().GetLocomotionInterface().GetGroundSpeed() < 0.01) - { - continue; - } + ChaserBossPostureCondition_WithinRange condition = view_as(conditions.GetSection(name)); + if (condition == null || !condition.GetEnabled(difficulty)) + { + continue; + } - CBaseEntity target = chaser.Target; - if (!target.IsValid()) - { - continue; - } + if (condition.CurrentCooldown > gameTime) + { + continue; + } - float range = controller.Path.GetLength() - controller.Path.GetCursorPosition(); + if (chaser.State != STATE_CHASE) + { + continue; + } - if (range > rangeInfo.MinRange[difficulty] && range < rangeInfo.MaxRange[difficulty]) - { - strcopy(buffer, bufferSize, postureInfo.Name); - delete snapshot; - return Plugin_Changed; - } - else - { - rangeInfo.CurrentCooldown = gameTime + rangeInfo.Cooldown[difficulty]; + if (chaser.MyNextBotPointer().GetLocomotionInterface().GetGroundSpeed() < 0.01) + { + continue; + } + + CBaseEntity target = chaser.Target; + if (!target.IsValid()) + { + continue; + } + + float range = controller.Path.GetLength() - controller.Path.GetCursorPosition(); + + if (range > condition.GetMinRange(difficulty) && range < condition.GetMaxRange(difficulty)) + { + posture.GetSectionName(name, sizeof(name)); + strcopy(buffer, bufferSize, name); + return Plugin_Changed; + } + else + { + condition.CurrentCooldown = gameTime + condition.GetCooldown(difficulty); + } } } - delete snapshot; return Plugin_Continue; } \ No newline at end of file diff --git a/addons/sourcemod/scripting/sf2/npc/entities/initialize.sp b/addons/sourcemod/scripting/sf2/npc/entities/initialize.sp index f2069a50..7a223b8d 100644 --- a/addons/sourcemod/scripting/sf2/npc/entities/initialize.sp +++ b/addons/sourcemod/scripting/sf2/npc/entities/initialize.sp @@ -1,4 +1,5 @@ #pragma semicolon 1 +#pragma newdecls required #include "base/entity.sp" #include "chaser/entity.sp" diff --git a/addons/sourcemod/scripting/sf2/npc/entities/statue/actions/chase.sp b/addons/sourcemod/scripting/sf2/npc/entities/statue/actions/chase.sp index 74817078..e876c469 100644 --- a/addons/sourcemod/scripting/sf2/npc/entities/statue/actions/chase.sp +++ b/addons/sourcemod/scripting/sf2/npc/entities/statue/actions/chase.sp @@ -1,4 +1,5 @@ #pragma semicolon 1 +#pragma newdecls required static NextBotActionFactory g_Factory; @@ -21,9 +22,8 @@ static int OnStart(SF2_StatueChaseAction action, SF2_StatueEntity actor, NextBot { SF2NPC_Statue controller = actor.Controller; int difficulty = controller.Difficulty; - SF2StatueBossProfileData data; - data = controller.GetProfileData(); - actor.CurrentChaseDuration = data.ChaseDuration[difficulty]; + StatueBossProfile data = controller.GetProfileDataEx(); + actor.CurrentChaseDuration = data.GetChaseDuration(difficulty); if (actor.InitialChaseDuration > 0.0) { actor.CurrentChaseDuration = actor.InitialChaseDuration; @@ -57,10 +57,7 @@ static int Update(SF2_StatueChaseAction action, SF2_StatueEntity actor) } SF2NPC_Statue controller = actor.Controller; - SF2StatueBossProfileData data; - data = controller.GetProfileData(); - SF2BossProfileData originalData; - originalData = view_as(controller).GetProfileData(); + StatueBossProfile data = controller.GetProfileDataEx(); bool attackEliminated = (controller.Flags & SFF_ATTACKWAITERS) != 0; int difficulty = controller.Difficulty; INextBot bot = actor.MyNextBotPointer(); @@ -86,20 +83,20 @@ static int Update(SF2_StatueChaseAction action, SF2_StatueEntity actor) if (visible) { - float maxRange = data.ChaseDurationAddMaxRange[difficulty]; + float maxRange = data.GetChaseDurationAddMaxRange(difficulty); if (maxRange > 0.0 && player.IsValid && player.CanSeeSlender(controller.Index, false, _, !attackEliminated)) { float distanceRatio = bot.GetRangeTo(player.index) / maxRange; if (distanceRatio < 1.0) { - float durationTimeAddMin = data.ChaseDurationAddVisibilityMin[difficulty]; - float durationTimeAddMax = data.ChaseDurationAddVisibilityMax[difficulty]; + float durationTimeAddMin = data.GetChaseDurationAddVisibilityMin(difficulty); + float durationTimeAddMax = data.GetChaseDurationAddVisibilityMax(difficulty); float durationAdd = durationTimeAddMin + ((durationTimeAddMax - durationTimeAddMin) * distanceRatio); actor.CurrentChaseDuration += durationAdd * GetGameFrameTime(); - if (actor.CurrentChaseDuration > data.ChaseDuration[difficulty]) + if (actor.CurrentChaseDuration > data.GetChaseDuration(difficulty)) { - actor.CurrentChaseDuration = data.ChaseDuration[difficulty]; + actor.CurrentChaseDuration = data.GetChaseDuration(difficulty); } } } @@ -115,12 +112,12 @@ static int Update(SF2_StatueChaseAction action, SF2_StatueEntity actor) if (SF_IsRaidMap() || SF_BossesChaseEndlessly() || SF_IsProxyMap() || SF_IsBoxingMap() || SF_IsSlaughterRunMap()) { - actor.CurrentChaseDuration = data.ChaseDuration[difficulty]; + actor.CurrentChaseDuration = data.GetChaseDuration(difficulty); } bool tooClose = target.IsValid() && visible && - bot.IsRangeLessThan(target.index, 8.0); + bot.GetRangeSquaredTo(target.index) <= 32.0; if ((tooClose || !actor.IsMoving) && path.IsValid()) { @@ -128,19 +125,15 @@ static int Update(SF2_StatueChaseAction action, SF2_StatueEntity actor) } else { - float pos[3]; - target.GetAbsOrigin(pos); + int pathTo = target.index; if (actor.Teleporters.Length > 0) { - CBaseEntity(actor.Teleporters.Get(0)).GetAbsOrigin(pos); + pathTo = actor.Teleporters.Get(0); } - if (!bot.IsRangeLessThanEx(pos, 8.0) && actor.IsMoving) + if (path.GetAge() > 0.3 || (path.IsValid() && (path.GetLength() - path.GetCursorPosition()) < 256.0)) { - if (path.GetAge() > 0.3 || (path.IsValid() && (path.GetLength() - path.GetCursorPosition()) < 256.0)) - { - path.ComputeToPos(bot, pos); - } + path.ComputeToTarget(bot, pathTo); } } @@ -155,9 +148,9 @@ static int Update(SF2_StatueChaseAction action, SF2_StatueEntity actor) if (actor.IsMoving) { - g_SlenderStatueIdleLifeTime[controller.Index] = gameTime + data.IdleLifeTime[difficulty]; + g_SlenderStatueIdleLifeTime[controller.Index] = gameTime + data.GetIdleLifeTime(difficulty); - if (bot.GetRangeSquaredTo(target.index) <= Pow(originalData.InstantKillRadius, 2.0) && visible) + if (bot.GetRangeSquaredTo(target.index) <= Pow(data.InstantKillRadius, 2.0) && visible) { if (controller.Flags & SFF_FAKE) { @@ -166,7 +159,7 @@ static int Update(SF2_StatueChaseAction action, SF2_StatueEntity actor) } else { - actor.LastKillTime = gameTime + originalData.InstantKillCooldown[difficulty]; + actor.LastKillTime = gameTime + data.GetInstantKillCooldown(difficulty); player.StartDeathCam(controller.Index, myPos); } } diff --git a/addons/sourcemod/scripting/sf2/npc/entities/statue/actions/idle.sp b/addons/sourcemod/scripting/sf2/npc/entities/statue/actions/idle.sp index c21f6dff..47ca655f 100644 --- a/addons/sourcemod/scripting/sf2/npc/entities/statue/actions/idle.sp +++ b/addons/sourcemod/scripting/sf2/npc/entities/statue/actions/idle.sp @@ -1,4 +1,5 @@ #pragma semicolon 1 +#pragma newdecls required static NextBotActionFactory g_Factory; diff --git a/addons/sourcemod/scripting/sf2/npc/entities/statue/actions/mainlayer.sp b/addons/sourcemod/scripting/sf2/npc/entities/statue/actions/mainlayer.sp index 03b2cd07..5228bc15 100644 --- a/addons/sourcemod/scripting/sf2/npc/entities/statue/actions/mainlayer.sp +++ b/addons/sourcemod/scripting/sf2/npc/entities/statue/actions/mainlayer.sp @@ -1,4 +1,5 @@ #pragma semicolon 1 +#pragma newdecls required static NextBotActionFactory g_Factory; @@ -72,11 +73,7 @@ static int Update(SF2_StatueBaseAction action, SF2_StatueEntity actor, float int return action.Done("I'm a faker"); } - SF2StatueBossProfileData data; - data = controller.GetProfileData(); - SF2BossProfileData originalData; - originalData = view_as(controller).GetProfileData(); - SF2BossProfileSoundInfo soundInfo; + StatueBossProfile data = controller.GetProfileDataEx(); CBaseEntity target = actor.Target; float myPos[3]; actor.GetAbsOrigin(myPos); @@ -89,10 +86,8 @@ static int Update(SF2_StatueBaseAction action, SF2_StatueEntity actor, float int if (actor.IsMoving) { - soundInfo = data.SingleMoveSounds; - soundInfo.EmitSound(_, actor.index); - soundInfo = data.MoveSounds; - soundInfo.EmitSound(_, actor.index); + data.GetSingleMoveSounds().EmitSound(_, actor.index, .difficulty = difficulty); + data.GetMoveSounds().EmitSound(_, actor.index, .difficulty = difficulty); if (target.IsValid()) { @@ -100,24 +95,24 @@ static int Update(SF2_StatueBaseAction action, SF2_StatueEntity actor, float int target.GetAbsOrigin(targetPos); float distance = GetVectorSquareMagnitude(targetPos, myPos); - float maxRange = Pow(data.ModelChangeDistanceMax[difficulty], 2.0); + float maxRange = Pow(data.GetMaxModelChangeDistance(difficulty), 2.0); char model[PLATFORM_MAX_PATH]; if (distance < maxRange * 0.33) { - data.ModelsCloseDist.GetString(difficulty, model, sizeof(model)); + data.GetCloseDistanceModel(difficulty, model, sizeof(model)); } else if (distance < maxRange * 0.66) { - data.ModelsAverageDist.GetString(difficulty, model, sizeof(model)); + data.GetAverageDistanceModel(difficulty, model, sizeof(model)); } else { - originalData.Models.GetString(difficulty, model, sizeof(model)); + data.GetModel(difficulty, model, sizeof(model)); } if (model[0] == '\0' || strcmp(model, "models/") == 0) { - originalData.Models.GetString(difficulty, model, sizeof(model)); + data.GetModel(difficulty, model, sizeof(model)); } actor.SetModel(model); @@ -125,8 +120,12 @@ static int Update(SF2_StatueBaseAction action, SF2_StatueEntity actor, float int } else { - soundInfo = data.MoveSounds; - soundInfo.StopAllSounds(actor.index); + data.GetMoveSounds().StopAllSounds(actor.index, difficulty); + } + + if (actor.IsKillingSomeone) + { + return action.SuspendFor(SF2_DeathCamAction()); } UnstuckCheck(action, actor); diff --git a/addons/sourcemod/scripting/sf2/npc/entities/statue/entity.sp b/addons/sourcemod/scripting/sf2/npc/entities/statue/entity.sp index 299c486d..9bb62709 100644 --- a/addons/sourcemod/scripting/sf2/npc/entities/statue/entity.sp +++ b/addons/sourcemod/scripting/sf2/npc/entities/statue/entity.sp @@ -1,4 +1,5 @@ #pragma semicolon 1 +#pragma newdecls required #include "actions/mainlayer.sp" #include "actions/idle.sp" @@ -114,26 +115,27 @@ methodmap SF2_StatueEntity < SF2_BaseBoss controller.GetProfile(profile, sizeof(profile)); statue.Controller = view_as(controller); - SF2BossProfileData originalData; - originalData = view_as(statue.Controller).GetProfileData(); + StatueBossProfile profileData = statue.Controller.GetProfileDataEx(); + int difficulty = g_DifficultyConVar.IntValue; char buffer[PLATFORM_MAX_PATH]; GetSlenderModel(controller.Index, _, buffer, sizeof(buffer)); statue.SetModel(buffer); - statue.SetRenderMode(view_as(g_SlenderRenderMode[controller.Index])); - statue.SetRenderFx(view_as(g_SlenderRenderFX[controller.Index])); - statue.SetRenderColor(g_SlenderRenderColor[controller.Index][0], g_SlenderRenderColor[controller.Index][1], - g_SlenderRenderColor[controller.Index][2], g_SlenderRenderColor[controller.Index][3]); + statue.SetRenderMode(profileData.GetRenderMode(difficulty)); + statue.SetRenderFx(profileData.GetRenderFx(difficulty)); + int color[4]; + profileData.GetRenderColor(difficulty, color); + statue.SetRenderColor(color[0], color[1], color[2], color[3]); if (SF_SpecialRound(SPECIALROUND_TINYBOSSES)) { - float scaleModel = controller.ModelScale * 0.5; + float scaleModel = profileData.ModelScale * 0.5; statue.SetPropFloat(Prop_Send, "m_flModelScale", scaleModel); } else { - statue.SetPropFloat(Prop_Send, "m_flModelScale", controller.ModelScale); + statue.SetPropFloat(Prop_Send, "m_flModelScale", profileData.ModelScale); } CBaseNPC npc = TheNPCs.FindNPCByEntIndex(statue.index); @@ -144,7 +146,9 @@ methodmap SF2_StatueEntity < SF2_BaseBoss npc.flGravity = 800.0; npc.flDeathDropHeight = 99999.0; npc.flJumpHeight = 512.0; - npc.flMaxYawRate = originalData.TurnRate; + npc.flFrictionForward = profileData.GetForwardFriction(difficulty); + npc.flFrictionSideways = profileData.GetSidewaysFriction(difficulty); + npc.flMaxYawRate = profileData.TurnRate; loco.SetCallback(LocomotionCallback_ShouldCollideWith, LocoCollideWith); loco.SetCallback(LocomotionCallback_ClimbUpToLedge, ClimbUpCBase); @@ -216,7 +220,7 @@ static void ThinkPost(int entIndex) ProcessSpeed(statue); - if (NPCGetCustomOutlinesState(statue.Controller.Index) && NPCGetRainbowOutlineState(statue.Controller.Index)) + if (statue.GetProfileData().CustomOutlines && statue.GetProfileData().RainbowOutline) { statue.ProcessRainbowOutline(); } @@ -227,7 +231,7 @@ static void ThinkPost(int entIndex) } statue.InterruptConditions = 0; - statue.SetNextThink(GetGameTime()); + statue.SetNextThink(GetGameTime() + statue.Controller.GetProfileDataEx().TickRate); } static MRESReturn UpdateTransmitState(int entIndex, DHookReturn ret, DHookParam params) @@ -261,10 +265,7 @@ static CBaseEntity ProcessVision(SF2_StatueEntity statue, int &interruptConditio return CBaseEntity(-1); } bool attackEliminated = (controller.Flags & SFF_ATTACKWAITERS) != 0; - SF2StatueBossProfileData data; - data = controller.GetProfileData(); - SF2BossProfileData originalData; - originalData = view_as(controller).GetProfileData(); + StatueBossProfile data = controller.GetProfileDataEx(); int difficulty = controller.Difficulty; float playerDists[MAXTF2PLAYERS]; @@ -288,7 +289,7 @@ static CBaseEntity ProcessVision(SF2_StatueEntity statue, int &interruptConditio } int bestNewTarget = oldTarget; - float searchRange = originalData.SearchRange[difficulty]; + float searchRange = data.GetSearchRange(difficulty); float bestNewTargetDist = Pow(searchRange, 2.0); if (IsValidEntity(bestNewTarget)) { @@ -337,7 +338,7 @@ static CBaseEntity ProcessVision(SF2_StatueEntity statue, int &interruptConditio bool isVisible = false; int traceHitEntity; - TR_TraceHullFilter(traceStartPos, + Handle trace = TR_TraceHullFilterEx(traceStartPos, traceEndPos, traceMins, traceMaxs, @@ -345,14 +346,16 @@ static CBaseEntity ProcessVision(SF2_StatueEntity statue, int &interruptConditio TraceRayBossVisibility, statue.index); - isVisible = !TR_DidHit(); - traceHitEntity = TR_GetEntityIndex(); + isVisible = !TR_DidHit(trace); + traceHitEntity = TR_GetEntityIndex(trace); if (!isVisible && traceHitEntity == client.index) { isVisible = true; } + delete trace; + if (isVisible) { isVisible = NPCShouldSeeEntity(controller.Index, client.index); @@ -373,7 +376,7 @@ static CBaseEntity ProcessVision(SF2_StatueEntity statue, int &interruptConditio } } - if (dist > Pow(originalData.SearchRange[difficulty], 2.0)) + if (dist > Pow(data.GetSearchRange(difficulty), 2.0)) { isVisible = false; } @@ -449,7 +452,7 @@ static CBaseEntity ProcessVision(SF2_StatueEntity statue, int &interruptConditio delete arrayRaidTargets; } } - statue.CurrentChaseDuration = data.ChaseDuration[difficulty]; + statue.CurrentChaseDuration = data.GetChaseDuration(difficulty); } if (bestNewTarget != INVALID_ENT_REFERENCE) @@ -464,28 +467,26 @@ static CBaseEntity ProcessVision(SF2_StatueEntity statue, int &interruptConditio static void ProcessSpeed(SF2_StatueEntity statue) { SF2NPC_Statue controller = statue.Controller; - SF2NPC_BaseNPC baseController = view_as(controller); int difficulty = controller.Difficulty; CBaseNPC npc = TheNPCs.FindNPCByEntIndex(statue.index); - SF2BossProfileData originalData; - originalData = baseController.GetProfileData(); + StatueBossProfile data = controller.GetProfileDataEx(); float speed, acceleration; - acceleration = originalData.Acceleration[difficulty]; + acceleration = data.GetAcceleration(difficulty); if (controller.HasAttribute(SF2Attribute_ReducedAccelerationOnLook) && controller.CanBeSeen(_, true)) { acceleration *= controller.GetAttributeValue(SF2Attribute_ReducedAccelerationOnLook); } acceleration += controller.GetAddAcceleration(); - speed = originalData.RunSpeed[difficulty] * 10.0; // Backwards compatibility + speed = data.GetRunSpeed(difficulty) * 10.0; // Backwards compatibility if (controller.HasAttribute(SF2Attribute_ReducedSpeedOnLook) && controller.CanBeSeen(_, true)) { speed *= controller.GetAttributeValue(SF2Attribute_ReducedSpeedOnLook); } - speed += baseController.GetAddSpeed(); + speed += controller.GetAddSpeed(); float forwardSpeed = speed; Action action = Plugin_Continue; @@ -517,14 +518,14 @@ static void ProcessSpeed(SF2_StatueEntity statue) if (SF_IsSlaughterRunMap()) { float slaughterSpeed = g_SlaughterRunMinimumBossRunSpeedConVar.FloatValue; - if (!originalData.SlaughterRunData.CustomMinimumSpeed[difficulty] && speed < slaughterSpeed) + if ((data.GetSlaughterRunData() == null || data.GetSlaughterRunData().ShouldUseCustomMinSpeed(difficulty)) && speed < slaughterSpeed) { speed = slaughterSpeed; } acceleration += 10000.0; } - if ((!originalData.IsPvEBoss && IsBeatBoxBeating(2)) || statue.IsKillingSomeone || !statue.IsMoving) + if ((!data.IsPvEBoss && IsBeatBoxBeating(2)) || statue.IsKillingSomeone || !statue.IsMoving) { speed = 0.0; } @@ -575,8 +576,5 @@ static any Native_GetProfileData(Handle plugin, int numParams) SF2_StatueEntity bossEntity = SF2_StatueEntity(entity); - SF2StatueBossProfileData data; - data = bossEntity.Controller.GetProfileData(); - SetNativeArray(2, data, sizeof(data)); - return 0; + return bossEntity.Controller.GetProfileDataEx(); } diff --git a/addons/sourcemod/scripting/sf2/npc/glow.sp b/addons/sourcemod/scripting/sf2/npc/glow.sp index 627000a1..4aef1703 100644 --- a/addons/sourcemod/scripting/sf2/npc/glow.sp +++ b/addons/sourcemod/scripting/sf2/npc/glow.sp @@ -1,3 +1,6 @@ +#pragma semicolon 1 +#pragma newdecls required + static const int g_DefaultColor[4] = { 150, 0, 255, 255 }; void SetupNPCGlows() @@ -45,8 +48,7 @@ static void OnSpecialRoundStart(int specialRound) static void OnBossSpawn(SF2NPC_BaseNPC controller) { - SF2BossProfileData data; - data = controller.GetProfileData(); + BaseBossProfile data = controller.GetProfileDataEx(); if (data.IsPvEBoss) { return; @@ -56,7 +58,7 @@ static void OnBossSpawn(SF2NPC_BaseNPC controller) color = g_DefaultColor; if (data.CustomOutlines) { - color = data.OutlineColor; + data.GetOutlineColor(color); } CreateGlowEntity(controller.EntIndex, color); UpdateVisibility(controller); diff --git a/addons/sourcemod/scripting/sf2/npc/npc_chaser.sp b/addons/sourcemod/scripting/sf2/npc/npc_chaser.sp index 2d8ffd0c..0b46f757 100644 --- a/addons/sourcemod/scripting/sf2/npc/npc_chaser.sp +++ b/addons/sourcemod/scripting/sf2/npc/npc_chaser.sp @@ -4,27 +4,17 @@ #define _sf2_npc_chaser_included #pragma semicolon 1 - -static SF2ChaserBossProfileData g_NpcChaserProfileData[MAX_BOSSES]; +#pragma newdecls required static float g_NpcStunAddHealth[MAX_BOSSES]; static float g_NpcDeathInitialHealth[MAX_BOSSES][Difficulty_Max]; static float g_NpcDeathHealth[MAX_BOSSES][Difficulty_Max]; -static float g_NpcAlertGracetime[MAX_BOSSES][Difficulty_Max]; -static float g_NpcAlertDuration[MAX_BOSSES][Difficulty_Max]; -static float g_NpcChaseDuration[MAX_BOSSES][Difficulty_Max]; - ArrayList g_NpcChaseOnLookTarget[MAX_BOSSES] = { null, ... }; -static float g_NpcSearchWanderRangeMin[MAX_BOSSES][Difficulty_Max]; -static float g_NpcSearchWanderRangeMax[MAX_BOSSES][Difficulty_Max]; - bool g_NpcCopyAlerted[MAX_BOSSES]; -static bool g_NpcHasIsBoxingBoss[MAX_BOSSES] = { false, ... }; - bool g_NpcStealingLife[MAX_BOSSES]; Handle g_NpcLifeStealTimer[MAX_BOSSES]; @@ -32,7 +22,6 @@ static Handle g_NpcInstantKillThink[MAX_BOSSES]; //Boxing stuff static int g_NpcBoxingCurrentDifficulty[MAX_BOSSES]; -static int g_NpcBoxingRagePhase[MAX_BOSSES]; static bool g_ClientShouldBeForceChased[MAX_BOSSES][2049]; static bool g_IsTargetMarked[MAX_BOSSES][2049]; @@ -85,22 +74,12 @@ static void OnPlayerEscape(SF2_BasePlayer client) static void OnBossRemoved(SF2NPC_BaseNPC npc) { - if (npc.Type == SF2BossType_Chaser) + if (npc.GetProfileDataEx().Type == SF2BossType_Chaser) { NPCChaserOnRemoveProfile(npc.Index); } } -SF2ChaserBossProfileData NPCChaserGetProfileData(int npcIndex) -{ - return g_NpcChaserProfileData[npcIndex]; -} - -void NPCChaserSetProfileData(int npcIndex, SF2ChaserBossProfileData value) -{ - g_NpcChaserProfileData[npcIndex] = value; -} - float NPCChaserGetAddStunHealth(int npcIndex) { return g_NpcStunAddHealth[npcIndex]; @@ -126,11 +105,6 @@ void NPCChaserSetDeathHealth(int npcIndex, int difficulty, float amount) g_NpcDeathHealth[npcIndex][difficulty] = amount; } -bool NPCChaserIsBoxingBoss(int npcIndex) -{ - return g_NpcHasIsBoxingBoss[npcIndex]; -} - int NPCChaserGetBoxingDifficulty(int npcIndex) { return g_NpcBoxingCurrentDifficulty[npcIndex]; @@ -179,13 +153,11 @@ void NPCChaserOnSelectProfile(int npcIndex) SF2NPC_Chaser chaser = SF2NPC_Chaser(npcIndex); char profile[SF2_MAX_PROFILE_NAME_LENGTH]; NPCGetProfile(npcIndex, profile, sizeof(profile)); - SF2ChaserBossProfileData profileData; - g_ChaserBossProfileData.GetArray(profile, profileData, sizeof(profileData)); - g_NpcChaserProfileData[npcIndex] = profileData; + ChaserBossProfile profileData = chaser.GetProfileDataEx(); for (int difficulty = 0; difficulty < Difficulty_Max; difficulty++) { - g_NpcDeathInitialHealth[npcIndex][difficulty] = GetChaserProfileDeathHealth(profile, difficulty); + g_NpcDeathInitialHealth[npcIndex][difficulty] = profileData.GetDeathBehavior().GetHealth(difficulty); g_NpcDeathHealth[npcIndex][difficulty] = g_NpcDeathInitialHealth[npcIndex][difficulty]; } @@ -198,13 +170,10 @@ void NPCChaserOnSelectProfile(int npcIndex) chaser.SetAddAcceleration(-chaser.GetAddAcceleration()); chaser.StunHealthAdd = -chaser.StunHealthAdd; - g_NpcHasIsBoxingBoss[npcIndex] = GetChaserProfileBoxingState(profile); - g_NpcStealingLife[npcIndex] = false; g_NpcLifeStealTimer[npcIndex] = null; g_NpcBoxingCurrentDifficulty[npcIndex] = 1; - g_NpcBoxingRagePhase[npcIndex] = 0; g_NpcCopyAlerted[npcIndex] = false; @@ -226,19 +195,10 @@ static void NPCChaserResetValues(int npcIndex) { for (int difficulty = 0; difficulty < Difficulty_Max; difficulty++) { - g_NpcAlertGracetime[npcIndex][difficulty] = 0.0; - g_NpcAlertDuration[npcIndex][difficulty] = 0.0; - g_NpcChaseDuration[npcIndex][difficulty] = 0.0; - - g_NpcSearchWanderRangeMin[npcIndex][difficulty] = 0.0; - g_NpcSearchWanderRangeMax[npcIndex][difficulty] = 0.0; - g_NpcDeathInitialHealth[npcIndex][difficulty] = 0.0; NPCChaserSetDeathHealth(npcIndex, difficulty, 0.0); } - g_NpcHasIsBoxingBoss[npcIndex] = false; - g_NpcStunAddHealth[npcIndex] = 0.0; g_NpcStealingLife[npcIndex] = false; @@ -254,7 +214,6 @@ static void NPCChaserResetValues(int npcIndex) NPCChaserSetAddStunHealth(npcIndex, -NPCChaserGetAddStunHealth(npcIndex)); g_NpcBoxingCurrentDifficulty[npcIndex] = 0; - g_NpcBoxingRagePhase[npcIndex] = 0; g_NpcCopyAlerted[npcIndex] = false; } @@ -393,7 +352,7 @@ bool IsTargetValidForSlenderEx(CBaseEntity target, int bossIndex, bool includeEl return false; } - if (!g_SlenderTeleportIgnoreChases[bossIndex]) + if (!SF_BossesChaseEndlessly() && !SF_IsRenevantMap() && !SF_IsSurvivalMap() && !SF2NPC_BaseNPC(bossIndex).GetProfileDataEx().TeleportIgnoreChases) { for (int i = 0; i < MAX_BOSSES; i++) { @@ -409,11 +368,8 @@ bool IsTargetValidForSlenderEx(CBaseEntity target, int bossIndex, bool includeEl continue; } - SF2BossProfileData data; - data = view_as(npc).GetProfileData(); - int state = chaser.State; - if (!data.IsPvEBoss && (state == STATE_CHASE || state == STATE_ATTACK || state == STATE_STUN)) + if (!npc.GetProfileDataEx().IsPvEBoss && (state == STATE_CHASE || state == STATE_ATTACK || state == STATE_STUN)) { return false; } @@ -692,12 +648,11 @@ static any Native_PerformVoice(Handle plugin, int numParams) return 0; } - SF2ChaserBossProfileData data; - data = controller.GetProfileData(); - SF2ChaserBossProfileAttackData attackData; - data.GetAttackFromIndex(GetNativeCell(3), attackData); + ChaserBossProfile data = controller.GetProfileDataEx(); + char name[64]; + data.GetAttackName(GetNativeCell(3), name, sizeof(name)); - return chaser.PerformVoice(GetNativeCell(2), attackData.Name); + return chaser.PerformVoice(GetNativeCell(2), name); } static any Native_CreateBossSoundHint(Handle plugin, int numParams) @@ -736,12 +691,10 @@ static any Native_GetBossAttackIndexType(Handle plugin, int numParams) return 0; } - SF2ChaserBossProfileData data; - data = controller.GetProfileData(); - SF2ChaserBossProfileAttackData attackData; - data.GetAttackFromIndex(GetNativeCell(2), attackData); - - return attackData.Type; + ChaserBossProfile data = controller.GetProfileDataEx(); + char name[64]; + data.GetAttackName(GetNativeCell(2), name, sizeof(name)); + return data.GetAttack(name).Type; } static any Native_GetBossAttackIndexDamage(Handle plugin, int numParams) @@ -758,12 +711,10 @@ static any Native_GetBossAttackIndexDamage(Handle plugin, int numParams) return 0; } - SF2ChaserBossProfileData data; - data = controller.GetProfileData(); - SF2ChaserBossProfileAttackData attackData; - data.GetAttackFromIndex(GetNativeCell(2), attackData); - - return attackData.Damage[GetNativeCell(3)]; + ChaserBossProfile data = controller.GetProfileDataEx(); + char name[64]; + data.GetAttackName(GetNativeCell(2), name, sizeof(name)); + return data.GetAttack(name).GetDamage(GetNativeCell(3)); } static any Native_UpdateBossAnimation(Handle plugin, int numParams) @@ -842,12 +793,10 @@ static any Native_GetBossAttackIndexDamageType(Handle plugin, int numParams) return 0; } - SF2ChaserBossProfileData data; - data = controller.GetProfileData(); - SF2ChaserBossProfileAttackData attackData; - data.GetAttackFromIndex(GetNativeCell(2), attackData); - - return attackData.DamageType[1]; + ChaserBossProfile data = controller.GetProfileDataEx(); + char name[64]; + data.GetAttackName(GetNativeCell(2), name, sizeof(name)); + return data.GetAttack(name).GetDamageType(1); } static any Native_GetProfileData(Handle plugin, int numParams) @@ -858,24 +807,14 @@ static any Native_GetProfileData(Handle plugin, int numParams) return ThrowNativeError(SP_ERROR_NATIVE, "Invalid boss index %d", controller.Index); } - SF2ChaserBossProfileData data; - data = controller.GetProfileData(); - SetNativeArray(2, data, sizeof(data)); - return 0; + return controller.GetProfileDataEx(); } static any Native_GetProfileDataEx(Handle plugin, int numParams) { char profile[SF2_MAX_PROFILE_NAME_LENGTH]; GetNativeString(1, profile, sizeof(profile)); - SF2ChaserBossProfileData data; - if (!g_ChaserBossProfileData.GetArray(profile, data, sizeof(data))) - { - return false; - } - - SetNativeArray(2, data, sizeof(data)); - return true; + return view_as(GetBossProfile(profile)); } static any Native_SetForceChaseState(Handle plugin, int numParams) diff --git a/addons/sourcemod/scripting/sf2/npc/npc_creeper.sp b/addons/sourcemod/scripting/sf2/npc/npc_creeper.sp index 3aabc616..786cba5c 100644 --- a/addons/sourcemod/scripting/sf2/npc/npc_creeper.sp +++ b/addons/sourcemod/scripting/sf2/npc/npc_creeper.sp @@ -4,53 +4,29 @@ #define _sf2_npc_creeper_included #pragma semicolon 1 - -static float g_NpcStatueIdleLifetime[MAX_BOSSES][Difficulty_Max]; -static SF2StatueBossProfileData g_StatueProfileData[MAX_BOSSES]; - -SF2StatueBossProfileData NPCStatueGetProfileData(int npcIndex) -{ - return g_StatueProfileData[npcIndex]; -} - -void NPCStatueSetProfileData(int npcIndex, SF2StatueBossProfileData value) -{ - g_StatueProfileData[npcIndex] = value; -} - -float NPCStatueGetIdleLifetime(int npcIndex, int difficulty) -{ - return g_NpcStatueIdleLifetime[npcIndex][difficulty]; -} +#pragma newdecls required void NPCStatueOnSelectProfile(int npcIndex) { SF2NPC_Statue statue = SF2NPC_Statue(npcIndex); - char profile[SF2_MAX_PROFILE_NAME_LENGTH]; - NPCGetProfile(npcIndex, profile, sizeof(profile)); - g_StatueBossProfileData.GetArray(profile, g_StatueProfileData[npcIndex], sizeof(g_StatueProfileData[])); - for (int difficulty = 0; difficulty < Difficulty_Max; difficulty++) - { - g_NpcStatueIdleLifetime[npcIndex][difficulty] = g_StatueProfileData[npcIndex].IdleLifeTime[difficulty]; - } statue.SetAffectedBySight(true); } SF2_StatueEntity Spawn_Statue(SF2NPC_BaseNPC controller, const float pos[3], const float ang[3]) { - g_SlenderStatueIdleLifeTime[controller.Index] = GetGameTime() + g_NpcStatueIdleLifetime[controller.Index][controller.Difficulty]; + g_SlenderStatueIdleLifeTime[controller.Index] = GetGameTime() + view_as(controller).GetProfileDataEx().GetIdleLifeTime(controller.Difficulty); return SF2_StatueEntity.Create(controller, pos, ang); } void Despawn_Statue(SF2NPC_Statue controller, CBaseEntity bossEnt) { - SF2StatueBossProfileData data; - data = controller.GetProfileData(); + StatueBossProfile data = controller.GetProfileDataEx(); // Stop all possible looping sounds. - SF2BossProfileSoundInfo soundInfo; - soundInfo = data.MoveSounds; - soundInfo.StopAllSounds(bossEnt.index); + for (int i = 0; i < Difficulty_Max; i++) + { + data.GetMoveSounds().StopAllSounds(bossEnt.index, i); + } } void NPCStatue_InitializeAPI() @@ -69,22 +45,12 @@ static any Native_GetProfileData(Handle plugin, int numParams) return ThrowNativeError(SP_ERROR_NATIVE, "Invalid boss index %d", controller.Index); } - SF2StatueBossProfileData data; - data = controller.GetProfileData(); - SetNativeArray(2, data, sizeof(data)); - return 0; + return controller.GetProfileDataEx(); } static any Native_GetProfileDataEx(Handle plugin, int numParams) { char profile[SF2_MAX_PROFILE_NAME_LENGTH]; GetNativeString(1, profile, sizeof(profile)); - SF2StatueBossProfileData data; - if (!g_StatueBossProfileData.GetArray(profile, data, sizeof(data))) - { - return false; - } - - SetNativeArray(2, data, sizeof(data)); - return true; + return view_as(GetBossProfile(profile)); } diff --git a/addons/sourcemod/scripting/sf2/playergroups.sp b/addons/sourcemod/scripting/sf2/playergroups.sp index a95d07af..86506693 100644 --- a/addons/sourcemod/scripting/sf2/playergroups.sp +++ b/addons/sourcemod/scripting/sf2/playergroups.sp @@ -4,6 +4,7 @@ #define _sf2_playergroups_included #pragma semicolon 1 +#pragma newdecls required #define SF2_MAX_PLAYER_GROUPS MAXPLAYERS #define SF2_MAX_PLAYER_GROUP_NAME_LENGTH 32 diff --git a/addons/sourcemod/scripting/sf2/playergroups/menus.sp b/addons/sourcemod/scripting/sf2/playergroups/menus.sp index cf8705ed..57732f70 100644 --- a/addons/sourcemod/scripting/sf2/playergroups/menus.sp +++ b/addons/sourcemod/scripting/sf2/playergroups/menus.sp @@ -5,6 +5,7 @@ #define _sf2_playergroups_menus #pragma semicolon 1 +#pragma newdecls required void DisplayGroupMainMenuToClient(int client) { diff --git a/addons/sourcemod/scripting/sf2/profiles.sp b/addons/sourcemod/scripting/sf2/profiles.sp index a5538756..a8fda855 100644 --- a/addons/sourcemod/scripting/sf2/profiles.sp +++ b/addons/sourcemod/scripting/sf2/profiles.sp @@ -4,6 +4,7 @@ #define _sf2_profiles_included #pragma semicolon 1 +#pragma newdecls required #define FILE_PROFILES_DIR "configs/sf2/profiles" #define FILE_PROFILES_PACKS "configs/sf2/profiles_packs.cfg" @@ -43,6 +44,8 @@ static char mapBossPack[64]; GlobalForward g_OnBossProfileLoadedFwd; static GlobalForward g_OnBossProfileUnloadedFwd; +#include "profiles/keymap.sp" +#include "profiles/objects.sp" #include "profiles/profiles_boss_functions.sp" #include "profiles/profile_chaser.sp" #include "profiles/profile_statue.sp" @@ -62,11 +65,14 @@ void SetupBossProfileNatives() CreateNative("SF2_GetBossAttributeName", Native_GetBossAttributeName); CreateNative("SF2_GetBossAttributeValue", Native_GetBossAttributeValue); - CreateNative("SF2_GetBossProfileData", Native_GetBossProfileData); - CreateNative("SF2_GetChaserBossProfileData", Native_GetChaserBossProfileData); - CreateNative("SF2_GetStatueBossProfileData", Native_GetStatueBossProfileData); CreateNative("SF2_TranslateProfileActivityFromName", Native_TranslateProfileActivityFromName); CreateNative("SF2_LookupProfileAnimation", Native_LookupProfileAnimation); + + CreateNative("SF2_BaseBossProfile.Type.get", Native_GetType); + CreateNative("SF2_BaseBossProfile.IsPvEBoss.get", Native_GetIsPvEBoss); + + SetupProfileObjectNatives(); + ProfileChaser_InititalizeAPI(); } void InitializeBossProfiles() @@ -76,8 +82,8 @@ void InitializeBossProfiles() g_Activities = new StringMap(); - g_OnBossProfileLoadedFwd = new GlobalForward("SF2_OnBossProfileLoaded", ET_Ignore, Param_String, Param_Any); - g_OnBossProfileUnloadedFwd = new GlobalForward("SF2_OnBossProfileUnloaded", ET_Ignore, Param_String); + g_OnBossProfileLoadedFwd = new GlobalForward("SF2_OnBossProfileLoaded", ET_Ignore, Param_String, Param_Cell); + g_OnBossProfileUnloadedFwd = new GlobalForward("SF2_OnBossProfileUnloaded", ET_Ignore, Param_String, Param_Cell); AddProfileActivities(); @@ -89,9 +95,6 @@ void InitializeBossProfiles() g_BossPackVoteShuffleConVar = CreateConVar("sf2_boss_profile_pack_endvote_shuffle", "0", "Shuffles the menu options of boss pack endvotes if enabled."); g_MaxCorePackBosses = CreateConVar("sf2_max_core_pack_bosses", "-1", "Determines how many bosses can load randomly from the core pack, if set to less than 0 will keep this feature off. Note that companion bosses will still load if needed."); - - InitializeStatueProfiles(); - InitializeChaserProfiles(); } static void AddProfileActivities() @@ -261,6 +264,10 @@ Activity TranslateProfileActivityFromName(const char[] activityName) int LookupProfileAnimation(int entity, const char[] animName) { CBaseAnimating animator = CBaseAnimating(entity); + if (animName[0] == '\0') + { + return -1; + } int sequence = -1; Activity activity = TranslateProfileActivityFromName(animName); @@ -276,6 +283,11 @@ int LookupProfileAnimation(int entity, const char[] animName) return sequence; } +int GetMaxProfileDifficultySuffixSize() +{ + return 11; +} + void GetCurrentBossPack(char[] bossPackName, int length) { g_BossPackConfig.Rewind(); @@ -351,27 +363,15 @@ void BossProfilesOnMapEnd() ClearBossProfiles(); } -static void PreUnloadBossProfile(const char[] profile) +BaseBossProfile GetBossProfile(const char[] profile) { - SF2BossProfileData profileData; - g_BossProfileData.GetArray(profile, profileData, sizeof(profileData)); - - LogSF2Message("Unloading %s...", profile); - - int bossType = GetBossProfileType(profile); - switch (bossType) + BaseBossProfile data = null; + if (g_BossProfileData.GetValue(profile, data)) { - case SF2BossType_Statue: - { - UnloadStatueBossProfile(profile); - } - case SF2BossType_Chaser: - { - UnloadChaserBossProfile(profile); - } + return data; } - profileData.Destroy(); + return null; } void UnloadBossProfile(const char[] profile) @@ -381,12 +381,16 @@ void UnloadBossProfile(const char[] profile) return; } + LogSF2Message("Unloading %s...", profile); + + BaseBossProfile profileData; + g_BossProfileData.GetValue(profile, profileData); + Call_StartForward(g_OnBossProfileUnloadedFwd); Call_PushString(profile); + Call_PushCell(profileData); Call_Finish(); - PreUnloadBossProfile(profile); - int index = g_BossProfileList.FindString(profile); if (index != -1) { @@ -423,22 +427,16 @@ void UnloadBossProfile(const char[] profile) g_SelectableRenevantBossAdminProfileList.Erase(index); } - SF2BossProfileData data; - g_BossProfileData.GetArray(profile, data, sizeof(data)); - if (data.IsPvEBoss) + if (profileData.IsPvEBoss) { char setProfile[SF2_MAX_PROFILE_NAME_LENGTH]; strcopy(setProfile, sizeof(setProfile), profile); UnregisterPvESlenderBoss(setProfile); } - g_BossProfileData.Remove(profile); + CleanupKeyMap(profileData); - g_Config.Rewind(); - if (g_Config.JumpToKey(profile)) - { - g_Config.DeleteThis(); - } + g_BossProfileData.Remove(profile); } /** @@ -461,11 +459,8 @@ void ClearBossProfiles() continue; } - Call_StartForward(g_OnBossProfileUnloadedFwd); - Call_PushString(profile); - Call_Finish(); - - PreUnloadBossProfile(profile); + UnloadBossProfile(profile); + i--; } if (g_SelectableBossProfileList != null) @@ -723,11 +718,206 @@ static bool LoadProfileFile(const char[] profilePath, char[] profileName, int pr kv.GetSectionName(profileName, profileNameLen); - bool result = LoadBossProfile(kv, profileName, errorReason, errorReasonLen, lookIntoLoads, originalDir); + BaseBossProfile profileData = view_as(KeyValuesToKeyMap(kv)); delete kv; - return result; + char path[PLATFORM_MAX_PATH]; + + if (lookIntoLoads) + { + bool skip = true; + if (profileData.GetBool("enable_random_selection", true)) + { + skip = false; + } + + if (profileData.GetBool("admin_only", false)) + { + skip = false; + } + + if (profileData.GetBool("enable_random_selection_boxing", false)) + { + skip = false; + } + + if (profileData.GetBool("enable_random_selection_renevant", false)) + { + skip = false; + } + + if (profileData.GetBool("enable_random_selection_renevant_admin", false)) + { + skip = false; + } + + if (profileData.GetBool("is_pve", false) && profileData.GetBool("pve_selectable", true)) + { + skip = false; + } + + if (profileData.GetBool("always_load", false)) + { + skip = false; + } + + ProfileObject pve = profileData.GetSection("pve"); + if (pve != null && pve.GetBool("selectable", true)) + { + skip = false; + } + + if (skip) + { + FormatEx(errorReason, errorReasonLen, "is not selectable, skipping!"); + //DeleteCfg(parent); + return false; + } + } + + if (profileData.Type == SF2BossType_Unknown || profileData.Type >= SF2BossType_MaxTypes) + { + FormatEx(errorReason, errorReasonLen, "boss type is unknown!"); + return false; + } + + for (int i = 0; i < Difficulty_Max; i++) + { + profileData.GetModel(i, path, sizeof(path)); + if (path[0] == '\0') + { + FormatEx(errorReason, errorReasonLen, "model cannot be blank!"); + //DeleteCfg(parent); + return false; + } + } + + UnloadBossProfile(profileName); + + profileData.Precache(); + + g_BossProfileData.SetValue(profileName, profileData); + + int index = g_BossProfileList.FindString(profileName); + if (index == -1) + { + g_BossProfileList.PushString(profileName); + } + + bool blacklisted = false; + + if (profileData.GetBlacklistedMaps() != null) + { + char map[64], currentMap[64], key[64]; + GetCurrentMap(currentMap, sizeof(currentMap)); + for (int i = 0; i < profileData.GetBlacklistedMaps().Size; i++) + { + profileData.GetBlacklistedMaps().GetKeyNameFromIndex(i, key, sizeof(key)); + profileData.GetBlacklistedMaps().GetString(key, map, sizeof(map)); + + if (StrContains(currentMap, map, false) != -1) + { + blacklisted = true; + break; + } + } + } + + if (!blacklisted) + { + if (profileData.GetBool("enable_random_selection", true)) + { + if (GetSelectableBossProfileList().FindString(profileName) == -1) + { + // Add to the selectable boss list if it isn't there already. + GetSelectableBossProfileList().PushString(profileName); + } + } + else + { + int selectIndex = GetSelectableBossProfileList().FindString(profileName); + if (selectIndex != -1) + { + GetSelectableBossProfileList().Erase(selectIndex); + } + } + + if (profileData.GetBool("admin_only", false)) + { + if (GetSelectableAdminBossProfileList().FindString(profileName) == -1) + { + // Add to the selectable boss list if it isn't there already. + GetSelectableAdminBossProfileList().PushString(profileName); + } + } + else + { + int selectIndex = GetSelectableAdminBossProfileList().FindString(profileName); + if (selectIndex != -1) + { + GetSelectableAdminBossProfileList().Erase(selectIndex); + } + } + + if (profileData.GetBool("enable_random_selection_boxing", false)) + { + if (GetSelectableBoxingBossProfileList().FindString(profileName) == -1) + { + // Add to the selectable boss list if it isn't there already. + GetSelectableBoxingBossProfileList().PushString(profileName); + } + } + else + { + int selectIndex = GetSelectableBoxingBossProfileList().FindString(profileName); + if (selectIndex != -1) + { + GetSelectableBoxingBossProfileList().Erase(selectIndex); + } + } + + if (profileData.GetBool("enable_random_selection_renevant", false)) + { + if (GetSelectableRenevantBossProfileList().FindString(profileName) == -1) + { + // Add to the selectable boss list if it isn't there already. + GetSelectableRenevantBossProfileList().PushString(profileName); + } + } + else + { + int selectIndex = GetSelectableRenevantBossProfileList().FindString(profileName); + if (selectIndex != -1) + { + GetSelectableRenevantBossProfileList().Erase(selectIndex); + } + } + + if (profileData.GetBool("enable_random_selection_renevant_admin", false)) + { + if (GetSelectableRenevantBossAdminProfileList().FindString(profileName) == -1) + { + // Add to the selectable boss list if it isn't there already. + GetSelectableRenevantBossAdminProfileList().PushString(profileName); + } + } + else + { + int selectIndex = GetSelectableRenevantBossAdminProfileList().FindString(profileName); + if (selectIndex != -1) + { + GetSelectableRenevantBossAdminProfileList().Erase(selectIndex); + } + } + } + + Call_StartForward(g_OnBossProfileLoadedFwd); + Call_PushString(profileName); + Call_PushCell(profileData); + Call_Finish(); + + return true; } static void LoadProfilesFromDirectory(const char[] relDirPath, int maxLoadedBosses = -1) @@ -1416,21 +1606,6 @@ void RemoveBossProfileFromQueueList(const char[] profile) } } -static any Native_GetBossProfileData(Handle plugin,int numParams) -{ - return g_BossProfileData; -} - -static any Native_GetChaserBossProfileData(Handle plugin,int numParams) -{ - return g_ChaserBossProfileData; -} - -static any Native_GetStatueBossProfileData(Handle plugin,int numParams) -{ - return g_StatueBossProfileData; -} - static any Native_TranslateProfileActivityFromName(Handle plugin, int numParams) { char activityName[64]; @@ -1609,3 +1784,25 @@ static any Native_GetBossAttributeValue(Handle plugin,int numParams) } return NPCGetAttributeValue(GetNativeCell(1), attributeIndex); } + +static any Native_GetType(Handle plugin, int numParams) +{ + BaseBossProfile profileData = GetNativeCell(1); + if (profileData == null) + { + return ThrowNativeError(SP_ERROR_NATIVE, "Invalid profile object handle %x", profileData); + } + + return profileData.Type; +} + +static any Native_GetIsPvEBoss(Handle plugin, int numParams) +{ + BaseBossProfile profileData = GetNativeCell(1); + if (profileData == null) + { + return ThrowNativeError(SP_ERROR_NATIVE, "Invalid profile object handle %x", profileData); + } + + return profileData.IsPvEBoss; +} \ No newline at end of file diff --git a/addons/sourcemod/scripting/sf2/profiles/profile_chaser.sp b/addons/sourcemod/scripting/sf2/profiles/profile_chaser.sp index 9dfcb168..64daab30 100644 --- a/addons/sourcemod/scripting/sf2/profiles/profile_chaser.sp +++ b/addons/sourcemod/scripting/sf2/profiles/profile_chaser.sp @@ -5,65 +5,3064 @@ #define _sf2_profiles_chaser #pragma semicolon 1 +#pragma newdecls required -StringMap g_ChaserBossProfileData; +/*for (int i = 0; i < Difficulty_Max; i++) + { + this.Enabled[i] = false; + this.Cooldown[i] = 8.0; + this.Duration[i] = 10.0; + this.CloakRange[i] = 350.0; + this.DecloakRange[i] = 150.0; + } -#include "profile_chaser_precache.sp" + this.CloakRenderColor[0] = 0; + this.CloakRenderColor[1] = 0; + this.CloakRenderColor[2] = 0; + this.CloakRenderColor[3] = 0; + this.CloakRenderMode = 1; + this.CloakEffects = null; + this.DecloakEffects = null;*/ -void InitializeChaserProfiles() +methodmap ChaserBossProfile < BaseBossProfile { - g_ChaserBossProfileData = new StringMap(); + property bool ClearLayersOnAnimUpdate + { + public get() + { + return this.GetBool("animation_clear_layers_on_update", false); + } + } + + property bool BoxingBoss + { + public get() + { + return this.GetBool("boxing_boss", false); + } + } + + property bool ChasesEndlessly + { + public get() + { + return this.GetBool("boss_chases_endlessly", false); + } + } + + property bool NormalSoundHook + { + public get() + { + return this.GetBool("normal_sound_hook", false); + } + } + + property bool OldAnimationAI + { + public get() + { + return this.GetBool("old_animation_ai", false); + } + } + + public float GetWalkSpeed(int difficulty) + { + return this.GetDifficultyFloat("walkspeed", difficulty, 90.0); + } + + public float GetWakeRadius(int difficulty) + { + return this.GetDifficultyFloat("wake_radius", difficulty, 90.0); + } + + public float GetHearingRange(int difficulty) + { + float value = 1024.0; + value = this.GetDifficultyFloat("hearing_range", difficulty, value); + value = this.GetDifficultyFloat("search_sound_range", difficulty, value); + return value; + } + + public bool ShouldIgnoreHearingPathChecking(int difficulty) + { + return this.GetDifficultyBool("hearing_ignore_path_checking", difficulty, false); + } + + public bool CanWander(int difficulty) + { + return this.GetDifficultyBool("wander_move", difficulty, true); + } + + public float GetWanderMinRange(int difficulty) + { + return this.GetDifficultyFloat("wander_range_min", difficulty, 800.0); + } + + public float GetWanderMaxRange(int difficulty) + { + return this.GetDifficultyFloat("wander_range_max", difficulty, 1600.0); + } + + public float GetWanderMinTime(int difficulty) + { + return this.GetDifficultyFloat("wander_time_min", difficulty, 8.0); + } + + public float GetWanderMaxTime(int difficulty) + { + return this.GetDifficultyFloat("wander_time_max", difficulty, 12.0); + } + + public float GetWanderEnterMinTime(int difficulty) + { + return this.GetDifficultyFloat("wander_enter_time_min", difficulty, 2.0); + } + + public float GetWanderEnterMaxTime(int difficulty) + { + return this.GetDifficultyFloat("wander_enter_time_max", difficulty, 4.5); + } + + property float BackstabDamageScale + { + public get() + { + return this.GetFloat("backstab_damage_scale", 0.05); + } + } + + public ChaserBossProfileIdleData GetIdleBehavior() + { + return view_as(this.GetSection("idle")); + } + + public ChaserBossProfileAlertData GetAlertBehavior() + { + return view_as(this.GetSection("alert")); + } + + public ChaserBossProfileChaseData GetChaseBehavior() + { + return view_as(this.GetSection("chase")); + } + + public ChaserBossProfileStunData GetStunBehavior() + { + return view_as(this.GetSection("stun")); + } + + property bool Healthbar + { + public get() + { + return this.GetBool("healthbar", false); + } + } + + public ChaserBossProfileDeathData GetDeathBehavior() + { + return view_as(this.GetSection("death")); + } + + public int GetAttackCount() + { + KeyMap_Array arr = this.GetArray("__chaser_attack_names"); + if (arr == null) + { + return -1; + } + + return arr.Length; + } + + public void GetAttackName(int index, char[] buffer, int bufferSize) + { + KeyMap_Array arr = this.GetArray("__chaser_attack_names"); + if (arr == null) + { + return; + } + + arr.GetString(index, buffer, bufferSize); + } + + public int GetAttackIndex(const char[] attackName) + { + KeyMap_Array arr = this.GetArray("__chaser_attack_names"); + if (arr == null) + { + return -1; + } + + return arr.IndexOf(attackName); + } + + public ChaserBossProfileBaseAttack GetAttack(const char[] name) + { + ProfileObject obj = this.GetSection("attacks"); + if (obj == null) + { + return null; + } + + return view_as(obj.GetSection(name)); + } + + public ChaserBossProfileBaseAttack GetAttackFromIndex(int index) + { + char name[256]; + this.GetAttackName(index, name, sizeof(name)); + return this.GetAttack(name); + } + + public ProfileObject GetPosture(const char[] name) + { + ProfileObject obj = this.GetSection("postures"); + if (obj == null || strcmp(name, SF2_PROFILE_CHASER_DEFAULT_POSTURE) == 0) + { + return null; + } + + return obj.GetSection(name); + } + + public ProfileObject GetPostureFromIndex(int index) + { + ProfileObject obj = this.GetSection("postures"); + if (obj == null) + { + return null; + } + + char name[64]; + obj.GetSectionNameFromIndex(index, name, sizeof(name)); + if (strcmp(name, SF2_PROFILE_CHASER_DEFAULT_POSTURE) == 0) + { + return null; + } + + return obj.GetSection(name); + } + + public float GetPostureRunSpeed(const char[] name, int difficulty) + { + float value = this.GetRunSpeed(difficulty); + + ProfileObject obj = this.GetPosture(name); + if (obj != null) + { + value = obj.GetDifficultyFloat("speed", difficulty, value); + } + + return value; + } + + public float GetPostureWalkSpeed(const char[] name, int difficulty) + { + float value = this.GetWalkSpeed(difficulty); + + ProfileObject obj = this.GetPosture(name); + if (obj != null) + { + value = obj.GetDifficultyFloat("walkspeed", difficulty, value); + } + + return value; + } + + public float GetPostureAcceleration(const char[] name, int difficulty) + { + float value = this.GetAcceleration(difficulty); + + ProfileObject obj = this.GetPosture(name); + if (obj != null) + { + value = obj.GetDifficultyFloat("acceleration", difficulty, value); + } + + return value; + } + + public ProfileMasterAnimations GetPostureAnimations(const char[] name) + { + ProfileObject obj = this.GetPosture(name); + obj = obj != null ? obj.GetSection("animations") : null; + if (obj != null) + { + return view_as(obj); + } + + return null; + } + + public ChaserBossProfileSmellData GetSmellData() + { + ProfileObject obj = this.GetSection("senses"); + obj = obj != null ? obj.GetSection("smell") : null; + if (obj != null) + { + return view_as(obj); + } + + return null; + } + + public ChaserBossSoundSenseData GetSoundSenseData() + { + ProfileObject obj = this.GetSection("senses"); + obj = obj != null ? obj.GetSection("hearing") : null; + if (obj != null) + { + return view_as(obj); + } + + return null; + } + + public ProfileMusic GetIdleMusics() + { + return view_as(this.GetSection("sound_idle_music")); + } + + public ProfileMusic GetAlertMusics() + { + return view_as(this.GetSection("sound_alert_music")); + } + + public ProfileMusic GetChaseMusics() + { + return view_as(this.GetSection("sound_chase_music")); + } + + public ProfileMusic GetVisibleIdleMusics() + { + return view_as(this.GetSection("sound_idle_visible")); + } + + public ProfileMusic GetVisibleAlertMusics() + { + return view_as(this.GetSection("sound_alert_visible")); + } + + public ProfileMusic GetVisibleChaseMusics() + { + return view_as(this.GetSection("sound_chase_visible")); + } + + public bool HasTraps(int difficulty) + { + return this.GetDifficultyBool("traps_enabled", difficulty, false); + } + + public int GetTrapType(int difficulty) + { + return this.GetDifficultyInt("trap_type", difficulty, 0); + } + + public float GetTrapCooldown(int difficulty) + { + return this.GetDifficultyFloat("trap_spawn_cooldown", difficulty, 8.0); + } + + public void GetTrapModel(char[] buffer, int bufferSize) + { + this.GetString("trap_model", buffer, bufferSize, TRAP_MODEL); + } + + public void GetTrapDeploySound(char[] buffer, int bufferSize) + { + this.GetString("trap_deploy_sound", buffer, bufferSize, TRAP_DEPLOY); + } + + public void GetTrapMissSound(char[] buffer, int bufferSize) + { + this.GetString("trap_miss_sound", buffer, bufferSize, TRAP_CLOSE); + } + + public void GetTrapCatchSound(char[] buffer, int bufferSize) + { + this.GetString("trap_catch_sound", buffer, bufferSize, TRAP_CLOSE); + } + + public void GetTrapIdleAnimation(char[] buffer, int bufferSize) + { + this.GetString("trap_animation_idle", buffer, bufferSize, "trapopenend"); + } + + public void GetTrapClosedAnimation(char[] buffer, int bufferSize) + { + this.GetString("trap_animation_closed", buffer, bufferSize, "trapclosed"); + } + + public void GetTrapOpenAnimation(char[] buffer, int bufferSize) + { + this.GetString("trap_animation_open", buffer, bufferSize); + } + + property bool EarthquakeFootsteps + { + public get() + { + return this.GetBool("earthquake_footsteps", false); + } + } + + property float EarthquakeFootstepRadius + { + public get() + { + return this.GetFloat("earthquake_footsteps_radius", 1000.0); + } + } + + property float EarthquakeFootstepDuration + { + public get() + { + return this.GetFloat("earthquake_footsteps_duration", 1.0); + } + } + + property bool EarthquakeFootstepAirShake + { + public get() + { + return this.GetBool("earthquake_footsteps_airshake", false); + } + } + + property float EarthquakeFootstepAmplitude + { + public get() + { + return this.GetFloat("earthquake_footsteps_amplitude", 5.0); + } + } + + property float EarthquakeFootstepFrequency + { + public get() + { + return this.GetFloat("earthquake_footsteps_frequency", 25.0); + } + } + + public ProfileObject GetRages() + { + return this.GetSection("rages"); + } + + public ChaserBossAutoChaseData GetAutoChaseData() + { + return view_as(this.GetSection("autochase")); + } + + public ChaserBossChaseOnLookData GetChaseOnLookData() + { + return view_as(this.GetSection("chase_on_look")); + } + + public ChaserBossProfileCloakData GetCloakData() + { + return view_as(this.GetSection("cloaking")); + } + + public ProfileObject GetResistances() + { + return this.GetSection("resistances"); + } + + public ChaserBossProjectileData GetProjectiles() + { + return view_as(this); + } + + public ProfileSound GetIdleSounds() + { + return view_as(this.GetSection(g_SlenderVoiceList[SF2BossSound_Idle])); + } + + public ProfileSound GetAlertSounds() + { + return view_as(this.GetSection(g_SlenderVoiceList[SF2BossSound_Alert])); + } + + public ProfileSound GetChasingSounds() + { + return view_as(this.GetSection(g_SlenderVoiceList[SF2BossSound_Chasing])); + } + + public ProfileSound GetChaseInitialSounds() + { + return view_as(this.GetSection(g_SlenderVoiceList[SF2BossSound_ChaseInitial])); + } + + public ProfileSound GetStunSounds() + { + return view_as(this.GetSection(g_SlenderVoiceList[SF2BossSound_Stun])); + } + + public ProfileSound GetAttackKilledSounds() + { + return view_as(this.GetSection(g_SlenderVoiceList[SF2BossSound_AttackKilled])); + } + + public ProfileSound GetAttackKilledAllSounds() + { + return view_as(this.GetSection("sound_attack_killed_all")); + } + + public ProfileSound GetAttackKilledClientSounds() + { + return view_as(this.GetSection("sound_attack_killed_client")); + } + + public ProfileSound GetHurtSounds() + { + return view_as(this.GetSection("sound_hurt")); + } + + public ProfileSound GetDeathSounds() + { + return view_as(this.GetSection(g_SlenderVoiceList[SF2BossSound_Death])); + } + + public ProfileSound GetTauntKillSounds() + { + return view_as(this.GetSection(g_SlenderVoiceList[SF2BossSound_TauntKill])); + } + + public ProfileSound GetSmellSounds() + { + return view_as(this.GetSection(g_SlenderVoiceList[SF2BossSound_Smell])); + } + + public ProfileSound GetSelfHealSounds() + { + return view_as(this.GetSection(g_SlenderVoiceList[SF2BossSound_SelfHeal])); + } + + public ProfileSound GetRageAllSounds() + { + return view_as(this.GetSection(g_SlenderVoiceList[SF2BossSound_RageAll])); + } + + public ProfileSound GetRageTwoSounds() + { + return view_as(this.GetSection(g_SlenderVoiceList[SF2BossSound_RageTwo])); + } + + public ProfileSound GetRageThreeSounds() + { + return view_as(this.GetSection(g_SlenderVoiceList[SF2BossSound_RageThree])); + } + + public ProfileSound GetDespawnSounds() + { + return view_as(this.GetSection(g_SlenderVoiceList[SF2BossSound_Despawn])); + } + + public ProfileSound GetFootstepSounds() + { + return view_as(this.GetSection("sound_footsteps")); + } + + public ProfileObject GetAttackSounds() + { + return this.GetSection(g_SlenderVoiceList[SF2BossSound_Attack]); + } + + public ProfileObject GetAttackBeginSounds() + { + return this.GetSection(g_SlenderVoiceList[SF2BossSound_AttackBegin]); + } + + public ProfileObject GetAttackLoopSounds() + { + return this.GetSection("sound_attack_loop"); + } + + public ProfileObject GetAttackEndSounds() + { + return this.GetSection(g_SlenderVoiceList[SF2BossSound_AttackEnd]); + } + + public ProfileObject GetHitSounds() + { + return this.GetSection("sound_hitenemy"); + } + + public ProfileObject GetMissSounds() + { + return this.GetSection("sound_missenemy"); + } + + public ProfileObject GetBulletShootSounds() + { + return this.GetSection("sound_bulletshoot"); + } + + public ProfileObject GetProjectileShootSounds() + { + return this.GetSection("sound_attackshootprojectile"); + } + + public void Precache() + { + // ======================== + // LEGACY KEY CONVERSION + // ======================== + ProfileObject newObj = this.GetIdleBehavior(); + ArrayList keys = new ArrayList(ByteCountToCells(256)); + newObj = this.InsertNewSection("idle"); + + keys.PushString("alert_gracetime"); + keys.PushString("alert_duration"); + keys.PushString("search_alert_gracetime"); + keys.PushString("search_alert_duration"); + if (this.ContainsAnyDifficultyKey(keys)) + { + newObj = this.InsertNewSection("alert"); + for (int i = 0; i < Difficulty_Max; i++) + { + float def = 0.5; + if (this.ContainsDifficultyKey("alert_gracetime", i) || this.ContainsDifficultyKey("search_alert_gracetime", i)) + { + def = this.GetDifficultyFloat("alert_gracetime", i, def); + def = this.GetDifficultyFloat("search_alert_gracetime", i, def); + newObj.SetDifficultyFloat("gracetime", i, def); + } + + def = 10.0; + if (this.ContainsDifficultyKey("alert_duration", i) || this.ContainsDifficultyKey("search_alert_duration", i)) + { + def = this.GetDifficultyFloat("alert_duration", i, def); + def = this.GetDifficultyFloat("search_alert_duration", i, def); + newObj.SetDifficultyFloat("duration", i, def); + } + } + } + + keys.Clear(); + ProfileObject temp = null, temp2 = null; + keys.PushString("chase_duration"); + keys.PushString("search_chase_duration"); + keys.PushString("chase_duration_add_max_range"); + keys.PushString("chase_duration_add_visible_min"); + keys.PushString("chase_duration_add_visible_max"); + if (this.ContainsAnyDifficultyKey(keys)) + { + newObj = this.InsertNewSection("chase"); + temp = newObj.InsertNewSection("duration"); + temp2 = temp.InsertNewSection("add"); + for (int i = 0; i < Difficulty_Max; i++) + { + float def = 10.0; + if (this.ContainsDifficultyKey("chase_duration", i) || this.ContainsDifficultyKey("search_chase_duration", i)) + { + def = this.GetDifficultyFloat("chase_duration", i, def); + def = this.GetDifficultyFloat("search_chase_duration", i, def); + temp.SetDifficultyFloat("max", i, def); + } + + if (this.ContainsDifficultyKey("chase_duration_add_max_range", i)) + { + temp2.SetDifficultyFloat("target_range", i, this.GetDifficultyFloat("chase_duration_add_max_range", i, this.GetSearchRange(i))); + } + + if (this.ContainsDifficultyKey("chase_duration_add_visible_min", i)) + { + temp2.SetDifficultyFloat("visible_target_near", i, this.GetDifficultyFloat("chase_duration_add_visible_min", i, 0.01)); + } + + if (this.ContainsDifficultyKey("chase_duration_add_visible_max", i)) + { + temp2.SetDifficultyFloat("visible_target_far", i, this.GetDifficultyFloat("chase_duration_add_visible_max", i, 0.05)); + } + } + } + + keys.Clear(); + keys.PushString("stun_enabled"); + keys.PushString("stun_health"); + keys.PushString("stun_cooldown"); + keys.PushString("disappear_on_stun"); + keys.PushString("stun_damage_flashlight_enabled"); + keys.PushString("stun_damage_flashlight"); + keys.PushString("chase_initial_on_stun"); + keys.PushString("drop_item_on_stun"); + keys.PushString("drop_item_type"); + if (this.ContainsAnyDifficultyKey(keys)) + { + newObj = this.InsertNewSection("stun"); + bool defBool = false; + char defString[PLATFORM_MAX_PATH]; + for (int i = 0; i < Difficulty_Max; i++) + { + if (this.ContainsDifficultyKey("stun_enabled", i)) + { + newObj.SetDifficultyBool("enabled", i, this.GetDifficultyBool("stun_enabled", i, false)); + } + + if (this.ContainsDifficultyKey("stun_health", i)) + { + newObj.SetDifficultyFloat("health", i, this.GetDifficultyFloat("stun_health", i, 50.0)); + } + + if (this.ContainsDifficultyKey("stun_cooldown", i)) + { + newObj.SetDifficultyFloat("cooldown", i, this.GetDifficultyFloat("stun_cooldown", i, 3.5)); + } + + if (this.ContainsDifficultyKey("disappear_on_stun", i)) + { + newObj.SetDifficultyBool("disappear", i, this.GetDifficultyBool("disappear_on_stun", i, false)); + } + + defBool = this.GetDifficultyBool("stun_damage_flashlight_enabled", i, false); + if (defBool) + { + temp = newObj.InsertNewSection("flashlight_stun"); + temp.SetDifficultyBool("enabled", i, defBool); + + if (this.ContainsDifficultyKey("stun_damage_flashlight", i)) + { + temp.SetDifficultyFloat("damage", i, this.GetDifficultyFloat("stun_damage_flashlight", i, 0.0)); + } + } + + if (this.ContainsDifficultyKey("chase_initial_on_stun", i)) + { + newObj.SetDifficultyBool("chase_initial_on_end", i, this.GetDifficultyBool("chase_initial_on_stun", i, false)); + } + + if (this.ContainsDifficultyKey("drop_item_on_stun", i)) + { + newObj.SetDifficultyBool("item_drop", i, this.GetDifficultyBool("drop_item_on_stun", i, false)); + } + + if (this.ContainsDifficultyKey("drop_item_type", i)) + { + newObj.SetDifficultyInt("item_drop_type", i, this.GetDifficultyInt("drop_item_type", i, 1)); + } + + keys.Clear(); + keys.PushString("stun_health_per_player"); + keys.PushString("stun_health_per_scout"); + keys.PushString("stun_health_per_soldier"); + keys.PushString("stun_health_per_pyro"); + keys.PushString("stun_health_per_demoman"); + keys.PushString("stun_health_per_heavyweapons"); + keys.PushString("stun_health_per_engineer"); + keys.PushString("stun_health_per_medic"); + keys.PushString("stun_health_per_sniper"); + keys.PushString("stun_health_per_spy"); + if (this.ContainsAnyDifficultyKey(keys, i)) + { + temp = newObj.InsertNewSection("add_health"); + if (this.ContainsDifficultyKey("stun_health_per_player", i)) + { + temp.SetDifficultyFloat("player", i, this.GetDifficultyFloat("stun_health_per_player", i, 0.0)); + } + + if (this.ContainsDifficultyKey("stun_health_per_scout", i)) + { + temp.SetDifficultyFloat("scout", i, this.GetDifficultyFloat("stun_health_per_scout", i, 0.0)); + } + + if (this.ContainsDifficultyKey("stun_health_per_soldier", i)) + { + temp.SetDifficultyFloat("soldier", i, this.GetDifficultyFloat("stun_health_per_soldier", i, 0.0)); + } + + if (this.ContainsDifficultyKey("stun_health_per_pyro", i)) + { + temp.SetDifficultyFloat("pyro", i, this.GetDifficultyFloat("stun_health_per_pyro", i, 0.0)); + } + + if (this.ContainsDifficultyKey("stun_health_per_demoman", i)) + { + temp.SetDifficultyFloat("demoman", i, this.GetDifficultyFloat("stun_health_per_demoman", i, 0.0)); + } + + if (this.ContainsDifficultyKey("stun_health_per_heavyweapons", i)) + { + temp.SetDifficultyFloat("heavy", i, this.GetDifficultyFloat("stun_health_per_heavyweapons", i, 0.0)); + } + + if (this.ContainsDifficultyKey("stun_health_per_engineer", i)) + { + temp.SetDifficultyFloat("engineer", i, this.GetDifficultyFloat("stun_health_per_engineer", i, 0.0)); + } + + if (this.ContainsDifficultyKey("stun_health_per_medic", i)) + { + temp.SetDifficultyFloat("medic", i, this.GetDifficultyFloat("stun_health_per_medic", i, 0.0)); + } + + if (this.ContainsDifficultyKey("stun_health_per_sniper", i)) + { + temp.SetDifficultyFloat("sniper", i, this.GetDifficultyFloat("stun_health_per_sniper", i, 0.0)); + } + + if (this.ContainsDifficultyKey("stun_health_per_spy", i)) + { + temp.SetDifficultyFloat("spy", i, this.GetDifficultyFloat("stun_health_per_spy", i, 0.0)); + } + } + } + + keys.Clear(); + keys.PushString("keydrop_enabled"); + keys.PushString("key_model"); + keys.PushString("key_trigger"); + if (this.ContainsAnyKey(keys)) + { + if (this.ContainsKey("keydrop_enabled")) + { + newObj.SetBool("key_drop", this.GetBool("keydrop_enabled", false)); + } + + defString = SF_KEYMODEL; + if (this.ContainsKey("key_model")) + { + this.GetString("key_model", defString, sizeof(defString), defString); + newObj.SetString("key_model", defString); + } + + defString = ""; + if (this.ContainsKey("key_trigger")) + { + this.GetString("key_trigger", defString, sizeof(defString), defString); + newObj.SetString("key_trigger", defString); + } + } + } + + keys.Clear(); + keys.PushString("chase_upon_look"); + keys.PushString("auto_chase_upon_look"); + if (this.ContainsAnyDifficultyKey(keys)) + { + newObj = this.GetChaseOnLookData(); + if (newObj == null) + { + newObj = this.InsertNewSection("chase_on_look"); + + for (int i = 0; i < Difficulty_Max; i++) + { + bool def = false; + def = this.GetDifficultyBool("chase_upon_look", i, def); + def = this.GetDifficultyBool("auto_chase_upon_look", i, def); + newObj.SetDifficultyBool("enabled", i, def); + } + } + } + + keys.Clear(); + keys.PushString("auto_chase_enabled"); + keys.PushString("auto_chase_sound_threshold"); + keys.PushString("auto_chase_cooldown_after_chase"); + keys.PushString("auto_chase_sprinters"); + if (this.ContainsAnyDifficultyKey(keys)) + { + newObj = this.InsertNewSection("autochase"); + int defInt = 0; + + keys.Clear(); + keys.PushString("auto_chase_sound_add"); + keys.PushString("auto_chase_sound_add_footsteps"); + keys.PushString("auto_chase_sound_add_footsteps_loud"); + keys.PushString("auto_chase_sound_add_footsteps_quiet"); + keys.PushString("auto_chase_sound_add_voice"); + keys.PushString("auto_chase_sound_add_weapon"); + + for (int i = 0; i < Difficulty_Max; i++) + { + if (this.ContainsDifficultyKey("auto_chase_enabled", i)) + { + newObj.SetDifficultyBool("enabled", i, this.GetDifficultyBool("auto_chase_enabled", i, false)); + } + + if (this.ContainsDifficultyKey("auto_chase_sound_threshold", i)) + { + newObj.SetDifficultyInt("threshold", i, this.GetDifficultyInt("auto_chase_sound_threshold", i, 100)); + } + + if (this.ContainsDifficultyKey("auto_chase_cooldown_after_chase", i)) + { + newObj.SetDifficultyFloat("cooldown_after_chase", i, this.GetDifficultyFloat("auto_chase_cooldown_after_chase", i, 3.0)); + } + + if (this.ContainsDifficultyKey("auto_chase_sprinters", i)) + { + newObj.SetDifficultyBool("sprinters", i, this.GetDifficultyBool("auto_chase_sprinters", i, false)); + } + + if (this.ContainsAnyDifficultyKey(keys, i)) + { + temp = newObj.InsertNewSection("add"); + + if (this.ContainsDifficultyKey("auto_chase_sound_add", i)) + { + temp.SetDifficultyInt("on_state_change", i, this.GetDifficultyInt("auto_chase_sound_add", i, 0)); + } + + if (this.ContainsDifficultyKey("auto_chase_sound_add_footsteps", i)) + { + temp.SetDifficultyInt("footsteps", i, this.GetDifficultyInt("auto_chase_sound_add_footsteps", i, 2)); + } + + defInt = temp.GetDifficultyInt("footsteps", i); + if (this.ContainsDifficultyKey("auto_chase_sound_add_footsteps_loud", i)) + { + defInt = this.GetDifficultyInt("auto_chase_sound_add_footsteps_loud", i, defInt); + temp.SetDifficultyInt("footsteps_loud", i, defInt); + } + + defInt = temp.GetDifficultyInt("footsteps", i); + if (this.ContainsDifficultyKey("auto_chase_sound_add_footsteps_quiet", i)) + { + defInt = this.GetDifficultyInt("auto_chase_sound_add_footsteps_quiet", i, defInt); + temp.SetDifficultyInt("footsteps_quiet", i, defInt); + } + + if (this.ContainsDifficultyKey("auto_chase_sound_add_voice", i)) + { + temp.SetDifficultyInt("voice", i, this.GetDifficultyInt("auto_chase_sound_add_voice", i, 8)); + } + + if (this.ContainsDifficultyKey("auto_chase_sound_add_weapon", i)) + { + temp.SetDifficultyInt("weapon", i, this.GetDifficultyInt("auto_chase_sound_add_weapon", i, 8)); + } + } + } + } + + if (this.GetBool("cloak_enable", false)) + { + newObj = this.InsertNewSection("cloaking"); + + float multipliers[Difficulty_Max] = {1.0, 1.0, 1.0, 1.0, 1.0, 1.0}; + bool addPosture = false; + for (int i = 0; i < Difficulty_Max; i++) + { + newObj.SetDifficultyBool("enabled", i, true); + if (this.ContainsDifficultyKey("cloak_cooldown", i)) + { + newObj.SetDifficultyFloat("cooldown", i, this.GetDifficultyFloat("cloak_cooldown", i, 10.0)); + } + if (this.ContainsDifficultyKey("cloak_range", i)) + { + newObj.SetDifficultyFloat("cloak_range", i, this.GetDifficultyFloat("cloak_range", i, 350.0)); + } + if (this.ContainsDifficultyKey("cloak_decloak_range", i)) + { + newObj.SetDifficultyFloat("decloak_range", i, this.GetDifficultyFloat("cloak_decloak_range", i, 150.0)); + } + if (this.ContainsDifficultyKey("cloak_decloak_range", i)) + { + newObj.SetDifficultyFloat("duration", i, this.GetDifficultyFloat("cloak_duration", i, 8.0)); + } + multipliers[i] = this.GetDifficultyFloat("cloak_speed_multiplier", i, multipliers[i]); + if (multipliers[i] != 1.0) + { + addPosture = true; + } + } + + int color[4]; + if (this.ContainsKey("cloak_rendercolor")) + { + this.GetColor("cloak_rendercolor", color, { 0, 0, 0, 0 }); + newObj.SetColor("color", color); + } + + if (this.ContainsKey("cloak_rendermode")) + { + newObj.SetInt("rendermode", this.GetInt("cloak_rendermode", view_as(RENDER_TRANSCOLOR))); + } + + char particle[128], sound[PLATFORM_MAX_PATH]; + temp = newObj.InsertNewSection("effects"); + ProfileEffectMaster effectSection = view_as(temp.InsertNewSection("cloak")); + + this.GetString("cloak_particle", particle, sizeof(particle), "drg_cow_explosioncore_charged_blue"); + this.GetString("cloak_on_sound", sound, sizeof(sound), "weapons/medi_shield_deploy.wav"); + ProfileEffect effect = view_as(effectSection.InsertNewSection("Legacy Cloak Particle")); + effect.SetString("type", "particle"); + effect.SetFloat("lifetime", 0.1); + effect.SetVector("origin", { 0.0, 0.0, 35.0 }); + effect.SetString("particlename", particle); + + effect = view_as(effectSection.InsertNewSection("Legacy Cloak Sound")); + effect.SetString("type", "sound"); + temp = effect.InsertNewSection("paths"); + temp.SetString("1", sound); + + this.GetString("cloak_off_sound", sound, sizeof(sound), "weapons/medi_shield_retract.wav"); + temp = newObj.GetSection("effects"); + effectSection = view_as(temp.InsertNewSection("decloak")); + + effect = view_as(effectSection.InsertNewSection("Legacy Cloak Particle")); + effect.SetString("type", "particle"); + effect.SetFloat("lifetime", 0.1); + effect.SetVector("origin", { 0.0, 0.0, 35.0 }); + effect.SetString("particlename", particle); + + effect = view_as(effectSection.InsertNewSection("Legacy Cloak Sound")); + effect.SetString("type", "sound"); + temp = effect.InsertNewSection("paths"); + temp.SetString("1", sound); + + if (addPosture) + { + temp = this.InsertNewSection("postures"); + temp2 = temp.InsertNewSection("Legacy Cloak"); + + for (int i = 0; i < Difficulty_Max; i++) + { + temp2.SetDifficultyFloat("speed", i, this.GetRunSpeed(i) * multipliers[i]); + temp2.SetDifficultyFloat("walkspeed", i, this.GetWalkSpeed(i) * multipliers[i]); + temp2.SetDifficultyFloat("acceleration", i, this.GetAcceleration(i) * multipliers[i]); + } + + temp = temp2.InsertNewSection("conditions"); + temp2 = temp.InsertNewSection("on_cloak"); + + for (int i = 0; i < Difficulty_Max; i++) + { + temp2.SetDifficultyBool("enabled", i, true); + } + } + } + + if (this.GetSection("attacks") != null) + { + if (this.GetAttackSounds() != null) + { + ProfileObject obj = this.GetAttackSounds().GetSection("paths"); + if (obj != null) + { + for (int i = 0; i < this.GetAttackCount(); i++) + { + ChaserBossProfileBaseAttack attack = this.GetAttackFromIndex(i); + } + } + else + { + if (this.GetAttackSounds().SectionLength > 0) + { + + } + else + { + + } + } + } + } + + if (this.GetProjectiles() != null) + { + this.GetProjectiles().Precache(); + } + + if (this.GetIdleSounds() != null) + { + if (this.NormalSoundHook) + { + this.GetIdleSounds().SetDefaultChannel(SNDCHAN_VOICE); + } + this.GetIdleSounds().Precache(); + } + + if (this.GetAlertSounds() != null) + { + if (this.NormalSoundHook) + { + this.GetAlertSounds().SetDefaultChannel(SNDCHAN_VOICE); + } + this.GetAlertSounds().Precache(); + } + + if (this.GetChasingSounds() != null) + { + if (this.NormalSoundHook) + { + this.GetChasingSounds().SetDefaultChannel(SNDCHAN_VOICE); + } + this.GetChasingSounds().Precache(); + } + + if (this.GetChaseInitialSounds() != null) + { + if (this.NormalSoundHook) + { + this.GetChaseInitialSounds().SetDefaultChannel(SNDCHAN_VOICE); + } + this.GetChaseInitialSounds().Precache(); + } + + if (this.GetStunSounds() != null) + { + if (this.NormalSoundHook) + { + this.GetStunSounds().SetDefaultChannel(SNDCHAN_VOICE); + } + this.GetStunSounds().Precache(); + } + + if (this.GetHurtSounds() != null) + { + if (this.NormalSoundHook) + { + this.GetHurtSounds().SetDefaultChannel(SNDCHAN_VOICE); + } + this.GetHurtSounds().Precache(); + } + + if (this.GetDeathSounds() != null) + { + if (this.NormalSoundHook) + { + this.GetDeathSounds().SetDefaultChannel(SNDCHAN_VOICE); + } + this.GetDeathSounds().Precache(); + } + + if (this.GetTauntKillSounds() != null) + { + if (this.NormalSoundHook) + { + this.GetTauntKillSounds().SetDefaultChannel(SNDCHAN_VOICE); + } + this.GetTauntKillSounds().Precache(); + } + + if (this.GetAttackKilledSounds() != null) + { + this.GetAttackKilledSounds().Precache(); + } + + if (this.GetAttackKilledAllSounds() != null) + { + this.GetAttackKilledAllSounds().Precache(); + } + + if (this.GetAttackKilledClientSounds() != null) + { + this.GetAttackKilledClientSounds().Precache(); + } + + if (this.GetSmellSounds() != null) + { + if (this.NormalSoundHook) + { + this.GetSmellSounds().SetDefaultChannel(SNDCHAN_VOICE); + } + this.GetSmellSounds().Precache(); + } + + if (this.GetSelfHealSounds() != null) + { + if (this.NormalSoundHook) + { + this.GetSelfHealSounds().SetDefaultChannel(SNDCHAN_VOICE); + } + this.GetSelfHealSounds().Precache(); + } + + if (this.GetRageAllSounds() != null) + { + if (this.NormalSoundHook) + { + this.GetRageAllSounds().SetDefaultChannel(SNDCHAN_VOICE); + } + this.GetRageAllSounds().Precache(); + } + + if (this.GetRageTwoSounds() != null) + { + if (this.NormalSoundHook) + { + this.GetRageTwoSounds().SetDefaultChannel(SNDCHAN_VOICE); + } + this.GetRageTwoSounds().Precache(); + } + + if (this.GetRageThreeSounds() != null) + { + if (this.NormalSoundHook) + { + this.GetRageThreeSounds().SetDefaultChannel(SNDCHAN_VOICE); + } + this.GetRageThreeSounds().Precache(); + } + + if (this.GetDespawnSounds() != null) + { + this.GetDespawnSounds().Precache(); + } + + if (this.GetFootstepSounds() != null) + { + this.GetFootstepSounds().Precache(); + } + + if (this.GetIdleMusics() != null) + { + this.GetIdleMusics().Precache(); + } + + if (this.GetAlertMusics() != null) + { + this.GetAlertMusics().Precache(); + } + + if (this.GetChaseMusics() != null) + { + this.GetChaseMusics().Precache(); + } + + if (this.GetVisibleIdleMusics() != null) + { + this.GetVisibleIdleMusics().Precache(); + } + + if (this.GetVisibleAlertMusics() != null) + { + this.GetVisibleAlertMusics().Precache(); + } + + if (this.GetVisibleChaseMusics() != null) + { + this.GetVisibleChaseMusics().Precache(); + } + + if (this.GetCloakData() != null) + { + this.GetCloakData().Precache(); + } + + if (this.GetStunBehavior() != null) + { + this.GetStunBehavior().Precache(); + } + + if (this.GetDeathBehavior() != null) + { + this.GetDeathBehavior().Precache(); + } + + this.PrecacheAttackSounds(this.GetAttackSounds(), "attack", this.NormalSoundHook); + + this.PrecacheAttackSounds(this.GetHitSounds(), "hitenemy", false); + + this.PrecacheAttackSounds(this.GetMissSounds(), "missenemy", false); + + this.PrecacheAttackSounds(this.GetAttackBeginSounds(), "attack_begin", this.NormalSoundHook); + + this.PrecacheAttackSounds(this.GetAttackLoopSounds(), "attack_loop", false); + + this.PrecacheAttackSounds(this.GetAttackEndSounds(), "attack_end", this.NormalSoundHook); + + this.PrecacheAttackSounds(this.GetBulletShootSounds(), "bulletshoot", false); + + this.PrecacheAttackSounds(this.GetProjectileShootSounds(), "attackshootprojectile", false); + + ProfileObject obj = this.GetSection("attacks"); + if (obj != null) + { + KeyMap_Array attackNames = new KeyMap_Array(Key_Type_Value); + this.SetSection("__chaser_attack_names", attackNames); + this.SetType("__chaser_attack_names", Key_Type_Section); + attackNames.Parent = this; + + for (int i = 0; i < obj.SectionLength; i++) + { + char name[64]; + obj.GetSectionNameFromIndex(i, name, sizeof(name)); + + ChaserBossProfileBaseAttack attack = view_as(obj.GetSection(name)); + if (attack != null) + { + attackNames.PushString(name); + attack.Precache(); + } + } + } + + if (this.OldAnimationAI && this.GetAnimations() != null && !this.GetAnimations().IsLegacy) + { + for (int i = 0; i < this.GetAnimations().SectionLength; i++) + { + char key[64]; + this.GetAnimations().GetSectionNameFromIndex(i, key, sizeof(key)); + obj = this.GetAnimations().GetSection(key); + if (obj != null && strcmp(key, g_SlenderAnimationsList[SF2BossAnimation_Walk]) == 0 || strcmp(key, g_SlenderAnimationsList[SF2BossAnimation_Run]) == 0) + { + for (int i2 = 0; i2 < obj.SectionLength; i2++) + { + obj.GetSectionNameFromIndex(i2, key, sizeof(key)); + ProfileAnimation animObj = view_as(obj.GetSection(key)); + if (animObj != null) + { + for (int i3 = 0; i3 < Difficulty_Max; i3++) + { + animObj.SetDifficultyBool("ground_sync", i3, true); + } + } + } + } + } + } + } + + public void PrecacheAttackSounds(ProfileObject base, char[] section, bool hook = false) + { + if (base == null) + { + return; + } + + if (hook) + { + view_as(base).SetDefaultChannel(SNDCHAN_VOICE); + } + + bool sections = false; + if (base.GetSection("paths") != null) + { + view_as(base).Precache(); + } + else + { + for (int i = 0; i < base.SectionLength; i++) + { + char key[64]; + base.GetSectionNameFromIndex(i, key, sizeof(key)); + if (base.GetSection(key) != null) + { + sections = true; + break; + } + } + + if (!sections) + { + view_as(base).Precache(); + } + else + { + char formatter[64]; + FormatEx(formatter, sizeof(formatter), "__chaser_%s_sounds", section); + KeyMap_Array sounds = new KeyMap_Array(Key_Type_Value); + this.SetSection(formatter, sounds); + this.SetType(formatter, Key_Type_Section); + sounds.Parent = this; + + for (int i = 0; i < base.SectionLength; i++) + { + char key[64]; + base.GetSectionNameFromIndex(i, key, sizeof(key)); + ProfileObject obj = base.GetSection(key); + if (obj != null) + { + sounds.PushString(key); + if (hook) + { + view_as(obj).SetDefaultChannel(SNDCHAN_VOICE); + } + view_as(obj).Precache(); + } + } + } + } + } +} + +methodmap ChaserBossProfileIdleData < ProfileObject +{ + public bool IsTurnEnabled(int difficulty) + { + ProfileObject obj = this.GetSection("turn"); + if (obj == null) + { + return true; + } + + return obj.GetDifficultyBool("enabled", difficulty, true); + } + + public float GetTurnAngle(int difficulty) + { + float def = 360.0; + ProfileObject obj = this.GetSection("turn"); + if (obj == null) + { + return def; + } + + return obj.GetDifficultyFloat("angle", difficulty, def); + } + + public float GetTurnMinCooldown(int difficulty) + { + float def = 1.5; + ProfileObject obj = this.GetSection("turn"); + if (obj == null) + { + return def; + } + + return obj.GetDifficultyFloat("cooldown_min", difficulty, def); + } + + public float GetTurnMaxCooldown(int difficulty) + { + float def = 3.0; + ProfileObject obj = this.GetSection("turn"); + if (obj == null) + { + return def; + } + + return obj.GetDifficultyFloat("cooldown_max", difficulty, def); + } +} + +methodmap ChaserBossProfileAlertData < ProfileObject +{ + public float GetGraceTime(int difficulty) + { + return this.GetDifficultyFloat("gracetime", difficulty, 0.5); + } + + public float GetDuration(int difficulty) + { + return this.GetDifficultyFloat("duration", difficulty, 10.0); + } + + public bool ShouldRunOnWander(int difficulty) + { + return this.GetDifficultyBool("run_on_wander", difficulty, false); + } + + public bool ShouldRunOnSuspect(int difficulty) + { + return this.GetDifficultyBool("run_on_suspect", difficulty, false); + } + + public bool IsTurnEnabled(int difficulty) + { + ProfileObject obj = this.GetSection("turn"); + if (obj == null) + { + return true; + } + + return obj.GetDifficultyBool("enabled", difficulty, true); + } + + public float GetTurnAngle(int difficulty) + { + float def = 360.0; + ProfileObject obj = this.GetSection("turn"); + if (obj == null) + { + return def; + } + + return obj.GetDifficultyFloat("angle", difficulty, def); + } + + public float GetTurnMinCooldown(int difficulty) + { + float def = 1.5; + ProfileObject obj = this.GetSection("turn"); + if (obj == null) + { + return def; + } + + return obj.GetDifficultyFloat("cooldown_min", difficulty, def); + } + + public float GetTurnMaxCooldown(int difficulty) + { + float def = 3.0; + ProfileObject obj = this.GetSection("turn"); + if (obj == null) + { + return def; + } + + return obj.GetDifficultyFloat("cooldown_max", difficulty, def); + } + + public ChaserBossAlertOnStateData GetAlertSyncData() + { + return view_as(this.GetSection("sync")); + } +} + +methodmap ChaserBossProfileChaseData < ProfileObject +{ + public float GetMaxChaseDuration(int difficulty) + { + float def = 10.0; + ProfileObject obj = this.GetSection("duration"); + if (obj != null) + { + def = obj.GetDifficultyFloat("max", difficulty, def); + } + return def; + } + + public float GetDurationTargetRange(int difficulty) + { + float def = 1024.0; + if (this == null) + { + return def; + } + def = view_as(this.Parent).GetSearchRange(difficulty); + ProfileObject obj = this.GetSection("duration"); + obj = obj != null ? obj.GetSection("add") : null; + if (obj != null) + { + def = obj.GetDifficultyFloat("target_range", difficulty, def); + } + return def; + } + + public float GetDurationAddVisibleTargetNear(int difficulty) + { + float def = 0.01; + ProfileObject obj = this.GetSection("duration"); + obj = obj != null ? obj.GetSection("add") : null; + if (obj != null) + { + def = obj.GetDifficultyFloat("visible_target_near", difficulty, def); + } + return def; + } + + public float GetDurationAddVisibleTargetFar(int difficulty) + { + float def = 0.05; + ProfileObject obj = this.GetSection("duration"); + obj = obj != null ? obj.GetSection("add") : null; + if (obj != null) + { + def = obj.GetDifficultyFloat("visible_target_far", difficulty, def); + } + return def; + } + + public float GetDurationAddOnAttack(int difficulty) + { + float def = 0.0; + ProfileObject obj = this.GetSection("duration"); + obj = obj != null ? obj.GetSection("add") : null; + if (obj != null) + { + def = obj.GetDifficultyFloat("attack", difficulty, def); + } + return def; + } + + public float GetDurationAddOnStunned(int difficulty) + { + float def = 0.0; + ProfileObject obj = this.GetSection("duration"); + obj = obj != null ? obj.GetSection("add") : null; + if (obj != null) + { + def = obj.GetDifficultyFloat("stunned", difficulty, def); + } + return def; + } + + public ChaserBossAlertOnStateData GetChaseTogetherData() + { + return view_as(this.GetSection("chase_together")); + } +} + +methodmap ChaserBossProfileStunData < ProfileObject +{ + public bool IsEnabled(int difficulty) + { + bool def = false; + if (this == null) + { + return def; + } + return this.GetDifficultyBool("enabled", difficulty, def); + } + + public float GetHealth(int difficulty) + { + float def = 50.0; + if (this == null) + { + return def; + } + return this.GetDifficultyFloat("health", difficulty, def); + } + + public float GetCooldown(int difficulty) + { + return this.GetDifficultyFloat("cooldown", difficulty, 3.5); + } + + public bool ShouldDisappear(int difficulty) + { + return this.GetDifficultyBool("disappear", difficulty, false); + } + + public bool CanFlashlightStun(int difficulty) + { + bool def = false; + ProfileObject obj = this.GetSection("flashlight_stun"); + if (obj != null) + { + def = obj.GetDifficultyBool("enabled", difficulty, def); + } + return def; + } + + public float GetFlashlightDamage(int difficulty) + { + float def = 0.0; + ProfileObject obj = this.GetSection("flashlight_stun"); + if (obj != null) + { + def = obj.GetDifficultyFloat("damage", difficulty, def); + } + return def; + } + + public bool CanChaseInitialOnEnd(int difficulty) + { + return this.GetDifficultyBool("chase_initial_on_end", difficulty, false); + } + + property bool KeyDrop + { + public get() + { + return this.GetBool("key_drop", false); + } + } + + public void GetKeyModel(char[] buffer, int bufferSize) + { + this.GetString("key_model", buffer, bufferSize, SF_KEYMODEL); + } + + public void GetKeyTrigger(char[] buffer, int bufferSize) + { + this.GetString("key_trigger", buffer, bufferSize); + } + + public bool CanDropItem(int difficulty) + { + return this.GetDifficultyBool("item_drop", difficulty, false); + } + + public int GetItemDropType(int difficulty) + { + return this.GetDifficultyInt("item_drop_type", difficulty, 1); + } + + public float GetAddHealthPerClass(int difficulty, TFClassType class) + { + float def = 0.0; + ProfileObject obj = this.GetSection("add_health"); + if (obj != null) + { + switch (class) + { + case TFClass_Scout: + { + def = obj.GetDifficultyFloat("scout", difficulty, def); + } + + case TFClass_Soldier: + { + def = obj.GetDifficultyFloat("soldier", difficulty, def); + } + + case TFClass_Pyro: + { + def = obj.GetDifficultyFloat("pyro", difficulty, def); + } + + case TFClass_DemoMan: + { + def = obj.GetDifficultyFloat("demoman", difficulty, def); + } + + case TFClass_Heavy: + { + def = obj.GetDifficultyFloat("heavy", difficulty, def); + } + + case TFClass_Engineer: + { + def = obj.GetDifficultyFloat("engineer", difficulty, def); + } + + case TFClass_Medic: + { + def = obj.GetDifficultyFloat("medic", difficulty, def); + } + + case TFClass_Sniper: + { + def = obj.GetDifficultyFloat("sniper", difficulty, def); + } + + case TFClass_Spy: + { + def = obj.GetDifficultyFloat("spy", difficulty, def); + } + } + } + return def; + } + + public float GetAddHealthPerPlayer(int difficulty) + { + float def = 0.0; + ProfileObject obj = this.GetSection("add_health"); + if (obj != null) + { + def = obj.GetDifficultyFloat("player", difficulty, def); + } + return def; + } + + public float GetAddHealthPerStun(int difficulty) + { + float def = 0.0; + ProfileObject obj = this.GetSection("add_health"); + if (obj != null) + { + def = obj.GetDifficultyFloat("on_stun", difficulty, def); + } + return def; + } + + public float GetAddRunSpeed(int difficulty) + { + return this.GetDifficultyFloat("add_speed", difficulty, 0.0); + } + + public float GetAddAcceleration(int difficulty) + { + return this.GetDifficultyFloat("add_acceleration", difficulty, 0.0); + } + + public ProfileEffectMaster GetOnStartEffects() + { + ProfileObject obj = this.GetSection("effects"); + obj = obj != null ? obj.GetSection("on_start") : null; + if (obj != null) + { + return view_as(obj); + } + + return null; + } + + public ProfileEffectMaster GetOnEndEffects() + { + ProfileObject obj = this.GetSection("effects"); + obj = obj != null ? obj.GetSection("on_end") : null; + if (obj != null) + { + return view_as(obj); + } + + return null; + } + + public void Precache() + { + if (this.GetOnStartEffects() != null) + { + this.GetOnStartEffects().Precache(); + } + + if (this.GetOnEndEffects() != null) + { + this.GetOnEndEffects().Precache(); + } + } +} + +methodmap ChaserBossProfileDeathData < ProfileObject +{ + public bool IsEnabled(int difficulty) + { + bool def = false; + if (this == null) + { + return def; + } + return this.GetDifficultyBool("enabled", difficulty, def); + } + + public float GetHealth(int difficulty) + { + float def = 400.0; + if (this == null) + { + return def; + } + return this.GetDifficultyFloat("health", difficulty, def); + } + + property bool RemoveOnDeath + { + public get() + { + return this.GetBool("remove", false); + } + } + + property bool DisappearOnDeath + { + public get() + { + return this.GetBool("disappear", false); + } + } + + property bool RagdollOnDeath + { + public get() + { + return this.GetBool("become_ragdoll", false); + } + } + + property bool KeyDrop + { + public get() + { + return this.GetBool("key_drop", false); + } + } + + public void GetKeyModel(char[] buffer, int bufferSize) + { + this.GetString("key_model", buffer, bufferSize, SF_KEYMODEL); + } + + public void GetKeyTrigger(char[] buffer, int bufferSize) + { + this.GetString("key_trigger", buffer, bufferSize); + } + + public bool CanDropItem(int difficulty) + { + return this.GetDifficultyBool("item_drop", difficulty, false); + } + + public int GetItemDropType(int difficulty) + { + return this.GetDifficultyInt("item_drop_type", difficulty, 1); + } + + public float GetAddHealthPerClass(int difficulty, TFClassType class) + { + float def = 0.0; + ProfileObject obj = this.GetSection("add_health"); + if (obj != null) + { + switch (class) + { + case TFClass_Scout: + { + def = obj.GetDifficultyFloat("scout", difficulty, def); + } + + case TFClass_Soldier: + { + def = obj.GetDifficultyFloat("soldier", difficulty, def); + } + + case TFClass_Pyro: + { + def = obj.GetDifficultyFloat("pyro", difficulty, def); + } + + case TFClass_DemoMan: + { + def = obj.GetDifficultyFloat("demoman", difficulty, def); + } + + case TFClass_Heavy: + { + def = obj.GetDifficultyFloat("heavy", difficulty, def); + } + + case TFClass_Engineer: + { + def = obj.GetDifficultyFloat("engineer", difficulty, def); + } + + case TFClass_Medic: + { + def = obj.GetDifficultyFloat("medic", difficulty, def); + } + + case TFClass_Sniper: + { + def = obj.GetDifficultyFloat("sniper", difficulty, def); + } + + case TFClass_Spy: + { + def = obj.GetDifficultyFloat("spy", difficulty, def); + } + } + } + return def; + } + + public float GetAddHealthPerPlayer(int difficulty) + { + float def = 0.0; + ProfileObject obj = this.GetSection("add_health"); + if (obj != null) + { + def = obj.GetDifficultyFloat("player", difficulty, def); + } + return def; + } + + public float GetAddHealthPerDeath(int difficulty) + { + float def = 0.0; + ProfileObject obj = this.GetSection("add_health"); + if (obj != null) + { + def = obj.GetDifficultyFloat("on_death", difficulty, def); + } + return def; + } + + public float GetAddRunSpeed(int difficulty) + { + return this.GetDifficultyFloat("add_speed", difficulty, 0.0); + } + + public float GetAddAcceleration(int difficulty) + { + return this.GetDifficultyFloat("add_acceleration", difficulty, 0.0); + } + + property int GibSkin + { + public get() + { + int def = 0; + ProfileObject obj = this.GetGibs(); + if (obj != null) + { + obj.GetInt("skin", def); + } + return def; + } + } + + public ProfileObject GetGibs() + { + return this.GetSection("gibs"); + } + + public ProfileEffectMaster GetOnStartEffects() + { + ProfileObject obj = this.GetSection("effects"); + obj = obj != null ? obj.GetSection("on_start") : null; + if (obj != null) + { + return view_as(obj); + } + + return null; + } + + public ProfileEffectMaster GetOnEndEffects() + { + ProfileObject obj = this.GetSection("effects"); + obj = obj != null ? obj.GetSection("on_end") : null; + if (obj != null) + { + return view_as(obj); + } + + return null; + } + + public void Precache() + { + if (this.GetOnStartEffects() != null) + { + this.GetOnStartEffects().Precache(); + } + + if (this.GetOnEndEffects() != null) + { + this.GetOnEndEffects().Precache(); + } + } +} + +methodmap ChaserBossProfileRageData < ProfileObject +{ + property float PercentageThreshold + { + public get() + { + return this.GetFloat("health_percent", 0.75); + } + } + + property bool IncreaseDifficulty + { + public get() + { + return this.GetBool("increase_difficulty", true); + } + } + + property bool Invincible + { + public get() + { + return this.GetBool("invincible", false); + } + } + + property bool IsHealing + { + public get() + { + return this.GetSection("heal") != null; + } + } + + property bool HealCloak + { + public get() + { + bool def = false; + ProfileObject obj = this.GetSection("heal"); + if (obj != null) + { + def = obj.GetBool("cloak", def); + } + return def; + } + } + + property float FleeMinRange + { + public get() + { + float def = 512.0; + ProfileObject obj = this.GetSection("heal"); + if (obj != null) + { + def = obj.GetFloat("flee_range_min", def); + } + return def; + } + } + + property float FleeMaxRange + { + public get() + { + float def = 1024.0; + ProfileObject obj = this.GetSection("heal"); + if (obj != null) + { + def = obj.GetFloat("flee_range_max", def); + } + return def; + } + } + + property float HealAmount + { + public get() + { + float def = 0.5; + ProfileObject obj = this.GetSection("heal"); + if (obj != null) + { + def = obj.GetFloat("amount", def); + } + return def; + } + } + + property float HealDelay + { + public get() + { + float def = 0.0; + ProfileObject obj = this.GetSection("heal"); + if (obj != null) + { + def = obj.GetFloat("delay", def); + } + return def; + } + } + + property float HealDuration + { + public get() + { + float def = 1.0; + ProfileObject obj = this.GetSection("heal"); + if (obj != null) + { + def = obj.GetFloat("duration", def); + } + return def; + } + } + + public ProfileSound GetStartSounds() + { + ProfileSound def = null; + ProfileObject obj = this.GetSection("sounds"); + if (obj != null) + { + def = view_as(obj.GetSection("start")); + } + return def; + } + + public ProfileSound GetHealSounds() + { + ProfileSound def = null; + ProfileObject obj = this.GetSection("sounds"); + if (obj != null) + { + def = view_as(obj.GetSection("healing")); + } + return def; + } + + public ProfileMasterAnimations GetAnimations() + { + return view_as(this.GetSection("animations")); + } + + public void Precache() + { + + } +} + +methodmap ChaserBossProfileCloakData < ProfileObject +{ + public bool IsEnabled(int difficulty) + { + if (this == null) + { + return false; + } + return this.GetDifficultyBool("enabled", false); + } + + public float GetDuration(int difficulty) + { + return this.GetDifficultyFloat("duration", difficulty, 8.0); + } + + public float GetCooldown(int difficulty) + { + return this.GetDifficultyFloat("cooldown", difficulty, 10.0); + } + + public float GetCloakRange(int difficulty) + { + return this.GetDifficultyFloat("cloak_range", difficulty, 350.0); + } + + public float GetDecloakRange(int difficulty) + { + return this.GetDifficultyFloat("decloak_range", difficulty, 150.0); + } + + public void GetRenderColor(int buffer[4]) + { + this.GetColor("color", buffer, { 0, 0, 0, 0 }); + } + + public RenderMode GetRenderMode(int difficulty) + { + return view_as(this.GetDifficultyInt("rendermode", difficulty, view_as(RENDER_TRANSCOLOR))); + } + + public RenderFx GetRenderFx(int difficulty) + { + return view_as(this.GetDifficultyInt("renderfx", difficulty, view_as(RENDERFX_NONE))); + } + + public ProfileEffectMaster GetCloakEffects() + { + ProfileObject obj = this.GetSection("effects"); + obj = obj != null ? obj.GetSection("cloak") : null; + if (obj != null) + { + return view_as(obj); + } + + return null; + } + + public ProfileEffectMaster GetDecloakEffects() + { + ProfileObject obj = this.GetSection("effects"); + obj = obj != null ? obj.GetSection("decloak") : null; + if (obj != null) + { + return view_as(obj); + } + + return null; + } + + public void Precache() + { + if (this.GetCloakEffects() != null) + { + this.GetCloakEffects().Precache(); + } + + if (this.GetDecloakEffects() != null) + { + this.GetDecloakEffects().Precache(); + } + } +} + +methodmap ChaserBossProfileSmellData < ProfileObject +{ + public bool IsEnabled(int difficulty) + { + if (this == null) + { + return false; + } + return this.GetDifficultyBool("enabled", false); + } + + public float GetMinCooldown(int difficulty) + { + return this.GetDifficultyFloat("cooldown_min", difficulty, 6.0); + } + + public float GetMaxCooldown(int difficulty) + { + return this.GetDifficultyFloat("cooldown_max", difficulty, 12.0); + } + + public float GetMinCooldownAfterState(int difficulty) + { + return this.GetDifficultyFloat("cooldown_after_state_min", difficulty, 16.0); + } + + public float GetMaxCooldownAfterState(int difficulty) + { + return this.GetDifficultyFloat("cooldown_after_state_min", difficulty, 24.0); + } + + public int GetRequiredPlayers(int difficulty) + { + return this.GetDifficultyInt("required_players", difficulty, 1); + } + + public float GetRequiredPlayerRange(int difficulty) + { + return this.GetDifficultyFloat("required_player_range", difficulty, 1000.0); + } + + public float GetSmellRange(int difficulty) + { + return this.GetDifficultyFloat("smelling_range", difficulty, 1500.0); + } + + public bool GetShouldChaseState(int difficulty) + { + return this.GetDifficultyBool("should_chase_upon_smelled", false); + } } -void UnloadChaserBossProfile(const char[] profile) -{ - SF2ChaserBossProfileData chaserProfileData; - if (!g_ChaserBossProfileData.GetArray(profile, chaserProfileData, sizeof(chaserProfileData))) +methodmap ChaserBossSoundSenseData < ProfileObject +{ + public int GetThreshold(int difficulty) + { + int def = 8; + if (this == null) + { + return def; + } + return this.GetDifficultyInt("threshold", difficulty, def); + } + + public float GetDiscardTime(int difficulty) + { + float def = 2.0; + if (this == null) + { + return def; + } + return this.GetDifficultyFloat("discard_time", difficulty, def); + } + + public float GetDistanceTolerance(int difficulty) + { + float def = 512.0; + if (this == null) + { + return def; + } + return this.GetDifficultyFloat("distance_tolerance", difficulty, def); + } + + public float GetFootstepCooldown(int difficulty) + { + float def = 0.0; + if (this == null) + { + return def; + } + ProfileObject obj = this.GetSection("cooldown"); + if (obj == null) + { + return def; + } + return this.GetDifficultyFloat("footstep", difficulty, def); + } + + public float GetLoudFootstepCooldown(int difficulty) + { + float def = 0.0; + if (this == null) + { + return def; + } + ProfileObject obj = this.GetSection("cooldown"); + if (obj == null) + { + return def; + } + return this.GetDifficultyFloat("footstep_loud", difficulty, def); + } + + public float GetQuietFootstepCooldown(int difficulty) + { + float def = 0.0; + if (this == null) + { + return def; + } + ProfileObject obj = this.GetSection("cooldown"); + if (obj == null) + { + return def; + } + return this.GetDifficultyFloat("footstep_quiet", difficulty, def); + } + + public float GetVoiceCooldown(int difficulty) + { + float def = 0.0; + if (this == null) + { + return def; + } + ProfileObject obj = this.GetSection("cooldown"); + if (obj == null) + { + return def; + } + return this.GetDifficultyFloat("voice", difficulty, def); + } + + public float GetWeaponCooldown(int difficulty) + { + float def = 0.0; + if (this == null) + { + return def; + } + ProfileObject obj = this.GetSection("cooldown"); + if (obj == null) + { + return def; + } + return this.GetDifficultyFloat("weapon", difficulty, def); + } + + public float GetFlashlightCooldown(int difficulty) + { + float def = 0.0; + if (this == null) + { + return def; + } + ProfileObject obj = this.GetSection("cooldown"); + if (obj == null) + { + return def; + } + return this.GetDifficultyFloat("flashlight", difficulty, def); + } + + public int GetFootstepAdd(int difficulty) + { + int def = 1; + if (this == null) + { + return def; + } + ProfileObject obj = this.GetSection("add"); + if (obj == null) + { + return def; + } + return this.GetDifficultyInt("footstep", difficulty, def); + } + + public int GetLoudFootstepAdd(int difficulty) { - return; + int def = 2; + if (this == null) + { + return def; + } + ProfileObject obj = this.GetSection("add"); + if (obj == null) + { + return def; + } + return this.GetDifficultyInt("footstep_loud", difficulty, def); } - chaserProfileData.Destroy(); + public int GetQuietFootstepAdd(int difficulty) + { + int def = 0; + if (this == null) + { + return def; + } + ProfileObject obj = this.GetSection("add"); + if (obj == null) + { + return def; + } + return this.GetDifficultyInt("footstep_quiet", difficulty, def); + } - g_ChaserBossProfileData.Remove(profile); -} + public int GetVoiceAdd(int difficulty) + { + int def = 10; + if (this == null) + { + return def; + } + ProfileObject obj = this.GetSection("add"); + if (obj == null) + { + return def; + } + return this.GetDifficultyInt("voice", difficulty, def); + } + + public int GetWeaponAdd(int difficulty) + { + int def = 5; + if (this == null) + { + return def; + } + ProfileObject obj = this.GetSection("add"); + if (obj == null) + { + return def; + } + return this.GetDifficultyInt("weapon", difficulty, def); + } -static SF2ChaserBossProfileData g_CachedProfileData; + public int GetFlashlightAdd(int difficulty) + { + int def = 5; + if (this == null) + { + return def; + } + ProfileObject obj = this.GetSection("add"); + if (obj == null) + { + return def; + } + return this.GetDifficultyInt("flashlight", difficulty, def); + } +} -float GetChaserProfileDeathHealth(const char[] profile, int difficulty) +methodmap ChaserBossPostureCondition < ProfileObject { - g_ChaserBossProfileData.GetArray(profile, g_CachedProfileData, sizeof(g_CachedProfileData)); - return g_CachedProfileData.DeathData.Health[difficulty]; + public bool GetEnabled(int difficulty) + { + if (this == null) + { + return false; + } + return this.GetDifficultyBool("enabled", difficulty, true); + } } -bool GetChaserProfileBoxingState(const char[] profile) +methodmap ChaserBossChaseOnLookData < ProfileObject { - g_ChaserBossProfileData.GetArray(profile, g_CachedProfileData, sizeof(g_CachedProfileData)); - return g_CachedProfileData.BoxingBoss; + public bool IsEnabled(int difficulty) + { + if (this == null) + { + return false; + } + return this.GetDifficultyBool("enabled", difficulty, false); + } + + public bool ShouldAddTargets(int difficulty) + { + return this.GetDifficultyBool("add_targets", difficulty, true); + } + + public void GetRequiredLookPosition(float buffer[3]) + { + this.GetVector("look_position", buffer, { 0.0, 0.0, 35.0 }); + } + + public float GetMinXAngle(int difficulty) + { + return this.GetDifficultyFloat("minimum_x_angle", difficulty, -45.0); + } + + public float GetMaxXAngle(int difficulty) + { + return this.GetDifficultyFloat("maximum_x_angle", difficulty, 180.0); + } + + public float GetMinYAngle(int difficulty) + { + return this.GetDifficultyFloat("minimum_y_angle", difficulty, 0.0); + } + + public float GetMaxYAngle(int difficulty) + { + return this.GetDifficultyFloat("maximum_y_angle", difficulty, 105.0); + } + + public float GetRequiredFOV(int difficulty) + { + return this.GetDifficultyFloat("required_fov", difficulty, -1.0); + } } -void GetChaserProfileChaseMusics(const char[] profile, SF2BossProfileSoundInfo params) +methodmap ChaserBossAutoChaseData < ProfileObject { - g_ChaserBossProfileData.GetArray(profile, g_CachedProfileData, sizeof(g_CachedProfileData)); - params = g_CachedProfileData.ChaseMusics; + public bool IsEnabled(int difficulty) + { + return this.GetDifficultyBool("enabled", difficulty, false); + } + + public int GetThreshold(int difficulty) + { + return this.GetDifficultyInt("threshold", difficulty, 100); + } + + public float GetCooldownAfterChase(int difficulty) + { + return this.GetDifficultyFloat("cooldown_after_chase", difficulty, 3.0); + } + + public bool ShouldChaseSprinters(int difficulty) + { + return this.GetDifficultyBool("sprinters", difficulty, false); + } + + public int GetAddOnStateChange(int difficulty) + { + int def = 0; + ProfileObject obj = this.GetSection("add"); + if (obj != null) + { + def = obj.GetDifficultyInt("on_state_change", difficulty, def); + } + return def; + } + + public int GetAddFootsteps(int difficulty) + { + int def = 2; + ProfileObject obj = this.GetSection("add"); + if (obj != null) + { + def = obj.GetDifficultyInt("footsteps", difficulty, def); + } + return def; + } + + public int GetAddLoudFootsteps(int difficulty) + { + int def = this.GetAddFootsteps(difficulty); + ProfileObject obj = this.GetSection("add"); + if (obj != null) + { + def = obj.GetDifficultyInt("footsteps_loud", difficulty, def); + } + return def; + } + + public int GetAddQuietFootsteps(int difficulty) + { + int def = this.GetAddFootsteps(difficulty); + ProfileObject obj = this.GetSection("add"); + if (obj != null) + { + def = obj.GetDifficultyInt("footsteps_quiet", difficulty, def); + } + return def; + } + + public int GetAddVoice(int difficulty) + { + int def = 8; + ProfileObject obj = this.GetSection("add"); + if (obj != null) + { + def = obj.GetDifficultyInt("voice", difficulty, def); + } + return def; + } + + public int GetAddWeapon(int difficulty) + { + int def = 8; + ProfileObject obj = this.GetSection("add"); + if (obj != null) + { + def = obj.GetDifficultyInt("weapon", difficulty, def); + } + return def; + } } -void GetChaserProfileChaseVisibleMusics(const char[] profile, SF2BossProfileSoundInfo params) +methodmap ChaserBossAlertOnStateData < ProfileObject { - g_ChaserBossProfileData.GetArray(profile, g_CachedProfileData, sizeof(g_CachedProfileData)); - params = g_CachedProfileData.ChaseVisibleMusics; + public bool IsEnabled(int difficulty) + { + if (this == null) + { + return false; + } + + return this.GetDifficultyBool("enabled", difficulty, false); + } + + public bool ShouldStartOnStateChange(int difficulty) + { + bool def = true; + if (this == null) + { + return def; + } + + return this.GetDifficultyBool("on_change_state", difficulty, true); + } + + public float GetRadius(int difficulty) + { + float def = 1024.0; + if (this == null) + { + return def; + } + + return this.GetDifficultyFloat("radius", difficulty, def); + } + + public bool ShouldBeVisible(int difficulty) + { + bool def = false; + if (this == null) + { + return def; + } + + return this.GetDifficultyBool("should_be_visible", difficulty, def); + } + + public bool ShouldFollow(int difficulty) + { + bool def = false; + if (this == null) + { + return def; + } + + return this.GetDifficultyBool("follow_leader", difficulty, def); + } + + public float GetFollowCooldown(int difficulty) + { + float def = 10.0; + if (this == null) + { + return def; + } + + return this.GetDifficultyFloat("follow_cooldown", difficulty, def); + } + + public bool GetCopies(int difficulty) + { + bool def = false; + if (this == null) + { + return def; + } + + return this.GetDifficultyBool("copies", difficulty, def); + } + + public bool GetCompanions(int difficulty) + { + bool def = false; + if (this == null) + { + return def; + } + + return this.GetDifficultyBool("companions", difficulty, def); + } } -void GetChaserProfileAlertMusics(const char[] profile, SF2BossProfileSoundInfo params) +methodmap ChaserBossResistanceData < ProfileObject { - g_ChaserBossProfileData.GetArray(profile, g_CachedProfileData, sizeof(g_CachedProfileData)); - params = g_CachedProfileData.AlertMusics; + public bool IsEnabled(int difficulty) + { + if (this == null) + { + return false; + } + return this.GetDifficultyBool("enabled", difficulty, true); + } + + public float GetMultiplier(int difficulty) + { + return this.GetDifficultyFloat("multiplier", difficulty, 1.0); + } + + public ProfileObject GetDamageTypes() + { + return this.GetSection("damage_type"); + } + + public ProfileObject GetHitboxes() + { + return this.GetSection("hitbox"); + } + + public ProfileObject GetWeapons() + { + return this.GetSection("weapon"); + } } -void GetChaserProfileIdleMusics(const char[] profile, SF2BossProfileSoundInfo params) +methodmap ChaserBossProjectileData < ProfileObject { - g_ChaserBossProfileData.GetArray(profile, g_CachedProfileData, sizeof(g_CachedProfileData)); - params = g_CachedProfileData.IdleMusics; + public bool IsEnabled(int difficulty) + { + return this.GetDifficultyBool("projectile_enable", difficulty, false); + } + + public float GetMinCooldown(int difficulty) + { + return this.GetDifficultyFloat("projectile_cooldown_min", difficulty, 1.0); + } + + public float GetMaxCooldown(int difficulty) + { + return this.GetDifficultyFloat("projectile_cooldown_max", difficulty, 2.0); + } + + public float GetSpeed(int difficulty) + { + return this.GetDifficultyFloat("projectile_speed", difficulty, 1100.0); + } + + public float GetDamage(int difficulty) + { + return this.GetDifficultyFloat("projectile_damage", difficulty, 50.0); + } + + public float GetRadius(int difficulty) + { + return this.GetDifficultyFloat("projectile_damageradius", difficulty, 128.0); + } + + public float GetDeviation(int difficulty) + { + return this.GetDifficultyFloat("projectile_deviation", difficulty, 0.0); + } + + public int GetCount(int difficulty) + { + return this.GetDifficultyInt("projectile_count", difficulty, 1); + } + + property int Type + { + public get() + { + return this.GetInt("projectile_type", SF2BossProjectileType_Fireball); + } + } + + public bool GetCritState(int difficulty) + { + return this.GetDifficultyBool("enable_crit_rockets", difficulty, false); + } + + public void GetShootGesture(char[] buffer, int bufferSize) + { + this.GetString("gesture_shootprojectile", buffer, bufferSize); + } + + property bool ProjectileClips + { + public get() + { + return this.GetBool("projectile_clips_enable", false); + } + } + + public int GetClipSize(int difficulty) + { + return this.GetDifficultyInt("projectile_ammo_loaded", difficulty, 3); + } + + public float GetReloadTime(int difficulty) + { + return this.GetDifficultyFloat("projectile_reload_time", difficulty, 2.0); + } + + property int MinRandomPos + { + public get() + { + return this.GetInt("projectile_pos_number_min", 1); + } + } + + property int MaxRandomPos + { + public get() + { + return this.GetInt("projectile_pos_number_max", 1); + } + } + + public void GetOffset(int index, float buffer[3]) + { + if (index == 1) + { + this.GetVector("projectile_pos_offset", buffer, buffer); + this.GetVector("projectile_pos_offset_1", buffer, buffer); + return; + } + char key[64]; + FormatEx(key, sizeof(key), "projectile_pos_offset_%i", index); + this.GetVector(key, buffer); + } + + public void GetFireballExplodeSound(char[] buffer, int bufferSize) + { + this.GetString("fire_explode_sound", buffer, bufferSize, FIREBALL_IMPACT); + } + + public void GetFireballShootSound(char[] buffer, int bufferSize) + { + this.GetString("fire_shoot_sound", buffer, bufferSize, FIREBALL_SHOOT); + } + + public void GetFireballTrail(char[] buffer, int bufferSize) + { + this.GetString("fire_trail", buffer, bufferSize, FIREBALL_TRAIL); + } + + public void GetRocketTrail(char[] buffer, int bufferSize) + { + this.GetString("rocket_trail_particle", buffer, bufferSize, ROCKET_TRAIL); + } + + public void GetRocketExplodeParticle(char[] buffer, int bufferSize) + { + this.GetString("rocket_explode_particle", buffer, bufferSize, ROCKET_EXPLODE_PARTICLE); + } + + public void GetRocketExplodeSound(char[] buffer, int bufferSize) + { + this.GetString("rocket_explode_sound", buffer, bufferSize, ROCKET_IMPACT); + } + + public void GetRocketShootSound(char[] buffer, int bufferSize) + { + this.GetString("rocket_shoot_sound", buffer, bufferSize, ROCKET_SHOOT); + } + + public void GetRocketModel(char[] buffer, int bufferSize) + { + this.GetString("rocket_model", buffer, bufferSize, ROCKET_MODEL); + } + + public float GetIceballSlowDuration(int difficulty) + { + return this.GetDifficultyFloat("projectile_iceslow_duration", difficulty, 2.0); + } + + public float GetIceballSlowPercent(int difficulty) + { + return this.GetDifficultyFloat("projectile_iceslow_percent", difficulty, 0.55); + } + + public void GetIceballSlowSound(char[] buffer, int bufferSize) + { + this.GetString("fire_iceball_slow_sound", buffer, bufferSize, ICEBALL_IMPACT); + } + + public void GetIceballTrail(char[] buffer, int bufferSize) + { + this.GetString("fire_iceball_slow_sound", buffer, bufferSize, ICEBALL_TRAIL); + } + + public void GetGrenadeShootSound(char[] buffer, int bufferSize) + { + this.GetString("grenade_shoot_sound", buffer, bufferSize, GRENADE_SHOOT); + } + + public void GetSentryRocketShootSound(char[] buffer, int bufferSize) + { + this.GetString("sentryrocket_shoot_sound", buffer, bufferSize, SENTRYROCKET_SHOOT); + } + + public void GetArrowShootSound(char[] buffer, int bufferSize) + { + this.GetString("arrow_shoot_sound", buffer, bufferSize, ARROW_SHOOT); + } + + public void GetManglerShootSound(char[] buffer, int bufferSize) + { + this.GetString("mangler_shoot_sound", buffer, bufferSize, MANGLER_SHOOT); + } + + public void GetBaseballShootSound(char[] buffer, int bufferSize) + { + this.GetString("baseball_shoot_sound", buffer, bufferSize, BASEBALL_SHOOT); + } + + public void GetBaseballModel(char[] buffer, int bufferSize) + { + this.GetString("baseball_model", buffer, bufferSize, BASEBALL_MODEL); + } + + public void Precache() + { + char path[PLATFORM_MAX_PATH]; + this.GetRocketShootSound(path, sizeof(path)); + if (path[0] != '\0') + { + PrecacheSound2(path, g_FileCheckConVar.BoolValue); + } + + this.GetRocketExplodeSound(path, sizeof(path)); + if (path[0] != '\0') + { + PrecacheSound2(path, g_FileCheckConVar.BoolValue); + } + + this.GetFireballShootSound(path, sizeof(path)); + if (path[0] != '\0') + { + PrecacheSound2(path, g_FileCheckConVar.BoolValue); + } + + this.GetFireballExplodeSound(path, sizeof(path)); + if (path[0] != '\0') + { + PrecacheSound2(path, g_FileCheckConVar.BoolValue); + } + + this.GetIceballSlowSound(path, sizeof(path)); + if (path[0] != '\0') + { + PrecacheSound2(path, g_FileCheckConVar.BoolValue); + } + + this.GetGrenadeShootSound(path, sizeof(path)); + if (path[0] != '\0') + { + PrecacheSound2(path, g_FileCheckConVar.BoolValue); + } + + this.GetSentryRocketShootSound(path, sizeof(path)); + if (path[0] != '\0') + { + PrecacheSound2(path, g_FileCheckConVar.BoolValue); + } + + this.GetArrowShootSound(path, sizeof(path)); + if (path[0] != '\0') + { + PrecacheSound2(path, g_FileCheckConVar.BoolValue); + } + + this.GetManglerShootSound(path, sizeof(path)); + if (path[0] != '\0') + { + PrecacheSound2(path, g_FileCheckConVar.BoolValue); + } + + this.GetBaseballShootSound(path, sizeof(path)); + if (path[0] != '\0') + { + PrecacheSound2(path, g_FileCheckConVar.BoolValue); + } + + this.GetBaseballModel(path, sizeof(path)); + if (path[0] != '\0') + { + PrecacheModel2(path, .checkFile = g_FileCheckConVar.BoolValue); + } + } } int GetProfileAttackNum(const char[] profile, const char[] keyValue, int defaultValue=0, const int attackIndex) @@ -135,4 +3134,49 @@ bool GetProfileAttackVector(const char[] profile, const char[] keyValue, float b g_Config.JumpToKey(key); g_Config.GetVector(keyValue, buffer, defaultValue); return true; -} \ No newline at end of file +} + +void ProfileChaser_InititalizeAPI() +{ + CreateNative("SF2_ChaserBossProfile.GetAttackCount", Native_GetAttackCount); + CreateNative("SF2_ChaserBossProfile.GetAttack", Native_GetAttack); + CreateNative("SF2_ChaserBossProfile.GetAttackFromIndex", Native_GetAttackFromIndex); +} + +static any Native_GetAttackCount(Handle plugin, int numParams) +{ + ChaserBossProfile profileData = GetNativeCell(1); + if (profileData == null || profileData.Type != SF2BossType_Chaser) + { + return ThrowNativeError(SP_ERROR_NATIVE, "Invalid Chaser boss profile handle %x", profileData); + } + + return profileData.GetAttackCount(); +} + +static any Native_GetAttack(Handle plugin, int numParams) +{ + ChaserBossProfile profileData = GetNativeCell(1); + if (profileData == null || profileData.Type != SF2BossType_Chaser) + { + return ThrowNativeError(SP_ERROR_NATIVE, "Invalid Chaser boss profile handle %x", profileData); + } + + char attackName[256]; + GetNativeString(2, attackName, sizeof(attackName)); + + return profileData.GetAttack(attackName); +} + +static any Native_GetAttackFromIndex(Handle plugin, int numParams) +{ + ChaserBossProfile profileData = GetNativeCell(1); + if (profileData == null || profileData.Type != SF2BossType_Chaser) + { + return ThrowNativeError(SP_ERROR_NATIVE, "Invalid Chaser boss profile handle %x", profileData); + } + + int attackIndex = GetNativeCell(2); + + return profileData.GetAttackFromIndex(attackIndex); +} diff --git a/addons/sourcemod/scripting/sf2/profiles/profile_chaser_precache.sp b/addons/sourcemod/scripting/sf2/profiles/profile_chaser_precache.sp index 5c7b17fe..a8760df2 100644 --- a/addons/sourcemod/scripting/sf2/profiles/profile_chaser_precache.sp +++ b/addons/sourcemod/scripting/sf2/profiles/profile_chaser_precache.sp @@ -5,6 +5,7 @@ #define _sf2_profiles_chaser_precache #pragma semicolon 1 +#pragma newdecls required /** * Parses and stores the unique values of a chaser profile from the current position in the profiles config. diff --git a/addons/sourcemod/scripting/sf2/profiles/profile_statue.sp b/addons/sourcemod/scripting/sf2/profiles/profile_statue.sp index 9f40351f..aa4f3be9 100644 --- a/addons/sourcemod/scripting/sf2/profiles/profile_statue.sp +++ b/addons/sourcemod/scripting/sf2/profiles/profile_statue.sp @@ -5,28 +5,88 @@ #define _sf2_profiles_statue #pragma semicolon 1 +#pragma newdecls required -StringMap g_StatueBossProfileData; - -void InitializeStatueProfiles() +methodmap StatueBossProfile < BaseBossProfile { - g_StatueBossProfileData = new StringMap(); -} + public void GetAverageDistanceModel(int difficulty, char[] buffer, int bufferSize) + { + this.GetDifficultyString("model_averagedist", difficulty, buffer, bufferSize); + ReplaceString(buffer, bufferSize, "\\", "/", false); + } -void UnloadStatueBossProfile(const char[] profile) -{ - SF2StatueBossProfileData statueProfileData; - if (!g_StatueBossProfileData.GetArray(profile, statueProfileData, sizeof(statueProfileData))) + public void GetCloseDistanceModel(int difficulty, char[] buffer, int bufferSize) { - return; + this.GetDifficultyString("model_closedist", difficulty, buffer, bufferSize); + ReplaceString(buffer, bufferSize, "\\", "/", false); } - statueProfileData.Destroy(); + public float GetMaxModelChangeDistance(int difficulty) + { + return this.GetDifficultyFloat("model_change_dist_max", difficulty, 1024.0); + } - g_StatueBossProfileData.Remove(profile); + public float GetChaseDuration(int difficulty) + { + return this.GetDifficultyFloat("chase_duration", difficulty, 5.0); + } + + public float GetChaseDurationAddMaxRange(int difficulty) + { + return this.GetDifficultyFloat("chase_duration_add_max_range", difficulty, 1024.0); + } + + public float GetChaseDurationAddVisibilityMin(int difficulty) + { + return this.GetDifficultyFloat("chase_duration_add_visible_min", difficulty, 0.025); + } + + public float GetChaseDurationAddVisibilityMax(int difficulty) + { + return this.GetDifficultyFloat("chase_duration_add_visible_max", difficulty, 0.15); + } + + public ProfileSound GetMoveSounds() + { + return view_as(this.GetSection("sound_move")); + } + + public ProfileSound GetSingleMoveSounds() + { + return view_as(this.GetSection("sound_move_single")); + } + + public void Precache() + { + if (this.GetMoveSounds() != null) + { + this.GetMoveSounds().Precache(); + } + + if (this.GetSingleMoveSounds() != null) + { + this.GetSingleMoveSounds().Precache(); + } + + char path[PLATFORM_MAX_PATH]; + for (int i = 0; i < Difficulty_Max; i++) + { + this.GetAverageDistanceModel(i, path, sizeof(path)); + if (path[0] != '\0') + { + PrecacheModel2(path, _, _, g_FileCheckConVar.BoolValue); + } + + this.GetCloseDistanceModel(i, path, sizeof(path)); + if (path[0] != '\0') + { + PrecacheModel2(path, _, _, g_FileCheckConVar.BoolValue); + } + } + } } -bool LoadStatueBossProfile(KeyValues kv, const char[] profile, char[] loadFailReasonBuffer, int loadFailReasonBufferLen, SF2BossProfileData baseData) +/*bool LoadStatueBossProfile(KeyValues kv, const char[] profile, char[] loadFailReasonBuffer, int loadFailReasonBufferLen, SF2BossProfileData baseData) { SF2StatueBossProfileData profileData; profileData.Init(); @@ -101,4 +161,4 @@ bool LoadStatueBossProfile(KeyValues kv, const char[] profile, char[] loadFailRe g_StatueBossProfileData.SetArray(profile, profileData, sizeof(profileData)); return true; -} +}*/ diff --git a/addons/sourcemod/scripting/sf2/profiles/profiles_boss_functions.sp b/addons/sourcemod/scripting/sf2/profiles/profiles_boss_functions.sp index 01261cc4..bc2f5d05 100644 --- a/addons/sourcemod/scripting/sf2/profiles/profiles_boss_functions.sp +++ b/addons/sourcemod/scripting/sf2/profiles/profiles_boss_functions.sp @@ -4,2429 +4,3328 @@ #define _sf2_profiles_precache_included #pragma semicolon 1 +#pragma newdecls required -/** - * Loads a profile in the current KeyValues position in kv. - */ -bool LoadBossProfile(KeyValues kv, const char[] profile, char[] loadFailReasonBuffer, int loadFailReasonBufferLen, bool lookIntoLoads = false, const char[] originalDir = "") +methodmap BaseBossProfile < ProfileObject { - SF2BossProfileData profileData; - profileData.Init(); + public ProfileObject GetBlacklistedMaps() + { + return this.GetSection("map_blacklist"); + } - if (kv.JumpToKey("map_blacklist")) + property int Type { - char s1[4], s2[64], s3[64]; - GetCurrentMap(s3, sizeof(s3)); - for (int i = 1;; i++) + public get() { - FormatEx(s1, sizeof(s1), "%d", i); - kv.GetString(s1, s2, sizeof(s2)); - if (s2[0] == '\0') + return this.GetInt("type", SF2BossType_Chaser); + } + } + + property bool IgnoreNavPrefer + { + public get() + { + return true; + } + } + + property int Flags + { + public get() + { + int bossFlags = 0; + if (this.GetBool("static_on_look", false)) { - break; + bossFlags |= SFF_STATICONLOOK; } - - if (StrContains(s3, s2, false) != -1) + if (this.GetBool("static_on_radius", false)) { - FormatEx(loadFailReasonBuffer, loadFailReasonBufferLen, "is blacklisted on %s!", s3); - return false; + bossFlags |= SFF_STATICONRADIUS; + } + if (this.GetBool("proxies", false)) + { + bossFlags |= SFF_PROXIES; + } + if (this.GetBool("jumpscare", false)) + { + bossFlags |= SFF_HASJUMPSCARE; + } + if (this.GetBool("sound_static_loop_local_enabled", false)) + { + bossFlags |= SFF_HASSTATICLOOPLOCALSOUND; + } + if (this.GetBool("view_shake", true)) + { + bossFlags |= SFF_HASVIEWSHAKE; + } + if (this.GetBool("wander_move", true)) + { + bossFlags |= SFF_WANDERMOVE; + } + if (this.GetBool("attack_props", false)) + { + bossFlags |= SFF_ATTACKPROPS; + } + if (this.GetBool("attack_weaponsenable", false)) + { + bossFlags |= SFF_WEAPONKILLS; + } + if (this.GetBool("kill_weaponsenable", false)) + { + bossFlags |= SFF_WEAPONKILLSONRADIUS; } + return bossFlags; } + } - kv.GoBack(); + public void GetModel(int difficulty, char[] buffer, int bufferSize) + { + this.GetDifficultyString("model", difficulty, buffer, bufferSize); + ReplaceString(buffer, bufferSize, "\\", "/", false); } - if (lookIntoLoads) + public void GetName(int difficulty, char[] buffer, int bufferSize) { - // In this, we're basically just gonna go look for companion bosses and skip them here - bool skip = true; + this.GetDifficultyString("name", difficulty, buffer, bufferSize); + } - if (kv.GetNum("enable_random_selection", true) != 0) + property float ModelScale + { + public get() { - skip = false; + return this.GetFloat("model_scale", 1.0); } + } - if (kv.GetNum("admin_only", false) != 0) - { - skip = false; - } + public int GetSkin(int difficulty) + { + return this.GetDifficultyInt("skin", difficulty); + } - if (kv.GetNum("enable_random_selection_boxing", false) != 0) + property int SkinMax + { + public get() { - skip = false; + return this.GetInt("skin_max"); } + } - if (kv.GetNum("enable_random_selection_renevant", false) != 0) - { - skip = false; - } + public int GetBodyGroup(int difficulty) + { + return this.GetDifficultyInt("body", difficulty); + } - if (kv.GetNum("enable_random_selection_renevant_admin", false) != 0) + property int BodyMax + { + public get() { - skip = false; + return this.GetInt("body_max"); } + } - if (kv.GetNum("is_pve", false) != 0 && kv.GetNum("pve_selectable", 1) != 0) + property bool BodyDifficultiesOn + { + public get() { - skip = false; + return this.GetBool("body_difficulty"); } + } - if (kv.GetNum("always_load", false) != 0) + property bool RaidHitbox + { + public get() { - skip = false; + return this.GetBool("use_raid_hitbox"); } + } - if (kv.JumpToKey("pve") && kv.GetNum("selectable", 1) != 0) + property float InstantKillRadius + { + public get() { - kv.GoBack(); - skip = false; + return this.GetFloat("kill_radius", -1.0); } + } - if (skip) - { - FormatEx(loadFailReasonBuffer, loadFailReasonBufferLen, "is not selectable, skipping!"); - return false; - } + public float GetInstantKillCooldown(int difficulty) + { + return this.GetDifficultyFloat("kill_cooldown", difficulty, 0.0); } - profileData.Models = new ArrayList(ByteCountToCells(PLATFORM_MAX_PATH)); - profileData.Names = new ArrayList(ByteCountToCells(PLATFORM_MAX_PATH)); - SetProfileDifficultyStringArrayValues(kv, "model", profileData.Models, true); - char modelName[PLATFORM_MAX_PATH]; - for (int i = 0; i < profileData.Models.Length; i++) + property int TeleportType { - profileData.Models.GetString(i, modelName, sizeof(modelName)); - if (modelName[0] != '\0' && strcmp(modelName, "models/", true) != 0 && strcmp(modelName, "models\\", true) != 0) + public get() { - PrecacheModel2(modelName, _, _, g_FileCheckConVar.BoolValue); + return this.GetInt("teleport_type", 2); } } - SetProfileDifficultyStringArrayValues(kv, "name", profileData.Names); - profileData.Type = kv.GetNum("type", profileData.Type); - if (profileData.Type == SF2BossType_Unknown || profileData.Type >= SF2BossType_MaxTypes) + public bool IsTeleportAllowed(int difficulty) { - FormatEx(loadFailReasonBuffer, loadFailReasonBufferLen, "boss type is unknown!"); - return false; + return this.GetDifficultyBool("teleport_allowed", difficulty, true); } - profileData.ModelScale = kv.GetFloat("model_scale", profileData.ModelScale); - if (profileData.ModelScale <= 0.0) + public float GetMinTeleportRange(int difficulty) { - FormatEx(loadFailReasonBuffer, loadFailReasonBufferLen, "model_scale must be a value greater than 0!"); - return false; + return this.GetDifficultyFloat("teleport_range_min", difficulty, 450.0); } - profileData.Skin[1] = kv.GetNum("skin", profileData.Skin[1]); - if (profileData.Skin[1] < 0) + public float GetMaxTeleportRange(int difficulty) { - FormatEx(loadFailReasonBuffer, loadFailReasonBufferLen, "skin must be a value that is at least 0!"); - return false; + return this.GetDifficultyFloat("teleport_range_max", difficulty, 1500.0); } - GetProfileDifficultyNumValues(kv, "skin", profileData.Skin, profileData.Skin); - profileData.SkinMax = kv.GetNum("skin_max", profileData.SkinMax); - if (profileData.SkinMax < 0) + public float GetMinTeleportTime(int difficulty) { - FormatEx(loadFailReasonBuffer, loadFailReasonBufferLen, "skin_max must be a value that is at least 0!"); - return false; + return this.GetDifficultyFloat("teleport_time_min", difficulty, 5.0); } - profileData.SkinDifficultiesOn = kv.GetNum("skin_difficulty", profileData.SkinDifficultiesOn) != 0; - - profileData.Body[1] = kv.GetNum("body", profileData.Body[1]); - if (profileData.Body[1] < 0) + public float GetMaxTeleportTime(int difficulty) { - FormatEx(loadFailReasonBuffer, loadFailReasonBufferLen, "body must be a value that is at least 0!"); - return false; + return this.GetDifficultyFloat("teleport_time_max", difficulty, 9.0); } - GetProfileDifficultyNumValues(kv, "body", profileData.Body, profileData.Body); - profileData.BodyMax = kv.GetNum("body_max", profileData.BodyMax); - if (profileData.BodyMax < 0) + public float GetTeleportRestPeriod(int difficulty) { - FormatEx(loadFailReasonBuffer, loadFailReasonBufferLen, "body_max must be a value that is at least 0!"); - return false; + return this.GetDifficultyFloat("teleport_target_rest_period", difficulty, 15.0); } - profileData.BodyDifficultiesOn = kv.GetNum("body_difficulty", profileData.BodyDifficultiesOn) != 0; + public float GetMinTeleportStress(int difficulty) + { + return this.GetDifficultyFloat("teleport_target_stress_min", difficulty, 0.2); + } - profileData.RaidHitbox = kv.GetNum("use_raid_hitbox", profileData.RaidHitbox) != 0; + public float GetMaxTeleportStress(int difficulty) + { + return this.GetDifficultyFloat("teleport_target_stress_max", difficulty, 1.0); + } - profileData.InstantKillRadius = kv.GetFloat("kill_radius", profileData.InstantKillRadius); + public float GetTeleportPersistencyPeriod(int difficulty) + { + return this.GetDifficultyFloat("teleport_target_persistency_period", difficulty, 13.0); + } - profileData.ScareRadius = kv.GetFloat("scare_radius", profileData.ScareRadius); - if (profileData.ScareRadius < 0.0) + property int TeleportIgnoreChases { - FormatEx(loadFailReasonBuffer, loadFailReasonBufferLen, "scare_radius must be a value that is at least 0!"); - return false; + public get() + { + return this.GetInt("teleport_target_ignore_chases", false); + } } - profileData.TeleportType = kv.GetNum("teleport_type", profileData.TeleportType); - if (profileData.TeleportType < 0) + property int TeleportIgnoreVis { - FormatEx(loadFailReasonBuffer, loadFailReasonBufferLen, "unknown teleport type!"); - return false; + public get() + { + return this.GetInt("teleport_target_ignore_visibility", false); + } } - FormatEx(loadFailReasonBuffer, loadFailReasonBufferLen, "unknown!"); + property float FOV + { + public get() + { + return this.GetFloat("fov", 90.0); + } + } - profileData.FOV = kv.GetFloat("fov", profileData.FOV); - if (profileData.FOV < 0.0) + property float TurnRate { - profileData.FOV = 0.0; + public get() + { + float val = 250.0; + val = this.GetFloat("maxyawrate", val); + val = this.GetFloat("turnrate", val); + return val; + } } - else if (profileData.FOV > 360.0) + + property float ScareRadius { - profileData.FOV = 360.0; + public get() + { + return this.GetFloat("scare_radius", 0.0); + } } - profileData.TurnRate = kv.GetFloat("maxyawrate", profileData.TurnRate); - profileData.TurnRate = kv.GetFloat("turnrate", profileData.TurnRate); + property float ScareCooldown + { + public get() + { + return this.GetFloat("scare_cooldown", 0.0); + } + } - switch (profileData.Type) + property float ScareReplenishSprintAmount { - case SF2BossType_Chaser: + public get() { - profileData.Description.Type = "Chaser"; + return this.GetFloat("scare_player_replenish_sprint_amount", 0.0); } + } - case SF2BossType_Statue: + property float ScareSpeedBoostDuration + { + public get() { - profileData.Description.Type = "Statue"; + return this.GetFloat("scare_player_speed_boost_duration", 0.0); } } - if (kv.JumpToKey("description")) + property int ScareReactionType { - profileData.Description.Load(kv); - kv.GoBack(); + public get() + { + return this.GetInt("scare_player_reaction_type", 0); + } } - profileData.ScareCooldown = kv.GetFloat("scare_cooldown", profileData.ScareCooldown); - if (profileData.ScareCooldown < 0.0) + public void GetCustomScareReaction(char[] buffer, int bufferSize) { - // clamp value - profileData.ScareCooldown = 0.0; + this.GetString("scare_player_reaction_response_custom", buffer, bufferSize); } - kv.GetVector("mins", profileData.Mins, profileData.Mins); - kv.GetVector("maxs", profileData.Maxs, profileData.Maxs); + public float GetJumpscareDistance(int difficulty) + { + return this.GetDifficultyFloat("jumpscare_distance", difficulty, 0.0); + } - profileData.StepSize = kv.GetFloat("stepsize", profileData.StepSize); + public float GetJumpscareDuration(int difficulty) + { + return this.GetDifficultyFloat("jumpscare_duration", difficulty, 0.0); + } - profileData.NodeDistanceLookAhead = kv.GetFloat("search_node_dist_lookahead", profileData.NodeDistanceLookAhead); + public float GetJumpscareCooldown(int difficulty) + { + return this.GetDifficultyFloat("jumpscare_cooldown", difficulty, 0.0); + } - GetProfileColorNoBacks(kv, "effect_rendercolor", profileData.RenderColor[0], profileData.RenderColor[1], profileData.RenderColor[2], profileData.RenderColor[3], - profileData.RenderColor[0], profileData.RenderColor[1], profileData.RenderColor[2], profileData.RenderColor[3]); - profileData.RenderFX = kv.GetNum("effect_renderfx", profileData.RenderFX); - profileData.RenderMode = kv.GetNum("effect_rendermode", profileData.RenderMode); + property bool JumpscareOnScare + { + public get() + { + return this.GetBool("jumpscare_on_scare", false); + } + } - kv.GetString("kill_weapontype", profileData.WeaponString, sizeof(profileData.WeaponString), profileData.WeaponString); - profileData.WeaponInt = kv.GetNum("kill_weapontype", profileData.WeaponInt); + property bool JumpscareNoSight + { + public get() + { + return this.GetBool("jumpscare_no_sight", false); + } + } - profileData.DiscoMode = kv.GetNum("disco_mode", profileData.DiscoMode) != 0; - if (profileData.DiscoMode) + public void GetJumpscareSound(char[] buffer, int bufferSize) { - profileData.DiscoDistanceMin = kv.GetFloat("disco_mode_rng_distance_min", profileData.DiscoDistanceMin); - profileData.DiscoDistanceMax = kv.GetFloat("disco_mode_rng_distance_max", profileData.DiscoDistanceMax); - kv.GetVector("disco_mode_pos", profileData.DiscoPos, profileData.DiscoPos); + ProfileObject obj = this.GetSection("sound_jumpscare"); + if (obj != null) + { + obj.GetString("1", buffer, bufferSize); + } } - profileData.FestiveLights = kv.GetNum("festive_lights", profileData.FestiveLights) != 0; - if (profileData.FestiveLights) + public void GetJumpscareOverlay(char[] buffer, int bufferSize) { - profileData.FestiveLightBrightness = kv.GetNum("festive_light_brightness", profileData.FestiveLightBrightness); - profileData.FestiveLightDistance = kv.GetFloat("festive_light_distance", profileData.FestiveLightDistance); - profileData.FestiveLightRadius = kv.GetFloat("festive_light_radius", profileData.FestiveLightRadius); - kv.GetVector("festive_lights_pos", profileData.FestiveLightPos, profileData.FestiveLightPos); - kv.GetVector("festive_lights_ang", profileData.FestiveLightAng, profileData.FestiveLightAng); + ProfileObject obj = this.GetSection("overlay_jumpscare"); + if (obj != null) + { + obj.GetString("1", buffer, bufferSize); + } } - if (kv.GetNum("tp_effect_spawn", false) != 0) + public void GetPlayerDeathOverlay(char[] buffer, int bufferSize) { - if (profileData.SpawnEffects == null) + ProfileObject obj = this.GetSection("overlay_player_death"); + if (obj != null) { - profileData.SpawnEffects = new StringMap(); + obj.GetString("1", buffer, bufferSize); } - ArrayList listEffects = new ArrayList(sizeof(SF2BossProfileBaseEffectInfo)); + } - SF2BossProfileBaseEffectInfo particle; - SF2BossProfileBaseEffectInfo sound; + public void GetHullMins(float vec[3]) + { + this.GetVector("mins", vec, HULL_HUMAN_MINS); + } - particle.Init(); - particle.Type = EffectType_Particle; - particle.Event = EffectEvent_Constant; - kv.GetString("tp_effect_spawn_particle", particle.ParticleName, sizeof(particle.ParticleName), particle.ParticleName); - particle.LifeTime = 0.1; - kv.GetVector("tp_effect_origin", particle.Origin, particle.Origin); - particle.PostLoad(); - listEffects.PushArray(particle); + public void GetHullMaxs(float vec[3]) + { + this.GetVector("maxs", vec, HULL_HUMAN_MAXS); + } - char soundName[PLATFORM_MAX_PATH]; - sound.Init(); - sound.Type = EffectType_Sound; - sound.Event = EffectEvent_Constant; - kv.GetString("tp_effect_spawn_sound", soundName, sizeof(soundName), soundName); - TryPrecacheBossProfileSoundPath(soundName, g_FileCheckConVar.BoolValue); - sound.SoundSounds.Paths = new ArrayList(ByteCountToCells(PLATFORM_MAX_PATH)); - sound.SoundSounds.Paths.PushString(soundName); - sound.SoundSounds.Volume = kv.GetFloat("tp_effect_spawn_sound_volume", sound.SoundSounds.Volume); - sound.SoundSounds.Pitch = kv.GetNum("tp_effect_spawn_sound_pitch", sound.SoundSounds.Pitch); - sound.SoundSounds.PostLoad(); - listEffects.PushArray(sound); - - profileData.SpawnEffects.SetValue("TPEffectSpawnBackwards", listEffects); + property float StepSize + { + public get() + { + return this.GetFloat("stepsize", 18.0); + } } - if (kv.GetNum("tp_effect_despawn", false) != 0) + property float NodeDistanceLookAhead { - if (profileData.DespawnEffects == null) + public get() { - profileData.DespawnEffects = new StringMap(); + return this.GetFloat("search_node_dist_lookahead", 128.0); } - ArrayList listEffects = new ArrayList(sizeof(SF2BossProfileBaseEffectInfo)); - - SF2BossProfileBaseEffectInfo particle; - SF2BossProfileBaseEffectInfo sound; - - particle.Init(); - particle.Type = EffectType_Particle; - particle.Event = EffectEvent_Constant; - kv.GetString("tp_effect_despawn_particle", particle.ParticleName, sizeof(particle.ParticleName), particle.ParticleName); - particle.LifeTime = 0.1; - kv.GetVector("tp_effect_origin", particle.Origin, particle.Origin); - particle.PostLoad(); - listEffects.PushArray(particle); + } - char soundName[PLATFORM_MAX_PATH]; - sound.Init(); - sound.Type = EffectType_Sound; - sound.Event = EffectEvent_Constant; - kv.GetString("tp_effect_despawn_sound", soundName, sizeof(soundName), soundName); - TryPrecacheBossProfileSoundPath(soundName, g_FileCheckConVar.BoolValue); - sound.SoundSounds.Paths = new ArrayList(ByteCountToCells(PLATFORM_MAX_PATH)); - sound.SoundSounds.Paths.PushString(soundName); - sound.SoundSounds.Volume = kv.GetFloat("tp_effect_despawn_sound_volume", sound.SoundSounds.Volume); - sound.SoundSounds.Pitch = kv.GetNum("tp_effect_despawn_sound_pitch", sound.SoundSounds.Pitch); - sound.SoundSounds.PostLoad(); - listEffects.PushArray(sound); + public void GetRenderColor(int difficulty, int buffer[4]) + { + this.GetDifficultyColor("effect_rendercolor", difficulty, buffer); + } - profileData.DespawnEffects.SetValue("TPEffectDespawnBackwards", listEffects); + public RenderFx GetRenderFx(int difficulty) + { + return view_as(this.GetDifficultyInt("effect_renderfx", difficulty, view_as(RENDERFX_NONE))); } - profileData.BlinkLookRate = kv.GetFloat("blink_look_rate_multiply", profileData.BlinkLookRate); - profileData.BlinkStaticRate = kv.GetFloat("blink_static_rate_multiply", profileData.BlinkStaticRate); + public RenderMode GetRenderMode(int difficulty) + { + return view_as(this.GetDifficultyInt("effect_rendermode", difficulty, view_as(RENDER_NORMAL))); + } - profileData.DeathCam = kv.GetNum("death_cam", profileData.DeathCam) != 0; - if (profileData.DeathCam) + public BossProfileEyeData GetEyes() { - profileData.DeathCamScareSound = kv.GetNum("death_cam_play_scare_sound", profileData.DeathCamScareSound) != 0; - profileData.PublicDeathCam = kv.GetNum("death_cam_public", profileData.PublicDeathCam) != 0; - if (profileData.PublicDeathCam) - { - profileData.PublicDeathCamSpeed = kv.GetFloat("death_cam_speed", profileData.PublicDeathCamSpeed); - profileData.PublicDeathCamAcceleration = kv.GetFloat("death_cam_acceleration", profileData.PublicDeathCamAcceleration); - profileData.PublicDeathCamDeceleration = kv.GetFloat("death_cam_deceleration", profileData.PublicDeathCamDeceleration); - profileData.PublicDeathCamBackwardOffset = kv.GetFloat("deathcam_death_backward_offset", profileData.PublicDeathCamBackwardOffset); - profileData.PublicDeathCamDownwardOffset = kv.GetFloat("deathcam_death_downward_offset", profileData.PublicDeathCamDownwardOffset); - } - profileData.DeathCamOverlay = kv.GetNum("death_cam_overlay", profileData.DeathCamOverlay) != 0; - profileData.DeathCamOverlayStartTime = kv.GetFloat("death_cam_time_overlay_start", profileData.DeathCamOverlayStartTime); - if (profileData.DeathCamOverlayStartTime < 0.0) - { - profileData.DeathCamOverlayStartTime = 0.0; - } - profileData.DeathCamTime = kv.GetFloat("death_cam_time_death", profileData.DeathCamTime); - if (profileData.DeathCamTime < 0.0) + ProfileObject obj = this.GetSection("eyes"); + if (obj == null) { - profileData.DeathCamTime = 0.0; + obj = this; } - kv.GetVector("death_cam_pos", profileData.DeathCamPos, profileData.DeathCamPos); - kv.GetString("death_cam_attachtment_target_point", profileData.PublicDeathCamAttachmentTarget, sizeof(profileData.PublicDeathCamAttachmentTarget), profileData.PublicDeathCamAttachmentTarget); - kv.GetString("death_cam_attachtment_point", profileData.PublicDeathCamAttachment, sizeof(profileData.PublicDeathCamAttachment), profileData.PublicDeathCamAttachment); + return view_as(obj); } - if (kv.JumpToKey("public_death_cam")) + public bool HasStaticOnRadius(int difficulty) { - profileData.DeathCamData.Load(kv, g_FileCheckConVar.BoolValue); - kv.GoBack(); + return this.GetDifficultyBool("static_on_radius", difficulty); } - GetProfileDifficultyFloatValues(kv, "sound_music_loop", profileData.SoundMusicLoop, profileData.SoundMusicLoop); - GetProfileDifficultyFloatValues(kv, "kill_cooldown", profileData.InstantKillCooldown, profileData.InstantKillCooldown); - - GetProfileDifficultyFloatValues(kv, "search_view_distance", profileData.SearchRange, profileData.SearchRange); - GetProfileDifficultyFloatValues(kv, "search_range", profileData.SearchRange, profileData.SearchRange); - GetProfileDifficultyFloatValues(kv, "hearing_range", profileData.SearchSoundRange, profileData.SearchSoundRange); - GetProfileDifficultyFloatValues(kv, "search_sound_range", profileData.SearchSoundRange, profileData.SearchSoundRange); - GetProfileDifficultyFloatValues(kv, "taunt_alert_range", profileData.TauntAlertRange, profileData.TauntAlertRange); + public float GetStaticRadius(int difficulty) + { + return this.GetDifficultyFloat("static_radius", difficulty, 150.0); + } - GetProfileDifficultyBoolValues(kv, "teleport_allowed", profileData.TeleportAllowed, profileData.TeleportAllowed); - GetProfileDifficultyFloatValues(kv, "teleport_range_min", profileData.TeleportRangeMin, profileData.TeleportRangeMin); - GetProfileDifficultyFloatValues(kv, "teleport_range_max", profileData.TeleportRangeMax, profileData.TeleportRangeMax); - GetProfileDifficultyFloatValues(kv, "teleport_time_min", profileData.TeleportTimeMin, profileData.TeleportTimeMin); - GetProfileDifficultyFloatValues(kv, "teleport_time_max", profileData.TeleportTimeMax, profileData.TeleportTimeMax); - GetProfileDifficultyFloatValues(kv, "teleport_target_rest_period", profileData.TeleportRestPeriod, profileData.TeleportRestPeriod); - GetProfileDifficultyFloatValues(kv, "teleport_target_stress_min", profileData.TeleportStressMin, profileData.TeleportStressMin); - GetProfileDifficultyFloatValues(kv, "teleport_target_stress_max", profileData.TeleportStressMax, profileData.TeleportStressMax); - GetProfileDifficultyFloatValues(kv, "teleport_target_persistency_period", profileData.TeleportPersistencyPeriod, profileData.TeleportPersistencyPeriod); - profileData.TeleportIgnoreChases = kv.GetNum("teleport_target_ignore_chases", profileData.TeleportIgnoreChases) != 0; - profileData.TeleportIgnoreVis = kv.GetNum("teleport_target_ignore_visibility", profileData.TeleportIgnoreVis) != 0; + public float GetStaticRate(int difficulty) + { + static const float defaultValue[Difficulty_Max] = { 0.8, 0.8, 0.75, 0.7, 0.5, 0.4 }; - GetProfileDifficultyFloatValues(kv, "jumpscare_distance", profileData.JumpscareDistance, profileData.JumpscareDistance); - GetProfileDifficultyFloatValues(kv, "jumpscare_duration", profileData.JumpscareDuration, profileData.JumpscareDuration); - GetProfileDifficultyFloatValues(kv, "jumpscare_cooldown", profileData.JumpscareCooldown, profileData.JumpscareCooldown); - profileData.JumpscareOnScare = kv.GetNum("jumpscare_on_scare", profileData.JumpscareOnScare) != 0; - profileData.JumpscareNoSight = kv.GetNum("jumpscare_no_sight", profileData.JumpscareNoSight) != 0; + return this.GetDifficultyFloat("static_rate", difficulty, defaultValue[difficulty]); + } - GetProfileDifficultyFloatValues(kv, "speed", profileData.RunSpeed, profileData.RunSpeed); - GetProfileDifficultyFloatValues(kv, "acceleration", profileData.Acceleration, profileData.Acceleration); + public float GetStaticRateDecay(int difficulty) + { + static const float defaultValue[Difficulty_Max] = { 0.2, 0.2, 0.25, 0.3, 0.4, 0.55 }; - GetProfileDifficultyFloatValues(kv, "idle_lifetime", profileData.IdleLifeTime, profileData.IdleLifeTime); + return this.GetDifficultyFloat("static_rate_decay", difficulty, defaultValue[difficulty]); + } - profileData.CustomOutlines = kv.GetNum("customizable_outlines", profileData.CustomOutlines) != 0; - if (profileData.CustomOutlines) + public bool HasStaticOnLook(int difficulty) { - profileData.OutlineColor[0] = kv.GetNum("outline_color_r", profileData.OutlineColor[0]); - profileData.OutlineColor[1] = kv.GetNum("outline_color_g", profileData.OutlineColor[1]); - profileData.OutlineColor[2] = kv.GetNum("outline_color_b", profileData.OutlineColor[2]); - profileData.OutlineColor[3] = kv.GetNum("outline_color_transparency", profileData.OutlineColor[3]); - profileData.RainbowOutline = !!kv.GetNum("enable_rainbow_outline", profileData.RainbowOutline); - if (profileData.RainbowOutline) - { - profileData.RainbowOutlineCycle = kv.GetFloat("rainbow_outline_cycle_rate", profileData.RainbowOutlineCycle); - if (profileData.RainbowOutlineCycle < 0.0) - { - profileData.RainbowOutlineCycle = 0.0; - } - } + return this.GetDifficultyBool("static_on_look", difficulty); } - profileData.SpeedBoostOnScare = !!kv.GetNum("scare_player_speed_boost", profileData.SpeedBoostOnScare); - if (profileData.SpeedBoostOnScare) + public float GetStaticOnLookGraceTime(int difficulty) { - profileData.ScareSpeedBoostDuration = kv.GetFloat("scare_player_speed_boost_duration", profileData.ScareSpeedBoostDuration); + return this.GetDifficultyFloat("static_on_look_gracetime", difficulty, 1.0); } - profileData.ScareReaction = !!kv.GetNum("scare_player_reaction", profileData.ScareReaction); - if (profileData.ScareReaction) + public float GetScareStaticAmount(int difficulty) { - profileData.ScareReactionType = kv.GetNum("scare_player_reaction_type", profileData.ScareReactionType); - if (profileData.ScareReactionType < 1) - { - profileData.ScareReactionType = 1; - } - if (profileData.ScareReactionType > 3) - { - profileData.ScareReactionType = 3; - } - kv.GetString("scare_player_reaction_response_custom", profileData.ScareReactionCustom, sizeof(profileData.ScareReactionCustom), profileData.ScareReactionCustom); + return this.GetDifficultyFloat("scare_static_amount", difficulty); } - profileData.ScareReplenishSprint = kv.GetNum("scare_player_replenish_sprint", profileData.ScareReplenishSprint) != 0; - if (profileData.ScareReplenishSprint) + public float GetRunSpeed(int difficulty) { - profileData.ScareReplenishSprintAmount = kv.GetFloat("scare_player_replenish_sprint_amount", profileData.ScareReplenishSprintAmount); + return this.GetDifficultyFloat("speed", difficulty, 300.0); } - GetProfileDifficultyFloatValues(kv, "static_radius", profileData.StaticRadius, profileData.StaticRadius); - GetProfileDifficultyFloatValues(kv, "static_rate", profileData.StaticRate, profileData.StaticRate); - GetProfileDifficultyFloatValues(kv, "static_rate_decay", profileData.StaticRateDecay, profileData.StaticRateDecay); - GetProfileDifficultyFloatValues(kv, "static_on_look_gracetime", profileData.StaticGraceTime, profileData.StaticGraceTime); - profileData.StaticScareAmount = kv.GetFloat("scare_static_amount", profileData.StaticScareAmount); - - profileData.StaticShakeLocalLevel = kv.GetNum("sound_static_loop_local_level", profileData.StaticShakeLocalLevel); - profileData.StaticShakeVolumeMin = kv.GetFloat("sound_static_shake_local_volume_min", profileData.StaticShakeVolumeMin); - profileData.StaticShakeVolumeMax = kv.GetFloat("sound_static_shake_local_volume_max", profileData.StaticShakeVolumeMax); - - profileData.DrainCredits = !!kv.GetNum("drain_credits_on_kill", profileData.DrainCredits); - GetProfileDifficultyNumValues(kv, "drain_credits_amount", profileData.DrainCreditAmount, profileData.DrainCreditAmount); + public float GetForwardFriction(int difficulty) + { + return this.GetDifficultyFloat("friction_forward", difficulty, 0.0); + } - profileData.Healthbar = !!kv.GetNum("healthbar", profileData.Healthbar); + public float GetSidewaysFriction(int difficulty) + { + return this.GetDifficultyFloat("friction_sideways", difficulty, 3.0); + } - profileData.DeathMessageDifficultyIndexes = kv.GetNum("chat_message_upon_death_difficulty_indexes", profileData.DeathMessageDifficultyIndexes); - if (kv.JumpToKey("chat_message_upon_death")) + public float GetAcceleration(int difficulty) { - profileData.DeathMessagesArray = new ArrayList(ByteCountToCells(256)); - char message[256], section[64]; - for (int i = 1;; i++) + float def; + + switch (this.Type) { - FormatEx(section, sizeof(section), "%d", i); - kv.GetString(section, message, sizeof(message)); - if (message[0] == '\0') + case SF2BossType_Statue: { - break; + def = 10000.0; + } + default: + { + def = 4000.0; } - - profileData.DeathMessagesArray.PushString(message); } - kv.GoBack(); + + return this.GetDifficultyFloat("acceleration", difficulty, def); } - kv.GetString("chat_message_upon_death_prefix", profileData.DeathMessagePrefix, sizeof(profileData.DeathMessagePrefix), profileData.DeathMessagePrefix); - profileData.BurnRagdoll = kv.GetNum("burn_ragdoll_on_kill", profileData.BurnRagdoll) != 0; - profileData.CloakRagdoll = kv.GetNum("cloak_ragdoll_on_kill", profileData.CloakRagdoll) != 0; - profileData.DecapRagdoll = kv.GetNum("decap_ragdoll_on_kill", profileData.DecapRagdoll) != 0; - profileData.GibRagdoll = kv.GetNum("gib_ragdoll_on_kill", profileData.GibRagdoll) != 0; - profileData.IceRagdoll = kv.GetNum("ice_ragdoll_on_kill", profileData.IceRagdoll) != 0; - profileData.GoldRagdoll = kv.GetNum("gold_ragdoll_on_kill", profileData.GoldRagdoll) != 0; - profileData.ElectrocuteRagdoll = kv.GetNum("electrocute_ragdoll_on_kill", profileData.ElectrocuteRagdoll) != 0; - profileData.AshRagdoll = kv.GetNum("disintegrate_ragdoll_on_kill", profileData.AshRagdoll) != 0; - profileData.DeleteRagdoll = kv.GetNum("delete_ragdoll_on_kill", profileData.DeleteRagdoll) != 0; - profileData.PushRagdoll = kv.GetNum("push_ragdoll_on_kill", profileData.PushRagdoll) != 0; - if (profileData.PushRagdoll) + public float GetSearchRange(int difficulty) { - kv.GetVector("push_ragdoll_force", profileData.PushRagdollForce, profileData.PushRagdollForce); + float value = 1024.0; + value = this.GetDifficultyFloat("search_view_distance", difficulty, value); + value = this.GetDifficultyFloat("search_range", difficulty, value); + return value; } - profileData.DissolveRagdoll = kv.GetNum("dissolve_ragdoll_on_kill", profileData.DissolveRagdoll) != 0; - if (profileData.DissolveRagdoll) + + public ProfileMasterAnimations GetAnimations() { - profileData.DissolveKillType = kv.GetNum("dissolve_ragdoll_type", profileData.DissolveKillType); + return view_as(this.GetSection("animations")); } - profileData.PlasmaRagdoll = kv.GetNum("plasma_ragdoll_on_kill", profileData.PlasmaRagdoll) != 0; - profileData.ResizeRagdoll = kv.GetNum("resize_ragdoll_on_kill", profileData.ResizeRagdoll) != 0; - if (profileData.ResizeRagdoll) + + public BossProfileCopies GetCopies() { - profileData.ResizeRagdollHead = kv.GetFloat("resize_ragdoll_head", profileData.ResizeRagdollHead); - profileData.ResizeRagdollHands = kv.GetFloat("resize_ragdoll_hands", profileData.ResizeRagdollHands); - profileData.ResizeRagdollTorso = kv.GetFloat("resize_ragdoll_torso", profileData.ResizeRagdollTorso); + ProfileObject obj = this.GetSection("copies"); + if (obj == null) + { + obj = this; + } + return view_as(obj); } - profileData.DecapOrGibRagdoll = kv.GetNum("decap_or_gib_ragdoll_on_kill", profileData.DecapOrGibRagdoll) != 0; - profileData.SilentKill = kv.GetNum("silent_kill", profileData.SilentKill) != 0; - profileData.MultiEffectRagdoll = kv.GetNum("multieffect_ragdoll_on_kill", profileData.MultiEffectRagdoll) != 0; - profileData.CustomDeathFlag = kv.GetNum("attack_custom_deathflag_enabled", profileData.CustomDeathFlag) != 0; - if (profileData.CustomDeathFlag) + + public BossProfileCompanions GetCompanions() { - profileData.CustomDeathFlagType = kv.GetNum("attack_custom_deathflag", profileData.CustomDeathFlagType); + return view_as(this.GetSection("companions")); } - profileData.OutroMusic = kv.GetNum("sound_music_outro_enabled", profileData.OutroMusic) != 0; - - profileData.EngineSoundLevel = kv.GetNum("constant_sound_level", profileData.EngineSoundLevel); - profileData.EngineSoundLevel = kv.GetNum("engine_sound_level", profileData.EngineSoundLevel); - profileData.EngineSoundVolume = kv.GetFloat("constant_sound_volume", profileData.EngineSoundVolume); - profileData.EngineSoundVolume = kv.GetFloat("engine_sound_volume", profileData.EngineSoundVolume); - - kv.GetVector("eye_pos", profileData.EyePosOffset, profileData.EyePosOffset); - kv.GetVector("eye_ang_offset", profileData.EyeAngOffset, profileData.EyeAngOffset); - - if (kv.JumpToKey("eyes")) + public BossProfileProxyData GetProxies() { - profileData.EyeData.Load(kv); - kv.GoBack(); - profileData.EyePosOffset = profileData.EyeData.OffsetPos; - profileData.EyeAngOffset = profileData.EyeData.OffsetAng; + return view_as(this.GetSection("proxies")); } - if (kv.JumpToKey("slaughter_run")) + public BossProfileDeathCamData GetDeathCamData() { - profileData.SlaughterRunData.Load(kv); - kv.GoBack(); + return view_as(this); } - // Parse through flags. - int bossFlags = 0; - if (kv.GetNum("static_on_look")) + property bool IsPvEBoss { - bossFlags |= SFF_STATICONLOOK; + public get() + { + bool val = this.GetBool("is_pve", false); + ProfileObject obj = this.GetSection("pve"); + if (obj != null) + { + val = true; + } + return val; + } } - if (kv.GetNum("static_on_radius")) + + property ProfileObject PvESpawnMessagesArray { - bossFlags |= SFF_STATICONRADIUS; + public get() + { + ProfileObject obj = this.GetSection("pve"); + if (obj != null) + { + return obj.GetSection("spawn_messages"); + } + return this.GetSection("pve_spawn_messages"); + } } - if (kv.GetNum("proxies")) + + public void GetPvESpawnMessagePrefix(char[] buffer, int bufferSize) { - bossFlags |= SFF_PROXIES; + ProfileObject obj = this.GetSection("pve"); + if (obj != null) + { + obj.GetString("spawn_message_prefix", buffer, bufferSize); + } + else + { + this.GetString("pve_spawn_message_prefix", buffer, bufferSize); + } } - if (kv.GetNum("jumpscare")) + + property bool DisplayPvEHealth { - bossFlags |= SFF_HASJUMPSCARE; + public get() + { + ProfileObject obj = this.GetSection("pve"); + if (obj != null) + { + return obj.GetBool("health_bar", true); + } + return this.GetBool("pve_health_bar", true); + } } - if (kv.GetNum("sound_static_loop_local_enabled")) + + property float PvETeleportEndTimer { - bossFlags |= SFF_HASSTATICLOOPLOCALSOUND; + public get() + { + float def = 5.0; + ProfileObject obj = this.GetSection("pve"); + if (obj != null) + { + return obj.GetFloat("teleport_players_time", def); + } + return def; + } } - if (kv.GetNum("view_shake", 1)) + + property bool CustomOutlines { - bossFlags |= SFF_HASVIEWSHAKE; + public get() + { + return this.GetBool("customizable_outlines", false); + } } - if (kv.GetNum("wander_move", 1)) + + public void GetOutlineColor(int buffer[4]) { - bossFlags |= SFF_WANDERMOVE; + buffer[0] = this.GetInt("outline_color_r", 255); + buffer[1] = this.GetInt("outline_color_g", 255); + buffer[2] = this.GetInt("outline_color_b", 255); + buffer[3] = this.GetInt("outline_color_transparency", 255); } - if (kv.GetNum("attack_props", 0)) + + property bool RainbowOutline { - bossFlags |= SFF_ATTACKPROPS; + public get() + { + return this.GetBool("enable_rainbow_outline", false); + } } - if (kv.GetNum("attack_weaponsenable", 0)) + + property float RainbowOutlineCycle { - bossFlags |= SFF_WEAPONKILLS; + public get() + { + return this.GetFloat("rainbow_outline_cycle_rate", 1.0); + } } - if (kv.GetNum("kill_weaponsenable", 0)) + + public void GetStaticSound(char[] buffer, int bufferSize) { - bossFlags |= SFF_WEAPONKILLSONRADIUS; + ProfileObject obj = this.GetSection("sound_static"); + if (obj != null) + { + obj.GetString("1", buffer, bufferSize); + } } - if (kv.GetNum("static_shake"), 0) + + public void GetStaticLocalLoopSound(char[] buffer, int bufferSize) { - bossFlags |= SFF_HASSTATICSHAKE; + ProfileObject obj = this.GetSection("sound_static_loop_local"); + if (obj != null) + { + obj.GetString("1", buffer, bufferSize); + } } - profileData.Flags = bossFlags; - profileData.CopiesInfo.Load(kv); + public void GetStaticShakeLocalSound(char[] buffer, int bufferSize) + { + ProfileObject obj = this.GetSection("sound_static_shake_local"); + if (obj != null) + { + obj.GetString("1", buffer, bufferSize); + } + } - if (profileData.Flags & SFF_PROXIES) + property float StaticShakeMinVolume { - kv.GetString("proxies_classes", profileData.ProxyClasses, sizeof(profileData.ProxyClasses), profileData.ProxyClasses); - GetProfileDifficultyFloatValues(kv, "proxies_damage_scale_vs_enemy", profileData.ProxyDamageVsEnemy, profileData.ProxyDamageVsEnemy); - GetProfileDifficultyFloatValues(kv, "proxies_damage_scale_vs_enemy_backstab", profileData.ProxyDamageVsBackstab, profileData.ProxyDamageVsBackstab); - GetProfileDifficultyFloatValues(kv, "proxies_damage_scale_vs_self", profileData.ProxyDamageVsSelf, profileData.ProxyDamageVsSelf); - GetProfileDifficultyNumValues(kv, "proxies_controlgain_hitenemy", profileData.ProxyControlGainHitEnemy, profileData.ProxyControlGainHitEnemy); - GetProfileDifficultyNumValues(kv, "proxies_controlgain_hitbyenemy", profileData.ProxyControlGainHitByEnemy, profileData.ProxyControlGainHitByEnemy); - GetProfileDifficultyFloatValues(kv, "proxies_controldrainrate", profileData.ProxyControlDrainRate, profileData.ProxyControlDrainRate); - GetProfileDifficultyNumValues(kv, "proxies_max", profileData.MaxProxies, profileData.MaxProxies); - GetProfileDifficultyFloatValues(kv, "proxies_spawn_chance_min", profileData.ProxySpawnChanceMin, profileData.ProxySpawnChanceMin); - GetProfileDifficultyFloatValues(kv, "proxies_spawn_chance_max", profileData.ProxySpawnChaceMax, profileData.ProxySpawnChaceMax); - GetProfileDifficultyFloatValues(kv, "proxies_spawn_chance_threshold", profileData.ProxySpawnChanceThreshold, profileData.ProxySpawnChanceThreshold); - GetProfileDifficultyNumValues(kv, "proxies_spawn_num_min", profileData.ProxySpawnNumMin, profileData.ProxySpawnNumMin); - GetProfileDifficultyNumValues(kv, "proxies_spawn_num_max", profileData.ProxySpawnNumMax, profileData.ProxySpawnNumMax); - GetProfileDifficultyFloatValues(kv, "proxies_spawn_cooldown_min", profileData.ProxySpawnCooldownMin, profileData.ProxySpawnCooldownMin); - GetProfileDifficultyFloatValues(kv, "proxies_spawn_cooldown_max", profileData.ProxySpawnCooldownMax, profileData.ProxySpawnCooldownMax); - GetProfileDifficultyFloatValues(kv, "proxies_teleport_range_min", profileData.ProxyTeleportRangeMin, profileData.ProxyTeleportRangeMin); - GetProfileDifficultyFloatValues(kv, "proxies_teleport_range_max", profileData.ProxyTeleportRangeMax, profileData.ProxyTeleportRangeMax); - profileData.ProxyAllowVoices = !!kv.GetNum("proxies_allownormalvoices", profileData.ProxyAllowVoices); - profileData.ProxyWeapons = !!kv.GetNum("proxies_weapon", profileData.ProxyWeapons); - profileData.ProxyDeathAnimations = new ArrayList(ByteCountToCells(PLATFORM_MAX_PATH)); - char className[15], deathSection[64], storedAnim[PLATFORM_MAX_PATH]; - for (int i = 0; i < 10; i++) + public get() { - TF2_GetClassName(view_as(i), className, sizeof(className)); - if (i == 0) - { - deathSection = "proxies_death_anim_all"; - } - else - { - FormatEx(deathSection, sizeof(deathSection), "proxies_death_anim_%s", className); - } - kv.GetString(deathSection, storedAnim, sizeof(storedAnim)); - profileData.ProxyDeathAnimations.PushString(storedAnim); - if (i == 0) - { - deathSection = "proxies_death_anim_frames_all"; - } - else - { - FormatEx(deathSection, sizeof(deathSection), "proxies_death_anim_frames_%s", className); - } - profileData.ProxyDeathAnimFrames[i] = kv.GetNum(deathSection); + return this.GetFloat("sound_static_shake_local_volume_min", 0.0); } - if (profileData.ProxyWeapons) + } + + property float StaticShakeMaxVolume + { + public get() { - profileData.ProxyWeaponClassNames = new ArrayList(ByteCountToCells(PLATFORM_MAX_PATH)); - profileData.ProxyWeaponStats = new ArrayList(ByteCountToCells(PLATFORM_MAX_PATH)); - char classKey[15], keyValue[45], arrayStringValue[PLATFORM_MAX_PATH]; - for (int i = 1; i < 10; i++) - { - TF2_GetClassName(view_as(i), classKey, sizeof(classKey)); + return this.GetFloat("sound_static_shake_local_volume_max", 0.0); + } + } - FormatEx(keyValue, sizeof(keyValue), "proxies_weapon_class_%s", classKey); - kv.GetString(keyValue, arrayStringValue, sizeof(arrayStringValue)); - profileData.ProxyWeaponClassNames.PushString(arrayStringValue); + property int StaticShakeLocalLevel + { + public get() + { + return this.GetInt("sound_static_loop_local_level", SNDLEVEL_NORMAL); + } + } - FormatEx(keyValue, sizeof(keyValue), "proxies_weapon_stats_%s", classKey); - kv.GetString(keyValue, arrayStringValue, sizeof(arrayStringValue)); - profileData.ProxyWeaponStats.PushString(arrayStringValue); + property float BlinkLookRate + { + public get() + { + return this.GetFloat("blink_look_rate_multiply", 1.0); + } + } - FormatEx(keyValue, sizeof(keyValue), "proxies_weapon_index_%s", classKey); - profileData.ProxyWeaponIndexes[i] = kv.GetNum(keyValue, profileData.ProxyWeaponIndexes[i]); + property float BlinkStaticRate + { + public get() + { + return this.GetFloat("blink_static_rate_multiply", 1.0); + } + } - FormatEx(keyValue, sizeof(keyValue), "proxies_weapon_slot_%s", classKey); - profileData.ProxyWeaponSlots[i] = kv.GetNum(keyValue, profileData.ProxyWeaponSlots[i]); - } + public ProfileSound GetIntroSounds() + { + return view_as(this.GetSection("sound_spawn_all")); + } + + public ProfileSound GetLocalSpawnSounds() + { + return view_as(this.GetSection("sound_spawn_local")); + } + + public ProfileSound GetScareSounds() + { + return view_as(this.GetSection("sound_scare_player")); + } + + public ProfileSound GetClientDeathCamSounds() + { + ProfileObject obj = this.GetSection("sound_player_deathcam"); + if (obj == null) + { + obj = this.GetSection("sound_player_death"); } - profileData.ProxySpawnEffect = kv.GetNum("proxies_spawn_effect_enabled", profileData.ProxySpawnEffect) != 0; - if (profileData.ProxySpawnEffect) + return view_as(obj); + } + + public ProfileSound GetGlobalDeathCamSounds() + { + return view_as(this.GetSection("sound_player_deathcam_all")); + } + + public ProfileSound GetLocalDeathCamSounds() + { + return view_as(this.GetSection("sound_player_deathcam_local")); + } + + public ProfileSound GetOverlayDeathCamSounds() + { + return view_as(this.GetSection("sound_player_deathcam_overlay")); + } + + public ProfileSound GetSightSounds() + { + return view_as(this.GetSection("sound_sight")); + } + + public void GetWeaponString(char[] buffer, int bufferSize) + { + this.GetString("kill_weapontype", buffer, bufferSize); + } + + property int WeaponInt + { + public get() { - kv.GetString("proxies_spawn_effect", profileData.ProxySpawnEffectName, sizeof(profileData.ProxySpawnEffectName), profileData.ProxySpawnEffectName); - profileData.ProxySpawnEffectZOffset = kv.GetFloat("proxies_spawn_effect_z_offset", profileData.ProxySpawnEffectZOffset); + return this.GetInt("kill_weapontypeint", 0); } - profileData.ProxyZombies = kv.GetNum("proxies_zombie", profileData.ProxyZombies) != 0; - profileData.ProxyRobots = kv.GetNum("proxies_robot", profileData.ProxyRobots) != 0; - profileData.ProxyDifficultyModels = kv.GetNum("proxy_difficulty_models", profileData.ProxyDifficultyModels) != 0; + } - char index[64], modelDirectory[PLATFORM_MAX_PATH]; - if (profileData.ProxyDifficultyModels) + property bool AshRagdoll + { + public get() { - for (int i = 0; i < 10; i++) - { - for (int j = 1; j < Difficulty_Max; j--) - { - TF2_GetClassName(view_as(i), className, sizeof(className)); - if (i == 0) - { - switch (j) - { - case Difficulty_Normal: - { - deathSection = "mod_proxy_all"; - } - case Difficulty_Hard: - { - deathSection = "mod_proxy_all_hard"; - } - case Difficulty_Insane: - { - deathSection = "mod_proxy_all_insane"; - } - case Difficulty_Nightmare: - { - deathSection = "mod_proxy_all_nightmare"; - } - case Difficulty_Apollyon: - { - deathSection = "mod_proxy_all_apollyon"; - } - } - } - else - { - switch (j) - { - case Difficulty_Normal: - { - FormatEx(deathSection, sizeof(deathSection), "mod_proxy_%s", className); - } - case Difficulty_Hard: - { - FormatEx(deathSection, sizeof(deathSection), "mod_proxy_%s_hard", className); - } - case Difficulty_Insane: - { - FormatEx(deathSection, sizeof(deathSection), "mod_proxy_%s_insane", className); - } - case Difficulty_Nightmare: - { - FormatEx(deathSection, sizeof(deathSection), "mod_proxy_%s_nightmare", className); - } - case Difficulty_Apollyon: - { - FormatEx(deathSection, sizeof(deathSection), "mod_proxy_%s_apollyon", className); - } - } - } - if (kv.JumpToKey(deathSection)) - { - switch (j) - { - case Difficulty_Normal: - { - profileData.ProxyModels[i] = new ArrayList(ByteCountToCells(PLATFORM_MAX_PATH)); - } - case Difficulty_Hard: - { - profileData.ProxyModelsHard[i] = new ArrayList(ByteCountToCells(PLATFORM_MAX_PATH)); - } - case Difficulty_Insane: - { - profileData.ProxyModelsInsane[i] = new ArrayList(ByteCountToCells(PLATFORM_MAX_PATH)); - } - case Difficulty_Nightmare: - { - profileData.ProxyModelsNightmare[i] = new ArrayList(ByteCountToCells(PLATFORM_MAX_PATH)); - } - case Difficulty_Apollyon: - { - profileData.ProxyModelsApollyon[i] = new ArrayList(ByteCountToCells(PLATFORM_MAX_PATH)); - } - } - for (int i2 = 1;; i2++) - { - FormatEx(index, sizeof(index), "%d", i2); - kv.GetString(index, modelDirectory, sizeof(modelDirectory)); - if (modelDirectory[0] == '\0') - { - break; - } + return this.GetBool("disintegrate_ragdoll_on_kill", false); + } + } - if (!PrecacheModel(modelDirectory, true)) - { - LogSF2Message("Proxy model file %s failed to be precached, this model will not be used.", modelDirectory); - } - else - { - switch (j) - { - case Difficulty_Normal: - { - profileData.ProxyModels[i].PushString(modelDirectory); - } - case Difficulty_Hard: - { - profileData.ProxyModelsHard[i].PushString(modelDirectory); - } - case Difficulty_Insane: - { - profileData.ProxyModelsInsane[i].PushString(modelDirectory); - } - case Difficulty_Nightmare: - { - profileData.ProxyModelsNightmare[i].PushString(modelDirectory); - } - case Difficulty_Apollyon: - { - profileData.ProxyModelsApollyon[i].PushString(modelDirectory); - } - } - PrecacheModel2(modelDirectory, _, _, g_FileCheckConVar.BoolValue); - } - } - kv.GoBack(); - } - } - } - } - else + property bool CloakRagdoll + { + public get() { - for (int i = 0; i < 10; i++) - { - TF2_GetClassName(view_as(i), className, sizeof(className)); - if (i == 0) - { - deathSection = "mod_proxy_all"; - } - else - { - FormatEx(deathSection, sizeof(deathSection), "mod_proxy_%s", className); - } - if (kv.JumpToKey(deathSection)) - { - profileData.ProxyModels[i] = new ArrayList(ByteCountToCells(PLATFORM_MAX_PATH)); - for (int i2 = 1;; i2++) - { - FormatEx(index, sizeof(index), "%d", i2); - kv.GetString(index, modelDirectory, sizeof(modelDirectory)); - if (modelDirectory[0] == '\0') - { - break; - } - - if (!PrecacheModel(modelDirectory, true)) - { - LogSF2Message("Proxy model file %s failed to be precached, this model will not be used.", modelDirectory); - } - else - { - profileData.ProxyModels[i].PushString(modelDirectory); - } - } - kv.GoBack(); - } - } + return this.GetBool("cloak_ragdoll_on_kill", false); } + } - profileData.ProxyOverrideMaxSpeed = !!kv.GetNum("proxies_override_max_speed", profileData.ProxyOverrideMaxSpeed); - if (profileData.ProxyOverrideMaxSpeed) + property bool DecapRagdoll + { + public get() { - GetProfileDifficultyFloatValues(kv, "proxies_max_speed", profileData.ProxyMaxSpeed, profileData.ProxyMaxSpeed); + return this.GetBool("decap_ragdoll_on_kill", false); } } - UnloadBossProfile(profile); - - profileData.AnimationData.Load(kv, true); - - switch (profileData.Type) + property bool DeleteRagdoll { - case SF2BossType_Statue: - { - if (!LoadStatueBossProfile(kv, profile, loadFailReasonBuffer, loadFailReasonBufferLen, profileData)) - { - return false; - } - } - case SF2BossType_Chaser: + public get() { - if (!LoadChaserBossProfile(kv, profile, loadFailReasonBuffer, loadFailReasonBufferLen, profileData)) - { - return false; - } + return this.GetBool("delete_ragdoll_on_kill", false); } } - // Add the section to our config. - g_Config.Rewind(); - g_Config.JumpToKey(profile, true); - g_Config.Import(kv); - - kv.GetString("constant_sound", profileData.EngineSound, sizeof(profileData.EngineSound), profileData.EngineSound); - kv.GetString("engine_sound", profileData.EngineSound, sizeof(profileData.EngineSound), profileData.EngineSound); - - TryPrecacheBossProfileSoundPath(profileData.EngineSound, g_FileCheckConVar.BoolValue); - int index = g_BossProfileList.FindString(profile); - if (index == -1) + property bool DissolveRagdoll { - g_BossProfileList.PushString(profile); + public get() + { + return this.GetBool("dissolve_ragdoll_on_kill", false); + } } - if (kv.GetNum("enable_random_selection", true) != 0) + property int DissolveKillType { - if (GetSelectableBossProfileList().FindString(profile) == -1) + public get() { - // Add to the selectable boss list if it isn't there already. - GetSelectableBossProfileList().PushString(profile); + return this.GetInt("dissolve_ragdoll_type", 0); } } - else + + property bool ElectrocuteRagdoll { - int selectIndex = GetSelectableBossProfileList().FindString(profile); - if (selectIndex != -1) + public get() { - GetSelectableBossProfileList().Erase(selectIndex); + return this.GetBool("electrocute_ragdoll_on_kill", false); } } - if (kv.GetNum("admin_only", false) != 0) + property bool GoldRagdoll { - if (GetSelectableAdminBossProfileList().FindString(profile) == -1) + public get() { - // Add to the selectable boss list if it isn't there already. - GetSelectableAdminBossProfileList().PushString(profile); + return this.GetBool("gold_ragdoll_on_kill", false); } } - else + + property bool IceRagdoll { - int selectIndex = GetSelectableAdminBossProfileList().FindString(profile); - if (selectIndex != -1) + public get() { - GetSelectableAdminBossProfileList().Erase(selectIndex); + return this.GetBool("ice_ragdoll_on_kill", false); } } - if (kv.GetNum("enable_random_selection_boxing", false) != 0) + property bool PlasmaRagdoll { - if (GetSelectableBoxingBossProfileList().FindString(profile) == -1) + public get() { - // Add to the selectable boss list if it isn't there already. - GetSelectableBoxingBossProfileList().PushString(profile); + return this.GetBool("plasma_ragdoll_on_kill", false); } } - else + + property bool PushRagdoll { - int selectIndex = GetSelectableBoxingBossProfileList().FindString(profile); - if (selectIndex != -1) + public get() { - GetSelectableBoxingBossProfileList().Erase(selectIndex); + return this.GetBool("push_ragdoll_on_kill", false); } } - if (kv.GetNum("enable_random_selection_renevant", false) != 0) + public void GetPushRagdollForce(float buffer[3]) { - if (GetSelectableRenevantBossProfileList().FindString(profile) == -1) - { - // Add to the selectable boss list if it isn't there already. - GetSelectableRenevantBossProfileList().PushString(profile); - } + this.GetVector("push_ragdoll_force", buffer); } - else + + property bool ResizeRagdoll { - int selectIndex = GetSelectableRenevantBossProfileList().FindString(profile); - if (selectIndex != -1) + public get() { - GetSelectableRenevantBossProfileList().Erase(selectIndex); + return this.GetBool("resize_ragdoll_on_kill", false); } } - if (kv.GetNum("enable_random_selection_renevant_admin", false) != 0) + property float ResizeRagdollHead { - if (GetSelectableRenevantBossAdminProfileList().FindString(profile) == -1) + public get() { - // Add to the selectable boss list if it isn't there already. - GetSelectableRenevantBossAdminProfileList().PushString(profile); + return this.GetFloat("resize_ragdoll_head", 1.0); } } - else + + property float ResizeRagdollTorso { - int selectIndex = GetSelectableRenevantBossAdminProfileList().FindString(profile); - if (selectIndex != -1) + public get() { - GetSelectableRenevantBossAdminProfileList().Erase(selectIndex); + return this.GetFloat("resize_ragdoll_torso", 1.0); } } - if (kv.JumpToKey("pve")) + property float ResizeRagdollHands { - profileData.IsPvEBoss = true; - kv.GoBack(); + public get() + { + return this.GetFloat("resize_ragdoll_hands", 1.0); + } } - else + + property bool BurnRagdoll { - profileData.IsPvEBoss = kv.GetNum("is_pve", profileData.IsPvEBoss) != 0; + public get() + { + return this.GetBool("burn_ragdoll_on_kill", false); + } } - if (profileData.IsPvEBoss) + property bool GibRagdoll { - profileData.Flags = profileData.Flags & ~SFF_PROXIES; - if (kv.JumpToKey("pve")) + public get() { - if (kv.JumpToKey("spawn_messages")) - { - profileData.PvESpawnMessagesArray = new ArrayList(ByteCountToCells(PLATFORM_MAX_PATH)); - char message[256], section[64]; - for (int i = 1;; i++) - { - FormatEx(section, sizeof(section), "%d", i); - kv.GetString(section, message, sizeof(message)); - if (message[0] == '\0') - { - break; - } - - profileData.PvESpawnMessagesArray.PushString(message); - } - kv.GoBack(); - } - kv.GetString("spawn_message_prefix", profileData.PvESpawnMessagePrefix, sizeof(profileData.PvESpawnMessagePrefix), profileData.PvESpawnMessagePrefix); - profileData.DisplayPvEHealth = kv.GetNum("health_bar", profileData.DisplayPvEHealth) != 0; - char setProfile[SF2_MAX_PROFILE_NAME_LENGTH]; - strcopy(setProfile, sizeof(setProfile), profile); - if (kv.GetNum("selectable", 1) != 0) - { - RegisterPvESlenderBoss(setProfile); - } - profileData.PvETeleportEndTimer = kv.GetFloat("teleport_players_time", profileData.PvETeleportEndTimer); - kv.GoBack(); + return this.GetBool("gib_ragdoll_on_kill", false); } - else - { - if (kv.JumpToKey("pve_spawn_messages")) - { - profileData.PvESpawnMessagesArray = new ArrayList(ByteCountToCells(PLATFORM_MAX_PATH)); - char message[256], section[64]; - for (int i = 1;; i++) - { - FormatEx(section, sizeof(section), "%d", i); - kv.GetString(section, message, sizeof(message)); - if (message[0] == '\0') - { - break; - } + } - profileData.PvESpawnMessagesArray.PushString(message); - } - kv.GoBack(); - } - kv.GetString("pve_spawn_message_prefix", profileData.PvESpawnMessagePrefix, sizeof(profileData.PvESpawnMessagePrefix), profileData.PvESpawnMessagePrefix); - profileData.DisplayPvEHealth = kv.GetNum("pve_health_bar", profileData.DisplayPvEHealth) != 0; - char setProfile[SF2_MAX_PROFILE_NAME_LENGTH]; - strcopy(setProfile, sizeof(setProfile), profile); - if (kv.GetNum("pve_selectable", 1) != 0) - { - RegisterPvESlenderBoss(setProfile); - } + property bool DecapOrGibRagdoll + { + public get() + { + return this.GetBool("decap_or_gib_ragdoll_on_kill", false); } + } - index = GetSelectableBossProfileList().FindString(profile); - if (index != -1) + property bool MultiEffectRagdoll + { + public get() { - GetSelectableBossProfileList().Erase(index); + return this.GetBool("multieffect_ragdoll_on_kill", false); } - index = GetSelectableAdminBossProfileList().FindString(profile); - if (index != -1) + } + + property bool CustomDeathFlag + { + public get() { - GetSelectableAdminBossProfileList().Erase(index); + return this.GetBool("attack_custom_deathflag_enabled", false); } - index = GetSelectableBoxingBossProfileList().FindString(profile); - if (index != -1) + } + + property int CustomDeathFlagType + { + public get() { - GetSelectableBoxingBossProfileList().Erase(index); + return this.GetInt("attack_custom_deathflag", 0); } - index = GetSelectableRenevantBossProfileList().FindString(profile); - if (index != -1) + } + + public void GetConstantSound(char[] buffer, int bufferSize) + { + this.GetString("constant_sound", buffer, bufferSize, buffer); + this.GetString("engine_sound", buffer, bufferSize, buffer); + } + + property int ConstantSoundLevel + { + public get() { - GetSelectableRenevantBossProfileList().Erase(index); + int def = 83; + def = this.GetInt("constant_sound_level", def); + def = this.GetInt("engine_sound_level", def); + return def; } - index = GetSelectableRenevantBossAdminProfileList().FindString(profile); - if (index != -1) + } + + property float ConstantSoundVolume + { + public get() { - GetSelectableRenevantBossAdminProfileList().Erase(index); + float def = 0.8; + def = this.GetFloat("constant_sound_volume", def); + def = this.GetFloat("engine_sound_volume", def); + return def; } } - ArrayList validSections = new ArrayList(ByteCountToCells(128)); + public float GetIdleLifeTime(int difficulty) + { + return this.GetDifficultyFloat("idle_lifetime", difficulty, 10.0); + } - if (kv.GotoFirstSubKey()) //Special thanks to Fire for modifying the code for download errors. + public BossProfileSlaughterRunData GetSlaughterRunData() { - char s2[64], s3[64], s4[PLATFORM_MAX_PATH], s5[PLATFORM_MAX_PATH]; + return view_as(this.GetSection("slaughter_run")); + } - do + public KeyMap_Array GetSpawnEffects() + { + return this.GetArray("spawn_effects"); + } + + public KeyMap_Array GetDespawnEffects() + { + return this.GetArray("despawn_effects"); + } + + property bool HideDespawnEffectsOnDeath + { + public get() { - kv.GetSectionName(s2, sizeof(s2)); + return this.GetBool("hide_on_death", false); + } + } - if (validSections.FindString(s2) != -1) - { - continue; - } + property bool DiscoMode + { + public get() + { + return this.GetBool("disco_mode", false); + } + } - validSections.PushString(s2); + property float DiscoDistanceMin + { + public get() + { + return this.GetFloat("disco_mode_rng_distance_min", 420.0); + } + } - if (StrContains(s2, "sound_") != -1) - { - bool doBack = false; - if (kv.JumpToKey("paths")) - { - doBack = true; - } - for (int i = 1;; i++) - { - FormatEx(s3, sizeof(s3), "%d", i); - kv.GetString(s3, s4, sizeof(s4)); - if (s4[0] == '\0') - { - break; - } + property float DiscoDistanceMax + { + public get() + { + return this.GetFloat("disco_mode_rng_distance_max", 750.0); + } + } - TryPrecacheBossProfileSoundPath(s4, g_FileCheckConVar.BoolValue); + public void GetDiscoPos(float buffer[3]) + { + this.GetVector("disco_mode_pos", buffer); + } - // Here comes an if else mess, I'm very sorry - if (strcmp(s2, "sound_jumpscare") == 0) - { - profileData.JumpscareSound = s4; - break; - } - else if (strcmp(s2, "sound_static") == 0) - { - profileData.StaticSound = s4; - break; - } - else if (strcmp(s2, "sound_static_loop_local") == 0) - { - profileData.StaticLocalSound = s4; - break; - } - else if (strcmp(s2, "sound_static_shake_local") == 0) - { - profileData.StaticShakeLocal = s4; - break; - } - } - if (doBack) - { - kv.GoBack(); - } - profileData.SortSoundSections(kv, s2, g_FileCheckConVar.BoolValue); - } - else if (strcmp(s2, "download") == 0) - { - for (int i = 1;; i++) - { - FormatEx(s3, sizeof(s3), "%d", i); - kv.GetString(s3, s4, sizeof(s4)); - if (s4[0] == '\0') - { - break; - } + property bool FestiveLights + { + public get() + { + return this.GetBool("festive_lights", false); + } + } - if (g_FileCheckConVar.BoolValue) - { - if (FileExists(s4) || FileExists(s4, true)) - { - AddFileToDownloadsTable(s4); - } - else - { - LogSF2Message("File %s does not exist, please fix this download or remove it from the array.", s4); - } - } - else - { - AddFileToDownloadsTable(s4); - } - } - } - else if (strcmp(s2, "mod_precache") == 0) - { - for (int i = 1;; i++) - { - FormatEx(s3, sizeof(s3), "%d", i); - kv.GetString(s3, s4, sizeof(s4)); - if (s4[0] == '\0') - { - break; - } + property int FestiveLightBrightness + { + public get() + { + return this.GetInt("festive_light_brightness", 0); + } + } - if (!PrecacheModel(s4, true)) - { - LogSF2Message("Model file %s failed to be precached, likely does not exist. This will crash the server if not fixed.", s4); - } - } + property float FestiveLightDistance + { + public get() + { + return this.GetFloat("festive_light_distance", 0.0); + } + } + + property float FestiveLightRadius + { + public get() + { + return this.GetFloat("festive_light_radius", 0.0); + } + } + + public void GetFestiveLightPos(float buffer[3]) + { + this.GetVector("festive_lights_pos", buffer); + } + + public void GetFestiveLightAng(float buffer[3]) + { + this.GetVector("festive_lights_ang", buffer); + } + + property float TickRate + { + public get() + { + return this.GetFloat("tick_rate", 0.0); + } + } + + public ProfileMusic GetGlobalMusic(int difficulty) + { + return view_as(this.GetDifficultySection("sound_music", difficulty)); + } + + public float GetGlobalMusicLoop(int difficulty) + { + return this.GetDifficultyFloat("sound_music_loop", difficulty, 0.0); + } + + public ProfileGlobalTracks GetGlobalTracks() + { + ProfileObject obj = this.GetSection("music"); + obj = obj != null ? obj.GetSection("global") : null; + if (obj != null) + { + return view_as(obj); + } + + return null; + } + + property bool OutroMusic + { + public get() + { + return this.GetBool("sound_music_outro_enabled", false); + } + } + + public ProfileSound GetOutroMusics() + { + return view_as(this.GetSection("sound_music_outro")); + } + + public BossProfileAttributes GetAttributes() + { + return view_as(this.GetSection("attributes")); + } + + public BossProfileDescription GetDescription() + { + return view_as(this.GetSection("description")); + } + + public ProfileSound GetFootstepEventSounds(int index) + { + char formatter[64]; + FormatEx(formatter, sizeof(formatter), "sound_footsteps_event_%i", index); + return view_as(this.GetSection(formatter)); + } + + public ProfileSound GetEventSounds(int index) + { + char formatter[64]; + FormatEx(formatter, sizeof(formatter), "sound_event_%i", index); + return view_as(this.GetSection(formatter)); + } + + public BossKillSoundsData GetLocalKillSounds() + { + return view_as(this.GetSection("local_kill_sounds")); + } + + public BossKillSoundsData GetGlobalKillSounds() + { + return view_as(this.GetSection("global_kill_sounds")); + } + + public BossKillSoundsData GetClientKillSounds() + { + return view_as(this.GetSection("client_kill_sounds")); + } + + public void Precache() + { + char path[PLATFORM_MAX_PATH]; + for (int i = 0; i < Difficulty_Max; i++) + { + this.GetModel(i, path, sizeof(path)); + if (path[0] != '\0') + { + PrecacheModel2(path, _, _, g_FileCheckConVar.BoolValue); } - else if (strcmp(s2, "mat_download") == 0) + } + + path[0] = '\0'; + this.GetConstantSound(path, sizeof(path)); + if (path[0] != '\0') + { + PrecacheSound2(path, g_FileCheckConVar.BoolValue); + } + + ProfileObject newObj = null, temp = null, temp2 = null, temp3 = null, temp4 = null; + ArrayList keys = new ArrayList(ByteCountToCells(256)); + if (this.GetAnimations() != null) + { + for (int i = 0; i < this.GetAnimations().SectionLength; i++) { - for (int i = 1;; i++) + char animType[64], name[64], formatter[256]; + int size = 0; + this.GetAnimations().GetSectionNameFromIndex(i, animType, sizeof(animType)); + temp = this.GetAnimations().GetSection(animType); + for (int i2 = 0; i2 < temp.SectionLength; i2++) { - FormatEx(s3, sizeof(s3), "%d", i); - kv.GetString(s3, s4, sizeof(s4)); - if (s4[0] == '\0') - { - break; - } - - FormatEx(s5, sizeof(s5), "%s.vtf", s4); - if (g_FileCheckConVar.BoolValue) + temp.GetSectionNameFromIndex(i2, name, sizeof(name)); + temp2 = temp.GetSection(name); + for (int i3 = 0; i3 < temp2.KeyLength; i3++) { - if (FileExists(s5) || FileExists(s5, true)) - { - AddFileToDownloadsTable(s5); - } - else + temp2.GetKeyNameFromIndex(i3, name, sizeof(name)); + FormatEx(formatter, sizeof(formatter), "animation_%s", animType); + if (strcmp(name, formatter) == 0) { - LogSF2Message("Texture file %s does not exist, please fix this download or remove it from the array.", s5); - } - } - else - { - AddFileToDownloadsTable(s5); - } + size = temp2.GetKeyValueLength(name); - FormatEx(s5, sizeof(s5), "%s.vmt", s4); - if (g_FileCheckConVar.BoolValue) - { - if (FileExists(s5) || FileExists(s5, true)) - { - AddFileToDownloadsTable(s5); - } - else - { - LogSF2Message("Material file %s does not exist, please fix this download or remove it from the array.", s5); } } - else - { - AddFileToDownloadsTable(s5); - } } } - else if (strcmp(s2, "mod_download") == 0) + } + else + { + keys.PushString("animation_idle"); + keys.PushString("animation_walk"); + keys.PushString("animation_walkalert"); + keys.PushString("animation_attack"); + keys.PushString("animation_shoot"); + keys.PushString("animation_run"); + keys.PushString("animation_chaseinitial"); + keys.PushString("animation_rage"); + keys.PushString("animation_stun"); + keys.PushString("animation_death"); + keys.PushString("animation_spawn"); + keys.PushString("animation_fleestart"); + keys.PushString("animation_heal"); + keys.PushString("animation_deathcam"); + keys.PushString("animation_crawlwalk"); + keys.PushString("animation_crawlrun"); + if (this.ContainsAnyDifficultyKey(keys)) { - for (int i = 1;; i++) - { - FormatEx(s3, sizeof(s3), "%d", i); - kv.GetString(s3, s4, sizeof(s4)); - if (s4[0] == '\0') - { - break; - } - - PrecacheModel2(s4, _, _, g_FileCheckConVar.BoolValue); - } + newObj = this.InsertNewSection("animations"); + this.InsertAnimationSection("idle", newObj); + this.InsertAnimationSection("walk", newObj); + this.InsertAnimationSection("walkalert", newObj); + this.InsertAnimationSection("attack", newObj); + this.InsertAnimationSection("shoot", newObj); + this.InsertAnimationSection("run", newObj); + this.InsertAnimationSection("chaseinitial", newObj); + this.InsertAnimationSection("rage", newObj); + this.InsertAnimationSection("stun", newObj); + this.InsertAnimationSection("death", newObj); + this.InsertAnimationSection("spawn", newObj); + this.InsertAnimationSection("fleestart", newObj); + this.InsertAnimationSection("heal", newObj); + this.InsertAnimationSection("deathcam", newObj); + this.InsertAnimationSection("crawlwalk", newObj); + this.InsertAnimationSection("crawlrun", newObj); } - else if (strcmp(s2, "overlay_player_death") == 0) + } + + char particle[128], sound[PLATFORM_MAX_PATH]; + float offset[3]; + this.GetVector("tp_effect_origin", offset, offset); + if (this.GetBool("tp_effect_spawn")) + { + newObj = this.InsertNewSection("spawn_effects"); + temp = newObj.InsertNewSection("Legacy Spawn"); + temp2 = temp.InsertNewSection("effects"); + this.GetString("tp_effect_spawn_particle", particle, sizeof(particle)); + this.GetString("tp_effect_spawn_sound", sound, sizeof(sound)); + if (particle[0] != '\0') { - kv.GetString("1", s4, sizeof(s4)); - profileData.OverlayPlayerDeath = s4; + temp3 = temp2.InsertNewSection("particle"); + temp3.SetString("type", "particle"); + temp3.SetString("particlename", particle); + temp3.SetVector("origin", offset); } - else if (strcmp(s2, "overlay_jumpscare") == 0) + + if (sound[0] != '\0') { - kv.GetString("1", s4, sizeof(s4)); - profileData.OverlayJumpscare = s4; + float defFloat = 1.0; + defFloat = this.GetFloat("tp_effect_spawn_sound_volume", defFloat); + int defInt = 100; + defInt = this.GetInt("tp_effect_spawn_sound_pitch", defInt); + + temp3 = temp2.InsertNewSection("sound"); + temp3.SetString("type", "sound"); + temp4 = temp3.InsertNewSection("paths"); + temp4.SetString("1", sound); + temp3.SetFloat("volume", defFloat); + temp3.SetInt("pitch", defInt); } - if (StrContains(s2, "sound_footsteps_event_") != -1) - { - if (profileData.FootstepEventSounds == null) - { - profileData.FootstepEventSounds = new ArrayList(sizeof(SF2BossProfileSoundInfo)); - } - if (profileData.FootstepEventIndexes == null) - { - profileData.FootstepEventIndexes = new ArrayList(); - } + } - SF2BossProfileSoundInfo soundInfo; - soundInfo.Init(); - soundInfo.Load(kv, g_FileCheckConVar.BoolValue); - soundInfo.PostLoad(); - if (soundInfo.Paths != null) - { - strcopy(s3, sizeof(s3), s2); - ReplaceStringEx(s3, sizeof(s3), "sound_footsteps_event_", ""); - int eventNumber = StringToInt(s3); + if (this.GetBool("tp_effect_despawn")) + { + newObj = this.InsertNewSection("despawn_effects"); + temp = newObj.InsertNewSection("Legacy Despawn"); + temp2 = temp.InsertNewSection("effects"); + this.GetString("tp_effect_despawn_particle", particle, sizeof(particle)); + this.GetString("tp_effect_despawn_sound", sound, sizeof(sound)); + if (particle[0] != '\0') + { + temp3 = temp2.InsertNewSection("particle"); + temp3.SetString("type", "particle"); + temp3.SetString("particlename", particle); + temp3.SetVector("origin", offset); + } - profileData.FootstepEventIndexes.Push(eventNumber); - profileData.FootstepEventSounds.PushArray(soundInfo); - } + if (sound[0] != '\0') + { + float defFloat = 1.0; + defFloat = this.GetFloat("tp_effect_despawn_sound_volume", defFloat); + int defInt = 100; + defInt = this.GetInt("tp_effect_despawn_sound_pitch", defInt); + + temp3 = temp2.InsertNewSection("sound"); + temp3.SetString("type", "sound"); + temp4 = temp3.InsertNewSection("paths"); + temp4.SetString("1", sound); + temp3.SetFloat("volume", defFloat); + temp3.SetInt("pitch", defInt); } - else if (StrContains(s2, "sound_event_") != -1) + } + + this.ConvertSectionsSectionToArray("spawn_effects"); + this.ConvertSectionsSectionToArray("despawn_effects"); + + if (this.GetIntroSounds() != null) + { + this.GetIntroSounds().Precache(); + } + + if (this.GetLocalSpawnSounds() != null) + { + this.GetLocalSpawnSounds().Precache(); + } + + if (this.GetScareSounds() != null) + { + this.GetScareSounds().Precache(); + } + + if (this.GetClientDeathCamSounds() != null) + { + this.GetClientDeathCamSounds().Precache(); + } + + if (this.GetGlobalDeathCamSounds() != null) + { + this.GetGlobalDeathCamSounds().Precache(); + } + + if (this.GetLocalDeathCamSounds() != null) + { + this.GetLocalDeathCamSounds().Precache(); + } + + if (this.GetOverlayDeathCamSounds() != null) + { + this.GetOverlayDeathCamSounds().Precache(); + } + + if (this.GetSightSounds() != null) + { + this.GetSightSounds().Precache(); + } + + if (this.GetSpawnEffects() != null) + { + for (int i = 0; i < this.GetSpawnEffects().Length; i++) { - if (profileData.EventSounds == null) - { - profileData.EventSounds = new ArrayList(sizeof(SF2BossProfileSoundInfo)); - } - if (profileData.EventIndexes == null) + ProfileObject obj = view_as(this.GetSpawnEffects().GetSection(i)); + obj = obj != null ? obj.GetSection("effects") : null; + if (obj == null) { - profileData.EventIndexes = new ArrayList(); + continue; } + view_as(obj).Precache(); + } + } - SF2BossProfileSoundInfo soundInfo; - soundInfo.Init(); - soundInfo.Load(kv, g_FileCheckConVar.BoolValue); - soundInfo.PostLoad(); - if (soundInfo.Paths != null) + if (this.GetDespawnEffects() != null) + { + for (int i = 0; i < this.GetDespawnEffects().Length; i++) + { + ProfileObject obj = view_as(this.GetDespawnEffects().GetSection(i)); + obj = obj != null ? obj.GetSection("effects") : null; + if (obj == null) { - strcopy(s3, sizeof(s3), s2); - ReplaceStringEx(s3, sizeof(s3), "sound_event_", ""); - int eventNumber = StringToInt(s3); - - profileData.EventIndexes.Push(eventNumber); - profileData.EventSounds.PushArray(soundInfo); + continue; } + view_as(obj).Precache(); } } - while (kv.GotoNextKey()); - kv.GoBack(); - } + for (int i = 0; i < this.SectionLength; i++) + { + char key[256]; + this.GetSectionNameFromIndex(i, key, sizeof(key)); - delete validSections; + ProfileObject obj = this.GetSection(key); + if (obj != null && StrContains(key, "sound_footsteps_event_") != -1) + { + view_as(obj).Precache(); + } - if (kv.JumpToKey("companions")) - { - profileData.CompanionsArray = new ArrayList(sizeof(SF2BossProfileCompanionsInfo)); + if (obj != null && StrContains(key, "sound_event_") != -1) + { + view_as(obj).Precache(); + } + } - kv.GetString("type", profileData.CompanionSpawnType, sizeof(profileData.CompanionSpawnType)); - if (kv.GotoFirstSubKey()) + for (int i = 1; i < Difficulty_Max; i++) { - do + if (this.GetGlobalMusic(i) != null) { - SF2BossProfileCompanionsInfo companions; - companions.Init(); - companions.Load(kv); - profileData.CompanionsArray.PushArray(companions); - if (lookIntoLoads) - { - char compProfile[SF2_MAX_PROFILE_NAME_LENGTH], otherProfile[SF2_MAX_PROFILE_NAME_LENGTH], dir[PLATFORM_MAX_PATH], file[PLATFORM_MAX_PATH]; - FileType fileType; - DirectoryListing directory = OpenDirectory(originalDir); - while (directory.GetNext(file, sizeof(file), fileType)) - { - if (fileType == FileType_Directory) - { - continue; - } + this.GetGlobalMusic(i).Precache(); + } + } - FormatEx(dir, sizeof(dir), "%s/%s", originalDir, file); + if (this.GetGlobalTracks() != null) + { + this.GetGlobalTracks().Precache(); + } - for (int i = 0; i < companions.Bosses.Length; i++) - { - companions.Bosses.GetString(i, compProfile, sizeof(compProfile)); + if (this.GetLocalKillSounds() != null) + { + this.GetLocalKillSounds().Precache(); + } - KeyValues otherKeys = new KeyValues("root"); - if (!FileToKeyValues(otherKeys, dir)) - { - delete otherKeys; - continue; - } + if (this.GetGlobalKillSounds() != null) + { + this.GetGlobalKillSounds().Precache(); + } - otherKeys.GetSectionName(otherProfile, sizeof(otherProfile)); + if (this.GetClientKillSounds() != null) + { + this.GetClientKillSounds().Precache(); + } - if (strcmp(compProfile, otherProfile) == 0) - { - if (!LoadBossProfile(otherKeys, otherProfile, loadFailReasonBuffer, loadFailReasonBufferLen)) - { - LogSF2Message("(COMPANION) %s...FAILED (reason: %s)", dir, loadFailReasonBuffer); - } - else - { - LogSF2Message("(COMPANION) %s...", otherProfile); - } - } + switch (this.Type) + { + case SF2BossType_Chaser: + { + view_as(this).Precache(); + } - delete otherKeys; - } - } - } + case SF2BossType_Statue: + { + view_as(this).Precache(); } - while (kv.GotoNextKey()); - kv.GoBack(); } - kv.GoBack(); - } - if (kv.JumpToKey("attributes")) - { - profileData.AttributesInfo.Load(kv); + delete keys; } - if (kv.JumpToKey("effects")) + public void InsertAnimationSection(char[] animName, ProfileObject animationSection) { - profileData.EffectsArray = new ArrayList(sizeof(SF2BossProfileBaseEffectInfo)); + ProfileObject temp = null; + char formatter[128], name[64]; - if (kv.GotoFirstSubKey()) + for (int i = 0; i < Difficulty_Max; i++) { - do + FormatEx(formatter, sizeof(formatter), "animation_%s", animName); + if (this.ContainsDifficultyKey(formatter, i)) { - SF2BossProfileBaseEffectInfo effects; - effects.Init(); - effects.ModelScale = profileData.ModelScale; - effects.Load(kv, g_FileCheckConVar.BoolValue); - profileData.EffectsArray.PushArray(effects); + temp = animationSection.InsertNewSection(animName); + temp = temp.InsertNewSection("1"); + this.GetDifficultyString(formatter, i, name, sizeof(name)); + temp.SetDifficultyString("name", i, name); + FormatEx(formatter, sizeof(formatter), "animation_%s_playbackrate", animName); + temp.SetDifficultyFloat("playbackrate", i, this.GetDifficultyFloat(formatter, i, 1.0)); + FormatEx(formatter, sizeof(formatter), "animation_%s_footstepinterval", animName); + temp.SetDifficultyFloat("footstepinterval", i, this.GetDifficultyFloat(formatter, i, 0.0)); } - while (kv.GotoNextKey()); - kv.GoBack(); } - kv.GoBack(); } +} - if (kv.JumpToKey("spawn_effects")) +methodmap BossProfileCopies < ProfileObject +{ + property bool IsLegacy { - if (profileData.SpawnEffects == null) + public get() { - profileData.SpawnEffects = new StringMap(); + char section[64]; + this.GetSectionName(section, sizeof(section)); + return strcmp(section, "copies") != 0; } + } - if (kv.GotoFirstSubKey()) + public bool IsEnabled(int difficulty) + { + bool def = false; + if (this.IsLegacy) { - do - { - char section[64]; - kv.GetSectionName(section, sizeof(section)); - if (kv.JumpToKey("effects")) - { - ArrayList list = new ArrayList(sizeof(SF2BossProfileBaseEffectInfo)); - if (kv.GotoFirstSubKey()) - { - do - { - SF2BossProfileBaseEffectInfo effects; - effects.Init(); - effects.ModelScale = profileData.ModelScale; - effects.Load(kv, g_FileCheckConVar.BoolValue); - if (effects.Type == EffectType_Particle) - { - effects.LifeTime = 0.1; - } - list.PushArray(effects); - } - while (kv.GotoNextKey()); - kv.GoBack(); - } - kv.GoBack(); - profileData.SpawnEffects.SetValue(section, list); - } - } - while (kv.GotoNextKey()); - kv.GoBack(); + return this.GetDifficultyBool("copy", difficulty, def); } - kv.GoBack(); + return this.GetDifficultyBool("enabled", difficulty, def); } - if (kv.JumpToKey("despawn_effects")) + public int GetMinCopies(int difficulty) { - if (profileData.DespawnEffects == null) + int def = 0; + if (this.IsLegacy) { - profileData.DespawnEffects = new StringMap(); + return def; } - profileData.HideDespawnEffectsOnDeath = kv.GetNum("hide_on_death", profileData.HideDespawnEffectsOnDeath) != 0; + return this.GetDifficultyInt("min", difficulty, def); + } - if (kv.GotoFirstSubKey()) + public int GetMaxCopies(int difficulty) + { + int def = 1; + if (this.IsLegacy) { - do - { - char section[64]; - kv.GetSectionName(section, sizeof(section)); - if (kv.JumpToKey("effects")) - { - ArrayList list = new ArrayList(sizeof(SF2BossProfileBaseEffectInfo)); - if (kv.GotoFirstSubKey()) - { - do - { - SF2BossProfileBaseEffectInfo effects; - effects.Init(); - effects.ModelScale = profileData.ModelScale; - effects.Load(kv, g_FileCheckConVar.BoolValue); - if (effects.Type == EffectType_Particle) - { - effects.LifeTime = 0.1; - } - list.PushArray(effects); - } - while (kv.GotoNextKey()); - kv.GoBack(); - } - kv.GoBack(); - profileData.DespawnEffects.SetValue(section, list); - } - } - while (kv.GotoNextKey()); - kv.GoBack(); + return this.GetDifficultyInt("copy_max", difficulty, def); } - kv.GoBack(); + return this.GetDifficultyInt("max", difficulty, def); } - profileData.PostLoad(); + public float GetTeleportDistanceSpacing(int difficulty) + { + float def = 800.0; + if (this.IsLegacy) + { + return this.GetDifficultyFloat("copy_teleport_dist_from_others", difficulty, def); + } + return this.GetDifficultyFloat("teleport_spacing_between", difficulty, def); + } - g_BossProfileData.SetArray(profile, profileData, sizeof(profileData)); + public bool GetFakes(int difficulty) + { + bool def = false; + if (this.IsLegacy) + { + return this.GetDifficultyBool("fake_copies", difficulty, def); + } + return this.GetDifficultyBool("fakes", difficulty, def); + } +} - Call_StartForward(g_OnBossProfileLoadedFwd); - Call_PushString(profile); - Call_PushCell(kv); - Call_Finish(); - - return true; -} - -static SF2BossProfileData g_CachedProfileData; - -int GetBossProfileSkin(const char[] profile) +methodmap BossProfileCompanions < ProfileObject { - g_BossProfileData.GetArray(profile, g_CachedProfileData, sizeof(g_CachedProfileData)); - return g_CachedProfileData.Skin[1]; -} - -int GetBossProfileSkinDifficulty(const char[] profile, int difficulty) -{ - g_BossProfileData.GetArray(profile, g_CachedProfileData, sizeof(g_CachedProfileData)); - return g_CachedProfileData.Skin[difficulty]; -} + public void GetSpawnType(char[] buffer, int bufferSize) + { + this.GetString("type", buffer, bufferSize, "on_spawn"); + } -bool GetBossProfileSkinDifficultyState(const char[] profile) -{ - g_BossProfileData.GetArray(profile, g_CachedProfileData, sizeof(g_CachedProfileData)); - return g_CachedProfileData.SkinDifficultiesOn; -} + public bool DoesGroupExist(char[] group) + { + return this.GetSection(group) != null; + } -int GetBossProfileSkinMax(const char[] profile) -{ - g_BossProfileData.GetArray(profile, g_CachedProfileData, sizeof(g_CachedProfileData)); - return g_CachedProfileData.SkinMax; -} + public float GetWeightFromGroup(char[] group, int difficulty) + { + float def = 1.0; + if (!this.DoesGroupExist(group)) + { + return 0.0; + } + return this.GetSection(group).GetDifficultyFloat("weight", difficulty, def); + } -int GetBossProfileBodyGroups(const char[] profile) -{ - g_BossProfileData.GetArray(profile, g_CachedProfileData, sizeof(g_CachedProfileData)); - return g_CachedProfileData.Body[1]; -} + public ProfileObject GetBossesFromGroup(char[] group) + { + if (!this.DoesGroupExist(group)) + { + return null; + } + ProfileObject obj = this.GetSection(group); + return obj.GetSection("bosses"); + } -int GetBossProfileBodyGroupsDifficulty(const char[] profile, int difficulty) -{ - g_BossProfileData.GetArray(profile, g_CachedProfileData, sizeof(g_CachedProfileData)); - return g_CachedProfileData.Body[difficulty]; -} + public bool DoesGroupExistEx(int group, char[] buffer, int bufferSize) + { + return this.GetSectionNameFromIndex(group, buffer, bufferSize); + } -bool GetBossProfileBodyGroupsDifficultyState(const char[] profile) -{ - g_BossProfileData.GetArray(profile, g_CachedProfileData, sizeof(g_CachedProfileData)); - return g_CachedProfileData.BodyDifficultiesOn; -} + public float GetWeightFromGroupEx(int group, int difficulty) + { + float def = 1.0; + char key[SF2_MAX_PROFILE_NAME_LENGTH]; + if (!this.GetSectionNameFromIndex(group, key, sizeof(key))) + { + return 0.0; + } + return this.GetSection(key).GetDifficultyFloat("weight", difficulty, def); + } -int GetBossProfileBodyGroupsMax(const char[] profile) -{ - g_BossProfileData.GetArray(profile, g_CachedProfileData, sizeof(g_CachedProfileData)); - return g_CachedProfileData.BodyMax; + public ProfileObject GetBossesFromGroupEx(int group) + { + char key[SF2_MAX_PROFILE_NAME_LENGTH]; + if (!this.GetSectionNameFromIndex(group, key, sizeof(key))) + { + return null; + } + ProfileObject obj = this.GetSection(key); + return obj.GetSection("bosses"); + } } -bool GetBossProfileRaidHitbox(const char[] profile) +methodmap BossProfileEyeData < ProfileObject { - g_BossProfileData.GetArray(profile, g_CachedProfileData, sizeof(g_CachedProfileData)); - return g_CachedProfileData.RaidHitbox; -} + property bool IsLegacy + { + public get() + { + char section[64]; + this.GetSectionName(section, sizeof(section)); + return strcmp(section, "eyes") != 0; + } + } -bool GetBossProfileIgnoreNavPrefer(const char[] profile) -{ - g_BossProfileData.GetArray(profile, g_CachedProfileData, sizeof(g_CachedProfileData)); - return g_CachedProfileData.IgnoreNavPrefer; -} + property int Type + { + public get() + { + if (this.IsLegacy) + { + return 0; + } -float GetBossProfileSoundMusicLoop(const char[] profile, int difficulty) -{ - g_BossProfileData.GetArray(profile, g_CachedProfileData, sizeof(g_CachedProfileData)); - return g_CachedProfileData.SoundMusicLoop[difficulty]; -} + char type[64]; + this.GetString("mode", type, sizeof(type), "default"); + if (strcmp(type, "bone") == 0) + { + return 1; + } + return 0; + } + } -int GetBossProfileMaxCopies(const char[] profile, int difficulty) -{ - g_BossProfileData.GetArray(profile, g_CachedProfileData, sizeof(g_CachedProfileData)); - return g_CachedProfileData.CopiesInfo.MaxCopies[difficulty]; -} + public void GetOffsetPos(float buffer[3]) + { + float def[3]; + if (this.Type == 0) + { + def = { 0.0, 0.0, 45.0 }; + } + if (this.IsLegacy) + { + this.GetVector("eye_pos", buffer, def); + } + else + { + this.GetVector("offset_pos", buffer, def); + } + } -float GetBossProfileModelScale(const char[] profile) -{ - g_BossProfileData.GetArray(profile, g_CachedProfileData, sizeof(g_CachedProfileData)); - return g_CachedProfileData.ModelScale; -} + public void GetOffsetAng(float buffer[3]) + { + if (this.IsLegacy) + { + this.GetVector("eye_ang_offset", buffer); + } + else + { + this.GetVector("offset_pos", buffer); + } + } -float GetBossProfileStepSize(const char[] profile) -{ - g_BossProfileData.GetArray(profile, g_CachedProfileData, sizeof(g_CachedProfileData)); - return g_CachedProfileData.StepSize; + public void GetBone(char[] buffer, int bufferSize) + { + this.GetString("bone", buffer, bufferSize); + } } -float GetBossProfileNodeDistanceLookAhead(const char[] profile) +methodmap BossProfileSlaughterRunData < ProfileObject { - g_BossProfileData.GetArray(profile, g_CachedProfileData, sizeof(g_CachedProfileData)); - return g_CachedProfileData.NodeDistanceLookAhead; -} + public bool ShouldUseCustomMinSpeed(int difficulty) + { + if (this == null) + { + return false; + } + return this.GetDifficultyBool("custom_minimum_speed", false); + } -void GetBossProfileRenderColor(const char[] profile, int buffer[4]) -{ - g_BossProfileData.GetArray(profile, g_CachedProfileData, sizeof(g_CachedProfileData)); - buffer = g_CachedProfileData.RenderColor; + public float GetCustomSpawnTime(int difficulty) + { + if (this == null) + { + return -1.0; + } + return this.GetDifficultyFloat("spawn_time", difficulty, -1.0); + } } -int GetBossProfileRenderFX(const char[] profile) +methodmap BossProfileAttributes < ProfileObject { - g_BossProfileData.GetArray(profile, g_CachedProfileData, sizeof(g_CachedProfileData)); - return g_CachedProfileData.RenderFX; + public float GetValue(int attribute) + { + float def = -1.0; + if (this == null) + { + return def; + } + ProfileObject obj = this.GetSection(g_AttributesList[attribute]); + if (obj == null) + { + return def; + } + return obj.GetFloat("value", def); + } } -int GetBossProfileRenderMode(const char[] profile) +methodmap BossProfileDescription < ProfileObject { - g_BossProfileData.GetArray(profile, g_CachedProfileData, sizeof(g_CachedProfileData)); - return g_CachedProfileData.RenderMode; -} + property bool Hidden + { + public get() + { + if (this == null) + { + return false; + } + return this.GetBool("hidden", false); + } + } -int GetBossProfileWeaponString(const char[] profile, char[] buffer, int bufferlen) -{ - g_BossProfileData.GetArray(profile, g_CachedProfileData, sizeof(g_CachedProfileData)); - return strcopy(buffer, bufferlen, g_CachedProfileData.WeaponString); -} + public void GetType(char[] buffer, int bufferSize, char[] def) + { + if (this == null) + { + strcopy(buffer, bufferSize, def); + return; + } + this.GetString("type", buffer, bufferSize, def); + } -int GetBossProfileWeaponInt(const char[] profile) -{ - g_BossProfileData.GetArray(profile, g_CachedProfileData, sizeof(g_CachedProfileData)); - return g_CachedProfileData.WeaponInt; + public void GetDescription(char[] buffer, int bufferSize) + { + char def[64]; + def = "No description provided."; + if (this == null) + { + strcopy(buffer, bufferSize, def); + return; + } + this.GetString("description", buffer, bufferSize, def); + } } -void GetBossProfileHullMins(const char[] profile, float buffer[3]) +methodmap BossProfileParticleData < ProfileObject { - g_BossProfileData.GetArray(profile, g_CachedProfileData, sizeof(g_CachedProfileData)); - buffer = g_CachedProfileData.Mins; -} + public void GetName(char[] buffer, int bufferSize) + { + this.GetString("particle", buffer, bufferSize); + } -void GetBossProfileHullMaxs(const char[] profile, float buffer[3]) -{ - g_BossProfileData.GetArray(profile, g_CachedProfileData, sizeof(g_CachedProfileData)); - buffer = g_CachedProfileData.Maxs; -} + property bool AttachParticles + { + public get() + { + return this.GetBool("attach", true); + } + } -bool GetBossProfileDiscoModeState(const char[] profile) -{ - g_BossProfileData.GetArray(profile, g_CachedProfileData, sizeof(g_CachedProfileData)); - return g_CachedProfileData.DiscoMode; -} + property bool BeamParticles + { + public get() + { + return this.GetBool("beam", false); + } + } -float GetBossProfileDiscoRadiusMin(const char[] profile) -{ - g_BossProfileData.GetArray(profile, g_CachedProfileData, sizeof(g_CachedProfileData)); - return g_CachedProfileData.DiscoDistanceMin; -} + property ParticleAttachment Type + { + public get() + { + return view_as(this.GetInt("attach_type", view_as(PATTACH_CUSTOMORIGIN))); + } + } -float GetBossProfileDiscoRadiusMax(const char[] profile) -{ - g_BossProfileData.GetArray(profile, g_CachedProfileData, sizeof(g_CachedProfileData)); - return g_CachedProfileData.DiscoDistanceMax; -} + public void GetAttachment(char[] buffer, int bufferSize) + { + this.GetString("attachment", buffer, bufferSize); + } -void GetBossProfileDiscoPosition(const char[] profile, float buffer[3]) -{ - g_BossProfileData.GetArray(profile, g_CachedProfileData, sizeof(g_CachedProfileData)); - buffer = g_CachedProfileData.DiscoPos; -} + public void Apply(CBaseAnimating target, CBaseAnimating caster) + { + CBaseAnimating castTo; + float myPos[3], myAng[3], targetPos[3]; + if (!this.AttachParticles || this.BeamParticles) + { + caster.WorldSpaceCenter(myPos); + caster.GetAbsAngles(myAng); + target.WorldSpaceCenter(targetPos); + if (this.AttachParticles) + { + castTo = caster; + } + } + else + { + target.WorldSpaceCenter(myPos); + target.GetAbsAngles(myAng); + castTo = target; + } -bool GetBossProfileFestiveLightState(const char[] profile) -{ - g_BossProfileData.GetArray(profile, g_CachedProfileData, sizeof(g_CachedProfileData)); - return g_CachedProfileData.FestiveLights; -} + int attachment = 0; + char name[128], attachmentName[64]; + this.GetAttachment(attachmentName, sizeof(attachmentName)); + this.GetName(name, sizeof(name)); + if (attachmentName[0] != '\0') + { + attachment = castTo.LookupAttachment(attachmentName); + } + if (attachment != 0) + { + castTo.GetAttachment(attachment, myPos, myAng); + } -int GetBossProfileFestiveLightBrightness(const char[] profile) -{ - g_BossProfileData.GetArray(profile, g_CachedProfileData, sizeof(g_CachedProfileData)); - return g_CachedProfileData.FestiveLightBrightness; -} + if (this.Type == PATTACH_ROOTBONE_FOLLOW) + { + myPos = NULL_VECTOR; + myAng = NULL_VECTOR; + } -float GetBossProfileFestiveLightDistance(const char[] profile) -{ - g_BossProfileData.GetArray(profile, g_CachedProfileData, sizeof(g_CachedProfileData)); - return g_CachedProfileData.FestiveLightDistance; -} + if (this.BeamParticles) + { + DispatchParticleEffectBeam(castTo.index, name, myPos, myAng, targetPos, attachment, this.Type, true); + } + else + { + if (!DispatchParticleEffect(castTo.index, name, myPos, myAng, myPos, attachment, this.Type, true)) + { + if (this.Type == PATTACH_ROOTBONE_FOLLOW) + { + castTo.WorldSpaceCenter(myPos); + castTo.GetAbsAngles(myAng); + } + CBaseEntity particleEnt = CBaseEntity(CreateEntityByName("info_particle_system")); + if (particleEnt.IsValid()) + { + particleEnt.Teleport(myPos, myAng, NULL_VECTOR); -float GetBossProfileFestiveLightRadius(const char[] profile) -{ - g_BossProfileData.GetArray(profile, g_CachedProfileData, sizeof(g_CachedProfileData)); - return g_CachedProfileData.FestiveLightRadius; + particleEnt.KeyValue("effect_name", name); + particleEnt.Spawn(); + particleEnt.Activate(); + particleEnt.AcceptInput("start"); + RemoveEntity(particleEnt.index); + } + } + } + } } -void GetBossProfileFestiveLightPosition(const char[] profile, float buffer[3]) +methodmap BossKillSoundsData < ProfileObject { - g_BossProfileData.GetArray(profile, g_CachedProfileData, sizeof(g_CachedProfileData)); - buffer = g_CachedProfileData.FestiveLightPos; -} + public ProfileSound GetKilledAllSounds() + { + return view_as(this.GetSection("player")); + } -void GetBossProfileFestiveLightAngles(const char[] profile, float buffer[3]) -{ - g_BossProfileData.GetArray(profile, g_CachedProfileData, sizeof(g_CachedProfileData)); - buffer = g_CachedProfileData.FestiveLightAng; -} + public ProfileSound GetKilledClassSounds(TFClassType class) + { + switch (class) + { + case TFClass_Scout: + { + return view_as(this.GetSection("scout")); + } -ArrayList GetBossProfileNames(const char[] profile) -{ - g_BossProfileData.GetArray(profile, g_CachedProfileData, sizeof(g_CachedProfileData)); - return g_CachedProfileData.Names; -} + case TFClass_Soldier: + { + return view_as(this.GetSection("soldier")); + } -ArrayList GetBossProfileModels(const char[] profile) -{ - g_BossProfileData.GetArray(profile, g_CachedProfileData, sizeof(g_CachedProfileData)); - return g_CachedProfileData.Models; -} + case TFClass_Pyro: + { + return view_as(this.GetSection("pyro")); + } -int GetBossProfileType(const char[] profile) -{ - g_BossProfileData.GetArray(profile, g_CachedProfileData, sizeof(g_CachedProfileData)); - return g_CachedProfileData.Type; -} + case TFClass_DemoMan: + { + return view_as(this.GetSection("demoman")); + } -int GetBossProfileFlags(const char[] profile) -{ - g_BossProfileData.GetArray(profile, g_CachedProfileData, sizeof(g_CachedProfileData)); - return g_CachedProfileData.Flags; -} + case TFClass_Heavy: + { + return view_as(this.GetSection("heavy")); + } -float GetBossProfileBlinkLookRate(const char[] profile) -{ - g_BossProfileData.GetArray(profile, g_CachedProfileData, sizeof(g_CachedProfileData)); - return g_CachedProfileData.BlinkLookRate; -} + case TFClass_Engineer: + { + return view_as(this.GetSection("engineer")); + } -float GetBossProfileBlinkStaticRate(const char[] profile) -{ - g_BossProfileData.GetArray(profile, g_CachedProfileData, sizeof(g_CachedProfileData)); - return g_CachedProfileData.BlinkStaticRate; -} + case TFClass_Medic: + { + return view_as(this.GetSection("medic")); + } -bool GetBossProfileDeathCamState(const char[] profile) -{ - g_BossProfileData.GetArray(profile, g_CachedProfileData, sizeof(g_CachedProfileData)); - return g_CachedProfileData.DeathCam; -} + case TFClass_Sniper: + { + return view_as(this.GetSection("sniper")); + } -bool GetBossProfileDeathCamScareSound(const char[] profile) -{ - g_BossProfileData.GetArray(profile, g_CachedProfileData, sizeof(g_CachedProfileData)); - return g_CachedProfileData.DeathCamScareSound; -} + case TFClass_Spy: + { + return view_as(this.GetSection("spy")); + } + } + return this.GetKilledAllSounds(); + } -bool GetBossProfilePublicDeathCamState(const char[] profile) -{ - g_BossProfileData.GetArray(profile, g_CachedProfileData, sizeof(g_CachedProfileData)); - return g_CachedProfileData.PublicDeathCam; -} + public void Precache() + { + if (this.GetKilledAllSounds() != null) + { + this.GetKilledAllSounds().Precache(); + } -float GetBossProfilePublicDeathCamSpeed(const char[] profile) -{ - g_BossProfileData.GetArray(profile, g_CachedProfileData, sizeof(g_CachedProfileData)); - return g_CachedProfileData.PublicDeathCamSpeed; + for (int i = 1; i <= view_as(TFClass_Engineer); i++) + { + if (this.GetKilledClassSounds(view_as(i)) != null) + { + this.GetKilledClassSounds(view_as(i)).Precache(); + } + } + } } -float GetBossProfilePublicDeathCamAcceleration(const char[] profile) +/** + * Loads a profile in the current KeyValues position in kv. + */ +/*bool LoadBossProfile(const char[] profile, char[] loadFailReasonBuffer, int loadFailReasonBufferLen, bool lookIntoLoads = false, const char[] originalDir = "") { - g_BossProfileData.GetArray(profile, g_CachedProfileData, sizeof(g_CachedProfileData)); - return g_CachedProfileData.PublicDeathCamAcceleration; -} + SF2BossProfileData profileData; + profileData.Init(); -float GetBossProfilePublicDeathCamDeceleration(const char[] profile) -{ - g_BossProfileData.GetArray(profile, g_CachedProfileData, sizeof(g_CachedProfileData)); - return g_CachedProfileData.PublicDeathCamDeceleration; -} + if (kv.JumpToKey("map_blacklist")) + { + char s1[4], s2[64], s3[64]; + GetCurrentMap(s3, sizeof(s3)); + for (int i = 1;; i++) + { + FormatEx(s1, sizeof(s1), "%d", i); + kv.GetString(s1, s2, sizeof(s2)); + if (s2[0] == '\0') + { + break; + } -float GetBossProfilePublicDeathCamBackwardOffset(const char[] profile) -{ - g_BossProfileData.GetArray(profile, g_CachedProfileData, sizeof(g_CachedProfileData)); - return g_CachedProfileData.PublicDeathCamBackwardOffset; -} + if (StrContains(s3, s2, false) != -1) + { + FormatEx(loadFailReasonBuffer, loadFailReasonBufferLen, "is blacklisted on %s!", s3); + return false; + } + } -float GetBossProfilePublicDeathCamDownwardOffset(const char[] profile) -{ - g_BossProfileData.GetArray(profile, g_CachedProfileData, sizeof(g_CachedProfileData)); - return g_CachedProfileData.PublicDeathCamDownwardOffset; -} + kv.GoBack(); + } -bool GetBossProfileDeathCamOverlayState(const char[] profile) -{ - g_BossProfileData.GetArray(profile, g_CachedProfileData, sizeof(g_CachedProfileData)); - return g_CachedProfileData.DeathCamOverlay; -} + if (lookIntoLoads) + { + // In this, we're basically just gonna go look for companion bosses and skip them here + bool skip = true; -float GetBossProfileDeathCamOverlayStartTime(const char[] profile) -{ - g_BossProfileData.GetArray(profile, g_CachedProfileData, sizeof(g_CachedProfileData)); - return g_CachedProfileData.DeathCamOverlayStartTime; -} + if (kv.GetNum("enable_random_selection", true) != 0) + { + skip = false; + } -float GetBossProfileDeathCamTime(const char[] profile) -{ - g_BossProfileData.GetArray(profile, g_CachedProfileData, sizeof(g_CachedProfileData)); - return g_CachedProfileData.DeathCamTime; -} + if (kv.GetNum("admin_only", false) != 0) + { + skip = false; + } -float GetBossProfileIdleLifetime(const char[] profile, int difficulty) -{ - g_BossProfileData.GetArray(profile, g_CachedProfileData, sizeof(g_CachedProfileData)); - return g_CachedProfileData.IdleLifeTime[difficulty]; -} + if (kv.GetNum("enable_random_selection_boxing", false) != 0) + { + skip = false; + } -float GetBossProfileStaticRadius(const char[] profile, int difficulty) -{ - g_BossProfileData.GetArray(profile, g_CachedProfileData, sizeof(g_CachedProfileData)); - return g_CachedProfileData.StaticRadius[difficulty]; -} + if (kv.GetNum("enable_random_selection_renevant", false) != 0) + { + skip = false; + } -float GetBossProfileStaticRate(const char[] profile, int difficulty) -{ - g_BossProfileData.GetArray(profile, g_CachedProfileData, sizeof(g_CachedProfileData)); - return g_CachedProfileData.StaticRate[difficulty]; -} + if (kv.GetNum("enable_random_selection_renevant_admin", false) != 0) + { + skip = false; + } -float GetBossProfileStaticRateDecay(const char[] profile, int difficulty) -{ - g_BossProfileData.GetArray(profile, g_CachedProfileData, sizeof(g_CachedProfileData)); - return g_CachedProfileData.StaticRateDecay[difficulty]; -} + if (kv.GetNum("is_pve", false) != 0 && kv.GetNum("pve_selectable", 1) != 0) + { + skip = false; + } -float GetBossProfileStaticGraceTime(const char[] profile, int difficulty) -{ - g_BossProfileData.GetArray(profile, g_CachedProfileData, sizeof(g_CachedProfileData)); - return g_CachedProfileData.StaticGraceTime[difficulty]; -} + if (kv.GetNum("always_load", false) != 0) + { + skip = false; + } -float GetBossProfileStaticScareAmount(const char[] profile) -{ - g_BossProfileData.GetArray(profile, g_CachedProfileData, sizeof(g_CachedProfileData)); - return g_CachedProfileData.StaticScareAmount; -} + if (kv.JumpToKey("pve") && kv.GetNum("selectable", 1) != 0) + { + kv.GoBack(); + skip = false; + } -int GetBossProfileStaticShakeLocalLevel(const char[] profile) -{ - g_BossProfileData.GetArray(profile, g_CachedProfileData, sizeof(g_CachedProfileData)); - return g_CachedProfileData.StaticShakeLocalLevel; -} + if (skip) + { + FormatEx(loadFailReasonBuffer, loadFailReasonBufferLen, "is not selectable, skipping!"); + return false; + } + } -float GetBossProfileStaticShakeLocalVolumeMin(const char[] profile) -{ - g_BossProfileData.GetArray(profile, g_CachedProfileData, sizeof(g_CachedProfileData)); - return g_CachedProfileData.StaticShakeVolumeMin; -} + profileData.Models = new ArrayList(ByteCountToCells(PLATFORM_MAX_PATH)); + profileData.Names = new ArrayList(ByteCountToCells(PLATFORM_MAX_PATH)); + SetProfileDifficultyStringArrayValues(kv, "model", profileData.Models, true); + char modelName[PLATFORM_MAX_PATH]; + for (int i = 0; i < profileData.Models.Length; i++) + { + profileData.Models.GetString(i, modelName, sizeof(modelName)); + if (modelName[0] != '\0' && strcmp(modelName, "models/", true) != 0 && strcmp(modelName, "models\\", true) != 0) + { + PrecacheModel2(modelName, _, _, g_FileCheckConVar.BoolValue); + } + } + SetProfileDifficultyStringArrayValues(kv, "name", profileData.Names); -float GetBossProfileStaticShakeLocalVolumeMax(const char[] profile) -{ - g_BossProfileData.GetArray(profile, g_CachedProfileData, sizeof(g_CachedProfileData)); - return g_CachedProfileData.StaticShakeVolumeMax; -} + profileData.Type = kv.GetNum("type", profileData.Type); + if (profileData.Type == SF2BossType_Unknown || profileData.Type >= SF2BossType_MaxTypes) + { + FormatEx(loadFailReasonBuffer, loadFailReasonBufferLen, "boss type is unknown!"); + return false; + } -bool GetBossProfileTeleportAllowed(const char[] profile, int difficulty) -{ - g_BossProfileData.GetArray(profile, g_CachedProfileData, sizeof(g_CachedProfileData)); - return g_CachedProfileData.TeleportAllowed[difficulty]; -} + profileData.ModelScale = kv.GetFloat("model_scale", profileData.ModelScale); + if (profileData.ModelScale <= 0.0) + { + FormatEx(loadFailReasonBuffer, loadFailReasonBufferLen, "model_scale must be a value greater than 0!"); + return false; + } -float GetBossProfileTeleportTimeMin(const char[] profile, int difficulty) -{ - g_BossProfileData.GetArray(profile, g_CachedProfileData, sizeof(g_CachedProfileData)); - return g_CachedProfileData.TeleportTimeMin[difficulty]; -} + profileData.Skin[1] = kv.GetNum("skin", profileData.Skin[1]); + if (profileData.Skin[1] < 0) + { + FormatEx(loadFailReasonBuffer, loadFailReasonBufferLen, "skin must be a value that is at least 0!"); + return false; + } + GetProfileDifficultyNumValues(kv, "skin", profileData.Skin, profileData.Skin); -float GetBossProfileTeleportTimeMax(const char[] profile, int difficulty) -{ - g_BossProfileData.GetArray(profile, g_CachedProfileData, sizeof(g_CachedProfileData)); - return g_CachedProfileData.TeleportTimeMax[difficulty]; -} + profileData.SkinMax = kv.GetNum("skin_max", profileData.SkinMax); + if (profileData.SkinMax < 0) + { + FormatEx(loadFailReasonBuffer, loadFailReasonBufferLen, "skin_max must be a value that is at least 0!"); + return false; + } -float GetBossProfileTeleportTargetRestPeriod(const char[] profile, int difficulty) -{ - g_BossProfileData.GetArray(profile, g_CachedProfileData, sizeof(g_CachedProfileData)); - return g_CachedProfileData.TeleportRestPeriod[difficulty]; -} + profileData.SkinDifficultiesOn = kv.GetNum("skin_difficulty", profileData.SkinDifficultiesOn) != 0; -float GetBossProfileTeleportTargetStressMin(const char[] profile, int difficulty) -{ - g_BossProfileData.GetArray(profile, g_CachedProfileData, sizeof(g_CachedProfileData)); - return g_CachedProfileData.TeleportStressMin[difficulty]; -} + profileData.Body[1] = kv.GetNum("body", profileData.Body[1]); + if (profileData.Body[1] < 0) + { + FormatEx(loadFailReasonBuffer, loadFailReasonBufferLen, "body must be a value that is at least 0!"); + return false; + } + GetProfileDifficultyNumValues(kv, "body", profileData.Body, profileData.Body); -float GetBossProfileTeleportTargetStressMax(const char[] profile, int difficulty) -{ - g_BossProfileData.GetArray(profile, g_CachedProfileData, sizeof(g_CachedProfileData)); - return g_CachedProfileData.TeleportStressMax[difficulty]; -} + profileData.BodyMax = kv.GetNum("body_max", profileData.BodyMax); + if (profileData.BodyMax < 0) + { + FormatEx(loadFailReasonBuffer, loadFailReasonBufferLen, "body_max must be a value that is at least 0!"); + return false; + } -float GetBossProfileTeleportTargetPersistencyPeriod(const char[] profile, int difficulty) -{ - g_BossProfileData.GetArray(profile, g_CachedProfileData, sizeof(g_CachedProfileData)); - return g_CachedProfileData.TeleportPersistencyPeriod[difficulty]; -} + profileData.BodyDifficultiesOn = kv.GetNum("body_difficulty", profileData.BodyDifficultiesOn) != 0; -float GetBossProfileTeleportRangeMin(const char[] profile, int difficulty) -{ - g_BossProfileData.GetArray(profile, g_CachedProfileData, sizeof(g_CachedProfileData)); - return g_CachedProfileData.TeleportRangeMin[difficulty]; -} + profileData.RaidHitbox = kv.GetNum("use_raid_hitbox", profileData.RaidHitbox) != 0; -float GetBossProfileTeleportRangeMax(const char[] profile, int difficulty) -{ - g_BossProfileData.GetArray(profile, g_CachedProfileData, sizeof(g_CachedProfileData)); - return g_CachedProfileData.TeleportRangeMax[difficulty]; -} + profileData.InstantKillRadius = kv.GetFloat("kill_radius", profileData.InstantKillRadius); -bool GetBossProfileTeleportIgnoreChases(const char[] profile) -{ - g_BossProfileData.GetArray(profile, g_CachedProfileData, sizeof(g_CachedProfileData)); - return g_CachedProfileData.TeleportIgnoreChases; -} + profileData.ScareRadius = kv.GetFloat("scare_radius", profileData.ScareRadius); + if (profileData.ScareRadius < 0.0) + { + FormatEx(loadFailReasonBuffer, loadFailReasonBufferLen, "scare_radius must be a value that is at least 0!"); + return false; + } -bool GetBossProfileTeleportIgnoreVis(const char[] profile) -{ - g_BossProfileData.GetArray(profile, g_CachedProfileData, sizeof(g_CachedProfileData)); - return g_CachedProfileData.TeleportIgnoreVis; -} + profileData.TeleportType = kv.GetNum("teleport_type", profileData.TeleportType); + if (profileData.TeleportType < 0) + { + FormatEx(loadFailReasonBuffer, loadFailReasonBufferLen, "unknown teleport type!"); + return false; + } -float GetBossProfileTeleportCopyDistance(const char[] profile, int difficulty) -{ - g_BossProfileData.GetArray(profile, g_CachedProfileData, sizeof(g_CachedProfileData)); - return g_CachedProfileData.CopiesInfo.TeleportDistanceSpacing[difficulty]; -} + FormatEx(loadFailReasonBuffer, loadFailReasonBufferLen, "unknown!"); -float GetBossProfileJumpscareDistance(const char[] profile, int difficulty) -{ - g_BossProfileData.GetArray(profile, g_CachedProfileData, sizeof(g_CachedProfileData)); - return g_CachedProfileData.JumpscareDistance[difficulty]; -} + profileData.FOV = kv.GetFloat("fov", profileData.FOV); + if (profileData.FOV < 0.0) + { + profileData.FOV = 0.0; + } + else if (profileData.FOV > 360.0) + { + profileData.FOV = 360.0; + } -float GetBossProfileJumpscareDuration(const char[] profile, int difficulty) -{ - g_BossProfileData.GetArray(profile, g_CachedProfileData, sizeof(g_CachedProfileData)); - return g_CachedProfileData.JumpscareDuration[difficulty]; -} + profileData.TurnRate = kv.GetFloat("maxyawrate", profileData.TurnRate); + profileData.TurnRate = kv.GetFloat("turnrate", profileData.TurnRate); -float GetBossProfileJumpscareCooldown(const char[] profile, int difficulty) -{ - g_BossProfileData.GetArray(profile, g_CachedProfileData, sizeof(g_CachedProfileData)); - return g_CachedProfileData.JumpscareCooldown[difficulty]; -} + switch (profileData.Type) + { + case SF2BossType_Chaser: + { + profileData.Description.Type = "Chaser"; + } -int GetBossProfileProxyClasses(const char[] profile, char[] buffer, int bufferlen) -{ - g_BossProfileData.GetArray(profile, g_CachedProfileData, sizeof(g_CachedProfileData)); - return strcopy(buffer, bufferlen, g_CachedProfileData.ProxyClasses); -} + case SF2BossType_Statue: + { + profileData.Description.Type = "Statue"; + } + } -float GetBossProfileProxyDamageVsEnemy(const char[] profile, int difficulty) -{ - g_BossProfileData.GetArray(profile, g_CachedProfileData, sizeof(g_CachedProfileData)); - return g_CachedProfileData.ProxyDamageVsEnemy[difficulty]; -} + if (kv.JumpToKey("description")) + { + profileData.Description.Load(kv); + kv.GoBack(); + } -float GetBossProfileProxyDamageVsBackstab(const char[] profile, int difficulty) -{ - g_BossProfileData.GetArray(profile, g_CachedProfileData, sizeof(g_CachedProfileData)); - return g_CachedProfileData.ProxyDamageVsBackstab[difficulty]; -} + profileData.ScareCooldown = kv.GetFloat("scare_cooldown", profileData.ScareCooldown); + if (profileData.ScareCooldown < 0.0) + { + // clamp value + profileData.ScareCooldown = 0.0; + } -float GetBossProfileProxyDamageVsSelf(const char[] profile, int difficulty) -{ - g_BossProfileData.GetArray(profile, g_CachedProfileData, sizeof(g_CachedProfileData)); - return g_CachedProfileData.ProxyDamageVsSelf[difficulty]; -} + kv.GetVector("mins", profileData.Mins, profileData.Mins); + kv.GetVector("maxs", profileData.Maxs, profileData.Maxs); -int GetBossProfileProxyControlGainHitEnemy(const char[] profile, int difficulty) -{ - g_BossProfileData.GetArray(profile, g_CachedProfileData, sizeof(g_CachedProfileData)); - return g_CachedProfileData.ProxyControlGainHitEnemy[difficulty]; -} + profileData.StepSize = kv.GetFloat("stepsize", profileData.StepSize); -int GetBossProfileProxyControlGainHitByEnemy(const char[] profile, int difficulty) -{ - g_BossProfileData.GetArray(profile, g_CachedProfileData, sizeof(g_CachedProfileData)); - return g_CachedProfileData.ProxyControlGainHitByEnemy[difficulty]; -} + profileData.NodeDistanceLookAhead = kv.GetFloat("search_node_dist_lookahead", profileData.NodeDistanceLookAhead); -float GetBossProfileProxyControlDrainRate(const char[] profile, int difficulty) -{ - g_BossProfileData.GetArray(profile, g_CachedProfileData, sizeof(g_CachedProfileData)); - return g_CachedProfileData.ProxyControlDrainRate[difficulty]; -} + GetProfileColorNoBacks(kv, "effect_rendercolor", profileData.RenderColor[0], profileData.RenderColor[1], profileData.RenderColor[2], profileData.RenderColor[3], + profileData.RenderColor[0], profileData.RenderColor[1], profileData.RenderColor[2], profileData.RenderColor[3]); + profileData.RenderFX = kv.GetNum("effect_renderfx", profileData.RenderFX); + profileData.RenderMode = kv.GetNum("effect_rendermode", profileData.RenderMode); -float GetBossProfileProxySpawnChanceMin(const char[] profile, int difficulty) -{ - g_BossProfileData.GetArray(profile, g_CachedProfileData, sizeof(g_CachedProfileData)); - return g_CachedProfileData.ProxySpawnChanceMin[difficulty]; -} + kv.GetString("kill_weapontype", profileData.WeaponString, sizeof(profileData.WeaponString), profileData.WeaponString); + profileData.WeaponInt = kv.GetNum("kill_weapontype", profileData.WeaponInt); -float GetBossProfileProxySpawnChanceMax(const char[] profile, int difficulty) -{ - g_BossProfileData.GetArray(profile, g_CachedProfileData, sizeof(g_CachedProfileData)); - return g_CachedProfileData.ProxySpawnChaceMax[difficulty]; -} + profileData.DiscoMode = kv.GetNum("disco_mode", profileData.DiscoMode) != 0; + if (profileData.DiscoMode) + { + profileData.DiscoDistanceMin = kv.GetFloat("disco_mode_rng_distance_min", profileData.DiscoDistanceMin); + profileData.DiscoDistanceMax = kv.GetFloat("disco_mode_rng_distance_max", profileData.DiscoDistanceMax); + kv.GetVector("disco_mode_pos", profileData.DiscoPos, profileData.DiscoPos); + } -float GetBossProfileProxySpawnChanceThreshold(const char[] profile, int difficulty) -{ - g_BossProfileData.GetArray(profile, g_CachedProfileData, sizeof(g_CachedProfileData)); - return g_CachedProfileData.ProxySpawnChanceThreshold[difficulty]; -} + profileData.FestiveLights = kv.GetNum("festive_lights", profileData.FestiveLights) != 0; + if (profileData.FestiveLights) + { + profileData.FestiveLightBrightness = kv.GetNum("festive_light_brightness", profileData.FestiveLightBrightness); + profileData.FestiveLightDistance = kv.GetFloat("festive_light_distance", profileData.FestiveLightDistance); + profileData.FestiveLightRadius = kv.GetFloat("festive_light_radius", profileData.FestiveLightRadius); + kv.GetVector("festive_lights_pos", profileData.FestiveLightPos, profileData.FestiveLightPos); + kv.GetVector("festive_lights_ang", profileData.FestiveLightAng, profileData.FestiveLightAng); + } -int GetBossProfileProxySpawnNumberMin(const char[] profile, int difficulty) -{ - g_BossProfileData.GetArray(profile, g_CachedProfileData, sizeof(g_CachedProfileData)); - return g_CachedProfileData.ProxySpawnNumMin[difficulty]; -} + if (kv.GetNum("tp_effect_spawn", false) != 0) + { + if (profileData.SpawnEffects == null) + { + profileData.SpawnEffects = new StringMap(); + } + ArrayList listEffects = new ArrayList(sizeof(SF2BossProfileBaseEffectInfo)); -int GetBossProfileProxySpawnNumberMax(const char[] profile, int difficulty) -{ - g_BossProfileData.GetArray(profile, g_CachedProfileData, sizeof(g_CachedProfileData)); - return g_CachedProfileData.ProxySpawnNumMax[difficulty]; -} + SF2BossProfileBaseEffectInfo particle; + SF2BossProfileBaseEffectInfo sound; -float GetBossProfileProxySpawnCooldownMin(const char[] profile, int difficulty) -{ - g_BossProfileData.GetArray(profile, g_CachedProfileData, sizeof(g_CachedProfileData)); - return g_CachedProfileData.ProxySpawnCooldownMin[difficulty]; -} + particle.Init(); + particle.Type = EffectType_Particle; + particle.Event = EffectEvent_Constant; + kv.GetString("tp_effect_spawn_particle", particle.ParticleName, sizeof(particle.ParticleName), particle.ParticleName); + particle.LifeTime = 0.1; + kv.GetVector("tp_effect_origin", particle.Origin, particle.Origin); + particle.PostLoad(); + listEffects.PushArray(particle); -float GetBossProfileProxySpawnCooldownMax(const char[] profile, int difficulty) -{ - g_BossProfileData.GetArray(profile, g_CachedProfileData, sizeof(g_CachedProfileData)); - return g_CachedProfileData.ProxySpawnCooldownMax[difficulty]; -} + char soundName[PLATFORM_MAX_PATH]; + sound.Init(); + sound.Type = EffectType_Sound; + sound.Event = EffectEvent_Constant; + kv.GetString("tp_effect_spawn_sound", soundName, sizeof(soundName), soundName); + TryPrecacheBossProfileSoundPath(soundName, g_FileCheckConVar.BoolValue); + sound.SoundSounds.Paths = new ArrayList(ByteCountToCells(PLATFORM_MAX_PATH)); + sound.SoundSounds.Paths.PushString(soundName); + sound.SoundSounds.Volume = kv.GetFloat("tp_effect_spawn_sound_volume", sound.SoundSounds.Volume); + sound.SoundSounds.Pitch = kv.GetNum("tp_effect_spawn_sound_pitch", sound.SoundSounds.Pitch); + sound.SoundSounds.PostLoad(); + listEffects.PushArray(sound); -float GetBossProfileProxyTeleportRangeMin(const char[] profile, int difficulty) -{ - g_BossProfileData.GetArray(profile, g_CachedProfileData, sizeof(g_CachedProfileData)); - return g_CachedProfileData.TeleportRangeMin[difficulty]; -} + profileData.SpawnEffects.SetValue("TPEffectSpawnBackwards", listEffects); + } -float GetBossProfileProxyTeleportRangeMax(const char[] profile, int difficulty) -{ - g_BossProfileData.GetArray(profile, g_CachedProfileData, sizeof(g_CachedProfileData)); - return g_CachedProfileData.TeleportRangeMax[difficulty]; -} + if (kv.GetNum("tp_effect_despawn", false) != 0) + { + if (profileData.DespawnEffects == null) + { + profileData.DespawnEffects = new StringMap(); + } + ArrayList listEffects = new ArrayList(sizeof(SF2BossProfileBaseEffectInfo)); -int GetBossProfileMaxProxies(const char[] profile, int difficulty) -{ - g_BossProfileData.GetArray(profile, g_CachedProfileData, sizeof(g_CachedProfileData)); - return g_CachedProfileData.MaxProxies[difficulty]; -} + SF2BossProfileBaseEffectInfo particle; + SF2BossProfileBaseEffectInfo sound; -bool GetBossProfileFakeCopies(const char[] profile, int difficulty) -{ - g_BossProfileData.GetArray(profile, g_CachedProfileData, sizeof(g_CachedProfileData)); - return g_CachedProfileData.CopiesInfo.Fakes[difficulty]; -} + particle.Init(); + particle.Type = EffectType_Particle; + particle.Event = EffectEvent_Constant; + kv.GetString("tp_effect_despawn_particle", particle.ParticleName, sizeof(particle.ParticleName), particle.ParticleName); + particle.LifeTime = 0.1; + kv.GetVector("tp_effect_origin", particle.Origin, particle.Origin); + particle.PostLoad(); + listEffects.PushArray(particle); -bool GetBossProfileDrainCreditState(const char[] profile) -{ - g_BossProfileData.GetArray(profile, g_CachedProfileData, sizeof(g_CachedProfileData)); - return g_CachedProfileData.DrainCredits; -} + char soundName[PLATFORM_MAX_PATH]; + sound.Init(); + sound.Type = EffectType_Sound; + sound.Event = EffectEvent_Constant; + kv.GetString("tp_effect_despawn_sound", soundName, sizeof(soundName), soundName); + TryPrecacheBossProfileSoundPath(soundName, g_FileCheckConVar.BoolValue); + sound.SoundSounds.Paths = new ArrayList(ByteCountToCells(PLATFORM_MAX_PATH)); + sound.SoundSounds.Paths.PushString(soundName); + sound.SoundSounds.Volume = kv.GetFloat("tp_effect_despawn_sound_volume", sound.SoundSounds.Volume); + sound.SoundSounds.Pitch = kv.GetNum("tp_effect_despawn_sound_pitch", sound.SoundSounds.Pitch); + sound.SoundSounds.PostLoad(); + listEffects.PushArray(sound); -int GetBossProfileDrainCreditAmount(const char[] profile, int difficulty) -{ - g_BossProfileData.GetArray(profile, g_CachedProfileData, sizeof(g_CachedProfileData)); - return g_CachedProfileData.DrainCreditAmount[difficulty]; -} + profileData.DespawnEffects.SetValue("TPEffectDespawnBackwards", listEffects); + } -bool GetBossProfileProxySpawnEffectState(const char[] profile) -{ - g_BossProfileData.GetArray(profile, g_CachedProfileData, sizeof(g_CachedProfileData)); - return g_CachedProfileData.ProxySpawnEffect; -} + profileData.BlinkLookRate = kv.GetFloat("blink_look_rate_multiply", profileData.BlinkLookRate); + profileData.BlinkStaticRate = kv.GetFloat("blink_static_rate_multiply", profileData.BlinkStaticRate); -int GetBossProfileProxySpawnEffectName(const char[] profile, char[] buffer, int bufferlen) -{ - g_BossProfileData.GetArray(profile, g_CachedProfileData, sizeof(g_CachedProfileData)); - return strcopy(buffer, bufferlen, g_CachedProfileData.ProxySpawnEffectName); -} + profileData.DeathCam = kv.GetNum("death_cam", profileData.DeathCam) != 0; + if (profileData.DeathCam) + { + profileData.DeathCamScareSound = kv.GetNum("death_cam_play_scare_sound", profileData.DeathCamScareSound) != 0; + profileData.PublicDeathCam = kv.GetNum("death_cam_public", profileData.PublicDeathCam) != 0; + if (profileData.PublicDeathCam) + { + profileData.PublicDeathCamSpeed = kv.GetFloat("death_cam_speed", profileData.PublicDeathCamSpeed); + profileData.PublicDeathCamAcceleration = kv.GetFloat("death_cam_acceleration", profileData.PublicDeathCamAcceleration); + profileData.PublicDeathCamDeceleration = kv.GetFloat("death_cam_deceleration", profileData.PublicDeathCamDeceleration); + profileData.PublicDeathCamBackwardOffset = kv.GetFloat("deathcam_death_backward_offset", profileData.PublicDeathCamBackwardOffset); + profileData.PublicDeathCamDownwardOffset = kv.GetFloat("deathcam_death_downward_offset", profileData.PublicDeathCamDownwardOffset); + } + profileData.DeathCamOverlay = kv.GetNum("death_cam_overlay", profileData.DeathCamOverlay) != 0; + profileData.DeathCamOverlayStartTime = kv.GetFloat("death_cam_time_overlay_start", profileData.DeathCamOverlayStartTime); + if (profileData.DeathCamOverlayStartTime < 0.0) + { + profileData.DeathCamOverlayStartTime = 0.0; + } + profileData.DeathCamTime = kv.GetFloat("death_cam_time_death", profileData.DeathCamTime); + if (profileData.DeathCamTime < 0.0) + { + profileData.DeathCamTime = 0.0; + } + kv.GetVector("death_cam_pos", profileData.DeathCamPos, profileData.DeathCamPos); + kv.GetString("death_cam_attachtment_target_point", profileData.PublicDeathCamAttachmentTarget, sizeof(profileData.PublicDeathCamAttachmentTarget), profileData.PublicDeathCamAttachmentTarget); + kv.GetString("death_cam_attachtment_point", profileData.PublicDeathCamAttachment, sizeof(profileData.PublicDeathCamAttachment), profileData.PublicDeathCamAttachment); + } -float GetBossProfileProxySpawnEffectZOffset(const char[] profile) -{ - g_BossProfileData.GetArray(profile, g_CachedProfileData, sizeof(g_CachedProfileData)); - return g_CachedProfileData.ProxySpawnEffectZOffset; -} + if (kv.JumpToKey("public_death_cam")) + { + profileData.DeathCamData.Load(kv, g_FileCheckConVar.BoolValue); + kv.GoBack(); + } -ArrayList GetBossProfileProxyDeathAnimations(const char[] profile) -{ - g_BossProfileData.GetArray(profile, g_CachedProfileData, sizeof(g_CachedProfileData)); - return g_CachedProfileData.ProxyDeathAnimations; -} + GetProfileDifficultyFloatValues(kv, "sound_music_loop", profileData.SoundMusicLoop, profileData.SoundMusicLoop); + GetProfileDifficultyFloatValues(kv, "kill_cooldown", profileData.InstantKillCooldown, profileData.InstantKillCooldown); -int GetBossProfileProxyDeathAnimFrames(const char[] profile, int index) -{ - g_BossProfileData.GetArray(profile, g_CachedProfileData, sizeof(g_CachedProfileData)); - return g_CachedProfileData.ProxyDeathAnimFrames[index]; -} + GetProfileDifficultyFloatValues(kv, "search_view_distance", profileData.SearchRange, profileData.SearchRange); + GetProfileDifficultyFloatValues(kv, "search_range", profileData.SearchRange, profileData.SearchRange); + GetProfileDifficultyFloatValues(kv, "hearing_range", profileData.SearchSoundRange, profileData.SearchSoundRange); + GetProfileDifficultyFloatValues(kv, "search_sound_range", profileData.SearchSoundRange, profileData.SearchSoundRange); + GetProfileDifficultyFloatValues(kv, "taunt_alert_range", profileData.TauntAlertRange, profileData.TauntAlertRange); -bool GetBossProfileProxyZombiesState(const char[] profile) -{ - g_BossProfileData.GetArray(profile, g_CachedProfileData, sizeof(g_CachedProfileData)); - return g_CachedProfileData.ProxyZombies; -} + GetProfileDifficultyBoolValues(kv, "teleport_allowed", profileData.TeleportAllowed, profileData.TeleportAllowed); + GetProfileDifficultyFloatValues(kv, "teleport_range_min", profileData.TeleportRangeMin, profileData.TeleportRangeMin); + GetProfileDifficultyFloatValues(kv, "teleport_range_max", profileData.TeleportRangeMax, profileData.TeleportRangeMax); + GetProfileDifficultyFloatValues(kv, "teleport_time_min", profileData.TeleportTimeMin, profileData.TeleportTimeMin); + GetProfileDifficultyFloatValues(kv, "teleport_time_max", profileData.TeleportTimeMax, profileData.TeleportTimeMax); + GetProfileDifficultyFloatValues(kv, "teleport_target_rest_period", profileData.TeleportRestPeriod, profileData.TeleportRestPeriod); + GetProfileDifficultyFloatValues(kv, "teleport_target_stress_min", profileData.TeleportStressMin, profileData.TeleportStressMin); + GetProfileDifficultyFloatValues(kv, "teleport_target_stress_max", profileData.TeleportStressMax, profileData.TeleportStressMax); + GetProfileDifficultyFloatValues(kv, "teleport_target_persistency_period", profileData.TeleportPersistencyPeriod, profileData.TeleportPersistencyPeriod); + profileData.TeleportIgnoreChases = kv.GetNum("teleport_target_ignore_chases", profileData.TeleportIgnoreChases) != 0; + profileData.TeleportIgnoreVis = kv.GetNum("teleport_target_ignore_visibility", profileData.TeleportIgnoreVis) != 0; -bool GetBossProfileProxyDifficultyModelsState(const char[] profile) -{ - g_BossProfileData.GetArray(profile, g_CachedProfileData, sizeof(g_CachedProfileData)); - return g_CachedProfileData.ProxyDifficultyModels; -} + GetProfileDifficultyFloatValues(kv, "jumpscare_distance", profileData.JumpscareDistance, profileData.JumpscareDistance); + GetProfileDifficultyFloatValues(kv, "jumpscare_duration", profileData.JumpscareDuration, profileData.JumpscareDuration); + GetProfileDifficultyFloatValues(kv, "jumpscare_cooldown", profileData.JumpscareCooldown, profileData.JumpscareCooldown); + profileData.JumpscareOnScare = kv.GetNum("jumpscare_on_scare", profileData.JumpscareOnScare) != 0; + profileData.JumpscareNoSight = kv.GetNum("jumpscare_no_sight", profileData.JumpscareNoSight) != 0; -ArrayList GetBossProfileProxyModels(const char[] profile, int index, int difficulty) -{ - g_BossProfileData.GetArray(profile, g_CachedProfileData, sizeof(g_CachedProfileData)); - switch (difficulty) + GetProfileDifficultyFloatValues(kv, "speed", profileData.RunSpeed, profileData.RunSpeed); + GetProfileDifficultyFloatValues(kv, "acceleration", profileData.Acceleration, profileData.Acceleration); + + GetProfileDifficultyFloatValues(kv, "idle_lifetime", profileData.IdleLifeTime, profileData.IdleLifeTime); + + profileData.CustomOutlines = kv.GetNum("customizable_outlines", profileData.CustomOutlines) != 0; + if (profileData.CustomOutlines) + { + profileData.OutlineColor[0] = kv.GetNum("outline_color_r", profileData.OutlineColor[0]); + profileData.OutlineColor[1] = kv.GetNum("outline_color_g", profileData.OutlineColor[1]); + profileData.OutlineColor[2] = kv.GetNum("outline_color_b", profileData.OutlineColor[2]); + profileData.OutlineColor[3] = kv.GetNum("outline_color_transparency", profileData.OutlineColor[3]); + profileData.RainbowOutline = !!kv.GetNum("enable_rainbow_outline", profileData.RainbowOutline); + if (profileData.RainbowOutline) + { + profileData.RainbowOutlineCycle = kv.GetFloat("rainbow_outline_cycle_rate", profileData.RainbowOutlineCycle); + if (profileData.RainbowOutlineCycle < 0.0) + { + profileData.RainbowOutlineCycle = 0.0; + } + } + } + + profileData.SpeedBoostOnScare = !!kv.GetNum("scare_player_speed_boost", profileData.SpeedBoostOnScare); + if (profileData.SpeedBoostOnScare) + { + profileData.ScareSpeedBoostDuration = kv.GetFloat("scare_player_speed_boost_duration", profileData.ScareSpeedBoostDuration); + } + + profileData.ScareReaction = !!kv.GetNum("scare_player_reaction", profileData.ScareReaction); + if (profileData.ScareReaction) + { + profileData.ScareReactionType = kv.GetNum("scare_player_reaction_type", profileData.ScareReactionType); + if (profileData.ScareReactionType < 1) + { + profileData.ScareReactionType = 1; + } + if (profileData.ScareReactionType > 3) + { + profileData.ScareReactionType = 3; + } + kv.GetString("scare_player_reaction_response_custom", profileData.ScareReactionCustom, sizeof(profileData.ScareReactionCustom), profileData.ScareReactionCustom); + } + + profileData.ScareReplenishSprint = kv.GetNum("scare_player_replenish_sprint", profileData.ScareReplenishSprint) != 0; + if (profileData.ScareReplenishSprint) + { + profileData.ScareReplenishSprintAmount = kv.GetFloat("scare_player_replenish_sprint_amount", profileData.ScareReplenishSprintAmount); + } + + GetProfileDifficultyFloatValues(kv, "static_radius", profileData.StaticRadius, profileData.StaticRadius); + GetProfileDifficultyFloatValues(kv, "static_rate", profileData.StaticRate, profileData.StaticRate); + GetProfileDifficultyFloatValues(kv, "static_rate_decay", profileData.StaticRateDecay, profileData.StaticRateDecay); + GetProfileDifficultyFloatValues(kv, "static_on_look_gracetime", profileData.StaticGraceTime, profileData.StaticGraceTime); + profileData.StaticScareAmount = kv.GetFloat("scare_static_amount", profileData.StaticScareAmount); + + profileData.StaticShakeLocalLevel = kv.GetNum("sound_static_loop_local_level", profileData.StaticShakeLocalLevel); + profileData.StaticShakeVolumeMin = kv.GetFloat("sound_static_shake_local_volume_min", profileData.StaticShakeVolumeMin); + profileData.StaticShakeVolumeMax = kv.GetFloat("sound_static_shake_local_volume_max", profileData.StaticShakeVolumeMax); + + profileData.DrainCredits = !!kv.GetNum("drain_credits_on_kill", profileData.DrainCredits); + GetProfileDifficultyNumValues(kv, "drain_credits_amount", profileData.DrainCreditAmount, profileData.DrainCreditAmount); + + profileData.Healthbar = !!kv.GetNum("healthbar", profileData.Healthbar); + + profileData.DeathMessageDifficultyIndexes = kv.GetNum("chat_message_upon_death_difficulty_indexes", profileData.DeathMessageDifficultyIndexes); + if (kv.JumpToKey("chat_message_upon_death")) + { + profileData.DeathMessagesArray = new ArrayList(ByteCountToCells(256)); + char message[256], section[64]; + for (int i = 1;; i++) + { + FormatEx(section, sizeof(section), "%d", i); + kv.GetString(section, message, sizeof(message)); + if (message[0] == '\0') + { + break; + } + + profileData.DeathMessagesArray.PushString(message); + } + kv.GoBack(); + } + kv.GetString("chat_message_upon_death_prefix", profileData.DeathMessagePrefix, sizeof(profileData.DeathMessagePrefix), profileData.DeathMessagePrefix); + + profileData.BurnRagdoll = kv.GetNum("burn_ragdoll_on_kill", profileData.BurnRagdoll) != 0; + profileData.CloakRagdoll = kv.GetNum("cloak_ragdoll_on_kill", profileData.CloakRagdoll) != 0; + profileData.DecapRagdoll = kv.GetNum("decap_ragdoll_on_kill", profileData.DecapRagdoll) != 0; + profileData.GibRagdoll = kv.GetNum("gib_ragdoll_on_kill", profileData.GibRagdoll) != 0; + profileData.IceRagdoll = kv.GetNum("ice_ragdoll_on_kill", profileData.IceRagdoll) != 0; + profileData.GoldRagdoll = kv.GetNum("gold_ragdoll_on_kill", profileData.GoldRagdoll) != 0; + profileData.ElectrocuteRagdoll = kv.GetNum("electrocute_ragdoll_on_kill", profileData.ElectrocuteRagdoll) != 0; + profileData.AshRagdoll = kv.GetNum("disintegrate_ragdoll_on_kill", profileData.AshRagdoll) != 0; + profileData.DeleteRagdoll = kv.GetNum("delete_ragdoll_on_kill", profileData.DeleteRagdoll) != 0; + profileData.PushRagdoll = kv.GetNum("push_ragdoll_on_kill", profileData.PushRagdoll) != 0; + if (profileData.PushRagdoll) + { + kv.GetVector("push_ragdoll_force", profileData.PushRagdollForce, profileData.PushRagdollForce); + } + profileData.DissolveRagdoll = kv.GetNum("dissolve_ragdoll_on_kill", profileData.DissolveRagdoll) != 0; + if (profileData.DissolveRagdoll) { - case Difficulty_Hard: + profileData.DissolveKillType = kv.GetNum("dissolve_ragdoll_type", profileData.DissolveKillType); + } + profileData.PlasmaRagdoll = kv.GetNum("plasma_ragdoll_on_kill", profileData.PlasmaRagdoll) != 0; + profileData.ResizeRagdoll = kv.GetNum("resize_ragdoll_on_kill", profileData.ResizeRagdoll) != 0; + if (profileData.ResizeRagdoll) + { + profileData.ResizeRagdollHead = kv.GetFloat("resize_ragdoll_head", profileData.ResizeRagdollHead); + profileData.ResizeRagdollHands = kv.GetFloat("resize_ragdoll_hands", profileData.ResizeRagdollHands); + profileData.ResizeRagdollTorso = kv.GetFloat("resize_ragdoll_torso", profileData.ResizeRagdollTorso); + } + profileData.DecapOrGibRagdoll = kv.GetNum("decap_or_gib_ragdoll_on_kill", profileData.DecapOrGibRagdoll) != 0; + profileData.SilentKill = kv.GetNum("silent_kill", profileData.SilentKill) != 0; + profileData.MultiEffectRagdoll = kv.GetNum("multieffect_ragdoll_on_kill", profileData.MultiEffectRagdoll) != 0; + profileData.CustomDeathFlag = kv.GetNum("attack_custom_deathflag_enabled", profileData.CustomDeathFlag) != 0; + if (profileData.CustomDeathFlag) + { + profileData.CustomDeathFlagType = kv.GetNum("attack_custom_deathflag", profileData.CustomDeathFlagType); + } + + profileData.OutroMusic = kv.GetNum("sound_music_outro_enabled", profileData.OutroMusic) != 0; + + profileData.EngineSoundLevel = kv.GetNum("constant_sound_level", profileData.EngineSoundLevel); + profileData.EngineSoundLevel = kv.GetNum("engine_sound_level", profileData.EngineSoundLevel); + profileData.EngineSoundVolume = kv.GetFloat("constant_sound_volume", profileData.EngineSoundVolume); + profileData.EngineSoundVolume = kv.GetFloat("engine_sound_volume", profileData.EngineSoundVolume); + + kv.GetVector("eye_pos", profileData.EyePosOffset, profileData.EyePosOffset); + kv.GetVector("eye_ang_offset", profileData.EyeAngOffset, profileData.EyeAngOffset); + + if (kv.JumpToKey("eyes")) + { + profileData.EyeData.Load(kv); + kv.GoBack(); + profileData.EyePosOffset = profileData.EyeData.OffsetPos; + profileData.EyeAngOffset = profileData.EyeData.OffsetAng; + } + + if (kv.JumpToKey("slaughter_run")) + { + profileData.SlaughterRunData.Load(kv); + kv.GoBack(); + } + + // Parse through flags. + int bossFlags = 0; + if (kv.GetNum("static_on_look")) + { + bossFlags |= SFF_STATICONLOOK; + } + if (kv.GetNum("static_on_radius")) + { + bossFlags |= SFF_STATICONRADIUS; + } + if (kv.GetNum("proxies")) + { + bossFlags |= SFF_PROXIES; + } + if (kv.GetNum("jumpscare")) + { + bossFlags |= SFF_HASJUMPSCARE; + } + if (kv.GetNum("sound_static_loop_local_enabled")) + { + bossFlags |= SFF_HASSTATICLOOPLOCALSOUND; + } + if (kv.GetNum("view_shake", 1)) + { + bossFlags |= SFF_HASVIEWSHAKE; + } + if (kv.GetNum("wander_move", 1)) + { + bossFlags |= SFF_WANDERMOVE; + } + if (kv.GetNum("attack_props", 0)) + { + bossFlags |= SFF_ATTACKPROPS; + } + if (kv.GetNum("attack_weaponsenable", 0)) + { + bossFlags |= SFF_WEAPONKILLS; + } + if (kv.GetNum("kill_weaponsenable", 0)) + { + bossFlags |= SFF_WEAPONKILLSONRADIUS; + } + profileData.Flags = bossFlags; + + profileData.CopiesInfo.Load(kv); + + if (profileData.Flags & SFF_PROXIES) + { + kv.GetString("proxies_classes", profileData.ProxyClasses, sizeof(profileData.ProxyClasses), profileData.ProxyClasses); + GetProfileDifficultyFloatValues(kv, "proxies_damage_scale_vs_enemy", profileData.ProxyDamageVsEnemy, profileData.ProxyDamageVsEnemy); + GetProfileDifficultyFloatValues(kv, "proxies_damage_scale_vs_enemy_backstab", profileData.ProxyDamageVsBackstab, profileData.ProxyDamageVsBackstab); + GetProfileDifficultyFloatValues(kv, "proxies_damage_scale_vs_self", profileData.ProxyDamageVsSelf, profileData.ProxyDamageVsSelf); + GetProfileDifficultyNumValues(kv, "proxies_controlgain_hitenemy", profileData.ProxyControlGainHitEnemy, profileData.ProxyControlGainHitEnemy); + GetProfileDifficultyNumValues(kv, "proxies_controlgain_hitbyenemy", profileData.ProxyControlGainHitByEnemy, profileData.ProxyControlGainHitByEnemy); + GetProfileDifficultyFloatValues(kv, "proxies_controldrainrate", profileData.ProxyControlDrainRate, profileData.ProxyControlDrainRate); + GetProfileDifficultyNumValues(kv, "proxies_max", profileData.MaxProxies, profileData.MaxProxies); + GetProfileDifficultyFloatValues(kv, "proxies_spawn_chance_min", profileData.ProxySpawnChanceMin, profileData.ProxySpawnChanceMin); + GetProfileDifficultyFloatValues(kv, "proxies_spawn_chance_max", profileData.ProxySpawnChaceMax, profileData.ProxySpawnChaceMax); + GetProfileDifficultyFloatValues(kv, "proxies_spawn_chance_threshold", profileData.ProxySpawnChanceThreshold, profileData.ProxySpawnChanceThreshold); + GetProfileDifficultyNumValues(kv, "proxies_spawn_num_min", profileData.ProxySpawnNumMin, profileData.ProxySpawnNumMin); + GetProfileDifficultyNumValues(kv, "proxies_spawn_num_max", profileData.ProxySpawnNumMax, profileData.ProxySpawnNumMax); + GetProfileDifficultyFloatValues(kv, "proxies_spawn_cooldown_min", profileData.ProxySpawnCooldownMin, profileData.ProxySpawnCooldownMin); + GetProfileDifficultyFloatValues(kv, "proxies_spawn_cooldown_max", profileData.ProxySpawnCooldownMax, profileData.ProxySpawnCooldownMax); + GetProfileDifficultyFloatValues(kv, "proxies_teleport_range_min", profileData.ProxyTeleportRangeMin, profileData.ProxyTeleportRangeMin); + GetProfileDifficultyFloatValues(kv, "proxies_teleport_range_max", profileData.ProxyTeleportRangeMax, profileData.ProxyTeleportRangeMax); + profileData.ProxyAllowVoices = !!kv.GetNum("proxies_allownormalvoices", profileData.ProxyAllowVoices); + profileData.ProxyWeapons = !!kv.GetNum("proxies_weapon", profileData.ProxyWeapons); + profileData.ProxyDeathAnimations = new ArrayList(ByteCountToCells(PLATFORM_MAX_PATH)); + char className[15], deathSection[64], storedAnim[PLATFORM_MAX_PATH]; + for (int i = 0; i < 10; i++) + { + TF2_GetClassName(view_as(i), className, sizeof(className)); + if (i == 0) + { + deathSection = "proxies_death_anim_all"; + } + else + { + FormatEx(deathSection, sizeof(deathSection), "proxies_death_anim_%s", className); + } + kv.GetString(deathSection, storedAnim, sizeof(storedAnim)); + profileData.ProxyDeathAnimations.PushString(storedAnim); + if (i == 0) + { + deathSection = "proxies_death_anim_frames_all"; + } + else + { + FormatEx(deathSection, sizeof(deathSection), "proxies_death_anim_frames_%s", className); + } + profileData.ProxyDeathAnimFrames[i] = kv.GetNum(deathSection); + } + if (profileData.ProxyWeapons) + { + profileData.ProxyWeaponClassNames = new ArrayList(ByteCountToCells(PLATFORM_MAX_PATH)); + profileData.ProxyWeaponStats = new ArrayList(ByteCountToCells(PLATFORM_MAX_PATH)); + char classKey[15], keyValue[45], arrayStringValue[PLATFORM_MAX_PATH]; + for (int i = 1; i < 10; i++) + { + TF2_GetClassName(view_as(i), classKey, sizeof(classKey)); + + FormatEx(keyValue, sizeof(keyValue), "proxies_weapon_class_%s", classKey); + kv.GetString(keyValue, arrayStringValue, sizeof(arrayStringValue)); + profileData.ProxyWeaponClassNames.PushString(arrayStringValue); + + FormatEx(keyValue, sizeof(keyValue), "proxies_weapon_stats_%s", classKey); + kv.GetString(keyValue, arrayStringValue, sizeof(arrayStringValue)); + profileData.ProxyWeaponStats.PushString(arrayStringValue); + + FormatEx(keyValue, sizeof(keyValue), "proxies_weapon_index_%s", classKey); + profileData.ProxyWeaponIndexes[i] = kv.GetNum(keyValue, profileData.ProxyWeaponIndexes[i]); + + FormatEx(keyValue, sizeof(keyValue), "proxies_weapon_slot_%s", classKey); + profileData.ProxyWeaponSlots[i] = kv.GetNum(keyValue, profileData.ProxyWeaponSlots[i]); + } + } + profileData.ProxySpawnEffect = kv.GetNum("proxies_spawn_effect_enabled", profileData.ProxySpawnEffect) != 0; + if (profileData.ProxySpawnEffect) + { + kv.GetString("proxies_spawn_effect", profileData.ProxySpawnEffectName, sizeof(profileData.ProxySpawnEffectName), profileData.ProxySpawnEffectName); + profileData.ProxySpawnEffectZOffset = kv.GetFloat("proxies_spawn_effect_z_offset", profileData.ProxySpawnEffectZOffset); + } + profileData.ProxyZombies = kv.GetNum("proxies_zombie", profileData.ProxyZombies) != 0; + profileData.ProxyRobots = kv.GetNum("proxies_robot", profileData.ProxyRobots) != 0; + profileData.ProxyDifficultyModels = kv.GetNum("proxy_difficulty_models", profileData.ProxyDifficultyModels) != 0; + + char index[64], modelDirectory[PLATFORM_MAX_PATH]; + if (profileData.ProxyDifficultyModels) + { + for (int i = 0; i < 10; i++) + { + for (int j = 1; j < Difficulty_Max; j--) + { + TF2_GetClassName(view_as(i), className, sizeof(className)); + if (i == 0) + { + switch (j) + { + case Difficulty_Normal: + { + deathSection = "mod_proxy_all"; + } + case Difficulty_Hard: + { + deathSection = "mod_proxy_all_hard"; + } + case Difficulty_Insane: + { + deathSection = "mod_proxy_all_insane"; + } + case Difficulty_Nightmare: + { + deathSection = "mod_proxy_all_nightmare"; + } + case Difficulty_Apollyon: + { + deathSection = "mod_proxy_all_apollyon"; + } + } + } + else + { + switch (j) + { + case Difficulty_Normal: + { + FormatEx(deathSection, sizeof(deathSection), "mod_proxy_%s", className); + } + case Difficulty_Hard: + { + FormatEx(deathSection, sizeof(deathSection), "mod_proxy_%s_hard", className); + } + case Difficulty_Insane: + { + FormatEx(deathSection, sizeof(deathSection), "mod_proxy_%s_insane", className); + } + case Difficulty_Nightmare: + { + FormatEx(deathSection, sizeof(deathSection), "mod_proxy_%s_nightmare", className); + } + case Difficulty_Apollyon: + { + FormatEx(deathSection, sizeof(deathSection), "mod_proxy_%s_apollyon", className); + } + } + } + if (kv.JumpToKey(deathSection)) + { + switch (j) + { + case Difficulty_Normal: + { + profileData.ProxyModels[i] = new ArrayList(ByteCountToCells(PLATFORM_MAX_PATH)); + } + case Difficulty_Hard: + { + profileData.ProxyModelsHard[i] = new ArrayList(ByteCountToCells(PLATFORM_MAX_PATH)); + } + case Difficulty_Insane: + { + profileData.ProxyModelsInsane[i] = new ArrayList(ByteCountToCells(PLATFORM_MAX_PATH)); + } + case Difficulty_Nightmare: + { + profileData.ProxyModelsNightmare[i] = new ArrayList(ByteCountToCells(PLATFORM_MAX_PATH)); + } + case Difficulty_Apollyon: + { + profileData.ProxyModelsApollyon[i] = new ArrayList(ByteCountToCells(PLATFORM_MAX_PATH)); + } + } + for (int i2 = 1;; i2++) + { + FormatEx(index, sizeof(index), "%d", i2); + kv.GetString(index, modelDirectory, sizeof(modelDirectory)); + if (modelDirectory[0] == '\0') + { + break; + } + + if (!PrecacheModel(modelDirectory, true)) + { + LogSF2Message("Proxy model file %s failed to be precached, this model will not be used.", modelDirectory); + } + else + { + switch (j) + { + case Difficulty_Normal: + { + profileData.ProxyModels[i].PushString(modelDirectory); + } + case Difficulty_Hard: + { + profileData.ProxyModelsHard[i].PushString(modelDirectory); + } + case Difficulty_Insane: + { + profileData.ProxyModelsInsane[i].PushString(modelDirectory); + } + case Difficulty_Nightmare: + { + profileData.ProxyModelsNightmare[i].PushString(modelDirectory); + } + case Difficulty_Apollyon: + { + profileData.ProxyModelsApollyon[i].PushString(modelDirectory); + } + } + PrecacheModel2(modelDirectory, _, _, g_FileCheckConVar.BoolValue); + } + } + kv.GoBack(); + } + } + } + } + else + { + for (int i = 0; i < 10; i++) + { + TF2_GetClassName(view_as(i), className, sizeof(className)); + if (i == 0) + { + deathSection = "mod_proxy_all"; + } + else + { + FormatEx(deathSection, sizeof(deathSection), "mod_proxy_%s", className); + } + if (kv.JumpToKey(deathSection)) + { + profileData.ProxyModels[i] = new ArrayList(ByteCountToCells(PLATFORM_MAX_PATH)); + for (int i2 = 1;; i2++) + { + FormatEx(index, sizeof(index), "%d", i2); + kv.GetString(index, modelDirectory, sizeof(modelDirectory)); + if (modelDirectory[0] == '\0') + { + break; + } + + if (!PrecacheModel(modelDirectory, true)) + { + LogSF2Message("Proxy model file %s failed to be precached, this model will not be used.", modelDirectory); + } + else + { + profileData.ProxyModels[i].PushString(modelDirectory); + } + } + kv.GoBack(); + } + } + } + + profileData.ProxyOverrideMaxSpeed = !!kv.GetNum("proxies_override_max_speed", profileData.ProxyOverrideMaxSpeed); + if (profileData.ProxyOverrideMaxSpeed) + { + GetProfileDifficultyFloatValues(kv, "proxies_max_speed", profileData.ProxyMaxSpeed, profileData.ProxyMaxSpeed); + } + } + + UnloadBossProfile(profile); + + profileData.AnimationData.Load(kv, true); + + switch (profileData.Type) + { + case SF2BossType_Statue: + { + if (!LoadStatueBossProfile(kv, profile, loadFailReasonBuffer, loadFailReasonBufferLen, profileData)) + { + return false; + } + } + case SF2BossType_Chaser: + { + if (!LoadChaserBossProfile(kv, profile, loadFailReasonBuffer, loadFailReasonBufferLen, profileData)) + { + return false; + } + } + } + // Add the section to our config. + g_Config.Rewind(); + g_Config.JumpToKey(profile, true); + g_Config.Import(kv); + + kv.GetString("constant_sound", profileData.EngineSound, sizeof(profileData.EngineSound), profileData.EngineSound); + kv.GetString("engine_sound", profileData.EngineSound, sizeof(profileData.EngineSound), profileData.EngineSound); + + TryPrecacheBossProfileSoundPath(profileData.EngineSound, g_FileCheckConVar.BoolValue); + + int index = g_BossProfileList.FindString(profile); + if (index == -1) + { + g_BossProfileList.PushString(profile); + } + + if (kv.GetNum("enable_random_selection", true) != 0) + { + if (GetSelectableBossProfileList().FindString(profile) == -1) + { + // Add to the selectable boss list if it isn't there already. + GetSelectableBossProfileList().PushString(profile); + } + } + else + { + int selectIndex = GetSelectableBossProfileList().FindString(profile); + if (selectIndex != -1) + { + GetSelectableBossProfileList().Erase(selectIndex); + } + } + + if (kv.GetNum("admin_only", false) != 0) + { + if (GetSelectableAdminBossProfileList().FindString(profile) == -1) + { + // Add to the selectable boss list if it isn't there already. + GetSelectableAdminBossProfileList().PushString(profile); + } + } + else + { + int selectIndex = GetSelectableAdminBossProfileList().FindString(profile); + if (selectIndex != -1) + { + GetSelectableAdminBossProfileList().Erase(selectIndex); + } + } + + if (kv.GetNum("enable_random_selection_boxing", false) != 0) + { + if (GetSelectableBoxingBossProfileList().FindString(profile) == -1) + { + // Add to the selectable boss list if it isn't there already. + GetSelectableBoxingBossProfileList().PushString(profile); + } + } + else + { + int selectIndex = GetSelectableBoxingBossProfileList().FindString(profile); + if (selectIndex != -1) + { + GetSelectableBoxingBossProfileList().Erase(selectIndex); + } + } + + if (kv.GetNum("enable_random_selection_renevant", false) != 0) + { + if (GetSelectableRenevantBossProfileList().FindString(profile) == -1) + { + // Add to the selectable boss list if it isn't there already. + GetSelectableRenevantBossProfileList().PushString(profile); + } + } + else + { + int selectIndex = GetSelectableRenevantBossProfileList().FindString(profile); + if (selectIndex != -1) + { + GetSelectableRenevantBossProfileList().Erase(selectIndex); + } + } + + if (kv.GetNum("enable_random_selection_renevant_admin", false) != 0) + { + if (GetSelectableRenevantBossAdminProfileList().FindString(profile) == -1) + { + // Add to the selectable boss list if it isn't there already. + GetSelectableRenevantBossAdminProfileList().PushString(profile); + } + } + else + { + int selectIndex = GetSelectableRenevantBossAdminProfileList().FindString(profile); + if (selectIndex != -1) + { + GetSelectableRenevantBossAdminProfileList().Erase(selectIndex); + } + } + + if (kv.JumpToKey("pve")) + { + profileData.IsPvEBoss = true; + kv.GoBack(); + } + else + { + profileData.IsPvEBoss = kv.GetNum("is_pve", profileData.IsPvEBoss) != 0; + } + + if (profileData.IsPvEBoss) + { + profileData.Flags = profileData.Flags & ~SFF_PROXIES; + if (kv.JumpToKey("pve")) + { + if (kv.JumpToKey("spawn_messages")) + { + profileData.PvESpawnMessagesArray = new ArrayList(ByteCountToCells(PLATFORM_MAX_PATH)); + char message[256], section[64]; + for (int i = 1;; i++) + { + FormatEx(section, sizeof(section), "%d", i); + kv.GetString(section, message, sizeof(message)); + if (message[0] == '\0') + { + break; + } + + profileData.PvESpawnMessagesArray.PushString(message); + } + kv.GoBack(); + } + kv.GetString("spawn_message_prefix", profileData.PvESpawnMessagePrefix, sizeof(profileData.PvESpawnMessagePrefix), profileData.PvESpawnMessagePrefix); + profileData.DisplayPvEHealth = kv.GetNum("health_bar", profileData.DisplayPvEHealth) != 0; + char setProfile[SF2_MAX_PROFILE_NAME_LENGTH]; + strcopy(setProfile, sizeof(setProfile), profile); + if (kv.GetNum("selectable", 1) != 0) + { + RegisterPvESlenderBoss(setProfile); + } + profileData.PvETeleportEndTimer = kv.GetFloat("teleport_players_time", profileData.PvETeleportEndTimer); + kv.GoBack(); + } + else + { + if (kv.JumpToKey("pve_spawn_messages")) + { + profileData.PvESpawnMessagesArray = new ArrayList(ByteCountToCells(PLATFORM_MAX_PATH)); + char message[256], section[64]; + for (int i = 1;; i++) + { + FormatEx(section, sizeof(section), "%d", i); + kv.GetString(section, message, sizeof(message)); + if (message[0] == '\0') + { + break; + } + + profileData.PvESpawnMessagesArray.PushString(message); + } + kv.GoBack(); + } + kv.GetString("pve_spawn_message_prefix", profileData.PvESpawnMessagePrefix, sizeof(profileData.PvESpawnMessagePrefix), profileData.PvESpawnMessagePrefix); + profileData.DisplayPvEHealth = kv.GetNum("pve_health_bar", profileData.DisplayPvEHealth) != 0; + char setProfile[SF2_MAX_PROFILE_NAME_LENGTH]; + strcopy(setProfile, sizeof(setProfile), profile); + if (kv.GetNum("pve_selectable", 1) != 0) + { + RegisterPvESlenderBoss(setProfile); + } + } + + index = GetSelectableBossProfileList().FindString(profile); + if (index != -1) + { + GetSelectableBossProfileList().Erase(index); + } + index = GetSelectableAdminBossProfileList().FindString(profile); + if (index != -1) { - return g_CachedProfileData.ProxyModelsHard[index]; + GetSelectableAdminBossProfileList().Erase(index); } - case Difficulty_Insane: + index = GetSelectableBoxingBossProfileList().FindString(profile); + if (index != -1) { - return g_CachedProfileData.ProxyModelsInsane[index]; + GetSelectableBoxingBossProfileList().Erase(index); } - case Difficulty_Nightmare: + index = GetSelectableRenevantBossProfileList().FindString(profile); + if (index != -1) { - return g_CachedProfileData.ProxyModelsNightmare[index]; + GetSelectableRenevantBossProfileList().Erase(index); } - case Difficulty_Apollyon: + index = GetSelectableRenevantBossAdminProfileList().FindString(profile); + if (index != -1) { - return g_CachedProfileData.ProxyModelsApollyon[index]; + GetSelectableRenevantBossAdminProfileList().Erase(index); } } - return g_CachedProfileData.ProxyModels[index]; -} -bool GetBossProfileProxyOverrideMaxSpeed(const char[] profile) -{ - g_BossProfileData.GetArray(profile, g_CachedProfileData, sizeof(g_CachedProfileData)); - return g_CachedProfileData.ProxyOverrideMaxSpeed; -} + ArrayList validSections = new ArrayList(ByteCountToCells(128)); -float GetBossProfileProxyMaxSpeed(const char[] profile, int difficulty) -{ - g_BossProfileData.GetArray(profile, g_CachedProfileData, sizeof(g_CachedProfileData)); - return g_CachedProfileData.ProxyMaxSpeed[difficulty]; -} + if (kv.GotoFirstSubKey()) //Special thanks to Fire for modifying the code for download errors. + { + char s2[64], s3[64], s4[PLATFORM_MAX_PATH], s5[PLATFORM_MAX_PATH]; -void GetBossProfileEyePositionOffset(const char[] profile, float buffer[3]) -{ - g_BossProfileData.GetArray(profile, g_CachedProfileData, sizeof(g_CachedProfileData)); - buffer = g_CachedProfileData.EyePosOffset; -} + do + { + kv.GetSectionName(s2, sizeof(s2)); -void GetBossProfileEyeAngleOffset(const char[] profile, float buffer[3]) -{ - g_BossProfileData.GetArray(profile, g_CachedProfileData, sizeof(g_CachedProfileData)); - buffer = g_CachedProfileData.EyeAngOffset; -} + if (validSections.FindString(s2) != -1) + { + continue; + } -float GetBossProfileScareRadius(const char[] profile) -{ - g_BossProfileData.GetArray(profile, g_CachedProfileData, sizeof(g_CachedProfileData)); - return g_CachedProfileData.ScareRadius; -} + validSections.PushString(s2); -float GetBossProfileScareCooldown(const char[] profile) -{ - g_BossProfileData.GetArray(profile, g_CachedProfileData, sizeof(g_CachedProfileData)); - return g_CachedProfileData.ScareCooldown; -} + if (StrContains(s2, "sound_") != -1) + { + bool doBack = false; + if (kv.JumpToKey("paths")) + { + doBack = true; + } + for (int i = 1;; i++) + { + FormatEx(s3, sizeof(s3), "%d", i); + kv.GetString(s3, s4, sizeof(s4)); + if (s4[0] == '\0') + { + break; + } -bool GetBossProfileSpeedBoostOnScare(const char[] profile) -{ - g_BossProfileData.GetArray(profile, g_CachedProfileData, sizeof(g_CachedProfileData)); - return g_CachedProfileData.SpeedBoostOnScare; -} + TryPrecacheBossProfileSoundPath(s4, g_FileCheckConVar.BoolValue); -bool GetBossProfileJumpscareOnScare(const char[] profile) -{ - g_BossProfileData.GetArray(profile, g_CachedProfileData, sizeof(g_CachedProfileData)); - return g_CachedProfileData.JumpscareOnScare; -} + // Here comes an if else mess, I'm very sorry + if (strcmp(s2, "sound_jumpscare") == 0) + { + profileData.JumpscareSound = s4; + break; + } + else if (strcmp(s2, "sound_static") == 0) + { + profileData.StaticSound = s4; + break; + } + else if (strcmp(s2, "sound_static_loop_local") == 0) + { + profileData.StaticLocalSound = s4; + break; + } + else if (strcmp(s2, "sound_static_shake_local") == 0) + { + profileData.StaticShakeLocal = s4; + break; + } + } + if (doBack) + { + kv.GoBack(); + } + profileData.SortSoundSections(kv, s2, g_FileCheckConVar.BoolValue); + } + else if (strcmp(s2, "download") == 0) + { + for (int i = 1;; i++) + { + FormatEx(s3, sizeof(s3), "%d", i); + kv.GetString(s3, s4, sizeof(s4)); + if (s4[0] == '\0') + { + break; + } -bool GetBossProfileJumpscareNoSight(const char[] profile) -{ - g_BossProfileData.GetArray(profile, g_CachedProfileData, sizeof(g_CachedProfileData)); - return g_CachedProfileData.JumpscareNoSight; -} + if (g_FileCheckConVar.BoolValue) + { + if (FileExists(s4) || FileExists(s4, true)) + { + AddFileToDownloadsTable(s4); + } + else + { + LogSF2Message("File %s does not exist, please fix this download or remove it from the array.", s4); + } + } + else + { + AddFileToDownloadsTable(s4); + } + } + } + else if (strcmp(s2, "mod_precache") == 0) + { + for (int i = 1;; i++) + { + FormatEx(s3, sizeof(s3), "%d", i); + kv.GetString(s3, s4, sizeof(s4)); + if (s4[0] == '\0') + { + break; + } -float GetBossProfileScareSpeedBoostDuration(const char[] profile) -{ - g_BossProfileData.GetArray(profile, g_CachedProfileData, sizeof(g_CachedProfileData)); - return g_CachedProfileData.ScareSpeedBoostDuration; -} + if (!PrecacheModel(s4, true)) + { + LogSF2Message("Model file %s failed to be precached, likely does not exist. This will crash the server if not fixed.", s4); + } + } + } + else if (strcmp(s2, "mat_download") == 0) + { + for (int i = 1;; i++) + { + FormatEx(s3, sizeof(s3), "%d", i); + kv.GetString(s3, s4, sizeof(s4)); + if (s4[0] == '\0') + { + break; + } -bool GetBossProfileScareReactionState(const char[] profile) -{ - g_BossProfileData.GetArray(profile, g_CachedProfileData, sizeof(g_CachedProfileData)); - return g_CachedProfileData.ScareReaction; -} + FormatEx(s5, sizeof(s5), "%s.vtf", s4); + if (g_FileCheckConVar.BoolValue) + { + if (FileExists(s5) || FileExists(s5, true)) + { + AddFileToDownloadsTable(s5); + } + else + { + LogSF2Message("Texture file %s does not exist, please fix this download or remove it from the array.", s5); + } + } + else + { + AddFileToDownloadsTable(s5); + } -int GetBossProfileScareReactionType(const char[] profile) -{ - g_BossProfileData.GetArray(profile, g_CachedProfileData, sizeof(g_CachedProfileData)); - return g_CachedProfileData.ScareReactionType; -} + FormatEx(s5, sizeof(s5), "%s.vmt", s4); + if (g_FileCheckConVar.BoolValue) + { + if (FileExists(s5) || FileExists(s5, true)) + { + AddFileToDownloadsTable(s5); + } + else + { + LogSF2Message("Material file %s does not exist, please fix this download or remove it from the array.", s5); + } + } + else + { + AddFileToDownloadsTable(s5); + } + } + } + else if (strcmp(s2, "mod_download") == 0) + { + for (int i = 1;; i++) + { + FormatEx(s3, sizeof(s3), "%d", i); + kv.GetString(s3, s4, sizeof(s4)); + if (s4[0] == '\0') + { + break; + } -int GetBossProfileScareReactionCustom(const char[] profile, char[] buffer, int bufferlen) -{ - g_BossProfileData.GetArray(profile, g_CachedProfileData, sizeof(g_CachedProfileData)); - return strcopy(buffer, bufferlen, g_CachedProfileData.ScareReactionCustom); -} + PrecacheModel2(s4, _, _, g_FileCheckConVar.BoolValue); + } + } + else if (strcmp(s2, "overlay_player_death") == 0) + { + kv.GetString("1", s4, sizeof(s4)); + profileData.OverlayPlayerDeath = s4; + } + else if (strcmp(s2, "overlay_jumpscare") == 0) + { + kv.GetString("1", s4, sizeof(s4)); + profileData.OverlayJumpscare = s4; + } + if (StrContains(s2, "sound_footsteps_event_") != -1) + { + if (profileData.FootstepEventSounds == null) + { + profileData.FootstepEventSounds = new ArrayList(sizeof(SF2BossProfileSoundInfo)); + } + if (profileData.FootstepEventIndexes == null) + { + profileData.FootstepEventIndexes = new ArrayList(); + } -bool GetBossProfileScareReplenishState(const char[] profile) -{ - g_BossProfileData.GetArray(profile, g_CachedProfileData, sizeof(g_CachedProfileData)); - return g_CachedProfileData.ScareReplenishSprint; -} + SF2BossProfileSoundInfo soundInfo; + soundInfo.Init(); + soundInfo.Load(kv, g_FileCheckConVar.BoolValue); + soundInfo.PostLoad(); + if (soundInfo.Paths != null) + { + strcopy(s3, sizeof(s3), s2); + ReplaceStringEx(s3, sizeof(s3), "sound_footsteps_event_", ""); + int eventNumber = StringToInt(s3); -float GetBossProfileScareReplenishAmount(const char[] profile) -{ - g_BossProfileData.GetArray(profile, g_CachedProfileData, sizeof(g_CachedProfileData)); - return g_CachedProfileData.ScareReplenishSprintAmount; -} + profileData.FootstepEventIndexes.Push(eventNumber); + profileData.FootstepEventSounds.PushArray(soundInfo); + } + } + else if (StrContains(s2, "sound_event_") != -1) + { + if (profileData.EventSounds == null) + { + profileData.EventSounds = new ArrayList(sizeof(SF2BossProfileSoundInfo)); + } + if (profileData.EventIndexes == null) + { + profileData.EventIndexes = new ArrayList(); + } -int GetBossProfileTeleportType(const char[] profile) -{ - g_BossProfileData.GetArray(profile, g_CachedProfileData, sizeof(g_CachedProfileData)); - return g_CachedProfileData.TeleportType; -} + SF2BossProfileSoundInfo soundInfo; + soundInfo.Init(); + soundInfo.Load(kv, g_FileCheckConVar.BoolValue); + soundInfo.PostLoad(); + if (soundInfo.Paths != null) + { + strcopy(s3, sizeof(s3), s2); + ReplaceStringEx(s3, sizeof(s3), "sound_event_", ""); + int eventNumber = StringToInt(s3); + + profileData.EventIndexes.Push(eventNumber); + profileData.EventSounds.PushArray(soundInfo); + } + } + } + while (kv.GotoNextKey()); -bool GetBossProfileCustomOutlinesState(const char[] profile) -{ - g_BossProfileData.GetArray(profile, g_CachedProfileData, sizeof(g_CachedProfileData)); - return g_CachedProfileData.CustomOutlines; -} + kv.GoBack(); + } -bool GetBossProfileRainbowOutlineState(const char[] profile) -{ - g_BossProfileData.GetArray(profile, g_CachedProfileData, sizeof(g_CachedProfileData)); - return g_CachedProfileData.RainbowOutline; -} + delete validSections; -bool GetBossProfileProxyWeapons(const char[] profile) -{ - g_BossProfileData.GetArray(profile, g_CachedProfileData, sizeof(g_CachedProfileData)); - return g_CachedProfileData.ProxyWeapons; -} + if (kv.JumpToKey("companions")) + { + profileData.CompanionsArray = new ArrayList(sizeof(SF2BossProfileCompanionsInfo)); -ArrayList GetBossProfileProxyWeaponClassNames(const char[] profile) -{ - g_BossProfileData.GetArray(profile, g_CachedProfileData, sizeof(g_CachedProfileData)); - return g_CachedProfileData.ProxyWeaponClassNames; -} + kv.GetString("type", profileData.CompanionSpawnType, sizeof(profileData.CompanionSpawnType)); + if (kv.GotoFirstSubKey()) + { + do + { + SF2BossProfileCompanionsInfo companions; + companions.Init(); + companions.Load(kv); + profileData.CompanionsArray.PushArray(companions); + if (lookIntoLoads) + { + char compProfile[SF2_MAX_PROFILE_NAME_LENGTH], otherProfile[SF2_MAX_PROFILE_NAME_LENGTH], dir[PLATFORM_MAX_PATH], file[PLATFORM_MAX_PATH]; + FileType fileType; + DirectoryListing directory = OpenDirectory(originalDir); + while (directory.GetNext(file, sizeof(file), fileType)) + { + if (fileType == FileType_Directory) + { + continue; + } -ArrayList GetBossProfileProxyWeaponStats(const char[] profile) -{ - g_BossProfileData.GetArray(profile, g_CachedProfileData, sizeof(g_CachedProfileData)); - return g_CachedProfileData.ProxyWeaponStats; -} + FormatEx(dir, sizeof(dir), "%s/%s", originalDir, file); -int GetBossProfileProxyWeaponIndexes(const char[] profile, int index) -{ - g_BossProfileData.GetArray(profile, g_CachedProfileData, sizeof(g_CachedProfileData)); - return g_CachedProfileData.ProxyWeaponIndexes[index]; -} + for (int i = 0; i < companions.Bosses.Length; i++) + { + companions.Bosses.GetString(i, compProfile, sizeof(compProfile)); -int GetBossProfileProxyWeaponSlots(const char[] profile, int index) -{ - g_BossProfileData.GetArray(profile, g_CachedProfileData, sizeof(g_CachedProfileData)); - return g_CachedProfileData.ProxyWeaponSlots[index]; -} + KeyValues otherKeys = new KeyValues("root"); + if (!FileToKeyValues(otherKeys, dir)) + { + delete otherKeys; + continue; + } -bool GetBossProfileProxyAllowNormalVoices(const char[] profile) -{ - g_BossProfileData.GetArray(profile, g_CachedProfileData, sizeof(g_CachedProfileData)); - return g_CachedProfileData.ProxyAllowVoices; -} + otherKeys.GetSectionName(otherProfile, sizeof(otherProfile)); -int GetBossProfileChatDeathMessageDifficultyIndexes(const char[] profile) -{ - g_BossProfileData.GetArray(profile, g_CachedProfileData, sizeof(g_CachedProfileData)); - return g_CachedProfileData.DeathMessageDifficultyIndexes; -} + if (strcmp(compProfile, otherProfile) == 0) + { + if (!LoadBossProfile(otherKeys, otherProfile, loadFailReasonBuffer, loadFailReasonBufferLen)) + { + LogSF2Message("(COMPANION) %s...FAILED (reason: %s)", dir, loadFailReasonBuffer); + } + else + { + LogSF2Message("(COMPANION) %s...", otherProfile); + } + } -ArrayList GetBossProfileChatDeathMessages(const char[] profile) -{ - g_BossProfileData.GetArray(profile, g_CachedProfileData, sizeof(g_CachedProfileData)); - return g_CachedProfileData.DeathMessagesArray; -} + delete otherKeys; + } + } + } + } + while (kv.GotoNextKey()); + kv.GoBack(); + } + kv.GoBack(); + } -int GetBossProfileChatDeathMessagePrefix(const char[] profile, char[] buffer, int bufferlen) -{ - g_BossProfileData.GetArray(profile, g_CachedProfileData, sizeof(g_CachedProfileData)); - return strcopy(buffer, bufferlen, g_CachedProfileData.DeathMessagePrefix); -} + if (kv.JumpToKey("attributes")) + { + profileData.AttributesInfo.Load(kv); + } -void GetBossProfileMusicSounds(const char[] profile, SF2BossProfileSoundInfo params, int difficulty) -{ - g_BossProfileData.GetArray(profile, g_CachedProfileData, sizeof(g_CachedProfileData)); - switch (difficulty) + if (kv.JumpToKey("effects")) { - case Difficulty_Normal: + profileData.EffectsArray = new ArrayList(sizeof(SF2BossProfileBaseEffectInfo)); + + if (kv.GotoFirstSubKey()) { - params = g_CachedProfileData.MusicSoundsNormal; + do + { + SF2BossProfileBaseEffectInfo effects; + effects.Init(); + effects.ModelScale = profileData.ModelScale; + effects.Load(kv, g_FileCheckConVar.BoolValue); + profileData.EffectsArray.PushArray(effects); + } + while (kv.GotoNextKey()); + kv.GoBack(); } - case Difficulty_Hard: + kv.GoBack(); + } + + if (kv.JumpToKey("spawn_effects")) + { + if (profileData.SpawnEffects == null) { - params = g_CachedProfileData.MusicSoundsHard; + profileData.SpawnEffects = new StringMap(); } - case Difficulty_Insane: + + if (kv.GotoFirstSubKey()) { - params = g_CachedProfileData.MusicSoundsInsane; + do + { + char section[64]; + kv.GetSectionName(section, sizeof(section)); + if (kv.JumpToKey("effects")) + { + ArrayList list = new ArrayList(sizeof(SF2BossProfileBaseEffectInfo)); + if (kv.GotoFirstSubKey()) + { + do + { + SF2BossProfileBaseEffectInfo effects; + effects.Init(); + effects.ModelScale = profileData.ModelScale; + effects.Load(kv, g_FileCheckConVar.BoolValue); + if (effects.Type == EffectType_Particle) + { + effects.LifeTime = 0.1; + } + list.PushArray(effects); + } + while (kv.GotoNextKey()); + kv.GoBack(); + } + kv.GoBack(); + profileData.SpawnEffects.SetValue(section, list); + } + } + while (kv.GotoNextKey()); + kv.GoBack(); } - case Difficulty_Nightmare: + kv.GoBack(); + } + + if (kv.JumpToKey("despawn_effects")) + { + if (profileData.DespawnEffects == null) { - params = g_CachedProfileData.MusicSoundsNightmare; + profileData.DespawnEffects = new StringMap(); } - case Difficulty_Apollyon: + profileData.HideDespawnEffectsOnDeath = kv.GetNum("hide_on_death", profileData.HideDespawnEffectsOnDeath) != 0; + + if (kv.GotoFirstSubKey()) { - params = g_CachedProfileData.MusicSoundsApollyon; + do + { + char section[64]; + kv.GetSectionName(section, sizeof(section)); + if (kv.JumpToKey("effects")) + { + ArrayList list = new ArrayList(sizeof(SF2BossProfileBaseEffectInfo)); + if (kv.GotoFirstSubKey()) + { + do + { + SF2BossProfileBaseEffectInfo effects; + effects.Init(); + effects.ModelScale = profileData.ModelScale; + effects.Load(kv, g_FileCheckConVar.BoolValue); + if (effects.Type == EffectType_Particle) + { + effects.LifeTime = 0.1; + } + list.PushArray(effects); + } + while (kv.GotoNextKey()); + kv.GoBack(); + } + kv.GoBack(); + profileData.DespawnEffects.SetValue(section, list); + } + } + while (kv.GotoNextKey()); + kv.GoBack(); } + kv.GoBack(); } -} - -void GetBossProfileScareSounds(const char[] profile, SF2BossProfileSoundInfo params) -{ - g_BossProfileData.GetArray(profile, g_CachedProfileData, sizeof(g_CachedProfileData)); - params = g_CachedProfileData.ScareSounds; -} - -void GetBossProfileSightSounds(const char[] profile, SF2BossProfileSoundInfo params) -{ - g_BossProfileData.GetArray(profile, g_CachedProfileData, sizeof(g_CachedProfileData)); - params = g_CachedProfileData.SightSounds; -} - -void GetBossProfileIntroSounds(const char[] profile, SF2BossProfileSoundInfo params) -{ - g_BossProfileData.GetArray(profile, g_CachedProfileData, sizeof(g_CachedProfileData)); - params = g_CachedProfileData.IntroSounds; -} - -void GetBossProfileSpawnLocalSounds(const char[] profile, SF2BossProfileSoundInfo params) -{ - g_BossProfileData.GetArray(profile, g_CachedProfileData, sizeof(g_CachedProfileData)); - params = g_CachedProfileData.SpawnLocalSounds; -} - -void GetBossProfileProxySpawnSounds(const char[] profile, SF2BossProfileSoundInfo params) -{ - g_BossProfileData.GetArray(profile, g_CachedProfileData, sizeof(g_CachedProfileData)); - params = g_CachedProfileData.ProxySpawnSounds; -} - -void GetBossProfileProxyIdleSounds(const char[] profile, SF2BossProfileSoundInfo params) -{ - g_BossProfileData.GetArray(profile, g_CachedProfileData, sizeof(g_CachedProfileData)); - params = g_CachedProfileData.ProxyIdleSounds; -} - -void GetBossProfileProxyHurtSounds(const char[] profile, SF2BossProfileSoundInfo params) -{ - g_BossProfileData.GetArray(profile, g_CachedProfileData, sizeof(g_CachedProfileData)); - params = g_CachedProfileData.ProxyHurtSounds; -} - -void GetBossProfileProxyDeathSounds(const char[] profile, SF2BossProfileSoundInfo params) -{ - g_BossProfileData.GetArray(profile, g_CachedProfileData, sizeof(g_CachedProfileData)); - params = g_CachedProfileData.ProxyDeathSounds; -} - -void GetBossProfileOutroMusics(const char[] profile, SF2BossProfileSoundInfo params) -{ - g_BossProfileData.GetArray(profile, g_CachedProfileData, sizeof(g_CachedProfileData)); - params = g_CachedProfileData.OutroMusics; -} - -ArrayList GetBossProfileFootstepEventSounds(const char[] profile) -{ - g_BossProfileData.GetArray(profile, g_CachedProfileData, sizeof(g_CachedProfileData)); - return g_CachedProfileData.FootstepEventSounds; -} - -ArrayList GetBossProfileFootstepEventIndexes(const char[] profile) -{ - g_BossProfileData.GetArray(profile, g_CachedProfileData, sizeof(g_CachedProfileData)); - return g_CachedProfileData.FootstepEventIndexes; -} - -ArrayList GetBossProfileEventSounds(const char[] profile) -{ - g_BossProfileData.GetArray(profile, g_CachedProfileData, sizeof(g_CachedProfileData)); - return g_CachedProfileData.EventSounds; -} - -ArrayList GetBossProfileEventIndexes(const char[] profile) -{ - g_BossProfileData.GetArray(profile, g_CachedProfileData, sizeof(g_CachedProfileData)); - return g_CachedProfileData.EventIndexes; -} -void GetBossProfileAttributesInfo(const char[] profile, SF2BossProfileAttributesInfo params) -{ - g_BossProfileData.GetArray(profile, g_CachedProfileData, sizeof(g_CachedProfileData)); - params = g_CachedProfileData.AttributesInfo; -} - -int GetBossProfileJumpscareSound(const char[] profile, char[] buffer, int bufferlen) -{ - g_BossProfileData.GetArray(profile, g_CachedProfileData, sizeof(g_CachedProfileData)); - return strcopy(buffer, bufferlen, g_CachedProfileData.JumpscareSound); -} - -int GetBossProfileStaticSound(const char[] profile, char[] buffer, int bufferlen) -{ - g_BossProfileData.GetArray(profile, g_CachedProfileData, sizeof(g_CachedProfileData)); - return strcopy(buffer, bufferlen, g_CachedProfileData.StaticSound); -} - -int GetBossProfileStaticLocalSound(const char[] profile, char[] buffer, int bufferlen) -{ - g_BossProfileData.GetArray(profile, g_CachedProfileData, sizeof(g_CachedProfileData)); - return strcopy(buffer, bufferlen, g_CachedProfileData.StaticLocalSound); -} - -int GetBossProfileStaticShakeSound(const char[] profile, char[] buffer, int bufferlen) -{ - g_BossProfileData.GetArray(profile, g_CachedProfileData, sizeof(g_CachedProfileData)); - return strcopy(buffer, bufferlen, g_CachedProfileData.StaticShakeLocal); -} - -int GetBossProfileOverlayJumpscare(const char[] profile, char[] buffer, int bufferlen) -{ - g_BossProfileData.GetArray(profile, g_CachedProfileData, sizeof(g_CachedProfileData)); - return strcopy(buffer, bufferlen, g_CachedProfileData.OverlayJumpscare); -} - -int GetBossProfileOverlayPlayerDeath(const char[] profile, char[] buffer, int bufferlen) -{ - g_BossProfileData.GetArray(profile, g_CachedProfileData, sizeof(g_CachedProfileData)); - return strcopy(buffer, bufferlen, g_CachedProfileData.OverlayPlayerDeath); -} + profileData.PostLoad(); -ArrayList GetBossProfileCompanions(const char[] profile) -{ - g_BossProfileData.GetArray(profile, g_CachedProfileData, sizeof(g_CachedProfileData)); - return g_CachedProfileData.CompanionsArray; -} + g_BossProfileData.SetArray(profile, profileData, sizeof(profileData)); -int GetBossProfileCompanionsSpawnType(const char[] profile, char[] buffer, int bufferlen) -{ - g_BossProfileData.GetArray(profile, g_CachedProfileData, sizeof(g_CachedProfileData)); - return strcopy(buffer, bufferlen, g_CachedProfileData.CompanionSpawnType); -} + Call_StartForward(g_OnBossProfileLoadedFwd); + Call_PushString(profile); + Call_PushCell(kv); + Call_Finish(); -void GetBossProfileAnimationsData(const char[] profile, SF2BossProfileMasterAnimationsData data) -{ - g_BossProfileData.GetArray(profile, g_CachedProfileData, sizeof(g_CachedProfileData)); - data = g_CachedProfileData.AnimationData; -} \ No newline at end of file + return true; +}*/ diff --git a/addons/sourcemod/scripting/sf2/pve.sp b/addons/sourcemod/scripting/sf2/pve.sp index 00ef2e2b..98ed376c 100644 --- a/addons/sourcemod/scripting/sf2/pve.sp +++ b/addons/sourcemod/scripting/sf2/pve.sp @@ -1,4 +1,5 @@ #pragma semicolon 1 +#pragma newdecls required static bool g_PlayerInPvE[MAXTF2PLAYERS]; static bool g_PlayerIsLeavingPvE[MAXTF2PLAYERS]; @@ -438,9 +439,8 @@ static void OnPlayerAverageUpdate(SF2_BasePlayer client) SF2_ChaserEntity chaser = SF2_ChaserEntity(EntRefToEntIndex(bosses.Get(i2))); if (chaser.IsValid() && chaser.Controller.IsValid()) { - SF2BossProfileData data; - data = view_as(chaser.Controller).GetProfileData(); - data.Names.GetString(1, name, sizeof(name)); + ChaserBossProfile data = chaser.Controller.GetProfileDataEx(); + data.GetName(1, name, sizeof(name)); if (!data.DisplayPvEHealth) { continue; @@ -875,13 +875,9 @@ static void SpawnPvEBoss(const char[] override = "") if (npc.IsValid()) { npc.Spawn(spawnPos); - SF2BossProfileData data; - data = npc.GetProfileData(); - SF2BossProfileSoundInfo soundInfo; - soundInfo = data.MusicSoundsNormal; - SF2ChaserBossProfileData chaserData; - chaserData = view_as(npc).GetProfileData(); - g_PvEBoxingMode = chaserData.BoxingBoss; + ChaserBossProfile data = view_as(npc).GetProfileDataEx(); + ProfileSound soundInfo = data.GetGlobalMusic(1); + g_PvEBoxingMode = data.BoxingBoss; if (soundInfo.Paths != null && soundInfo.Paths.Length > 0) { soundInfo.Paths.GetString(GetRandomInt(0, soundInfo.Paths.Length - 1), g_CustomMusicOverride, sizeof(g_CustomMusicOverride)); @@ -900,14 +896,13 @@ static void SpawnPvEBoss(const char[] override = "") testNPC.Spawn(spawnPos); g_ActiveBosses.Push(EntIndexToEntRef(testNPC.EntIndex)); - SF2BossProfileData tempData; - tempData = testNPC.GetProfileData(); + BaseBossProfile tempData = testNPC.GetProfileDataEx(); - if (tempData.CopiesInfo.Enabled[1]) + if (tempData.GetCopies().IsEnabled(1)) { char tempProfile[SF2_MAX_PROFILE_NAME_LENGTH]; testNPC.GetProfile(tempProfile, sizeof(tempProfile)); - for (int i2 = 0; i2 < tempData.CopiesInfo.MaxCopies[1]; i2++) + for (int i2 = 0; i2 < tempData.GetCopies().GetMaxCopies(1); i2++) { SF2NPC_BaseNPC copy = AddProfile(tempProfile, _, testNPC); if (!copy.IsValid()) @@ -921,9 +916,9 @@ static void SpawnPvEBoss(const char[] override = "") } } - if (data.CopiesInfo.Enabled[1]) + if (data.GetCopies().IsEnabled(1)) { - for (int i = 0; i < data.CopiesInfo.MaxCopies[1]; i++) + for (int i = 0; i < data.GetCopies().GetMaxCopies(1); i++) { SF2NPC_BaseNPC copy = AddProfile(profile, _, npc); if (!copy.IsValid()) @@ -1259,9 +1254,7 @@ void KillPvEBoss(int boss) float time = 5.0; if (bossIndex != -1) { - SF2BossProfileData data; - data = NPCGetProfileData(bossIndex); - time = data.PvETeleportEndTimer; + time = SF2NPC_BaseNPC(bossIndex).GetProfileDataEx().PvETeleportEndTimer; } for (int i = 1; i <= MaxClients; i++) { @@ -1314,9 +1307,7 @@ static Action Timer_RemoveAllPvEBosses(Handle timer) continue; } - SF2BossProfileData data; - data = npc.GetProfileData(); - if (!data.IsPvEBoss) + if (!npc.GetProfileDataEx().IsPvEBoss) { continue; } diff --git a/addons/sourcemod/scripting/sf2/pvp.sp b/addons/sourcemod/scripting/sf2/pvp.sp index 0d359e80..3e2a26e6 100644 --- a/addons/sourcemod/scripting/sf2/pvp.sp +++ b/addons/sourcemod/scripting/sf2/pvp.sp @@ -998,24 +998,6 @@ void PvP_OnClientGhostModeEnable(int client) g_PlayerPvPRespawnTimer[client] = null; } -static bool Hook_ClientPvPShouldCollide(int ent,int collisiongroup,int contentsmask, bool originalResult) -{ - if (!g_Enabled || g_PlayerProxy[ent] || !IsClientInPvP(ent) || !g_PlayerEliminated[ent]) - { - SDKUnhook(ent, SDKHook_ShouldCollide, Hook_ClientPvPShouldCollide); - if (collisiongroup == 8) - { - return false; - } - return originalResult; - } - if (IsClientInPvP(ent) && GetClientTeam(ent) == TFTeam_Blue && collisiongroup == 8) - { - return true; - } - return originalResult; -} - void PvP_OnTriggerStartTouch(int trigger, int other) { char name[64]; diff --git a/addons/sourcemod/scripting/sf2/pvp/menus.sp b/addons/sourcemod/scripting/sf2/pvp/menus.sp index 1994ccdb..bebc4cc3 100644 --- a/addons/sourcemod/scripting/sf2/pvp/menus.sp +++ b/addons/sourcemod/scripting/sf2/pvp/menus.sp @@ -5,6 +5,7 @@ #define _sf2_pvp_menus #pragma semicolon 1 +#pragma newdecls required Menu g_MenuSettingsPvP; diff --git a/addons/sourcemod/scripting/sf2/specialround.sp b/addons/sourcemod/scripting/sf2/specialround.sp index e45ad534..e0d07c99 100644 --- a/addons/sourcemod/scripting/sf2/specialround.sp +++ b/addons/sourcemod/scripting/sf2/specialround.sp @@ -4,6 +4,7 @@ #define _sf2_specialround_included #pragma semicolon 1 +#pragma newdecls required #define SR_CYCLELENGTH 10.0 #define SR_STARTDELAY 0.25 @@ -1010,7 +1011,6 @@ static ArrayList SpecialEnabledList() { AddSpecialRoundToList(SPECIALROUND_TRIPLEBOSSES, enabledRounds); } - if (!SF_SpecialRound(SPECIALROUND_MODBOSSES) && !SF_IsRaidMap() && !SF_IsBoxingMap() && !SF_BossesChaseEndlessly() && !SF_IsProxyMap() && !SF_SpecialRound(SPECIALROUND_VOTE) && (GetSelectableAdminBossProfileList().Length > 0 || IsProfileValid(snatcher))) { AddSpecialRoundToList(SPECIALROUND_MODBOSSES, enabledRounds); @@ -1345,7 +1345,6 @@ void SpecialRoundStart() char buffer[SF2_MAX_PROFILE_NAME_LENGTH], nightmareDisplay[256]; if (!SF_SpecialRound(SPECIALROUND_DOUBLEROULETTE) && !SF_SpecialRound(SPECIALROUND_REVOLUTION)) { - NPCStopMusic(); NPCRemoveAll(); } ArrayList selectableBosses = GetSelectableAdminBossProfileList().Clone(); @@ -1531,10 +1530,9 @@ void SpecialRoundStart() case SPECIALROUND_TRIPLEBOSSES: { char buffer[SF2_MAX_PROFILE_NAME_LENGTH]; - int tripleBosses=0; + int tripleBosses = 0; for (int i = 0; i < MAX_BOSSES; i++) { - NPCStopMusic(); SF2NPC_BaseNPC Npc = SF2NPC_BaseNPC(i); if (!Npc.IsValid()) { diff --git a/addons/sourcemod/scripting/sf2/stocks.sp b/addons/sourcemod/scripting/sf2/stocks.sp index 71180d4d..d7b538b8 100644 --- a/addons/sourcemod/scripting/sf2/stocks.sp +++ b/addons/sourcemod/scripting/sf2/stocks.sp @@ -4,6 +4,7 @@ #define _sf2_stocks_included #pragma semicolon 1 +#pragma newdecls required #define VALID_MINIMUM_MEMORY_ADDRESS 0x10000 @@ -417,6 +418,31 @@ bool CBaseAnimating_GetSequenceVelocity(Address studioHdr, int sequence, float c return SDKCall(g_SDKSequenceVelocity, studioHdr, sequence, cycle, poseParameter, velocity); } +float GetDamageDistance(float start[3], float end[3], float baseDamage, float minRange, float maxRange, float minMultiplier, float maxMultiplier) +{ + float minDamage = baseDamage * minMultiplier; + float maxDamage = baseDamage * maxMultiplier; + float newDamage = baseDamage; + + float distance = GetVectorDistance(start, end, true); + float percent = (distance - minRange) / (maxRange - minRange); + if (percent <= 0.0) + { + percent = distance / minRange; + newDamage = LerpFloats(maxDamage, baseDamage, percent); + } + else + { + if (percent > 1.0) + { + percent = 1.0; + } + newDamage = LerpFloats(baseDamage, minDamage, percent); + } + + return newDamage; +} + // ========================================================= // GLOW FUNCTIONS // ========================================================= @@ -1105,7 +1131,7 @@ void UTIL_ScreenShake(float center[3], float amplitude, float frequency, float d SF2_BasePlayer player = SF2_BasePlayer(i); if (player.IsValid && !player.IsBot && !player.IsInGhostMode) { - if (!airShake && command == 0 && !(player.GetFlags() && FL_ONGROUND)) + if (!airShake && command == 0 && (player.GetFlags() & FL_ONGROUND) != 0) { continue; } @@ -1237,7 +1263,7 @@ void CopyVector(const float copy[3], float dest[3]) dest[2] = copy[2]; } -/*void LerpVectors(const float a[3] , const float b[3], float c[3], float t) +void LerpVectors(const float a[3] , const float b[3], float c[3], float t) { if (t < 0.0) { @@ -1251,7 +1277,7 @@ void CopyVector(const float copy[3], float dest[3]) c[0] = a[0] + (b[0] - a[0]) * t; c[1] = a[1] + (b[1] - a[1]) * t; c[2] = a[2] + (b[2] - a[2]) * t; -}*/ +} /** * Translates and re-orients a given offset vector into world space, given a world position and angle. @@ -1470,19 +1496,6 @@ Action Timer_KillEntity(Handle timer, any entref) return Plugin_Stop; } -Action Timer_KillEdict(Handle timer, any entref) -{ - int ent = EntRefToEntIndex(entref); - if (!ent || ent == INVALID_ENT_REFERENCE) - { - return Plugin_Stop; - } - - RemoveEdict(ent); - - return Plugin_Stop; -} - // ========================================================== // SPECIAL ROUND FUNCTIONS // ========================================================== @@ -1565,15 +1578,9 @@ int GetLocalGlobalDifficulty(int npcIndex = -1) { return g_DifficultyConVar.IntValue; } - SF2BossProfileData data; SF2NPC_BaseNPC controller = SF2NPC_BaseNPC(npcIndex); - data = controller.GetProfileData(); - SF2ChaserBossProfileData chaserData; - if (data.Type == SF2BossType_Chaser) - { - chaserData = view_as(controller).GetProfileData(); - } - if (data.IsPvEBoss || chaserData.BoxingBoss) + ChaserBossProfile data = view_as(controller.GetProfileDataEx()); + if (data.IsPvEBoss || data.BoxingBoss) { if (NPCGetUniqueID(npcIndex) != -1) { diff --git a/addons/sourcemod/scripting/sf2/traps.sp b/addons/sourcemod/scripting/sf2/traps.sp index 56f246da..fa837bc9 100644 --- a/addons/sourcemod/scripting/sf2/traps.sp +++ b/addons/sourcemod/scripting/sf2/traps.sp @@ -4,6 +4,7 @@ #define _sf2_traps_included #pragma semicolon 1 +#pragma newdecls required static float g_TrapDespawnTimer[2049]; static bool g_TrapClosed[2049]; @@ -64,11 +65,11 @@ void Trap_SpawnTrap(float position[3], float direction[3], SF2NPC_Chaser control float yaw = GetAngleBetweenVectors(product2, cross, tempAngles); RotateYaw(newAngles, yaw - 90.0); - SF2ChaserBossProfileData data; - data = controller.GetProfileData(); + ChaserBossProfile data = controller.GetProfileDataEx(); int difficulty = controller.Difficulty; + char buffer[PLATFORM_MAX_PATH]; - switch (data.TrapType[difficulty]) + switch (data.GetTrapType(difficulty)) { case SF2BossTrapType_BearTrap: { @@ -76,7 +77,8 @@ void Trap_SpawnTrap(float position[3], float direction[3], SF2NPC_Chaser control if (trapEntity != -1) { TeleportEntity(trapEntity, newPos, newAngles, NULL_VECTOR); - SetEntityModel(trapEntity, data.TrapModel); + data.GetTrapModel(buffer, sizeof(buffer)); + SetEntityModel(trapEntity, buffer); DispatchSpawn(trapEntity); ActivateEntity(trapEntity); @@ -104,16 +106,19 @@ void Trap_SpawnTrap(float position[3], float direction[3], SF2NPC_Chaser control g_TrapClosed[trapEntity] = false; g_TrapAnimChange[trapEntity] = true; SetEntProp(trapEntity, Prop_Data, "m_bSequenceLoops", false); - if (data.TrapAnimOpen[0] != '\0') + + data.GetTrapOpenAnimation(buffer, sizeof(buffer)); + if (buffer[0] != '\0') { - SetVariantString(data.TrapAnimOpen); + SetVariantString(buffer); AcceptEntityInput(trapEntity, "SetAnimation"); HookSingleEntityOutput(trapEntity, "OnAnimationDone", OnTrapOpenComplete, false); g_TrapStartedOpenAnim[trapEntity] = true; } else { - SetVariantString(data.TrapAnimIdle); + data.GetTrapIdleAnimation(buffer, sizeof(buffer)); + SetVariantString(buffer); AcceptEntityInput(trapEntity, "SetAnimation"); } @@ -122,7 +127,8 @@ void Trap_SpawnTrap(float position[3], float direction[3], SF2NPC_Chaser control g_TrapDespawnTimer[trapEntity] = GetGameTime() + GetRandomFloat(20.0, 40.0); g_TrapState[trapEntity] = 0; - EmitSoundToAll(data.TrapDeploySound, trapEntity, SNDCHAN_AUTO, SNDLEVEL_SCREAMING, _, 1.0); + data.GetTrapDeploySound(buffer, sizeof(buffer)); + EmitSoundToAll(buffer, trapEntity, SNDCHAN_AUTO, SNDLEVEL_SCREAMING, _, 1.0); SDKHook(trapEntity, SDKHook_OnTakeDamage, Hook_TrapOnTakeDamage); g_TrapTimer[trapEntity] = CreateTimer(0.1, Timer_TrapThink, EntIndexToEntRef(trapEntity), TIMER_FLAG_NO_MAPCHANGE | TIMER_REPEAT); @@ -211,10 +217,12 @@ static Action Timer_TrapThink(Handle timer, any entref) player.TakeDamage(true, _, _, 10.0, 128); g_TrapState[trapEntity] = 1; g_TrapAnimChange[trapEntity] = true; - SF2ChaserBossProfileData data; - data = controller.GetProfileData(); - EmitSoundToAll(data.TrapCatchSound, trapEntity, SNDCHAN_AUTO, SNDLEVEL_SCREAMING, _, 1.0); - SetVariantString(data.TrapAnimClose); + ChaserBossProfile data = controller.GetProfileDataEx(); + char buffer[PLATFORM_MAX_PATH]; + data.GetTrapCatchSound(buffer, sizeof(buffer)); + EmitSoundToAll(buffer, trapEntity, SNDCHAN_AUTO, SNDLEVEL_SCREAMING, _, 1.0); + data.GetTrapClosedAnimation(buffer, sizeof(buffer)); + SetVariantString(buffer); AcceptEntityInput(trapEntity, "SetAnimation"); AcceptEntityInput(trapEntity, "DisableCollision"); g_TrapClosed[trapEntity] = true; @@ -238,28 +246,31 @@ static void TrapUpdateAnimation(int trapEntity) { return; } - SF2ChaserBossProfileData data; - data = controller.GetProfileData(); + ChaserBossProfile data = controller.GetProfileDataEx(); + char buffer[PLATFORM_MAX_PATH]; switch (state) { case 0: { - if (!g_TrapStartedOpenAnim[trapEntity] && data.TrapAnimOpen[0] != '\0') + data.GetTrapOpenAnimation(buffer, sizeof(buffer)); + if (!g_TrapStartedOpenAnim[trapEntity] && buffer[0] != '\0') { - SetVariantString(data.TrapAnimOpen); + SetVariantString(buffer); AcceptEntityInput(trapEntity, "SetAnimation"); HookSingleEntityOutput(trapEntity, "OnAnimationDone", OnTrapOpenComplete, true); g_TrapStartedOpenAnim[trapEntity] = true; } else if (g_TrapDoIdleAnim[trapEntity]) { - SetVariantString(data.TrapAnimIdle); + data.GetTrapIdleAnimation(buffer, sizeof(buffer)); + SetVariantString(buffer); AcceptEntityInput(trapEntity, "SetAnimation"); } } case 1: { - SetVariantString(data.TrapAnimClose); + data.GetTrapClosedAnimation(buffer, sizeof(buffer)); + SetVariantString(buffer); AcceptEntityInput(trapEntity, "SetAnimation"); AcceptEntityInput(trapEntity, "DisableCollision"); } @@ -294,10 +305,12 @@ static Action Hook_TrapOnTakeDamage(int trapEntity, int &attacker, int &inflicto g_TrapState[trapEntity] = 1; g_TrapAnimChange[trapEntity] = true; SF2NPC_Chaser controller = g_TrapMaster[trapEntity]; - SF2ChaserBossProfileData data; - data = controller.GetProfileData(); - EmitSoundToAll(data.TrapMissSound, trapEntity, SNDCHAN_AUTO, SNDLEVEL_SCREAMING, _, 1.0); - SetVariantString(data.TrapAnimClose); + ChaserBossProfile data = controller.GetProfileDataEx(); + char buffer[PLATFORM_MAX_PATH]; + data.GetTrapMissSound(buffer, sizeof(buffer)); + EmitSoundToAll(buffer, trapEntity, SNDCHAN_AUTO, SNDLEVEL_SCREAMING, _, 1.0); + data.GetTrapClosedAnimation(buffer, sizeof(buffer)); + SetVariantString(buffer); AcceptEntityInput(trapEntity, "SetAnimation"); AcceptEntityInput(trapEntity, "DisableCollision"); if (g_TrapDespawnTimer[trapEntity] > 5.0) From 8b561f56f8e18964895cab6f6c03b56a3a63d96e Mon Sep 17 00:00:00 2001 From: Mentrillum Date: Tue, 24 Dec 2024 10:41:07 -0700 Subject: [PATCH 2/5] Update sf2.phrases.txt --- addons/sourcemod/translations/sf2.phrases.txt | 32 +++++++++++++++++++ 1 file changed, 32 insertions(+) diff --git a/addons/sourcemod/translations/sf2.phrases.txt b/addons/sourcemod/translations/sf2.phrases.txt index 3c0617d3..3224f6ec 100644 --- a/addons/sourcemod/translations/sf2.phrases.txt +++ b/addons/sourcemod/translations/sf2.phrases.txt @@ -706,6 +706,16 @@ "ko" "HUD 버전 설정" } + "SF2 Settings Hud New" + { + "en" "New" + } + + "SF2 Settings Hud Legacy" + { + "en" "Legacy" + } + "SF2 Settings Music Volume Title" { "en" "Set music volume" @@ -732,6 +742,11 @@ "ko" "{lightblue}음악 볼륨이 {1}%% 으로 설정 되었습니다." } + "SF2 Settings Projected Flashlight Title" + { + "en" "Projected flashlight" + } + "SF2 Settings Flashlight Temperature Title" { "en" "Set flashlight temperature" @@ -1161,6 +1176,23 @@ "ko" "현재 보스 재정의 : {1}" } + "SF2 Disabled Boss Pack" + { + "en" "{red}Boss Pack vote is disabled on this server." + } + + "SF2 Boss Pack Next" + { + "#format" "{1:s}" + "en" "{dodgerblue}Next boss pack: {lightblue}{1}{default}." + } + + "SF2 Current Boss Pack" + { + "#format" "{1:s}" + "en" "{dodgerblue}Current boss pack: {lightblue}{1}{default}." + } + "SF2 Admin Menu Player Set Play State" { "en" "Force player in/out of game" From 16fe77680eda6f723134dbafaad644a638445481 Mon Sep 17 00:00:00 2001 From: Mentrillum Date: Wed, 25 Dec 2024 21:56:03 -0700 Subject: [PATCH 3/5] 12-25-24 --- addons/sourcemod/scripting/include/sf2.inc | 78 +++- addons/sourcemod/scripting/sf2.sp | 114 +++--- addons/sourcemod/scripting/sf2/adminmenu.sp | 10 +- addons/sourcemod/scripting/sf2/client.sp | 333 ++++++++++++++++++ .../sourcemod/scripting/sf2/client/blink.sp | 2 +- .../scripting/sf2/client/deathcam.sp | 4 +- .../scripting/sf2/client/ghostmode.sp | 2 +- .../sourcemod/scripting/sf2/client/music.sp | 44 +-- .../scripting/sf2/client/new_music.sp | 12 +- .../sourcemod/scripting/sf2/client/proxy.sp | 10 +- .../sourcemod/scripting/sf2/client/sprint.sp | 4 +- .../sourcemod/scripting/sf2/client/think.sp | 293 --------------- .../sourcemod/scripting/sf2/client/weapons.sp | 2 +- addons/sourcemod/scripting/sf2/effects.sp | 22 ++ .../scripting/sf2/extras/commands.sp | 15 +- .../scripting/sf2/extras/game_events.sp | 21 +- .../sourcemod/scripting/sf2/extras/natives.sp | 4 +- .../scripting/sf2/gamemodes/renevant.sp | 4 +- .../sf2/mapentities/sf2_boss_maker.sp | 2 +- addons/sourcemod/scripting/sf2/methodmaps.sp | 14 +- addons/sourcemod/scripting/sf2/npc.sp | 105 +++--- .../sf2/npc/entities/base/actions/deathcam.sp | 2 +- .../base/actions/playsequenceandwait_ex.sp | 18 +- .../scripting/sf2/npc/entities/base/entity.sp | 20 +- .../sf2/npc/entities/chaser/actions/alert.sp | 18 +- .../sf2/npc/entities/chaser/actions/attack.sp | 79 ++++- .../entities/chaser/actions/attacks/bullet.sp | 4 +- .../entities/chaser/actions/attacks/custom.sp | 2 +- .../chaser/actions/attacks/explosive_dance.sp | 2 +- .../chaser/actions/attacks/forward_based.sp | 2 +- .../chaser/actions/attacks/laser_beam.sp | 2 +- .../entities/chaser/actions/attacks/melee.sp | 25 +- .../chaser/actions/attacks/projectile.sp | 6 +- .../entities/chaser/actions/attacks/tongue.sp | 4 +- .../sf2/npc/entities/chaser/actions/chase.sp | 8 +- .../entities/chaser/actions/chaseinitial.sp | 4 +- .../npc/entities/chaser/actions/chaselayer.sp | 9 +- .../sf2/npc/entities/chaser/actions/death.sp | 28 +- .../entities/chaser/actions/flee_to_heal.sp | 4 +- .../sf2/npc/entities/chaser/actions/idle.sp | 4 +- .../npc/entities/chaser/actions/mainlayer.sp | 14 +- .../sf2/npc/entities/chaser/actions/rage.sp | 4 +- .../sf2/npc/entities/chaser/actions/smell.sp | 4 +- .../sf2/npc/entities/chaser/actions/stun.sp | 22 +- .../npc/entities/chaser/actions/tauntkill.sp | 6 +- .../sf2/npc/entities/chaser/entity.sp | 217 ++++++++---- .../npc/entities/chaser/postures/on_alert.sp | 2 +- .../npc/entities/chaser/postures/on_cloak.sp | 2 +- .../npc/entities/chaser/postures/on_look.sp | 2 +- .../entities/chaser/postures/rage_phase.sp | 2 +- .../entities/chaser/postures/running_away.sp | 2 +- .../entities/chaser/postures/within_bounds.sp | 2 +- .../entities/chaser/postures/within_range.sp | 2 +- .../sf2/npc/entities/statue/actions/chase.sp | 6 +- .../npc/entities/statue/actions/mainlayer.sp | 2 +- .../sf2/npc/entities/statue/entity.sp | 14 +- addons/sourcemod/scripting/sf2/npc/glow.sp | 33 +- .../sourcemod/scripting/sf2/npc/npc_chaser.sp | 18 +- .../scripting/sf2/npc/npc_creeper.sp | 6 +- addons/sourcemod/scripting/sf2/profiles.sp | 203 ++++------- .../scripting/sf2/profiles/keymap.sp | 6 - .../scripting/sf2/profiles/objects.sp | 58 ++- .../scripting/sf2/profiles/profile_chaser.sp | 62 +++- .../sf2/profiles/profiles_boss_functions.sp | 233 +++++++----- addons/sourcemod/scripting/sf2/pve.sp | 116 ++++-- .../sourcemod/scripting/sf2/specialround.sp | 44 +-- addons/sourcemod/scripting/sf2/stocks.sp | 2 +- addons/sourcemod/scripting/sf2/traps.sp | 8 +- 68 files changed, 1431 insertions(+), 997 deletions(-) diff --git a/addons/sourcemod/scripting/include/sf2.inc b/addons/sourcemod/scripting/include/sf2.inc index 6e82b165..ff4f2542 100644 --- a/addons/sourcemod/scripting/include/sf2.inc +++ b/addons/sourcemod/scripting/include/sf2.inc @@ -7,8 +7,8 @@ #include #include -#define PLUGIN_VERSION "1.8.0 M Alpha 3 Indev 12-21-2024" -#define PLUGIN_VERSION_DISPLAY "1.8.0 M Alpha 3 Indev 12-21-2024" +#define PLUGIN_VERSION "1.8.0 M Alpha 3 Indev 12-25-2024" +#define PLUGIN_VERSION_DISPLAY "1.8.0 M Alpha 3 Indev 12-25-2024" // Some defines. #define SF2_MAX_PROFILE_NAME_LENGTH 64 @@ -2249,7 +2249,7 @@ methodmap SF2_ProfileObject < Handle } /** - * Retrieve the number of keys (not sections) that exist in this section. + * Retrieve the number of keys (not sections) that exist in this object. */ property int KeyLength { @@ -2257,19 +2257,47 @@ methodmap SF2_ProfileObject < Handle } /** - * Retrieve the number of sections (not keys) that exist in this section. + * Retrieve the number of sections (not keys) that exist in this object. */ property int SectionLength { public native get(); } + /** + * Retrieves the object's name + * + * @param buffer String buffer + * @param bufferSize Size of string buffer + */ + public native void GetSectionName(char[] buffer, int bufferSize); + + /** + * Retrieves a key's name from a specified index. + * + * @param index Index to use + * @param buffer String buffer + * @param bufferSize Size of string buffer + * @return True on success, false otherwise + */ + public native bool GetKeyNameFromIndex(int index, char[] buffer, int bufferSize); + + /** + * Retrieves a section's name from a specified index. + * + * @param index Index to use + * @param buffer String buffer + * @param bufferSize Size of string buffer + * @return True on success, false otherwise + */ + public native bool GetSectionNameFromIndex(int index, char[] buffer, int bufferSize); + /** * Retrieves an integer value from the given key. * - * @param key Key name - * @param defaultValue Value to return as a fallback - * @return Value stored at key + * @param key Key name + * @param defaultValue Value to return as a fallback + * @return Value stored at key */ public native int GetInt(const char[] key, int defaultValue = 0); @@ -2480,7 +2508,6 @@ methodmap SF2_ProfileObject < Handle * @param difficulty Difficulty value * @param buffer Float buffer * @param defaultValue Value to return as a fallback - * @return Value stored at key */ public native void GetDifficultyVector(const char[] key, int difficulty, float buffer[3], const float defaultValue[3] = { 0.0, 0.0, 0.0 }); @@ -2500,7 +2527,6 @@ methodmap SF2_ProfileObject < Handle * @param difficulty Difficulty value * @param buffer Float buffer * @param defaultValue Value to return as a fallback - * @return Value stored at key */ public native void GetDifficultyColor(const char[] key, int difficulty, int buffer[4], const int defaultValue[4] = { 0, 0, 0, 0 }); @@ -3029,19 +3055,49 @@ methodmap SF2_ChaserBossProfileBaseAttack < SF2_ProfileObject */ public native float GetCooldown(int difficulty); + /** + * Determines what the minimum difficulty must be for this attack to be used on + * Anything lower than this threshold blocks the attack. + */ property int UseOnDifficulty { public native get(); } + /** + * Determines what the maximum difficulty must not be for this attack to be used + * Anything higher than this threshold blocks the attack. + */ property int BlockOnDifficulty { public native get(); } + /** + * Determines how much health the target must have at maximum for this attack to be used. + * Anything higher than this threshold blocks the attack. + * + * @param difficulty Difficulty value + * @return Maximum health threshold + */ public native float CanUseOnHealth(int difficulty); + /** + * Determines how much health the target must have at minimum for this attack to be used. + * Anything lower than this threshold blocks the attack. + * + * @param difficulty Difficulty value + * @return Minimum health threshold + */ public native float CanBlockOnHealth(int difficulty); + + /** + * The animation's event index that'll be used for an attack to fire. + * + * @param difficulty Difficulty value + * @return Animation event index + */ + public native int GetEventNumber(int difficulty); } /** @@ -4788,6 +4844,9 @@ public void __pl_sf2_SetNTVOptional() MarkNativeAsOptional("SF2_ProfileObject.Parent.get"); MarkNativeAsOptional("SF2_ProfileObject.KeyLength.get"); MarkNativeAsOptional("SF2_ProfileObject.SectionLength.get"); + MarkNativeAsOptional("SF2_ProfileObject.GetSectionName"); + MarkNativeAsOptional("SF2_ProfileObject.GetKeyNameFromIndex"); + MarkNativeAsOptional("SF2_ProfileObject.GetSectionNameFromIndex"); MarkNativeAsOptional("SF2_ProfileObject.GetInt"); MarkNativeAsOptional("SF2_ProfileObject.SetInt"); MarkNativeAsOptional("SF2_ProfileObject.GetBool"); @@ -4885,6 +4944,7 @@ public void __pl_sf2_SetNTVOptional() MarkNativeAsOptional("SF2_ChaserBossProfileBaseAttack.BlockOnDifficulty.get"); MarkNativeAsOptional("SF2_ChaserBossProfileBaseAttack.CanUseOnHealth"); MarkNativeAsOptional("SF2_ChaserBossProfileBaseAttack.CanBlockOnHealth"); + MarkNativeAsOptional("SF2_ChaserBossProfileBaseAttack.GetEventNumber"); MarkNativeAsOptional("SF2_ChaserBossProfileCustomAttack.GetSubType"); MarkNativeAsOptional("SF2_ChaserBossProfileCustomAttack.IsSubType"); diff --git a/addons/sourcemod/scripting/sf2.sp b/addons/sourcemod/scripting/sf2.sp index 4c2106d8..7633cfa5 100644 --- a/addons/sourcemod/scripting/sf2.sp +++ b/addons/sourcemod/scripting/sf2.sp @@ -577,6 +577,7 @@ PrivateForward g_OnAdminMenuCreateOptionsPFwd; PrivateForward g_OnPlayerJumpPFwd; PrivateForward g_OnPlayerSpawnPFwd; PrivateForward g_OnPlayerTakeDamagePFwd; +PrivateForward g_OnPlayerTakeDamagePostPFwd; PrivateForward g_OnPlayerDeathPrePFwd; PrivateForward g_OnPlayerDeathPFwd; PrivateForward g_OnPlayerPutInServerPFwd; @@ -837,7 +838,6 @@ public void OnConfigsExecuted() continue; } g_ClientInGame[i] = true; - SDKHook(i, SDKHook_OnTakeDamage, Hook_ClientOnTakeDamage); Call_StartForward(g_OnPlayerPutInServerPFwd); Call_PushCell(SF2_BasePlayer(i)); Call_Finish(); @@ -1427,17 +1427,17 @@ static Action Timer_GlobalGameFrame(Handle timer) } SF2NPC_Chaser controller = chaser.Controller; - if (!controller.GetProfileDataEx().BoxingBoss) + if (!controller.GetProfileData().BoxingBoss) { continue; } SF2NPC_BaseNPC baseNPC = view_as(controller); - if (baseNPC.GetProfileDataEx().IsPvEBoss) + if (baseNPC.GetProfileData().IsPvEBoss) { continue; } - baseNPC.GetProfileDataEx().GetName(1, boxingBossName, sizeof(boxingBossName)); + baseNPC.GetProfileData().GetName(1, boxingBossName, sizeof(boxingBossName)); float health = float(chaser.GetProp(Prop_Data, "m_iHealth")); float maxHealth = chaser.MaxHealth; if (chaser.GetProp(Prop_Data, "m_takedamage") == DAMAGE_EVENTS_ONLY) @@ -1477,7 +1477,7 @@ static Action Timer_GlobalGameFrame(Handle timer) } int difficulty = GetLocalGlobalDifficulty(bossIndex); - BossProfileProxyData proxyData = SF2NPC_BaseNPC(bossIndex).GetProfileDataEx().GetProxies(); + BossProfileProxyData proxyData = SF2NPC_BaseNPC(bossIndex).GetProfileData().GetProxies(); if (!proxyData.IsEnabled(difficulty)) { @@ -1756,7 +1756,7 @@ static Action Timer_BossCountUpdate(Handle timer) SF2NPC_BaseNPC Npc = SF2NPC_BaseNPC(i); if (Npc.UniqueID == -1 || Npc.IsCopy || - (Npc.Flags & SFF_FAKE) || Npc.GetProfileDataEx().IsPvEBoss) + (Npc.Flags & SFF_FAKE) || Npc.GetProfileData().IsPvEBoss) { continue; } @@ -1764,7 +1764,7 @@ static Action Timer_BossCountUpdate(Handle timer) bossPreferredCount++; int difficulty = GetLocalGlobalDifficulty(Npc.Index); - BaseBossProfile data = Npc.GetProfileDataEx(); + BaseBossProfile data = Npc.GetProfileData(); if (!data.GetCopies().IsEnabled(GetLocalGlobalDifficulty(i)) || (Npc.Flags & SFF_NOCOPIES) != 0) { continue; @@ -1889,7 +1889,7 @@ static Action Timer_BossCountUpdate(Handle timer) { continue; } - if (Npc.GetProfileDataEx().IsPvEBoss) + if (Npc.GetProfileData().IsPvEBoss) { continue; } @@ -1957,7 +1957,7 @@ static Action Timer_BossCountUpdate(Handle timer) continue; } - if (Npc.GetProfileDataEx().IsPvEBoss) + if (Npc.GetProfileData().IsPvEBoss) { continue; } @@ -1965,7 +1965,7 @@ static Action Timer_BossCountUpdate(Handle timer) if (Npc.CanRemove) { SF2NPC_BaseNPC master = Npc.CopyMaster; - BaseBossProfile data = master.GetProfileDataEx(); + BaseBossProfile data = master.GetProfileData(); int difficulty = GetLocalGlobalDifficulty(master.Index); if (data.GetCopies().GetMinCopies(difficulty) > 0) { @@ -2031,7 +2031,7 @@ static Action Timer_BossCountUpdate(Handle timer) continue; } - BaseBossProfile data = Npc.GetProfileDataEx(); + BaseBossProfile data = Npc.GetProfileData(); if (!data.GetCopies().IsEnabled(GetLocalGlobalDifficulty(i)) || (Npc.Flags & SFF_NOCOPIES) != 0) { continue; @@ -3507,7 +3507,6 @@ public void OnClientPutInServer(int client) { if (g_LoadOutsideMapsConVar.BoolValue) { - SDKHook(client, SDKHook_OnTakeDamage, Hook_ClientOnTakeDamage); Call_StartForward(g_OnPlayerPutInServerPFwd); Call_PushCell(SF2_BasePlayer(client)); Call_Finish(); @@ -3551,7 +3550,6 @@ public void OnClientPutInServer(int client) SDKHook(client, SDKHook_PreThink, Hook_ClientPreThink); SDKHook(client, SDKHook_PreThinkPost, Hook_OnFlashlightThink); SDKHook(client, SDKHook_SetTransmit, Hook_ClientSetTransmit); - SDKHook(client, SDKHook_OnTakeDamage, Hook_ClientOnTakeDamage); g_DHookWantsLagCompensationOnEntity.HookEntity(Hook_Pre, client, Hook_ClientWantsLagCompensationOnEntity); @@ -4051,7 +4049,7 @@ void SetRoundState(SF2RoundState roundState) { continue; } - if (view_as(Npc).GetProfileDataEx().BoxingBoss && !Npc.GetProfileDataEx().IsPvEBoss) + if (view_as(Npc).GetProfileData().BoxingBoss && !Npc.GetProfileData().IsPvEBoss) { g_SlenderBoxingBossCount++; } @@ -4580,7 +4578,7 @@ void SlenderOnClientStressUpdate(int client) } Npc.GetProfile(profile, sizeof(profile)); - BaseBossProfile profileData = Npc.GetProfileDataEx(); + BaseBossProfile profileData = Npc.GetProfileData(); int teleportTarget = EntRefToEntIndex(g_SlenderProxyTarget[Npc.Index]); if (teleportTarget && teleportTarget != INVALID_ENT_REFERENCE) @@ -4915,7 +4913,7 @@ void SetPageCount(int num) { continue; } - BaseBossProfile data = SF2NPC_BaseNPC(npcIndex).GetProfileDataEx(); + BaseBossProfile data = SF2NPC_BaseNPC(npcIndex).GetProfileData(); if (data.GetSlaughterRunData() != null && data.GetSlaughterRunData().GetCustomSpawnTime(difficulty) > 0.0) { @@ -8085,38 +8083,24 @@ void InitializeNewGame() else { // Spawn the boss! - if (!SF_SpecialRound(SPECIALROUND_MODBOSSES)) + if (!SF_SpecialRound(SPECIALROUND_MODBOSSES) && !SF_IsRenevantMap()) { - if (!SF_IsBoxingMap() && !SF_IsRenevantMap()) + if (SF_SpecialRound(SPECIALROUND_DOUBLETROUBLE) || SF_SpecialRound(SPECIALROUND_SILENTSLENDER) || SF_SpecialRound(SPECIALROUND_2DOUBLE)) { - if (SF_SpecialRound(SPECIALROUND_DOUBLETROUBLE) || SF_SpecialRound(SPECIALROUND_SILENTSLENDER) || SF_SpecialRound(SPECIALROUND_2DOUBLE)) - { - AddProfile(g_RoundBossProfile); - RemoveBossProfileFromQueueList(g_RoundBossProfile); - } - else if (SF_SpecialRound(SPECIALROUND_TRIPLEBOSSES)) - { - AddProfile(g_RoundBossProfile); - AddProfile(g_RoundBossProfile, _, _, _, false); - AddProfile(g_RoundBossProfile, _, _, _, false); - RemoveBossProfileFromQueueList(g_RoundBossProfile); - } - else if (!SF_SpecialRound(SPECIALROUND_DOUBLETROUBLE) && !SF_SpecialRound(SPECIALROUND_SILENTSLENDER) && !SF_SpecialRound(SPECIALROUND_2DOUBLE) && !SF_SpecialRound(SPECIALROUND_TRIPLEBOSSES)) - { - AddProfile(g_RoundBossProfile); - RemoveBossProfileFromQueueList(g_RoundBossProfile); - } + AddProfile(g_RoundBossProfile); + RemoveBossProfileFromQueueList(g_RoundBossProfile); } - else if (SF_IsBoxingMap()) + else if (SF_SpecialRound(SPECIALROUND_TRIPLEBOSSES)) { - char buffer[SF2_MAX_PROFILE_NAME_LENGTH]; - ArrayList selectableBosses = GetSelectableBoxingBossProfileList().Clone(); - if (selectableBosses.Length > 0) - { - selectableBosses.GetString(GetRandomInt(0, selectableBosses.Length - 1), buffer, sizeof(buffer)); - AddProfile(buffer); - } - delete selectableBosses; + AddProfile(g_RoundBossProfile); + AddProfile(g_RoundBossProfile, _, _, _, false); + AddProfile(g_RoundBossProfile, _, _, _, false); + RemoveBossProfileFromQueueList(g_RoundBossProfile); + } + else if (!SF_SpecialRound(SPECIALROUND_DOUBLETROUBLE) &&!SF_SpecialRound(SPECIALROUND_SILENTSLENDER) && !SF_SpecialRound(SPECIALROUND_2DOUBLE) && !SF_SpecialRound(SPECIALROUND_TRIPLEBOSSES)) + { + AddProfile(g_RoundBossProfile); + RemoveBossProfileFromQueueList(g_RoundBossProfile); } } } @@ -8329,38 +8313,24 @@ static Action Timer_ActivateRoundFromIntro(Handle timer) SF2_RefreshRestrictions(); // Spawn the boss! - if (!SF_SpecialRound(SPECIALROUND_MODBOSSES)) + if (!SF_SpecialRound(SPECIALROUND_MODBOSSES) && !SF_IsRenevantMap()) { - if (!SF_IsBoxingMap() && !SF_IsRenevantMap()) + if (SF_SpecialRound(SPECIALROUND_DOUBLETROUBLE) || SF_SpecialRound(SPECIALROUND_SILENTSLENDER) || SF_SpecialRound(SPECIALROUND_2DOUBLE)) { - if (SF_SpecialRound(SPECIALROUND_DOUBLETROUBLE) || SF_SpecialRound(SPECIALROUND_SILENTSLENDER) || SF_SpecialRound(SPECIALROUND_2DOUBLE)) - { - AddProfile(g_RoundBossProfile); - RemoveBossProfileFromQueueList(g_RoundBossProfile); - } - else if (SF_SpecialRound(SPECIALROUND_TRIPLEBOSSES)) - { - AddProfile(g_RoundBossProfile); - AddProfile(g_RoundBossProfile, _, _, _, false); - AddProfile(g_RoundBossProfile, _, _, _, false); - RemoveBossProfileFromQueueList(g_RoundBossProfile); - } - else if (!SF_SpecialRound(SPECIALROUND_DOUBLETROUBLE) && !SF_SpecialRound(SPECIALROUND_SILENTSLENDER) && !SF_SpecialRound(SPECIALROUND_2DOUBLE) && !SF_SpecialRound(SPECIALROUND_TRIPLEBOSSES)) - { - AddProfile(g_RoundBossProfile); - RemoveBossProfileFromQueueList(g_RoundBossProfile); - } + AddProfile(g_RoundBossProfile); + RemoveBossProfileFromQueueList(g_RoundBossProfile); } - else if (SF_IsBoxingMap()) + else if (SF_SpecialRound(SPECIALROUND_TRIPLEBOSSES)) { - char buffer[SF2_MAX_PROFILE_NAME_LENGTH]; - ArrayList selectableBosses = GetSelectableBoxingBossProfileList().Clone(); - if (selectableBosses.Length > 0) - { - selectableBosses.GetString(GetRandomInt(0, selectableBosses.Length - 1), buffer, sizeof(buffer)); - AddProfile(buffer); - } - delete selectableBosses; + AddProfile(g_RoundBossProfile); + AddProfile(g_RoundBossProfile, _, _, _, false); + AddProfile(g_RoundBossProfile, _, _, _, false); + RemoveBossProfileFromQueueList(g_RoundBossProfile); + } + else if (!SF_SpecialRound(SPECIALROUND_DOUBLETROUBLE) && !SF_SpecialRound(SPECIALROUND_SILENTSLENDER) && !SF_SpecialRound(SPECIALROUND_2DOUBLE) && !SF_SpecialRound(SPECIALROUND_TRIPLEBOSSES)) + { + AddProfile(g_RoundBossProfile); + RemoveBossProfileFromQueueList(g_RoundBossProfile); } } return Plugin_Stop; diff --git a/addons/sourcemod/scripting/sf2/adminmenu.sp b/addons/sourcemod/scripting/sf2/adminmenu.sp index 04fc8ced..add089a8 100644 --- a/addons/sourcemod/scripting/sf2/adminmenu.sp +++ b/addons/sourcemod/scripting/sf2/adminmenu.sp @@ -1035,7 +1035,7 @@ static int AdminMenu_BossWanderToPos(Menu menu, MenuAction action, int param1, i else { SF2NPC_BaseNPC npc = SF2NPC_BaseNPC(index); - switch (npc.GetProfileDataEx().Type) + switch (npc.GetProfileData().Type) { case SF2BossType_Chaser: { @@ -1135,7 +1135,7 @@ static int AdminMenu_BossAlertToPos(Menu menu, MenuAction action, int param1, in else { SF2NPC_BaseNPC npc = SF2NPC_BaseNPC(index); - switch (npc.GetProfileDataEx().Type) + switch (npc.GetProfileData().Type) { case SF2BossType_Chaser: { @@ -1199,13 +1199,13 @@ static bool DisplayBossAttackAdminMenu(int client) continue; } - if (SF2NPC_BaseNPC(i).GetProfileDataEx().Type != SF2BossType_Chaser) + if (SF2NPC_BaseNPC(i).GetProfileData().Type != SF2BossType_Chaser) { continue; } SF2NPC_Chaser controller = SF2NPC_Chaser(i); - ChaserBossProfile chaserData = controller.GetProfileDataEx(); + ChaserBossProfile chaserData = controller.GetProfileData(); ProfileObject attacks = chaserData.GetSection("attacks"); if (attacks == null || attacks.Size == 0) { @@ -1321,7 +1321,7 @@ static bool DisplayBossAttackListAdminMenu(int client) return false; } - ChaserBossProfile data = g_SelectedBoss[client].GetProfileDataEx(); + ChaserBossProfile data = g_SelectedBoss[client].GetProfileData(); ProfileObject attacks = data.GetSection("attacks"); Menu menuHandle = new Menu(AdminMenu_BossAttackList); for (int i = 0; i < attacks.Size; i++) diff --git a/addons/sourcemod/scripting/sf2/client.sp b/addons/sourcemod/scripting/sf2/client.sp index c5df27d4..a222b4eb 100644 --- a/addons/sourcemod/scripting/sf2/client.sp +++ b/addons/sourcemod/scripting/sf2/client.sp @@ -9,6 +9,8 @@ #define SF2_OVERLAY_DEFAULT "overlays/slender/newcamerahud_3" #define SF2_OVERLAY_DEFAULT_NO_FILMGRAIN "overlays/slender/nofilmgrain" +static int g_ClientModifiedMaxHealth[MAXTF2PLAYERS]; + //Client Special Round Timer static Handle g_ClientSpecialRoundTimer[MAXTF2PLAYERS]; @@ -41,11 +43,332 @@ int g_ClientFrame[MAXTF2PLAYERS]; #include "client/new_music.sp" #include "client/proxy.sp" +void SetupClients() +{ + g_OnPlayerPutInServerPFwd.AddFunction(null, OnPutInServer); + g_OnPlayerSpawnPFwd.AddFunction(null, OnPlayerSpawn); +} + void Client_SetupAPI() { Sprint_SetupAPI(); } +static void OnPutInServer(SF2_BasePlayer client) +{ + SDKHook(client.index, SDKHook_OnTakeDamage, OnTakeDamage); + SDKHook(client.index, SDKHook_OnTakeDamageAlivePost, OnTakeDamageAlivePost); +} + +static void OnPlayerSpawn(SF2_BasePlayer client) +{ + CreateTimer(0.1, Timer_CheckHealth, client.UserID, TIMER_FLAG_NO_MAPCHANGE); +} + +static Action OnTakeDamage(int victim, int &attacker, int &inflictor, float &damage, int &damagetype, int &weapon, float damageForce[3], float damagePosition[3], int damagecustom) +{ + SF2_BasePlayer victimPlayer = SF2_BasePlayer(victim); + if (!g_Enabled) + { + if (NPCGetFromEntIndex(attacker) != -1 && GetEntProp(attacker, Prop_Data, "m_iTeamNum") == victimPlayer.Team) + { + damage = 0.0; + return Plugin_Changed; + } + return Plugin_Continue; + } + + Action action = Plugin_Continue; + + float damage2 = damage; + Call_StartForward(g_OnClientTakeDamageFwd); + Call_PushCell(victimPlayer.index); + Call_PushCellRef(attacker); + Call_PushCellRef(inflictor); + Call_PushFloatRef(damage2); + Call_Finish(action); + + if (action == Plugin_Changed) + { + damage = damage2; + return Plugin_Changed; + } + + Call_StartForward(g_OnPlayerTakeDamagePFwd); + Call_PushCell(victimPlayer); + Call_PushCellRef(attacker); + Call_PushCellRef(inflictor); + Call_PushFloatRef(damage2); + Call_PushCellRef(damagetype); + Call_PushCell(damagecustom); + Call_Finish(action); + + if (action == Plugin_Changed) + { + damage = damage2; + return Plugin_Changed; + } + + TFClassType class = victimPlayer.Class; + + if (IsClientInKart(victimPlayer.index) && (attacker == -1 || inflictor == -1)) + { + damage = 0.0; + return Plugin_Changed; + } + + char inflictorClass[32]; + if (inflictor >= 0) + { + GetEdictClassname(inflictor, inflictorClass, sizeof(inflictorClass)); + } + + if (IsValidClient(attacker) && victimPlayer.IsValid && g_PlayerProxy[attacker] && victimPlayer.Team == TFTeam_Red && victimPlayer.InCondition(TFCond_Gas)) + { + victimPlayer.Ignite(true); + victimPlayer.ChangeCondition(TFCond_Gas, true); + } + + if (victimPlayer.InCondition(TFCond_Gas) && SF2_ChaserEntity(attacker).IsValid()) + { + victimPlayer.Ignite(true); + victimPlayer.ChangeCondition(TFCond_Gas, true); + } + + if (IsValidClient(attacker) && victimPlayer.IsValid && (victimPlayer.IsInPvP || victimPlayer.IsInPvE) && victimPlayer.Team == TFTeam_Red && GetClientTeam(attacker) == TFTeam_Red && victim != attacker) + { + damage = 0.0; + return Plugin_Changed; + } + + if (IsValidClient(attacker) && victimPlayer.IsValid && victimPlayer.Team == TFTeam_Red && GetClientTeam(attacker) == TFTeam_Red && (victimPlayer.IsTrapped || victimPlayer.IsLatched)) + { + if (!g_PlayerEliminated[attacker] && !victimPlayer.IsEliminated && (damagetype & 0x80) != 0) + { + victimPlayer.IsTrapped = false; + if (victimPlayer.IsLatched) + { + victimPlayer.ChangeCondition(TFCond_Dazed, true); + for (int i = 0; i < MAX_BOSSES; i++) + { + SF2NPC_BaseNPC npc = SF2NPC_BaseNPC(i); + if (!npc.IsValid()) + { + continue; + } + + if (victimPlayer.Latcher != npc.Index) + { + continue; + } + + SF2_ChaserEntity chaser = SF2_ChaserEntity(npc.EntIndex); + if (!chaser.IsValid()) + { + continue; + } + + chaser.MyNextBotPointer().GetIntentionInterface().OnCommandString("break tongue"); + } + } + victimPlayer.IsLatched = false; + victimPlayer.LatchCount = 0; + TF2_AddCondition(attacker, TFCond_SpeedBuffAlly, 4.0); + TF2_AddCondition(victim, TFCond_SpeedBuffAlly, 4.0); + } + } + + if (IsValidClient(attacker) && !g_PlayerEliminated[attacker] && !DidClientEscape(attacker) && class == TFClass_Soldier && !(GetEntityFlags(attacker) & FL_ONGROUND)) + { + int weaponEnt = GetPlayerWeaponSlot(attacker, TFWeaponSlot_Melee); + if (IsValidEntity(weaponEnt)) + { + int itemDefInt = GetEntProp(weaponEnt, Prop_Send, "m_iItemDefinitionIndex"); + float zVelocity[3]; + GetEntPropVector(attacker, Prop_Data, "m_vecVelocity", zVelocity); + if (itemDefInt == 416 && zVelocity[2] < 0.0 && weaponEnt == GetEntPropEnt(attacker, Prop_Send, "m_hActiveWeapon")) // A soldier has the market gardener and is currently falling down, like Minecraft with it's critical hits. + { + damagetype |= DMG_ACID; + } + } + } + + if (!SF2_ChaserEntity(inflictor).IsValid() && !SF2_StatueEntity(inflictor).IsValid() && !IsValidClient(inflictor)) + { + int npcIndex = NPCGetFromEntIndex(GetEntPropEnt(inflictor, Prop_Send, "m_hOwnerEntity")); + if (npcIndex != -1) + { + bool attackEliminated = (NPCGetFlags(npcIndex) & SFF_ATTACKWAITERS) != 0; + if (!attackEliminated && (GetClientTeam(victim) == TFTeam_Blue) && IsValidClient(victim) ) + { + damage = 0.0; + return Plugin_Changed; + } + } + } + + bool canDamage = false; + if (attacker != victim && IsValidClient(attacker)) + { + if (IsClientInPvP(victim) && IsClientInPvP(attacker)) + { + canDamage = true; + } + if (IsClientLeavingPvP(victim) && !IsClientInPvP(attacker)) + { + canDamage = true; + } + if (!IsRoundEnding()) + { + if (canDamage) + { + if (attacker == inflictor) + { + if (IsValidEdict(weapon)) + { + char weaponClass[64]; + GetEdictClassname(weapon, weaponClass, sizeof(weaponClass)); + + // Backstab check! + if ((strcmp(weaponClass, "tf_weapon_knife") == 0 || (TF2_GetPlayerClass(attacker) == TFClass_Spy && strcmp(weaponClass, "saxxy") == 0)) && + (damagecustom != TF_CUSTOM_TAUNT_FENCING)) + { + float myPos[3], hisPos[3], myDirection[3]; + GetClientAbsOrigin(victim, myPos); + GetClientAbsOrigin(attacker, hisPos); + GetClientEyeAngles(victim, myDirection); + GetAngleVectors(myDirection, myDirection, NULL_VECTOR, NULL_VECTOR); + NormalizeVector(myDirection, myDirection); + ScaleVector(myDirection, 32.0); + AddVectors(myDirection, myPos, myDirection); + + float p[3], s[3]; + MakeVectorFromPoints(myPos, hisPos, p); + MakeVectorFromPoints(myPos, myDirection, s); + if (GetVectorDotProduct(p, s) <= 0.0)//We can backstab him m8 + { + if (GetClientTeam(victim) == GetClientTeam(attacker) && class == TFClass_Sniper) + { + //look if the player has a razorback + int wearableEnt = INVALID_ENT_REFERENCE; + while ((wearableEnt = FindEntityByClassname(wearableEnt, "tf_wearable")) != -1) + { + if (GetEntPropEnt(wearableEnt, Prop_Send, "m_hOwnerEntity") == victim && GetEntProp(wearableEnt, Prop_Send, "m_iItemDefinitionIndex") == 57) + { + RemoveEntity(wearableEnt); + damage = 0.0; + EmitSoundToClient(victim, "player/spy_shield_break.wav", _, _, SNDLEVEL_TRAFFIC, SND_NOFLAGS, 0.7, 100); + EmitSoundToClient(attacker, "player/spy_shield_break.wav", _, _, SNDLEVEL_TRAFFIC, SND_NOFLAGS, 0.7, 100); + + SetEntPropFloat(weapon, Prop_Send, "m_flNextPrimaryAttack", GetGameTime() + 2.0); + SetEntPropFloat(attacker, Prop_Send, "m_flNextAttack", GetGameTime() + 2.0); + SetEntPropFloat(attacker, Prop_Send, "m_flStealthNextChangeTime", GetGameTime() + 2.0); + int vm = GetEntPropEnt(attacker, Prop_Send, "m_hViewModel"); + if (vm > MaxClients) + { + int meleeIndex = GetEntProp(weapon, Prop_Send, "m_iItemDefinitionIndex"); + int anim = 41; + switch (meleeIndex) + { + case 4, 194, 225, 356, 461, 574, 649, 665, 794, 803, 883, 892, 901, 910, 959, 968: + { + anim = 15; + } + case 638: + { + anim = 31; + } + } + SetEntProp(vm, Prop_Send, "m_nSequence", anim); + } + return Plugin_Changed; + } + } + } + if (damagecustom == TF_CUSTOM_BACKSTAB) // Modify backstab damage. + { + damage = 120.0; + if (damagetype & DMG_ACID) + { + damage = 120.0; + } + } + + if (g_WeaponCriticalsConVar != null && g_WeaponCriticalsConVar.BoolValue) + { + damagetype |= DMG_ACID; + } + + if (!IsClientCritUbercharged(victim)) + { + if (GetClientTeam(victim) == GetClientTeam(attacker)) + { + int pistol = GetPlayerWeaponSlot(attacker, TFWeaponSlot_Primary); + if (pistol > MaxClients && GetEntProp(pistol, Prop_Send, "m_iItemDefinitionIndex") == 525) //Give one crit fort the backstab + { + int crits = GetEntProp(attacker, Prop_Send, "m_iRevengeCrits"); + crits++; + SetEntProp(attacker, Prop_Send, "m_iRevengeCrits", crits); + } + } + if (GetEntProp(victim, Prop_Send, "m_iHealth") <= 120) + { + g_PlayerBackStabbed[victim] = true; + } + else + { + g_PlayerBackStabbed[victim] = false; + } + } + return Plugin_Changed; + } + } + } + } + } + else + { + damage = 0.0; + return Plugin_Changed; + } + } + else + { + if (g_PlayerEliminated[attacker] == g_PlayerEliminated[victim]) + { + damage = 0.0; + return Plugin_Changed; + } + } + } + + return Plugin_Continue; +} + +static void OnTakeDamageAlivePost(int victim, int attacker, int inflictor, float damage, int damageType, int weaponEntIndex, const float vecDamageForce[3], const float vecDamagePosition[3]) +{ + Call_StartForward(g_OnPlayerTakeDamagePostPFwd); + Call_PushCell(SF2_BasePlayer(victim)); + Call_PushCell(attacker); + Call_PushCell(inflictor); + Call_PushFloat(damage); + Call_PushCell(damageType); + Call_Finish(); +} + +static Action Timer_CheckHealth(Handle timer, any id) +{ + int client = GetClientOfUserId(id); + if (!IsValidClient(client)) + { + return Plugin_Stop; + } + + g_ClientModifiedMaxHealth[client] = SF2_BasePlayer(client).Health; + + return Plugin_Stop; +} + // ========================================================== // GENERAL CLIENT HOOK FUNCTIONS // ========================================================== @@ -103,8 +426,18 @@ void ClientSetScareBoostEndTime(int client, float time) g_PlayerScareBoostEndTime[client] = time; } +int ClientGetModifiedMaxHealth(int client) +{ + return g_ClientModifiedMaxHealth[client]; +} + Action Hook_HealthKitOnTouch(int healthKit, int client) { + if (!g_Enabled) + { + return Plugin_Continue; + } + if (IsValidClient(client)) { if (IsClientInPvE(client) || IsClientInPvP(client)) diff --git a/addons/sourcemod/scripting/sf2/client/blink.sp b/addons/sourcemod/scripting/sf2/client/blink.sp index 6b8edb3f..5c421845 100644 --- a/addons/sourcemod/scripting/sf2/client/blink.sp +++ b/addons/sourcemod/scripting/sf2/client/blink.sp @@ -264,7 +264,7 @@ static float ClientGetBlinkRate(int client) continue; } - BaseBossProfile profileData = SF2NPC_BaseNPC(i).GetProfileDataEx(); + BaseBossProfile profileData = SF2NPC_BaseNPC(i).GetProfileData(); if (g_PlayerSeesSlender[client][i]) { diff --git a/addons/sourcemod/scripting/sf2/client/deathcam.sp b/addons/sourcemod/scripting/sf2/client/deathcam.sp index f6da55ea..c48ea08a 100644 --- a/addons/sourcemod/scripting/sf2/client/deathcam.sp +++ b/addons/sourcemod/scripting/sf2/client/deathcam.sp @@ -672,7 +672,7 @@ static void StopDeathCam(int client) SF2NPC_BaseNPC deathCamBoss = SF2NPC_BaseNPC(NPCGetFromUniqueID(g_PlayerDeathCamBoss[client])); if (deathCamBoss != SF2_INVALID_NPC) { - BossProfilePublicDeathCamData publicDeathCamData = deathCamBoss.GetProfileDataEx().GetDeathCamData().PublicDeathCam; + BossProfilePublicDeathCamData publicDeathCamData = deathCamBoss.GetProfileData().GetDeathCamData().PublicDeathCam; if ((deathCamBoss.Flags & SFF_FAKE) == 0) { if (deathCamBoss.HasAttribute(SF2Attribute_IgnitePlayerOnDeath)) @@ -758,7 +758,7 @@ static void Hook_DeathCamThink(int client) if (Npc.IsValid()) { g_PlayerDeathCamShowOverlay[player.index] = true; - BaseBossProfile data = Npc.GetProfileDataEx(); + BaseBossProfile data = Npc.GetProfileData(); data.GetOverlayDeathCamSounds().EmitSound(true, player.index, SOUND_FROM_PLAYER); duration = data.GetDeathCamData().Duration; } diff --git a/addons/sourcemod/scripting/sf2/client/ghostmode.sp b/addons/sourcemod/scripting/sf2/client/ghostmode.sp index c3ef87f5..a3d523b6 100644 --- a/addons/sourcemod/scripting/sf2/client/ghostmode.sp +++ b/addons/sourcemod/scripting/sf2/client/ghostmode.sp @@ -353,7 +353,7 @@ void ClientGhostModeNextTarget(int client, bool ignoreSetting = false) continue; } - if (SF2NPC_BaseNPC(bossIndex).GetProfileDataEx().IsPvEBoss) + if (SF2NPC_BaseNPC(bossIndex).GetProfileData().IsPvEBoss) { continue; } diff --git a/addons/sourcemod/scripting/sf2/client/music.sp b/addons/sourcemod/scripting/sf2/client/music.sp index c2b9973d..638eee37 100644 --- a/addons/sourcemod/scripting/sf2/client/music.sp +++ b/addons/sourcemod/scripting/sf2/client/music.sp @@ -237,7 +237,7 @@ void ClientUpdateMusicSystem(int client, bool initialize = false) continue; } - BaseBossProfile data = SF2NPC_BaseNPC(i).GetProfileDataEx(); + BaseBossProfile data = SF2NPC_BaseNPC(i).GetProfileData(); if (data.IsPvEBoss) { continue; @@ -259,7 +259,7 @@ void ClientUpdateMusicSystem(int client, bool initialize = false) } ProfileSound soundInfo; - ChaserBossProfile chaserData = SF2NPC_Chaser(i).GetProfileDataEx(); + ChaserBossProfile chaserData = SF2NPC_Chaser(i).GetProfileData(); GetClientAbsOrigin(client, buffer); chaser.GetAbsOrigin(buffer3); float pos[3]; @@ -740,13 +740,13 @@ void ClientAlertMusicReset(int client) { continue; } - BaseBossProfile data = SF2NPC_BaseNPC(i).GetProfileDataEx(); + BaseBossProfile data = SF2NPC_BaseNPC(i).GetProfileData(); if (data.Type != -1 && data.Type == SF2BossType_Chaser) { if (IsValidClient(client)) { - SF2NPC_Chaser(i).GetProfileDataEx().GetAlertMusics().StopAllSounds(1, client); + SF2NPC_Chaser(i).GetProfileData().GetAlertMusics().StopAllSounds(1, client); } } } @@ -771,7 +771,7 @@ void ClientAlertMusicStart(int client,int bossIndex) NPCGetProfile(bossIndex, profile, sizeof(profile)); char buffer[PLATFORM_MAX_PATH]; - ProfileSound soundInfo = SF2NPC_Chaser(bossIndex).GetProfileDataEx().GetAlertMusics(); + ProfileSound soundInfo = SF2NPC_Chaser(bossIndex).GetProfileData().GetAlertMusics(); if (soundInfo.Paths != null && soundInfo.Paths.Length > 0) { soundInfo.Paths.GetString(GetRandomInt(0, soundInfo.Paths.Length - 1), buffer, sizeof(buffer)); @@ -842,13 +842,13 @@ void ClientIdleMusicReset(int client) { continue; } - BaseBossProfile data = SF2NPC_BaseNPC(i).GetProfileDataEx(); + BaseBossProfile data = SF2NPC_BaseNPC(i).GetProfileData(); if (data.Type != -1 && data.Type == SF2BossType_Chaser) { if (IsValidClient(client)) { - SF2NPC_Chaser(i).GetProfileDataEx().GetIdleMusics().StopAllSounds(1, client); + SF2NPC_Chaser(i).GetProfileData().GetIdleMusics().StopAllSounds(1, client); } } } @@ -873,7 +873,7 @@ void ClientIdleMusicStart(int client,int bossIndex) NPCGetProfile(bossIndex, profile, sizeof(profile)); char buffer[PLATFORM_MAX_PATH]; - ProfileSound soundInfo = SF2NPC_Chaser(bossIndex).GetProfileDataEx().GetIdleMusics(); + ProfileSound soundInfo = SF2NPC_Chaser(bossIndex).GetProfileData().GetIdleMusics(); if (soundInfo.Paths != null && soundInfo.Paths.Length > 0) { soundInfo.Paths.GetString(GetRandomInt(0, soundInfo.Paths.Length - 1), buffer, sizeof(buffer)); @@ -944,13 +944,13 @@ void ClientChaseMusicReset(int client) { continue; } - BaseBossProfile data = SF2NPC_BaseNPC(i).GetProfileDataEx(); + BaseBossProfile data = SF2NPC_BaseNPC(i).GetProfileData(); if (data.Type != -1 && data.Type == SF2BossType_Chaser) { if (IsValidClient(client)) { - SF2NPC_Chaser(i).GetProfileDataEx().GetChaseMusics().StopAllSounds(1, client); + SF2NPC_Chaser(i).GetProfileData().GetChaseMusics().StopAllSounds(1, client); } } } @@ -975,7 +975,7 @@ void ClientMusicChaseStart(int client,int bossIndex) NPCGetProfile(bossIndex, profile, sizeof(profile)); char buffer[PLATFORM_MAX_PATH]; - ProfileSound soundInfo = SF2NPC_Chaser(bossIndex).GetProfileDataEx().GetChaseMusics(); + ProfileSound soundInfo = SF2NPC_Chaser(bossIndex).GetProfileData().GetChaseMusics(); if (soundInfo.Paths != null && soundInfo.Paths.Length > 0) { soundInfo.Paths.GetString(GetRandomInt(0, soundInfo.Paths.Length - 1), buffer, sizeof(buffer)); @@ -1047,13 +1047,13 @@ void ClientChaseMusicSeeReset(int client) { continue; } - BaseBossProfile data = SF2NPC_BaseNPC(i).GetProfileDataEx(); + BaseBossProfile data = SF2NPC_BaseNPC(i).GetProfileData(); if (data.Type != -1 && data.Type == SF2BossType_Chaser) { if (IsValidClient(client)) { - SF2NPC_Chaser(i).GetProfileDataEx().GetVisibleChaseMusics().StopAllSounds(1, client); + SF2NPC_Chaser(i).GetProfileData().GetVisibleChaseMusics().StopAllSounds(1, client); } } } @@ -1078,7 +1078,7 @@ void ClientMusicChaseSeeStart(int client, int bossIndex) NPCGetProfile(bossIndex, profile, sizeof(profile)); char buffer[PLATFORM_MAX_PATH]; - ProfileSound soundInfo = SF2NPC_Chaser(bossIndex).GetProfileDataEx().GetVisibleChaseMusics(); + ProfileSound soundInfo = SF2NPC_Chaser(bossIndex).GetProfileData().GetVisibleChaseMusics(); if (soundInfo.Paths != null && soundInfo.Paths.Length > 0) { soundInfo.Paths.GetString(GetRandomInt(0, soundInfo.Paths.Length - 1), buffer, sizeof(buffer)); @@ -1223,7 +1223,7 @@ Action Timer_PlayerFadeInAlertMusic(Handle timer, any userid) return Plugin_Stop; } - ChaserBossProfile data = SF2NPC_Chaser(bossIndex).GetProfileDataEx(); + ChaserBossProfile data = SF2NPC_Chaser(bossIndex).GetProfileData(); if (data == null) { StopSound(client, MUSIC_CHAN, g_PlayerAlertMusicString[client][bossIndex]); @@ -1283,7 +1283,7 @@ Action Timer_PlayerFadeOutAlertMusic(Handle timer, any userid) return Plugin_Stop; } - ChaserBossProfile data = SF2NPC_Chaser(bossIndex).GetProfileDataEx(); + ChaserBossProfile data = SF2NPC_Chaser(bossIndex).GetProfileData(); if (data == null) { StopSound(client, MUSIC_CHAN, g_PlayerAlertMusicString[client][bossIndex]); @@ -1348,7 +1348,7 @@ Action Timer_PlayerFadeInIdleMusic(Handle timer, any userid) return Plugin_Stop; } - ChaserBossProfile data = SF2NPC_Chaser(bossIndex).GetProfileDataEx(); + ChaserBossProfile data = SF2NPC_Chaser(bossIndex).GetProfileData(); if (data == null) { StopSound(client, MUSIC_CHAN, g_PlayerIdleMusicString[client][bossIndex]); @@ -1408,7 +1408,7 @@ Action Timer_PlayerFadeOutIdleMusic(Handle timer, any userid) return Plugin_Stop; } - ChaserBossProfile data = SF2NPC_Chaser(bossIndex).GetProfileDataEx(); + ChaserBossProfile data = SF2NPC_Chaser(bossIndex).GetProfileData(); if (data == null) { StopSound(client, MUSIC_CHAN, g_PlayerIdleMusicString[client][bossIndex]); @@ -1473,7 +1473,7 @@ Action Timer_PlayerFadeInChaseMusic(Handle timer, any userid) return Plugin_Stop; } - ChaserBossProfile data = SF2NPC_Chaser(bossIndex).GetProfileDataEx(); + ChaserBossProfile data = SF2NPC_Chaser(bossIndex).GetProfileData(); if (data == null) { StopSound(client, MUSIC_CHAN, g_PlayerChaseMusicString[client][bossIndex]); @@ -1533,7 +1533,7 @@ Action Timer_PlayerFadeInChaseMusicSee(Handle timer, any userid) return Plugin_Stop; } - ChaserBossProfile data = SF2NPC_Chaser(bossIndex).GetProfileDataEx(); + ChaserBossProfile data = SF2NPC_Chaser(bossIndex).GetProfileData(); if (data == null) { StopSound(client, MUSIC_CHAN, g_PlayerChaseMusicSeeString[client][bossIndex]); @@ -1593,7 +1593,7 @@ Action Timer_PlayerFadeOutChaseMusic(Handle timer, any userid) return Plugin_Stop; } - ChaserBossProfile data = SF2NPC_Chaser(bossIndex).GetProfileDataEx(); + ChaserBossProfile data = SF2NPC_Chaser(bossIndex).GetProfileData(); if (data == null) { StopSound(client, MUSIC_CHAN, g_PlayerChaseMusicString[client][bossIndex]); @@ -1658,7 +1658,7 @@ Action Timer_PlayerFadeOutChaseMusicSee(Handle timer, any userid) return Plugin_Stop; } - ChaserBossProfile data = SF2NPC_Chaser(bossIndex).GetProfileDataEx(); + ChaserBossProfile data = SF2NPC_Chaser(bossIndex).GetProfileData(); if (data == null) { StopSound(client, MUSIC_CHAN, g_PlayerChaseMusicSeeString[client][bossIndex]); diff --git a/addons/sourcemod/scripting/sf2/client/new_music.sp b/addons/sourcemod/scripting/sf2/client/new_music.sp index 1bc7e0a9..3e03bdb9 100644 --- a/addons/sourcemod/scripting/sf2/client/new_music.sp +++ b/addons/sourcemod/scripting/sf2/client/new_music.sp @@ -463,7 +463,7 @@ static void OnBossAdded(SF2NPC_BaseNPC npc) return; } - if (npc.GetProfileDataEx().IsPvEBoss) + if (npc.GetProfileData().IsPvEBoss) { return; } @@ -494,7 +494,7 @@ static void OnBossRemoved(SF2NPC_BaseNPC npc) return; } - if (npc.GetProfileDataEx().IsPvEBoss) + if (npc.GetProfileData().IsPvEBoss) { return; } @@ -532,7 +532,7 @@ static void OnDifficultyChange(int oldDifficulty, int newDifficulty) continue; } - if (npc.GetProfileDataEx().IsPvEBoss) + if (npc.GetProfileData().IsPvEBoss) { continue; } @@ -1152,7 +1152,7 @@ static void MusicThink() continue; } - BaseBossProfile data = SF2NPC_BaseNPC(i).GetProfileDataEx(); + BaseBossProfile data = SF2NPC_BaseNPC(i).GetProfileData(); if (data.IsPvEBoss) { continue; @@ -1268,7 +1268,7 @@ static void MusicThink() continue; } - BaseBossProfile data = SF2NPC_BaseNPC(i).GetProfileDataEx(); + BaseBossProfile data = SF2NPC_BaseNPC(i).GetProfileData(); if (data.IsPvEBoss) { continue; @@ -1401,7 +1401,7 @@ static void GetBossMusicTrack(SF2NPC_BaseNPC controller, return; } - BaseBossProfile data = controller.GetProfileDataEx(); + BaseBossProfile data = controller.GetProfileData(); if (data.IsPvEBoss) { return; diff --git a/addons/sourcemod/scripting/sf2/client/proxy.sp b/addons/sourcemod/scripting/sf2/client/proxy.sp index 50c4850d..4cd9a30b 100644 --- a/addons/sourcemod/scripting/sf2/client/proxy.sp +++ b/addons/sourcemod/scripting/sf2/client/proxy.sp @@ -711,7 +711,7 @@ static Action OnPlayerTakeDamage(SF2_BasePlayer client, int &attacker, int &infl SF2NPC_BaseNPC master = SF2NPC_BaseNPC(attackerPlayer.ProxyMaster); if (master.IsValid()) { - proxyData = master.GetProfileDataEx().GetProxies(); + proxyData = master.GetProfileData().GetProxies(); classData = proxyData.GetClassData(attackerPlayer.Class); int difficulty = master.Difficulty; @@ -768,7 +768,7 @@ static Action OnPlayerTakeDamage(SF2_BasePlayer client, int &attacker, int &infl SF2NPC_BaseNPC master = SF2NPC_BaseNPC(client.ProxyMaster); if (master.IsValid()) { - proxyData = master.GetProfileDataEx().GetProxies(); + proxyData = master.GetProfileData().GetProxies(); classData = proxyData.GetClassData(client.Class); int difficulty = master.Difficulty; @@ -841,7 +841,7 @@ static void ProxyThink(int client) int difficulty = controller.Difficulty; TFClassType class = player.Class; - BossProfileProxyData proxyData = controller.GetProfileDataEx().GetProxies(); + BossProfileProxyData proxyData = controller.GetProfileData().GetProxies(); BossProfileProxyClass classData = proxyData.GetClassData(class); float speed = classData.GetRunSpeed(difficulty); @@ -1249,7 +1249,7 @@ static TFClassType SelectProxyClass(SF2_BasePlayer client) SF2NPC_BaseNPC controller = SF2NPC_BaseNPC(client.ProxyMaster); int difficulty = controller.Difficulty; - BossProfileProxyData proxyData = controller.GetProfileDataEx().GetProxies(); + BossProfileProxyData proxyData = controller.GetProfileData().GetProxies(); ArrayList allowed = new ArrayList(); int classCount[10] = { 0, ... }; @@ -1480,7 +1480,7 @@ static Action Timer_GiveWeaponAll(Handle timer, any userid) if (g_PlayerProxy[client] && bossIndex != -1) { - BossProfileProxyData proxyData = SF2NPC_BaseNPC(bossIndex).GetProfileDataEx().GetProxies(); + BossProfileProxyData proxyData = SF2NPC_BaseNPC(bossIndex).GetProfileData().GetProxies(); if (!proxyData.CustomWeapons) { return Plugin_Stop; diff --git a/addons/sourcemod/scripting/sf2/client/sprint.sp b/addons/sourcemod/scripting/sf2/client/sprint.sp index 6da53013..498de4e6 100644 --- a/addons/sourcemod/scripting/sf2/client/sprint.sp +++ b/addons/sourcemod/scripting/sf2/client/sprint.sp @@ -524,7 +524,7 @@ static void Hook_SpeedThink(int client) continue; } - if (SF2NPC_BaseNPC(i).GetProfileDataEx().Type == SF2BossType_Chaser) + if (SF2NPC_BaseNPC(i).GetProfileData().Type == SF2BossType_Chaser) { SF2_ChaserEntity chaser = SF2_ChaserEntity(ent); bossTarget = chaser.Target; @@ -570,7 +570,7 @@ static void Hook_SpeedThink(int client) continue; } - if (SF2NPC_BaseNPC(i).GetProfileDataEx().Type == SF2BossType_Chaser) + if (SF2NPC_BaseNPC(i).GetProfileData().Type == SF2BossType_Chaser) { if (state == STATE_ALERT) { diff --git a/addons/sourcemod/scripting/sf2/client/think.sp b/addons/sourcemod/scripting/sf2/client/think.sp index 694fb7da..ba2db019 100644 --- a/addons/sourcemod/scripting/sf2/client/think.sp +++ b/addons/sourcemod/scripting/sf2/client/think.sp @@ -107,299 +107,6 @@ void Hook_ClientPreThink(int client) ClientProcessVisibility(player.index); } -Action Hook_ClientOnTakeDamage(int victim, int &attacker, int &inflictor, float &damage, int &damagetype, int &weapon, float damageForce[3], float damagePosition[3], int damagecustom) -{ - SF2_BasePlayer victimPlayer = SF2_BasePlayer(victim); - if (!g_Enabled) - { - if (NPCGetFromEntIndex(attacker) != -1 && GetEntProp(attacker, Prop_Data, "m_iTeamNum") == victimPlayer.Team) - { - damage = 0.0; - return Plugin_Changed; - } - return Plugin_Continue; - } - - Action action = Plugin_Continue; - - float damage2 = damage; - Call_StartForward(g_OnClientTakeDamageFwd); - Call_PushCell(victimPlayer.index); - Call_PushCellRef(attacker); - Call_PushCellRef(inflictor); - Call_PushFloatRef(damage2); - Call_Finish(action); - - if (action == Plugin_Changed) - { - damage = damage2; - return Plugin_Changed; - } - - Call_StartForward(g_OnPlayerTakeDamagePFwd); - Call_PushCell(victimPlayer); - Call_PushCellRef(attacker); - Call_PushCellRef(inflictor); - Call_PushFloatRef(damage2); - Call_PushCellRef(damagetype); - Call_PushCell(damagecustom); - Call_Finish(action); - - if (action == Plugin_Changed) - { - damage = damage2; - return Plugin_Changed; - } - - TFClassType class = victimPlayer.Class; - - if (IsRoundInWarmup() && IsValidClient(attacker)) - { - float modelScale = GetEntPropFloat(attacker, Prop_Send, "m_flModelScale"); - float headScale = GetEntPropFloat(attacker, Prop_Send, "m_flHeadScale"); - float torsoScale = GetEntPropFloat(attacker, Prop_Send, "m_flTorsoScale"); - float handScale = GetEntPropFloat(attacker, Prop_Send, "m_flHandScale"); - if (modelScale < 1.0 || modelScale > 1.0 || headScale < 1.0 || headScale > 1.0 || torsoScale < 1.0 || torsoScale > 1.0 || handScale < 1.0 || handScale > 1.0) - { - damage = 0.0; //So how does it feel? - return Plugin_Changed; - } - } - - if (IsClientInKart(victimPlayer.index) && (attacker == -1 || inflictor == -1)) - { - damage = 0.0; - return Plugin_Changed; - } - - char inflictorClass[32]; - if (inflictor >= 0) - { - GetEdictClassname(inflictor, inflictorClass, sizeof(inflictorClass)); - } - - if (IsValidClient(attacker) && victimPlayer.IsValid && g_PlayerProxy[attacker] && victimPlayer.Team == TFTeam_Red && victimPlayer.InCondition(TFCond_Gas)) - { - victimPlayer.Ignite(true); - victimPlayer.ChangeCondition(TFCond_Gas, true); - } - - if (victimPlayer.InCondition(TFCond_Gas) && SF2_ChaserEntity(attacker).IsValid()) - { - victimPlayer.Ignite(true); - victimPlayer.ChangeCondition(TFCond_Gas, true); - } - - if (IsValidClient(attacker) && victimPlayer.IsValid && (victimPlayer.IsInPvP || victimPlayer.IsInPvE) && victimPlayer.Team == TFTeam_Red && GetClientTeam(attacker) == TFTeam_Red && victim != attacker) - { - damage = 0.0; - return Plugin_Changed; - } - - if (IsValidClient(attacker) && victimPlayer.IsValid && victimPlayer.Team == TFTeam_Red && GetClientTeam(attacker) == TFTeam_Red && (victimPlayer.IsTrapped || victimPlayer.IsLatched)) - { - if (!g_PlayerEliminated[attacker] && !victimPlayer.IsEliminated && (damagetype & 0x80) != 0) - { - victimPlayer.IsTrapped = false; - if (victimPlayer.IsLatched) - { - victimPlayer.ChangeCondition(TFCond_Dazed, true); - for (int i = 0; i < MAX_BOSSES; i++) - { - SF2NPC_BaseNPC npc = SF2NPC_BaseNPC(i); - if (!npc.IsValid()) - { - continue; - } - - if (victimPlayer.Latcher != npc.Index) - { - continue; - } - - SF2_ChaserEntity chaser = SF2_ChaserEntity(npc.EntIndex); - if (!chaser.IsValid()) - { - continue; - } - - chaser.MyNextBotPointer().GetIntentionInterface().OnCommandString("break tongue"); - } - } - victimPlayer.IsLatched = false; - victimPlayer.LatchCount = 0; - TF2_AddCondition(attacker, TFCond_SpeedBuffAlly, 4.0); - TF2_AddCondition(victim, TFCond_SpeedBuffAlly, 4.0); - } - } - - if (IsValidClient(attacker) && !g_PlayerEliminated[attacker] && !DidClientEscape(attacker) && class == TFClass_Soldier && !(GetEntityFlags(attacker) & FL_ONGROUND)) - { - int weaponEnt = GetPlayerWeaponSlot(attacker, TFWeaponSlot_Melee); - if (IsValidEntity(weaponEnt)) - { - int itemDefInt = GetEntProp(weaponEnt, Prop_Send, "m_iItemDefinitionIndex"); - float zVelocity[3]; - GetEntPropVector(attacker, Prop_Data, "m_vecVelocity", zVelocity); - if (itemDefInt == 416 && zVelocity[2] < 0.0 && weaponEnt == GetEntPropEnt(attacker, Prop_Send, "m_hActiveWeapon")) // A soldier has the market gardener and is currently falling down, like Minecraft with it's critical hits. - { - damagetype |= DMG_ACID; - } - } - } - - if (!SF2_ChaserEntity(inflictor).IsValid() && !SF2_StatueEntity(inflictor).IsValid() && !IsValidClient(inflictor)) - { - int npcIndex = NPCGetFromEntIndex(GetEntPropEnt(inflictor, Prop_Send, "m_hOwnerEntity")); - if (npcIndex != -1) - { - bool attackEliminated = (NPCGetFlags(npcIndex) & SFF_ATTACKWAITERS) != 0; - if (!attackEliminated && (GetClientTeam(victim) == TFTeam_Blue) && IsValidClient(victim) ) - { - damage = 0.0; - return Plugin_Changed; - } - } - } - - bool canDamage = false; - if (attacker != victim && IsValidClient(attacker)) - { - if (IsClientInPvP(victim) && IsClientInPvP(attacker)) - { - canDamage = true; - } - if (IsClientLeavingPvP(victim) && !IsClientInPvP(attacker)) - { - canDamage = true; - } - if (!IsRoundEnding()) - { - if (canDamage) - { - if (attacker == inflictor) - { - if (IsValidEdict(weapon)) - { - char weaponClass[64]; - GetEdictClassname(weapon, weaponClass, sizeof(weaponClass)); - - // Backstab check! - if ((strcmp(weaponClass, "tf_weapon_knife") == 0 || (TF2_GetPlayerClass(attacker) == TFClass_Spy && strcmp(weaponClass, "saxxy") == 0)) && - (damagecustom != TF_CUSTOM_TAUNT_FENCING)) - { - float myPos[3], hisPos[3], myDirection[3]; - GetClientAbsOrigin(victim, myPos); - GetClientAbsOrigin(attacker, hisPos); - GetClientEyeAngles(victim, myDirection); - GetAngleVectors(myDirection, myDirection, NULL_VECTOR, NULL_VECTOR); - NormalizeVector(myDirection, myDirection); - ScaleVector(myDirection, 32.0); - AddVectors(myDirection, myPos, myDirection); - - float p[3], s[3]; - MakeVectorFromPoints(myPos, hisPos, p); - MakeVectorFromPoints(myPos, myDirection, s); - if (GetVectorDotProduct(p, s) <= 0.0)//We can backstab him m8 - { - if (GetClientTeam(victim) == GetClientTeam(attacker) && class == TFClass_Sniper) - { - //look if the player has a razorback - int wearableEnt = INVALID_ENT_REFERENCE; - while ((wearableEnt = FindEntityByClassname(wearableEnt, "tf_wearable")) != -1) - { - if (GetEntPropEnt(wearableEnt, Prop_Send, "m_hOwnerEntity") == victim && GetEntProp(wearableEnt, Prop_Send, "m_iItemDefinitionIndex") == 57) - { - RemoveEntity(wearableEnt); - damage = 0.0; - EmitSoundToClient(victim, "player/spy_shield_break.wav", _, _, SNDLEVEL_TRAFFIC, SND_NOFLAGS, 0.7, 100); - EmitSoundToClient(attacker, "player/spy_shield_break.wav", _, _, SNDLEVEL_TRAFFIC, SND_NOFLAGS, 0.7, 100); - - SetEntPropFloat(weapon, Prop_Send, "m_flNextPrimaryAttack", GetGameTime() + 2.0); - SetEntPropFloat(attacker, Prop_Send, "m_flNextAttack", GetGameTime() + 2.0); - SetEntPropFloat(attacker, Prop_Send, "m_flStealthNextChangeTime", GetGameTime() + 2.0); - int vm = GetEntPropEnt(attacker, Prop_Send, "m_hViewModel"); - if (vm > MaxClients) - { - int meleeIndex = GetEntProp(weapon, Prop_Send, "m_iItemDefinitionIndex"); - int anim = 41; - switch (meleeIndex) - { - case 4, 194, 225, 356, 461, 574, 649, 665, 794, 803, 883, 892, 901, 910, 959, 968: - { - anim = 15; - } - case 638: - { - anim = 31; - } - } - SetEntProp(vm, Prop_Send, "m_nSequence", anim); - } - return Plugin_Changed; - } - } - } - if (damagecustom == TF_CUSTOM_BACKSTAB) // Modify backstab damage. - { - damage = 120.0; - if (damagetype & DMG_ACID) - { - damage = 120.0; - } - } - - if (g_WeaponCriticalsConVar != null && g_WeaponCriticalsConVar.BoolValue) - { - damagetype |= DMG_ACID; - } - - if (!IsClientCritUbercharged(victim)) - { - if (GetClientTeam(victim) == GetClientTeam(attacker)) - { - int pistol = GetPlayerWeaponSlot(attacker, TFWeaponSlot_Primary); - if (pistol > MaxClients && GetEntProp(pistol, Prop_Send, "m_iItemDefinitionIndex") == 525) //Give one crit fort the backstab - { - int crits = GetEntProp(attacker, Prop_Send, "m_iRevengeCrits"); - crits++; - SetEntProp(attacker, Prop_Send, "m_iRevengeCrits", crits); - } - } - if (GetEntProp(victim, Prop_Send, "m_iHealth") <= 120) - { - g_PlayerBackStabbed[victim] = true; - } - else - { - g_PlayerBackStabbed[victim] = false; - } - } - return Plugin_Changed; - } - } - } - } - } - else - { - damage = 0.0; - return Plugin_Changed; - } - } - else - { - if (g_PlayerEliminated[attacker] == g_PlayerEliminated[victim]) - { - damage = 0.0; - return Plugin_Changed; - } - } - } - - return Plugin_Continue; -} - void ClientOnButtonPress(SF2_BasePlayer client, int button) { switch (button) diff --git a/addons/sourcemod/scripting/sf2/client/weapons.sp b/addons/sourcemod/scripting/sf2/client/weapons.sp index e2070e50..c7bedf4c 100644 --- a/addons/sourcemod/scripting/sf2/client/weapons.sp +++ b/addons/sourcemod/scripting/sf2/client/weapons.sp @@ -713,7 +713,7 @@ bool IsWeaponRestricted(SF2_BasePlayer client, int itemDefInt) { continue; } - if (Npc.GetProfileDataEx().GetProxies().IsEnabled(Npc.Difficulty)) + if (Npc.GetProfileData().GetProxies().IsEnabled(Npc.Difficulty)) { proxyBoss = true; break; diff --git a/addons/sourcemod/scripting/sf2/effects.sp b/addons/sourcemod/scripting/sf2/effects.sp index 6382e797..9cc02df3 100644 --- a/addons/sourcemod/scripting/sf2/effects.sp +++ b/addons/sourcemod/scripting/sf2/effects.sp @@ -188,6 +188,16 @@ methodmap ProfileEffect < ProfileObject this.GetDifficultyColor("rendercolor", difficulty, buffer); } + public ProfileEntityInputsArray GetInputs() + { + return view_as(this.GetSection("inputs")); + } + + public ProfileEntityOutputsArray GetOutputs() + { + return view_as(this.GetSection("outputs")); + } + public void Precache() { switch (this.Type) @@ -1014,6 +1024,11 @@ static void SpawnEffect(ProfileEffect effect, int bossIndex, const float overrid DispatchKeyValueInt(entity, "renderfx", view_as(effect.RenderEffect)); DispatchKeyValueInt(entity, "spawnflags", effect.SpawnFlags); + if (effect.GetOutputs() != null) + { + effect.GetOutputs().AddOutputs(entity); + } + switch (effect.Type) { case EffectType_Steam: @@ -1223,9 +1238,16 @@ static void SpawnEffect(ProfileEffect effect, int bossIndex, const float overrid AcceptEntityInput(entity, "ShowSprite"); } } + SDKHook(entity, SDKHook_SetTransmit, Hook_EffectTransmit); g_EntityEffectType[entity] = effect.Type; g_EntityEffectEvent[entity] = effect.Event; + + if (effect.GetInputs() != null) + { + effect.GetInputs().AcceptInputs(entity); + } + if (!noParenting) { g_NpcEffectsArray[bossIndex].Push(entity); diff --git a/addons/sourcemod/scripting/sf2/extras/commands.sp b/addons/sourcemod/scripting/sf2/extras/commands.sp index df394aad..f861b5f9 100644 --- a/addons/sourcemod/scripting/sf2/extras/commands.sp +++ b/addons/sourcemod/scripting/sf2/extras/commands.sp @@ -420,6 +420,7 @@ public void OnPluginStart() g_OnPlayerJumpPFwd = new PrivateForward(ET_Ignore, Param_Cell); g_OnPlayerSpawnPFwd = new PrivateForward(ET_Ignore, Param_Cell); g_OnPlayerTakeDamagePFwd = new PrivateForward(ET_Hook, Param_Cell, Param_CellByRef, Param_CellByRef, Param_FloatByRef, Param_CellByRef, Param_Cell); + g_OnPlayerTakeDamagePostPFwd = new PrivateForward(ET_Ignore, Param_Cell, Param_Cell, Param_Cell, Param_Float, Param_Cell); g_OnPlayerDeathPrePFwd = new PrivateForward(ET_Ignore, Param_Cell, Param_Cell, Param_Cell, Param_Cell); g_OnPlayerDeathPFwd = new PrivateForward(ET_Ignore, Param_Cell, Param_Cell, Param_Cell, Param_Cell); g_OnPlayerPutInServerPFwd = new PrivateForward(ET_Ignore, Param_Cell); @@ -472,6 +473,8 @@ public void OnPluginStart() InitializeEffects(); + SetupClients(); + SetupAntiCamping(); SetupBlink(); SetupBreathing(); @@ -1139,7 +1142,7 @@ static Action Hook_CommandVoiceMenu(int client, const char[] command,int argc) if (master != -1) { SF2NPC_BaseNPC npc = SF2NPC_BaseNPC(master); - BossProfileProxyData proxyData = npc.GetProfileDataEx().GetProxies(); + BossProfileProxyData proxyData = npc.GetProfileData().GetProxies(); BossProfileProxyClass classData = proxyData.GetClassData(TF2_GetPlayerClass(client)); ProfileSound soundInfo = classData.GetIdleSounds(); if (soundInfo.Paths != null && soundInfo.Paths.Length > 0 && GetGameTime() >= g_PlayerProxyNextVoiceSound[client]) @@ -1200,7 +1203,7 @@ static Action Command_ClientKillDeathcam(int client, int args) SF2NPC_BaseNPC npc = SF2NPC_BaseNPC(StringToInt(arg2)); if (npc.IsValid()) { - if ((npc.Flags & SFF_ATTACKWAITERS) != 0 || npc.GetProfileDataEx().IsPvEBoss) + if ((npc.Flags & SFF_ATTACKWAITERS) != 0 || npc.GetProfileData().IsPvEBoss) { eliminated = true; } @@ -1288,7 +1291,7 @@ static Action Command_SpawnSlender(int client, int args) return Plugin_Handled; } - if (npc.GetProfileDataEx().IsPvEBoss) + if (npc.GetProfileData().IsPvEBoss) { ReplyToCommand(client, "You may not spawn PvE bosses!"); return Plugin_Handled; @@ -1352,7 +1355,7 @@ static Action Command_SpawnAllSlenders(int client, int args) npc = SF2NPC_BaseNPC(npcIndex); if (npc.IsValid()) { - if (npc.GetProfileDataEx().IsPvEBoss) + if (npc.GetProfileData().IsPvEBoss) { continue; } @@ -1407,7 +1410,7 @@ static Action Timer_SpawnAllSlenders(Handle timer, any userid) SF2NPC_BaseNPC npc = SF2NPC_BaseNPC(g_SpawnAllBossesCount); if (npc.IsValid()) { - if (!npc.GetProfileDataEx().IsPvEBoss) + if (!npc.GetProfileData().IsPvEBoss) { npc.Spawn(endPos); } @@ -1475,7 +1478,7 @@ static Action Command_RemoveAllSlenders(int client, int args) continue; } - if (npc.GetProfileDataEx().IsPvEBoss) + if (npc.GetProfileData().IsPvEBoss) { continue; } diff --git a/addons/sourcemod/scripting/sf2/extras/game_events.sp b/addons/sourcemod/scripting/sf2/extras/game_events.sp index be64ce7e..a19110e1 100644 --- a/addons/sourcemod/scripting/sf2/extras/game_events.sp +++ b/addons/sourcemod/scripting/sf2/extras/game_events.sp @@ -144,7 +144,7 @@ Action Event_Audio(Event event, const char[] name, bool dB) { continue; } - if (!SF2NPC_BaseNPC(bossIndex).GetProfileDataEx().OutroMusic) + if (!SF2NPC_BaseNPC(bossIndex).GetProfileData().OutroMusic) { continue; } @@ -192,7 +192,7 @@ Action Event_RoundEnd(Handle event, const char[] name, bool dB) continue; } - BaseBossProfile data = SF2NPC_BaseNPC(npcIndex).GetProfileDataEx(); + BaseBossProfile data = SF2NPC_BaseNPC(npcIndex).GetProfileData(); if (data.OutroMusic) { char profile[SF2_MAX_PROFILE_NAME_LENGTH]; @@ -352,22 +352,23 @@ Action Event_PlayerTeam(Handle event, const char[] name, bool dB) Action Event_PlayerSpawn(Handle event, const char[] name, bool dB) { + int client = GetClientOfUserId(GetEventInt(event, "userid")); + if (client <= 0) + { + return Plugin_Continue; + } + if (!g_Enabled) { - if (g_LoadOutsideMapsConVar.BoolValue && GetClientOfUserId(GetEventInt(event, "userid")) > 0) + if (g_LoadOutsideMapsConVar.BoolValue) { Call_StartForward(g_OnPlayerSpawnPFwd); - Call_PushCell(SF2_BasePlayer(GetClientOfUserId(GetEventInt(event, "userid")))); + Call_PushCell(SF2_BasePlayer(client)); Call_Finish(); } return Plugin_Continue; } - int client = GetClientOfUserId(GetEventInt(event, "userid")); - if (client <= 0) - { - return Plugin_Continue; - } #if defined DEBUG Handle profiler = CreateProfiler(); @@ -703,7 +704,7 @@ Action Event_PlayerDeathPre(Event event, const char[] name, bool dB) if (NPCGetFlags(npcIndex) & SFF_WEAPONKILLS && SF2_ChaserEntity(owner).IsValid()) { SF2_ChaserEntity chaser = SF2_ChaserEntity(owner); - ChaserBossProfileBaseAttack attackData = SF2NPC_Chaser(npcIndex).GetProfileDataEx().GetAttack(chaser.GetAttackName()); + ChaserBossProfileBaseAttack attackData = SF2NPC_Chaser(npcIndex).GetProfileData().GetAttack(chaser.GetAttackName()); attackData.GetWeaponString(weaponType, sizeof(weaponType)); event.SetString("weapon_logclassname", weaponType); event.SetString("weapon", weaponType); diff --git a/addons/sourcemod/scripting/sf2/extras/natives.sp b/addons/sourcemod/scripting/sf2/extras/natives.sp index e04f21c9..f0da1b14 100644 --- a/addons/sourcemod/scripting/sf2/extras/natives.sp +++ b/addons/sourcemod/scripting/sf2/extras/natives.sp @@ -678,12 +678,12 @@ static any Native_SetBossTarget(Handle plugin, int numParams) static any Native_IsBossStunnable(Handle plugin, int numParams) { - return SF2NPC_Chaser(GetNativeCell(1)).GetProfileDataEx().GetStunBehavior().IsEnabled(1); + return SF2NPC_Chaser(GetNativeCell(1)).GetProfileData().GetStunBehavior().IsEnabled(1); } static any Native_IsBossStunnableByFlashlight(Handle plugin, int numParams) { - return SF2NPC_Chaser(GetNativeCell(1)).GetProfileDataEx().GetStunBehavior().CanFlashlightStun(1); + return SF2NPC_Chaser(GetNativeCell(1)).GetProfileData().GetStunBehavior().CanFlashlightStun(1); } static any Native_IsBossCloaked(Handle plugin, int numParams) diff --git a/addons/sourcemod/scripting/sf2/gamemodes/renevant.sp b/addons/sourcemod/scripting/sf2/gamemodes/renevant.sp index 12418e5d..92523968 100644 --- a/addons/sourcemod/scripting/sf2/gamemodes/renevant.sp +++ b/addons/sourcemod/scripting/sf2/gamemodes/renevant.sp @@ -72,11 +72,13 @@ bool SF_IsRenevantMap() static bool Renevant_TryAddBossProfile(char profile[SF2_MAX_PROFILE_NAME_LENGTH], int profileLen, char[] name, int nameLen, bool playSpawnSound = true) { - if (!GetRandomRenevantBossProfile(profile, profileLen)) + if (GetSelectableBossProfileList().Length == 0) { return false; } + GetSelectableBossProfileList().GetString(GetRandomInt(0, GetSelectableBossProfileList().Length - 1), profile, profileLen); + GetBossProfile(profile).GetName(1, name, nameLen); if (name[0] == '\0') { diff --git a/addons/sourcemod/scripting/sf2/mapentities/sf2_boss_maker.sp b/addons/sourcemod/scripting/sf2/mapentities/sf2_boss_maker.sp index ad38b48e..cbeb3539 100644 --- a/addons/sourcemod/scripting/sf2/mapentities/sf2_boss_maker.sp +++ b/addons/sourcemod/scripting/sf2/mapentities/sf2_boss_maker.sp @@ -247,7 +247,7 @@ methodmap SF2BossMakerEntity < SF2SpawnPointBaseEntity } } - if (SF2NPC_BaseNPC(bossIndex).GetProfileDataEx().Type == SF2BossType_Chaser) + if (SF2NPC_BaseNPC(bossIndex).GetProfileData().Type == SF2BossType_Chaser) { char spawnAnim[64]; this.GetSpawnAnimation(spawnAnim, sizeof(spawnAnim)); diff --git a/addons/sourcemod/scripting/sf2/methodmaps.sp b/addons/sourcemod/scripting/sf2/methodmaps.sp index b139c522..9be81a7b 100644 --- a/addons/sourcemod/scripting/sf2/methodmaps.sp +++ b/addons/sourcemod/scripting/sf2/methodmaps.sp @@ -80,7 +80,7 @@ methodmap SF2NPC_BaseNPC } } - public BaseBossProfile GetProfileDataEx() + public BaseBossProfile GetProfileData() { char profile[SF2_MAX_PROFILE_NAME_LENGTH]; this.GetProfile(profile, sizeof(profile)); @@ -443,6 +443,14 @@ methodmap SF2_BasePlayer < CBaseCombatCharacter } } + property int ModifiedMaxHealth + { + public get() + { + return ClientGetModifiedMaxHealth(this.index); + } + } + property bool Ducking { public get() @@ -1031,7 +1039,7 @@ methodmap SF2_BasePlayer < CBaseCombatCharacter methodmap SF2NPC_Chaser < SF2NPC_BaseNPC { - public ChaserBossProfile GetProfileDataEx() + public ChaserBossProfile GetProfileData() { char profile[SF2_MAX_PROFILE_NAME_LENGTH]; this.GetProfile(profile, sizeof(profile)); @@ -1087,7 +1095,7 @@ methodmap SF2NPC_Statue < SF2NPC_BaseNPC return view_as(SF2NPC_BaseNPC(index)); } - public StatueBossProfile GetProfileDataEx() + public StatueBossProfile GetProfileData() { char profile[SF2_MAX_PROFILE_NAME_LENGTH]; this.GetProfile(profile, sizeof(profile)); diff --git a/addons/sourcemod/scripting/sf2/npc.sp b/addons/sourcemod/scripting/sf2/npc.sp index 0dddfb29..7a0cd61e 100644 --- a/addons/sourcemod/scripting/sf2/npc.sp +++ b/addons/sourcemod/scripting/sf2/npc.sp @@ -176,9 +176,9 @@ static void EntityTeleported(CBaseEntity teleporter, CBaseEntity activator) controller.UnSpawn(); } - if (controller.GetProfileDataEx().Type == SF2BossType_Chaser) + if (controller.GetProfileData().Type == SF2BossType_Chaser) { - if (view_as(controller).GetProfileDataEx().ChasesEndlessly) + if (view_as(controller).GetProfileData().ChasesEndlessly) { controller.UnSpawn(); } @@ -190,7 +190,7 @@ static void EntityTeleported(CBaseEntity teleporter, CBaseEntity activator) static void OnPlayerLookAtBoss(SF2_BasePlayer client, SF2NPC_BaseNPC boss) { - switch (boss.GetProfileDataEx().Type) + switch (boss.GetProfileData().Type) { case SF2BossType_Statue: { @@ -202,12 +202,12 @@ static void OnPlayerLookAtBoss(SF2_BasePlayer client, SF2NPC_BaseNPC boss) } } -void NPCOnDespawn(SF2NPC_BaseNPC controller, CBaseEntity entity, bool killed = false) +void NPCOnDespawn(SF2NPC_BaseNPC controller, CBaseEntity entity) { char profile[SF2_MAX_PROFILE_NAME_LENGTH]; controller.GetProfile(profile, sizeof(profile)); int bossIndex = controller.Index; - BaseBossProfile data = controller.GetProfileDataEx(); + BaseBossProfile data = controller.GetProfileData(); Call_StartForward(g_OnBossDespawnFwd); Call_PushCell(bossIndex); Call_Finish(); @@ -231,24 +231,32 @@ void NPCOnDespawn(SF2NPC_BaseNPC controller, CBaseEntity entity, bool killed = f if (data.GetDespawnEffects() != null) { - if (killed && data.HideDespawnEffectsOnDeath) - { - // Do nothing - } - else + ProfileObject obj = view_as(data.GetDespawnEffects().GetSection(GetRandomInt(0, data.GetDespawnEffects().Length - 1))); + if (obj != null) { - ProfileObject obj = view_as(data.GetDespawnEffects().GetSection(GetRandomInt(0, data.GetDespawnEffects().Length - 1))); - obj = obj != null ? obj.GetSection("effects") : null; - if (obj != null) + if (data.GetBool("__was_killed") && obj.GetBool("hide_on_death", false)) { - float pos[3], ang[3]; - CBaseEntity(NPCGetEntIndex(bossIndex)).GetAbsOrigin(pos); - CBaseEntity(NPCGetEntIndex(bossIndex)).GetAbsAngles(ang); - SlenderSpawnEffects(view_as(obj), bossIndex, false, pos, ang, _, _, true); + // Do nothing + } + else + { + obj = obj.GetSection("effects"); + if (obj != null) + { + float pos[3], ang[3]; + CBaseEntity(NPCGetEntIndex(bossIndex)).GetAbsOrigin(pos); + CBaseEntity(NPCGetEntIndex(bossIndex)).GetAbsAngles(ang); + SlenderSpawnEffects(view_as(obj), bossIndex, false, pos, ang, _, _, true); + } } } } + if (data.GetDespawnInputs() != null) + { + data.GetDespawnInputs().AcceptInputs(entity.index); + } + char sound[PLATFORM_MAX_PATH]; data.GetConstantSound(sound, sizeof(sound)); if (sound[0] != '\0') @@ -281,7 +289,7 @@ void NPCOnDespawn(SF2NPC_BaseNPC controller, CBaseEntity entity, bool killed = f { continue; } - data = SF2NPC_BaseNPC(npcIndex).GetProfileDataEx(); + data = SF2NPC_BaseNPC(npcIndex).GetProfileData(); if (view_as(data).Healthbar) { int tempSlender = NPCGetEntIndex(npcIndex); @@ -298,6 +306,8 @@ void NPCOnDespawn(SF2NPC_BaseNPC controller, CBaseEntity entity, bool killed = f UpdateHealthBar(bossIndex, 0); } } + + data.SetBool("__was_killed", false); } void NPCOnConfigsExecuted() @@ -528,7 +538,7 @@ bool NPCShouldHearEntity(int npcIndex, int entity, SoundType soundType) return false; } - if (SF2NPC_BaseNPC(npcIndex).GetProfileDataEx().Type == SF2BossType_Statue) + if (SF2NPC_BaseNPC(npcIndex).GetProfileData().Type == SF2BossType_Statue) { return false; } @@ -583,7 +593,7 @@ void NPCGetEyePosition(int npcIndex, float buffer[3], const float defaultValue[3 float pos[3], eyePosOffset[3]; CBaseEntity(npcEnt).GetAbsOrigin(pos); - SF2NPC_BaseNPC(npcIndex).GetProfileDataEx().GetEyes().GetOffsetPos(eyePosOffset); + SF2NPC_BaseNPC(npcIndex).GetProfileData().GetEyes().GetOffsetPos(eyePosOffset); AddVectors(pos, eyePosOffset, buffer); } @@ -831,17 +841,18 @@ bool SelectProfile(SF2NPC_BaseNPC npc, const char[] profile, int additionalBossF } else { - if (profileData.IsPvEBoss && showPvEMessage && profileData.PvESpawnMessagesArray != null && profileData.PvESpawnMessagesArray.Size > 0) + BossProfilePvEData pveData = profileData.GetPvEData(); + if (pveData.IsEnabled && showPvEMessage && pveData.GetSpawnMessages() != null && pveData.GetSpawnMessages().KeyLength > 0) { char prefix[PLATFORM_MAX_PATH], message[PLATFORM_MAX_PATH], name[SF2_MAX_NAME_LENGTH], keyName[64]; - profileData.GetPvESpawnMessagePrefix(prefix, sizeof(prefix)); + pveData.GetSpawnMessagePrefix(prefix, sizeof(prefix)); if (prefix[0] == '\0') { prefix = "[SF2]"; } - int messageIndex = GetRandomInt(0, profileData.PvESpawnMessagesArray.Size - 1); - profileData.PvESpawnMessagesArray.GetKeyNameFromIndex(messageIndex, keyName, sizeof(keyName)); - profileData.PvESpawnMessagesArray.GetString(keyName, message, sizeof(message)); + int messageIndex = GetRandomInt(0, pveData.GetSpawnMessages().KeyLength - 1); + pveData.GetSpawnMessages().GetKeyNameFromIndex(messageIndex, keyName, sizeof(keyName)); + pveData.GetSpawnMessages().GetString(keyName, message, sizeof(message)); if (StrContains(message, "[BOSS]", true) != -1) { profileData.GetName(1, name, sizeof(name)); @@ -973,7 +984,7 @@ void NPCAddCompanions(SF2NPC_BaseNPC npc) { char profile[SF2_MAX_PROFILE_NAME_LENGTH]; npc.GetProfile(profile, sizeof(profile)); - BossProfileCompanions companions = npc.GetProfileDataEx().GetCompanions(); + BossProfileCompanions companions = npc.GetProfileData().GetCompanions(); if (companions == null) { return; @@ -1084,7 +1095,7 @@ bool GetSlenderModel(int bossIndex, int modelState = 0, char[] buffer, int buffe bool NPCFindUnstuckPosition(SF2_BaseBoss boss, float lastPos[3], float destination[3]) { SF2NPC_BaseNPC controller = boss.Controller; - BaseBossProfile data = controller.GetProfileDataEx(); + BaseBossProfile data = controller.GetProfileData(); PathFollower path = controller.Path; CBaseNPC npc = TheNPCs.FindNPCByEntIndex(boss.index); CNavArea area = TheNavMesh.GetNearestNavArea(lastPos, _, _, _, false); @@ -1182,7 +1193,7 @@ bool NPCFindUnstuckPosition(SF2_BaseBoss boss, float lastPos[3], float destinati int ent = -1; char targetName[64]; - if (controller.GetProfileDataEx().IsPvEBoss) + if (controller.GetProfileData().IsPvEBoss) { ArrayList spawnPointList = new ArrayList(); @@ -1323,7 +1334,7 @@ void RemoveProfile(int bossIndex) KillPvEBoss(controller.EntIndex); } - if (SF_IsBoxingMap() && (GetRoundState() == SF2RoundState_Escape) && view_as(controller).GetProfileDataEx().BoxingBoss) + if (SF_IsBoxingMap() && (GetRoundState() == SF2RoundState_Escape) && view_as(controller).GetProfileData().BoxingBoss) { g_SlenderBoxingBossCount -= 1; } @@ -1418,7 +1429,7 @@ void SpawnSlender(SF2NPC_BaseNPC npc, const float pos[3]) npc.UnSpawn(true); npc.GetProfile(profile, sizeof(profile)); npc.WasKilled = false; - BaseBossProfile data = npc.GetProfileDataEx(); + BaseBossProfile data = npc.GetProfileData(); float truePos[3], trueAng[3]; trueAng[1] = GetRandomFloat(0.0, 360.0); @@ -1518,6 +1529,11 @@ void SpawnSlender(SF2NPC_BaseNPC npc, const float pos[3]) } } + if (data.GetOutputs() != null) + { + data.GetOutputs().AddOutputs(entity.index); + } + int master = g_SlenderCopyMaster[bossIndex]; int flags = NPCGetFlags(bossIndex); @@ -1539,6 +1555,11 @@ void SpawnSlender(SF2NPC_BaseNPC npc, const float pos[3]) float teleportTime = GetRandomFloat(data.GetMinTeleportTime(difficulty), data.GetMaxTeleportTime(difficulty)); g_SlenderNextTeleportTime[bossIndex] = GetGameTime() + teleportTime; + if (data.GetSpawnInputs() != null) + { + data.GetSpawnInputs().AcceptInputs(entity.index); + } + // Call our forward. Call_StartForward(g_OnBossSpawnFwd); Call_PushCell(bossIndex); @@ -1582,6 +1603,10 @@ void UpdateHealthBar(int bossIndex, int optionalSetPercent = -1) SF2_ChaserEntity chaser = SF2_ChaserEntity(NPCGetEntIndex(bossIndex)); if (!chaser.IsValid()) { + if (g_HealthBar != -1) + { + SetEntProp(g_HealthBar, Prop_Send, "m_iBossHealthPercentageByte", 0); + } return; } float maxHealth = chaser.MaxHealth; @@ -1785,7 +1810,7 @@ Action Timer_BossMarked(Handle timer, any entref) bool SlenderUsesBlink(int bossIndex) { - if (SF2NPC_BaseNPC(bossIndex).GetProfileDataEx().Type == SF2BossType_Statue) + if (SF2NPC_BaseNPC(bossIndex).GetProfileData().Type == SF2BossType_Statue) { return true; } @@ -1919,7 +1944,7 @@ void SlenderCastFootstepAnimEvent(int bossIndex, int event, int slender) GetEntPropVector(slender, Prop_Data, "m_vecAbsOrigin", myPos); soundInfo.EmitSound(_, slender); - ChaserBossProfile data = SF2NPC_Chaser(bossIndex).GetProfileDataEx(); + ChaserBossProfile data = SF2NPC_Chaser(bossIndex).GetProfileData(); if (data.EarthquakeFootsteps) { UTIL_ScreenShake(myPos, data.EarthquakeFootstepAmplitude, @@ -1995,7 +2020,7 @@ static Action Timer_SlenderTeleportThink(Handle timer, any id) } float gameTime = GetGameTime(); - BaseBossProfile data = controller.GetProfileDataEx(); + BaseBossProfile data = controller.GetProfileData(); int difficulty = GetLocalGlobalDifficulty(bossIndex); @@ -2281,7 +2306,7 @@ static Action Timer_SlenderTeleportThink(Handle timer, any id) SubtractVectors(spawnPos, offset, spawnPos); // Look for copies - if (controller.GetProfileDataEx().GetCopies().IsEnabled(difficulty) && canSpawn) + if (controller.GetProfileData().GetCopies().IsEnabled(difficulty) && canSpawn) { float minDistBetweenBosses = data.GetCopies().GetTeleportDistanceSpacing(difficulty); @@ -2426,7 +2451,7 @@ static Action Timer_SlenderRespawnThink(Handle timer, any id) float gameTime = GetGameTime(); int difficulty = GetLocalGlobalDifficulty(bossIndex); - BaseBossProfile data = controller.GetProfileDataEx(); + BaseBossProfile data = controller.GetProfileData(); bool cont = false; @@ -2503,7 +2528,7 @@ bool SlenderMarkAsFake(int bossIndex) NPCSetFlags(bossIndex, bossFlags | SFF_MARKEDASFAKE); - BaseBossProfile data = SF2NPC_BaseNPC(bossIndex).GetProfileDataEx(); + BaseBossProfile data = SF2NPC_BaseNPC(bossIndex).GetProfileData(); g_SlenderFakeTimer[bossIndex] = CreateTimer(3.0, Timer_SlenderMarkedAsFake, bossIndex, TIMER_FLAG_NO_MAPCHANGE); @@ -3232,7 +3257,7 @@ static any Native_GetBossName(Handle plugin, int numParams) static any Native_GetBossType(Handle plugin, int numParams) { - return SF2NPC_BaseNPC(GetNativeCell(1)).GetProfileDataEx().Type; + return SF2NPC_BaseNPC(GetNativeCell(1)).GetProfileData().Type; } static any Native_GetBossFlags(Handle plugin, int numParams) @@ -3290,7 +3315,7 @@ static any Native_GetBossMaster(Handle plugin, int numParams) static any Native_GetBossIdleLifetime(Handle plugin, int numParams) { - return SF2NPC_BaseNPC(GetNativeCell(1)).GetProfileDataEx().GetIdleLifeTime(GetNativeCell(2)); + return SF2NPC_BaseNPC(GetNativeCell(1)).GetProfileData().GetIdleLifeTime(GetNativeCell(2)); } static any Native_GetBossState(Handle plugin, int numParams) @@ -3342,7 +3367,7 @@ static any Native_GetBossEyePositionOffset(Handle plugin, int numParams) } float eyePos[3]; - boss.GetProfileDataEx().GetEyes().GetOffsetPos(eyePos); + boss.GetProfileData().GetEyes().GetOffsetPos(eyePos); SetNativeArray(2, eyePos, 3); return 0; @@ -3434,7 +3459,7 @@ static any Native_GetProfileData(Handle plugin, int numParams) return ThrowNativeError(SP_ERROR_NATIVE, "Invalid boss index %d", controller.Index); } - return controller.GetProfileDataEx(); + return controller.GetProfileData(); } static any Native_GetProfileDataEx(Handle plugin, int numParams) diff --git a/addons/sourcemod/scripting/sf2/npc/entities/base/actions/deathcam.sp b/addons/sourcemod/scripting/sf2/npc/entities/base/actions/deathcam.sp index b860e7b2..2a069676 100644 --- a/addons/sourcemod/scripting/sf2/npc/entities/base/actions/deathcam.sp +++ b/addons/sourcemod/scripting/sf2/npc/entities/base/actions/deathcam.sp @@ -43,7 +43,7 @@ static NextBotAction InitialContainedAction(SF2_DeathCamAction action, SF2_BaseB actor.IsKillingSomeone = true; float duration = 0.0, rate = 1.0, cycle = 0.0; SF2NPC_BaseNPC controller = actor.Controller; - BaseBossProfile data = controller.GetProfileDataEx(); + BaseBossProfile data = controller.GetProfileData(); data.GetLocalDeathCamSounds().EmitSound(_, actor.index, .difficulty = controller.Difficulty); int sequence = actor.SelectProfileAnimation(g_SlenderAnimationsList[SF2BossAnimation_DeathCam], rate, duration, cycle); diff --git a/addons/sourcemod/scripting/sf2/npc/entities/base/actions/playsequenceandwait_ex.sp b/addons/sourcemod/scripting/sf2/npc/entities/base/actions/playsequenceandwait_ex.sp index 821985ef..18c87e5e 100644 --- a/addons/sourcemod/scripting/sf2/npc/entities/base/actions/playsequenceandwait_ex.sp +++ b/addons/sourcemod/scripting/sf2/npc/entities/base/actions/playsequenceandwait_ex.sp @@ -5,7 +5,7 @@ static NextBotActionFactory g_Factory; methodmap SF2_PlaySequenceAndWaitEx < NextBotAction { - public SF2_PlaySequenceAndWaitEx(char[] section) + public SF2_PlaySequenceAndWaitEx(const char[] section, const char[] preDefinedName = "") { if (g_Factory == null) { @@ -16,6 +16,7 @@ methodmap SF2_PlaySequenceAndWaitEx < NextBotAction g_Factory.SetCallback(NextBotActionCallbackType_OnEnd, OnEnd); g_Factory.BeginDataMapDesc() .DefineStringField("m_Section") + .DefineStringField("m_PreDefinedName") .DefineFloatField("m_EndTime") .EndDataMapDesc(); } @@ -23,6 +24,7 @@ methodmap SF2_PlaySequenceAndWaitEx < NextBotAction SF2_PlaySequenceAndWaitEx action = view_as(g_Factory.Create()); action.SetSection(section); + action.SetPreDefinedName(preDefinedName); return action; } @@ -39,6 +41,18 @@ methodmap SF2_PlaySequenceAndWaitEx < NextBotAction this.SetDataString("m_Section", name); } + public char[] GetPreDefinedName() + { + char name[128]; + this.GetDataString("m_PreDefinedName", name, sizeof(name)); + return name; + } + + public void SetPreDefinedName(const char[] name) + { + this.SetDataString("m_PreDefinedName", name); + } + property float EndTime { public get() @@ -57,7 +71,7 @@ static int OnStart(SF2_PlaySequenceAndWaitEx action, SF2_BaseBoss actor, NextBot { float duration = 0.0, cycle = 0.0, rate = 1.0; int sequence = -1; - if (!actor.ResetProfileAnimation(action.GetSection(), .sequence = sequence, .duration = duration, .rate = rate, .cycle = cycle)) + if (!actor.ResetProfileAnimation(action.GetSection(), .preDefinedName = action.GetPreDefinedName(), .sequence = sequence, .duration = duration, .rate = rate, .cycle = cycle)) { return action.Done("Invalid section"); } diff --git a/addons/sourcemod/scripting/sf2/npc/entities/base/entity.sp b/addons/sourcemod/scripting/sf2/npc/entities/base/entity.sp index bc89fe99..0d733cc1 100644 --- a/addons/sourcemod/scripting/sf2/npc/entities/base/entity.sp +++ b/addons/sourcemod/scripting/sf2/npc/entities/base/entity.sp @@ -132,7 +132,7 @@ methodmap SF2_BaseBoss < CBaseCombatCharacter public BaseBossProfile GetProfileData() { - return this.Controller.GetProfileDataEx(); + return this.Controller.GetProfileData(); } property CBaseEntity Target @@ -575,7 +575,7 @@ methodmap SF2_BaseBoss < CBaseCombatCharacter bool found = false; ProfileAnimation section = null; - if (controller.GetProfileDataEx().Type == SF2BossType_Chaser && !IsNullString(posture) && strcmp(posture, SF2_PROFILE_CHASER_DEFAULT_POSTURE) != 0) + if (controller.GetProfileData().Type == SF2BossType_Chaser && !IsNullString(posture) && strcmp(posture, SF2_PROFILE_CHASER_DEFAULT_POSTURE) != 0) { ChaserBossProfile data = view_as(this.GetProfileData()); found = data.GetPosture(posture) != null; @@ -599,7 +599,7 @@ methodmap SF2_BaseBoss < CBaseCombatCharacter } } - section = controller.GetProfileDataEx().GetAnimations().GetAnimation(animType, preDefinedIndex, preDefinedName, index); + section = controller.GetProfileData().GetAnimations().GetAnimation(animType, preDefinedIndex, preDefinedName, index); if (section == null) { @@ -636,7 +636,7 @@ methodmap SF2_BaseBoss < CBaseCombatCharacter char gesture[64]; - ProfileAnimation section = controller.GetProfileDataEx().GetAnimations().GetAnimation(animType, definedIndex, definedName); + ProfileAnimation section = controller.GetProfileData().GetAnimations().GetAnimation(animType, definedIndex, definedName); if (section == null) { @@ -796,11 +796,11 @@ methodmap SF2_BaseBoss < CBaseCombatCharacter public void ProcessRainbowOutline() { SF2NPC_BaseNPC controller = this.Controller; - BaseBossProfile data = controller.GetProfileDataEx(); + BossProfileOutlineData data = controller.GetProfileData().GetOutlineData(); int color[4]; - color[0] = RoundToNearest(Cosine((GetGameTime() * data.RainbowOutlineCycle) + controller.Index + 0) * 127.5 + 127.5); - color[1] = RoundToNearest(Cosine((GetGameTime() * data.RainbowOutlineCycle) + controller.Index + 2) * 127.5 + 127.5); - color[2] = RoundToNearest(Cosine((GetGameTime() * data.RainbowOutlineCycle) + controller.Index + 4) * 127.5 + 127.5); + color[0] = RoundToNearest(Cosine((GetGameTime() * data.GetRainbowCycle(controller.Difficulty)) + controller.Index + 0) * 127.5 + 127.5); + color[1] = RoundToNearest(Cosine((GetGameTime() * data.GetRainbowCycle(controller.Difficulty)) + controller.Index + 2) * 127.5 + 127.5); + color[2] = RoundToNearest(Cosine((GetGameTime() * data.GetRainbowCycle(controller.Difficulty)) + controller.Index + 4) * 127.5 + 127.5); color[3] = 255; SetGlowColor(this.index, color); } @@ -1086,7 +1086,7 @@ static any Native_GetName(Handle plugin, int numParams) } char buffer[SF2_MAX_PROFILE_NAME_LENGTH]; - controller.GetProfileDataEx().GetName(controller.Difficulty, buffer, sizeof(buffer)); + controller.GetProfileData().GetName(controller.Difficulty, buffer, sizeof(buffer)); SetNativeString(2, buffer, sizeof(buffer)); return 0; @@ -1132,7 +1132,7 @@ static any Native_GetProfileData(Handle plugin, int numParams) return 0; } - return bossEntity.Controller.GetProfileDataEx(); + return bossEntity.Controller.GetProfileData(); } static any Native_ResetProfileAnimation(Handle plugin, int numParams) diff --git a/addons/sourcemod/scripting/sf2/npc/entities/chaser/actions/alert.sp b/addons/sourcemod/scripting/sf2/npc/entities/chaser/actions/alert.sp index 7639d0af..a617166f 100644 --- a/addons/sourcemod/scripting/sf2/npc/entities/chaser/actions/alert.sp +++ b/addons/sourcemod/scripting/sf2/npc/entities/chaser/actions/alert.sp @@ -173,7 +173,7 @@ methodmap SF2_ChaserAlertAction < NextBotAction static int OnStart(SF2_ChaserAlertAction action, SF2_ChaserEntity actor, NextBotAction priorAction) { SF2NPC_Chaser controller = actor.Controller; - ChaserBossProfile data = controller.GetProfileDataEx(); + ChaserBossProfile data = controller.GetProfileData(); ChaserBossProfileAlertData alertData = data.GetAlertBehavior(); int difficulty = controller.Difficulty; float gameTime = GetGameTime(); @@ -222,7 +222,7 @@ static int Update(SF2_ChaserAlertAction action, SF2_ChaserEntity actor, float in return action.Continue(); } - ChaserBossProfile data = controller.GetProfileDataEx(); + ChaserBossProfile data = controller.GetProfileData(); ChaserBossProfileAlertData alertData = data.GetAlertBehavior(); if (!data.IsPvEBoss && IsBeatBoxBeating(2)) @@ -273,6 +273,18 @@ static int Update(SF2_ChaserAlertAction action, SF2_ChaserEntity actor, float in if (target.IsValid()) { + if (SF_IsRaidMap() || SF_BossesChaseEndlessly() || SF_IsProxyMap() || SF_IsBoxingMap() || SF_IsSlaughterRunMap() || data.ChasesEndlessly || + data.IsPvEBoss) + { + actor.State = STATE_CHASE; + path.Invalidate(); + if (data.NormalSoundHook) + { + actor.NextVoiceTime = 0.0; + } + return action.ChangeTo(SF2_ChaserChaseAction(), "We must endless chase, GET THEM!"); + } + if ((interruptConditions & COND_ENEMYRECHASE) != 0) { actor.State = STATE_CHASE; @@ -513,7 +525,7 @@ static void OnResume(SF2_ChaserAlertAction action, SF2_ChaserEntity actor, NextB static void OnReachedAlertPosition(SF2_ChaserAlertAction action, SF2_ChaserEntity actor) { SF2NPC_Chaser controller = actor.Controller; - ChaserBossProfile data = controller.GetProfileDataEx(); + ChaserBossProfile data = controller.GetProfileData(); ChaserBossProfileAlertData alertData = data.GetAlertBehavior(); int difficulty = controller.Difficulty; float gameTime = GetGameTime(); diff --git a/addons/sourcemod/scripting/sf2/npc/entities/chaser/actions/attack.sp b/addons/sourcemod/scripting/sf2/npc/entities/chaser/actions/attack.sp index 1476ba3a..93d23b10 100644 --- a/addons/sourcemod/scripting/sf2/npc/entities/chaser/actions/attack.sp +++ b/addons/sourcemod/scripting/sf2/npc/entities/chaser/actions/attack.sp @@ -570,6 +570,16 @@ methodmap ChaserBossProfileBaseAttack < ProfileObject return null; } + public ProfileEntityInputsArray GetStartInputs() + { + ProfileObject obj = this.GetSection("inputs"); + if (obj != null) + { + return view_as(obj.GetSection("start")); + } + return null; + } + public ProfileEffectMaster GetHitEffects() { ProfileObject obj = this.GetSection("effects"); @@ -582,6 +592,16 @@ methodmap ChaserBossProfileBaseAttack < ProfileObject return null; } + public ProfileEntityInputsArray GetHitInputs() + { + ProfileObject obj = this.GetSection("inputs"); + if (obj != null) + { + return view_as(obj.GetSection("hit")); + } + return null; + } + public ProfileEffectMaster GetMissEffects() { ProfileObject obj = this.GetSection("effects"); @@ -594,6 +614,16 @@ methodmap ChaserBossProfileBaseAttack < ProfileObject return null; } + public ProfileEntityInputsArray GetMissInputs() + { + ProfileObject obj = this.GetSection("inputs"); + if (obj != null) + { + return view_as(obj.GetSection("miss")); + } + return null; + } + public ProfileEffectMaster GetOnKillEffects() { ProfileObject obj = this.GetSection("effects"); @@ -606,6 +636,16 @@ methodmap ChaserBossProfileBaseAttack < ProfileObject return null; } + public ProfileEntityInputsArray GetOnKillInputs() + { + ProfileObject obj = this.GetSection("inputs"); + if (obj != null) + { + return view_as(obj.GetSection("on_kill")); + } + return null; + } + public KeyMap_Array GetDamageEffects() { return this.GetArray("apply_conditions"); @@ -884,7 +924,7 @@ methodmap BossProfileDamageEffect < ProfileObject { char playerName[32], bossName[SF2_MAX_NAME_LENGTH]; GetClientName(player.index, playerName, sizeof(playerName)); - controller.GetProfileDataEx().GetName(controller.Difficulty, bossName, sizeof(bossName)); + controller.GetProfileData().GetName(controller.Difficulty, bossName, sizeof(bossName)); CPrintToChatAll("{royalblue}%t {default}%t", "SF2 Prefix", "SF2 Smote target", bossName, playerName); } } @@ -1269,6 +1309,7 @@ methodmap SF2_ChaserAttackAction < NextBotAction CreateNative("SF2_ChaserBossProfileBaseAttack.BlockOnDifficulty.get", Native_GetBlockOnDifficulty); CreateNative("SF2_ChaserBossProfileBaseAttack.CanUseOnHealth", Native_GetCanUseOnHealth); CreateNative("SF2_ChaserBossProfileBaseAttack.CanBlockOnHealth", Native_GetCanBlockOnHealth); + CreateNative("SF2_ChaserBossProfileBaseAttack.GetEventNumber", Native_GetEventNumber); ChaserBossProfileCustomAttack.SetupAPI(); } @@ -1444,7 +1485,7 @@ static int OnStart(SF2_ChaserAttackAction action, SF2_ChaserEntity actor, NextBo int difficulty = controller.Difficulty; float gameTime = GetGameTime(); - ChaserBossProfile data = controller.GetProfileDataEx(); + ChaserBossProfile data = controller.GetProfileData(); ChaserBossProfileChaseData chaseData = data.GetChaseBehavior(); ChaserBossProfileBaseAttack attackData = action.ProfileData; actor.AttackRunDelay = gameTime + attackData.GetRunDelay(difficulty); @@ -1470,6 +1511,11 @@ static int OnStart(SF2_ChaserAttackAction action, SF2_ChaserEntity actor, NextBo SlenderSpawnEffects(attackData.GetStartEffects(), controller.Index, false); } + if (attackData.GetStartInputs() != null) + { + attackData.GetStartInputs().AcceptInputs(actor.index); + } + if (attackData.GetRunSpeed(difficulty) <= 0.0) { actor.MyNextBotPointer().GetLocomotionInterface().Stop(); @@ -1486,7 +1532,6 @@ static int OnStart(SF2_ChaserAttackAction action, SF2_ChaserEntity actor, NextBo return action.Continue(); } - actor.ResetProfileAnimation(g_SlenderAnimationsList[SF2BossAnimation_Attack], _, action.GetAttackName()); actor.AddGesture(g_SlenderAnimationsList[SF2BossAnimation_Attack], _, action.GetAttackName()); ProfileSound info; @@ -1500,12 +1545,11 @@ static int OnStart(SF2_ChaserAttackAction action, SF2_ChaserEntity actor, NextBo action.PlayedBeginVoice = true; } - float duration = 0.0; - NextBotAction newAction = actor.IsAttackTransitionPossible(action.GetAttackName(), _, duration); + NextBotAction newAction = actor.IsAttackTransitionPossible(action.GetAttackName()); action.ShouldReplayAnimation = newAction != NULL_ACTION; - if (newAction != NULL_ACTION) + if (newAction == NULL_ACTION) { - action.EndTime += duration; + actor.ResetProfileAnimation(g_SlenderAnimationsList[SF2BossAnimation_Attack], _, action.GetAttackName()); } return newAction != NULL_ACTION ? action.SuspendFor(newAction) : action.Continue(); } @@ -1524,7 +1568,7 @@ static int Update(SF2_ChaserAttackAction action, SF2_ChaserEntity actor, float i return action.Done(); } - ChaserBossProfile data = controller.GetProfileDataEx(); + ChaserBossProfile data = controller.GetProfileData(); ChaserBossProfileBaseAttack attackData = action.ProfileData; int interrputConditions = actor.InterruptConditions; bool end = false; @@ -1608,7 +1652,9 @@ static int Update(SF2_ChaserAttackAction action, SF2_ChaserEntity actor, float i } } - if (action.ActiveChild == NULL_ACTION || GetGameTime() > action.EndTime || end) + action.EndTime -= interval; + + if (action.ActiveChild == NULL_ACTION || action.EndTime <= 0.0 || end) { NextBotAction newAction = actor.IsAttackTransitionPossible(action.GetAttackName(), true); if (!action.DidEndAnimation && newAction != NULL_ACTION) @@ -1685,7 +1731,7 @@ static void OnEnd(SF2_ChaserAttackAction action, SF2_ChaserEntity actor) if (controller.IsValid()) { float gameTime = GetGameTime(); - ChaserBossProfile data = controller.GetProfileDataEx(); + ChaserBossProfile data = controller.GetProfileData(); ChaserBossProfileBaseAttack attackData = action.ProfileData; int difficulty = controller.Difficulty; @@ -1913,3 +1959,16 @@ static any Native_GetCanBlockOnHealth(Handle plugin, int numParams) return attackData.CanBlockOnHealth(difficulty); } + +static any Native_GetEventNumber(Handle plugin, int numParams) +{ + ChaserBossProfileBaseAttack attackData = GetNativeCell(1); + if (attackData == null) + { + return ThrowNativeError(SP_ERROR_NATIVE, "Invalid profile object handle %x", attackData); + } + + int difficulty = GetNativeCell(2); + + return attackData.GetEventNumber(difficulty); +} diff --git a/addons/sourcemod/scripting/sf2/npc/entities/chaser/actions/attacks/bullet.sp b/addons/sourcemod/scripting/sf2/npc/entities/chaser/actions/attacks/bullet.sp index 4434f042..8862ad92 100644 --- a/addons/sourcemod/scripting/sf2/npc/entities/chaser/actions/attacks/bullet.sp +++ b/addons/sourcemod/scripting/sf2/npc/entities/chaser/actions/attacks/bullet.sp @@ -125,7 +125,7 @@ static Action OnChaserGetAttackAction(SF2_ChaserEntity chaser, const char[] atta return Plugin_Continue; } - ChaserBossProfile data = chaser.Controller.GetProfileDataEx(); + ChaserBossProfile data = chaser.Controller.GetProfileData(); ChaserBossProfileBulletAttack attackData = view_as(data.GetAttack(attackName)); int difficulty = chaser.Controller.Difficulty; @@ -202,7 +202,7 @@ static void DoBulletAttack(SF2_ChaserAttackAction_Bullet action, SF2_ChaserEntit int difficulty = controller.Difficulty; - ChaserBossProfile data = controller.GetProfileDataEx(); + ChaserBossProfile data = controller.GetProfileData(); ChaserBossProfileBulletAttack attackData = action.ProfileData; float spread = attackData.GetBulletSpread(difficulty); diff --git a/addons/sourcemod/scripting/sf2/npc/entities/chaser/actions/attacks/custom.sp b/addons/sourcemod/scripting/sf2/npc/entities/chaser/actions/attacks/custom.sp index b99ff761..cbc08fbd 100644 --- a/addons/sourcemod/scripting/sf2/npc/entities/chaser/actions/attacks/custom.sp +++ b/addons/sourcemod/scripting/sf2/npc/entities/chaser/actions/attacks/custom.sp @@ -31,7 +31,7 @@ static Action OnChaserGetAttackAction(SF2_ChaserEntity chaser, const char[] atta return Plugin_Continue; } - ChaserBossProfile data = chaser.Controller.GetProfileDataEx(); + ChaserBossProfile data = chaser.Controller.GetProfileData(); ChaserBossProfileCustomAttack attackData = view_as(data.GetAttack(attackName)); if (attackData.Type != SF2BossAttackType_Custom) diff --git a/addons/sourcemod/scripting/sf2/npc/entities/chaser/actions/attacks/explosive_dance.sp b/addons/sourcemod/scripting/sf2/npc/entities/chaser/actions/attacks/explosive_dance.sp index 1787aba0..12215fec 100644 --- a/addons/sourcemod/scripting/sf2/npc/entities/chaser/actions/attacks/explosive_dance.sp +++ b/addons/sourcemod/scripting/sf2/npc/entities/chaser/actions/attacks/explosive_dance.sp @@ -126,7 +126,7 @@ static Action OnChaserGetAttackAction(SF2_ChaserEntity chaser, const char[] atta return Plugin_Continue; } - ChaserBossProfile data = chaser.Controller.GetProfileDataEx(); + ChaserBossProfile data = chaser.Controller.GetProfileData(); ChaserBossProfileExplosiveDanceAttack attackData = view_as(data.GetAttack(attackName)); int difficulty = chaser.Controller.Difficulty; diff --git a/addons/sourcemod/scripting/sf2/npc/entities/chaser/actions/attacks/forward_based.sp b/addons/sourcemod/scripting/sf2/npc/entities/chaser/actions/attacks/forward_based.sp index 5696d264..00227e7b 100644 --- a/addons/sourcemod/scripting/sf2/npc/entities/chaser/actions/attacks/forward_based.sp +++ b/addons/sourcemod/scripting/sf2/npc/entities/chaser/actions/attacks/forward_based.sp @@ -92,7 +92,7 @@ static Action OnChaserGetAttackAction(SF2_ChaserEntity chaser, const char[] atta return Plugin_Continue; } - ChaserBossProfile data = chaser.Controller.GetProfileDataEx(); + ChaserBossProfile data = chaser.Controller.GetProfileData(); ChaserBossProfileBaseAttack attackData = data.GetAttack(attackName); int difficulty = chaser.Controller.Difficulty; diff --git a/addons/sourcemod/scripting/sf2/npc/entities/chaser/actions/attacks/laser_beam.sp b/addons/sourcemod/scripting/sf2/npc/entities/chaser/actions/attacks/laser_beam.sp index c0aa15b6..30736beb 100644 --- a/addons/sourcemod/scripting/sf2/npc/entities/chaser/actions/attacks/laser_beam.sp +++ b/addons/sourcemod/scripting/sf2/npc/entities/chaser/actions/attacks/laser_beam.sp @@ -171,7 +171,7 @@ static Action OnChaserGetAttackAction(SF2_ChaserEntity chaser, const char[] atta return Plugin_Continue; } - ChaserBossProfile data = chaser.Controller.GetProfileDataEx(); + ChaserBossProfile data = chaser.Controller.GetProfileData(); ChaserBossProfileLaserAttack attackData = view_as(data.GetAttack(attackName)); int difficulty = chaser.Controller.Difficulty; diff --git a/addons/sourcemod/scripting/sf2/npc/entities/chaser/actions/attacks/melee.sp b/addons/sourcemod/scripting/sf2/npc/entities/chaser/actions/attacks/melee.sp index 54f44dde..631ada64 100644 --- a/addons/sourcemod/scripting/sf2/npc/entities/chaser/actions/attacks/melee.sp +++ b/addons/sourcemod/scripting/sf2/npc/entities/chaser/actions/attacks/melee.sp @@ -93,7 +93,7 @@ static Action OnChaserGetAttackAction(SF2_ChaserEntity chaser, const char[] atta return Plugin_Continue; } - ChaserBossProfile data = chaser.Controller.GetProfileDataEx(); + ChaserBossProfile data = chaser.Controller.GetProfileData(); ChaserBossProfileBaseAttack attackData = data.GetAttack(attackName); int difficulty = chaser.Controller.Difficulty; @@ -170,7 +170,7 @@ static void DoMeleeAttack(SF2_ChaserAttackAction_Melee action, SF2_ChaserEntity int difficulty = controller.Difficulty; bool attackEliminated = (controller.Flags & SFF_ATTACKWAITERS) != 0; - ChaserBossProfile data = controller.GetProfileDataEx(); + ChaserBossProfile data = controller.GetProfileData(); ChaserBossProfileBaseAttack attackData = action.ProfileData; if (data.IsPvEBoss) { @@ -297,8 +297,16 @@ static void DoMeleeAttack(SF2_ChaserAttackAction_Melee action, SF2_ChaserEntity float realDamage = damage; if (attackData.GetDamagePercent(difficulty) > 0.0) { - realDamage = strcmp(class, "tank_boss", false) != 0 ? float(prop.GetProp(Prop_Send, "m_iMaxHealth")) : float(prop.GetProp(Prop_Data, "m_iMaxHealth")); - realDamage *= attackData.GetDamagePercent(difficulty); + if (SF2_BasePlayer(targets.Get(i)).IsValid) + { + realDamage = float(SF2_BasePlayer(targets.Get(i)).ModifiedMaxHealth); + realDamage *= attackData.GetDamagePercent(difficulty); + } + else + { + realDamage = (strcmp(class, "tank_boss", false) != 0 && strcmp(class, "func_breakable", false) != 0) ? float(prop.GetProp(Prop_Send, "m_iMaxHealth")) : float(prop.GetProp(Prop_Data, "m_iMaxHealth")); + realDamage *= attackData.GetDamagePercent(difficulty); + } } SDKHooks_TakeDamage(prop.index, actor.index, actor.index, realDamage, 64, _, _, myEyePos, false); } @@ -337,7 +345,7 @@ static void DoMeleeAttack(SF2_ChaserAttackAction_Melee action, SF2_ChaserEntity float realDamage = damage; if (attackData.GetDamagePercent(difficulty) > 0.0) { - realDamage = float(player.GetProp(Prop_Data, "m_iMaxHealth")) * attackData.GetDamagePercent(difficulty); + realDamage = float(player.ModifiedMaxHealth) * attackData.GetDamagePercent(difficulty); } if (controller.HasAttribute(SF2Attribute_DeathCamOnLowHealth) || attackData.DeathCamLowHealth) @@ -420,6 +428,11 @@ static void DoMeleeAttack(SF2_ChaserAttackAction_Melee action, SF2_ChaserEntity { SlenderSpawnEffects(attackData.GetMissEffects(), controller.Index, false); } + + if (attackData.GetMissInputs() != null) + { + attackData.GetMissInputs().AcceptInputs(actor.index); + } } if (!SF_IsSlaughterRunMap()) @@ -465,7 +478,7 @@ static bool IsTargetInMeleeChecks(SF2_ChaserEntity actor, ChaserBossProfileBaseA actor.GetAbsOrigin(myPos); actor.Controller.GetEyePosition(myEyePos); actor.GetAbsAngles(myEyeAng); - actor.Controller.GetProfileDataEx().GetEyes().GetOffsetPos(offset); + actor.Controller.GetProfileData().GetEyes().GetOffsetPos(offset); AddVectors(offset, myEyeAng, myEyeAng); diff --git a/addons/sourcemod/scripting/sf2/npc/entities/chaser/actions/attacks/projectile.sp b/addons/sourcemod/scripting/sf2/npc/entities/chaser/actions/attacks/projectile.sp index b785171f..0763932d 100644 --- a/addons/sourcemod/scripting/sf2/npc/entities/chaser/actions/attacks/projectile.sp +++ b/addons/sourcemod/scripting/sf2/npc/entities/chaser/actions/attacks/projectile.sp @@ -184,7 +184,7 @@ static Action OnChaserGetAttackAction(SF2_ChaserEntity chaser, const char[] atta return Plugin_Continue; } - ChaserBossProfile data = chaser.Controller.GetProfileDataEx(); + ChaserBossProfile data = chaser.Controller.GetProfileData(); ChaserBossProfileProjectileAttack attackData = view_as(data.GetAttack(attackName)); int difficulty = chaser.Controller.Difficulty; @@ -277,7 +277,7 @@ static void FireProjectile(SF2_ChaserEntity actor, SF2_ChaserAttackAction_Projec targetPos[2] = eyePos[2] + fwd[2] * 9001.0; } int difficulty = controller.Difficulty; - ChaserBossProfile data = controller.GetProfileDataEx(); + ChaserBossProfile data = controller.GetProfileData(); ChaserBossProfileProjectileAttack attackData = action.ProfileData; ChaserBossProjectileData projectileData = data.GetProjectiles(); @@ -301,7 +301,7 @@ static void FireProjectile(SF2_ChaserEntity actor, SF2_ChaserAttackAction_Projec { float direction[3], angle[3]; SubtractVectors(targetPos, effectPos, direction); - float deviation = attackData.GetDeviation(difficulty); + float deviation = attackData.GetDeviation(difficulty) / 10.0; NormalizeVector(direction, direction); GetVectorAngles(direction, angle); diff --git a/addons/sourcemod/scripting/sf2/npc/entities/chaser/actions/attacks/tongue.sp b/addons/sourcemod/scripting/sf2/npc/entities/chaser/actions/attacks/tongue.sp index 669402bf..28d87635 100644 --- a/addons/sourcemod/scripting/sf2/npc/entities/chaser/actions/attacks/tongue.sp +++ b/addons/sourcemod/scripting/sf2/npc/entities/chaser/actions/attacks/tongue.sp @@ -295,7 +295,7 @@ static Action OnChaserGetAttackAction(SF2_ChaserEntity chaser, const char[] atta return Plugin_Continue; } - ChaserBossProfile data = chaser.Controller.GetProfileDataEx(); + ChaserBossProfile data = chaser.Controller.GetProfileData(); ChaserBossProfileTongueAttack attackData = view_as(data.GetAttack(attackName)); int difficulty = chaser.Controller.Difficulty; @@ -376,7 +376,7 @@ static int Update(SF2_ChaserAttackAction_Tongue action, SF2_ChaserEntity actor, SF2NPC_Chaser controller = actor.Controller; bool attackEliminated = (controller.Flags & SFF_ATTACKWAITERS) != 0; - ChaserBossProfile data = controller.GetProfileDataEx(); + ChaserBossProfile data = controller.GetProfileData(); ChaserBossProfileTongueAttack attackData = action.ProfileData; if (data.IsPvEBoss) { diff --git a/addons/sourcemod/scripting/sf2/npc/entities/chaser/actions/chase.sp b/addons/sourcemod/scripting/sf2/npc/entities/chaser/actions/chase.sp index 75999961..9bbefa83 100644 --- a/addons/sourcemod/scripting/sf2/npc/entities/chaser/actions/chase.sp +++ b/addons/sourcemod/scripting/sf2/npc/entities/chaser/actions/chase.sp @@ -39,7 +39,7 @@ static int OnStart(SF2_ChaserChaseAction action, SF2_ChaserEntity actor, NextBot return action.ChangeTo(SF2_ChaserIdleAction(), "My target is no longer valid!"); } - ChaserBossProfile data = controller.GetProfileDataEx(); + ChaserBossProfile data = controller.GetProfileData(); ChaserBossProfileChaseData chaseData = data.GetChaseBehavior(); actor.CurrentChaseDuration = chaseData.GetMaxChaseDuration(difficulty); @@ -68,7 +68,7 @@ static int Update(SF2_ChaserChaseAction action, SF2_ChaserEntity actor) return action.Continue(); } - ChaserBossProfile data = controller.GetProfileDataEx(); + ChaserBossProfile data = controller.GetProfileData(); ChaserBossProfileAlertData alertData = data.GetAlertBehavior(); ChaserBossProfileChaseData chaseData = data.GetChaseBehavior(); @@ -177,7 +177,7 @@ static void OnResume(SF2_ChaserChaseAction action, SF2_ChaserEntity actor) SF2NPC_Chaser controller = actor.Controller; if (controller.IsValid()) { - if (controller.GetProfileDataEx().GetStunBehavior().CanChaseInitialOnEnd(controller.Difficulty)) + if (controller.GetProfileData().GetStunBehavior().CanChaseInitialOnEnd(controller.Difficulty)) { actor.PerformVoice(SF2BossSound_ChaseInitial); } @@ -192,7 +192,7 @@ static void OnEnd(SF2_ChaserChaseAction action, SF2_ChaserEntity actor) return; } SF2NPC_Chaser controller = actor.Controller; - ChaserBossProfile data = controller.GetProfileDataEx(); + ChaserBossProfile data = controller.GetProfileData(); actor.EndCloak(); PathFollower path = actor.Controller.Path; float gameTime = GetGameTime(); diff --git a/addons/sourcemod/scripting/sf2/npc/entities/chaser/actions/chaseinitial.sp b/addons/sourcemod/scripting/sf2/npc/entities/chaser/actions/chaseinitial.sp index cd200811..adfc1aa9 100644 --- a/addons/sourcemod/scripting/sf2/npc/entities/chaser/actions/chaseinitial.sp +++ b/addons/sourcemod/scripting/sf2/npc/entities/chaser/actions/chaseinitial.sp @@ -26,7 +26,7 @@ methodmap SF2_ChaserChaseInitialAction < NextBotAction return false; } - ChaserBossProfile data = actor.Controller.GetProfileDataEx(); + ChaserBossProfile data = actor.Controller.GetProfileData(); if (!data.GetAnimations().HasAnimationSection(g_SlenderAnimationsList[SF2BossAnimation_ChaseInitial])) { return false; @@ -39,7 +39,7 @@ methodmap SF2_ChaserChaseInitialAction < NextBotAction static NextBotAction InitialContainedAction(SF2_ChaserChaseInitialAction action, SF2_ChaserEntity actor) { SF2NPC_Chaser controller = actor.Controller; - ChaserBossProfile data = controller.GetProfileDataEx(); + ChaserBossProfile data = controller.GetProfileData(); actor.IsInChaseInitial = true; ProfileAnimation section = data.GetAnimations().GetAnimation(g_SlenderAnimationsList[SF2BossAnimation_ChaseInitial]); diff --git a/addons/sourcemod/scripting/sf2/npc/entities/chaser/actions/chaselayer.sp b/addons/sourcemod/scripting/sf2/npc/entities/chaser/actions/chaselayer.sp index aa872956..b1c1d4f3 100644 --- a/addons/sourcemod/scripting/sf2/npc/entities/chaser/actions/chaselayer.sp +++ b/addons/sourcemod/scripting/sf2/npc/entities/chaser/actions/chaselayer.sp @@ -57,15 +57,16 @@ static int Update(SF2_ChaserChaseLayerAction action, SF2_ChaserEntity actor, flo } else if (target.IsValid()) { - int pathTo = target.index; + float pos[3]; + target.GetAbsOrigin(pos); if (actor.Teleporters.Length > 0) { - pathTo = actor.Teleporters.Get(0); + CBaseEntity(actor.Teleporters.Get(0)).GetAbsOrigin(pos); } if ((interrputConditions & COND_NEWENEMY) != 0 || path.GetAge() > 0.3 || (path.IsValid() && (path.GetLength() - path.GetCursorPosition()) < 256.0)) { - path.ComputeToTarget(bot, pathTo); + path.ComputeToPos(bot, pos); } } @@ -124,7 +125,7 @@ static int OnResume(SF2_ChaserChaseLayerAction action, SF2_ChaserEntity actor, N SF2NPC_Chaser controller = actor.Controller; if (controller.IsValid()) { - if (controller.GetProfileDataEx().GetStunBehavior().CanChaseInitialOnEnd(controller.Difficulty) && SF2_ChaserChaseInitialAction.IsPossible(actor)) + if (controller.GetProfileData().GetStunBehavior().CanChaseInitialOnEnd(controller.Difficulty) && SF2_ChaserChaseInitialAction.IsPossible(actor)) { return action.SuspendFor(SF2_ChaserChaseInitialAction()); } diff --git a/addons/sourcemod/scripting/sf2/npc/entities/chaser/actions/death.sp b/addons/sourcemod/scripting/sf2/npc/entities/chaser/actions/death.sp index 4c6ff7e7..4d8ef81a 100644 --- a/addons/sourcemod/scripting/sf2/npc/entities/chaser/actions/death.sp +++ b/addons/sourcemod/scripting/sf2/npc/entities/chaser/actions/death.sp @@ -29,12 +29,12 @@ methodmap SF2_ChaserDeathAction < NextBotAction { public get() { - return this.GetDataEnt("m_Attacker"); + return EntRefToEntIndex(this.GetDataEnt("m_Attacker")); } public set(int value) { - this.SetDataEnt("m_Attacker", value); + this.SetDataEnt("m_Attacker", EnsureEntRef(value)); } } } @@ -42,7 +42,7 @@ methodmap SF2_ChaserDeathAction < NextBotAction static NextBotAction InitialContainedAction(SF2_ChaserDeathAction action, SF2_ChaserEntity actor) { SF2NPC_Chaser controller = actor.Controller; - ChaserBossProfile data = controller.GetProfileDataEx(); + ChaserBossProfile data = controller.GetProfileData(); INextBot bot = actor.MyNextBotPointer(); ILocomotion loco = bot.GetLocomotionInterface(); @@ -73,7 +73,7 @@ static NextBotAction InitialContainedAction(SF2_ChaserDeathAction action, SF2_Ch static int OnStart(SF2_ChaserDeathAction action, SF2_ChaserEntity actor, NextBotAction priorAction) { SF2NPC_Chaser controller = actor.Controller; - ChaserBossProfile data = controller.GetProfileDataEx(); + ChaserBossProfile data = controller.GetProfileData(); ChaserBossProfileDeathData deathData = data.GetDeathBehavior(); actor.GroundSpeedOverride = true; int difficulty = controller.Difficulty; @@ -83,7 +83,12 @@ static int OnStart(SF2_ChaserDeathAction action, SF2_ChaserEntity actor, NextBot float pos[3], ang[3]; actor.GetAbsOrigin(pos); actor.GetAbsAngles(ang); - SlenderSpawnEffects(deathData.GetOnStartEffects(), controller.Index, false, pos, ang, _, _, true); + SlenderSpawnEffects(deathData.GetOnStartEffects(), controller.Index, false, pos, ang, _, _, false); + } + + if (deathData.GetOnStartInputs() != null) + { + deathData.GetOnStartInputs().AcceptInputs(actor.index, action.Attacker, action.Attacker); } if (deathData.KeyDrop) @@ -141,7 +146,7 @@ static void OnEnd(SF2_ChaserDeathAction action, SF2_ChaserEntity actor) return; } - ChaserBossProfile data = controller.GetProfileDataEx(); + ChaserBossProfile data = controller.GetProfileData(); ChaserBossProfileDeathData deathData = data.GetDeathBehavior(); if (deathData.GetOnEndEffects() != null) @@ -149,9 +154,16 @@ static void OnEnd(SF2_ChaserDeathAction action, SF2_ChaserEntity actor) float pos[3], ang[3]; actor.GetAbsOrigin(pos); actor.GetAbsAngles(ang); - SlenderSpawnEffects(deathData.GetOnEndEffects(), controller.Index, false, pos, ang, _, _, true); + SlenderSpawnEffects(deathData.GetOnEndEffects(), controller.Index, false, pos, ang, _, _, false); } + if (deathData.GetOnEndInputs() != null) + { + deathData.GetOnEndInputs().AcceptInputs(actor.index, action.Attacker, action.Attacker); + } + + data.SetBool("__was_killed", true); + if (deathData.RemoveOnDeath) { SpawnGibs(actor); @@ -248,7 +260,7 @@ static void OnAnimationEvent(SF2_ChaserDeathAction action, SF2_ChaserEntity acto static void SpawnGibs(SF2_ChaserEntity actor) { SF2NPC_Chaser controller = actor.Controller; - ChaserBossProfile data = controller.GetProfileDataEx(); + ChaserBossProfile data = controller.GetProfileData(); ChaserBossProfileDeathData deathData = data.GetDeathBehavior(); if (deathData.GetGibs() == null) { diff --git a/addons/sourcemod/scripting/sf2/npc/entities/chaser/actions/flee_to_heal.sp b/addons/sourcemod/scripting/sf2/npc/entities/chaser/actions/flee_to_heal.sp index 11caa21c..fbf072c0 100644 --- a/addons/sourcemod/scripting/sf2/npc/entities/chaser/actions/flee_to_heal.sp +++ b/addons/sourcemod/scripting/sf2/npc/entities/chaser/actions/flee_to_heal.sp @@ -136,7 +136,7 @@ methodmap SF2_ChaserFleeToHealAction < NextBotAction static NextBotAction InitialContainedAction(SF2_ChaserFleeToHealAction action, SF2_ChaserEntity actor) { SF2NPC_Chaser controller = actor.Controller; - ChaserBossProfile data = controller.GetProfileDataEx(); + ChaserBossProfile data = controller.GetProfileData(); char name[64]; data.GetRages().GetSectionNameFromIndex(actor.RageIndex, name, sizeof(name)); ChaserBossProfileRageData rageData = view_as(data.GetRages().GetSection(name)); @@ -175,7 +175,7 @@ static int Update(SF2_ChaserFleeToHealAction action, SF2_ChaserEntity actor, flo INextBot bot = actor.MyNextBotPointer(); ILocomotion loco = bot.GetLocomotionInterface(); SF2NPC_Chaser controller = actor.Controller; - ChaserBossProfile data = controller.GetProfileDataEx(); + ChaserBossProfile data = controller.GetProfileData(); char name[64]; data.GetRages().GetSectionNameFromIndex(actor.RageIndex, name, sizeof(name)); ChaserBossProfileRageData rageData = view_as(data.GetRages().GetSection(name)); diff --git a/addons/sourcemod/scripting/sf2/npc/entities/chaser/actions/idle.sp b/addons/sourcemod/scripting/sf2/npc/entities/chaser/actions/idle.sp index 95ef612f..35950e80 100644 --- a/addons/sourcemod/scripting/sf2/npc/entities/chaser/actions/idle.sp +++ b/addons/sourcemod/scripting/sf2/npc/entities/chaser/actions/idle.sp @@ -76,7 +76,7 @@ static int OnStart(SF2_ChaserIdleAction action, SF2_ChaserEntity actor, NextBotA { INextBot bot = actor.MyNextBotPointer(); SF2NPC_Chaser controller = actor.Controller; - ChaserBossProfile data = controller.GetProfileDataEx(); + ChaserBossProfile data = controller.GetProfileData(); ChaserBossProfileIdleData idleData = data.GetIdleBehavior(); ChaserBossProfileSmellData smellData = data.GetSmellData(); int difficulty = controller.Difficulty; @@ -125,7 +125,7 @@ static int Update(SF2_ChaserIdleAction action, SF2_ChaserEntity actor, float int return action.Continue(); } - ChaserBossProfile data = controller.GetProfileDataEx(); + ChaserBossProfile data = controller.GetProfileData(); ChaserBossProfileIdleData idleData = data.GetIdleBehavior(); ChaserBossProfileAlertData alertData = data.GetAlertBehavior(); ChaserBossProfileSmellData smellData = data.GetSmellData(); diff --git a/addons/sourcemod/scripting/sf2/npc/entities/chaser/actions/mainlayer.sp b/addons/sourcemod/scripting/sf2/npc/entities/chaser/actions/mainlayer.sp index 400b508c..987e365e 100644 --- a/addons/sourcemod/scripting/sf2/npc/entities/chaser/actions/mainlayer.sp +++ b/addons/sourcemod/scripting/sf2/npc/entities/chaser/actions/mainlayer.sp @@ -113,7 +113,7 @@ static int Update(SF2_ChaserMainAction action, SF2_ChaserEntity actor) actor.DoAttackMiscConditions(actor.GetAttackName()); } - ChaserBossProfile data = controller.GetProfileDataEx(); + ChaserBossProfile data = controller.GetProfileData(); ChaserBossProfileStunData stunData = data.GetStunBehavior(); if (stunData != null && stunData.CanFlashlightStun(difficulty) && actor.CanBeStunned() && actor.CanTakeDamage() && actor.FlashlightTick < gameTime && !IsNightVisionEnabled()) @@ -220,7 +220,7 @@ static int Update(SF2_ChaserMainAction action, SF2_ChaserEntity actor) } } - if (data.InstantKillRadius > 0.0) + if (data.GetInstantKillRadius(difficulty) > 0.0) { if (gameTime >= actor.LastKillTime && !actor.IsKillingSomeone) { @@ -228,7 +228,7 @@ static int Update(SF2_ChaserMainAction action, SF2_ChaserEntity actor) actor.WorldSpaceCenter(worldSpace); actor.GetAbsOrigin(myPos); bool attackEliminated = (controller.Flags & SFF_ATTACKWAITERS) != 0; - if (controller.GetProfileDataEx().IsPvEBoss) + if (controller.GetProfileData().IsPvEBoss) { attackEliminated = true; } @@ -245,7 +245,7 @@ static int Update(SF2_ChaserMainAction action, SF2_ChaserEntity actor) continue; } - if (actor.MyNextBotPointer().GetRangeSquaredTo(client.index) > Pow(data.InstantKillRadius, 2.0) || + if (actor.MyNextBotPointer().GetRangeSquaredTo(client.index) > Pow(data.GetInstantKillRadius(difficulty), 2.0) || !client.CanSeeSlender(controller.Index, false, _, !attackEliminated)) { continue; @@ -387,7 +387,7 @@ static int OnInjured(SF2_ChaserMainAction action, SF2_ChaserEntity actor, CBaseE } SF2NPC_Chaser controller = actor.Controller; - ChaserBossProfile data = controller.GetProfileDataEx(); + ChaserBossProfile data = controller.GetProfileData(); int search = actor.RageIndex + 1; if ((data.BoxingBoss || data.IsPvEBoss) && actor.CanTakeDamage(attacker, inflictor, damage) && data.GetRages() != null && search < data.GetRages().Size && !actor.IsRaging) @@ -545,9 +545,9 @@ static int OnCommandString(SF2_ChaserMainAction action, SF2_ChaserEntity actor, char attack[128]; strcopy(attack, sizeof(attack), command); ReplaceString(attack, sizeof(attack), "debug attack ", ""); - ChaserBossProfile data = controller.GetProfileDataEx(); + ChaserBossProfile data = controller.GetProfileData(); ChaserBossProfileBaseAttack attackData = data.GetAttack(attack); - return action.TrySuspendFor(SF2_ChaserAttackAction(data, attack, data.IndexOfSection(attackData), attackData.GetDuration(difficulty) + GetGameTime()), RESULT_IMPORTANT); + return action.TrySuspendFor(SF2_ChaserAttackAction(data, attack, data.IndexOfSection(attackData), attackData.GetDuration(difficulty)), RESULT_IMPORTANT); } if (strcmp(command, "suspend for action") == 0) diff --git a/addons/sourcemod/scripting/sf2/npc/entities/chaser/actions/rage.sp b/addons/sourcemod/scripting/sf2/npc/entities/chaser/actions/rage.sp index 88c797d8..275701da 100644 --- a/addons/sourcemod/scripting/sf2/npc/entities/chaser/actions/rage.sp +++ b/addons/sourcemod/scripting/sf2/npc/entities/chaser/actions/rage.sp @@ -52,7 +52,7 @@ static NextBotAction InitialContainedAction(SF2_ChaserRageAction action, SF2_Cha { actor.RageIndex++; SF2NPC_Chaser controller = actor.Controller; - ChaserBossProfile data = controller.GetProfileDataEx(); + ChaserBossProfile data = controller.GetProfileData(); char name[64]; data.GetRages().GetSectionNameFromIndex(actor.RageIndex, name, sizeof(name)); ChaserBossProfileRageData rageData = view_as(data.GetRages().GetSection(name)); @@ -130,7 +130,7 @@ static void OnEnd(SF2_ChaserRageAction action, SF2_ChaserEntity actor) actor.IsGoingToHeal = false; if (actor.Controller.IsValid()) { - ChaserBossProfile data = actor.Controller.GetProfileDataEx(); + ChaserBossProfile data = actor.Controller.GetProfileData(); char name[64]; data.GetRages().GetSectionNameFromIndex(actor.RageIndex, name, sizeof(name)); ChaserBossProfileRageData rageData = view_as(data.GetRages().GetSection(name)); diff --git a/addons/sourcemod/scripting/sf2/npc/entities/chaser/actions/smell.sp b/addons/sourcemod/scripting/sf2/npc/entities/chaser/actions/smell.sp index 6c6c46a2..32e37137 100644 --- a/addons/sourcemod/scripting/sf2/npc/entities/chaser/actions/smell.sp +++ b/addons/sourcemod/scripting/sf2/npc/entities/chaser/actions/smell.sp @@ -21,7 +21,7 @@ methodmap SF2_ChaserSmellAction < NextBotAction public static bool IsPossible(SF2_ChaserEntity actor) { - ChaserBossProfile data = actor.Controller.GetProfileDataEx(); + ChaserBossProfile data = actor.Controller.GetProfileData(); if (!data.GetAnimations().HasAnimationSection(g_SlenderAnimationsList[SF2BossAnimation_Smell])) { return false; @@ -58,7 +58,7 @@ static int Update(SF2_ChaserSmellAction action, SF2_ChaserEntity actor, NextBotA { SF2NPC_Chaser controller = actor.Controller; int difficulty = controller.Difficulty; - ChaserBossProfile data = controller.GetProfileDataEx(); + ChaserBossProfile data = controller.GetProfileData(); ChaserBossProfileSmellData smellData = data.GetSmellData(); ChaserBossProfileAlertData alertData = data.GetAlertBehavior(); PathFollower path = controller.Path; diff --git a/addons/sourcemod/scripting/sf2/npc/entities/chaser/actions/stun.sp b/addons/sourcemod/scripting/sf2/npc/entities/chaser/actions/stun.sp index c772d02d..ccdcbdfe 100644 --- a/addons/sourcemod/scripting/sf2/npc/entities/chaser/actions/stun.sp +++ b/addons/sourcemod/scripting/sf2/npc/entities/chaser/actions/stun.sp @@ -76,7 +76,7 @@ static NextBotAction InitialContainedAction(SF2_ChaserStunnedAction action, SF2_ char posture[64]; actor.GetPosture(posture, sizeof(posture)); - ChaserBossProfile data = actor.Controller.GetProfileDataEx(); + ChaserBossProfile data = actor.Controller.GetProfileData(); if (data.GetAnimations().HasAnimationSection(g_SlenderAnimationsList[SF2BossAnimation_Stun])) { return SF2_PlaySequenceAndWaitEx(g_SlenderAnimationsList[SF2BossAnimation_Stun]); @@ -88,7 +88,7 @@ static NextBotAction InitialContainedAction(SF2_ChaserStunnedAction action, SF2_ static int OnStart(SF2_ChaserStunnedAction action, SF2_ChaserEntity actor, NextBotAction priorAction) { SF2NPC_Chaser controller = actor.Controller; - ChaserBossProfile data = controller.GetProfileDataEx(); + ChaserBossProfile data = controller.GetProfileData(); ChaserBossProfileChaseData chaseData = data.GetChaseBehavior(); ChaserBossProfileStunData stunData = data.GetStunBehavior(); int difficulty = controller.Difficulty; @@ -98,7 +98,12 @@ static int OnStart(SF2_ChaserStunnedAction action, SF2_ChaserEntity actor, NextB float pos[3], ang[3]; actor.GetAbsOrigin(pos); actor.GetAbsAngles(ang); - SlenderSpawnEffects(stunData.GetOnStartEffects(), controller.Index, false, pos, ang, _, _, true); + SlenderSpawnEffects(stunData.GetOnStartEffects(), controller.Index, false, pos, ang, _, _, false); + } + + if (stunData.GetOnStartInputs() != null) + { + stunData.GetOnStartInputs().AcceptInputs(actor.index, action.Attacker.index, action.Attacker.index); } if (stunData.KeyDrop) @@ -181,7 +186,7 @@ static int Update(SF2_ChaserStunnedAction action, SF2_ChaserEntity actor, float return action.Continue(); } - if (actor.Controller.GetProfileDataEx().GetStunBehavior().ShouldDisappear(actor.Controller.Difficulty)) + if (actor.Controller.GetProfileData().GetStunBehavior().ShouldDisappear(actor.Controller.Difficulty)) { actor.Controller.UnSpawn(true); } @@ -202,7 +207,7 @@ static void OnEnd(SF2_ChaserStunnedAction action, SF2_ChaserEntity actor) return; } - ChaserBossProfile data = controller.GetProfileDataEx(); + ChaserBossProfile data = controller.GetProfileData(); ChaserBossProfileStunData stunData = data.GetStunBehavior(); if (stunData.GetOnEndEffects() != null) @@ -210,7 +215,12 @@ static void OnEnd(SF2_ChaserStunnedAction action, SF2_ChaserEntity actor) float pos[3], ang[3]; actor.GetAbsOrigin(pos); actor.GetAbsAngles(ang); - SlenderSpawnEffects(stunData.GetOnEndEffects(), controller.Index, false, pos, ang, _, _, true); + SlenderSpawnEffects(stunData.GetOnEndEffects(), controller.Index, false, pos, ang, _, _, false); + } + + if (stunData.GetOnEndInputs() != null) + { + stunData.GetOnEndInputs().AcceptInputs(actor.index, action.Attacker.index, action.Attacker.index); } actor.IsStunned = false; diff --git a/addons/sourcemod/scripting/sf2/npc/entities/chaser/actions/tauntkill.sp b/addons/sourcemod/scripting/sf2/npc/entities/chaser/actions/tauntkill.sp index 8b58319b..bfd32b61 100644 --- a/addons/sourcemod/scripting/sf2/npc/entities/chaser/actions/tauntkill.sp +++ b/addons/sourcemod/scripting/sf2/npc/entities/chaser/actions/tauntkill.sp @@ -18,7 +18,7 @@ methodmap SF2_ChaserTauntKillAction < NextBotAction public static bool IsPossible(SF2_ChaserEntity actor) { - ChaserBossProfile data = actor.Controller.GetProfileDataEx(); + ChaserBossProfile data = actor.Controller.GetProfileData(); if (!data.GetAnimations().HasAnimationSection(g_SlenderAnimationsList[SF2BossAnimation_TauntKill])) { return false; @@ -45,7 +45,7 @@ static int OnStart(SF2_ChaserTauntKillAction action, SF2_ChaserEntity actor, Nex SF2NPC_Chaser controller = actor.Controller; if (controller.IsValid()) { - ChaserBossProfile data = controller.GetProfileDataEx(); + ChaserBossProfile data = controller.GetProfileData(); if (data.NormalSoundHook) { actor.NextVoiceTime = 0.0; @@ -60,7 +60,7 @@ static int OnResume(SF2_ChaserTauntKillAction action, SF2_ChaserEntity actor, Ne SF2NPC_Chaser controller = actor.Controller; if (controller.IsValid()) { - ChaserBossProfile data = controller.GetProfileDataEx(); + ChaserBossProfile data = controller.GetProfileData(); if (data.NormalSoundHook) { actor.NextVoiceTime = 0.0; diff --git a/addons/sourcemod/scripting/sf2/npc/entities/chaser/entity.sp b/addons/sourcemod/scripting/sf2/npc/entities/chaser/entity.sp index e0fadd6d..acdc3603 100644 --- a/addons/sourcemod/scripting/sf2/npc/entities/chaser/entity.sp +++ b/addons/sourcemod/scripting/sf2/npc/entities/chaser/entity.sp @@ -83,6 +83,7 @@ methodmap SF2_ChaserEntity < SF2_BaseBoss .DefineFloatField("m_AlertSoundTriggerCooldown", MAXTF2PLAYERS) .DefineVectorField("m_AlertTriggerPositionEx") .DefineFloatField("m_AlertChangePositionCooldown") + .DefineIntField("m_TauntAlertStrikes", MAXTF2PLAYERS) .DefineIntField("m_AutoChaseCount", MAXTF2PLAYERS) .DefineFloatField("m_AutoChaseAddCooldown", MAXTF2PLAYERS) .DefineFloatField("m_AutoChaseCooldown", MAXTF2PLAYERS) @@ -122,7 +123,7 @@ methodmap SF2_ChaserEntity < SF2_BaseBoss g_OnEntityCreatedPFwd.AddFunction(null, EntityCreated); g_OnPlayerSpawnPFwd.AddFunction(null, OnPlayerSpawn); - g_OnPlayerTakeDamagePFwd.AddFunction(null, OnPlayerTakeDamage); + g_OnPlayerTakeDamagePostPFwd.AddFunction(null, OnPlayerTakeDamagePost); g_OnPlayerDeathPrePFwd.AddFunction(null, OnPlayerDeathPre); g_OnPlayerDeathPFwd.AddFunction(null, OnPlayerDeath); @@ -178,7 +179,7 @@ methodmap SF2_ChaserEntity < SF2_BaseBoss public bool CanBeStunned() { - if (SF_IsSlaughterRunMap() && !this.Controller.GetProfileDataEx().IsPvEBoss) + if (SF_IsSlaughterRunMap() && !this.Controller.GetProfileData().IsPvEBoss) { return false; } @@ -188,7 +189,7 @@ methodmap SF2_ChaserEntity < SF2_BaseBoss return false; } - if (!this.Controller.GetProfileDataEx().GetStunBehavior().IsEnabled(this.Controller.Difficulty)) + if (!this.Controller.GetProfileData().GetStunBehavior().IsEnabled(this.Controller.Difficulty)) { return false; } @@ -223,7 +224,7 @@ methodmap SF2_ChaserEntity < SF2_BaseBoss public bool CanTakeDamage(CBaseEntity attacker = view_as(-1), CBaseEntity inflictor = view_as(-1), float damage = 0.0) { - if (SF_IsSlaughterRunMap() && !this.Controller.GetProfileDataEx().IsPvEBoss) + if (SF_IsSlaughterRunMap() && !this.Controller.GetProfileData().IsPvEBoss) { return false; } @@ -255,7 +256,7 @@ methodmap SF2_ChaserEntity < SF2_BaseBoss int difficulty = this.Controller.Difficulty; - return !this.Controller.GetProfileDataEx().GetAttack(this.GetAttackName()).IsImmuneToDamage(difficulty); + return !this.Controller.GetProfileData().GetAttack(this.GetAttackName()).IsImmuneToDamage(difficulty); } property bool IsStunned @@ -391,7 +392,7 @@ methodmap SF2_ChaserEntity < SF2_BaseBoss return; } - ChaserBossProfile data = this.Controller.GetProfileDataEx(); + ChaserBossProfile data = this.Controller.GetProfileData(); if (data.GetPosture(posture) == null) { @@ -406,7 +407,7 @@ methodmap SF2_ChaserEntity < SF2_BaseBoss if (this.Controller.IsValid() && strcmp(currentPosture, posture) != 0 && update) { - this.UpdateMovementAnimation(); + this.SetPosture(posture); } } @@ -686,6 +687,16 @@ methodmap SF2_ChaserEntity < SF2_BaseBoss } } + public int GetTauntAlertStrikes(SF2_BasePlayer player) + { + return this.GetProp(Prop_Data, "m_TauntAlertStrikes", _, player.index); + } + + public void SetTauntAlertStrikes(SF2_BasePlayer player, int value) + { + this.SetProp(Prop_Data, "m_TauntAlertStrikes", value, _, player.index); + } + public int GetAutoChaseCount(SF2_BasePlayer player) { return this.GetProp(Prop_Data, "m_AutoChaseCount", _, player.index); @@ -1130,7 +1141,7 @@ methodmap SF2_ChaserEntity < SF2_BaseBoss int difficulty = controller.Difficulty; float myPos[3]; this.GetAbsOrigin(myPos); - ChaserBossProfile data = controller.GetProfileDataEx(); + ChaserBossProfile data = controller.GetProfileData(); SF2_BasePlayer closest = SF2_INVALID_PLAYER; float range = Pow(data.GetSearchRange(difficulty), 2.0); @@ -1220,7 +1231,7 @@ methodmap SF2_ChaserEntity < SF2_BaseBoss return false; } - ChaserBossProfile data = this.Controller.GetProfileDataEx(); + ChaserBossProfile data = this.Controller.GetProfileData(); KeyMap_Array soundList; if (!isSet) { @@ -1343,7 +1354,7 @@ methodmap SF2_ChaserEntity < SF2_BaseBoss public void CastAnimEvent(int event, bool footstep = false) { - ChaserBossProfile data = this.Controller.GetProfileDataEx(); + ChaserBossProfile data = this.Controller.GetProfileData(); ProfileSound soundInfo = data.GetEventSounds(event); @@ -1376,7 +1387,7 @@ methodmap SF2_ChaserEntity < SF2_BaseBoss { return; } - ChaserBossProfile data = controller.GetProfileDataEx(); + ChaserBossProfile data = controller.GetProfileData(); ProfileSound info = data.GetFootstepSounds(); info.EmitSound(_, this.index); @@ -1396,7 +1407,7 @@ methodmap SF2_ChaserEntity < SF2_BaseBoss } int difficulty = this.Controller.Difficulty; - int threshold = this.Controller.GetProfileDataEx().GetSoundSenseData().GetThreshold(difficulty); + int threshold = this.Controller.GetProfileData().GetSoundSenseData().GetThreshold(difficulty); if (threshold <= 0) { @@ -1459,7 +1470,7 @@ methodmap SF2_ChaserEntity < SF2_BaseBoss } int difficulty = this.Controller.Difficulty; - ChaserBossProfile data = this.Controller.GetProfileDataEx(); + ChaserBossProfile data = this.Controller.GetProfileData(); if (data.GetAutoChaseData().GetThreshold(difficulty) <= 0) { @@ -1490,7 +1501,7 @@ methodmap SF2_ChaserEntity < SF2_BaseBoss canAttack = false; } - ChaserBossProfile data = controller.GetProfileDataEx(); + ChaserBossProfile data = controller.GetProfileData(); ProfileObject attacks = data.GetSection("attacks"); if (attacks == null || attacks.Size == 0) { @@ -1637,7 +1648,7 @@ methodmap SF2_ChaserEntity < SF2_BaseBoss attackData.GetSectionName(attackName, sizeof(attackName)); - return SF2_ChaserAttackAction(data, attackName, attackData.Index, attackData.GetDuration(difficulty) + gameTime); + return SF2_ChaserAttackAction(data, attackName, attackData.Index, attackData.GetDuration(difficulty)); } delete arrayAttacks; @@ -1648,7 +1659,7 @@ methodmap SF2_ChaserEntity < SF2_BaseBoss { NextBotAction nbAction = NULL_ACTION; Action action = Plugin_Continue; - ChaserBossProfileBaseAttack attackData = this.Controller.GetProfileDataEx().GetAttack(attackName); + ChaserBossProfileBaseAttack attackData = this.Controller.GetProfileData().GetAttack(attackName); Call_StartForward(g_OnBossGetCustomAttackActionFwd); Call_PushCell(this); @@ -1669,7 +1680,7 @@ methodmap SF2_ChaserEntity < SF2_BaseBoss public bool IsCustomAttackPossible(const char[] attackName, CBaseEntity target) { Action action = Plugin_Continue; - ChaserBossProfileBaseAttack attackData = this.Controller.GetProfileDataEx().GetAttack(attackName); + ChaserBossProfileBaseAttack attackData = this.Controller.GetProfileData().GetAttack(attackName); Call_StartForward(g_OnIsBossCustomAttackPossibleFwd); Call_PushCell(this); @@ -1681,10 +1692,10 @@ methodmap SF2_ChaserEntity < SF2_BaseBoss return action == Plugin_Continue; } - public NextBotAction IsAttackTransitionPossible(const char[] attackName, bool end = false, float& duration = 0.0) + public NextBotAction IsAttackTransitionPossible(const char[] attackName, bool end = false) { SF2NPC_Chaser controller = this.Controller; - ChaserBossProfile data = controller.GetProfileDataEx(); + ChaserBossProfile data = controller.GetProfileData(); char section[32]; if (!end) { @@ -1705,7 +1716,7 @@ methodmap SF2_ChaserEntity < SF2_BaseBoss return NULL_ACTION; } - return SF2_PlaySequenceAndWaitEx(section); + return SF2_PlaySequenceAndWaitEx(section, attackName); } public void DoAttackMiscConditions(const char[] attackName) @@ -1717,7 +1728,7 @@ methodmap SF2_ChaserEntity < SF2_BaseBoss { return; } - ChaserBossProfileBaseAttack attackData = controller.GetProfileDataEx().GetAttack(attackName); + ChaserBossProfileBaseAttack attackData = controller.GetProfileData().GetAttack(attackName); CBaseEntity target = this.Target; int difficulty = controller.Difficulty; @@ -1770,7 +1781,7 @@ methodmap SF2_ChaserEntity < SF2_BaseBoss return; } - ChaserBossProfile data = controller.GetProfileDataEx(); + ChaserBossProfile data = controller.GetProfileData(); ChaserBossProfileBaseAttack attackData = data.GetAttack(attackName); BossProfileShockwave shockwaveData = attackData.GetShockwave(); @@ -1871,7 +1882,7 @@ methodmap SF2_ChaserEntity < SF2_BaseBoss { return false; } - ChaserBossProfile data = this.Controller.GetProfileDataEx(); + ChaserBossProfile data = this.Controller.GetProfileData(); char arrayName[64]; FormatEx(arrayName, sizeof(arrayName), "__chaser_%s_sounds", section); KeyMap_Array array = data.GetArray(arrayName); @@ -1904,7 +1915,7 @@ methodmap SF2_ChaserEntity < SF2_BaseBoss { return; } - ChaserBossProfile data = controller.GetProfileDataEx(); + ChaserBossProfile data = controller.GetProfileData(); ChaserBossProjectileData projectileData = data.GetProjectiles(); int difficulty = controller.Difficulty; if (!projectileData.IsEnabled(difficulty)) @@ -1969,7 +1980,7 @@ methodmap SF2_ChaserEntity < SF2_BaseBoss this.GetAbsAngles(myAng); this.Target.WorldSpaceCenter(targetPos); int difficulty = controller.Difficulty; - ChaserBossProfile data = controller.GetProfileDataEx(); + ChaserBossProfile data = controller.GetProfileData(); ChaserBossProjectileData projectileData = data.GetProjectiles(); int randomPosMin = projectileData.MinRandomPos; int randomPosMax = projectileData.MaxRandomPos; @@ -1997,11 +2008,11 @@ methodmap SF2_ChaserEntity < SF2_BaseBoss { float direction[3], angle[3]; SubtractVectors(targetPos, effectPos, direction); - float deviation = projectileData.GetDeviation(difficulty); + float deviation = projectileData.GetDeviation(difficulty) / 10.0; NormalizeVector(direction, direction); GetVectorAngles(direction, angle); - if (deviation != 0) + if (deviation != 0.0) { angle[0] += GetRandomFloat(-deviation, deviation); angle[1] += GetRandomFloat(-deviation, deviation); @@ -2141,7 +2152,7 @@ methodmap SF2_ChaserEntity < SF2_BaseBoss SF2NPC_BaseNPC copyMaster = controller.CopyMaster; SF2NPC_BaseNPC companionMaster = controller.CompanionMaster; ChaserBossProfile data, otherData; - data = controller.GetProfileDataEx(); + data = controller.GetProfileData(); ChaserBossAlertOnStateData alertStateData, otherAlertStateData; if (data.GetAlertBehavior() == null) { @@ -2177,12 +2188,12 @@ methodmap SF2_ChaserEntity < SF2_BaseBoss } SF2NPC_BaseNPC otherController = SF2NPC_BaseNPC(index); - if (!otherController.IsValid() || otherController.GetProfileDataEx().Type != SF2BossType_Chaser || otherController.EntIndex == INVALID_ENT_REFERENCE) + if (!otherController.IsValid() || otherController.GetProfileData().Type != SF2BossType_Chaser || otherController.EntIndex == INVALID_ENT_REFERENCE) { continue; } - otherData = view_as(otherController).GetProfileDataEx(); + otherData = view_as(otherController).GetProfileData(); if (otherData.GetAlertBehavior() == null) { continue; @@ -2285,7 +2296,7 @@ methodmap SF2_ChaserEntity < SF2_BaseBoss SF2NPC_BaseNPC copyMaster = controller.CopyMaster; SF2NPC_BaseNPC companionMaster = controller.CompanionMaster; ChaserBossProfile data, otherData; - data = controller.GetProfileDataEx(); + data = controller.GetProfileData(); ChaserBossAlertOnStateData alertStateData, otherAlertStateData; if (data.GetAlertBehavior() == null) { @@ -2322,7 +2333,7 @@ methodmap SF2_ChaserEntity < SF2_BaseBoss } SF2NPC_BaseNPC otherController = SF2NPC_BaseNPC(index); - if (!otherController.IsValid() || otherController.GetProfileDataEx().Type != SF2BossType_Chaser || otherController.EntIndex == INVALID_ENT_REFERENCE) + if (!otherController.IsValid() || otherController.GetProfileData().Type != SF2BossType_Chaser || otherController.EntIndex == INVALID_ENT_REFERENCE) { continue; } @@ -2333,7 +2344,7 @@ methodmap SF2_ChaserEntity < SF2_BaseBoss continue; } - otherData = view_as(otherController).GetProfileDataEx(); + otherData = view_as(otherController).GetProfileData(); if (otherData.GetAlertBehavior() == null) { continue; @@ -2448,7 +2459,7 @@ methodmap SF2_ChaserEntity < SF2_BaseBoss SF2NPC_BaseNPC copyMaster = controller.CopyMaster; SF2NPC_BaseNPC companionMaster = controller.CompanionMaster; ChaserBossProfile data, otherData; - data = controller.GetProfileDataEx(); + data = controller.GetProfileData(); ChaserBossAlertOnStateData alertStateData, otherAlertStateData; if (data.GetChaseBehavior() == null) { @@ -2474,12 +2485,12 @@ methodmap SF2_ChaserEntity < SF2_BaseBoss } SF2NPC_BaseNPC otherController = SF2NPC_BaseNPC(index); - if (!otherController.IsValid() || otherController.GetProfileDataEx().Type != SF2BossType_Chaser || otherController.EntIndex == INVALID_ENT_REFERENCE) + if (!otherController.IsValid() || otherController.GetProfileData().Type != SF2BossType_Chaser || otherController.EntIndex == INVALID_ENT_REFERENCE) { continue; } - otherData = view_as(otherController).GetProfileDataEx(); + otherData = view_as(otherController).GetProfileData(); if (otherData.GetChaseBehavior() == null) { continue; @@ -2585,7 +2596,7 @@ methodmap SF2_ChaserEntity < SF2_BaseBoss SF2NPC_BaseNPC copyMaster = controller.CopyMaster; SF2NPC_BaseNPC companionMaster = controller.CompanionMaster; ChaserBossProfile data, otherData; - data = controller.GetProfileDataEx(); + data = controller.GetProfileData(); ChaserBossAlertOnStateData alertStateData, otherAlertStateData; if (data.GetChaseBehavior() == null) { @@ -2622,7 +2633,7 @@ methodmap SF2_ChaserEntity < SF2_BaseBoss } SF2NPC_BaseNPC otherController = SF2NPC_BaseNPC(index); - if (!otherController.IsValid() || otherController.GetProfileDataEx().Type != SF2BossType_Chaser || otherController.EntIndex == INVALID_ENT_REFERENCE) + if (!otherController.IsValid() || otherController.GetProfileData().Type != SF2BossType_Chaser || otherController.EntIndex == INVALID_ENT_REFERENCE) { continue; } @@ -2633,7 +2644,7 @@ methodmap SF2_ChaserEntity < SF2_BaseBoss continue; } - otherData = view_as(otherController).GetProfileDataEx(); + otherData = view_as(otherController).GetProfileData(); if (otherData.GetChaseBehavior() == null) { continue; @@ -2733,7 +2744,7 @@ methodmap SF2_ChaserEntity < SF2_BaseBoss { return; } - ChaserBossProfile data = controller.GetProfileDataEx(); + ChaserBossProfile data = controller.GetProfileData(); ChaserBossProfileCloakData cloakData = data.GetCloakData(); int difficulty = controller.Difficulty; float gameTime = GetGameTime(); @@ -2792,7 +2803,7 @@ methodmap SF2_ChaserEntity < SF2_BaseBoss } SF2NPC_Chaser controller = this.Controller; - ChaserBossProfile data = controller.GetProfileDataEx(); + ChaserBossProfile data = controller.GetProfileData(); ChaserBossProfileCloakData cloakData = data.GetCloakData(); int difficulty = controller.Difficulty; if (!cloakData.IsEnabled(difficulty)) @@ -2826,7 +2837,7 @@ methodmap SF2_ChaserEntity < SF2_BaseBoss return; } SF2NPC_Chaser controller = this.Controller; - ChaserBossProfile data = controller.GetProfileDataEx(); + ChaserBossProfile data = controller.GetProfileData(); ChaserBossProfileCloakData cloakData = data.GetCloakData(); int difficulty = controller.Difficulty; if (!cloakData.IsEnabled(difficulty)) @@ -2856,7 +2867,7 @@ methodmap SF2_ChaserEntity < SF2_BaseBoss public void DropItem(bool death = false) { SF2NPC_Chaser controller = this.Controller; - ChaserBossProfile data = controller.GetProfileDataEx(); + ChaserBossProfile data = controller.GetProfileData(); ChaserBossProfileStunData stunData = data.GetStunBehavior(); ChaserBossProfileDeathData deathData = data.GetDeathBehavior(); int difficulty = controller.Difficulty; @@ -2910,6 +2921,9 @@ methodmap SF2_ChaserEntity < SF2_BaseBoss this.GetAbsOrigin(myPos); CBaseEntity item = CBaseEntity(CreateEntityByName(class)); item.KeyValue("OnPlayerTouch", "!self,Kill,,0,-1"); + SetVariantString("OnUser1 !self:Kill::60.0:1"); + item.AcceptInput("AddOutput"); + item.AcceptInput("FireUser1"); item.Spawn(); item.SetProp(Prop_Send, "m_iTeamNum", 0); item.Teleport(myPos, NULL_VECTOR, NULL_VECTOR); @@ -2918,7 +2932,7 @@ methodmap SF2_ChaserEntity < SF2_BaseBoss public void ProcessTraps() { SF2NPC_Chaser controller = this.Controller; - ChaserBossProfile data = controller.GetProfileDataEx(); + ChaserBossProfile data = controller.GetProfileData(); int difficulty = controller.Difficulty; if (!data.HasTraps(difficulty)) { @@ -2959,7 +2973,7 @@ methodmap SF2_ChaserEntity < SF2_BaseBoss controller.GetProfile(profile, sizeof(profile)); chaser.Controller = view_as(controller); - ChaserBossProfile data = chaser.Controller.GetProfileDataEx(); + ChaserBossProfile data = chaser.Controller.GetProfileData(); ChaserBossProfileStunData stunData = data.GetStunBehavior(); char buffer[PLATFORM_MAX_PATH]; @@ -3195,18 +3209,18 @@ static void OnPlayerSpawn(SF2_BasePlayer client) } } -static Action OnPlayerTakeDamage(SF2_BasePlayer client, int &attacker, int &inflictor, float &damage, int &damageType, int damageCustom) +static void OnPlayerTakeDamagePost(SF2_BasePlayer client, int attacker, int inflictor, float damage, int damageType) { SF2_ChaserEntity boss = SF2_ChaserEntity(inflictor); if (!boss.IsValid()) { - return Plugin_Continue; + return; } SF2NPC_Chaser controller = boss.Controller; if (!controller.IsValid()) { - return Plugin_Continue; + return; } Call_StartForward(g_OnClientDamagedByBossFwd); @@ -3217,7 +3231,7 @@ static Action OnPlayerTakeDamage(SF2_BasePlayer client, int &attacker, int &infl Call_PushCell(damageType); Call_Finish(); - ChaserBossProfile data = controller.GetProfileDataEx(); + ChaserBossProfile data = controller.GetProfileData(); char attack[64]; strcopy(attack, sizeof(attack), boss.GetAttackName()); @@ -3229,9 +3243,12 @@ static Action OnPlayerTakeDamage(SF2_BasePlayer client, int &attacker, int &infl { SlenderSpawnEffects(attackData.GetHitEffects(), controller.Index, false, _, _, _, client.index); } - } - return Plugin_Continue; + if (attackData.GetHitInputs() != null) + { + attackData.GetHitInputs().AcceptInputs(boss.index, client.index, client.index); + } + } } static void OnPlayerDeathPre(SF2_BasePlayer client, int attacker, int inflictor, bool fake) @@ -3279,7 +3296,7 @@ static void OnPlayerDeathPre(SF2_BasePlayer client, int attacker, int inflictor, return; } - ChaserBossProfile data = controller.GetProfileDataEx(); + ChaserBossProfile data = controller.GetProfileData(); char attack[64]; strcopy(attack, sizeof(attack), boss.GetAttackName()); @@ -3291,6 +3308,11 @@ static void OnPlayerDeathPre(SF2_BasePlayer client, int attacker, int inflictor, { SlenderSpawnEffects(attackData.GetOnKillEffects(), controller.Index, false, _, _, _, client.index); } + + if (attackData.GetOnKillInputs() != null) + { + attackData.GetOnKillInputs().AcceptInputs(boss.index, client.index, client.index); + } } } @@ -3340,7 +3362,7 @@ static void OnPlayerDeath(SF2_BasePlayer client, int attacker, int inflictor, bo boss.PerformVoice(SF2BossSound_AttackKilled); - ChaserBossProfile data = controller.GetProfileDataEx(); + ChaserBossProfile data = controller.GetProfileData(); ProfileSound info = data.GetAttackKilledClientSounds(); info.EmitSound(true, client.index); @@ -3433,13 +3455,13 @@ static void ThinkPost(int entIndex) { SF2_ChaserEntity chaser = SF2_ChaserEntity(entIndex); SF2NPC_Chaser controller = chaser.Controller; - ChaserBossProfile data = controller.GetProfileDataEx(); + ChaserBossProfile data = controller.GetProfileData(); ProcessSpeed(chaser); ProcessBody(chaser); - if (data.CustomOutlines && data.RainbowOutline) + if (data.GetOutlineData() != null && data.GetOutlineData().GetRainbowState(controller.Difficulty)) { chaser.ProcessRainbowOutline(); } @@ -3470,7 +3492,7 @@ static void SpawnPost(int entIndex) { SF2_ChaserEntity chaser = SF2_ChaserEntity(entIndex); SF2NPC_Chaser controller = chaser.Controller; - ChaserBossProfile data = controller.GetProfileDataEx(); + ChaserBossProfile data = controller.GetProfileData(); ChaserBossProfileDeathData deathData = data.GetDeathBehavior(); int difficulty = controller.Difficulty; if (!deathData.IsEnabled(difficulty)) @@ -3491,16 +3513,26 @@ static void SpawnPost(int entIndex) { continue; } - if (data.IsPvEBoss) + if (g_Enabled) { - if (!player.IsEliminated) + if (data.IsPvEBoss) { - continue; + if (!player.IsEliminated) + { + continue; + } + } + else + { + if (player.IsEliminated || !player.IsAlive || player.HasEscaped) + { + continue; + } } } else { - if (player.IsEliminated || !player.IsAlive || player.HasEscaped) + if (player.Team != TFTeam_Red && player.Team != TFTeam_Blue) { continue; } @@ -3528,15 +3560,28 @@ static void SpawnPost(int entIndex) if (data.Healthbar) { controller.Flags |= SFF_NOTELEPORT; - UpdateHealthBar(controller.Index); + CreateTimer(0.1, Timer_UpdateHealthBar, controller.UniqueID, TIMER_FLAG_NO_MAPCHANGE); + } +} + +static Action Timer_UpdateHealthBar(Handle timer, any id) +{ + int bossIndex = NPCGetFromUniqueID(id); + if (bossIndex == -1) + { + return Plugin_Continue; } + + UpdateHealthBar(bossIndex); + + return Plugin_Stop; } static Action OnTakeDamage(int victim, int &attacker, int &inflictor, float &damage, int &damageType, int &weapon, float damageForce[3], float damagePosition[3], int damageCustom) { SF2_ChaserEntity chaser = SF2_ChaserEntity(victim); SF2_BasePlayer player = SF2_BasePlayer(attacker); - ChaserBossProfile data = chaser.Controller.GetProfileDataEx(); + ChaserBossProfile data = chaser.Controller.GetProfileData(); float gameTime = GetGameTime(); int difficulty = chaser.Controller.Difficulty; @@ -3760,7 +3805,7 @@ static void OnTakeDamageAlivePost(int victim, int attacker, int inflictor, float { SF2_ChaserEntity chaser = SF2_ChaserEntity(victim); SF2_BasePlayer player = SF2_BasePlayer(attacker); - ChaserBossProfile data = chaser.Controller.GetProfileDataEx(); + ChaserBossProfile data = chaser.Controller.GetProfileData(); bool broadcastDamage = false; @@ -4039,7 +4084,7 @@ static Action TraceOnHit(int victim, int& attacker, int& inflictor, float& damag int difficulty = controller.Difficulty; - ChaserBossProfile data = controller.GetProfileDataEx(); + ChaserBossProfile data = controller.GetProfileData(); if (data.GetResistances() != null) { ChaserBossResistanceData resistanceData; @@ -4100,7 +4145,7 @@ static CBaseEntity ProcessVision(SF2_ChaserEntity chaser, int &interruptConditio return CBaseEntity(-1); } bool attackEliminated = (controller.Flags & SFF_ATTACKWAITERS) != 0; - ChaserBossProfile data = controller.GetProfileDataEx(); + ChaserBossProfile data = controller.GetProfileData(); if (data.IsPvEBoss) { attackEliminated = data.IsPvEBoss; @@ -4352,6 +4397,27 @@ static CBaseEntity ProcessVision(SF2_ChaserEntity chaser, int &interruptConditio TF2_StunPlayer(player.index, SPECIALROUND_BOO_DURATION, _, TF_STUNFLAGS_GHOSTSCARE); } + if (!data.IsPvEBoss && player.IsValid && chaser.State < STATE_ALERT && player.InCondition(TFCond_Taunting) && !controller.HasAttribute(SF2Attribute_IgnoreNonMarkedForChase) && GetVectorSquareMagnitude(traceEndPos, traceStartPos) < SquareFloat(data.GetTauntAlertRange(difficulty))) + { + if (chaser.GetTauntAlertStrikes(player) < 3) + { + chaser.SetTauntAlertStrikes(player, chaser.GetTauntAlertStrikes(player) + 1); + + chaser.InterruptConditions |= COND_ALERT_TRIGGER; + + float pos[3]; + player.GetAbsOrigin(pos); + + chaser.SetAlertTriggerPosition(player, pos); + chaser.AlertTriggerTarget = player; + } + else + { + chaser.SetTauntAlertStrikes(player, 0); + player.SetForceChaseState(controller, true); + } + } + // FOV check. SubtractVectors(traceEndPos, traceStartPos, buffer); GetVectorAngles(buffer, buffer); @@ -4505,7 +4571,9 @@ static CBaseEntity ProcessVision(SF2_ChaserEntity chaser, int &interruptConditio delete valids; - if (!data.IsPvEBoss && (SF_IsRaidMap() || SF_BossesChaseEndlessly() || SF_IsProxyMap() || SF_IsBoxingMap() || SF_IsSlaughterRunMap() || data.ChasesEndlessly || g_RenevantBossesChaseEndlessly)) + CNavArea myArea = chaser.GetLastKnownArea(); + + if (!data.IsPvEBoss && myArea != NULL_AREA && (SF_IsRaidMap() || SF_BossesChaseEndlessly() || SF_IsProxyMap() || SF_IsBoxingMap() || SF_IsSlaughterRunMap() || data.ChasesEndlessly || g_RenevantBossesChaseEndlessly)) { if (!IsTargetValidForSlender(chaser, CBaseEntity(bestNewTarget), attackEliminated)) { @@ -4519,6 +4587,7 @@ static CBaseEntity ProcessVision(SF2_ChaserEntity chaser, int &interruptConditio { continue; } + arrayRaidTargets.Push(EntIndexToEntRef(i)); } @@ -4537,6 +4606,7 @@ static CBaseEntity ProcessVision(SF2_ChaserEntity chaser, int &interruptConditio { continue; } + arrayRaidTargets.Push(g_Buildings.Get(i)); } @@ -4546,6 +4616,7 @@ static CBaseEntity ProcessVision(SF2_ChaserEntity chaser, int &interruptConditio { continue; } + arrayRaidTargets.Push(g_WhitelistedEntities.Get(i)); } } @@ -4620,10 +4691,10 @@ static void ProcessSpeed(SF2_ChaserEntity chaser) CBaseNPC npc = TheNPCs.FindNPCByEntIndex(chaser.index); char profile[SF2_MAX_PROFILE_NAME_LENGTH]; controller.GetProfile(profile, sizeof(profile)); - ChaserBossProfile profileData = controller.GetProfileDataEx(); + ChaserBossProfile profileData = controller.GetProfileData(); float gameTime = GetGameTime(); - ChaserBossProfile data = controller.GetProfileDataEx(); + ChaserBossProfile data = controller.GetProfileData(); char posture[64]; if (data.GetSection("postures") != null) @@ -4805,7 +4876,7 @@ static void ProcessBody(SF2_ChaserEntity chaser) return; } - ChaserBossProfile data = controller.GetProfileDataEx(); + ChaserBossProfile data = controller.GetProfileData(); if (data.GetSection("postures") != null && chaser.CanUpdatePosture()) { @@ -5015,7 +5086,7 @@ static bool LocoCollideWith(CBaseNPC_Locomotion loco, int other) if (chaser.IsValid() && chaser.Controller.IsValid()) { SF2NPC_BaseNPC controller = view_as(chaser.Controller); - BaseBossProfile data = controller.GetProfileDataEx(); + BaseBossProfile data = controller.GetProfileData(); if ((data.IsPvEBoss && player.IsInPvE) || (controller.Flags & SFF_ATTACKWAITERS) != 0) { return true; @@ -5035,7 +5106,7 @@ static bool LocoCollideWith(CBaseNPC_Locomotion loco, int other) if (chaser.IsValid() && chaser.Controller.IsValid()) { - ChaserBossProfile data = chaser.Controller.GetProfileDataEx(); + ChaserBossProfile data = chaser.Controller.GetProfileData(); if (data.IsPvEBoss && SF2_ChaserEntity(other).IsValid()) { return false; @@ -5211,7 +5282,7 @@ static void OnPlayerEmitSound(SF2_BasePlayer client, SoundType soundType) continue; } - ChaserBossProfile data = controller.GetProfileDataEx(); + ChaserBossProfile data = controller.GetProfileData(); ChaserBossSoundSenseData senseData = data.GetSoundSenseData(); ChaserBossAutoChaseData autoChaseData = data.GetAutoChaseData(); @@ -5583,7 +5654,7 @@ static any Native_GetProfileData(Handle plugin, int numParams) SF2_ChaserEntity bossEntity = SF2_ChaserEntity(entity); - return bossEntity.Controller.GetProfileDataEx(); + return bossEntity.Controller.GetProfileData(); } static any Native_PerformVoice(Handle plugin, int numParams) diff --git a/addons/sourcemod/scripting/sf2/npc/entities/chaser/postures/on_alert.sp b/addons/sourcemod/scripting/sf2/npc/entities/chaser/postures/on_alert.sp index 07922cf5..0c6391f6 100644 --- a/addons/sourcemod/scripting/sf2/npc/entities/chaser/postures/on_alert.sp +++ b/addons/sourcemod/scripting/sf2/npc/entities/chaser/postures/on_alert.sp @@ -16,7 +16,7 @@ static Action OnChaserUpdatePosture(SF2NPC_Chaser controller, char[] buffer, int int difficulty = controller.Difficulty; - ChaserBossProfile data = controller.GetProfileDataEx(); + ChaserBossProfile data = controller.GetProfileData(); ProfileObject obj = data.GetSection("postures"); if (obj == null) { diff --git a/addons/sourcemod/scripting/sf2/npc/entities/chaser/postures/on_cloak.sp b/addons/sourcemod/scripting/sf2/npc/entities/chaser/postures/on_cloak.sp index 0befa1bc..f6bc6ab6 100644 --- a/addons/sourcemod/scripting/sf2/npc/entities/chaser/postures/on_cloak.sp +++ b/addons/sourcemod/scripting/sf2/npc/entities/chaser/postures/on_cloak.sp @@ -16,7 +16,7 @@ static Action OnChaserUpdatePosture(SF2NPC_Chaser controller, char[] buffer, int int difficulty = controller.Difficulty; - ChaserBossProfile data = controller.GetProfileDataEx(); + ChaserBossProfile data = controller.GetProfileData(); ProfileObject obj = data.GetSection("postures"); if (obj == null) { diff --git a/addons/sourcemod/scripting/sf2/npc/entities/chaser/postures/on_look.sp b/addons/sourcemod/scripting/sf2/npc/entities/chaser/postures/on_look.sp index cdbac40e..e667a02f 100644 --- a/addons/sourcemod/scripting/sf2/npc/entities/chaser/postures/on_look.sp +++ b/addons/sourcemod/scripting/sf2/npc/entities/chaser/postures/on_look.sp @@ -16,7 +16,7 @@ static Action OnChaserUpdatePosture(SF2NPC_Chaser controller, char[] buffer, int int difficulty = controller.Difficulty; - ChaserBossProfile data = controller.GetProfileDataEx(); + ChaserBossProfile data = controller.GetProfileData(); ProfileObject obj = data.GetSection("postures"); if (obj == null) { diff --git a/addons/sourcemod/scripting/sf2/npc/entities/chaser/postures/rage_phase.sp b/addons/sourcemod/scripting/sf2/npc/entities/chaser/postures/rage_phase.sp index 19aad2a4..8e04f142 100644 --- a/addons/sourcemod/scripting/sf2/npc/entities/chaser/postures/rage_phase.sp +++ b/addons/sourcemod/scripting/sf2/npc/entities/chaser/postures/rage_phase.sp @@ -35,7 +35,7 @@ static Action OnChaserUpdatePosture(SF2NPC_Chaser controller, char[] buffer, int int difficulty = controller.Difficulty; - ChaserBossProfile data = controller.GetProfileDataEx(); + ChaserBossProfile data = controller.GetProfileData(); ProfileObject obj = data.GetSection("postures"); if (obj == null) { diff --git a/addons/sourcemod/scripting/sf2/npc/entities/chaser/postures/running_away.sp b/addons/sourcemod/scripting/sf2/npc/entities/chaser/postures/running_away.sp index fc92e00e..59807577 100644 --- a/addons/sourcemod/scripting/sf2/npc/entities/chaser/postures/running_away.sp +++ b/addons/sourcemod/scripting/sf2/npc/entities/chaser/postures/running_away.sp @@ -16,7 +16,7 @@ static Action OnChaserUpdatePosture(SF2NPC_Chaser controller, char[] buffer, int int difficulty = controller.Difficulty; - ChaserBossProfile data = controller.GetProfileDataEx(); + ChaserBossProfile data = controller.GetProfileData(); ProfileObject obj = data.GetSection("postures"); if (obj == null) { diff --git a/addons/sourcemod/scripting/sf2/npc/entities/chaser/postures/within_bounds.sp b/addons/sourcemod/scripting/sf2/npc/entities/chaser/postures/within_bounds.sp index 33f9e0d2..9559201f 100644 --- a/addons/sourcemod/scripting/sf2/npc/entities/chaser/postures/within_bounds.sp +++ b/addons/sourcemod/scripting/sf2/npc/entities/chaser/postures/within_bounds.sp @@ -29,7 +29,7 @@ static Action OnChaserUpdatePosture(SF2NPC_Chaser controller, char[] buffer, int int difficulty = controller.Difficulty; - ChaserBossProfile data = controller.GetProfileDataEx(); + ChaserBossProfile data = controller.GetProfileData(); ProfileObject obj = data.GetSection("postures"); if (obj == null) { diff --git a/addons/sourcemod/scripting/sf2/npc/entities/chaser/postures/within_range.sp b/addons/sourcemod/scripting/sf2/npc/entities/chaser/postures/within_range.sp index 45de3303..9a48cd8e 100644 --- a/addons/sourcemod/scripting/sf2/npc/entities/chaser/postures/within_range.sp +++ b/addons/sourcemod/scripting/sf2/npc/entities/chaser/postures/within_range.sp @@ -50,7 +50,7 @@ static Action OnChaserUpdatePosture(SF2NPC_Chaser controller, char[] buffer, int int difficulty = controller.Difficulty; float gameTime = GetGameTime(); - ChaserBossProfile data = controller.GetProfileDataEx(); + ChaserBossProfile data = controller.GetProfileData(); ProfileObject obj = data.GetSection("postures"); if (obj == null) { diff --git a/addons/sourcemod/scripting/sf2/npc/entities/statue/actions/chase.sp b/addons/sourcemod/scripting/sf2/npc/entities/statue/actions/chase.sp index e876c469..4a429e20 100644 --- a/addons/sourcemod/scripting/sf2/npc/entities/statue/actions/chase.sp +++ b/addons/sourcemod/scripting/sf2/npc/entities/statue/actions/chase.sp @@ -22,7 +22,7 @@ static int OnStart(SF2_StatueChaseAction action, SF2_StatueEntity actor, NextBot { SF2NPC_Statue controller = actor.Controller; int difficulty = controller.Difficulty; - StatueBossProfile data = controller.GetProfileDataEx(); + StatueBossProfile data = controller.GetProfileData(); actor.CurrentChaseDuration = data.GetChaseDuration(difficulty); if (actor.InitialChaseDuration > 0.0) { @@ -57,7 +57,7 @@ static int Update(SF2_StatueChaseAction action, SF2_StatueEntity actor) } SF2NPC_Statue controller = actor.Controller; - StatueBossProfile data = controller.GetProfileDataEx(); + StatueBossProfile data = controller.GetProfileData(); bool attackEliminated = (controller.Flags & SFF_ATTACKWAITERS) != 0; int difficulty = controller.Difficulty; INextBot bot = actor.MyNextBotPointer(); @@ -150,7 +150,7 @@ static int Update(SF2_StatueChaseAction action, SF2_StatueEntity actor) { g_SlenderStatueIdleLifeTime[controller.Index] = gameTime + data.GetIdleLifeTime(difficulty); - if (bot.GetRangeSquaredTo(target.index) <= Pow(data.InstantKillRadius, 2.0) && visible) + if (bot.GetRangeSquaredTo(target.index) <= Pow(data.GetInstantKillRadius(difficulty), 2.0) && visible) { if (controller.Flags & SFF_FAKE) { diff --git a/addons/sourcemod/scripting/sf2/npc/entities/statue/actions/mainlayer.sp b/addons/sourcemod/scripting/sf2/npc/entities/statue/actions/mainlayer.sp index 5228bc15..f4a2816a 100644 --- a/addons/sourcemod/scripting/sf2/npc/entities/statue/actions/mainlayer.sp +++ b/addons/sourcemod/scripting/sf2/npc/entities/statue/actions/mainlayer.sp @@ -73,7 +73,7 @@ static int Update(SF2_StatueBaseAction action, SF2_StatueEntity actor, float int return action.Done("I'm a faker"); } - StatueBossProfile data = controller.GetProfileDataEx(); + StatueBossProfile data = controller.GetProfileData(); CBaseEntity target = actor.Target; float myPos[3]; actor.GetAbsOrigin(myPos); diff --git a/addons/sourcemod/scripting/sf2/npc/entities/statue/entity.sp b/addons/sourcemod/scripting/sf2/npc/entities/statue/entity.sp index 9bb62709..c3a96864 100644 --- a/addons/sourcemod/scripting/sf2/npc/entities/statue/entity.sp +++ b/addons/sourcemod/scripting/sf2/npc/entities/statue/entity.sp @@ -115,7 +115,7 @@ methodmap SF2_StatueEntity < SF2_BaseBoss controller.GetProfile(profile, sizeof(profile)); statue.Controller = view_as(controller); - StatueBossProfile profileData = statue.Controller.GetProfileDataEx(); + StatueBossProfile profileData = statue.Controller.GetProfileData(); int difficulty = g_DifficultyConVar.IntValue; char buffer[PLATFORM_MAX_PATH]; @@ -217,10 +217,12 @@ static Action Think(int entIndex) static void ThinkPost(int entIndex) { SF2_StatueEntity statue = SF2_StatueEntity(entIndex); + SF2NPC_Statue controller = statue.Controller; + StatueBossProfile data = controller.GetProfileData(); ProcessSpeed(statue); - if (statue.GetProfileData().CustomOutlines && statue.GetProfileData().RainbowOutline) + if (data.GetOutlineData() != null && data.GetOutlineData().GetRainbowState(controller.Difficulty)) { statue.ProcessRainbowOutline(); } @@ -231,7 +233,7 @@ static void ThinkPost(int entIndex) } statue.InterruptConditions = 0; - statue.SetNextThink(GetGameTime() + statue.Controller.GetProfileDataEx().TickRate); + statue.SetNextThink(GetGameTime() + statue.Controller.GetProfileData().TickRate); } static MRESReturn UpdateTransmitState(int entIndex, DHookReturn ret, DHookParam params) @@ -265,7 +267,7 @@ static CBaseEntity ProcessVision(SF2_StatueEntity statue, int &interruptConditio return CBaseEntity(-1); } bool attackEliminated = (controller.Flags & SFF_ATTACKWAITERS) != 0; - StatueBossProfile data = controller.GetProfileDataEx(); + StatueBossProfile data = controller.GetProfileData(); int difficulty = controller.Difficulty; float playerDists[MAXTF2PLAYERS]; @@ -469,7 +471,7 @@ static void ProcessSpeed(SF2_StatueEntity statue) SF2NPC_Statue controller = statue.Controller; int difficulty = controller.Difficulty; CBaseNPC npc = TheNPCs.FindNPCByEntIndex(statue.index); - StatueBossProfile data = controller.GetProfileDataEx(); + StatueBossProfile data = controller.GetProfileData(); float speed, acceleration; @@ -576,5 +578,5 @@ static any Native_GetProfileData(Handle plugin, int numParams) SF2_StatueEntity bossEntity = SF2_StatueEntity(entity); - return bossEntity.Controller.GetProfileDataEx(); + return bossEntity.Controller.GetProfileData(); } diff --git a/addons/sourcemod/scripting/sf2/npc/glow.sp b/addons/sourcemod/scripting/sf2/npc/glow.sp index 4aef1703..ae62f341 100644 --- a/addons/sourcemod/scripting/sf2/npc/glow.sp +++ b/addons/sourcemod/scripting/sf2/npc/glow.sp @@ -26,7 +26,34 @@ static void OnPlayerSpawn(SF2_BasePlayer client) static void OnDifficultyChange(int oldDifficulty, int newDifficulty) { + for (int i = 0; i < MAX_BOSSES; i++) + { + SF2NPC_BaseNPC npc = SF2NPC_BaseNPC(i); + if (!npc.IsValid()) + { + continue; + } + + if (!IsValidEntity(npc.EntIndex)) + { + continue; + } + + BaseBossProfile data = npc.GetProfileData(); + if (data.IsPvEBoss) + { + continue; + } + int color[4]; + color = g_DefaultColor; + if (data.GetOutlineData() != null) + { + data.GetOutlineData().GetOutlineColor(color, npc.Difficulty); + } + SetGlowColor(npc.EntIndex, color); + UpdateVisibility(npc); + } } static void OnSpecialRoundStart(int specialRound) @@ -48,7 +75,7 @@ static void OnSpecialRoundStart(int specialRound) static void OnBossSpawn(SF2NPC_BaseNPC controller) { - BaseBossProfile data = controller.GetProfileDataEx(); + BaseBossProfile data = controller.GetProfileData(); if (data.IsPvEBoss) { return; @@ -56,9 +83,9 @@ static void OnBossSpawn(SF2NPC_BaseNPC controller) int color[4]; color = g_DefaultColor; - if (data.CustomOutlines) + if (data.GetOutlineData() != null) { - data.GetOutlineColor(color); + data.GetOutlineData().GetOutlineColor(color, controller.Difficulty); } CreateGlowEntity(controller.EntIndex, color); UpdateVisibility(controller); diff --git a/addons/sourcemod/scripting/sf2/npc/npc_chaser.sp b/addons/sourcemod/scripting/sf2/npc/npc_chaser.sp index 0b46f757..bc97bd3e 100644 --- a/addons/sourcemod/scripting/sf2/npc/npc_chaser.sp +++ b/addons/sourcemod/scripting/sf2/npc/npc_chaser.sp @@ -74,7 +74,7 @@ static void OnPlayerEscape(SF2_BasePlayer client) static void OnBossRemoved(SF2NPC_BaseNPC npc) { - if (npc.GetProfileDataEx().Type == SF2BossType_Chaser) + if (npc.GetProfileData().Type == SF2BossType_Chaser) { NPCChaserOnRemoveProfile(npc.Index); } @@ -153,7 +153,7 @@ void NPCChaserOnSelectProfile(int npcIndex) SF2NPC_Chaser chaser = SF2NPC_Chaser(npcIndex); char profile[SF2_MAX_PROFILE_NAME_LENGTH]; NPCGetProfile(npcIndex, profile, sizeof(profile)); - ChaserBossProfile profileData = chaser.GetProfileDataEx(); + ChaserBossProfile profileData = chaser.GetProfileData(); for (int difficulty = 0; difficulty < Difficulty_Max; difficulty++) { @@ -352,7 +352,7 @@ bool IsTargetValidForSlenderEx(CBaseEntity target, int bossIndex, bool includeEl return false; } - if (!SF_BossesChaseEndlessly() && !SF_IsRenevantMap() && !SF_IsSurvivalMap() && !SF2NPC_BaseNPC(bossIndex).GetProfileDataEx().TeleportIgnoreChases) + if (!SF_BossesChaseEndlessly() && !SF_IsRenevantMap() && !SF_IsSurvivalMap() && !SF2NPC_BaseNPC(bossIndex).GetProfileData().TeleportIgnoreChases) { for (int i = 0; i < MAX_BOSSES; i++) { @@ -369,7 +369,7 @@ bool IsTargetValidForSlenderEx(CBaseEntity target, int bossIndex, bool includeEl } int state = chaser.State; - if (!npc.GetProfileDataEx().IsPvEBoss && (state == STATE_CHASE || state == STATE_ATTACK || state == STATE_STUN)) + if (!npc.GetProfileData().IsPvEBoss && (state == STATE_CHASE || state == STATE_ATTACK || state == STATE_STUN)) { return false; } @@ -648,7 +648,7 @@ static any Native_PerformVoice(Handle plugin, int numParams) return 0; } - ChaserBossProfile data = controller.GetProfileDataEx(); + ChaserBossProfile data = controller.GetProfileData(); char name[64]; data.GetAttackName(GetNativeCell(3), name, sizeof(name)); @@ -691,7 +691,7 @@ static any Native_GetBossAttackIndexType(Handle plugin, int numParams) return 0; } - ChaserBossProfile data = controller.GetProfileDataEx(); + ChaserBossProfile data = controller.GetProfileData(); char name[64]; data.GetAttackName(GetNativeCell(2), name, sizeof(name)); return data.GetAttack(name).Type; @@ -711,7 +711,7 @@ static any Native_GetBossAttackIndexDamage(Handle plugin, int numParams) return 0; } - ChaserBossProfile data = controller.GetProfileDataEx(); + ChaserBossProfile data = controller.GetProfileData(); char name[64]; data.GetAttackName(GetNativeCell(2), name, sizeof(name)); return data.GetAttack(name).GetDamage(GetNativeCell(3)); @@ -793,7 +793,7 @@ static any Native_GetBossAttackIndexDamageType(Handle plugin, int numParams) return 0; } - ChaserBossProfile data = controller.GetProfileDataEx(); + ChaserBossProfile data = controller.GetProfileData(); char name[64]; data.GetAttackName(GetNativeCell(2), name, sizeof(name)); return data.GetAttack(name).GetDamageType(1); @@ -807,7 +807,7 @@ static any Native_GetProfileData(Handle plugin, int numParams) return ThrowNativeError(SP_ERROR_NATIVE, "Invalid boss index %d", controller.Index); } - return controller.GetProfileDataEx(); + return controller.GetProfileData(); } static any Native_GetProfileDataEx(Handle plugin, int numParams) diff --git a/addons/sourcemod/scripting/sf2/npc/npc_creeper.sp b/addons/sourcemod/scripting/sf2/npc/npc_creeper.sp index 786cba5c..7fb4d521 100644 --- a/addons/sourcemod/scripting/sf2/npc/npc_creeper.sp +++ b/addons/sourcemod/scripting/sf2/npc/npc_creeper.sp @@ -15,13 +15,13 @@ void NPCStatueOnSelectProfile(int npcIndex) SF2_StatueEntity Spawn_Statue(SF2NPC_BaseNPC controller, const float pos[3], const float ang[3]) { - g_SlenderStatueIdleLifeTime[controller.Index] = GetGameTime() + view_as(controller).GetProfileDataEx().GetIdleLifeTime(controller.Difficulty); + g_SlenderStatueIdleLifeTime[controller.Index] = GetGameTime() + view_as(controller).GetProfileData().GetIdleLifeTime(controller.Difficulty); return SF2_StatueEntity.Create(controller, pos, ang); } void Despawn_Statue(SF2NPC_Statue controller, CBaseEntity bossEnt) { - StatueBossProfile data = controller.GetProfileDataEx(); + StatueBossProfile data = controller.GetProfileData(); // Stop all possible looping sounds. for (int i = 0; i < Difficulty_Max; i++) { @@ -45,7 +45,7 @@ static any Native_GetProfileData(Handle plugin, int numParams) return ThrowNativeError(SP_ERROR_NATIVE, "Invalid boss index %d", controller.Index); } - return controller.GetProfileDataEx(); + return controller.GetProfileData(); } static any Native_GetProfileDataEx(Handle plugin, int numParams) diff --git a/addons/sourcemod/scripting/sf2/profiles.sp b/addons/sourcemod/scripting/sf2/profiles.sp index a8fda855..d15b8586 100644 --- a/addons/sourcemod/scripting/sf2/profiles.sp +++ b/addons/sourcemod/scripting/sf2/profiles.sp @@ -17,8 +17,6 @@ ArrayList g_BossProfileList = null; static ArrayList g_SelectableBossProfileList = null; static ArrayList g_SelectableAdminBossProfileList = null; -static ArrayList g_SelectableBoxingBossProfileList = null; -static ArrayList g_SelectableRenevantBossProfileList = null; static ArrayList g_SelectableRenevantBossAdminProfileList = null; static ArrayList g_SelectableBossProfileQueueList = null; @@ -409,18 +407,6 @@ void UnloadBossProfile(const char[] profile) g_SelectableAdminBossProfileList.Erase(index); } - index = g_SelectableBoxingBossProfileList.FindString(profile); - if (index != -1) - { - g_SelectableBoxingBossProfileList.Erase(index); - } - - index = g_SelectableRenevantBossProfileList.FindString(profile); - if (index != -1) - { - g_SelectableRenevantBossProfileList.Erase(index); - } - index = g_SelectableRenevantBossAdminProfileList.FindString(profile); if (index != -1) { @@ -429,9 +415,7 @@ void UnloadBossProfile(const char[] profile) if (profileData.IsPvEBoss) { - char setProfile[SF2_MAX_PROFILE_NAME_LENGTH]; - strcopy(setProfile, sizeof(setProfile), profile); - UnregisterPvESlenderBoss(setProfile); + UnregisterPvESlenderBoss(profile); } CleanupKeyMap(profileData); @@ -473,16 +457,6 @@ void ClearBossProfiles() delete g_SelectableAdminBossProfileList; } - if (g_SelectableBoxingBossProfileList != null) - { - delete g_SelectableBoxingBossProfileList; - } - - if (g_SelectableRenevantBossProfileList != null) - { - delete g_SelectableRenevantBossProfileList; - } - if (g_SelectableRenevantBossAdminProfileList != null) { delete g_SelectableRenevantBossAdminProfileList; @@ -528,16 +502,6 @@ void ReloadBossProfiles() g_SelectableAdminBossProfileList = new ArrayList(SF2_MAX_PROFILE_NAME_LENGTH); } - if (g_SelectableBoxingBossProfileList == null) - { - g_SelectableBoxingBossProfileList = new ArrayList(SF2_MAX_PROFILE_NAME_LENGTH); - } - - if (g_SelectableRenevantBossProfileList == null) - { - g_SelectableRenevantBossProfileList = new ArrayList(SF2_MAX_PROFILE_NAME_LENGTH); - } - if (g_SelectableRenevantBossAdminProfileList == null) { g_SelectableRenevantBossAdminProfileList = new ArrayList(SF2_MAX_PROFILE_NAME_LENGTH); @@ -722,27 +686,69 @@ static bool LoadProfileFile(const char[] profilePath, char[] profileName, int pr delete kv; - char path[PLATFORM_MAX_PATH]; + bool selectable = true; + if (profileData.GetMapSelectionBlacklist() != null) + { + char currentMap[128]; + GetCurrentMap(currentMap, sizeof(currentMap)); - if (lookIntoLoads) + for (int i = 0; i < profileData.GetMapSelectionBlacklist().KeyLength; i++) + { + char key[64], map[128]; + profileData.GetMapSelectionBlacklist().GetKeyNameFromIndex(i, key, sizeof(key)); + profileData.GetMapSelectionBlacklist().GetString(key, map, sizeof(map)); + + if (StrContains(currentMap, map, false) != -1) + { + selectable = false; + } + } + } + + if (profileData.GetModeSelectionBlacklist() != null) { - bool skip = true; - if (profileData.GetBool("enable_random_selection", true)) + if (selectable && SF_IsBoxingMap() && profileData.GetModeSelectionBlacklist().GetBool("boxing", false)) { - skip = false; + selectable = false; } - if (profileData.GetBool("admin_only", false)) + if (selectable && SF_IsProxyMap() && profileData.GetModeSelectionBlacklist().GetBool("proxy", false)) { - skip = false; + selectable = false; } - if (profileData.GetBool("enable_random_selection_boxing", false)) + if (selectable && SF_IsRaidMap() && profileData.GetModeSelectionBlacklist().GetBool("raid", false)) + { + selectable = false; + } + + if (selectable && SF_IsRenevantMap() && profileData.GetModeSelectionBlacklist().GetBool("renevant", false)) + { + selectable = false; + } + + if (selectable && SF_IsSlaughterRunMap() && profileData.GetModeSelectionBlacklist().GetBool("slaughter_run", false)) + { + selectable = false; + } + + if (selectable && SF_IsSurvivalMap() && profileData.GetModeSelectionBlacklist().GetBool("survival", false)) + { + selectable = false; + } + } + + char path[PLATFORM_MAX_PATH]; + + if (lookIntoLoads) + { + bool skip = true; + if (selectable) { skip = false; } - if (profileData.GetBool("enable_random_selection_renevant", false)) + if (profileData.GetBool("admin_only", false)) { skip = false; } @@ -771,12 +777,12 @@ static bool LoadProfileFile(const char[] profilePath, char[] profileName, int pr if (skip) { FormatEx(errorReason, errorReasonLen, "is not selectable, skipping!"); - //DeleteCfg(parent); + CleanupKeyMap(profileData); return false; } } - if (profileData.Type == SF2BossType_Unknown || profileData.Type >= SF2BossType_MaxTypes) + if (profileData.Type <= SF2BossType_Unknown || profileData.Type >= SF2BossType_MaxTypes) { FormatEx(errorReason, errorReasonLen, "boss type is unknown!"); return false; @@ -788,7 +794,7 @@ static bool LoadProfileFile(const char[] profilePath, char[] profileName, int pr if (path[0] == '\0') { FormatEx(errorReason, errorReasonLen, "model cannot be blank!"); - //DeleteCfg(parent); + CleanupKeyMap(profileData); return false; } } @@ -805,26 +811,16 @@ static bool LoadProfileFile(const char[] profilePath, char[] profileName, int pr g_BossProfileList.PushString(profileName); } - bool blacklisted = false; - - if (profileData.GetBlacklistedMaps() != null) + if (profileData.IsPvEBoss) { - char map[64], currentMap[64], key[64]; - GetCurrentMap(currentMap, sizeof(currentMap)); - for (int i = 0; i < profileData.GetBlacklistedMaps().Size; i++) + selectable = false; + if (profileData.GetPvEData().IsSelectable) { - profileData.GetBlacklistedMaps().GetKeyNameFromIndex(i, key, sizeof(key)); - profileData.GetBlacklistedMaps().GetString(key, map, sizeof(map)); - - if (StrContains(currentMap, map, false) != -1) - { - blacklisted = true; - break; - } + RegisterPvESlenderBoss(profileName); } } - if (!blacklisted) + if (selectable) { if (profileData.GetBool("enable_random_selection", true)) { @@ -834,14 +830,6 @@ static bool LoadProfileFile(const char[] profilePath, char[] profileName, int pr GetSelectableBossProfileList().PushString(profileName); } } - else - { - int selectIndex = GetSelectableBossProfileList().FindString(profileName); - if (selectIndex != -1) - { - GetSelectableBossProfileList().Erase(selectIndex); - } - } if (profileData.GetBool("admin_only", false)) { @@ -851,48 +839,6 @@ static bool LoadProfileFile(const char[] profilePath, char[] profileName, int pr GetSelectableAdminBossProfileList().PushString(profileName); } } - else - { - int selectIndex = GetSelectableAdminBossProfileList().FindString(profileName); - if (selectIndex != -1) - { - GetSelectableAdminBossProfileList().Erase(selectIndex); - } - } - - if (profileData.GetBool("enable_random_selection_boxing", false)) - { - if (GetSelectableBoxingBossProfileList().FindString(profileName) == -1) - { - // Add to the selectable boss list if it isn't there already. - GetSelectableBoxingBossProfileList().PushString(profileName); - } - } - else - { - int selectIndex = GetSelectableBoxingBossProfileList().FindString(profileName); - if (selectIndex != -1) - { - GetSelectableBoxingBossProfileList().Erase(selectIndex); - } - } - - if (profileData.GetBool("enable_random_selection_renevant", false)) - { - if (GetSelectableRenevantBossProfileList().FindString(profileName) == -1) - { - // Add to the selectable boss list if it isn't there already. - GetSelectableRenevantBossProfileList().PushString(profileName); - } - } - else - { - int selectIndex = GetSelectableRenevantBossProfileList().FindString(profileName); - if (selectIndex != -1) - { - GetSelectableRenevantBossProfileList().Erase(selectIndex); - } - } if (profileData.GetBool("enable_random_selection_renevant_admin", false)) { @@ -902,14 +848,6 @@ static bool LoadProfileFile(const char[] profilePath, char[] profileName, int pr GetSelectableRenevantBossAdminProfileList().PushString(profileName); } } - else - { - int selectIndex = GetSelectableRenevantBossAdminProfileList().FindString(profileName); - if (selectIndex != -1) - { - GetSelectableRenevantBossAdminProfileList().Erase(selectIndex); - } - } } Call_StartForward(g_OnBossProfileLoadedFwd); @@ -1547,37 +1485,16 @@ ArrayList GetSelectableBossProfileList() return g_SelectableBossProfileList; } -ArrayList GetSelectableBoxingBossProfileList() -{ - return g_SelectableBoxingBossProfileList; -} - ArrayList GetSelectableAdminBossProfileList() { return g_SelectableAdminBossProfileList; } -ArrayList GetSelectableRenevantBossProfileList() -{ - return g_SelectableRenevantBossProfileList; -} - ArrayList GetSelectableRenevantBossAdminProfileList() { return g_SelectableRenevantBossAdminProfileList; } -bool GetRandomRenevantBossProfile(char[] sBuffer, int iBufferLen) -{ - if (g_SelectableRenevantBossProfileList.Length == 0) - { - return false; - } - - g_SelectableRenevantBossProfileList.GetString(GetRandomInt(0, g_SelectableRenevantBossProfileList.Length - 1), sBuffer, iBufferLen); - return true; -} - /** * Returns an array of boss that didn't play in game yet. */ diff --git a/addons/sourcemod/scripting/sf2/profiles/keymap.sp b/addons/sourcemod/scripting/sf2/profiles/keymap.sp index 58a54259..95323218 100644 --- a/addons/sourcemod/scripting/sf2/profiles/keymap.sp +++ b/addons/sourcemod/scripting/sf2/profiles/keymap.sp @@ -422,12 +422,6 @@ methodmap KeyMap < StringMap public KeyMap Clone() { KeyMap clone = CloneKeyMap(this); - clone.Parent = null; - KeyMap section = clone.GetSection("execution"); - if (section != null) - { - section.GetSection("paths"); - } return clone; } diff --git a/addons/sourcemod/scripting/sf2/profiles/objects.sp b/addons/sourcemod/scripting/sf2/profiles/objects.sp index 07d8a873..a95f3c5b 100644 --- a/addons/sourcemod/scripting/sf2/profiles/objects.sp +++ b/addons/sourcemod/scripting/sf2/profiles/objects.sp @@ -984,7 +984,7 @@ methodmap ProfileSound < ProfileObject break; } - TryPrecacheBossProfileSoundPath(path, g_FileCheckConVar.BoolValue); + PrecacheSound2(path, g_FileCheckConVar.BoolValue); paths.PushString(path); obj.RemoveKey(num); } @@ -1425,8 +1425,6 @@ methodmap ProfileMasterAnimations < ProfileObject // This covers the whole "anim strcmp(animType, g_SlenderAnimationsList[SF2BossAnimation_DeathCam]) == 0 || strcmp(animType, g_SlenderAnimationsList[SF2BossAnimation_Death]) == 0 || strcmp(animType, g_SlenderAnimationsList[SF2BossAnimation_TauntKill]) == 0 || - strcmp(animType, g_SlenderAnimationsList[SF2BossAnimation_AttackBegin]) == 0 || - strcmp(animType, g_SlenderAnimationsList[SF2BossAnimation_AttackEnd]) == 0 || strcmp(animType, g_SlenderAnimationsList[SF2BossAnimation_ProjectileShoot]) == 0 || strcmp(animType, g_SlenderAnimationsList[SF2BossAnimation_Despawn]) == 0) { @@ -1747,6 +1745,9 @@ void SetupProfileObjectNatives() CreateNative("SF2_ProfileObject.Parent.get", Native_GetObjectParent); CreateNative("SF2_ProfileObject.KeyLength.get", Native_GetObjectKeyLength); CreateNative("SF2_ProfileObject.SectionLength.get", Native_GetObjectSectionLength); + CreateNative("SF2_ProfileObject.GetSectionName", Native_GetObjectSectionName); + CreateNative("SF2_ProfileObject.GetKeyNameFromIndex", Native_GetObjectKeyNameFromIndex); + CreateNative("SF2_ProfileObject.GetSectionNameFromIndex", Native_GetObjectSectionNameFromIndex); CreateNative("SF2_ProfileObject.GetInt", Native_GetObjectInt); CreateNative("SF2_ProfileObject.SetInt", Native_SetObjectInt); CreateNative("SF2_ProfileObject.GetBool", Native_GetObjectBool); @@ -1849,6 +1850,57 @@ static any Native_GetObjectSectionLength(Handle plugin, int numParams) return obj.SectionLength; } +static any Native_GetObjectSectionName(Handle plugin, int numParams) +{ + ProfileObject obj = view_as(GetNativeCell(1)); + if (obj == null) + { + return ThrowNativeError(SP_ERROR_NATIVE, "Invalid profile object handle %x", obj); + } + + int bufferSize = GetNativeCell(3); + char[] buffer = new char[bufferSize]; + + obj.GetSectionName(buffer, bufferSize); + + SetNativeString(2, buffer, bufferSize); + return 0; +} + +static any Native_GetObjectKeyNameFromIndex(Handle plugin, int numParams) +{ + ProfileObject obj = view_as(GetNativeCell(1)); + if (obj == null) + { + return ThrowNativeError(SP_ERROR_NATIVE, "Invalid profile object handle %x", obj); + } + + int bufferSize = GetNativeCell(4); + char[] buffer = new char[bufferSize]; + + bool state = obj.GetKeyNameFromIndex(GetNativeCell(2), buffer, bufferSize); + + SetNativeString(3, buffer, bufferSize); + return state; +} + +static any Native_GetObjectSectionNameFromIndex(Handle plugin, int numParams) +{ + ProfileObject obj = view_as(GetNativeCell(1)); + if (obj == null) + { + return ThrowNativeError(SP_ERROR_NATIVE, "Invalid profile object handle %x", obj); + } + + int bufferSize = GetNativeCell(4); + char[] buffer = new char[bufferSize]; + + bool state = obj.GetSectionNameFromIndex(GetNativeCell(2), buffer, bufferSize); + + SetNativeString(3, buffer, bufferSize); + return state; +} + static any Native_GetObjectInt(Handle plugin, int numParams) { ProfileObject obj = view_as(GetNativeCell(1)); diff --git a/addons/sourcemod/scripting/sf2/profiles/profile_chaser.sp b/addons/sourcemod/scripting/sf2/profiles/profile_chaser.sp index 64daab30..0cf5c26c 100644 --- a/addons/sourcemod/scripting/sf2/profiles/profile_chaser.sp +++ b/addons/sourcemod/scripting/sf2/profiles/profile_chaser.sp @@ -7,23 +7,6 @@ #pragma semicolon 1 #pragma newdecls required -/*for (int i = 0; i < Difficulty_Max; i++) - { - this.Enabled[i] = false; - this.Cooldown[i] = 8.0; - this.Duration[i] = 10.0; - this.CloakRange[i] = 350.0; - this.DecloakRange[i] = 150.0; - } - - this.CloakRenderColor[0] = 0; - this.CloakRenderColor[1] = 0; - this.CloakRenderColor[2] = 0; - this.CloakRenderColor[3] = 0; - this.CloakRenderMode = 1; - this.CloakEffects = null; - this.DecloakEffects = null;*/ - methodmap ChaserBossProfile < BaseBossProfile { property bool ClearLayersOnAnimUpdate @@ -84,6 +67,11 @@ methodmap ChaserBossProfile < BaseBossProfile return value; } + public float GetTauntAlertRange(int difficulty) + { + return this.GetDifficultyFloat("taunt_alert_range", difficulty, 512.0); + } + public bool ShouldIgnoreHearingPathChecking(int difficulty) { return this.GetDifficultyBool("hearing_ignore_path_checking", difficulty, false); @@ -1781,6 +1769,16 @@ methodmap ChaserBossProfileStunData < ProfileObject return null; } + public ProfileEntityInputsArray GetOnStartInputs() + { + ProfileObject obj = this.GetSection("inputs"); + if (obj != null) + { + return view_as(obj.GetSection("on_start")); + } + return null; + } + public ProfileEffectMaster GetOnEndEffects() { ProfileObject obj = this.GetSection("effects"); @@ -1793,6 +1791,16 @@ methodmap ChaserBossProfileStunData < ProfileObject return null; } + public ProfileEntityInputsArray GetOnEndInputs() + { + ProfileObject obj = this.GetSection("inputs"); + if (obj != null) + { + return view_as(obj.GetSection("on_end")); + } + return null; + } + public void Precache() { if (this.GetOnStartEffects() != null) @@ -2001,6 +2009,16 @@ methodmap ChaserBossProfileDeathData < ProfileObject return null; } + public ProfileEntityInputsArray GetOnStartInputs() + { + ProfileObject obj = this.GetSection("inputs"); + if (obj != null) + { + return view_as(obj.GetSection("on_start")); + } + return null; + } + public ProfileEffectMaster GetOnEndEffects() { ProfileObject obj = this.GetSection("effects"); @@ -2013,6 +2031,16 @@ methodmap ChaserBossProfileDeathData < ProfileObject return null; } + public ProfileEntityInputsArray GetOnEndInputs() + { + ProfileObject obj = this.GetSection("inputs"); + if (obj != null) + { + return view_as(obj.GetSection("on_end")); + } + return null; + } + public void Precache() { if (this.GetOnStartEffects() != null) diff --git a/addons/sourcemod/scripting/sf2/profiles/profiles_boss_functions.sp b/addons/sourcemod/scripting/sf2/profiles/profiles_boss_functions.sp index bc2f5d05..8cfc5b28 100644 --- a/addons/sourcemod/scripting/sf2/profiles/profiles_boss_functions.sp +++ b/addons/sourcemod/scripting/sf2/profiles/profiles_boss_functions.sp @@ -139,12 +139,9 @@ methodmap BaseBossProfile < ProfileObject } } - property float InstantKillRadius + public float GetInstantKillRadius(int difficulty) { - public get() - { - return this.GetFloat("kill_radius", -1.0); - } + return this.GetDifficultyFloat("kill_radius", difficulty, -1.0); } public float GetInstantKillCooldown(int difficulty) @@ -505,103 +502,22 @@ methodmap BaseBossProfile < ProfileObject return view_as(this); } - property bool IsPvEBoss - { - public get() - { - bool val = this.GetBool("is_pve", false); - ProfileObject obj = this.GetSection("pve"); - if (obj != null) - { - val = true; - } - return val; - } - } - - property ProfileObject PvESpawnMessagesArray - { - public get() - { - ProfileObject obj = this.GetSection("pve"); - if (obj != null) - { - return obj.GetSection("spawn_messages"); - } - return this.GetSection("pve_spawn_messages"); - } - } - - public void GetPvESpawnMessagePrefix(char[] buffer, int bufferSize) - { - ProfileObject obj = this.GetSection("pve"); - if (obj != null) - { - obj.GetString("spawn_message_prefix", buffer, bufferSize); - } - else - { - this.GetString("pve_spawn_message_prefix", buffer, bufferSize); - } - } - - property bool DisplayPvEHealth - { - public get() - { - ProfileObject obj = this.GetSection("pve"); - if (obj != null) - { - return obj.GetBool("health_bar", true); - } - return this.GetBool("pve_health_bar", true); - } - } - - property float PvETeleportEndTimer + public BossProfilePvEData GetPvEData() { - public get() - { - float def = 5.0; - ProfileObject obj = this.GetSection("pve"); - if (obj != null) - { - return obj.GetFloat("teleport_players_time", def); - } - return def; - } - } - - property bool CustomOutlines - { - public get() - { - return this.GetBool("customizable_outlines", false); - } + return view_as(this.GetSection("pve")); } - public void GetOutlineColor(int buffer[4]) - { - buffer[0] = this.GetInt("outline_color_r", 255); - buffer[1] = this.GetInt("outline_color_g", 255); - buffer[2] = this.GetInt("outline_color_b", 255); - buffer[3] = this.GetInt("outline_color_transparency", 255); - } - - property bool RainbowOutline + property bool IsPvEBoss { public get() { - return this.GetBool("enable_rainbow_outline", false); + return this.GetPvEData().IsEnabled; } } - property float RainbowOutlineCycle + public BossProfileOutlineData GetOutlineData() { - public get() - { - return this.GetFloat("rainbow_outline_cycle_rate", 1.0); - } + return view_as(this.GetSection("outline")); } public void GetStaticSound(char[] buffer, int bufferSize) @@ -945,11 +861,36 @@ methodmap BaseBossProfile < ProfileObject return this.GetArray("spawn_effects"); } + public ProfileEntityInputsArray GetSpawnInputs() + { + ProfileObject obj = this.GetSection("inputs"); + if (obj != null) + { + return view_as(obj.GetSection("spawn")); + } + return null; + } + public KeyMap_Array GetDespawnEffects() { return this.GetArray("despawn_effects"); } + public ProfileEntityInputsArray GetDespawnInputs() + { + ProfileObject obj = this.GetSection("inputs"); + if (obj != null) + { + return view_as(obj.GetSection("spawn")); + } + return null; + } + + public ProfileEntityOutputsArray GetOutputs() + { + return view_as(this.GetSection("outputs")); + } + property bool HideDespawnEffectsOnDeath { public get() @@ -1111,9 +1052,23 @@ methodmap BaseBossProfile < ProfileObject return view_as(this.GetSection("client_kill_sounds")); } + public ProfileObject GetMapSelectionBlacklist() + { + ProfileObject obj = this.GetSection("selection_blacklist"); + obj = obj != null ? obj.GetSection("maps") : null; + return obj; + } + + public ProfileObject GetModeSelectionBlacklist() + { + ProfileObject obj = this.GetSection("selection_blacklist"); + obj = obj != null ? obj.GetSection("modes") : null; + return obj; + } + public void Precache() { - char path[PLATFORM_MAX_PATH]; + char path[PLATFORM_MAX_PATH], value[2048]; for (int i = 0; i < Difficulty_Max; i++) { this.GetModel(i, path, sizeof(path)); @@ -1262,6 +1217,35 @@ methodmap BaseBossProfile < ProfileObject } } + if (this.GetBool("customizable_outlines", false)) + { + newObj = this.InsertNewSection("outline"); + int color[4]; + color[0] = this.GetInt("outline_color_r", 255); + color[1] = this.GetInt("outline_color_g", 255); + color[2] = this.GetInt("outline_color_b", 255); + color[3] = this.GetInt("outline_color_transparency", 255); + ColorToString(color, value, sizeof(value)); + newObj.SetKeyValue("color", value); + newObj.TransferKey(this, "enable_rainbow_outline", "rainbow"); + newObj.TransferKey(this, "rainbow_outline_cycle_rate", "rainbow_cycle"); + } + + if (this.GetBool("is_pve")) + { + newObj = this.InsertNewSection("pve"); + newObj.TransferKey(this, "pve_spawn_message_prefix", "spawn_message_prefix"); + newObj.TransferKey(this, "pve_health_bar", "health_bar"); + newObj.TransferKey(this, "pve_selectable", "selectable"); + if (this.GetSection("pve_spawn_messages") != null) + { + temp = view_as(this.GetSection("pve_spawn_messages").Clone()); + temp.SetSectionName("spawn_messages"); + newObj.AddExistingSection(temp); + this.RemoveKey("pve_spawn_messages"); + } + } + this.ConvertSectionsSectionToArray("spawn_effects"); this.ConvertSectionsSectionToArray("despawn_effects"); @@ -1417,6 +1401,51 @@ methodmap BaseBossProfile < ProfileObject } } +methodmap BossProfilePvEData < ProfileObject +{ + property bool IsEnabled + { + public get() + { + return this != null; + } + } + + property bool IsSelectable + { + public get() + { + return this.GetBool("selectable", true); + } + } + + public ProfileObject GetSpawnMessages() + { + return this.GetSection("spawn_messages"); + } + + public void GetSpawnMessagePrefix(char[] buffer, int bufferSize) + { + this.GetString("spawn_message_prefix", buffer, bufferSize); + } + + property bool DisplayHealth + { + public get() + { + this.GetBool("health_bar", true); + } + } + + property float TeleportEndTimer + { + public get() + { + return this.GetFloat("teleport_players_time", 5.0); + } + } +} + methodmap BossProfileCopies < ProfileObject { property bool IsLegacy @@ -1606,6 +1635,24 @@ methodmap BossProfileEyeData < ProfileObject } } +methodmap BossProfileOutlineData < ProfileObject +{ + public void GetOutlineColor(int buffer[4], int difficulty) + { + this.GetDifficultyColor("color", difficulty, buffer); + } + + public bool GetRainbowState(int difficulty) + { + return this.GetDifficultyBool("rainbow", difficulty, false); + } + + public float GetRainbowCycle(int difficulty) + { + return this.GetDifficultyFloat("rainbow_cycle", difficulty, 1.0); + } +} + methodmap BossProfileSlaughterRunData < ProfileObject { public bool ShouldUseCustomMinSpeed(int difficulty) diff --git a/addons/sourcemod/scripting/sf2/pve.sp b/addons/sourcemod/scripting/sf2/pve.sp index 98ed376c..14099d47 100644 --- a/addons/sourcemod/scripting/sf2/pve.sp +++ b/addons/sourcemod/scripting/sf2/pve.sp @@ -14,6 +14,8 @@ static ArrayList g_ActiveBosses; static bool g_IsPvEActive; static bool g_DoesPvEExist; static char g_PlayerCurrentPvEMusic[MAXTF2PLAYERS][PLATFORM_MAX_PATH]; +static char g_PlayerUsedPvEMusic[MAXTF2PLAYERS][PLATFORM_MAX_PATH]; +static float g_PlayerUsedPvEMusicVolume[MAXTF2PLAYERS]; static bool g_PvEBoxingMode; static float g_TimeUntilBossSpawns; @@ -284,6 +286,18 @@ static void RoundStart() g_HasBossSpawned = false; g_ActiveBosses.Clear(); + for (int i = 1; i <= MaxClients; i++) + { + SF2_BasePlayer client = SF2_BasePlayer(i); + if (!client.IsValid) + { + continue; + } + + g_PlayerUsedPvEMusic[client.index][0] = '\0'; + g_PlayerUsedPvEMusicVolume[client.index] = 1.0; + } + int ent = -1; while ((ent = FindEntityByClassname(ent, "trigger_multiple")) != -1) { @@ -334,6 +348,9 @@ static void OnPutInServer(SF2_BasePlayer client) PvE_ForceResetPlayerPvEData(client.index); + g_PlayerUsedPvEMusic[client.index][0] = '\0'; + g_PlayerUsedPvEMusicVolume[client.index] = 1.0; + if (IsClientAuthorized(client.index)) { OnClientAuthorized(client.index, NULL_STRING); @@ -439,9 +456,9 @@ static void OnPlayerAverageUpdate(SF2_BasePlayer client) SF2_ChaserEntity chaser = SF2_ChaserEntity(EntRefToEntIndex(bosses.Get(i2))); if (chaser.IsValid() && chaser.Controller.IsValid()) { - ChaserBossProfile data = chaser.Controller.GetProfileDataEx(); + ChaserBossProfile data = chaser.Controller.GetProfileData(); data.GetName(1, name, sizeof(name)); - if (!data.DisplayPvEHealth) + if (!data.GetPvEData().DisplayHealth) { continue; } @@ -658,33 +675,43 @@ void PvE_OnTriggerStartTouch(int trigger, int other) PvE_SetPlayerPvEState(other, true); if (g_IsPvEActive && g_PvETriggers.FindValue(entRef) != -1) { - if (g_CustomMusicOverride[0] != '\0') + if (g_PlayerUsedPvEMusic[other][0] != '\0') { - EmitSoundToClient(other, g_CustomMusicOverride, _, _, _, _, 0.75); - strcopy(g_PlayerCurrentPvEMusic[other], sizeof(g_PlayerCurrentPvEMusic[]), g_CustomMusicOverride); + EmitSoundToClient(other, g_PlayerUsedPvEMusic[other], _, _, _, _, g_PlayerUsedPvEMusicVolume[other]); + strcopy(g_PlayerCurrentPvEMusic[other], sizeof(g_PlayerCurrentPvEMusic[]), g_PlayerUsedPvEMusic[other]); } else { - ArrayList musics = new ArrayList(ByteCountToCells(PLATFORM_MAX_PATH)); - ArrayList volumes = new ArrayList(); + ArrayList usableMusics = new ArrayList(ByteCountToCells(PLATFORM_MAX_PATH)); + ArrayList usableVolumes = new ArrayList(); + if (g_CustomMusicOverride[0] != '\0') + { + usableMusics.PushString(g_CustomMusicOverride); + usableVolumes.Push(0.75); + } + for (int i = 0; i < MAX_MUSICS; i++) { if (g_MusicFile[other][i][0] != '\0') { - musics.PushString(g_MusicFile[other][i]); - volumes.Push(g_MusicVolume[other][i]); + usableMusics.PushString(g_MusicFile[other][i]); + usableVolumes.Push(g_MusicVolume[other][i]); } } - if (musics.Length > 0) + + if (usableMusics.Length > 0) { char preferredMusic[PLATFORM_MAX_PATH]; - int random = GetRandomInt(0, musics.Length - 1); - musics.GetString(random, preferredMusic, sizeof(preferredMusic)); - EmitSoundToClient(other, preferredMusic, _, _, _, _, volumes.Get(random)); + int random = GetRandomInt(0, usableMusics.Length - 1); + usableMusics.GetString(random, preferredMusic, sizeof(preferredMusic)); + EmitSoundToClient(other, preferredMusic, _, _, _, _, usableVolumes.Get(random)); strcopy(g_PlayerCurrentPvEMusic[other], sizeof(g_PlayerCurrentPvEMusic[]), preferredMusic); + strcopy(g_PlayerUsedPvEMusic[other], sizeof(g_PlayerUsedPvEMusic[]), preferredMusic); + g_PlayerUsedPvEMusicVolume[other] = usableVolumes.Get(random); } - delete volumes; - delete musics; + + delete usableVolumes; + delete usableMusics; } } } @@ -875,7 +902,7 @@ static void SpawnPvEBoss(const char[] override = "") if (npc.IsValid()) { npc.Spawn(spawnPos); - ChaserBossProfile data = view_as(npc).GetProfileDataEx(); + ChaserBossProfile data = view_as(npc).GetProfileData(); ProfileSound soundInfo = data.GetGlobalMusic(1); g_PvEBoxingMode = data.BoxingBoss; if (soundInfo.Paths != null && soundInfo.Paths.Length > 0) @@ -896,7 +923,7 @@ static void SpawnPvEBoss(const char[] override = "") testNPC.Spawn(spawnPos); g_ActiveBosses.Push(EntIndexToEntRef(testNPC.EntIndex)); - BaseBossProfile tempData = testNPC.GetProfileDataEx(); + BaseBossProfile tempData = testNPC.GetProfileData(); if (tempData.GetCopies().IsEnabled(1)) { @@ -984,12 +1011,14 @@ static Action Command_AddPvEMusic(int client, int args) } bool isAvailable = false; + int index = 0; for (int i = 0; i < MAX_MUSICS; i++) { if (g_MusicFile[client][i][0] == '\0') { isAvailable = true; strcopy(g_MusicFile[client][i], sizeof(g_MusicFile[][]), soundFile); + index = i; break; } @@ -1009,6 +1038,8 @@ static Action Command_AddPvEMusic(int client, int args) PrecacheSound(soundFile); CPrintToChat(client, "{royalblue}%t {default}%T", "SF2 Prefix", "SF2 PvE Added Track", client, soundFile); + UpdateMusicToDatabase(client, index); + ClientSaveCookies(client); return Plugin_Handled; @@ -1155,10 +1186,12 @@ static int PvEMenu_SelectedMusic(Menu menu, MenuAction action, int param1, int p case 1: { + int index = 0; for (int i = 0; i < MAX_MUSICS; i++) { if (strcmp(g_MusicFile[param1][i], g_MenuMusic[param1], false) == 0) { + index = i; g_MusicFile[param1][i][0] = '\0'; g_MusicVolume[param1][i] = 0.75; g_MusicLoopTime[param1][i] = 0.0; @@ -1167,6 +1200,7 @@ static int PvEMenu_SelectedMusic(Menu menu, MenuAction action, int param1, int p } CPrintToChat(param1, "{royalblue}%t {default}%T", "SF2 Prefix", "SF2 PvE Removed Music", param1, g_MenuMusic[param1]); DisplayMusicSelectionPvE(param1); + UpdateMusicToDatabase(param1, index); } } } @@ -1189,15 +1223,20 @@ static int Panel_SettingsMusicVolume(Menu menu, MenuAction action, int param1, i { volume += 0.25; } + int index = 0; for (int i = 0; i < MAX_MUSICS; i++) { if (strcmp(g_MusicFile[param1][i], g_MenuMusic[param1], false) == 0) { g_MusicVolume[param1][i] = volume; + index = i; break; } } CPrintToChat(param1, "%t", "SF2 Music Volum Changed", RoundToNearest(volume * 100.0)); + + UpdateMusicToDatabase(param1, index); + ClientSaveCookies(param1); DisplayMusicSelectionPvE(param1); @@ -1205,6 +1244,31 @@ static int Panel_SettingsMusicVolume(Menu menu, MenuAction action, int param1, i return 0; } +static void UpdateMusicToDatabase(int client, int index) +{ + int id = GetSteamAccountID(client); + if (g_MusicDataBase != null && !IsFakeClient(client) && g_IsMusicCached[client] && id != 0) + { + Transaction action = new Transaction(); + + char formatter[512]; + FormatEx(formatter, sizeof(formatter), "UPDATE music_selection_%i SET " + ... "music_file = '%s', " + ... "music_volume = %f, " + ... "music_loop_time = %f " + ... "WHERE steamid = %d;", + index, + g_MusicFile[client][index], + g_MusicVolume[client][index], + g_MusicLoopTime[client][index], + id); + + action.AddQuery(formatter); + + g_MusicDataBase.Execute(action, _, Database_Fail, _, DBPrio_High); + } +} + // These register boss entity names to choose from void RegisterPvEBoss(char[] bossName) { @@ -1220,12 +1284,12 @@ void UnregisterPveBoss(char[] bossName) } } -void RegisterPvESlenderBoss(char profile[SF2_MAX_PROFILE_NAME_LENGTH]) +void RegisterPvESlenderBoss(const char[] profile) { g_SlenderBosses.PushString(profile); } -void UnregisterPvESlenderBoss(char profile[SF2_MAX_PROFILE_NAME_LENGTH]) +void UnregisterPvESlenderBoss(const char[] profile) { int index = g_SlenderBosses.FindString(profile); if (index != -1) @@ -1254,12 +1318,20 @@ void KillPvEBoss(int boss) float time = 5.0; if (bossIndex != -1) { - time = SF2NPC_BaseNPC(bossIndex).GetProfileDataEx().PvETeleportEndTimer; + time = SF2NPC_BaseNPC(bossIndex).GetProfileData().GetPvEData().TeleportEndTimer; } for (int i = 1; i <= MaxClients; i++) { SF2_BasePlayer client = SF2_BasePlayer(i); - if (!client.IsValid || !client.IsInPvE) + if (!client.IsValid) + { + continue; + } + + g_PlayerUsedPvEMusic[client.index][0] = '\0'; + g_PlayerUsedPvEMusicVolume[client.index] = 1.0; + + if (!client.IsInPvE) { continue; } @@ -1307,7 +1379,7 @@ static Action Timer_RemoveAllPvEBosses(Handle timer) continue; } - if (!npc.GetProfileDataEx().IsPvEBoss) + if (!npc.GetProfileData().IsPvEBoss) { continue; } diff --git a/addons/sourcemod/scripting/sf2/specialround.sp b/addons/sourcemod/scripting/sf2/specialround.sp index e0d07c99..8899c3ae 100644 --- a/addons/sourcemod/scripting/sf2/specialround.sp +++ b/addons/sourcemod/scripting/sf2/specialround.sp @@ -868,21 +868,10 @@ static ArrayList SpecialEnabledList() } } - if (!SF_IsBoxingMap()) - { - if (GetSelectableBossProfileList().Length > 0) - { - AddSpecialRoundToList(SPECIALROUND_DOUBLETROUBLE, enabledRounds); - AddSpecialRoundToList(SPECIALROUND_SILENTSLENDER, enabledRounds); - } - } - else + if (GetSelectableBossProfileList().Length > 0) { - if (GetSelectableBoxingBossProfileList().Length > 0) - { - AddSpecialRoundToList(SPECIALROUND_DOUBLETROUBLE, enabledRounds); - AddSpecialRoundToList(SPECIALROUND_SILENTSLENDER, enabledRounds); - } + AddSpecialRoundToList(SPECIALROUND_DOUBLETROUBLE, enabledRounds); + AddSpecialRoundToList(SPECIALROUND_SILENTSLENDER, enabledRounds); } if (GetActivePlayerCount() <= g_MaxPlayersConVar.IntValue * 2 && !SF_IsBoxingMap()) @@ -1066,27 +1055,13 @@ void SpecialRoundStart() case SPECIALROUND_DOUBLETROUBLE: { char buffer[SF2_MAX_PROFILE_NAME_LENGTH]; - ArrayList selectableBosses = GetSelectableBossProfileList().Clone(); - ArrayList selectableBoxingBosses = GetSelectableBoxingBossProfileList().Clone(); + ArrayList selectableBosses = GetSelectableBossProfileList(); - if (!SF_IsBoxingMap()) - { - if (selectableBosses.Length > 0) - { - selectableBosses.GetString(GetRandomInt(0, selectableBosses.Length - 1), buffer, sizeof(buffer)); - AddProfile(buffer); - } - } - else + if (selectableBosses.Length > 0) { - if (selectableBoxingBosses.Length > 0) - { - selectableBoxingBosses.GetString(GetRandomInt(0, selectableBoxingBosses.Length - 1), buffer, sizeof(buffer)); - AddProfile(buffer); - } + selectableBosses.GetString(GetRandomInt(0, selectableBosses.Length - 1), buffer, sizeof(buffer)); + AddProfile(buffer); } - delete selectableBosses; - delete selectableBoxingBosses; SF_AddSpecialRound(SPECIALROUND_DOUBLETROUBLE); } case SPECIALROUND_SILENTSLENDER: @@ -1102,8 +1077,7 @@ void SpecialRoundStart() } char buffer[SF2_MAX_PROFILE_NAME_LENGTH]; - ArrayList selectableBosses = GetSelectableBossProfileList().Clone(); - ArrayList selectableBoxingBosses = GetSelectableBoxingBossProfileList().Clone(); + ArrayList selectableBosses = GetSelectableBossProfileList(); if (selectableBosses.Length > 0) { @@ -1119,8 +1093,6 @@ void SpecialRoundStart() selectableBosses.GetString(GetRandomInt(0, selectableBosses.Length - 1), buffer, sizeof(buffer)); AddProfile(buffer, _, _, _, false); } - delete selectableBosses; - delete selectableBoxingBosses; SF_AddSpecialRound(SPECIALROUND_SILENTSLENDER); } case SPECIALROUND_THANATOPHOBIA: diff --git a/addons/sourcemod/scripting/sf2/stocks.sp b/addons/sourcemod/scripting/sf2/stocks.sp index d7b538b8..00c79ebd 100644 --- a/addons/sourcemod/scripting/sf2/stocks.sp +++ b/addons/sourcemod/scripting/sf2/stocks.sp @@ -1579,7 +1579,7 @@ int GetLocalGlobalDifficulty(int npcIndex = -1) return g_DifficultyConVar.IntValue; } SF2NPC_BaseNPC controller = SF2NPC_BaseNPC(npcIndex); - ChaserBossProfile data = view_as(controller.GetProfileDataEx()); + ChaserBossProfile data = view_as(controller.GetProfileData()); if (data.IsPvEBoss || data.BoxingBoss) { if (NPCGetUniqueID(npcIndex) != -1) diff --git a/addons/sourcemod/scripting/sf2/traps.sp b/addons/sourcemod/scripting/sf2/traps.sp index fa837bc9..c7a395a3 100644 --- a/addons/sourcemod/scripting/sf2/traps.sp +++ b/addons/sourcemod/scripting/sf2/traps.sp @@ -65,7 +65,7 @@ void Trap_SpawnTrap(float position[3], float direction[3], SF2NPC_Chaser control float yaw = GetAngleBetweenVectors(product2, cross, tempAngles); RotateYaw(newAngles, yaw - 90.0); - ChaserBossProfile data = controller.GetProfileDataEx(); + ChaserBossProfile data = controller.GetProfileData(); int difficulty = controller.Difficulty; char buffer[PLATFORM_MAX_PATH]; @@ -217,7 +217,7 @@ static Action Timer_TrapThink(Handle timer, any entref) player.TakeDamage(true, _, _, 10.0, 128); g_TrapState[trapEntity] = 1; g_TrapAnimChange[trapEntity] = true; - ChaserBossProfile data = controller.GetProfileDataEx(); + ChaserBossProfile data = controller.GetProfileData(); char buffer[PLATFORM_MAX_PATH]; data.GetTrapCatchSound(buffer, sizeof(buffer)); EmitSoundToAll(buffer, trapEntity, SNDCHAN_AUTO, SNDLEVEL_SCREAMING, _, 1.0); @@ -246,7 +246,7 @@ static void TrapUpdateAnimation(int trapEntity) { return; } - ChaserBossProfile data = controller.GetProfileDataEx(); + ChaserBossProfile data = controller.GetProfileData(); char buffer[PLATFORM_MAX_PATH]; switch (state) { @@ -305,7 +305,7 @@ static Action Hook_TrapOnTakeDamage(int trapEntity, int &attacker, int &inflicto g_TrapState[trapEntity] = 1; g_TrapAnimChange[trapEntity] = true; SF2NPC_Chaser controller = g_TrapMaster[trapEntity]; - ChaserBossProfile data = controller.GetProfileDataEx(); + ChaserBossProfile data = controller.GetProfileData(); char buffer[PLATFORM_MAX_PATH]; data.GetTrapMissSound(buffer, sizeof(buffer)); EmitSoundToAll(buffer, trapEntity, SNDCHAN_AUTO, SNDLEVEL_SCREAMING, _, 1.0); From aa8487f27fa0e211ff0f56722137417e9f13222c Mon Sep 17 00:00:00 2001 From: Mentrillum Date: Wed, 25 Dec 2024 22:02:31 -0700 Subject: [PATCH 4/5] Wait let me try that again --- addons/sourcemod/scripting/sf2/profiles/objects.sp | 9 ++++++++- .../scripting/sf2/profiles/profiles_boss_functions.sp | 10 ++++++++++ 2 files changed, 18 insertions(+), 1 deletion(-) diff --git a/addons/sourcemod/scripting/sf2/profiles/objects.sp b/addons/sourcemod/scripting/sf2/profiles/objects.sp index a95f3c5b..ca3e99ee 100644 --- a/addons/sourcemod/scripting/sf2/profiles/objects.sp +++ b/addons/sourcemod/scripting/sf2/profiles/objects.sp @@ -846,7 +846,14 @@ methodmap ProfileObject < KeyMap { return; } - this.SetKeyValue(newKey, keyValue); + if (this.ContainsKey(newKey)) + { + this.Super.Super.SetString(newKey, keyValue); + } + else + { + this.SetKeyValue(newKey, keyValue); + } } public void TransferDifficultyKey(ProfileObject target, const char[] oldKey, const char[] newKey, int difficulty) diff --git a/addons/sourcemod/scripting/sf2/profiles/profiles_boss_functions.sp b/addons/sourcemod/scripting/sf2/profiles/profiles_boss_functions.sp index 8cfc5b28..d2ae0f42 100644 --- a/addons/sourcemod/scripting/sf2/profiles/profiles_boss_functions.sp +++ b/addons/sourcemod/scripting/sf2/profiles/profiles_boss_functions.sp @@ -1246,6 +1246,16 @@ methodmap BaseBossProfile < ProfileObject } } + if (this.GetBool("enable_random_selection_boxing")) + { + this.TransferKey(this, "enable_random_selection_boxing", "enable_random_selection"); + } + + if (this.GetBool("enable_random_selection_renevant")) + { + this.TransferKey(this, "enable_random_selection_renevant", "enable_random_selection"); + } + this.ConvertSectionsSectionToArray("spawn_effects"); this.ConvertSectionsSectionToArray("despawn_effects"); From d36a91888e22e4449b26be502aa840aa0cb46011 Mon Sep 17 00:00:00 2001 From: Mentrillum Date: Wed, 25 Dec 2024 22:06:36 -0700 Subject: [PATCH 5/5] Alright, let's finish this! Merasmus is...getting a little bored watching you! --- addons/sourcemod/scripting/sf2/profiles/objects.sp | 2 -- 1 file changed, 2 deletions(-) diff --git a/addons/sourcemod/scripting/sf2/profiles/objects.sp b/addons/sourcemod/scripting/sf2/profiles/objects.sp index ca3e99ee..6119db20 100644 --- a/addons/sourcemod/scripting/sf2/profiles/objects.sp +++ b/addons/sourcemod/scripting/sf2/profiles/objects.sp @@ -1625,8 +1625,6 @@ methodmap ProfileEntityOutputObject < ProfileObject char[] addOutput = new char[size]; FormatEx(addOutput, size, "EntityOutputs.AddOutput(self, `%s`, `%s`, `%s`, `%s`, %0.3f, %d)", output, target, input, parameter, this.GetDelay(), this.GetTimesToFire()); - PrintToChatAll("%s", addOutput); - SetVariantString(addOutput); AcceptEntityInput(entity, "RunScriptCode"); }