{"TotalCount":222,"Files":[{"Ident":"facepunch.ss1","Path":"ui/panels/infopanel.razor.scss","FileName":"infopanel.razor.scss","PackageType":"game","CodeKind":"Game","AssetVersionId":421898,"IsPrivate":false,"Code":"InfoPanel {\r\n    position: absolute;\r\n    width: 280px;\r\n    left: 20px;\r\n    bottom: 20px;\r\n    top: 20px;\r\n    align-self: flex-end;\r\n    pointer-events: none;\r\n    justify-content: flex-start;\r\n    flex-direction: column-reverse;\r\n    gap: 10px;\r\n    //background-color: red;\r\n\r\n    .info_dash_container {\r\n        width: 100%;\r\n        //flex-direction: column-reverse;\r\n        flex-direction: row;\r\n        align-items: center;\r\n        gap: 8px;\r\n    }\r\n\r\n    .dash {\r\n        position: relative;\r\n        flex-shrink: 1;\r\n        width: 100%;\r\n        height: 28px;\r\n        background-color: #0005;\r\n    }\r\n\r\n    .info_bar {\r\n        position: relative;\r\n        width: 100%;\r\n        overflow: hidden;\r\n        height: 28px;\r\n        background-color: #00000099;\r\n        //border-left: 2px solid #fff;\r\n        //border-right: 2px solid #fff;\r\n        flex-shrink: 1;\r\n        //border: 2px solid black;\r\n\r\n        .info_bar_overlay {\r\n            position: absolute;\r\n            left: 0px;\r\n            width: 100%;\r\n            height: 100%;\r\n        }\r\n    }\r\n\r\n    .data_container {\r\n        width: 100%;\r\n        height: 100%;\r\n        flex-direction: row-reverse;\r\n    }\r\n\r\n    .info_bar_label {\r\n        position: absolute;\r\n        color: #fff;\r\n        font-size: 26px;\r\n        align-items: center;\r\n        font-weight: bolder;\r\n        font-family: \u0022Mini Pixel-7\u0022;\r\n        //width: 100%;\r\n        left: 0px;\r\n        justify-content: flex-start;\r\n        padding-left: 5px;\r\n        padding-top: 1px;\r\n        text-stroke: 5px black;\r\n        opacity: 0.7;\r\n    }\r\n\r\n    .data {\r\n        position: relative;\r\n        color: #ffffffaa;\r\n        font-size: 26px;\r\n        align-items: center;\r\n        font-family: \u0022Mini Pixel-7\u0022;\r\n        //left: 0px;\r\n        padding-right: 5px;\r\n        padding-top: 1px;\r\n        text-stroke: 5px black;\r\n        opacity: 0.9;\r\n        //letter-spacing: 1px;\r\n    }\r\n    //.data_center {\r\n    //    position: absolute;\r\n    //    color: #ffffff88;\r\n    //    font-size: 26px;\r\n    //    align-items: center;\r\n    //    justify-content: center;\r\n    //    font-family: \u0022Mini Pixel-7\u0022;\r\n    //left: 0px;\r\n    //    width: 100%;\r\n    //    padding-left: 5px;\r\n    //    padding-top: 1px;\r\n    //    text-stroke: 3px #00000099;\r\n    //    opacity: 0.9;\r\n    //}\r\n}\r\n"},{"Ident":"facepunch.ss1","Path":"Camera2D.cs","FileName":"Camera2D.cs","PackageType":"game","CodeKind":"Game","AssetVersionId":421898,"IsPrivate":false,"Code":"using Sandbox;\r\n\r\npublic class Camera2D : Component\r\n{\r\n\t[Property] public CameraComponent Camera { get; set; }\r\n\r\n\tpublic Vector2 TargetPos { get; set; }\r\n\tpublic Vector2 CameraPos { get; set; }\r\n\r\n\tprotected override void OnUpdate()\r\n\t{\r\n\t\tbase.OnUpdate();\r\n\r\n\t\t//Vector2 newPos = Vector2.Lerp( (Vector2)WorldPosition, TargetPos, Time.Delta * 3f );\r\n\t\tCameraPos = Utils.DynamicEaseTo( CameraPos, TargetPos, 0.2f, Time.Delta );\r\n\r\n\t\tvar newPos = CameraPos \u002B Utils.GetRandomVector() * Manager.Instance.Player.CamShakeAmount;\r\n\r\n\t\tfloat bounds_zoom = 1f \u002B Manager.Instance.Player.Stats[PlayerStat.ZoomAmount] * 0.44f;\r\n\t\tvar XDIST = 10.75f / bounds_zoom;\r\n\t\tvar Y_MIN = -8.8f / bounds_zoom;\r\n\t\tvar Y_MAX = 8.9f / bounds_zoom;\r\n\t\tnewPos = new Vector2( MathX.Clamp( newPos.x, -XDIST, XDIST ), MathX.Clamp( newPos.y, Y_MIN, Y_MAX ) );\r\n\r\n\t\tWorldPosition = ((Vector3)newPos).WithZ( WorldPosition.z );\r\n\t}\r\n\r\n\tpublic void SetPos( Vector2 pos )\r\n\t{\r\n\t\tCameraPos = pos;\r\n\t\tTargetPos = pos;\r\n\t\tWorldPosition = ((Vector3)pos).WithZ( WorldPosition.z );\r\n\t}\r\n}\r\n"},{"Ident":"facepunch.ss1","Path":"FloatingDamageNumber.cs","FileName":"FloatingDamageNumber.cs","PackageType":"game","CodeKind":"Game","AssetVersionId":421898,"IsPrivate":false,"Code":"using Sandbox;\r\n\r\npublic class FloatingDamageNumber : Component\r\n{\r\n\tprivate RealTimeSince _timeSince;\r\n\r\n\tprotected override void OnAwake()\r\n\t{\r\n\t\tbase.OnAwake();\r\n\r\n\t\t_timeSince = 0f;\r\n\t}\r\n\r\n\tprotected override void OnUpdate()\r\n\t{\r\n\t\tbase.OnUpdate();\r\n\r\n\t\tif ( _timeSince \u003E 1f )\r\n\t\t\tGameObject.Destroy();\r\n\t}\r\n}\r\n"},{"Ident":"facepunch.ss1","Path":"LavaPuddle.cs","FileName":"LavaPuddle.cs","PackageType":"game","CodeKind":"Game","AssetVersionId":421898,"IsPrivate":false,"Code":"using Sandbox.UI;\r\nusing System;\r\nusing System.Collections.Generic;\r\nusing System.Linq;\r\nusing System.Linq.Expressions;\r\nusing System.Text;\r\nusing System.Threading.Tasks;\r\nusing static Manager;\r\n\r\npublic class LavaPuddle : Component\r\n{\r\n\t[Property] public Sprite2D Sprite { get; set; }\r\n\r\n\tpublic TimeSince TimeSinceSpawn { get; set; }\r\n\tpublic float Lifetime { get; set; }\r\n\t\r\n\tpublic float Radius { get; set; }\r\n\tpublic float FullRadius { get; set; }\r\n\r\n\tprivate float _timeOffset;\r\n\tprivate TimeSince _timeSinceDamagePlayer;\r\n\tprivate const float DAMAGE_INTERVAL = 0.25f;\r\n\r\n\tprivate float _expandTime;\r\n\r\n\tpublic float DamageToPlayer { get; set; }\r\n\r\n\tpublic Color ColorA { get; set; }\r\n\tpublic Color ColorB { get; set; }\r\n\r\n\tpublic Vector2 Position2D\r\n\t{\r\n\t\tget { return (Vector2)WorldPosition; }\r\n\t\tset { WorldPosition = new Vector3( value.x, value.y, WorldPosition.z ); }\r\n\t}\r\n\r\n\tprotected override void OnAwake()\r\n\t{\r\n\t\tbase.OnAwake();\r\n\r\n\t\tif ( Game.Random.Float( 0f, 1f ) \u003C 0.5f )\r\n\t\t\tSprite.SpriteFlags = SpriteFlags.HorizontalFlip;\r\n\r\n\t\tRadius = 0f;\r\n\t\tLocalScale = new Vector3( Radius * 1f, Radius * 1.06f, 1f ) * 2f * Globals.SPRITE_SCALE;\r\n\r\n\t\t//LocalScale = new Vector3( Game.Random.Float( 0.4f, 0.6f ), Game.Random.Float( 0.15f, 0.25f ), 1f ) * Globals.SPRITE_SCALE;\r\n\t\t//LocalScale = new Vector3( Game.Random.Float( 0.33f, 0.48f ), Game.Random.Float( 0.4f, 0.63f ), 1f ) * 5f * Globals.SPRITE_SCALE;\r\n\r\n\t\t_timeOffset = Game.Random.Float( 0f, 99f );\r\n\r\n\t\tTimeSinceSpawn = 0f;\r\n\t\t_expandTime = Game.Random.Float( 0.4f, 0.5f );\r\n\r\n\t\tDamageToPlayer = 2f \u002B Math.Min(Manager.Instance.Difficulty, 5);\r\n\t}\r\n\r\n\tprotected override void OnUpdate()\r\n\t{\r\n\t\tbase.OnUpdate();\r\n\r\n\t\tfloat FADE_IN_TIME = 0.3f;\r\n\t\tvar color = Color.Lerp( ColorA, ColorB, 0.5f \u002B Utils.FastSin( TimeSinceSpawn * 16f ) * 0.5f );\r\n\t\tvar opacity = 0.3f \r\n\t\t\t* Utils.Map( TimeSinceSpawn, 0f, FADE_IN_TIME, 0f, 1f, EasingType.SineOut ) \r\n\t\t\t* Utils.Map( TimeSinceSpawn, Lifetime - 1f, Lifetime, 1f, 0f, EasingType.SineIn ) \r\n\t\t\t* ( 0.85f \u002B Utils.FastSin( _timeOffset \u002B Time.Now * 16f ) * 0.15f );\r\n\t\tSprite.Tint = color.WithAlpha( opacity );\r\n\r\n\t\t//Gizmo.Draw.Color = Color.White.WithAlpha( 0.05f );\r\n\t\t//Gizmo.Draw.LineSphere( WorldPosition, Radius, 20 );\r\n\r\n\t\tif (TimeSinceSpawn \u003C _expandTime )\r\n\t\t{\r\n\t\t\tRadius = Utils.Map( TimeSinceSpawn, 0f, _expandTime, FullRadius * 0.05f, FullRadius, EasingType.QuadOut );\r\n\t\t\tLocalScale = new Vector3( Radius * 0.98f, Radius * 1.06f, 1f ) * 2f * Globals.SPRITE_SCALE;\r\n\t\t}\r\n\r\n\t\tif ( TimeSinceSpawn \u003E Lifetime )\r\n\t\t{\r\n\t\t\tManager.Instance.RemoveLavaPuddle( this );\r\n\t\t\tGameObject.Destroy();\r\n\t\t\treturn;\r\n\t\t}\r\n\r\n\t\tif( TimeSinceSpawn \u003E FADE_IN_TIME \u0026\u0026 TimeSinceSpawn \u003C Lifetime - 0.5f ) \r\n\t\t{\r\n\t\t\tvar player = Manager.Instance.Player;\r\n\t\t\tfloat distSqr = (player.Position2D - Position2D).LengthSquared;\r\n\r\n\t\t\tif( distSqr \u003C MathF.Pow(Radius, 1.9f) \u0026\u0026 _timeSinceDamagePlayer \u003E DAMAGE_INTERVAL \u0026\u0026 player.TimeSinceHurtLava \u003E DAMAGE_INTERVAL \u0026\u0026 !player.IsDead )\r\n\t\t\t{\r\n\t\t\t\tfloat currDmg = Utils.Map( TimeSinceSpawn, FADE_IN_TIME, FADE_IN_TIME * 2f, 1f, DamageToPlayer );\r\n\t\t\t\tfloat dmg = player.CheckDamageAmount( currDmg, DamageType.LavaPuddle );\r\n\r\n\t\t\t\tif ( !player.IsInvulnerable \u0026\u0026 !player.IsTimePausedForChoosing )\r\n\t\t\t\t{\r\n\t\t\t\t\tplayer.Damage( dmg );\r\n\r\n\t\t\t\t\t_timeSinceDamagePlayer = 0f;\r\n\t\t\t\t\tplayer.TimeSinceHurtLava = 0f;\r\n\r\n\t\t\t\t\tManager.Instance.PlaySfxNearby( \u0022lava_puddle_03\u0022, player.Position2D, pitch: Game.Random.Float( 0.9f, 1.1f ), volume: 1f, maxDist: 4f );\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t}\r\n\t}\r\n}\r\n"},{"Ident":"facepunch.ss1","Path":"status/BulletLifetimeDamageStatus.cs","FileName":"BulletLifetimeDamageStatus.cs","PackageType":"game","CodeKind":"Game","AssetVersionId":421898,"IsPrivate":false,"Code":"using System;\r\nusing System.Collections.Generic;\r\nusing System.Linq;\r\nusing Sandbox;\r\n\r\n[Status( 5, 0, 1f, 0, false )]\r\npublic class BulletLifetimeDamageStatus : Status\r\n{\r\n\tpublic BulletLifetimeDamageStatus()\r\n\t{\r\n\t\tTitle = \u0022Growing Bullets\u0022;\r\n\t\tIconPath = \u0022textures/icons/bullet_lifetime_damage.png\u0022;\r\n\t}\r\n\r\n\tpublic override void Init( Player player )\r\n\t{\r\n\t\tbase.Init( player );\r\n\t}\r\n\r\n\tpublic override void Refresh()\r\n\t{\r\n\t\tDescription = GetDescription( Level );\r\n\r\n\t\tPlayer.Modify( this, PlayerStat.BulletDamageGrow, GetAddForLevel( Level ), ModifierType.Add );\r\n\t}\r\n\r\n\tpublic override string GetDescription( int newLevel )\r\n\t{\r\n\t\treturn string.Format( \u0022Bullets grow their damage by {0} per second\u0022, GetPrintAmountForLevel( Level ) );\r\n\t}\r\n\r\n\tpublic override string GetUpgradeDescription( int newLevel )\r\n\t{\r\n\t\treturn newLevel \u003E 1 ? string.Format( \u0022Bullets grow their damage by {0}\u2192{1} per second\u0022, GetPrintAmountForLevel( newLevel - 1 ), GetPrintAmountForLevel( newLevel ) ) : GetDescription( newLevel );\r\n\t}\r\n\r\n\tpublic float GetAddForLevel( int level )\r\n\t{\r\n\t\treturn 0.2f \u002B 1.5f * level \u002B (level == 7 ? 1.5f : 0f);\r\n\t}\r\n\r\n\tpublic string GetPrintAmountForLevel( int level )\r\n\t{\r\n\t\treturn string.Format( \u0022{0:0.0}\u0022, GetAddForLevel( level ) );\r\n\t}\r\n}\r\n"},{"Ident":"facepunch.ss1","Path":"status/CritChanceStatus.cs","FileName":"CritChanceStatus.cs","PackageType":"game","CodeKind":"Game","AssetVersionId":421898,"IsPrivate":false,"Code":"using System;\r\nusing System.Collections.Generic;\r\nusing System.Linq;\r\nusing Sandbox;\r\n\r\n[Status( 7, 0, 1f, 0, false )]\r\npublic class CritChanceStatus : Status\r\n{\r\n\tpublic CritChanceStatus()\r\n\t{\r\n\t\tTitle = \u0022Sharp Bullets\u0022;\r\n\t\tIconPath = \u0022textures/icons/crit_chance.png\u0022;\r\n\t}\r\n\r\n\tpublic override void Init( Player player )\r\n\t{\r\n\t\tbase.Init( player );\r\n\t}\r\n\r\n\tpublic override void Refresh()\r\n\t{\r\n\t\tDescription = GetDescription( Level );\r\n\r\n\t\tPlayer.Modify( this, PlayerStat.CritChance, GetAddForLevel( Level ), ModifierType.Add );\r\n\t}\r\n\r\n\tpublic override string GetDescription( int newLevel )\r\n\t{\r\n\t\treturn string.Format( \u0022Increase critical chance from 5%\u2192{0}%\u0022, GetPercentForLevel( Level ) );\r\n\t}\r\n\r\n\tpublic override string GetUpgradeDescription( int newLevel )\r\n\t{\r\n\t\treturn newLevel \u003E 1 ? string.Format( \u0022Increase critical chance from {0}%\u2192{1}%\u0022, GetPercentForLevel( newLevel - 1 ), GetPercentForLevel( newLevel ) ) : GetDescription( newLevel );\r\n\t}\r\n\r\n\tpublic float GetAddForLevel( int level )\r\n\t{\r\n\t\treturn 0.05f \u002B 0.08f * level \u002B (level == 7 ? 0.04f : 0f);\r\n\t}\r\n\r\n\tpublic float GetPercentForLevel( int level )\r\n\t{\r\n\t\treturn 5 \u002B 8 * level \u002B (level == 7 ? 4 : 0);\r\n\t}\r\n}\r\n"},{"Ident":"facepunch.ss1","Path":"status/CurseAimDir.cs","FileName":"CurseAimDir.cs","PackageType":"game","CodeKind":"Game","AssetVersionId":421898,"IsPrivate":false,"Code":"using System;\r\nusing System.Collections.Generic;\r\nusing System.Linq;\r\nusing Sandbox;\r\n\r\n[Status(4, 0, 0.5f, 0, true)]\r\npublic class CurseAimDir : Status\r\n{\r\n\tpublic CurseAimDir()\r\n    {\r\n\t\tTitle = \u0022Random Aim\u0022;\r\n\t\tIconPath = \u0022textures/icons/curse_shoot_random_dir.png\u0022;\r\n\t}\r\n\r\n\tpublic override void Init(Player player)\r\n\t{\r\n\t\tbase.Init(player);\r\n\t}\r\n\r\n\tpublic override void Refresh()\r\n    {\r\n\t\tDescription = GetDescription(Level);\r\n\r\n\t\tPlayer.Modify(this, PlayerStat.ShootRandomDirChance, GetChanceForLevel(Level), ModifierType.Add);\r\n\t}\r\n\r\n\tpublic override string GetDescription( int newLevel )\r\n\t{\r\n\t\treturn string.Format( \u0022{0}% chance to shoot in a random direction\u0022, GetPercentForLevel( Level ) );\r\n\t}\r\n\r\n\tpublic override string GetUpgradeDescription( int newLevel )\r\n\t{\r\n\t\treturn newLevel \u003E 1 ? string.Format( \u0022{0}%\u2192{1}% chance to shoot in a random direction\u0022, GetPercentForLevel( newLevel - 1 ), GetPercentForLevel( newLevel ) ) : GetDescription( newLevel );\r\n\t}\r\n\r\n\tpublic float GetChanceForLevel( int level )\r\n\t{\r\n\t\treturn 0.25f * level;\r\n\t}\r\n\r\n\tpublic float GetPercentForLevel( int level )\r\n\t{\r\n\t\treturn 25 * level;\r\n\t}\r\n}\r\n"},{"Ident":"facepunch.ss1","Path":"status/CurseAttackSpeedStatus.cs","FileName":"CurseAttackSpeedStatus.cs","PackageType":"game","CodeKind":"Game","AssetVersionId":421898,"IsPrivate":false,"Code":"using System;\r\nusing System.Collections.Generic;\r\nusing System.Linq;\r\nusing Sandbox;\r\n\r\n[Status( 7, 0, 1f, 0, true )]\r\npublic class CurseAttackSpeedStatus : Status\r\n{\r\n\tpublic CurseAttackSpeedStatus()\r\n\t{\r\n\t\tTitle = \u0022Lazy Shooting\u0022;\r\n\t\tIconPath = \u0022textures/icons/curse_attack_speed.png\u0022;\r\n\t}\r\n\r\n\tpublic override void Init( Player player )\r\n\t{\r\n\t\tbase.Init( player );\r\n\t}\r\n\r\n\tpublic override void Refresh()\r\n\t{\r\n\t\tDescription = GetDescription( Level );\r\n\r\n\t\tPlayer.Modify( this, PlayerStat.AttackSpeed, GetMultForLevel( Level ), ModifierType.Mult );\r\n\t}\r\n\r\n\tpublic override string GetDescription( int newLevel )\r\n\t{\r\n\t\treturn string.Format( \u0022Decrease attack speed by {0}%\u0022, GetPercentForLevel( Level ) );\r\n\t}\r\n\r\n\tpublic override string GetUpgradeDescription( int newLevel )\r\n\t{\r\n\t\treturn newLevel \u003E 1 ? string.Format( \u0022Decrease attack speed by {0}%\u2192{1}%\u0022, GetPercentForLevel( newLevel - 1 ), GetPercentForLevel( newLevel ) ) : GetDescription( newLevel );\r\n\t}\r\n\r\n\tpublic float GetMultForLevel( int level )\r\n\t{\r\n\t\treturn 1f - 0.20f * level;\r\n\t}\r\n\r\n\tpublic float GetPercentForLevel( int level )\r\n\t{\r\n\t\treturn 20 * level;\r\n\t}\r\n}\r\n"},{"Ident":"facepunch.ss1","Path":"status/DashStrengthStatus.cs","FileName":"DashStrengthStatus.cs","PackageType":"game","CodeKind":"Game","AssetVersionId":421898,"IsPrivate":false,"Code":"using System;\r\nusing System.Collections.Generic;\r\nusing System.Linq;\r\nusing Sandbox;\r\n\r\n[Status( 4, 0, 1f, 0, false )]\r\npublic class DashStrengthStatus : Status\r\n{\r\n\tpublic DashStrengthStatus()\r\n\t{\r\n\t\tTitle = \u0022Leg Day\u0022;\r\n\t\tIconPath = \u0022textures/icons/dash_strength.png\u0022;\r\n\t}\r\n\r\n\tpublic override void Init( Player player )\r\n\t{\r\n\t\tbase.Init( player );\r\n\t}\r\n\r\n\tpublic override void Refresh()\r\n\t{\r\n\t\tDescription = GetDescription( Level );\r\n\r\n\t\tPlayer.Modify( this, PlayerStat.DashStrength, GetMultForLevel( Level ), ModifierType.Mult );\r\n\t\tPlayer.Modify( this, PlayerStat.DashInvulnTime, GetMultForLevel( Level ), ModifierType.Mult );\r\n\t}\r\n\r\n\tpublic override string GetDescription( int newLevel )\r\n\t{\r\n\t\treturn string.Format( \u0022You dash {0}% longer\u0022, GetPercentForLevel( Level ) );\r\n\t}\r\n\r\n\tpublic override string GetUpgradeDescription( int newLevel )\r\n\t{\r\n\t\treturn newLevel \u003E 1 ? string.Format( \u0022You dash {0}%\u2192{1}% longer\u0022, GetPercentForLevel( newLevel - 1 ), GetPercentForLevel( newLevel ) ) : GetDescription( newLevel );\r\n\t}\r\n\r\n\tpublic float GetMultForLevel( int level )\r\n\t{\r\n\t\treturn 1f \u002B 0.18f * level \u002B (level == 4 ? 0.03f : 0f);\r\n\t}\r\n\r\n\tpublic float GetPercentForLevel( int level )\r\n\t{\r\n\t\treturn 18 * level \u002B (level == 4 ? 3 : 0);\r\n\t}\r\n}\r\n"},{"Ident":"facepunch.ss1","Path":"status/FearDropGrenadeStatus.cs","FileName":"FearDropGrenadeStatus.cs","PackageType":"game","CodeKind":"Game","AssetVersionId":421898,"IsPrivate":false,"Code":"using System;\r\nusing System.Collections.Generic;\r\nusing System.Linq;\r\nusing Sandbox;\r\n\r\n[Status( 7, 0, 1f, 0, false, typeof( DashFearStatus ), typeof( GrenadeFearStatus ) )]\r\npublic class FearDropGrenadeStatus : Status\r\n{\r\n\tpublic FearDropGrenadeStatus()\r\n\t{\r\n\t\tTitle = \u0022Bomb Curse\u0022;\r\n\t\tIconPath = \u0022textures/icons/fear_drop_grenade.png\u0022;\r\n\t}\r\n\r\n\tpublic override void Init( Player player )\r\n\t{\r\n\t\tbase.Init( player );\r\n\t}\r\n\r\n\tpublic override void Refresh()\r\n\t{\r\n\t\tDescription = GetDescription( Level );\r\n\r\n\t\tPlayer.Modify( this, PlayerStat.FearDropGrenadeChance, GetAddForLevel( Level ), ModifierType.Add ); ;\r\n\t}\r\n\r\n\tpublic override string GetDescription( int newLevel )\r\n\t{\r\n\t\treturn string.Format( \u0022Enemies you scare have a {0}% chance to drop a grenade on death\u0022, GetPercentForLevel( Level ) );\r\n\t}\r\n\r\n\tpublic override string GetUpgradeDescription( int newLevel )\r\n\t{\r\n\t\treturn newLevel \u003E 1 ? string.Format( \u0022Enemies you scare have a {0}%\u2192{1}% chance to drop a grenade on death\u0022, GetPercentForLevel( newLevel - 1 ), GetPercentForLevel( newLevel ) ) : GetDescription( newLevel );\r\n\t}\r\n\r\n\tpublic float GetAddForLevel( int level )\r\n\t{\r\n\t\treturn level * 0.07f;\r\n\t}\r\n\r\n\tpublic float GetPercentForLevel( int level )\r\n\t{\r\n\t\treturn level * 7;\r\n\t}\r\n}\r\n"},{"Ident":"facepunch.ss1","Path":"status/FearPainStatus.cs","FileName":"FearPainStatus.cs","PackageType":"game","CodeKind":"Game","AssetVersionId":421898,"IsPrivate":false,"Code":"using System;\r\nusing System.Collections.Generic;\r\nusing System.Linq;\r\nusing Sandbox;\r\n\r\n[Status( 5, 0, 1f, 0, false, typeof( DashFearStatus ), typeof( GrenadeFearStatus ) )]\r\npublic class FearPainStatus : Status\r\n{\r\n\tpublic FearPainStatus()\r\n\t{\r\n\t\tTitle = \u0022Killer Stress\u0022;\r\n\t\tIconPath = \u0022textures/icons/fear_pain.png\u0022;\r\n\t}\r\n\r\n\tpublic override void Init( Player player )\r\n\t{\r\n\t\tbase.Init( player );\r\n\t}\r\n\r\n\tpublic override void Refresh()\r\n\t{\r\n\t\tDescription = GetDescription( Level );\r\n\r\n\t\tPlayer.Modify( this, PlayerStat.FearPainPercent, GetAddForLevel( Level ), ModifierType.Add );\r\n\t}\r\n\r\n\tpublic override string GetDescription( int newLevel )\r\n\t{\r\n\t\treturn string.Format( \u0022Enemies you scare lose {0}% of their remaining HP each second\u0022, GetPercentForLevel( Level ) );\r\n\t}\r\n\r\n\tpublic override string GetUpgradeDescription( int newLevel )\r\n\t{\r\n\t\treturn newLevel \u003E 1 ? string.Format( \u0022Enemies you scare lose {0}%\u2192{1}% of their remaining HP each second\u0022, GetPercentForLevel( newLevel - 1 ), GetPercentForLevel( newLevel ) ) : GetDescription( newLevel );\r\n\t}\r\n\r\n\tpublic float GetAddForLevel( int level )\r\n\t{\r\n\t\treturn 0.02f \u002B level * 0.07f \u002B (level == 5 ? 0.01f : 0f);\r\n\t}\r\n\r\n\tpublic float GetPercentForLevel( int level )\r\n\t{\r\n\t\treturn 2 \u002B level * 7 \u002B (level == 5 ? 1 : 0);\r\n\t}\r\n}\r\n"},{"Ident":"facepunch.ss1","Path":"status/GrenadeFearStatus.cs","FileName":"GrenadeFearStatus.cs","PackageType":"game","CodeKind":"Game","AssetVersionId":421898,"IsPrivate":false,"Code":"using System;\r\nusing System.Collections.Generic;\r\nusing System.Linq;\r\nusing Sandbox;\r\n\r\n[Status(4, 0, 1f, 0, false, typeof(GrenadeShootReloadStatus), typeof(FearDropGrenadeStatus))]\r\npublic class GrenadeFearStatus : Status\r\n{\r\n    public GrenadeFearStatus()\r\n    {\r\n        Title = \u0022Terrorism\u0022;\r\n        IconPath = \u0022textures/icons/grenade_fear.png\u0022;\r\n    }\r\n\r\n    public override void Init(Player player)\r\n    {\r\n        base.Init(player);\r\n    }\r\n\r\n    public override void Refresh()\r\n    {\r\n        Description = GetDescription(Level);\r\n\r\n        Player.Modify(this, PlayerStat.GrenadeFearChance, GetAddForLevel(Level), ModifierType.Add); ;\r\n    }\r\n\r\n    public override string GetDescription(int newLevel)\r\n    {\r\n        return string.Format(\u0022Your grenades have a {0}% chance to scare enemies they hurt\u0022, GetPercentForLevel(Level));\r\n    }\r\n\r\n    public override string GetUpgradeDescription(int newLevel)\r\n    {\r\n        return newLevel \u003E 1 ? string.Format(\u0022Your grenades have a {0}%\u2192{1}% chance to scare enemies they hurt\u0022, GetPercentForLevel(newLevel - 1), GetPercentForLevel(newLevel)) : GetDescription(newLevel);\r\n    }\r\n\r\n    public float GetAddForLevel(int level)\r\n    {\r\n        return level == 4 ? 1f : 0.3f * level;\r\n    }\r\n\r\n    public float GetPercentForLevel(int level)\r\n    {\r\n        return level == 4 ? 100 : 30 * level;\r\n    }\r\n}\r\n"},{"Ident":"facepunch.ss1","Path":"status/KillHealStatus.cs","FileName":"KillHealStatus.cs","PackageType":"game","CodeKind":"Game","AssetVersionId":421898,"IsPrivate":false,"Code":"using System;\r\nusing System.Collections.Generic;\r\nusing System.Linq;\r\nusing Sandbox;\r\n\r\n[Status(5, 3, 1f, 0, false )]\r\npublic class KillHealStatus : Status\r\n{\r\n\tpublic KillHealStatus()\r\n    {\r\n\t\tTitle = \u0022Vampire\u0022;\r\n\t\tIconPath = \u0022textures/icons/kill_heal.png\u0022;\r\n\t}\r\n\r\n\tpublic override void Init(Player player)\r\n\t{\r\n\t\tbase.Init(player);\r\n\t}\r\n\r\n\tpublic override void Refresh()\r\n    {\r\n\t\tDescription = GetDescription(Level);\r\n\r\n        Player.Modify(this, PlayerStat.HealthRegen, -GetHpDrainAmountForLevel(Level), ModifierType.Add);\r\n    }\r\n\r\n\tpublic override string GetDescription(int newLevel)\r\n\t{\r\n\t\treturn string.Format(\u0022Heal for {0} whenever you kill an enemy within 2 meters but lose {1} HP/s\u0022, GetPrintAmountForLevel(Level), GetHpDrainPrintAmountForLevel(Level));\r\n\t}\r\n\r\n\tpublic override string GetUpgradeDescription(int newLevel)\r\n\t{\r\n\t\treturn newLevel \u003E 1 ? string.Format( \u0022Heal for {0}\u2192{1} whenever you kill an enemy within 2 meters but lose {2}\u2192{3} HP/s\u0022, GetPrintAmountForLevel(newLevel - 1), GetPrintAmountForLevel(newLevel), GetHpDrainPrintAmountForLevel(newLevel - 1), GetHpDrainPrintAmountForLevel(newLevel)) : GetDescription(newLevel);\r\n\t}\r\n\r\n    public override void OnKill(Enemy enemy)\r\n    {\r\n\t\tvar distSqr = (enemy.Position2D - Player.Position2D).LengthSquared;\r\n\t\tif ( distSqr \u003E 2f * 2f )\r\n\t\t\treturn;\r\n\r\n\t\tvar amount = GetAmountForLevel( Level );\r\n\r\n\t\tif ( Player.Health \u003C Player.Stats[PlayerStat.MaxHp] )\r\n\t\t\tPlayer.TimeSinceChangeHP = 0f;\r\n\r\n\t\tPlayer.RegenHealth( amount );\r\n\r\n\t\t//DamageNumbersLegacy.Create( amount, Player.Position2D \u002B new Vector2( 0.2f \u002B Game.Random.Float( -0.1f, 0.1f ), Player.Radius * 3f \u002B Game.Random.Float( -0.2f, 0.3f ) ), color: Color.Green, sizeMultiplier: 0.7f );\r\n\t}\r\n\r\n\tpublic float GetAmountForLevel(int level)\r\n\t{\r\n\t\treturn 0.1f \u002B level * 0.5f \u002B (level == 5 ? 0.05f : 0f);\r\n\t}\r\n\r\n    public string GetPrintAmountForLevel(int level)\r\n    {\r\n        return string.Format(\u0022{0:0.00}\u0022, GetAmountForLevel(level));\r\n    }\r\n\r\n    public float GetHpDrainAmountForLevel(int level)\r\n    {\r\n        return level * 0.4f;\r\n    }\r\n\r\n    public string GetHpDrainPrintAmountForLevel(int level)\r\n    {\r\n        return string.Format(\u0022{0:0.00}\u0022, GetHpDrainAmountForLevel(level));\r\n    }\r\n}\r\n"},{"Ident":"facepunch.ss1","Path":"status/MoreRerollsStatus.cs","FileName":"MoreRerollsStatus.cs","PackageType":"game","CodeKind":"Game","AssetVersionId":421898,"IsPrivate":false,"Code":"using System;\r\nusing System.Collections.Generic;\r\nusing System.Linq;\r\nusing Sandbox;\r\n\r\n[Status(3, 0, 1f, maxDifficulty: 2, isCurse: false )]\r\npublic class MoreRerollsStatus : Status\r\n{\r\n\tpublic MoreRerollsStatus()\r\n    {\r\n\t\tTitle = \u0022More Rerolls\u0022;\r\n\t\tIconPath = \u0022textures/icons/more_rerolls.png\u0022;\r\n\t}\r\n\r\n\tpublic override void Init(Player player)\r\n\t{\r\n\t\tbase.Init(player);\r\n\t}\r\n\r\n\tpublic override void Refresh()\r\n    {\r\n\t\tDescription = GetDescription(Level);\r\n\r\n\t\tPlayer.Modify(this, PlayerStat.NumRerollsPerLevel, GetAddForLevel(Level), ModifierType.Add);\r\n\t}\r\n\r\n\tpublic override string GetDescription(int newLevel)\r\n\t{\r\n\t\treturn string.Format(\u0022Gain {0} addition reroll each level\u0022, GetAddForLevel(Level));\r\n\t}\r\n\r\n\tpublic override string GetUpgradeDescription(int newLevel)\r\n    {\r\n\t\treturn newLevel \u003E 1 ? string.Format(\u0022Gain {0}\u2192{1} addition rerolls each level\u0022, GetAddForLevel(newLevel - 1), GetAddForLevel(newLevel)) : GetDescription(newLevel);\r\n\t}\r\n\r\n\tpublic float GetAddForLevel(int level)\r\n    {\r\n\t\treturn 1f * level;\r\n    }\r\n}\r\n"},{"Ident":"facepunch.ss1","Path":"status/MovespeedStatus.cs","FileName":"MovespeedStatus.cs","PackageType":"game","CodeKind":"Game","AssetVersionId":421898,"IsPrivate":false,"Code":"using Sandbox;\r\n\r\n[Status( 7, 0, 1f, 0, false )]\r\npublic class MovespeedStatus : Status\r\n{\r\n\tpublic MovespeedStatus()\r\n\t{\r\n\t\tTitle = \u0022Fast Shoes\u0022;\r\n\t\tIconPath = \u0022textures/icons/shoe.png\u0022;\r\n\t}\r\n\r\n\tpublic override void Init( Player player )\r\n\t{\r\n\t\tbase.Init( player );\r\n\t}\r\n\r\n\tpublic override void Refresh()\r\n\t{\r\n\t\tDescription = GetDescription( Level );\r\n\r\n\t\tPlayer.Modify( this, PlayerStat.MoveSpeed, GetMultForLevel( Level ), ModifierType.Mult );\r\n\t}\r\n\r\n\tpublic override string GetDescription( int newLevel )\r\n\t{\r\n\t\treturn string.Format( \u0022Increase movespeed by {0}%\u0022, GetPercentForLevel( Level ) );\r\n\t}\r\n\r\n\tpublic override string GetUpgradeDescription( int newLevel )\r\n\t{\r\n\t\treturn newLevel \u003E 1 ? string.Format( \u0022Increase movespeed by {0}%\u2192{1}%\u0022, GetPercentForLevel( newLevel - 1 ), GetPercentForLevel( newLevel ) ) : GetDescription( newLevel );\r\n\t}\r\n\r\n\tpublic float GetMultForLevel( int level )\r\n\t{\r\n\t\treturn 1f \u002B 0.2f * level \u002B (level == 7 ? 0.2f : 0f);\r\n\t}\r\n\r\n\tpublic float GetPercentForLevel( int level )\r\n\t{\r\n\t\treturn 20 * level \u002B (level == 7 ? 20 : 0);\r\n\t}\r\n}\r\n"},{"Ident":"facepunch.ss1","Path":"status/Status.cs","FileName":"Status.cs","PackageType":"game","CodeKind":"Game","AssetVersionId":421898,"IsPrivate":false,"Code":"using System;\r\nusing System.Collections.Generic;\r\nusing System.Linq;\r\nusing System.Text;\r\nusing System.Threading.Tasks;\r\n\r\npublic class Status\r\n{\r\n\tpublic bool ShouldUpdate { get; protected set; }\r\n\tpublic Player Player { get; protected set; }\r\n\tpublic int Level { get; set; }\r\n\tpublic int MaxLevel { get; set; }\r\n\tpublic TimeSince ElapsedTime { get; protected set; }\r\n\tpublic string Title { get; protected set; }\r\n\tpublic string Description { get; protected set; }\r\n\tpublic string IconPath { get; protected set; }\r\n\r\n\tpublic string DataString { get; protected set; }\r\n\r\n\tpublic Status()\r\n\t{\r\n\t\tLevel = 1;\r\n\t}\r\n\r\n\tpublic virtual void Init( Player player )\r\n\t{\r\n\t\tPlayer = player;\r\n\t\tElapsedTime = 0f;\r\n\t\tShouldUpdate = false;\r\n\t}\r\n\r\n\t// when gaining or leveling up\r\n\tpublic virtual void Refresh()\r\n\t{\r\n\r\n\t}\r\n\r\n\tpublic virtual void Update( float dt )\r\n\t{\r\n\t\t//if (ElapsedTime \u003E 10f)\r\n\t\t//    Player.RemoveStatus(this);\r\n\t}\r\n\r\n\tpublic virtual void Remove()\r\n\t{\r\n\r\n\t}\r\n\r\n\tpublic virtual string GetDescription( int newLevel )\r\n\t{\r\n\t\treturn \u0022...\u0022;\r\n\t}\r\n\r\n\tpublic virtual string GetUpgradeDescription( int newLevel )\r\n\t{\r\n\t\treturn \u0022...\u0022;\r\n\t}\r\n\r\n\tpublic virtual void Colliding( Thing other, float percent, float dt ) { }\r\n\tpublic virtual void OnDashStarted() { }\r\n\tpublic virtual void OnDashFinished() { }\r\n\tpublic virtual void OnDashRecharged() { }\r\n\tpublic virtual void OnReload() { }\r\n\t//public virtual void OnBurn( Enemy enemy ) { }\r\n\t//public virtual void OnFreeze( Enemy enemy ) { }\r\n\t//public virtual void OnFear( Enemy enemy ) { }\r\n\tpublic virtual void OnKill( Enemy enemy ) { }\r\n\tpublic virtual void OnHurt( float amount ) { }\r\n\tpublic virtual void OnGainExperience( int xp ) { }\r\n\tpublic virtual void OnLevelUp() { }\r\n\tpublic virtual void OnReroll() { }\r\n\tpublic virtual void OnGainShield() { }\r\n\tpublic virtual void OnLoseShield() { }\r\n\tpublic virtual void OnAddStatus( int typeIdentity ) { }\r\n}\r\n"},{"Ident":"facepunch.ss1","Path":"things/enemies/Charger.cs","FileName":"Charger.cs","PackageType":"game","CodeKind":"Game","AssetVersionId":421898,"IsPrivate":false,"Code":"using Sandbox;\r\nusing Sandbox.ModelEditor.Nodes;\r\nusing System.Net.NetworkInformation;\r\n\r\npublic class Charger : Enemy\r\n{\r\n\tprivate TimeSince _damageTime;\r\n\tprivate const float DAMAGE_TIME = 1f;\r\n\r\n\tprotected float _chargeDelayTimer;\r\n\tprivate const float CHARGE_DELAY_MIN = 2f;\r\n\tprivate const float CHARGE_DELAY_MAX = 6f;\r\n\r\n\tpublic bool IsPreparingToCharge { get; private set; }\r\n\tpublic bool IsCharging { get; private set; }\r\n\tprivate float _prepareTimer;\r\n\tprivate const float PREPARE_TIME = 1f;\r\n\tprotected float _chargeTimer;\r\n\tprotected float CHARGE_TIME_MIN = 1.8f;\r\n\tprotected float CHARGE_TIME_MAX = 2.5f;\r\n\tprivate float _chargeTime;\r\n\tprivate float _nextRedirectTime;\r\n\tprivate TimeSince _timeSinceRedirect;\r\n\r\n\tprotected Vector2 _chargeDir;\r\n\tprotected Vector2 _chargeVel;\r\n\tprivate TimeSince _chargeCloudTimer;\r\n\r\n\tpublic override float HeightVariance =\u003E 0.03f;\r\n\tpublic override float WidthVariance =\u003E 0.015f;\r\n\r\n\tpublic float ChargeRange { get; set; }\r\n\r\n\tprotected float REDIRECT_DELAY_MIN = 0.3f;\r\n\tprotected float REDIRECT_DELAY_MAX = 2.7f;\r\n\r\n\tprotected override void OnAwake()\r\n\t{\r\n\t\t//OffsetY = -0.57f;\r\n\t\tShadowScale = 1.25f;\r\n\t\tShadowFullOpacity = 0.8f;\r\n\t\tShadowOpacity = 0f;\r\n\r\n\t\tScale = 1.25f;\r\n\r\n\t\tbase.OnAwake();\r\n\r\n\t\t//Sprite.Texture = Texture.Load(\u0022textures/sprites/charger.vtex\u0022);\r\n\t\t//Sprite.Size = new Vector2( 1f, 1f ) * Scale;\r\n\r\n\t\tPushStrength = 25f;\r\n\r\n\t\tRadius = 0.275f;\r\n\r\n\t\tHealth = 75f;\r\n\r\n\t\tif ( Manager.Instance.Difficulty \u003C 0 )\r\n\t\t\tHealth = 55f;\r\n\r\n\t\tMaxHealth = Health;\r\n\t\tDamageToPlayer = 10f;\r\n\r\n\t\tCoinValueMin = 2;\r\n\t\tCoinValueMax = 5;\r\n\t\tCoinChance = 0.7f;\r\n\r\n\t\tSprite.PlayAnimation( AnimSpawnPath );\r\n\r\n\t\tif ( IsProxy )\r\n\t\t\treturn;\r\n\r\n\t\tCollideWith.Add( typeof( Enemy ) );\r\n\t\tCollideWith.Add( typeof( Player ) );\r\n\r\n\t\t_damageTime = DAMAGE_TIME;\r\n\t\t_chargeDelayTimer = Game.Random.Float( CHARGE_DELAY_MIN, CHARGE_DELAY_MAX );\r\n\r\n\t\tChargeRange = 4.2f;\r\n\t}\r\n\r\n\tprotected override void UpdatePosition( float dt )\r\n\t{\r\n\t\t//Gizmo.Draw.Color = Color.White.WithAlpha(0.5f);\r\n\t\t//Gizmo.Draw.Text( $\u0022IsCharging: {IsCharging}\u0022, new global::Transform( (Vector3)Position2D \u002B new Vector3( 0f, -0.7f, 0f ) ) );\r\n\r\n\t\tbase.UpdatePosition( dt );\r\n\r\n\t\tvar targetPos = Target.IsValid() ? Target.Position2D : (IsCharmed ? Manager.Instance.Player.Position2D : Position2D);\r\n\r\n\t\tif ( IsPreparingToCharge )\r\n\t\t{\r\n\t\t\t_prepareTimer -= dt;\r\n\t\t\tif ( _prepareTimer \u003C 0f )\r\n\t\t\t{\r\n\t\t\t\tCharge();\r\n\t\t\t\treturn;\r\n\t\t\t}\r\n\t\t}\r\n\t\telse if ( IsCharging )\r\n\t\t{\r\n\t\t\t_chargeTimer -= dt;\r\n\t\t\tif ( _chargeTimer \u003C 0f )\r\n\t\t\t{\r\n\t\t\t\tIsCharging = false;\r\n\t\t\t\tSprite.PlayAnimation( AnimIdlePath );\r\n\t\t\t\tCanTurn = true;\r\n\t\t\t\tDontChangeAnimSpeed = false;\r\n\t\t\t}\r\n\t\t\telse\r\n\t\t\t{\r\n\t\t\t\tHandleCharging( dt );\r\n\t\t\t}\r\n\r\n\t\t\tWorldPosition \u002B= (Vector3)(_chargeVel \u002B Velocity) * dt;\r\n\r\n\t\t\tif ( Manager.Instance.Difficulty \u003E= 1 \u0026\u0026 _timeSinceRedirect \u003E _nextRedirectTime )\r\n\t\t\t{\r\n\t\t\t\t_chargeDir = (targetPos - Position2D).Normal;\r\n\r\n\t\t\t\tif(Math.Abs( targetPos.x - Position2D.x ) \u003E 0.15f )\r\n\t\t\t\t\tFlipX = targetPos.x \u003E Position2D.x;\r\n\r\n\t\t\t\t_nextRedirectTime = Game.Random.Float( REDIRECT_DELAY_MIN, REDIRECT_DELAY_MAX );\r\n\t\t\t\t_timeSinceRedirect = 0f;\r\n\t\t\t}\r\n\r\n\t\t\tif ( _chargeCloudTimer \u003E 0.25f )\r\n\t\t\t{\r\n\t\t\t\tSpawnCloudClient( Position2D \u002B new Vector2( 0f, 0.25f ), -_chargeDir * Game.Random.Float( 0.2f, 0.8f ) );\r\n\t\t\t\t_chargeCloudTimer = Game.Random.Float( 0f, 0.075f );\r\n\t\t\t}\r\n\t\t}\r\n\t\telse\r\n\t\t{\r\n\t\t\tVelocity \u002B= (targetPos - Position2D).Normal * dt * (IsFeared ? -1f : 1f);\r\n\r\n\t\t\tfloat speed = 0.75f * (IsAttacking ? 1.3f : 0.7f) \u002B Utils.FastSin( MoveTimeOffset \u002B Time.Now * (IsAttacking ? 15f : 7.5f) ) * (IsAttacking ? 0.66f : 0.35f);\r\n\r\n\t\t\tif ( Manager.Instance.Difficulty \u003C 0 )\r\n\t\t\t\tspeed *= 0.85f;\r\n\r\n\t\t\tWorldPosition \u002B= (Vector3)Velocity * speed * dt;\r\n\t\t}\r\n\r\n\t\tvar player_dist_sqr = (targetPos - Position2D).LengthSquared;\r\n\t\tif ( !IsPreparingToCharge \u0026\u0026 !IsCharging \u0026\u0026 !IsAttacking \u0026\u0026 player_dist_sqr \u003C ChargeRange * ChargeRange \u0026\u0026 Target.IsValid() )\r\n\t\t{\r\n\t\t\t_chargeDelayTimer -= dt;\r\n\t\t\tif ( _chargeDelayTimer \u003C 0f )\r\n\t\t\t{\r\n\t\t\t\tPrepareToCharge();\r\n\t\t\t}\r\n\t\t}\r\n\t}\r\n\r\n\tprotected virtual void HandleCharging(float dt)\r\n\t{\r\n\t\tfloat chargeSpeed = Manager.Instance.Difficulty \u003E= 1 ? 12f : 4f; ;\r\n\t\t_chargeVel \u002B= _chargeDir * chargeSpeed * Utils.MapReturn( _chargeTimer, _chargeTime, 0f, 0f, 1f, EasingType.Linear ) * dt;\r\n\t\tTempWeight \u002B= Utils.MapReturn( _chargeTimer, _chargeTime, 0f, 1f, 6f, EasingType.Linear ) * dt;\r\n\r\n\t\tfloat BUFFER = 0.01f;\r\n\t\tvar x_min = Manager.Instance.BOUNDS_MIN.x \u002B Radius \u002B BUFFER;\r\n\t\tvar x_max = Manager.Instance.BOUNDS_MAX.x - Radius - BUFFER;\r\n\t\tvar y_min = Manager.Instance.BOUNDS_MIN.y \u002B BUFFER;\r\n\t\tvar y_max = Manager.Instance.BOUNDS_MAX.y - Radius - BUFFER;\r\n\r\n\t\tif ( Position2D.x \u003C x_min \u0026\u0026 _chargeDir.x \u003C 0f )\r\n\t\t{\r\n\t\t\t_chargeDir = _chargeDir.WithX( Math.Abs( _chargeDir.x ) );\r\n\t\t\t_chargeVel = _chargeVel.WithX( Math.Abs( _chargeVel.x ) * 0.1f );\r\n\t\t\tFlipX = true;\r\n\t\t\tSprite.SpriteFlags = SpriteFlags.HorizontalFlip;\r\n\t\t}\r\n\t\telse if ( Position2D.x \u003E x_max \u0026\u0026 _chargeDir.x \u003E 0f )\r\n\t\t{\r\n\t\t\t_chargeDir = _chargeDir.WithX( -Math.Abs( _chargeDir.x ) );\r\n\t\t\t_chargeVel = _chargeVel.WithX( -Math.Abs( _chargeVel.x ) * 0.1f );\r\n\t\t\tFlipX = false;\r\n\t\t\tSprite.SpriteFlags = SpriteFlags.None;\r\n\t\t}\r\n\r\n\t\tif ( Position2D.y \u003C y_min \u0026\u0026 _chargeDir.y \u003C 0f )\r\n\t\t{\r\n\t\t\t_chargeDir = _chargeDir.WithY( Math.Abs( _chargeDir.y ) );\r\n\t\t\t_chargeVel = _chargeDir.WithY( Math.Abs( _chargeVel.y ) * 0.1f );\r\n\t\t}\r\n\t\telse if ( Position2D.y \u003E y_max \u0026\u0026 _chargeDir.y \u003E 0f )\r\n\t\t{\r\n\t\t\t_chargeDir = _chargeDir.WithY( -Math.Abs( _chargeDir.y ) );\r\n\t\t\t_chargeVel = _chargeDir.WithY( -Math.Abs( _chargeVel.y ) * 0.1f );\r\n\t\t}\r\n\t}\r\n\r\n\tprotected override void HandleDeceleration( float dt )\r\n\t{\r\n\t\tif ( IsCharging )\r\n\t\t{\r\n\t\t\tVelocity *= (1f - dt * 1.75f);\r\n\r\n\t\t\tfloat decel = Manager.Instance.Difficulty \u003E= 1 ? 3f : 0.5f;\r\n\t\t\t_chargeVel *= (1f - dt * decel);\r\n\t\t}\r\n\t\telse\r\n\t\t{\r\n\t\t\tbase.HandleDeceleration( dt );\r\n\t\t}\r\n\t}\r\n\r\n\tprotected override void UpdateSprite( Thing target )\r\n\t{\r\n\t\tif ( !IsCharging )\r\n\t\t\tbase.UpdateSprite( target );\r\n\t}\r\n\r\n\tprotected override void HandleAttacking( Thing target, float dt )\r\n\t{\r\n\t\tif ( !IsPreparingToCharge \u0026\u0026 !IsCharging )\r\n\t\t\tbase.HandleAttacking( target, dt );\r\n\t}\r\n\r\n\tpublic void PrepareToCharge()\r\n\t{\r\n\t\t_prepareTimer = PREPARE_TIME;\r\n\t\tIsPreparingToCharge = true;\r\n\t\tManager.Instance.PlaySfxNearby( \u0022enemy.roar.prepare\u0022, Position2D, pitch: Game.Random.Float( 0.95f, 1.05f ), volume: 1f, maxDist: 5f );\r\n\t\tSprite.PlayAnimation( \u0022charge_start\u0022 );\r\n\t\tCanTurn = false;\r\n\t\tCanAttack = false;\r\n\t\tCanAttackAnim = false;\r\n\t\tDontChangeAnimSpeed = true;\r\n\r\n\t\tif ( Manager.Instance.Difficulty \u003E= 1 )\r\n\t\t{\r\n\t\t\t_nextRedirectTime = Game.Random.Float( REDIRECT_DELAY_MIN, REDIRECT_DELAY_MAX );\r\n\t\t\t_timeSinceRedirect = 0f;\r\n\t\t}\r\n\t}\r\n\r\n\tpublic void Charge()\r\n\t{\r\n\t\tvar target_pos = Target.IsValid() \u0026\u0026 !IsFeared\r\n\t\t\t? Target.Position2D \u002B Target.Velocity * Game.Random.Float( 0.5f, 1.75f )\r\n\t\t\t: Position2D \u002B Utils.GetRandomVector() * 0.5f;\r\n\r\n\t\t_chargeDir = Utils.RotateVector( (target_pos - Position2D).Normal, Game.Random.Float( -10f, 10f ) );\r\n\r\n\t\tIsPreparingToCharge = false;\r\n\t\tIsCharging = true;\r\n\t\t_chargeTime = Game.Random.Float( CHARGE_TIME_MIN, CHARGE_TIME_MAX ) * (Manager.Instance.Difficulty \u003E= 1 ? Game.Random.Float(1.25f, Utils.Map(Manager.Instance.Difficulty, 1, 10, 1.75f, 3f, EasingType.SineIn)) : 1f);\r\n\r\n\t\t_chargeTimer = _chargeTime;\r\n\t\tCanAttack = true;\r\n\t\tCanAttackAnim = true;\r\n\r\n\t\t_chargeDelayTimer = Game.Random.Float( CHARGE_DELAY_MIN, CHARGE_DELAY_MAX ) * (Manager.Instance.Difficulty \u003C 0 ? 1.4f : 1f);\r\n\t\t_chargeVel = Vector2.Zero;\r\n\t\tSprite.PlayAnimation( \u0022charge_loop\u0022 );\r\n\t\tAnimSpeed = 3f;\r\n\t\tFlipX = _chargeDir.x \u003E 0f;\r\n\t\tSprite.SpriteFlags = FlipX ? SpriteFlags.HorizontalFlip : SpriteFlags.None;\r\n\t\t//Sprite.SpriteFlags = target_pos.x \u003E Position2D.x ? SpriteFlags.HorizontalFlip : SpriteFlags.None;\r\n\r\n\t\tManager.Instance.PlaySfxNearby( \u0022enemy.roar\u0022, Position2D, pitch: Game.Random.Float( 0.925f, 1.075f ), volume: 1f, maxDist: 8f );\r\n\t}\r\n\r\n\tpublic override void Colliding( Thing other, float percent, float dt )\r\n\t{\r\n\t\tbase.Colliding( other, percent, dt );\r\n\r\n\t\tif ( other is Enemy enemy \u0026\u0026 !enemy.IsDying )\r\n\t\t{\r\n\t\t\tvar spawnFactor = Utils.Map( enemy.TimeSinceSpawn, 0f, enemy.SpawnTime, 0f, 1f, EasingType.QuadIn );\r\n\t\t\tVelocity \u002B= (Position2D - enemy.Position2D).Normal * Utils.Map( percent, 0f, 1f, 0f, 1f ) * enemy.PushStrength * (1f \u002B enemy.TempWeight) * spawnFactor * dt;\r\n\r\n\t\t\tif ( (IsAttacking || IsCharging) \u0026\u0026 IsCharmed != enemy.IsCharmed \u0026\u0026 _damageTime \u003E (DAMAGE_TIME / TimeScale) )\r\n\t\t\t{\r\n\t\t\t\tvar dmg = DamageToPlayer;\r\n\t\t\t\tif ( IsCharmed )\r\n\t\t\t\t\tdmg *= CharmDamageDealtMultiplier;\r\n\r\n\t\t\t\tenemy.Damage( dmg, null, addVel: Vector2.Zero, addTempWeight: 0f, isCrit: false, DamageType.Melee );\r\n\t\t\t\tenemy.Target = this;\r\n\t\t\t\t_damageTime = 0f;\r\n\t\t\t\tManager.Instance.PlaySfxNearby( \u0022zombie.attack.player\u0022, Position2D, pitch: Utils.Map( enemy.Health, enemy.MaxHealth, 0f, 0.95f, 1.15f, EasingType.QuadIn ), volume: 0.6f, maxDist: 4.5f );\r\n\t\t\t}\r\n\t\t}\r\n\t\t// todo: move collision check to player instead to prevent laggy hits?\r\n\t\telse if ( other is Player player )\r\n\t\t{\r\n\t\t\tif ( !player.IsDead )\r\n\t\t\t{\r\n\t\t\t\tVelocity \u002B= (Position2D - player.Position2D).Normal * Utils.Map( percent, 0f, 1f, 0f, 1f ) * player.Stats[PlayerStat.PushStrength] * (1f \u002B player.TempWeight) * dt;\r\n\r\n\t\t\t\tif ( (IsAttacking || IsCharging) \u0026\u0026 _damageTime \u003E (DAMAGE_TIME / TimeScale) \u0026\u0026 !IsCharmed )\r\n\t\t\t\t{\r\n\t\t\t\t\tfloat dmg = player.CheckDamageAmount( DamageToPlayer, DamageType.Melee );\r\n\r\n\t\t\t\t\tif ( !player.IsInvulnerable \u0026\u0026 !player.IsTimePausedForChoosing )\r\n\t\t\t\t\t{\r\n\t\t\t\t\t\tManager.Instance.PlaySfxNearby( \u0022zombie.attack.player\u0022, Position2D, pitch: Utils.Map( player.Health, player.Stats[PlayerStat.MaxHp], 0f, 0.95f, 1.15f, EasingType.QuadIn ), volume: 1f, maxDist: 5.5f );\r\n\r\n\t\t\t\t\t\tplayer.Damage( dmg );\r\n\r\n\t\t\t\t\t\tif ( dmg \u003E 0f )\r\n\t\t\t\t\t\t\tOnDamagePlayer( player, dmg );\r\n\t\t\t\t\t}\r\n\r\n\t\t\t\t\t_damageTime = 0f;\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t}\r\n\t}\r\n\r\n\tpublic override void Celebrate()\r\n\t{\r\n\t\tbase.Celebrate();\r\n\r\n\t\tCelebrateAsync();\r\n\t}\r\n\r\n\tasync void CelebrateAsync()\r\n\t{\r\n\t\tawait Task.Delay( Game.Random.Int( 0, 500 ) );\r\n\r\n\t\tSprite.PlaybackSpeed = Game.Random.Float( 1f, 2.5f );\r\n\r\n\t\tSprite.PlayAnimation( \u0022cheer_start\u0022 );\r\n\r\n\t\tawait Task.Delay( Game.Random.Int( 200, 400 ) );\r\n\r\n\t\tSprite.PlayAnimation( \u0022cheer\u0022 );\r\n\t}\r\n}\r\n"},{"Ident":"facepunch.ss1","Path":"things/enemies/RunnerEliteSpecial.cs","FileName":"RunnerEliteSpecial.cs","PackageType":"game","CodeKind":"Game","AssetVersionId":421898,"IsPrivate":false,"Code":"using Sandbox;\r\n\r\npublic class RunnerEliteSpecial : RunnerElite\r\n{\r\n\tpublic override float FullOpacity =\u003E 0f;\r\n\r\n\tprotected override void OnAwake()\r\n\t{\r\n\t\tbase.OnAwake();\r\n\r\n\t\tRadius = 0.5075f;\r\n\t\tScale = 2.275f;\r\n\t\tSprite.LocalScale = new Vector3( Scale * Game.Random.Float( 1f - HeightVariance, 1f \u002B HeightVariance ), Scale * Game.Random.Float( 1f - WidthVariance, 1f \u002B WidthVariance ), 1f ) * Globals.SPRITE_SCALE;\r\n\r\n\t\tHealth = 300f;\r\n\t\tMaxHealth = Health;\r\n\r\n\t\tShadowScale = 2.275f;\r\n\t\tShadowFullOpacity = 0f;\r\n\t\tShadowSpriteDirty = true;\r\n\r\n\t\tPushStrength = 55f;\r\n\t\tAggroRange = 2.25f;\r\n\t\t\r\n\t\tDamageToPlayer = 5f;\r\n\r\n\t\tCoinChance = 1f;\r\n\t\tCoinValueMin = 4;\r\n\t\tCoinValueMax = 8;\r\n\r\n\t\tSprite.Tint = Color.White.WithAlpha( FullOpacity );\r\n\r\n\t\tMoveSpeed = 0.35f;\r\n\r\n\t\tJUMP_DELAY_MIN = 4f;\r\n\t\tJUMP_DELAY_MAX = 10f;\r\n\t}\r\n\r\n\tprotected override void SpawnLandingClouds()\r\n\t{\r\n\t\tfor ( int i = 0; i \u003C Game.Random.Int( 2, 3 ); i\u002B\u002B )\r\n\t\t{\r\n\t\t\tvar dir = Utils.GetRandomVector();\r\n\t\t\tSpawnCloudClient( Position2D \u002B dir * Game.Random.Float(0.4f, 0.6f), dir * Game.Random.Float( 0.3f, 1.5f ) );\r\n\t\t}\r\n\t}\r\n\r\n\tpublic override void DealDamage()\r\n\t{\r\n\t\tFlash( 0.1f, Color.Red.WithAlpha( 0.25f ) );\r\n\t}\r\n\r\n\tpublic override void Celebrate()\r\n\t{\r\n\t\tif ( IsSpawning )\r\n\t\t\tFinishSpawning();\r\n\r\n\t\tif ( _isJumping )\r\n\t\t\treturn;\r\n\r\n\t\tCelebrateAsync();\r\n\t}\r\n\r\n\tasync void CelebrateAsync()\r\n\t{\r\n\t\tawait Task.Delay( Game.Random.Int( 0, 500 ) );\r\n\r\n\t\tSprite.PlaybackSpeed = Game.Random.Float( 2f, 4f );\r\n\r\n\t\tSprite.Tint = Color.Red.WithAlpha( 0.25f );\r\n\r\n\t\tSprite.PlayAnimation( \u0022cheer\u0022 );\r\n\t}\r\n}\r\n"},{"Ident":"facepunch.ss1","Path":"things/enemies/Spiker.cs","FileName":"Spiker.cs","PackageType":"game","CodeKind":"Game","AssetVersionId":421898,"IsPrivate":false,"Code":"using Sandbox;\r\nusing static Sandbox.VertexLayout;\r\n\r\npublic class Spiker : Enemy\r\n{\r\n\tprivate TimeSince _damageTime;\r\n\tprivate const float DAMAGE_TIME = 0.75f;\r\n\r\n\tprivate float _shootDelayTimer;\r\n\tprivate const float SHOOT_DELAY_MIN = 2f;\r\n\tprivate const float SHOOT_DELAY_MAX = 4f;\r\n\r\n\tpublic bool IsShooting { get; private set; }\r\n\tprivate float _shotTimer;\r\n\tprivate const float SHOOT_TIME = 4f;\r\n\tprivate bool _hasShot;\r\n\tprivate TimeSince _prepareStartTime;\r\n\tprivate bool _hasReversed;\r\n\r\n\tpublic override float HeightVariance =\u003E 0.02f;\r\n\tpublic override float WidthVariance =\u003E 0.01f;\r\n\r\n\tprivate bool _moveClockwise;\r\n\tpublic static int SpikerNum { get; set; }\r\n\tprivate float _perpendicularMaxDist;\r\n\r\n\tprivate float _digDelayTimer;\r\n\tprivate const float DIG_DELAY_MIN = 4f;\r\n\tprivate const float DIG_DELAY_MAX = 13f;\r\n\tpublic bool IsDigging { get; private set; }\r\n\tprivate TimeSince _timeSinceStartDigging;\r\n\tprivate const float DIG_TIME = 1.2f;\r\n\r\n\tpublic float ShootRange { get; set; }\r\n\r\n\tpublic float MoveSpeed { get; set; }\r\n\r\n\tprotected override void OnAwake()\r\n\t{\r\n\t\t//OffsetY = -0.58f;\r\n\t\tShadowScale = 1.2f;\r\n\t\tShadowFullOpacity = 0.8f;\r\n\t\tShadowOpacity = 0f;\r\n\r\n\t\tScale = 1.4f;\r\n\r\n\t\tbase.OnAwake();\r\n\r\n\t\t//AnimSpeed = 4f;\r\n\t\t//Sprite.Texture = Texture.Load(\u0022textures/sprites/spiker.vtex\u0022);\r\n\r\n\t\tPushStrength = 8f;\r\n\t\tDeceleration = 2.57f;\r\n\t\tDecelerationAttacking = 2.35f;\r\n\t\tAggroRange = 0.75f;\r\n\r\n\t\tRadius = 0.27f;\r\n\r\n\t\tHealth = 80f;\r\n\r\n\t\tif ( Manager.Instance.Difficulty \u003C 0 )\r\n\t\t\tHealth = 70f;\r\n\r\n\t\tMaxHealth = Health;\r\n\t\tDamageToPlayer = 14f;\r\n\r\n\t\tCoinValueMin = 2;\r\n\t\tCoinValueMax = 4;\r\n\t\tCoinChance = 0.75f;\r\n\r\n\t\tSprite.PlayAnimation( AnimSpawnPath );\r\n\r\n\t\tif ( IsProxy )\r\n\t\t\treturn;\r\n\t\t\r\n\t\tCollideWith.Add( typeof( Enemy ) );\r\n\t\tCollideWith.Add( typeof( Player ) );\r\n\r\n\t\t_damageTime = DAMAGE_TIME;\r\n\t\t_shootDelayTimer = Game.Random.Float( SHOOT_DELAY_MIN, SHOOT_DELAY_MAX );\r\n\t\t_digDelayTimer = Game.Random.Float( DIG_DELAY_MIN, DIG_DELAY_MAX );\r\n\r\n\t\t_moveClockwise = SpikerNum % 2 == 0;\r\n\t\tSpikerNum\u002B\u002B;\r\n\t\t_perpendicularMaxDist = Game.Random.Float( 3.5f, 6.5f );\r\n\r\n\t\tShootRange = 4.5f;\r\n\r\n\t\tMoveSpeed = 0.9f;\r\n\t}\r\n\r\n\tprotected override void UpdatePosition( float dt )\r\n\t{\r\n\t\tbase.UpdatePosition( dt );\r\n\r\n\t\t//if(!IsDigging)\r\n\t\t//{\r\n\t\t//\tGizmo.Draw.Color = Color.White;\r\n\t\t//\tGizmo.Draw.Text( $\u0022{_digDelayTimer}\u0022, new global::Transform( (Vector3)Position2D \u002B new Vector3( 0f, -0.4f, 0f ) ) );\r\n\t\t//}\r\n\r\n\t\tvar targetPos = GetTargetPos();\r\n\r\n\t\tif ( IsShooting )\r\n\t\t{\r\n\t\t\tVelocity *= (1f - dt * (IsAttacking ? DecelerationAttacking : Deceleration));\r\n\t\t\tif ( !_hasShot \u0026\u0026 _prepareStartTime \u003E 1f )\r\n\t\t\t{\r\n\t\t\t\tCreateSpike();\r\n\t\t\t\t_hasShot = true;\r\n\t\t\t}\r\n\r\n\t\t\tif ( !_hasReversed \u0026\u0026 _prepareStartTime \u003E 3f )\r\n\t\t\t{\r\n\t\t\t\t_hasReversed = true;\r\n\t\t\t\tSprite.PlayAnimation( \u0022shoot_reverse\u0022 );\r\n\t\t\t}\r\n\r\n\t\t\tVelocity *= (1f - dt * 4f);\r\n\r\n\t\t\t_shotTimer -= dt;\r\n\t\t\tif ( _shotTimer \u003C 0f )\r\n\t\t\t{\r\n\t\t\t\tFinishShooting();\r\n\t\t\t\treturn;\r\n\t\t\t}\r\n\t\t}\r\n\t\telse if ( IsDigging )\r\n\t\t{\r\n\t\t\tVelocity *= (1f - dt * 6f);\r\n\r\n\t\t\tif ( _timeSinceStartDigging \u003E DIG_TIME )\r\n\t\t\t{\r\n\t\t\t\tVector2 pos;\r\n\t\t\t\tif ( Target.IsValid() )\r\n\t\t\t\t{\r\n\t\t\t\t\tpos = targetPos \u002B Target.Velocity * Game.Random.Float( 0f, 2f ) \u002B Utils.GetRandomVector() * Game.Random.Float( 1.5f, 5.5f);\r\n\t\t\t\t\tif ( (Position2D - pos).LengthSquared \u003C MathF.Pow( 0.5f, 2f ) )\r\n\t\t\t\t\t\tpos = Position2D \u002B Utils.GetRandomVector() * Game.Random.Float( 3f, 5f );\r\n\t\t\t\t}\r\n\t\t\t\telse\r\n\t\t\t\t{\r\n\t\t\t\t\tpos = Position2D \u002B Game.Random.Float( 4f, 5f );\r\n\t\t\t\t}\r\n\r\n\t\t\t\tFinishDigging( Manager.Instance.ClampToBounds( pos ) );\r\n\t\t\t}\r\n\t\t\telse\r\n\t\t\t{\r\n\t\t\t\tfloat progress = Utils.Map( _timeSinceStartDigging, 0f, DIG_TIME, 0f, 1f );\r\n\t\t\t\t//ZPos = Utils.Map( progress, 0f, 1f, 0f, DIG_DEPTH );\r\n\t\t\t\t//PlaybackRate = Utils.Map( progress, 0f, 1f, 0f, 1f ) * _personalSpeedScale;\r\n\r\n\t\t\t\tfloat shadowOpacity = Utils.Map( progress, 0f, 1f, ShadowOpacity, 0f, EasingType.QuadIn );\r\n\t\t\t\tShadowSprite.Tint = Color.Black.WithAlpha( shadowOpacity );\r\n\r\n\t\t\t\tVfxOpacity = Utils.Map( progress, 0f, 1f, 1f, 0f, EasingType.QuadIn );\r\n\r\n\t\t\t\t//Gizmo.Draw.Color = Color.White;\r\n\t\t\t\t//Gizmo.Draw.Text( $\u0022{progress}\u0022, new global::Transform( (Vector3)Position2D \u002B new Vector3( 0f, -0.4f, 0f ) ) );\r\n\r\n\t\t\t\tIgnoreCollision = progress \u003E 0.3f;\r\n\r\n\t\t\t\tif ( _spawnCloudTime \u003E (0.3f / TimeScale) )\r\n\t\t\t\t{\r\n\t\t\t\t\tvar cloud = Manager.Instance.SpawnCloud( Position2D \u002B new Vector2( 0f, 0.05f ) );\r\n\t\t\t\t\tcloud.Velocity = new Vector2( Game.Random.Float( -1f, 1f ), Game.Random.Float( -1f, 1f ) ).Normal * Game.Random.Float( 0.2f, 0.6f );\r\n\t\t\t\t\t_spawnCloudTime = Game.Random.Float( 0f, 0.15f );\r\n\t\t\t\t}\r\n\t\t\t}\r\n\r\n\t\t\treturn;\r\n\t\t}\r\n\t\telse\r\n\t\t{\r\n\t\t\tVector2 toTarget = (targetPos - Position2D).Normal;\r\n\r\n\t\t\tif(Manager.Instance.Difficulty \u003E= 1)\r\n\t\t\t{\r\n\t\t\t\tif ( (targetPos - Position2D).LengthSquared \u003C MathF.Pow( _perpendicularMaxDist, 2f ) )\r\n\t\t\t\t\ttoTarget = Vector2.Lerp( toTarget, new Vector2( toTarget.y, -toTarget.x ) * (_moveClockwise ? -1f : 1f), Utils.Map( (targetPos - Position2D).LengthSquared, MathF.Pow( _perpendicularMaxDist, 2f ), MathF.Pow( 1.5f, 2f ), 0f, 1f ) );\r\n\t\t\t}\r\n\r\n\t\t\tVelocity \u002B= toTarget * 1.0f * dt * (IsFeared ? -1f : 1f);\r\n\t\t}\r\n\r\n\t\tfloat speed = MoveSpeed * (IsAttacking ? 1.3f : 0.7f) \u002B Utils.FastSin( MoveTimeOffset \u002B Time.Now * (IsAttacking ? 15f : 7.5f) ) * (IsAttacking ? 0.66f : 0.35f);\r\n\r\n\t\tif ( Manager.Instance.Difficulty \u003C 0 )\r\n\t\t\tspeed *= 0.85f;\r\n\r\n\t\tWorldPosition \u002B= (Vector3)Velocity * speed * dt;\r\n\r\n\t\tif ( !IsShooting \u0026\u0026 !IsDigging \u0026\u0026 (!IsAttacking || IsCharmed) \u0026\u0026 !Manager.Instance.IsGameOver )\r\n\t\t{\r\n\t\t\tvar target_dist_sqr = ((Target.IsValid() ? Target.Position2D : targetPos) - Position2D).LengthSquared;\r\n\t\t\tvar rangeSqr = ShootRange * ShootRange;\r\n\r\n\t\t\tif ( Manager.Instance.Difficulty \u003C 0 )\r\n\t\t\t\trangeSqr *= 0.7f;\r\n\r\n\t\t\tif ( target_dist_sqr \u003C rangeSqr )\r\n\t\t\t{\r\n\t\t\t\t_shootDelayTimer -= dt;\r\n\t\t\t\tif ( _shootDelayTimer \u003C 0f )\r\n\t\t\t\t\tStartShooting();\r\n\t\t\t}\r\n\r\n\t\t\tif ( target_dist_sqr \u003C MathF.Pow( 12f, 2f ) \u0026\u0026 Manager.Instance.Difficulty \u003E 0 )\r\n\t\t\t{\r\n\t\t\t\t_digDelayTimer -= dt;\r\n\t\t\t\tif ( _digDelayTimer \u003C 0f )\r\n\t\t\t\t\tStartDigging();\r\n\t\t\t}\r\n\t\t}\r\n\t}\r\n\r\n\tprotected virtual Vector2 GetTargetPos()\r\n\t{\r\n\t\treturn Target.IsValid() ? Target.Position2D : (IsCharmed ? Manager.Instance.Player.Position2D : Position2D);\r\n\t}\r\n\r\n\tprotected override void UpdateSprite( Thing target )\r\n\t{\r\n\t\tif ( Sprite.CurrentAnimation.Name.Contains( \u0022shoot\u0022 ) || IsDigging ) \r\n\t\t\treturn;\r\n\r\n\t\tbase.UpdateSprite( target );\r\n\t}\r\n\r\n\tpublic void StartShooting()\r\n\t{\r\n\t\t_shotTimer = SHOOT_TIME;\r\n\t\tIsShooting = true;\r\n\t\tCanAttack = false;\r\n\t\tCanTurn = false;\r\n\t\tCanAttackAnim = false;\r\n\t\t_hasShot = false;\r\n\t\t_hasReversed = false;\r\n\t\t_prepareStartTime = 0f;\r\n\t\tVelocity *= 0.25f;\r\n\t\tDontChangeAnimSpeed = true;\r\n\t\tAnimSpeed = 1f;\r\n\t\tSprite.PlayAnimation( \u0022shoot\u0022 );\r\n\r\n\t\tShouldUpdateAfterGameOver = true;\r\n\t}\r\n\r\n\tpublic virtual void CreateSpike()\r\n\t{\r\n\t\tvar target_pos = Target.IsValid()\r\n\t\t\t? Target.Position2D \u002B Target.Velocity * Game.Random.Float( 0.2f, 2f ) \u002B new Vector2( Game.Random.Float( -1f, 1f ), Game.Random.Float( -1f, 1f ) ) * 0.8f\r\n\t\t\t: Position2D \u002B Utils.GetRandomVector() * Game.Random.Float( 3f, 6f );\r\n\r\n\t\tvar BUFFER = 0.1f;\r\n\r\n\t\tvar spike = Manager.Instance.SpawnEnemySpike( new Vector2( Math.Clamp( target_pos.x, Manager.Instance.BOUNDS_MIN.x \u002B BUFFER, Manager.Instance.BOUNDS_MAX.x - BUFFER ), Math.Clamp( target_pos.y, Manager.Instance.BOUNDS_MIN.y \u002B BUFFER, Manager.Instance.BOUNDS_MAX.y - BUFFER ) ) );\r\n\r\n\t\tif(IsCharmed)\r\n\t\t{\r\n\t\t\tspike.BecomeCharmed();\r\n\t\t}\r\n\r\n\t\tManager.Instance.PlaySfxNearby( \u0022spike.prepare\u0022, target_pos, pitch: Game.Random.Float( 0.95f, 1.05f ), volume: 1.5f, maxDist: 5f );\r\n\t}\r\n\r\n\tpublic void FinishShooting()\r\n\t{\r\n\t\t_shootDelayTimer = Game.Random.Float( SHOOT_DELAY_MIN, SHOOT_DELAY_MAX ) * (Manager.Instance.Difficulty \u003C 0 ? 2.5f : 1f);\r\n\t\tIsShooting = false;\r\n\t\tCanAttack = true;\r\n\t\tCanAttackAnim = true;\r\n\t\tCanTurn = true;\r\n\t\tDontChangeAnimSpeed = false;\r\n\t\tSprite.PlayAnimation( AnimIdlePath );\r\n\r\n\t\tShouldUpdateAfterGameOver = false;\r\n\t\tif ( Manager.Instance.IsGameOver \u0026\u0026 !Manager.Instance.ShouldUpdateThings )\r\n\t\t\tCelebrate();\r\n\t}\r\n\r\n\tpublic override void Colliding( Thing other, float percent, float dt )\r\n\t{\r\n\t\tbase.Colliding( other, percent, dt );\r\n\r\n\t\tif ( other is Enemy enemy \u0026\u0026 !enemy.IsDying )\r\n\t\t{\r\n\t\t\tvar spawnFactor = Utils.Map( enemy.TimeSinceSpawn, 0f, enemy.SpawnTime, 0f, 1f, EasingType.QuadIn );\r\n\t\t\tVelocity \u002B= (Position2D - enemy.Position2D).Normal * Utils.Map( percent, 0f, 1f, 0f, 1f ) * enemy.PushStrength * (1f \u002B enemy.TempWeight) * spawnFactor * dt;\r\n\r\n\t\t\tif ( IsAttacking \u0026\u0026 IsCharmed != enemy.IsCharmed \u0026\u0026 _damageTime \u003E (DAMAGE_TIME / TimeScale) )\r\n\t\t\t{\r\n\t\t\t\tvar dmg = DamageToPlayer;\r\n\t\t\t\tif ( IsCharmed )\r\n\t\t\t\t\tdmg *= CharmDamageDealtMultiplier;\r\n\r\n\t\t\t\tenemy.Damage( dmg, null, addVel: Vector2.Zero, addTempWeight: 0f, isCrit: false, DamageType.Melee );\r\n\t\t\t\tenemy.Target = this;\r\n\t\t\t\t_damageTime = 0f;\r\n\t\t\t\tManager.Instance.PlaySfxNearby( \u0022zombie.attack.player\u0022, Position2D, pitch: Utils.Map( enemy.Health, enemy.MaxHealth, 0f, 0.95f, 1.15f, EasingType.QuadIn ), volume: 0.6f, maxDist: 4.5f );\r\n\t\t\t}\r\n\t\t}\r\n\t\t// todo: move collision check to player instead to prevent laggy hits?\r\n\t\telse if ( other is Player player )\r\n\t\t{\r\n\t\t\tif ( !player.IsDead )\r\n\t\t\t{\r\n\t\t\t\tVelocity \u002B= (Position2D - player.Position2D).Normal * Utils.Map( percent, 0f, 1f, 0f, 1f ) * player.Stats[PlayerStat.PushStrength] * (1f \u002B player.TempWeight) * dt;\r\n\r\n\t\t\t\tif ( IsAttacking \u0026\u0026 _damageTime \u003E (DAMAGE_TIME / TimeScale) \u0026\u0026 !IsCharmed )\r\n\t\t\t\t{\r\n\t\t\t\t\tfloat dmg = player.CheckDamageAmount( DamageToPlayer, DamageType.Melee );\r\n\r\n\t\t\t\t\tif ( !player.IsInvulnerable \u0026\u0026 !player.IsTimePausedForChoosing )\r\n\t\t\t\t\t{\r\n\t\t\t\t\t\tManager.Instance.PlaySfxNearby( \u0022zombie.attack.player\u0022, Position2D, pitch: Utils.Map( player.Health, player.Stats[PlayerStat.MaxHp], 0f, 0.95f, 1.15f, EasingType.QuadIn ), volume: 1f, maxDist: 5.5f );\r\n\r\n\t\t\t\t\t\tplayer.Damage( dmg );\r\n\r\n\t\t\t\t\t\tif( dmg \u003E 0f )\r\n\t\t\t\t\t\t\tOnDamagePlayer( player, dmg );\r\n\t\t\t\t\t}\r\n\r\n\t\t\t\t\t_damageTime = 0f;\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t}\r\n\t}\r\n\r\n\tpublic override void Damage( float damage, Player player, Vector2 addVel, float addTempWeight, bool isCrit = false, DamageType damageType = DamageType.PlayerBullet )\r\n\t{\r\n\t\tbase.Damage( damage, player, addVel, addTempWeight, isCrit, damageType );\r\n\r\n\t\tif ( Game.Random.Float( 0f, 1f ) \u003C Utils.Map( damage, 1f, 20f, 0.1f, 0.7f ) )\r\n\t\t\t_digDelayTimer *= Game.Random.Float( 0.6f, 0.95f );\r\n\t}\r\n\r\n\tpublic void StartDigging()\r\n\t{\r\n\t\tIsDigging = true;\r\n\t\t_timeSinceStartDigging = 0f;\r\n\t\tCanAttack = false;\r\n\t\tCanAttackAnim = false;\r\n\t\tCanTurn = false;\r\n\t\tVelocity *= 0.5f;\r\n\t\tSprite.PlayAnimation( \u0022dig\u0022 );\r\n\t\tManager.Instance.PlaySfxNearby( \u0022zombie.dirt\u0022, Position2D, pitch: Game.Random.Float( 0.5f, 0.55f ), volume: 0.6f, maxDist: 7.5f );\r\n\t\t//SS2Game.PlaySfx( \u0022zombie.dirt\u0022, Position, pitch: Game.Random.Float( 0.6f, 0.8f ), volume: 0.7f );\r\n\t\t//SS2Game.Current.DustCloudClient( Position2D );\r\n\r\n\t\tShouldUpdateAfterGameOver = true;\r\n\t}\r\n\r\n\tvoid FinishDigging( Vector2 pos )\r\n\t{\r\n\t\tPosition2D = pos;\r\n\t\t//WorldPosition = ((Vector3)Position2D).WithZ( ZPos );\r\n\r\n\t\tTransform.ClearInterpolation();\r\n\r\n\t\tIsDigging = false;\r\n\t\tCanAttack = true;\r\n\t\tCanAttackAnim = true;\r\n\t\tCanTurn = true;\r\n\t\tIgnoreCollision = false;\r\n\t\t//SetAnim( \u0022Attack1\u0022 );\r\n\r\n\t\t_moveClockwise = !_moveClockwise;\r\n\r\n\t\t_digDelayTimer = Game.Random.Float( DIG_DELAY_MIN, DIG_DELAY_MAX );\r\n\r\n\t\t//SS2Game.PlaySfx( \u0022zombie.dirt\u0022, Position, pitch: Game.Random.Float( 0.6f, 0.8f ), volume: 0.7f );\r\n\t\t//SS2Game.Current.DustCloudClient( Position2D );\r\n\r\n\t\tIsSpawning = true;\r\n\t\t//_hasDug = true;\r\n\t\tTimeSinceSpawn = 0f;\r\n\t\t//SpawnProgress = 0f;\r\n\r\n\t\t//ShadowRadiusModifier = 1.5f;\r\n\t\t//ShadowOpacityModifier = 0f;\r\n\r\n\t\tManager.Instance.PlaySfxNearby( \u0022zombie.dirt\u0022, Position2D, pitch: Game.Random.Float( 0.85f, 0.9f ), volume: 0.6f, maxDist: 7.5f );\r\n\r\n\t\tShadowSprite.Tint = Color.Black.WithAlpha( 0f );\r\n\t\tVfxOpacity = 0f;\r\n\t}\r\n\r\n\tpublic override void Celebrate()\r\n\t{\r\n\t\tbase.Celebrate();\r\n\r\n\t\tif ( IsShooting || IsDigging )\r\n\t\t\treturn;\r\n\r\n\t\tCelebrateAsync();\r\n\t}\r\n\r\n\tasync void CelebrateAsync()\r\n\t{\r\n\t\tawait Task.Delay( Game.Random.Int( 0, 500 ) );\r\n\r\n\t\tSprite.PlaybackSpeed = Game.Random.Float( 1.5f, 3.5f );\r\n\r\n\t\tSprite.PlayAnimation( \u0022cheer_start\u0022 );\r\n\r\n\t\tawait Task.Delay( Game.Random.Int( 200, 400 ) );\r\n\r\n\t\tSprite.PlayAnimation( \u0022cheer\u0022 );\r\n\t}\r\n\r\n\tprotected override void FinishSpawning()\r\n\t{\r\n\t\tbase.FinishSpawning();\r\n\r\n\t\tShouldUpdateAfterGameOver = false;\r\n\t\tif ( Manager.Instance.IsGameOver \u0026\u0026 !Manager.Instance.ShouldUpdateThings )\r\n\t\t\tCelebrate();\r\n\t}\r\n}\r\n"},{"Ident":"facepunch.ss1","Path":"things/Player.cs","FileName":"Player.cs","PackageType":"game","CodeKind":"Game","AssetVersionId":421898,"IsPrivate":false,"Code":"using static Manager;\r\n\r\npublic enum ModifierType { Set, Add, Mult }\r\npublic class ModifierData\r\n{\r\n\tpublic float value;\r\n\tpublic ModifierType type;\r\n\tpublic float priority;\r\n\r\n\tpublic ModifierData( float _value, ModifierType _type, float _priority = 0f )\r\n\t{\r\n\t\tvalue = _value;\r\n\t\ttype = _type;\r\n\t\tpriority = _priority;\r\n\t}\r\n}\r\n\r\npublic enum PlayerStat\r\n{\r\n\tAttackTime, AttackSpeed, ReloadTime, ReloadSpeed, MaxAmmoCount, BulletDamage, BulletForce, Recoil, MoveSpeed, NumProjectiles, BulletSpread, BulletInaccuracy, BulletSpeed, BulletLifetime,\r\n\tBulletNumPiercing, CritChance, CritMultiplier, LowHealthDamageMultiplier, NumUpgradeChoices, HealthRegen, HealthRegenStill, DamageReductionPercent, PushStrength, CoinAttractRange, CoinAttractStrength, Luck, MaxHp,\r\n\tNumDashes, DashInvulnTime, DashCooldown, DashProgress, DashStrength, ThornsPercent, ShootFireIgniteChance, FireDamage, FireLifetime, FireSpreadChance, ShootFreezeChance, FreezeLifetime,\r\n\tFreezeTimeScale, FreezeOnMeleeChance, FreezeFireDamageMultiplier, LastAmmoDamageMultiplier, FearLifetime, FearDamageMultiplier, FearOnMeleeChance, BulletDamageGrow, BulletDamageShrink,\r\n\tBulletDistanceDamage, NumRerollsPerLevel, FullHealthDamageMultiplier, DamagePerEarlierShot, DamageForSpeed, OverallDamageMultiplier, ExplosionSizeMultiplier, GrenadeVelocity, ExplosionDamageMultiplier,\r\n\tBulletDamageMultiplier, ExplosionDamageReductionPercent, NonExplosionDamageIncreasePercent, GrenadeStickyPercent, GrenadeFearChance, FearDrainPercent, FearPainPercent, CrateChanceAdditional,\r\n\tAttackSpeedStill, FearDropGrenadeChance, FrozenShardsNum, NoDashInvuln, BulletFlatDamageAddition, GrenadesCanCrit, BulletHealTeammateAmount, HomingBulletChance, PauseWhileChoosing,\r\n\tBulletNumBouncing, DashCharm, CharmedEnemyDmgTakenMultiplier, CharmedEnemyDmgDealtMultiplier, BossArrivalTime, RadiusMultiplier, SpecialistStatusAmount, ZoomAmount, MaxFireStacks, XpRepel, HealthPackAmount,\r\n\tMaxBulletSpread, ShootRandomDirChance, DashRandomDirChance, MoveSelfDmg, MoveSelfDmgReqDist, MoveSelfDmgAmount, SelfDmgDistanceMoved, IncreasedDmgTaken, ReverseControls, SelfCritChance,\r\n}\r\n\r\npublic enum DamageType { Melee, Ranged, Explosion, Fire, PlayerBullet, Self, Generic, LavaPuddle, FearPain, }\r\npublic enum PlayerDamageType { Enemy, Self, Grenade }\r\n\r\npublic struct CamShakeData\r\n{\r\n\tpublic float strength;\r\n\tpublic float startTime;\r\n\tpublic float time;\r\n\tpublic EasingType easingType;\r\n\tpublic bool useRealTime;\r\n\r\n\tpublic CamShakeData( float _strength, float _startTime, float _time, EasingType _easingType, bool _useRealTime )\r\n\t{\r\n\t\tstrength = _strength;\r\n\t\tstartTime = _startTime;\r\n\t\ttime = _time;\r\n\t\teasingType = _easingType;\r\n\t\tuseRealTime = _useRealTime;\r\n\t}\r\n}\r\n\r\npublic class Player : Thing\r\n{\r\n\t[Property] public GameObject Body { get; set; }\r\n\t[Property] public GameObject ArrowAimerPrefab { get; set; }\r\n\t[Property] public GameObject BulletPrefab { get; set; }\r\n\t[Property] public Sprite EasySprite { get; set; }\r\n\t[Property] public Sprite Difficulty1Sprite { get; set; }\r\n\t[Property] public Sprite Difficulty2Sprite { get; set; }\r\n\t[Property] public Sprite Difficulty3Sprite { get; set; }\r\n\t[Property] public Sprite Difficulty4Sprite { get; set; }\r\n\t[Property] public Sprite Difficulty5Sprite { get; set; }\r\n\t[Property] public Sprite Difficulty6Sprite { get; set; }\r\n\t[Property] public Sprite Difficulty7Sprite { get; set; }\r\n\t[Property] public Sprite Difficulty8Sprite { get; set; }\r\n\t[Property] public Sprite Difficulty9Sprite { get; set; }\r\n\t[Property] public Sprite Difficulty10Sprite { get; set; }\r\n\t[Property] public Sprite Difficulty11Sprite { get; set; }\r\n\t[Property] public Sprite Difficulty12Sprite { get; set; }\r\n\t[Property] public Sprite Difficulty13Sprite { get; set; }\r\n\t[Property] public Sprite Difficulty14Sprite { get; set; }\r\n\t[Property] public Sprite Difficulty15Sprite { get; set; }\r\n\r\n\r\n\t[Sync] public float Health { get; set; }\r\n\tprivate float _regenHpAccumulated;\r\n\tprivate float _drainHpAccumulated;\r\n\r\n\t[Sync] public Vector2 InputVector { get; set; }\r\n\r\n\tpublic GameObject ArrowAimer { get; private set; }\r\n\tpublic Sprite2D ArrowSprite { get; private set; }\r\n\tpublic Vector2 AimDir { get; private set; }\r\n\tprivate Vector2 _controllerAimTarget;\r\n\tprivate const float CONTROLLER_AIM_DEADZONE = 0.25f;\r\n\r\n\t[Sync] public bool IsDead { get; private set; }\r\n\tpublic float Timer { get; protected set; }\r\n\t[Sync] public bool IsReloading { get; protected set; }\r\n\t[Sync] public float ReloadProgress { get; protected set; }\r\n\r\n\tpublic const float BASE_MOVE_SPEED = 15f;\r\n\tprivate int _shotNum;\r\n\r\n\t[Sync] public int Level { get; protected set; }\r\n\tpublic int ExperienceTotal { get; protected set; }\r\n\tpublic int ExperienceCurrent { get; protected set; }\r\n\tpublic int ExperienceRequired { get; protected set; }\r\n\tpublic bool IsChoosingLevelUpReward { get; protected set; }\r\n\tpublic TimeSince TimeSinceLevelUp { get; set; }\r\n\tpublic RealTimeSince RealTimeSinceChoseUpgrade { get; set; }\r\n\tpublic List\u003CStatus\u003E LevelUpChoices { get; private set; }\r\n\r\n\t[Sync] public float DashTimer { get; private set; }\r\n\t[Sync] public bool IsDashing { get; private set; }\r\n\t[Sync] public Vector2 DashVelocity { get; private set; }\r\n\t[Sync] public float DashInvulnTimer { get; private set; }\r\n\tprivate TimeSince _dashCloudTime;\r\n\tpublic float DashProgress { get; protected set; }\r\n\t[Sync] public float DashRechargeProgress { get; protected set; }\r\n\t[Sync] public int NumDashesAvailable { get; set; }\r\n\tpublic int AmmoCount { get; protected set; }\r\n\r\n\tpublic bool IsMoving =\u003E Velocity.LengthSquared \u003E 0.05f \u0026\u0026 !IsDashing;\r\n\t//public bool IsMoving =\u003E (Position2D - _lastPos2D).LengthSquared \u003E 0.000001f;\r\n\tpublic bool IsInputtingMove =\u003E Input.AnalogMove.LengthSquared \u003E 0.01f;\r\n\tpublic bool IsInvulnerable =\u003E IsDashing \u0026\u0026 Stats[PlayerStat.NoDashInvuln] \u003C= 0f;\r\n\tpublic bool IsTimePausedForChoosing =\u003E IsChoosingLevelUpReward \u0026\u0026 Stats[PlayerStat.PauseWhileChoosing] \u003E 0f;\r\n\r\n\r\n\tprivate float _flashTimer;\r\n\tprivate bool _isFlashing;\r\n\tpublic TimeSince TimeSinceHurt { get; private set; }\r\n\tpublic TimeSince TimeSinceChangeHP { get; set; }\r\n\r\n\tprivate GameObject _shieldVfx;\r\n\r\n\t[Sync] public int NumRerollAvailable { get; set; }\r\n\r\n\t[Sync] public NetDictionary\u003CPlayerStat, float\u003E Stats { get; private set; } = new();\r\n\r\n\tpublic Dictionary\u003Cint, Status\u003E Statuses { get; private set; }\r\n\r\n\tprivate Dictionary\u003CStatus, Dictionary\u003CPlayerStat, ModifierData\u003E\u003E _modifiers_stat = new Dictionary\u003CStatus, Dictionary\u003CPlayerStat, ModifierData\u003E\u003E();\r\n\tprivate Dictionary\u003CPlayerStat, float\u003E _original_properties_stat = new Dictionary\u003CPlayerStat, float\u003E();\r\n\r\n\tprivate bool _doneFirstUpdate;\r\n\tprivate TimeSince _timeSinceShoot;\r\n\tprivate TimeSince _timeSinceSpawn;\r\n\r\n\tprivate Vector2 _lastPos2D;\r\n\tprivate TimeSince _timeSinceTouchLeftSide;\r\n\tprivate bool _hasUnlockedSprinterAchievement;\r\n\r\n\tprivate bool _hasUnlockedExperiencedAchievement;\r\n\r\n\tpublic TimeSince TimeSinceInputMove { get; set; }\r\n\tprivate bool _hasUnlockedNoMoveAchievement;\r\n\r\n\tprivate List\u003CCamShakeData\u003E _camShakeDatas = new();\r\n\tpublic float CamShakeAmount { get; set; }\r\n\r\n\tpublic int ChoiceHash { get; set; }\r\n\r\n\tpublic TimeSince TimeSinceHurtLava { get; set; }\r\n\r\n\tpublic RealTimeSince RealTimeSinceDeath { get; set; }\r\n\tprivate float _arrowDeathAlphaStart;\r\n\tprivate bool _hasPlayedDeathSfx;\r\n\r\n\tprotected override void OnAwake()\r\n\t{\r\n\t\tbase.OnAwake();\r\n\r\n\t\tScale = 1f;\r\n\r\n\t\tShadowOpacity = 0.8f;\r\n\t\tShadowScale = 1.12f;\r\n\r\n\t\tStatuses = new Dictionary\u003Cint, Status\u003E();\r\n\t\tLevelUpChoices = new List\u003CStatus\u003E();\r\n\t\tInitializeStats();\r\n\r\n\t\tif ( IsProxy )\r\n\t\t\treturn;\r\n\r\n\t\tCollideWith.Add( typeof( Enemy ) );\r\n\t\tCollideWith.Add( typeof( Player ) );\r\n\r\n\t\tArrowAimer = ArrowAimerPrefab.Clone( WorldPosition );\r\n\t\tArrowAimer.SetParent( GameObject );\r\n\t\tArrowAimer.NetworkMode = NetworkMode.Never;\r\n\t\tArrowSprite = ArrowAimer.Components.Get\u003CSprite2D\u003E();\r\n\t\tArrowSprite.Tint = Color.White.WithAlpha( 0f );\r\n\r\n\t\t_timeSinceShoot = 999f;\r\n\t\t_timeSinceSpawn = 0f;\r\n\r\n\t\tif ( Manager.Instance.Difficulty \u003C 0 ) Sprite.Sprite = EasySprite;\r\n\t\telse if ( Manager.Instance.Difficulty == 1 ) Sprite.Sprite = Difficulty1Sprite;\r\n\t\telse if ( Manager.Instance.Difficulty == 2 ) Sprite.Sprite = Difficulty2Sprite;\r\n\t\telse if ( Manager.Instance.Difficulty == 3 ) Sprite.Sprite = Difficulty3Sprite;\r\n\t\telse if ( Manager.Instance.Difficulty == 4 ) Sprite.Sprite = Difficulty4Sprite;\r\n\t\telse if ( Manager.Instance.Difficulty == 5 ) Sprite.Sprite = Difficulty5Sprite;\r\n\t\telse if ( Manager.Instance.Difficulty == 6 ) Sprite.Sprite = Difficulty6Sprite;\r\n\t\telse if ( Manager.Instance.Difficulty == 7 ) Sprite.Sprite = Difficulty7Sprite;\r\n\t\telse if ( Manager.Instance.Difficulty == 8 ) Sprite.Sprite = Difficulty8Sprite;\r\n\t\telse if ( Manager.Instance.Difficulty == 9 ) Sprite.Sprite = Difficulty9Sprite;\r\n\t\telse if ( Manager.Instance.Difficulty == 10 ) Sprite.Sprite = Difficulty10Sprite;\r\n\t\telse if ( Manager.Instance.Difficulty == 11 ) Sprite.Sprite = Difficulty11Sprite;\r\n\t\telse if ( Manager.Instance.Difficulty == 12 ) Sprite.Sprite = Difficulty12Sprite;\r\n\t\telse if ( Manager.Instance.Difficulty == 13 ) Sprite.Sprite = Difficulty13Sprite;\r\n\t\telse if ( Manager.Instance.Difficulty == 14 ) Sprite.Sprite = Difficulty14Sprite;\r\n\t\telse if ( Manager.Instance.Difficulty == 15 ) Sprite.Sprite = Difficulty15Sprite;\r\n\r\n\t\t//Sprite.LocalScale = 0.5f * Globals.SPRITE_SCALE;\r\n\t}\r\n\r\n\tpublic void InitializeStats()\r\n\t{\r\n\t\t_original_properties_stat.Clear();\r\n\r\n\t\tif ( Network.Active )\r\n\t\t{\r\n\t\t\tRemoveShieldVfx();\r\n\t\t}\r\n\t\telse\r\n\t\t{\r\n\t\t\tif ( _shieldVfx != null )\r\n\t\t\t{\r\n\t\t\t\t_shieldVfx.Destroy();\r\n\t\t\t\t_shieldVfx = null;\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\tLevel = 0;\r\n\t\tExperienceRequired = GetExperienceReqForLevel( Level \u002B 1 );\r\n\t\tExperienceTotal = 0;\r\n\t\tExperienceCurrent = 0;\r\n\t\tStats[PlayerStat.AttackTime] = 0.15f;\r\n\t\tAmmoCount = 5;\r\n\t\tStats[PlayerStat.MaxAmmoCount] = AmmoCount;\r\n\t\tStats[PlayerStat.ReloadTime] = 1.5f;\r\n\t\tStats[PlayerStat.ReloadSpeed] = 1f;\r\n\t\tStats[PlayerStat.AttackSpeed] = 1f;\r\n\t\tStats[PlayerStat.BulletDamage] = 5f;\r\n\t\tStats[PlayerStat.BulletForce] = 0.55f;\r\n\t\tStats[PlayerStat.Recoil] = 0f;\r\n\t\tStats[PlayerStat.MoveSpeed] = 1f;\r\n\t\tStats[PlayerStat.NumProjectiles] = 1f;\r\n\t\tStats[PlayerStat.BulletSpread] = 35f;\r\n\t\tStats[PlayerStat.BulletInaccuracy] = 5f;\r\n\t\tStats[PlayerStat.BulletSpeed] = 4.5f;\r\n\t\tStats[PlayerStat.BulletLifetime] = 0.8f;\r\n\t\tStats[PlayerStat.Luck] = 1f;\r\n\t\tStats[PlayerStat.CritChance] = 0.05f;\r\n\t\tStats[PlayerStat.CritMultiplier] = 1.5f;\r\n\t\tStats[PlayerStat.LowHealthDamageMultiplier] = 1f;\r\n\t\tStats[PlayerStat.FullHealthDamageMultiplier] = 1f;\r\n\t\tStats[PlayerStat.ThornsPercent] = 0f;\r\n\r\n\t\tStats[PlayerStat.NumDashes] = 1f;\r\n\t\tNumDashesAvailable = (int)MathF.Round( Stats[PlayerStat.NumDashes] );\r\n\t\tStats[PlayerStat.DashCooldown] = 3f;\r\n\t\tStats[PlayerStat.DashInvulnTime] = 0.25f;\r\n\t\tStats[PlayerStat.DashStrength] = 3f;\r\n\t\tStats[PlayerStat.BulletNumPiercing] = 0f;\r\n\t\tStats[PlayerStat.BulletNumBouncing] = 0f;\r\n\t\tStats[PlayerStat.DashCharm] = 0f;\r\n\t\tStats[PlayerStat.CharmedEnemyDmgTakenMultiplier] = 1f;\r\n\t\tStats[PlayerStat.CharmedEnemyDmgDealtMultiplier] = 1f;\r\n\t\tStats[PlayerStat.BossArrivalTime] = 15 * 60f;\r\n\t\t//Stats[PlayerStat.BossArrivalTime] = (Manager.Instance.Difficulty \u003E= 5 ? 10 : 15) * 60f;\r\n\t\tStats[PlayerStat.RadiusMultiplier] = 1f;\r\n\t\tStats[PlayerStat.SpecialistStatusAmount] = 0f;\r\n\t\tStats[PlayerStat.ZoomAmount] = 0f;\r\n\t\tStats[PlayerStat.MaxFireStacks] = 0f;\r\n\t\tStats[PlayerStat.XpRepel] = 0f;\r\n\t\tStats[PlayerStat.HealthPackAmount] = 20f;\r\n\t\tStats[PlayerStat.MaxBulletSpread] = 0f;\r\n\t\tStats[PlayerStat.ShootRandomDirChance] = 0f;\r\n\t\tStats[PlayerStat.DashRandomDirChance] = 0f;\r\n\t\tStats[PlayerStat.MoveSelfDmg] = 0f;\r\n\t\tStats[PlayerStat.MoveSelfDmgReqDist] = 0f;\r\n\t\tStats[PlayerStat.MoveSelfDmgAmount] = 0f;\r\n\t\tStats[PlayerStat.SelfDmgDistanceMoved] = 0f;\r\n\t\tStats[PlayerStat.IncreasedDmgTaken] = 0f;\r\n\t\tStats[PlayerStat.ReverseControls] = 0f;\r\n\t\tStats[PlayerStat.SelfCritChance] = 0f;\r\n\r\n\t\tHealth = 100f;\r\n\t\tStats[PlayerStat.MaxHp] = 100f;\r\n\t\t//Health = 1f;\r\n\t\t_regenHpAccumulated = 0f;\r\n\t\t_drainHpAccumulated = 0f;\r\n\r\n\t\tIsDead = false;\r\n\t\tRadius = 0.10f;\r\n\t\tGridPos = Manager.Instance.GetGridSquareForPos( Position2D );\r\n\t\tAimDir = new Vector2( 0f, 1f );\r\n\t\t_controllerAimTarget = Vector2.Zero;\r\n\t\tNumRerollAvailable = Manager.Instance.Difficulty \u003C 0 ? 4 : (Manager.Instance.Difficulty \u003E= 3 ? 3 : 2);\r\n\r\n\t\tStats[PlayerStat.FireDamage] = 1f;\r\n\t\tStats[PlayerStat.FireLifetime] = 3f;\r\n\t\tStats[PlayerStat.ShootFireIgniteChance] = 0f;\r\n\t\tStats[PlayerStat.FireSpreadChance] = 0f;\r\n\t\tStats[PlayerStat.ShootFreezeChance] = 0f;\r\n\t\tStats[PlayerStat.FreezeLifetime] = 4f;\r\n\t\tStats[PlayerStat.FreezeTimeScale] = 0.55f;\r\n\t\tStats[PlayerStat.FreezeOnMeleeChance] = 0f;\r\n\t\tStats[PlayerStat.FreezeFireDamageMultiplier] = 1f;\r\n\t\tStats[PlayerStat.FearLifetime] = 4.5f;\r\n\t\tStats[PlayerStat.FearDamageMultiplier] = 1f;\r\n\t\tStats[PlayerStat.FearOnMeleeChance] = 0f;\r\n\r\n\t\tStats[PlayerStat.CoinAttractRange] = 1.7f;\r\n\t\tStats[PlayerStat.CoinAttractStrength] = 3.5f;\r\n\r\n\t\tStats[PlayerStat.NumUpgradeChoices] = 3f;\r\n\t\tStats[PlayerStat.HealthRegen] = Manager.Instance.Difficulty == -1 ? 0.4f : 0f;\r\n\t\tStats[PlayerStat.HealthRegenStill] = 0f;\r\n\t\t//Stats[PlayerStat.HealthDrain] = 0f;\r\n\t\tStats[PlayerStat.DamageReductionPercent] = 0f;\r\n\t\tStats[PlayerStat.PushStrength] = 30f;\r\n\t\tStats[PlayerStat.LastAmmoDamageMultiplier] = 1f;\r\n\t\tStats[PlayerStat.BulletDamageGrow] = 0f;\r\n\t\tStats[PlayerStat.BulletDamageShrink] = 0f;\r\n\t\tStats[PlayerStat.BulletDistanceDamage] = 0f;\r\n\t\tStats[PlayerStat.NumRerollsPerLevel] = 1f;\r\n\t\tStats[PlayerStat.DamagePerEarlierShot] = 0f;\r\n\t\tStats[PlayerStat.DamageForSpeed] = 0f;\r\n\t\tStats[PlayerStat.OverallDamageMultiplier] = 1f;\r\n\t\tStats[PlayerStat.ExplosionSizeMultiplier] = 1f;\r\n\t\tStats[PlayerStat.GrenadeVelocity] = 8f;\r\n\t\tStats[PlayerStat.ExplosionDamageMultiplier] = 1f;\r\n\t\tStats[PlayerStat.BulletDamageMultiplier] = 1f;\r\n\t\tStats[PlayerStat.ExplosionDamageReductionPercent] = 0f;\r\n\t\tStats[PlayerStat.NonExplosionDamageIncreasePercent] = 0f;\r\n\t\tStats[PlayerStat.GrenadeStickyPercent] = 0f;\r\n\t\tStats[PlayerStat.GrenadeFearChance] = 0f;\r\n\t\tStats[PlayerStat.FearDrainPercent] = 0f;\r\n\t\tStats[PlayerStat.FearPainPercent] = 0f;\r\n\t\tStats[PlayerStat.CrateChanceAdditional] = 0f;\r\n\t\tStats[PlayerStat.AttackSpeedStill] = 1f;\r\n\t\tStats[PlayerStat.FearDropGrenadeChance] = 0f;\r\n\t\tStats[PlayerStat.FrozenShardsNum] = 0f;\r\n\t\tStats[PlayerStat.NoDashInvuln] = 0f;\r\n\t\tStats[PlayerStat.BulletFlatDamageAddition] = 0f;\r\n\t\tStats[PlayerStat.GrenadesCanCrit] = 0f;\r\n\t\tStats[PlayerStat.BulletHealTeammateAmount] = 0f;\r\n\t\tStats[PlayerStat.HomingBulletChance] = 0f;\r\n\t\tStats[PlayerStat.PauseWhileChoosing] = 0f;\r\n\r\n\t\tStatuses.Clear();\r\n\t\t_modifiers_stat.Clear();\r\n\r\n\t\t_isFlashing = false;\r\n\t\tSprite.FlashTint = Color.White.WithAlpha( 0f );\r\n\t\tSprite.Tint = Color.White;\r\n\t\tIsChoosingLevelUpReward = false;\r\n\t\tIsDashing = false;\r\n\t\tIsReloading = true;\r\n\t\tTimer = Stats[PlayerStat.ReloadTime];\r\n\t\tReloadProgress = 0f;\r\n\t\tDashProgress = 0f;\r\n\t\tDashRechargeProgress = 1f;\r\n\t\tTempWeight = 0f;\r\n\t\t_shotNum = 0;\r\n\t\tTimeSinceHurt = 999f;\r\n\t\tTimeSinceChangeHP = 999f;\r\n\t\tTimeSinceHurtLava = 999f;\r\n\t\tShadowOpacity = 0.8f;\r\n\t\tShadowSpriteDirty = true;\r\n\r\n\t\t_timeSinceTouchLeftSide = 999f;\r\n\t\tTimeSinceInputMove = 0f;\r\n\r\n\t\tTimeSinceLevelUp = 999f;\r\n\t\tRealTimeSinceChoseUpgrade = 999f;\r\n\r\n\t\t_camShakeDatas.Clear();\r\n\r\n\t\tChoiceHash = 0;\r\n\t}\r\n\r\n\tpublic Vector2 AverageVelocity { get; private set; }\r\n\r\n\tprotected override void OnUpdate()\r\n\t{\r\n\t\tbase.OnUpdate();\r\n\r\n\t\tAverageVelocity \u002B= Velocity * Time.Delta * 8f;\r\n\t\t//AverageVelocity = Utils.DynamicEaseTo( AverageVelocity, Vector2.Zero, 0.02f, Time.Delta );\r\n\t\tAverageVelocity *= (1f - Time.Delta * 2.7f);\r\n\r\n\t\t//Gizmo.Draw.Color = Color.Red.WithAlpha( 0.5f );\r\n\t\t//Gizmo.Draw.Line( Position2D, Position2D \u002B AverageVelocity );\r\n\r\n\t\t//Gizmo.Draw.Color = Color.Red.WithAlpha( 0.5f );\r\n\t\t//Gizmo.Draw.Line( Position2D, Position2D \u002B AverageVelocity );\r\n\r\n\t\tVector2 anchor = Position2D \u002B AverageVelocity * 0.1f;\r\n\t\tVector2 perp = Utils.GetPerpendicularVector( AverageVelocity ).Normal;\r\n\t\tvar perpA = anchor - perp * 10f;\r\n\t\tvar perpB = anchor \u002B perp * 10f;\r\n\r\n\t\t//Gizmo.Draw.Color = Color.Green.WithAlpha( 0.3f );\r\n\t\t//Gizmo.Draw.Line( perpA, perpB );\r\n\r\n\t\t//Gizmo.Draw.Color = Color.White.WithAlpha( 0.03f );\r\n\t\t//Gizmo.Draw.LineSphere( (Vector3)Position2D, 2, 16 );\r\n\r\n\t\t//Gizmo.Draw.Color = Color.White.WithAlpha( 0.5f );\r\n\t\t//Gizmo.Draw.Text( $\u0022{Stats[PlayerStat.FearPainPercent]}\u0022, new global::Transform( (Vector3)Position2D \u002B new Vector3( 0f, -0.4f, 0f ) ) );\r\n\r\n\t\tif ( !_doneFirstUpdate )\r\n\t\t{\r\n\t\t\tSpawnShadow( ShadowScale, ShadowOpacity );\r\n\t\t\tManager.Instance.Camera2D.SetPos( Position2D );\r\n\r\n\t\t\t_doneFirstUpdate = true;\r\n\t\t}\r\n\r\n\t\tInputVector = new Vector2( -Input.AnalogMove.y, Input.AnalogMove.x );\r\n\r\n\t\tif ( Stats[PlayerStat.ReverseControls] \u003E 0f )\r\n\t\t\tInputVector *= -1f;\r\n\r\n\t\t//if ( Input.Pressed( \u0022Menu\u0022 ) )\r\n\t\t//{\r\n\t\t//\tManager.Instance.Restart();\r\n\t\t//\treturn;\r\n\t\t//}\r\n\r\n\t\tHandleCamShaking();\r\n\r\n\t\tif ( IsDead )\r\n\t\t{\r\n\t\t\tSprite.FlashTint = RealTimeSinceDeath \u003C 0.1f\r\n\t\t\t\t? Color.Red\r\n\t\t\t\t: Color.White.WithAlpha( 0f );\r\n\r\n\t\t\tShadowOpacity = Utils.Map( RealTimeSinceDeath, 0f, Manager.FINAL_PANEL_WAIT_TIME, 0.8f, 0f, EasingType.Linear );\r\n\t\t\tShadowSprite.Tint = Color.Black.WithAlpha( ShadowOpacity );\r\n\r\n\t\t\tArrowSprite.Tint = Color.White.WithAlpha( Utils.Map( RealTimeSinceDeath, 0f, 0.4f, _arrowDeathAlphaStart, 0f, EasingType.SineOut ) );\r\n\r\n\t\t\tif ( !_hasPlayedDeathSfx \u0026\u0026 RealTimeSinceDeath \u003E 0.7f )\r\n\t\t\t{\r\n\t\t\t\tManager.Instance.PlaySfxNearby( \u0022zombie.attack.player\u0022, Position2D, pitch: Game.Random.Float( 0.55f, 0.65f ), volume: 1f, maxDist: 5.5f );\r\n\t\t\t\t_hasPlayedDeathSfx = true;\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\tif ( !Manager.Instance.ShouldUpdatePlayer )\r\n\t\t\treturn;\r\n\r\n\t\tfloat dt = Time.Delta;\r\n\r\n\t\tif ( MathF.Abs( Velocity.x ) \u003E 0.01f )\r\n\t\t\tSprite.SpriteFlags = Velocity.x \u003E 0f ? SpriteFlags.HorizontalFlip : SpriteFlags.None;\r\n\r\n\t\tbool hurting = TimeSinceHurt \u003C 0.25f;\r\n\t\tbool attacking = !IsReloading;\r\n\t\tbool moving = Velocity.LengthSquared \u003E 0.01f \u0026\u0026 InputVector.LengthSquared \u003E 0.1f;\r\n\r\n\t\tstring stateStr = \u0022\u0022;\r\n\t\tif ( IsDead )\r\n\t\t\tstateStr = \u0022ghost_\u0022;\r\n\t\telse if ( hurting \u0026\u0026 attacking )\r\n\t\t\tstateStr = \u0022hurt_attack_\u0022;\r\n\t\telse if ( hurting )\r\n\t\t\tstateStr = \u0022hurt_\u0022;\r\n\t\telse if ( attacking )\r\n\t\t\tstateStr = \u0022attack_\u0022;\r\n\r\n\t\tSprite.PlayAnimation( $\u0022{stateStr}{(moving ? \u0022walk\u0022 : \u0022idle\u0022)}\u0022 );\r\n\t\tSprite.PlaybackSpeed = moving ? Utils.Map( Velocity.Length, 0f, 2f, 1.5f, 2f ) : 0.66f;\r\n\r\n\t\tSprite.LocalRotation = new Angles( 0f, -90f \u002B (Velocity.Length * Utils.FastSin( Time.Now * MathF.PI * 6f ) * 1.6f) * (Sprite.SpriteFlags.HasFlag( SpriteFlags.HorizontalFlip ) ? -1f : 1f), 0f );\r\n\r\n\t\tif ( !IsDead )\r\n\t\t{\r\n\t\t\tHandleFlashing( dt );\r\n\t\t}\r\n\r\n\t\tif ( IsProxy )\r\n\t\t\treturn;\r\n\r\n\t\t// ACHIEVEMENTS\r\n\t\tif ( Manager.Instance.Difficulty \u003E= 0 )\r\n\t\t{\r\n\t\t\tif ( _lastPos2D.x \u003C -15.7f \u0026\u0026 WorldPosition.x \u003E= -15.7f )\r\n\t\t\t{\r\n\t\t\t\t_timeSinceTouchLeftSide = 0f;\r\n\t\t\t}\r\n\r\n\t\t\tif ( _lastPos2D.x \u003C 15.7f \u0026\u0026 WorldPosition.x \u003E= 15.7f )\r\n\t\t\t{\r\n\t\t\t\tLog.Info( $\u0022_timeSinceTouchLeftSide: {_timeSinceTouchLeftSide}\u0022 );\r\n\r\n\t\t\t\tif ( _timeSinceTouchLeftSide \u003C 5.5f )\r\n\t\t\t\t{\r\n\t\t\t\t\tif ( !_hasUnlockedSprinterAchievement )\r\n\t\t\t\t\t\tSandbox.Services.Achievements.Unlock( \u0022sprinter\u0022 );\r\n\r\n\t\t\t\t\t_hasUnlockedSprinterAchievement = true;\r\n\t\t\t\t}\r\n\t\t\t}\r\n\r\n\t\t\tif ( !_hasUnlockedNoMoveAchievement )\r\n\t\t\t{\r\n\t\t\t\tif ( IsInputtingMove )\r\n\t\t\t\t{\r\n\t\t\t\t\tTimeSinceInputMove = 0f;\r\n\t\t\t\t}\r\n\t\t\t\telse if ( TimeSinceInputMove \u003E 60f * 10f )\r\n\t\t\t\t{\r\n\t\t\t\t\tSandbox.Services.Achievements.Unlock( \u0022stand_ground\u0022 );\r\n\t\t\t\t\t_hasUnlockedNoMoveAchievement = true;\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\t//Gizmo.Draw.Color = Color.White;\r\n\t\t//Gizmo.Draw.Text( $\u0022ArrowAimer: {ArrowAimer}\u0022, new global::Transform( (Vector3)Position2D \u002B new Vector3( 0f, -0.7f, 0f ) ) );\r\n\r\n\t\t//Gizmo.Draw.ScreenText( $\u0022_timeSinceTouchLeftSide: {_timeSinceTouchLeftSide}\u0022, new Vector2( 50, 50 ) );\r\n\r\n\t\t_lastPos2D = Position2D;\r\n\r\n\t\tvar velocity = Velocity \u002B (IsDashing ? DashVelocity : Vector2.Zero);\r\n\t\tPosition2D \u002B= velocity * dt;\r\n\r\n\t\tif ( Stats[PlayerStat.MoveSelfDmg] \u003E 0f )\r\n\t\t{\r\n\t\t\tStats[PlayerStat.SelfDmgDistanceMoved] \u002B= velocity.Length * dt;\r\n\r\n\t\t\tif ( !IsInvulnerable \u0026\u0026 Stats[PlayerStat.SelfDmgDistanceMoved] \u003E Stats[PlayerStat.MoveSelfDmgReqDist] )\r\n\t\t\t{\r\n\t\t\t\tStats[PlayerStat.SelfDmgDistanceMoved] -= Stats[PlayerStat.MoveSelfDmgReqDist];\r\n\t\t\t\tDamage( Stats[PlayerStat.MoveSelfDmgAmount], PlayerDamageType.Self );\r\n\t\t\t\tManager.Instance.PlaySfxNearby( \u0022zombie.attack.player\u0022, Position2D, pitch: Game.Random.Float( 1.25f, 1.45f ), volume: 0.9f, maxDist: 3f );\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\tWorldPosition = WorldPosition.WithZ( Globals.GetZPos( Position2D.y ) );\r\n\r\n\t\t//Velocity = Utils.DynamicEaseTo( Velocity, Vector2.Zero, 0.2f, dt );\r\n\t\tVelocity *= Math.Max( 1f - dt * 12.9f, 0f );\r\n\r\n\t\tif ( Velocity.LengthSquared \u003C 0.001f )\r\n\t\t\tVelocity = Vector2.Zero;\r\n\r\n\t\tTempWeight *= (1f - dt * 4.7f);\r\n\r\n\t\tif ( InputVector.LengthSquared \u003E 0f )\r\n\t\t{\r\n\t\t\tVelocity \u002B= InputVector.Normal * Stats[PlayerStat.MoveSpeed] * BASE_MOVE_SPEED * dt;\r\n\t\t\t//Log.Info( $\u0022dt: {dt}\u0022 );\r\n\t\t}\r\n\r\n\t\tHandleBounds();\r\n\r\n\t\tManager.Instance.Camera2D.TargetPos = Position2D;\r\n\r\n\t\tif ( Input.UsingController )\r\n\t\t{\r\n\t\t\t// raw stick rather than AnalogLook, which is scaled by look sensitivity and affected by invert-y (SDL stick y is positive downward)\r\n\t\t\tvar stick = new Vector2( Input.GetAnalog( InputAnalog.RightStickX ), -Input.GetAnalog( InputAnalog.RightStickY ) );\r\n\t\t\tif ( stick.Length \u003E CONTROLLER_AIM_DEADZONE )\r\n\t\t\t\t_controllerAimTarget = stick.Normal;\r\n\r\n\t\t\tif ( _controllerAimTarget.LengthSquared \u003E 0f )\r\n\t\t\t{\r\n\t\t\t\t// reverse here rather than when storing the target, so it still flips when ReverseControls toggles while the stick is released\r\n\t\t\t\tvar target = Stats[PlayerStat.ReverseControls] \u003E 0f ? -_controllerAimTarget : _controllerAimTarget;\r\n\r\n\t\t\t\t// rotate by angle, since a linear lerp toward the exact opposite direction never changes direction\r\n\t\t\t\t// keeps turning after the stick is released, so a quick flick still reaches the target\r\n\t\t\t\tfloat currentDegrees = Utils.VectorToDegrees( AimDir );\r\n\t\t\t\tfloat deltaDegrees = ((Utils.VectorToDegrees( target ) - currentDegrees \u002B 540f) % 360f) - 180f;\r\n\t\t\t\tAimDir = Utils.DegreesToVector( currentDegrees \u002B deltaDegrees * MathF.Min( Time.Delta * 25f, 1f ) );\r\n\t\t\t}\r\n\t\t}\r\n\t\telse\r\n\t\t{\r\n\t\t\tAimDir = (Manager.Instance.MouseWorldPos - (Position2D \u002B new Vector2( 0f, 0.5f ))).Normal;\r\n\r\n\t\t\tif ( Stats[PlayerStat.ReverseControls] \u003E 0f )\r\n\t\t\t\tAimDir *= -1f;\r\n\r\n\t\t\t// forget the last stick direction, so switching back to the controller keeps the mouse aim instead of swinging back to it\r\n\t\t\t_controllerAimTarget = Vector2.Zero;\r\n\t\t}\r\n\r\n\t\tif ( ArrowAimer != null \u0026\u0026 !Manager.Instance.IsPauseMenuOpen \u0026\u0026 !IsTimePausedForChoosing )\r\n\t\t{\r\n\t\t\tArrowAimer.LocalRotation = new Angles( 0f, MathF.Atan2( AimDir.y, AimDir.x ) * (180f / MathF.PI) - 180f, 0f );\r\n\t\t\tArrowAimer.LocalPosition = new Vector2( 0f, 0.4f ) \u002B AimDir * Utils.Map( _timeSinceShoot, 0f, 0.25f, 0.6f, 0.55f, EasingType.QuadOut );\r\n\t\t\tArrowAimer.LocalScale = new Vector3( Utils.Map( _timeSinceShoot, 0f, 0.25f, 1.25f, 0.75f, EasingType.QuadOut ), 1f, 1f ) * 0.005f;\r\n\t\t\tArrowSprite.Tint = Color.White.WithAlpha( Utils.Map( _timeSinceShoot, 0f, 0.3f, 1f, 0.3f, EasingType.QuadOut ) * Utils.Map( _timeSinceSpawn, 0f, 1f, 0f, 1f, EasingType.Linear ) );\r\n\t\t}\r\n\r\n\t\tfor ( int dx = -1; dx \u003C= 1; dx\u002B\u002B )\r\n\t\t{\r\n\t\t\tfor ( int dy = -1; dy \u003C= 1; dy\u002B\u002B )\r\n\t\t\t{\r\n\t\t\t\tManager.Instance.HandleThingCollisionForGridSquare( this, new GridSquare( GridPos.x \u002B dx, GridPos.y \u002B dy ), dt );\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\tif ( !IsDead )\r\n\t\t{\r\n\t\t\tHandleDashing( dt );\r\n\t\t\tHandleStatuses( dt );\r\n\t\t\tHandleShooting( dt );\r\n\t\t\tHandleRegen( dt );\r\n\t\t}\r\n\r\n\t\tif ( IsChoosingLevelUpReward \u0026\u0026 !Manager.Instance.IsPauseMenuOpen )\r\n\t\t{\r\n\t\t\tif ( Input.Pressed( \u0022reload\u0022 ) ) UseReroll();\r\n\t\t\telse if ( Input.Pressed( \u0022Slot1\u0022 ) ) UseChoiceHotkey( 1 );\r\n\t\t\telse if ( Input.Pressed( \u0022Slot2\u0022 ) ) UseChoiceHotkey( 2 );\r\n\t\t\telse if ( Input.Pressed( \u0022Slot3\u0022 ) ) UseChoiceHotkey( 3 );\r\n\t\t\telse if ( Input.Pressed( \u0022Slot4\u0022 ) ) UseChoiceHotkey( 4 );\r\n\t\t\telse if ( Input.Pressed( \u0022Slot5\u0022 ) ) UseChoiceHotkey( 5 );\r\n\t\t\telse if ( Input.Pressed( \u0022Slot6\u0022 ) ) UseChoiceHotkey( 6 );\r\n\t\t}\r\n\r\n\t\tif ( Input.Pressed( \u0022use\u0022 ) )\r\n\t\t{\r\n\t\t\t//AddExperience( 10 );\r\n\t\t}\r\n\t}\r\n\r\n\tvoid HandleRegen( float dt )\r\n\t{\r\n\t\tif ( Math.Abs( Stats[PlayerStat.HealthRegen] ) \u003E 0f )\r\n\t\t\tRegenHealth( Stats[PlayerStat.HealthRegen] * dt );\r\n\r\n\t\t//if ( Math.Abs( Stats[PlayerStat.HealthDrain] ) \u003E 0f )\r\n\t\t//\tRegenHealth( Stats[PlayerStat.HealthDrain] * dt );\r\n\r\n\t\tif ( Stats[PlayerStat.HealthRegenStill] \u003E 0f \u0026\u0026 !IsMoving )\r\n\t\t{\r\n\t\t\tRegenHealth( Stats[PlayerStat.HealthRegenStill] * dt );\r\n\r\n\t\t\tif ( !IsDashing \u0026\u0026 Health \u003C Stats[PlayerStat.MaxHp] )\r\n\t\t\t\tTimeSinceChangeHP = 0f;\r\n\t\t}\r\n\t}\r\n\r\n\tpublic void RegenHealth( float amount )\r\n\t{\r\n\t\tfloat maxHp = Stats[PlayerStat.MaxHp];\r\n\t\tfloat hpMissing = maxHp - Health;\r\n\r\n\t\tif ( amount \u003E 0f )\r\n\t\t{\r\n\t\t\tif ( hpMissing \u003C= 0f )\r\n\t\t\t\treturn;\r\n\r\n\t\t\t_regenHpAccumulated \u002B= amount;\r\n\r\n\t\t\tif ( _regenHpAccumulated \u003C 0.85f \u0026\u0026 hpMissing \u003E _regenHpAccumulated )\r\n\t\t\t\treturn;\r\n\r\n\t\t\tfloat hpRecovered = Math.Min( _regenHpAccumulated, hpMissing );\r\n\r\n\t\t\tHealth \u002B= hpRecovered;\r\n\r\n\t\t\t//var particle = DamageNumbersLegacy.Create( hpRecovered, Position2D \u002B new Vector2( 0.2f \u002B Game.Random.Float( -0.1f, 0.1f ), Radius * 3f \u002B Game.Random.Float( -0.2f, 0.3f ) ), color: Color.Green, sizeMultiplier: 0.8f );\r\n\t\t\t//Vector3 velocity = new Vector3( Game.Random.Float(-0.5f, 0.5f), 0f, 0f );\r\n\t\t\t//Vector3 gravity = new Vector3( 0f, 1.5f, 0f );\r\n\t\t\t//particle.SetVector( 1, velocity );\r\n\t\t\t//particle.SetNamedValue( \u0022Gravity\u0022, gravity );\r\n\r\n\t\t\tvar pos = Position2D \u002B new Vector2( Game.Random.Float( -0.1f, 0.1f ), Radius * 3f \u002B Game.Random.Float( -0.2f, 0.3f ) );\r\n\t\t\tfloat size = 1.1f;\r\n\t\t\tManager.Instance.SpawnDamageNumber( pos, amount, Color.Green, size, FloaterType.Heal );\r\n\r\n\t\t\t_regenHpAccumulated = 0f;\r\n\t\t}\r\n\t\telse\r\n\t\t{\r\n\t\t\t_drainHpAccumulated \u002B= amount;\r\n\t\t\tif ( _drainHpAccumulated \u003C -1f )\r\n\t\t\t{\r\n\t\t\t\tvar dmgAmount = MathF.Truncate( _drainHpAccumulated );\r\n\t\t\t\t_drainHpAccumulated -= dmgAmount;\r\n\r\n\t\t\t\tDamage( MathF.Abs( dmgAmount ), PlayerDamageType.Self );\r\n\r\n\t\t\t\tManager.Instance.PlaySfxNearby( \u0022lava_puddle_03\u0022, Position2D, pitch: Game.Random.Float( 1.7f, 1.75f ), volume: 0.15f, maxDist: 4f );\r\n\t\t\t}\r\n\t\t}\r\n\t}\r\n\r\n\tvoid HandleDashing( float dt )\r\n\t{\r\n\t\tint numDashes = (int)MathF.Round( Stats[PlayerStat.NumDashes] );\r\n\t\tif ( NumDashesAvailable \u003C numDashes )\r\n\t\t{\r\n\t\t\tDashTimer -= dt;\r\n\t\t\tDashRechargeProgress = Utils.Map( DashTimer, Stats[PlayerStat.DashCooldown], 0f, 0f, 1f );\r\n\t\t\tif ( DashTimer \u003C= 0f )\r\n\t\t\t{\r\n\t\t\t\tDashRecharged();\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\tif ( DashInvulnTimer \u003E 0f )\r\n\t\t{\r\n\t\t\tDashInvulnTimer -= dt;\r\n\t\t\tDashProgress = Utils.Map( DashInvulnTimer, Stats[PlayerStat.DashInvulnTime], 0f, 0f, 1f );\r\n\t\t\tif ( DashInvulnTimer \u003C= 0f )\r\n\t\t\t{\r\n\t\t\t\tIsDashing = false;\r\n\t\t\t\t//Sprite.Tint = Color.White;\r\n\t\t\t\tSprite.FlashTint = Color.White.WithAlpha( 0f );\r\n\r\n\t\t\t\tDashFinished();\r\n\t\t\t}\r\n\t\t\telse\r\n\t\t\t{\r\n\t\t\t\tif ( Stats[PlayerStat.DashCharm] \u003E 0f )\r\n\t\t\t\t{\r\n\t\t\t\t\tif ( IsInvulnerable )\r\n\t\t\t\t\t\tSprite.FlashTint = new Color( Game.Random.Float( 0.8f, 1f ), Game.Random.Float( 0f, 0.1f ), Game.Random.Float( 0.8f, 1f ), 0.9f );\r\n\t\t\t\t\telse if ( !_isFlashing )\r\n\t\t\t\t\t\tSprite.FlashTint = new Color( Game.Random.Float( 0.9f, 1f ), Game.Random.Float( 0.1f, 0.3f ), Game.Random.Float( 0.9f, 1f ), 0.8f );\r\n\t\t\t\t}\r\n\t\t\t\telse\r\n\t\t\t\t{\r\n\t\t\t\t\tif ( IsInvulnerable )\r\n\t\t\t\t\t\tSprite.FlashTint = new Color( Game.Random.Float( 0f, 0.25f ), Game.Random.Float( 0f, 0.25f ), Game.Random.Float( 0.8f, 1f ), 0.9f );\r\n\t\t\t\t}\r\n\r\n\t\t\t\tif ( _dashCloudTime \u003E Game.Random.Float( 0.1f, 0.2f ) )\r\n\t\t\t\t{\r\n\t\t\t\t\tSpawnDashCloudClient();\r\n\t\t\t\t\t_dashCloudTime = 0f;\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\tbool pressedDash = Input.Pressed( \u0022Dash\u0022 ) \u0026\u0026 !Gamepad.IsAClickingUi;\r\n\t\tif ( (pressedDash ||Input.Pressed( \u0022RB\u0022 )) \u0026\u0026 !Manager.Instance.IsPauseMenuOpen )\r\n\t\t{\r\n\t\t\t//Position2D = Manager.Instance.MouseWorldPos;\r\n\t\t\t////Manager.Instance.Camera2D.SetPos( Position2D );\r\n\t\t\t//Transform.ClearInterpolation();\r\n\t\t\t//return;\r\n\r\n\t\t\tDash();\r\n\t\t}\r\n\t}\r\n\r\n\tpublic void Dash()\r\n\t{\r\n\t\tif ( NumDashesAvailable \u003C= 0 || IsTimePausedForChoosing )\r\n\t\t\treturn;\r\n\r\n\t\tVector2 dashDir = Velocity.LengthSquared \u003E 0f ? Velocity.Normal : AimDir;\r\n\r\n\t\tif ( Game.Random.Float( 0f, 1f ) \u003C Stats[PlayerStat.DashRandomDirChance] )\r\n\t\t\tdashDir = Utils.GetRandomVector();\r\n\r\n\t\tDashVelocity = dashDir * Stats[PlayerStat.DashStrength];\r\n\t\tTempWeight = 2f;\r\n\r\n\t\tif ( NumDashesAvailable == (int)Stats[PlayerStat.NumDashes] )\r\n\t\t\tDashTimer = Stats[PlayerStat.DashCooldown];\r\n\r\n\t\tNumDashesAvailable--;\r\n\t\tIsDashing = true;\r\n\t\tDashInvulnTimer = Stats[PlayerStat.DashInvulnTime];\r\n\t\tDashProgress = 0f;\r\n\t\tDashRechargeProgress = 0f;\r\n\r\n\t\tManager.Instance.PlaySfxNearby( \u0022player.dash\u0022, Position2D \u002B dashDir * 0.5f, pitch: Utils.Map( NumDashesAvailable, 0, 5, 1f, 0.9f ), volume: 1f, maxDist: 4f );\r\n\t\tSpawnDashCloudClient();\r\n\t\t_dashCloudTime = 0f;\r\n\r\n\t\tForEachStatus( status =\u003E status.OnDashStarted() );\r\n\t}\r\n\r\n\tpublic void DashFinished()\r\n\t{\r\n\t\tForEachStatus( status =\u003E status.OnDashFinished() );\r\n\t}\r\n\r\n\tpublic void DashRecharged()\r\n\t{\r\n\t\tNumDashesAvailable\u002B\u002B;\r\n\t\tvar numDashes = (int)MathF.Round( Stats[PlayerStat.NumDashes] );\r\n\t\tif ( NumDashesAvailable \u003E numDashes )\r\n\t\t\tNumDashesAvailable = numDashes;\r\n\r\n\t\tif ( NumDashesAvailable \u003C numDashes )\r\n\t\t{\r\n\t\t\tDashTimer = Stats[PlayerStat.DashCooldown];\r\n\t\t\tDashRechargeProgress = 0f;\r\n\t\t}\r\n\t\telse\r\n\t\t{\r\n\t\t\tDashRechargeProgress = 1f;\r\n\t\t}\r\n\r\n\t\tForEachStatus( status =\u003E status.OnDashRecharged() );\r\n\r\n\t\tManager.Instance.PlaySfxNearby( \u0022player.dash.recharge\u0022, Position2D, pitch: Utils.Map( NumDashesAvailable, 1, numDashes, 1f, 1.2f ), volume: 0.2f, maxDist: 5f );\r\n\t}\r\n\r\n\tvoid HandleBounds()\r\n\t{\r\n\t\tvar x_min = Manager.Instance.BOUNDS_MIN.x \u002B Radius;\r\n\t\tvar x_max = Manager.Instance.BOUNDS_MAX.x - Radius;\r\n\t\tvar y_min = Manager.Instance.BOUNDS_MIN.y;\r\n\t\tvar y_max = Manager.Instance.BOUNDS_MAX.y - Radius;\r\n\r\n\t\tif ( Position2D.x \u003C x_min )\r\n\t\t\tPosition2D = new Vector2( x_min, Position2D.y );\r\n\t\telse if ( Position2D.x \u003E x_max )\r\n\t\t\tPosition2D = new Vector2( x_max, Position2D.y );\r\n\r\n\t\tif ( Position2D.y \u003C y_min )\r\n\t\t\tPosition2D = new Vector2( Position2D.x, y_min );\r\n\t\telse if ( Position2D.y \u003E y_max )\r\n\t\t\tPosition2D = new Vector2( Position2D.x, y_max );\r\n\t}\r\n\r\n\tpublic int GetExperienceReqForLevel( int level )\r\n\t{\r\n\t\tswitch ( Manager.Instance.Difficulty )\r\n\t\t{\r\n\t\t\tcase -1:\r\n\t\t\t\treturn (int)MathF.Round( Utils.Map( level, 1, 150, 3f, 240f, EasingType.SineIn ) );\r\n\t\t\tcase 0:\r\n\t\t\tdefault:\r\n\t\t\t\treturn (int)MathF.Round( Utils.Map( level, 1, 150, 3f, 320f, EasingType.SineIn ) );\r\n\t\t}\r\n\t}\r\n\r\n\tpublic void Flash( float time )\r\n\t{\r\n\t\tif ( _isFlashing )\r\n\t\t\treturn;\r\n\r\n\t\t//Sprite.Tint = new Color( 1f, 0f, 0f );\r\n\t\tSprite.FlashTint = new Color( 1f, 0f, 0f, 1f );\r\n\t\t_isFlashing = true;\r\n\t\t_flashTimer = time;\r\n\t}\r\n\r\n\tpublic void Heal( float amount, float flashTime )\r\n\t{\r\n\t\t//Sprite.Tint = new Color( 0f, 1f, 0f );\r\n\t\tSprite.FlashTint = new Color( 0f, 1f, 0f, 1f );\r\n\t\t_isFlashing = true;\r\n\t\t_flashTimer = flashTime;\r\n\r\n\t\tif ( IsProxy )\r\n\t\t\treturn;\r\n\r\n\t\tif ( Health \u003C Stats[PlayerStat.MaxHp] )\r\n\t\t\tTimeSinceChangeHP = 0f;\r\n\r\n\t\tHealth \u002B= amount;\r\n\t\tif ( Health \u003E Stats[PlayerStat.MaxHp] )\r\n\t\t\tHealth = Stats[PlayerStat.MaxHp];\r\n\t}\r\n\r\n\tvoid HandleFlashing( float dt )\r\n\t{\r\n\t\tif ( _isFlashing )\r\n\t\t{\r\n\t\t\t_flashTimer -= dt;\r\n\t\t\tif ( _flashTimer \u003C 0f )\r\n\t\t\t{\r\n\t\t\t\t_isFlashing = false;\r\n\t\t\t\t//Sprite.Tint = Color.White;\r\n\t\t\t\tSprite.FlashTint = Color.White.WithAlpha( 0f );\r\n\t\t\t}\r\n\t\t}\r\n\t}\r\n\r\n\t[ConCmd( \u0022give_status\u0022 )]\r\n\tpublic static void GiveStatus( string name )\r\n\t{\r\n\t\t// Cheat only works in the editor\r\n\t\tif ( !Game.IsEditor )\r\n\t\t\treturn;\r\n\r\n\t\tvar type = TypeLibrary.GetType( name );\r\n\t\tif ( type == null )\r\n\t\t{\r\n\t\t\tLog.Info( $\u0022No status with name \u0027{name}\u0027 found!\u0022 );\r\n\t\t\treturn;\r\n\t\t}\r\n\r\n\t\tManager.Instance?.GetLocalPlayer()?.AddStatus( type );\r\n\t}\r\n\r\n\tpublic void AddStatus( TypeDescription type )\r\n\t{\r\n\t\tStatus status = null;\r\n\t\tvar typeIdentity = type.Identity;\r\n\r\n\t\tForEachStatus( status =\u003E status.OnAddStatus( typeIdentity ) );\r\n\r\n\t\tif ( Statuses.ContainsKey( typeIdentity ) )\r\n\t\t{\r\n\t\t\tstatus = Statuses[typeIdentity];\r\n\t\t\tstatus.Level\u002B\u002B;\r\n\t\t}\r\n\r\n\t\tif ( status == null )\r\n\t\t{\r\n\t\t\tstatus = StatusManager.CreateStatus( type );\r\n\t\t\tStatuses.Add( typeIdentity, status );\r\n\t\t\tstatus.Init( this );\r\n\t\t}\r\n\r\n\t\t//Sandbox.Services.Stats.Increment( Client, \u0022status\u0022, 1, $\u0022{type.Name.ToLowerInvariant()}\u0022, new { Status = type.Name.ToLowerInvariant(), Level = status.Level } );\r\n\r\n\t\tstatus.Refresh();\r\n\r\n\t\tManager.Instance.PlaySfxNearby( \u0022click\u0022, Position2D, 0.9f, 0.75f, 5f );\r\n\r\n\t\tLevelUpChoices.Clear();\r\n\t\tIsChoosingLevelUpReward = false;\r\n\t\tRealTimeSinceChoseUpgrade = 0f;\r\n\r\n\t\tCheckForLevelUp();\r\n\t}\r\n\r\n\tpublic bool HasStatus( TypeDescription type )\r\n\t{\r\n\t\treturn Statuses.ContainsKey( type.Identity );\r\n\t}\r\n\r\n\tpublic Status GetStatus( TypeDescription type )\r\n\t{\r\n\t\tif ( Statuses.ContainsKey( type.Identity ) )\r\n\t\t\treturn Statuses[type.Identity];\r\n\r\n\t\treturn null;\r\n\t}\r\n\r\n\tpublic int GetStatusLevel( TypeDescription type )\r\n\t{\r\n\t\tif ( Statuses.ContainsKey( type.Identity ) )\r\n\t\t\treturn Statuses[type.Identity].Level;\r\n\r\n\t\treturn 0;\r\n\t}\r\n\r\n\tpublic void Modify( Status caller, PlayerStat statType, float value, ModifierType type, float priority = 0f, bool update = true )\r\n\t{\r\n\t\tif ( !_modifiers_stat.ContainsKey( caller ) )\r\n\t\t\t_modifiers_stat.Add( caller, new Dictionary\u003CPlayerStat, ModifierData\u003E() );\r\n\r\n\t\t_modifiers_stat[caller][statType] = new ModifierData( value, type, priority );\r\n\r\n\t\tif ( update )\r\n\t\t\tUpdateProperty( statType );\r\n\t}\r\n\r\n\tpublic void AdjustBaseStat( PlayerStat statType, float amount, bool update = true )\r\n\t{\r\n\t\tif ( !_original_properties_stat.ContainsKey( statType ) )\r\n\t\t\t_original_properties_stat.Add( statType, Stats[statType] );\r\n\r\n\t\t_original_properties_stat[statType] \u002B= amount;\r\n\r\n\t\tif ( update )\r\n\t\t\tUpdateProperty( statType );\r\n\t}\r\n\r\n\tvoid UpdateProperty( PlayerStat statType )\r\n\t{\r\n\t\tif ( !_original_properties_stat.ContainsKey( statType ) )\r\n\t\t{\r\n\t\t\t_original_properties_stat.Add( statType, Stats[statType] );\r\n\t\t}\r\n\r\n\t\tfloat curr_value = _original_properties_stat[statType];\r\n\t\tfloat curr_set = curr_value;\r\n\t\tbool should_set = false;\r\n\t\tfloat curr_priority = 0f;\r\n\t\tfloat total_add = 0f;\r\n\t\tfloat total_mult = 1f;\r\n\r\n\t\tforeach ( Status caller in _modifiers_stat.Keys )\r\n\t\t{\r\n\t\t\tvar dict = _modifiers_stat[caller];\r\n\t\t\tif ( dict.ContainsKey( statType ) )\r\n\t\t\t{\r\n\t\t\t\tvar mod_data = dict[statType];\r\n\t\t\t\tswitch ( mod_data.type )\r\n\t\t\t\t{\r\n\t\t\t\t\tcase ModifierType.Set:\r\n\t\t\t\t\t\tif ( mod_data.priority \u003E= curr_priority )\r\n\t\t\t\t\t\t{\r\n\t\t\t\t\t\t\tcurr_set = mod_data.value;\r\n\t\t\t\t\t\t\tcurr_priority = mod_data.priority;\r\n\t\t\t\t\t\t\tshould_set = true;\r\n\t\t\t\t\t\t}\r\n\t\t\t\t\t\tbreak;\r\n\t\t\t\t\tcase ModifierType.Add:\r\n\t\t\t\t\t\ttotal_add \u002B= mod_data.value;\r\n\t\t\t\t\t\tbreak;\r\n\t\t\t\t\tcase ModifierType.Mult:\r\n\t\t\t\t\t\ttotal_mult *= mod_data.value;\r\n\t\t\t\t\t\tbreak;\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\tif ( should_set )\r\n\t\t\tcurr_value = curr_set;\r\n\r\n\t\tcurr_value \u002B= total_add;\r\n\t\tcurr_value *= total_mult;\r\n\r\n\t\tStats[statType] = curr_value;\r\n\r\n\t\tif ( statType == PlayerStat.MaxHp )\r\n\t\t\tStats[statType] = Math.Max( curr_value, 1f );\r\n\t}\r\n\r\n\tpublic void AddExperience( int xp )\r\n\t{\r\n\t\tExperienceTotal \u002B= xp;\r\n\t\tExperienceCurrent \u002B= xp;\r\n\r\n\t\t//var particle = DamageNumbersLegacy.Create( xp, Position2D \u002B new Vector2( 0.2f \u002B Game.Random.Float( -0.1f, 0.1f ), Radius * 3f \u002B Game.Random.Float( -0.2f, 0.3f ) ), color: new Color(0.1f, 0.1f, 1f), sizeMultiplier: 0.8f );\r\n\t\t//Vector3 velocity = new Vector3( 0f, 0f, 0f );\r\n\t\t//Vector3 gravity = new Vector3( 0f, 1f, 0f );\r\n\t\t//particle.SetVector( 1, velocity );\r\n\t\t//particle.SetNamedValue( \u0022Gravity\u0022, gravity );\r\n\r\n\t\tvar pos = Position2D \u002B new Vector2( Game.Random.Float( -0.1f, 0.1f ), Radius * 3f \u002B Game.Random.Float( -0.2f, 0.3f ) );\r\n\t\tfloat size = Utils.Map( xp, 1f, 4f, 0.95f, 1.1f, EasingType.Linear );\r\n\t\tvar color = new Color( 0.4f, 0.4f, 1f );\r\n\t\tManager.Instance.SpawnDamageNumber( pos, xp, color, size, FloaterType.Xp );\r\n\r\n\t\tForEachStatus( status =\u003E status.OnGainExperience( xp ) );\r\n\t\tif ( !IsChoosingLevelUpReward )\r\n\t\t\tCheckForLevelUp();\r\n\t}\r\n\r\n\tpublic void LoseExperience( int amount )\r\n\t{\r\n\t\tExperienceCurrent = Math.Max( ExperienceCurrent - amount, 0 );\r\n\t}\r\n\r\n\tpublic void CheckForLevelUp()\r\n\t{\r\n\t\t//Log.Info(\u0022CheckForLevelUp: \u0022 \u002B ExperienceCurrent \u002B \u0022 / \u0022 \u002B ExperienceRequired \u002B \u0022 IsServer: \u0022 \u002B Sandbox.Game.IsServer \u002B \u0022 Level: \u0022 \u002B Level);\r\n\t\tif ( ExperienceCurrent \u003E= ExperienceRequired \u0026\u0026 Manager.Instance.ShouldUpdatePlayer )\r\n\t\t\tLevelUp();\r\n\t}\r\n\r\n\tpublic void LevelUp()\r\n\t{\r\n\t\tExperienceCurrent -= ExperienceRequired;\r\n\r\n\t\tLevel\u002B\u002B;\r\n\t\tExperienceRequired = GetExperienceReqForLevel( Level \u002B 1 );\r\n\r\n\t\tif ( Manager.Instance.Difficulty \u003C 3 )\r\n\t\t\tNumRerollAvailable \u002B= (int)Stats[PlayerStat.NumRerollsPerLevel];\r\n\r\n\t\tManager.Instance.PlaySfxNearby( \u0022levelup\u0022, Position2D, Game.Random.Float( 0.95f, 1.05f ), 0.5f, 5f );\r\n\r\n\t\tForEachStatus( status =\u003E status.OnLevelUp() );\r\n\r\n\t\tGenerateLevelUpChoices();\r\n\t\tIsChoosingLevelUpReward = true;\r\n\t\tTimeSinceLevelUp = 0f;\r\n\r\n\t\tif ( Manager.Instance.Difficulty \u003E= 0 \u0026\u0026 !_hasUnlockedExperiencedAchievement \u0026\u0026 Level \u003E= 85 )\r\n\t\t{\r\n\t\t\tSandbox.Services.Achievements.Unlock( \u0022experienced\u0022 );\r\n\t\t\t_hasUnlockedExperiencedAchievement = true;\r\n\t\t}\r\n\t}\r\n\r\n\tpublic void UseReroll()\r\n\t{\r\n\t\tif ( NumRerollAvailable \u003C= 0 )\r\n\t\t{\r\n\t\t\t// todo: sfx\r\n\t\t\treturn;\r\n\t\t}\r\n\r\n\t\tManager.Instance.PlaySfxNearby( \u0022reroll\u0022, Position2D, Utils.Map( NumRerollAvailable, 0, 20, 0.9f, 1.4f, EasingType.QuadIn ), 0.6f, 5f );\r\n\r\n\t\tNumRerollAvailable--;\r\n\r\n\t\tGenerateLevelUpChoices();\r\n\r\n\t\tForEachStatus( status =\u003E status.OnReroll() );\r\n\t}\r\n\r\n\t/// \u003Csummary\u003E\r\n\t/// Number of level up choices that have a hotkey (Slot1..Slot6 actions).\r\n\t/// \u003C/summary\u003E\r\n\tpublic const int NUM_CHOICE_HOTKEYS = 6;\r\n\r\n\tpublic void UseChoiceHotkey( int num )\r\n\t{\r\n\t\tvar index = num - 1;\r\n\r\n\t\tif ( !IsChoosingLevelUpReward || index \u003E= LevelUpChoices.Count )\r\n\t\t\treturn;\r\n\r\n\t\tAddStatus( TypeLibrary.GetType( LevelUpChoices[index].GetType() ) );\r\n\t}\r\n\r\n\tpublic float CheckDamageAmount( float damage, DamageType damageType )\r\n\t{\r\n\t\tif ( IsInvulnerable )\r\n\t\t{\r\n\t\t\treturn 0f;\r\n\t\t}\r\n\r\n\t\tif ( HasStatus( TypeLibrary.GetType( typeof( ShieldStatus ) ) ) \u0026\u0026 damageType != DamageType.LavaPuddle )\r\n\t\t{\r\n\t\t\tvar shieldStatus = GetStatus( TypeLibrary.GetType( typeof( ShieldStatus ) ) ) as ShieldStatus;\r\n\t\t\tif ( shieldStatus != null \u0026\u0026 shieldStatus.IsShielded )\r\n\t\t\t{\r\n\t\t\t\tshieldStatus.LoseShield();\r\n\t\t\t\treturn 0f;\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\tif ( Stats[PlayerStat.DamageReductionPercent] \u003E 0f )\r\n\t\t\tdamage *= (1f - MathX.Clamp( Stats[PlayerStat.DamageReductionPercent], 0f, 1f ));\r\n\r\n\t\tif ( Stats[PlayerStat.IncreasedDmgTaken] \u003E 0f )\r\n\t\t\tdamage *= (1f \u002B MathX.Clamp( Stats[PlayerStat.IncreasedDmgTaken], 0f, 1f ));\r\n\r\n\t\tif ( damageType == DamageType.Explosion \u0026\u0026 Stats[PlayerStat.ExplosionDamageReductionPercent] \u003E 0f )\r\n\t\t\tdamage *= (1f - MathX.Clamp( Stats[PlayerStat.ExplosionDamageReductionPercent], 0f, 1f ));\r\n\r\n\t\tif ( damageType != DamageType.Explosion \u0026\u0026 Stats[PlayerStat.NonExplosionDamageIncreasePercent] \u003E 0f )\r\n\t\t\tdamage *= (1f \u002B Stats[PlayerStat.NonExplosionDamageIncreasePercent]);\r\n\r\n\t\tif ( Manager.Instance.Difficulty \u003C 0 )\r\n\t\t\tdamage *= 0.571429f; // so zombie\u0027s 7 dmg becomes 4 dmg\r\n\r\n\t\treturn damage;\r\n\t}\r\n\r\n\tpublic void Damage( float damage, PlayerDamageType playerDamageType = PlayerDamageType.Enemy )\r\n\t{\r\n\t\tif ( !Manager.Instance.ShouldUpdatePlayer )\r\n\t\t\treturn;\r\n\r\n\t\tTimeSinceHurt = 0f;\r\n\r\n\t\tbool isCrit = Game.Random.Float( 0f, 1f ) \u003C Stats[PlayerStat.SelfCritChance];\r\n\r\n\t\tif ( isCrit )\r\n\t\t\tdamage *= 2f;\r\n\r\n\t\tif ( damage \u003E 0f )\r\n\t\t{\r\n\t\t\tTimeSinceChangeHP = 0f;\r\n\t\t\tFlash( 0.125f );\r\n\t\t}\r\n\r\n\t\tvar offset = new Vector2(\r\n\t\t\tGame.Random.Float( -0.1f, 0.1f ),\r\n\t\t\tRadius * 3f \u002B Game.Random.Float( -0.2f, 0.3f ) \u002B (Health - damage \u003C 0f ? -0.7f : 0f)\r\n\t\t);\r\n\r\n\t\t//DamageNumbers.Add( (int)damage, Position2D \u002B Vector2.Up * Radius * 3f \u002B new Vector2( Game.Random.Float( -1f, 1f ), Game.Random.Float( -1f, 1f ) ) * 0.2f, color: Color.Red );\r\n\t\t//DamageNumbersLegacy.Create( damage, Position2D \u002B offset, color: isCrit ? Color.Orange : Color.Red );\r\n\r\n\t\tvar pos = Position2D \u002B offset;\r\n\r\n\t\tfloat size;\r\n\t\tif ( damage \u003C 5f ) size = Utils.Map( damage, 1f, 5f, 1.1f, 1.25f, EasingType.QuadOut );\r\n\t\telse if ( damage \u003C 20f ) size = Utils.Map( damage, 5f, 20f, 1.25f, 1.6f, EasingType.Linear );\r\n\t\telse size = Utils.Map( damage, 20f, 100f, 1.6f, 1.8f, EasingType.Linear );\r\n\r\n\t\tvar color = isCrit ? Color.Orange : Color.Red;\r\n\r\n\t\tManager.Instance.SpawnDamageNumber( pos, damage, color, size );\r\n\r\n\t\tForEachStatus( status =\u003E status.OnHurt( damage ) );\r\n\r\n\t\tHealth -= damage;\r\n\r\n\t\t//if ( damage \u003E 3f )\r\n\t\t//\tShakeCam( Utils.Map( damage, 3f, 25f, 0f, 0.1f ), Utils.Map( damage, 3f, 20f, 0.1f, 0.25f ), EasingType.QuadOut );\r\n\r\n\t\tif ( Health \u003C= 0f )\r\n\t\t{\r\n\t\t\tDie();\r\n\t\t\tSpawnBlood( damage, sizeMultiplier: Game.Random.Float( 2.5f, 3f ), playbackSpeed: Game.Random.Float( 20f, 25f ), shouldUseRealTime: true );\r\n\t\t}\r\n\t\telse\r\n\t\t{\r\n\t\t\tSpawnBlood( damage );\r\n\t\t}\r\n\t}\r\n\r\n\tpublic void AddVelocity( Vector2 vel )\r\n\t{\r\n\t\tif ( !Manager.Instance.ShouldUpdatePlayer )\r\n\t\t\treturn;\r\n\r\n\t\tVelocity \u002B= vel;\r\n\t}\r\n\r\n\tpublic void SpawnBlood( float damage, float sizeMultiplier = 1f, float playbackSpeed = 0f, bool shouldUseRealTime = false )\r\n\t{\r\n\t\tvar blood = Manager.Instance.SpawnBloodSplatter( Position2D );\r\n\r\n\t\tif ( blood != null )\r\n\t\t{\r\n\t\t\tblood.LocalScale *= Utils.Map( damage, 1f, 20f, 0.5f, 1.2f, EasingType.QuadIn ) * Game.Random.Float( 0.8f, 1.2f ) * sizeMultiplier;\r\n\t\t\tblood.Lifetime *= 0.3f;\r\n\t\t\tblood.ShouldUseRealTime = shouldUseRealTime;\r\n\r\n\t\t\tif ( playbackSpeed \u003E 0f )\r\n\t\t\t\tblood.Sprite.PlaybackSpeed = playbackSpeed;\r\n\t\t}\r\n\t}\r\n\r\n\tpublic void Die()\r\n\t{\r\n\t\tif ( IsDead )\r\n\t\t\treturn;\r\n\r\n\t\tIsDead = true;\r\n\t\t_hasPlayedDeathSfx = false;\r\n\t\tSprite.Tint = new Color( 1f, 1f, 1f, 1f );\r\n\t\tSprite.FlashTint = new Color( 1f, 1f, 1f, 0f );\r\n\t\t//ShadowOpacity = 0.2f;\r\n\t\t_isFlashing = false;\r\n\t\tIsReloading = false;\r\n\r\n\t\tRealTimeSinceDeath = 0f;\r\n\t\t_arrowDeathAlphaStart = ArrowSprite.Tint.a;\r\n\r\n\t\tvar pitch = Game.Random.Float( 1.25f, 1.3f ) * (Manager.Instance.Difficulty \u003C 0 ? 2f : 1f);\r\n\t\tManager.Instance.PlaySfxNearby( \u0022die\u0022, Position2D, pitch, volume: 1.5f, maxDist: 12f );\r\n\r\n\t\tSprite.LocalScale *= 2f;\r\n\r\n\t\tSprite.PlayAnimation( $\u0022death\u0022 );\r\n\t\t//Sprite.PlayAnimation( \u0022ghost_idle\u0022 );\r\n\r\n\t\tShakeCam( Game.Random.Float( 0.025f, 0.065f ), Game.Random.Float( 0.3f, 0.5f ), EasingType.SineOut, useRealTime: true );\r\n\r\n\t\tif ( IsProxy )\r\n\t\t\treturn;\r\n\r\n\t\tManager.Instance.PlayerDied( this );\r\n\t}\r\n\r\n\tpublic void Revive()\r\n\t{\r\n\t\tif ( !IsDead )\r\n\t\t\treturn;\r\n\r\n\t\tIsDead = false;\r\n\t\tIsChoosingLevelUpReward = false;\r\n\t\tIsDashing = false;\r\n\t\tIsReloading = true;\r\n\t\tSprite.Tint = Color.White;\r\n\t\tShadowOpacity = 0.8f;\r\n\r\n\t\tif ( IsProxy )\r\n\t\t\treturn;\r\n\r\n\t\tTimer = Stats[PlayerStat.ReloadTime];\r\n\t\tReloadProgress = 0f;\r\n\t\tDashProgress = 0f;\r\n\t\tExperienceCurrent = 0;\r\n\r\n\t\tHealth = Stats[PlayerStat.MaxHp] * 0.33f;\r\n\t}\r\n\r\n\tpublic void ForEachStatus( Action\u003CStatus\u003E action )\r\n\t{\r\n\t\tif ( IsProxy )\r\n\t\t\treturn;\r\n\r\n\t\tforeach ( var (_, status) in Statuses )\r\n\t\t{\r\n\t\t\taction( status );\r\n\t\t}\r\n\t}\r\n\r\n\tvoid HandleStatuses( float dt )\r\n\t{\r\n\t\tforeach ( KeyValuePair\u003Cint, Status\u003E pair in Statuses )\r\n\t\t{\r\n\t\t\tStatus status = pair.Value;\r\n\t\t\tif ( status.ShouldUpdate )\r\n\t\t\t\tstatus.Update( dt );\r\n\t\t}\r\n\t}\r\n\r\n\tvoid HandleShooting( float dt )\r\n\t{\r\n\t\tif ( IsReloading )\r\n\t\t{\r\n\t\t\tReloadProgress = Utils.Map( Timer, Stats[PlayerStat.ReloadTime], 0f, 0f, 1f );\r\n\t\t\tTimer -= dt * Stats[PlayerStat.ReloadSpeed];\r\n\t\t\tif ( Timer \u003C= 0f )\r\n\t\t\t{\r\n\t\t\t\tReload();\r\n\t\t\t}\r\n\t\t}\r\n\t\telse\r\n\t\t{\r\n\t\t\tTimer -= dt * Stats[PlayerStat.AttackSpeed] * (IsMoving ? 1f : Stats[PlayerStat.AttackSpeedStill]);\r\n\t\t\tif ( Timer \u003C= 0f )\r\n\t\t\t{\r\n\t\t\t\tShoot( isLastAmmo: AmmoCount == 1 );\r\n\t\t\t\tAmmoCount--;\r\n\r\n\t\t\t\tif ( AmmoCount \u003C= 0 )\r\n\t\t\t\t{\r\n\t\t\t\t\tIsReloading = true;\r\n\r\n\t\t\t\t\tTimer \u002B= Stats[PlayerStat.ReloadTime];\r\n\t\t\t\t}\r\n\t\t\t\telse\r\n\t\t\t\t{\r\n\t\t\t\t\tTimer \u002B= Stats[PlayerStat.AttackTime];\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t}\r\n\t}\r\n\r\n\tpublic void Shoot( bool isLastAmmo = false )\r\n\t{\r\n\t\tint num_bullets_int = (int)Stats[PlayerStat.NumProjectiles];\r\n\r\n\t\tvar aimDir = Game.Random.Float( 0f, 1f ) \u003C Stats[PlayerStat.ShootRandomDirChance]\r\n\t\t\t? Utils.GetRandomVector()\r\n\t\t\t: AimDir;\r\n\r\n\t\tvar pos = Position2D \u002B AimDir * 0.3f;\r\n\r\n\t\tif ( Stats[PlayerStat.MaxBulletSpread] \u003E 0f )\r\n\t\t{\r\n\t\t\tfloat increment = 360f / num_bullets_int;\r\n\r\n\t\t\tfor ( int i = 0; i \u003C num_bullets_int; i\u002B\u002B )\r\n\t\t\t{\r\n\t\t\t\tvar dir = Utils.RotateVector( aimDir, i * increment );\r\n\t\t\t\tSpawnBullet( pos, dir, isLastAmmo );\r\n\t\t\t}\r\n\t\t}\r\n\t\telse\r\n\t\t{\r\n\t\t\tfloat start_angle = MathF.Sin( -_shotNum * 2f ) * Stats[PlayerStat.BulletInaccuracy];\r\n\r\n\t\t\tvar spread = Stats[PlayerStat.BulletSpread] * num_bullets_int;\r\n\r\n\t\t\tfloat currAngleOffset = num_bullets_int == 1 ? 0f : -spread * 0.5f;\r\n\t\t\tfloat increment = num_bullets_int == 1 ? 0f : spread / (float)(num_bullets_int - 1);\r\n\r\n\t\t\tfor ( int i = 0; i \u003C num_bullets_int; i\u002B\u002B )\r\n\t\t\t{\r\n\t\t\t\tvar dir = Utils.RotateVector( aimDir, start_angle \u002B currAngleOffset \u002B increment * i );\r\n\t\t\t\tSpawnBullet( pos, dir, isLastAmmo );\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\tManager.Instance.PlaySfxNearby( \u0022shoot\u0022, pos, pitch: Utils.Map( _shotNum, 0f, (float)Stats[PlayerStat.MaxAmmoCount], 1f, 1.25f ), volume: 1f, maxDist: 4f );\r\n\r\n\t\tVelocity -= aimDir * Stats[PlayerStat.Recoil];\r\n\r\n\t\t_shotNum\u002B\u002B;\r\n\t\t_timeSinceShoot = 0f;\r\n\t}\r\n\r\n\tvoid SpawnBullet( Vector2 pos, Vector2 dir, bool isLastAmmo = false, float damageMult = 1f )\r\n\t{\r\n\t\tvar damage = (Stats[PlayerStat.BulletDamage] * Stats[PlayerStat.BulletDamageMultiplier] \u002B Stats[PlayerStat.BulletFlatDamageAddition]) * GetDamageMultiplier() * damageMult;\r\n\t\tif ( isLastAmmo )\r\n\t\t\tdamage *= Stats[PlayerStat.LastAmmoDamageMultiplier];\r\n\r\n\t\tif ( Stats[PlayerStat.DamagePerEarlierShot] \u003E 0f )\r\n\t\t\tdamage \u002B= _shotNum * Stats[PlayerStat.DamagePerEarlierShot];\r\n\r\n\t\tif ( Stats[PlayerStat.DamageForSpeed] \u003E 0f )\r\n\t\t{\r\n\t\t\tdamage \u002B= Stats[PlayerStat.DamageForSpeed] * Velocity.Length;\r\n\r\n\t\t\tif ( IsDashing )\r\n\t\t\t\tdamage \u002B= Stats[PlayerStat.DamageForSpeed] * DashVelocity.Length;\r\n\t\t}\r\n\r\n\t\tvar bulletObj = BulletPrefab.Clone( (Vector3)pos );\r\n\t\tvar bullet = bulletObj.Components.Get\u003CBullet\u003E();\r\n\r\n\t\tbullet.Velocity = dir * Stats[PlayerStat.BulletSpeed];\r\n\t\tbullet.Shooter = this;\r\n\t\tbullet.TempWeight = 3f;\r\n\r\n\t\tbullet.Stats[BulletStat.Damage] = damage;\r\n\t\tbullet.Stats[BulletStat.Force] = Stats[PlayerStat.BulletForce];\r\n\t\tbullet.Stats[BulletStat.Lifetime] = Stats[PlayerStat.BulletLifetime];\r\n\t\tbullet.Stats[BulletStat.NumPiercing] = (int)MathF.Round( Stats[PlayerStat.BulletNumPiercing] );\r\n\t\tbullet.Stats[BulletStat.NumBouncing] = (int)MathF.Round( Stats[PlayerStat.BulletNumBouncing] );\r\n\t\tbullet.Stats[BulletStat.WillIgnite] = Game.Random.Float( 0f, 1f ) \u003C Stats[PlayerStat.ShootFireIgniteChance] ? 1f : 0f;\r\n\t\tbullet.Stats[BulletStat.WillFreeze] = Game.Random.Float( 0f, 1f ) \u003C Stats[PlayerStat.ShootFreezeChance] ? 1f : 0f;\r\n\t\tbullet.Stats[BulletStat.GrowDamageAmount] = Stats[PlayerStat.BulletDamageGrow];\r\n\t\tbullet.Stats[BulletStat.ShrinkDamageAmount] = Stats[PlayerStat.BulletDamageShrink];\r\n\t\tbullet.Stats[BulletStat.DistanceDamageAmount] = Stats[PlayerStat.BulletDistanceDamage];\r\n\t\tbullet.Stats[BulletStat.HealTeammateAmount] = Stats[PlayerStat.BulletHealTeammateAmount];\r\n\t\tbullet.IsHoming = Game.Random.Float( 0f, 1f ) \u003C Stats[PlayerStat.HomingBulletChance];\r\n\r\n\t\tif ( Stats[PlayerStat.GrenadesCanCrit] \u003C= 0f )\r\n\t\t{\r\n\t\t\tbullet.Stats[BulletStat.CriticalChance] = Stats[PlayerStat.CritChance];\r\n\t\t\tbullet.Stats[BulletStat.CriticalMultiplier] = Stats[PlayerStat.CritMultiplier];\r\n\t\t}\r\n\r\n\t\tbullet.Init();\r\n\r\n\t\t//bullet.GameObject.NetworkSpawn( Network.Owner );\r\n\t}\r\n\r\n\tvoid Reload()\r\n\t{\r\n\t\tAmmoCount = (int)Stats[PlayerStat.MaxAmmoCount];\r\n\t\tIsReloading = false;\r\n\t\t_shotNum = 0;\r\n\t\tReloadProgress = 0f;\r\n\r\n\t\tForEachStatus( status =\u003E status.OnReload() );\r\n\t}\r\n\r\n\tpublic float GetDamageMultiplier()\r\n\t{\r\n\t\tfloat damageMultiplier = Stats[PlayerStat.OverallDamageMultiplier];\r\n\r\n\t\tif ( Stats[PlayerStat.LowHealthDamageMultiplier] \u003E 1f )\r\n\t\t\tdamageMultiplier *= Utils.Map( Health, Stats[PlayerStat.MaxHp], 0f, 1f, Stats[PlayerStat.LowHealthDamageMultiplier] );\r\n\r\n\t\tif ( Stats[PlayerStat.FullHealthDamageMultiplier] \u003E 1f \u0026\u0026 !(Health \u003C Stats[PlayerStat.MaxHp]) )\r\n\t\t\tdamageMultiplier *= Stats[PlayerStat.FullHealthDamageMultiplier];\r\n\r\n\t\treturn damageMultiplier;\r\n\t}\r\n\r\n\tpublic override void Colliding( Thing other, float percent, float dt )\r\n\t{\r\n\t\tbase.Colliding( other, percent, dt );\r\n\r\n\t\tif ( IsDead )\r\n\t\t\treturn;\r\n\r\n\t\tForEachStatus( status =\u003E status.Colliding( other, percent, dt ) );\r\n\r\n\t\tif ( other is Enemy enemy \u0026\u0026 !enemy.IsDying )\r\n\t\t{\r\n\t\t\tif ( !Position2D.Equals( other.Position2D ) )\r\n\t\t\t{\r\n\t\t\t\tvar spawnFactor = Utils.Map( enemy.TimeSinceSpawn, 0f, enemy.SpawnTime, 0f, 1f, EasingType.QuadIn );\r\n\t\t\t\tVelocity \u002B= (Position2D - other.Position2D).Normal * Utils.Map( percent, 0f, 1f, 0f, 100f ) * (1f \u002B other.TempWeight) * spawnFactor * dt;\r\n\t\t\t}\r\n\t\t}\r\n\t\telse if ( other is Player player )\r\n\t\t{\r\n\t\t\tif ( !player.IsDead \u0026\u0026 !Position2D.Equals( other.Position2D ) )\r\n\t\t\t{\r\n\t\t\t\tVelocity \u002B= (Position2D - other.Position2D).Normal * Utils.Map( percent, 0f, 1f, 0f, 100f ) * (1f \u002B other.TempWeight) * dt;\r\n\t\t\t}\r\n\t\t}\r\n\t}\r\n\r\n\tpublic void SpawnDashCloudClient()\r\n\t{\r\n\t\tManager.Instance.SpawnCloud( Position2D \u002B new Vector2( Game.Random.Float( -1f, 1f ), Game.Random.Float( -1f, 1f ) ) * 0.05f );\r\n\t}\r\n\r\n\tpublic void GenerateLevelUpChoices()\r\n\t{\r\n\t\tLevelUpChoices.Clear();\r\n\r\n\t\t//if( Level == 1)\r\n\t\t//{\r\n\t\t//\tLevelUpChoices.Add( CreateStatus( TypeLibrary.GetType( typeof( PauseWhileChoosingStatus ) ) ) );\r\n\t\t//\tLevelUpChoices.Add( CreateStatus( TypeLibrary.GetType( typeof( MysteryBoxStatus ) ) ) );\r\n\t\t//\tLevelUpChoices.Add( CreateStatus( GetRandomStartingPerk() ) );\r\n\r\n\t\t//\tLevelUpChoices.Shuffle();\r\n\r\n\t\t//\treturn;\r\n\t\t//}\r\n\r\n\t\tbool offerCurses = false;\r\n\t\tif ( Manager.Instance.Difficulty \u003E= 6 )\r\n\t\t\tofferCurses = IsLevelCursed( Level );\r\n\r\n\t\tint numChoices = Math.Clamp( (int)MathF.Round( Stats[PlayerStat.NumUpgradeChoices] ), 1, 6 );\r\n\t\tList\u003CTypeDescription\u003E statusTypes = StatusManager.GetRandomStatuses( this, numChoices, offerCurses );\r\n\r\n\t\tfor ( int i = 0; i \u003C statusTypes.Count; i\u002B\u002B )\r\n\t\t\tLevelUpChoices.Add( CreateStatus( statusTypes[i] ) );\r\n\r\n\t\tif ( Level == 1 )\r\n\t\t{\r\n\t\t\tbool alreadyOffered = false;\r\n\r\n\t\t\tforeach ( var status in LevelUpChoices )\r\n\t\t\t{\r\n\t\t\t\tif ( status is PauseWhileChoosingStatus )\r\n\t\t\t\t{\r\n\t\t\t\t\talreadyOffered = true;\r\n\t\t\t\t\tbreak;\r\n\t\t\t\t}\r\n\t\t\t}\r\n\r\n\t\t\tif ( !alreadyOffered )\r\n\t\t\t{\r\n\t\t\t\tLevelUpChoices.RemoveAt( 1 );\r\n\t\t\t\tLevelUpChoices.Add( CreateStatus( TypeLibrary.GetType( typeof( PauseWhileChoosingStatus ) ) ) );\r\n\t\t\t\tLevelUpChoices.Shuffle();\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\tChoiceHash\u002B\u002B;\r\n\t}\r\n\r\n\tpublic bool IsLevelCursed( int level )\r\n\t{\r\n\t\tif ( Manager.Instance.Difficulty \u003C 6 || level \u003C= 1 )\r\n\t\t\treturn false;\r\n\r\n\t\tswitch ( Manager.Instance.Difficulty )\r\n\t\t{\r\n\t\t\tcase 6: return level % 10 == 0;\r\n\t\t\tcase 7: return level % 9 == 0;\r\n\t\t\tcase 8: return level % 8 == 0;\r\n\t\t\tcase 9: return level % 7 == 0;\r\n\t\t\tcase 10: return level % 6 == 0;\r\n\t\t\tcase 11: return level % 5 == 0;\r\n\t\t\tcase 12: return level % 4 == 0;\r\n\t\t\tcase 13: return level % 3 == 0;\r\n\t\t\tcase 14: return level % 2 == 0;\r\n\t\t\tcase 15: return level % 3 != 1;\r\n\t\t}\r\n\r\n\t\treturn false;\r\n\t}\r\n\r\n\tTypeDescription GetRandomStartingPerk()\r\n\t{\r\n\t\tList\u003C(TypeDescription Type, float Weight)\u003E perks = new List\u003C(TypeDescription, float)\u003E\r\n\t\t{\r\n\t\t\t(TypeLibrary.GetType( typeof( DamageStatus ) ), 5f),\r\n\t\t\t(TypeLibrary.GetType( typeof( MovespeedStatus ) ), 3f),\r\n\t\t\t(TypeLibrary.GetType( typeof( AttackSpeedStatus ) ), 2f),\r\n\t\t\t(TypeLibrary.GetType( typeof( NumProjectileStatus ) ), 2f),\r\n\t\t\t(TypeLibrary.GetType( typeof( PiercingStatus ) ), 3f),\r\n\t\t\t(TypeLibrary.GetType( typeof( GrenadeShootReloadStatus ) ), 1f),\r\n\t\t\t(TypeLibrary.GetType( typeof( NumDashesStatus ) ), 2f),\r\n\t\t\t(TypeLibrary.GetType( typeof( FireIgniteStatus ) ), 2f),\r\n\t\t\t(TypeLibrary.GetType( typeof( FreezeShootStatus ) ), 2f),\r\n\t\t\t(TypeLibrary.GetType( typeof( FullHealthDamageStatus ) ), 2f),\r\n\t\t\t(TypeLibrary.GetType( typeof( MoreRerollsStatus ) ), 4f),\r\n\t\t\t(TypeLibrary.GetType( typeof( MoreChoicesStatus ) ), 3f),\r\n\t\t\t(TypeLibrary.GetType( typeof( ReloadSpeedStatus ) ), 1f),\r\n\t\t\t(TypeLibrary.GetType( typeof( XpDamageStatus ) ), 1f),\r\n\t\t\t(TypeLibrary.GetType( typeof( HomingBulletStatus ) ), 4f),\r\n\t\t\t(TypeLibrary.GetType( typeof( ThornsStatus ) ), 1f),\r\n\t\t\t(TypeLibrary.GetType( typeof( BouncingBulletStatus ) ), 3f),\r\n\t\t};\r\n\r\n\t\tTypeDescription chosenPerk = null;\r\n\r\n\t\tfloat totalWeight = perks.Sum( x =\u003E x.Weight );\r\n\t\tvar rand = Game.Random.Float( 0f, totalWeight );\r\n\r\n\t\tfor ( int i = perks.Count - 1; i \u003E= 0; i-- )\r\n\t\t{\r\n\t\t\tvar (type, weight) = perks[i];\r\n\t\t\trand -= weight;\r\n\r\n\t\t\tif ( rand \u003C 0f )\r\n\t\t\t{\r\n\t\t\t\tchosenPerk = type;\r\n\t\t\t\tbreak;\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\treturn chosenPerk;\r\n\t}\r\n\r\n\tStatus CreateStatus( TypeDescription type )\r\n\t{\r\n\t\tvar status = StatusManager.CreateStatus( type );\r\n\t\tvar currLevel = GetStatusLevel( type );\r\n\t\tstatus.Level = currLevel \u002B 1;\r\n\t\treturn status;\r\n\t}\r\n\r\n\tpublic void Restart()\r\n\t{\r\n\t\tSprite.PlayAnimation( \u0022idle\u0022 );\r\n\t\tSprite.PlaybackSpeed = 0.66f;\r\n\r\n\t\tSprite.Tint = new Color( 1f, 1f, 1f, 1f );\r\n\r\n\t\tSprite.LocalScale = new Vector3( Globals.SPRITE_SCALE );\r\n\r\n\t\tif ( IsProxy )\r\n\t\t\treturn;\r\n\r\n\t\tPosition2D = new Vector3( Game.Random.Float( -3f, 3f ), Game.Random.Float( -3f, 3f ) );\r\n\t\tManager.Instance.Camera2D.SetPos( Position2D );\r\n\r\n\t\tInitializeStats();\r\n\r\n\t\tManager.Instance.PlaySfxNearby( \u0022restart\u0022, Position2D, Game.Random.Float( 0.95f, 1.05f ), 0.66f, 4f );\r\n\t}\r\n\r\n\tpublic void SpawnBulletRing( Vector2 pos, int numBullets, Vector2 aimDir, float damageMultMin = 1f, float damageMultMax = 1f )\r\n\t{\r\n\t\tfloat increment = 360f / numBullets;\r\n\r\n\t\tfor ( int i = 0; i \u003C numBullets; i\u002B\u002B )\r\n\t\t{\r\n\t\t\tvar dir = Utils.RotateVector( aimDir, i * increment );\r\n\t\t\tfloat damageMult = Game.Random.Float( damageMultMin, damageMultMax );\r\n\t\t\tSpawnBullet( pos, dir, false, damageMult );\r\n\t\t}\r\n\r\n\t\tManager.Instance.PlaySfxNearby( \u0022shoot\u0022, pos, pitch: 1f, volume: 1f, maxDist: 3f );\r\n\t}\r\n\r\n\tpublic Grenade SpawnGrenade( Vector2 pos, Vector2 vel )\r\n\t{\r\n\t\tvar grenadeObj = Manager.Instance.GrenadePrefab.Clone();\r\n\r\n\t\tvar grenade = grenadeObj.Components.Get\u003CGrenade\u003E();\r\n\t\tgrenade.Velocity = vel;\r\n\t\tgrenade.ExplosionSizeMultiplier = Stats[PlayerStat.ExplosionSizeMultiplier];\r\n\t\tgrenade.Player = this;\r\n\t\tgrenade.StickyPercent = Stats[PlayerStat.GrenadeStickyPercent];\r\n\t\tgrenade.FearChance = Stats[PlayerStat.GrenadeFearChance];\r\n\r\n\t\tif ( Stats[PlayerStat.GrenadesCanCrit] \u003E 0f )\r\n\t\t{\r\n\t\t\tgrenade.CriticalChance = Stats[PlayerStat.CritChance];\r\n\t\t\tgrenade.CriticalMultiplier = Stats[PlayerStat.CritMultiplier];\r\n\t\t}\r\n\r\n\t\t//grenadeObj.NetworkSpawn( Network.Owner );\r\n\t\tgrenadeObj.WorldPosition = new Vector3( pos.x, pos.y, Globals.GetZPos( pos.y ) );\r\n\r\n\t\tManager.Instance.AddThing( grenade );\r\n\r\n\t\treturn grenade;\r\n\t}\r\n\r\n\tpublic void CreateShieldVfx()\r\n\t{\r\n\t\t_shieldVfx = Manager.Instance.ShieldVfxPrefab.Clone( WorldPosition );\r\n\t\t_shieldVfx.Parent = GameObject;\r\n\t\t_shieldVfx.LocalPosition = new Vector3( 0f, 0f, 0.1f );\r\n\t\t_shieldVfx.LocalScale = new Vector3( 1f ) * 1.8f * Globals.SPRITE_SCALE;\r\n\t\t_shieldVfx.LocalRotation = new Angles( 0f, -90f, 0f );\r\n\t}\r\n\r\n\tpublic void RemoveShieldVfx()\r\n\t{\r\n\t\tif ( _shieldVfx != null )\r\n\t\t{\r\n\t\t\t_shieldVfx.Destroy();\r\n\t\t\t_shieldVfx = null;\r\n\t\t}\r\n\t}\r\n\r\n\tpublic void PlaySfx( string name, Vector2 pos, float pitch, float volume )\r\n\t{\r\n\t\tvar sfx = Sound.Play( name, new Vector3( pos.x, pos.y, Globals.SFX_DEPTH ) );\r\n\r\n\t\tif ( sfx != null )\r\n\t\t{\r\n\t\t\tsfx.Volume = volume;\r\n\t\t\tsfx.Pitch = pitch;\r\n\t\t}\r\n\t}\r\n\r\n\tprotected override void OnStart()\r\n\t{\r\n\t\tbase.OnStart();\r\n\r\n\t\tManager.Instance.AddPlayer( this );\r\n\t}\r\n\r\n\tprotected override void OnDestroy()\r\n\t{\r\n\t\tbase.OnDestroy();\r\n\r\n\t\tManager.Instance.RemovePlayer( this );\r\n\t}\r\n\r\n\tvoid HandleCamShaking()\r\n\t{\r\n\t\tCamShakeAmount = 0f;\r\n\r\n\t\tfor ( int i = _camShakeDatas.Count - 1; i \u003E= 0; i-- )\r\n\t\t{\r\n\t\t\tvar data = _camShakeDatas[i];\r\n\t\t\tvar time = data.useRealTime ? RealTime.Now : Time.Now;\r\n\r\n\t\t\tif ( time \u003E data.startTime \u002B data.time )\r\n\t\t\t{\r\n\t\t\t\t_camShakeDatas.RemoveAt( i );\r\n\t\t\t}\r\n\t\t\telse\r\n\t\t\t{\r\n\t\t\t\tfloat amount = Utils.Map( time, data.startTime, data.startTime \u002B data.time, data.strength, 0f, data.easingType );\r\n\t\t\t\tCamShakeAmount = MathF.Max( amount, CamShakeAmount );\r\n\t\t\t}\r\n\t\t}\r\n\t}\r\n\r\n\tpublic void ShakeCam( float strength, float time, EasingType easingType = EasingType.Linear, bool useRealTime = false )\r\n\t{\r\n\t\tvar timeNow = useRealTime ? RealTime.Now : Time.Now;\r\n\t\t_camShakeDatas.Add( new CamShakeData( strength, timeNow, time, easingType, useRealTime ) );\r\n\t}\r\n}\r\n"}]}