A Razor UI component (StatsScreen) that builds and renders the player stats panel. It gathers many player stats, formats them into StatDisplayData entries, handles scrolling, mouse wheel, and updates a displayed time when game over.
@namespace Sandbox
@using Sandbox;
@using Sandbox.UI;
@using System;
@inherits Panel
@attribute [StyleSheet("StatsScreen.razor.scss")]
<root class="flat">
@{
var player = Manager.Instance.LocalPlayer;
StatDatasToShow.Clear();
if(!Networking.IsHost)
StatDatasToShow.Add(new StatDisplayData("Ping", $"{Connection.Local.Ping}ms", _colorDefault, "ping", _iconColorDefault));
StatDatasToShow.Add(new StatDisplayData("DPS", $"{Player.DpsStat.ToString("0.#")}", _colorDefault, "dps", _iconColorDefault));
StatDatasToShow.Add(new StatDisplayData("Kills", Player.GetStatStr(PlayerStat.NumEnemiesKilled), _colorDefault, "kill", _iconColorDefault));
AddBulletDamageStat();
AddDamageMultStat();
AddNumProjectilesStat();
AddAmmoStat();
AddNumPierceStat();
AddNumBounceStat();
AddAttackSpeedStat();
AddReloadSpeedStat();
AddMoveSpeedStat();
AddMaxHpStat();
AddHpRegenStat();
AddHealEffectivenessStat();
AddHpPerKillStat();
AddDodgeChanceStat();
}
<div class="title" onclick="@(e => TitleClicked(e))">
@* <label style='font-family: Material Icons;'>@("bar_chart")</label> *@
<InputHint class="ctrl" Button="Tab" AspectRatio=@(1.55f)></InputHint>
</div>
<div class="flat panel">
<div class="flat column list_container">
@foreach(var statType in player.StatsToDisplay)
{
bool isDefaultValue = !player.OriginalStatValues.ContainsKey(statType) || MathF.Abs(player.Stats[statType] - player.OriginalStatValues[statType]) < 0.01f;
@* isDefaultValue = false; *@ // for debug
if(!isDefaultValue || player.DefaultValueStatsToDisplay.Contains(statType))
{
string title = "";
string amount = "";
Color color = new Color(0.9f, 1f, 0.95f, 0.8f);
string icon = "rule_folder";
Color iconColor = _iconColorDefault;
GetLabelForStat(statType, ref title, ref amount, ref color, ref icon, ref iconColor);
// todo: cache this?
StatDatasToShow.Add(new StatDisplayData(title, amount, color, icon, iconColor));
// once a stat has been shown, keep showing even if it returns to default value
player.DefaultValueStatsToDisplay.Add(statType);
}
}
@for(int i = StartIndex; i < StartIndex + MAX_ROWS; i++)
{
if(i < 0 || i >= StatDatasToShow.Count)
continue;
var data = StatDatasToShow[i];
var nameColor = Color.Lerp(data.iconColor, Color.White, 0.5f);
@* <div class="flat space-between list" style="background-color: @((i % 2 == 0 ? new Color(0,0,0,0.4f) : new Color(0,0,0,0.7f)).Rgba);"> *@
<div class="flat space-between list">
<div>
@* <label class="icon" style="color:@(data.iconColor.Rgba);">@(data.icon)</label> *@
<div class="icon_container">
<label class="icon" style="background-color:@(data.iconColor.Rgba); mask-image:@($"url(/textures/ui/stats/{data.icon}.png)")"></label>
</div>
<label class="bold stat_name" style="color:@(nameColor.Rgba); font-size:@(data.title.Length > 15 ? Math.Round(Utils.Map(data.title.Length, 15, 36, 14f, 10f, EasingType.SineIn)) : 14)px;">@(data.title)</label>
</div>
<label class="bold stat_value" style="color:@(data.color.Rgba);">@(data.amount)</label>
</div>
}
</div>
@if(StatDatasToShow.Count > MAX_ROWS)
{
var totalRowHeight = StatDatasToShow.Count * 30f;
@* var visibleRowHeight = MAX_ROWS * 30f; *@
var heightPercent = (MAX_ROWS / (float)StatDatasToShow.Count);
var topOffset = StartIndex * 30f * heightPercent;
//Log.Info($"{MAX_ROWS} / {StatDatasToShow.Count} = {heightPercent}");
<div class="scrollbar" style="top:@(topOffset)px; height:@(heightPercent * 100f)%;"></div>
}
else
{
StartIndex = 0;
}
</div>
</root>
@code {
public struct StatDisplayData
{
public string title;
public string amount;
public Color color;
public string icon;
public Color iconColor;
public StatDisplayData(string _title, string _amount, Color _color, string _icon, Color _iconColor)
{
title = _title;
amount = _amount;
color = _color;
icon = _icon;
iconColor = _iconColor;
}
}
public Player Player { get; set; }
public string TimeString { get; set; }
public List<StatDisplayData> StatDatasToShow { get; set; } = new();
public static int StartIndex { get; set; }
private const int MAX_ROWS = 25;
Color _colorDefault;
Color _colorGood;
Color _colorBad;
Color _iconColorDefault;
public StatsScreen()
{
Player = Manager.Instance.LocalPlayer;
_colorDefault = new Color(0.9f, 1f, 0.95f, 0.8f);
_colorGood = new Color(0f, 1f, 0f, 0.8f);
_colorBad = new Color(1f, 0f, 0f, 0.8f);
_iconColorDefault = new Color(0.91f, 1f, 0.96f, 0.5f);
}
public void OnRetry()
{
// SS2Game.RestartCmd();
}
public override void Tick()
{
base.Tick();
//Log.Info($"StartIndex: {StartIndex}");
if(Manager.Instance.IsGameOver)
{
TimeSpan t = TimeSpan.FromSeconds(Manager.Instance.GameOverTime);
TimeString = t.TotalSeconds > 3600 ? t.ToString(@"hh\:mm\:ss") : t.ToString(@"mm\:ss");
if(Input.Pressed("Retry") && Networking.IsHost)
{
OnRetry();
}
}
}
protected override int BuildHash()
{
int nthShotHash = Player.Stats[PlayerStat.NthShotNumBullets] > 0f ? ((int)Player.Stats[PlayerStat.TotalShotNum] % (int)Player.Stats[PlayerStat.NthShotReq] == 0 ? 1 : 2) : 0;
return HashCode.Combine(
StartIndex,
Player.ModifierHash,
HashCode.Combine(Player.GetDamageMultiplierDisplay(), Player.GetAttackSpeedMultiplier(), Player.GetMoveSpeedMultiplier(), Player.GetReloadSpeedMultiplier(), Player.GetHpRegenAmount(forDisplay: true), Player.GetHealEffectiveness(), Player.GetDodgeChance()),
Player.GetBulletDamage(isFromClip: true, isLastAmmo: Player.AmmoCount == 0, forDisplay: true),
HashCode.Combine(Player.Stats[PlayerStat.ShotDamageMult], nthShotHash),
Player.DpsStat,
Player.DefaultValueStatsToDisplay.Count,
Networking.IsHost ? 0 : Connection.Local.Ping
);
}
void GetLabelForStat(PlayerStat statType, ref string title, ref string amount, ref Color color, ref string icon, ref Color iconColor)
{
switch(statType)
{
// case PlayerStat.MaxHp: title = "MAX HP"; amount = GetStatStr(statType, StatFormat.IntDiff); icon = "favorite"; break;
// case PlayerStat.MaxHpDisplay: title = "MAX HP"; amount = GetStatStr(statType, StatFormat.IntDiff); icon = "favorite"; break;
// case PlayerStat.DodgeChance: title = "DODGE CHANCE"; amount = GetStatStr(statType, StatFormat.Percentage); icon = "air"; break;
case PlayerStat.DodgeExtraAttempts: title = "Extra Dodge Attempts"; amount = Player.GetStatStr(statType, StatFormat.Int); icon = "dodge_extra"; iconColor = new Color(0.5f, 0.5f, 1f); break;
case PlayerStat.DodgeAoeDamagePercent: title = "Dodge AOE Damage"; amount = Player.GetStatStr(statType, StatFormat.Percentage); icon = "dodge_aoe"; iconColor = new Color(1f, 0.2f, 0f); break;
case PlayerStat.DodgeHealChance: title = "Dodge Heal Chance"; amount = Player.GetStatStr(statType, StatFormat.Percentage); icon = "dodge_heal"; iconColor = new Color(0.5f, 1f, 0.5f); break;
case PlayerStat.DodgeReloadChance: title = "Dodge Reload Chance"; amount = Player.GetStatStr(statType, StatFormat.Percentage); icon = "dodge_reload"; iconColor = new Color(0.9f, 0.9f, 0.9f); break;
case PlayerStat.InvulnAfterHurtTimeDisplay: title = "Recovery Invuln Time"; amount = Player.GetStatStr(statType, StatFormat.Seconds1); icon = "invulnerable"; iconColor = new Color(0.9f, 0.9f, 0f); break;
case PlayerStat.DamageReductionPercent: title = "Damage Taken"; amount = Player.GetStatStr(statType, StatFormat.PercentageAddDiffInverse); icon = "dmg_reduction"; iconColor = new Color(0.9f, 0.9f, 0.9f); break;
case PlayerStat.BacksideDamageReductionPercent: title = "Backside Damage Taken"; amount = Player.GetStatStr(statType, StatFormat.PercentageAddDiffInverse); icon = "backstab"; iconColor = new Color(0.7f, 0f, 0f); break;
// case PlayerStat.ExplosionDamageReductionPercent: title = "Explosion Damage Taken"; amount = Player.GetStatStr(statType, StatFormat.PercentageAddDiffInverse); icon = "explosion_dmg_reduction"; iconColor = new Color(1f, 0.2f, 0f); break;
case PlayerStat.FullHpDamageReductionPercent: title = "Full HP Damage Taken"; amount = Player.GetStatStr(statType, StatFormat.PercentageAddDiffInverse); icon = "full_hp"; iconColor = new Color(0.9f, 0.9f, 0.9f); break;
case PlayerStat.SelfDmgReductionPercent: title = "Self Damage Taken"; amount = Player.GetStatStr(statType, StatFormat.PercentageAddDiffInverse); icon = "self-dmg"; iconColor = new Color(1f, 0f, 1f); break;
case PlayerStat.CritChance: title = "Bullet Crit Chance"; amount = Player.GetStatStr(statType, StatFormat.Percentage); icon = "crit"; iconColor = new Color(0.9f, 0.9f, 0.3f); break;
case PlayerStat.CritMultiplier: title = "Crit Multiplier"; amount = Player.GetStatStr(statType, StatFormat.Percentage); icon = "crit_multiplier"; iconColor = new Color(0.7f, 0.7f, 0.5f); break;
case PlayerStat.BulletHomingRadiusDisplay: title = "Bullet Homing Range"; amount = Player.GetStatStr(statType, StatFormat.Distance2); icon = "homing"; iconColor = new Color(0.9f, 0.9f, 0.9f); break;
case PlayerStat.BulletSplashChance: title = "Bullet Splash Chance"; amount = Player.GetStatStr(statType, StatFormat.Percentage); icon = "splash_chance"; iconColor = new Color(0.75f, 0.75f, 1f); break;
case PlayerStat.BulletSplashDamagePercent: title = "Bullet Splash Damage"; amount = Player.GetStatStr(statType, StatFormat.Percentage); icon = "splash"; iconColor = new Color(0.5f, 0.5f, 1f); break;
case PlayerStat.BulletOverflowPercent: title = "Bullet Overkill Damage"; amount = Player.GetStatStr(statType, StatFormat.Percentage); icon = "overkill"; iconColor = new Color(0.9f, 0.4f, 0.4f); break;
case PlayerStat.BulletDamageGrow: title = "Bullet Damage Growth"; amount = Player.GetStatStr(statType, StatFormat.PerSecond1); icon = "bullet_grow"; iconColor = new Color(0.9f, 0.9f, 0.9f); break;
case PlayerStat.BulletDistanceDamage: title = "Bullet Distance Damage"; amount = Player.GetStatStr(statType, StatFormat.PerDistance1); icon = "sniper"; iconColor = new Color(0.15f, 0.15f, 0.9f); break;
case PlayerStat.BulletHealTeammateAmount: title = "Bullet Heal Allies"; amount = Player.GetStatStr(statType, StatFormat.Decimals1Plus); icon = "bullet_heal"; iconColor = new Color(0.2f, 1f, 0.2f); break;
// case PlayerStat.Friction: title = "FRICTION"; amount = Player.GetStatStr(statType, StatFormat.PercentageDiff); icon = "roller_skating"; iconColor = new Color(0.9f, 0.9f, 0.9f); break;
case PlayerStat.NumDashes: title = "Max Dashes"; amount = Player.GetStatStr(statType, StatFormat.Int); icon = "dash"; iconColor = new Color(0.9f, 1f, 1f); break;
case PlayerStat.DashCooldown: title = "Dash Cooldown"; amount = Player.GetStatStr(statType, StatFormat.Seconds1); icon = "dash_cooldown"; iconColor = new Color(1f, 0.5f, 0.3f); break;
case PlayerStat.DashStrength: title = "Dash Strength"; amount = Player.GetStatStr(statType, StatFormat.PercentageDiff); icon = "dash_strength"; iconColor = new Color(0.5f, 0.7f, 1f); break;
// case PlayerStat.DashInvulnTime: title = "DASH DISTANCE"; amount = Player.GetStatStr(statType, StatFormat.Seconds2); icon = "timer"; iconColor = new Color(0.9f, 0.9f, 0.9f); break;
case PlayerStat.BulletForce: title = "Bullet Knockback"; amount = Player.GetStatStr(statType, StatFormat.PercentageDiff); icon = "force"; iconColor = new Color(0.7f); break;
case PlayerStat.Kickback: title = "Shot Kickback"; amount = Player.GetStatStr(statType, StatFormat.Int); icon = "recoil"; iconColor = new Color(1f, 1f, 0.9f); break;
case PlayerStat.BulletSpread: title = "Bullet Spread"; amount = Player.GetStatStr(statType, Player.Stats[PlayerStat.ShootMultipleProjectilesParallel] > 0f ? StatFormat.PercentageDiff : StatFormat.Degrees); icon = "spread"; iconColor = new Color(1f, 0.9f, 0.9f); break;
case PlayerStat.ShotInaccuracy: title = "Shot Inaccuracy"; amount = Player.GetStatStr(statType, StatFormat.Degrees); icon = "inaccuracy"; iconColor = new Color(0.6f, 0.6f, 0.6f); break;
case PlayerStat.BulletLifetime: title = "Bullet Lifetime"; amount = Player.GetStatStr(statType, StatFormat.Seconds1); icon = "bullet_lifetime"; iconColor = new Color(0.5f, 0.5f, 1f); break;
case PlayerStat.BulletSpeed: title = "Bullet Speed"; amount = Player.GetStatStr(statType, StatFormat.PercentageDiff); icon = "bullet_speed"; iconColor = new Color(1f, 0.2f, 0.5f); break;
case PlayerStat.NumPerkChoices: title = "Perk Choices"; amount = Player.GetStatStr(statType, StatFormat.Int); icon = "perk_choices"; iconColor = new Color(0.9f, 0.9f, 0.9f); break;
case PlayerStat.ExistingPerkChance: title = "Offer Existing Perks"; amount = Player.GetStatStr(statType, StatFormat.PercentageAddDiff); icon = "perk_lvl"; iconColor = new Color(0.9f, 0.9f, 0.9f); break;
case PlayerStat.LevelUpExistingPerkChance: title = "Auto Choose Existing Perk"; amount = Player.GetStatStr(statType, StatFormat.Percentage); icon = "perk_auto_choose"; iconColor = new Color(0.9f, 0.9f, 0.9f); break;
case PlayerStat.RarityIncreaseCommon: title = "Common Perk Chance"; amount = Player.GetStatStr(statType, StatFormat.PercentageAddDiff); icon = "perk_new"; iconColor = PerkManager.GetFontRarityColor(Rarity.Common); break;
case PlayerStat.RarityIncreaseUncommon: title = "Uncommon Perk Chance"; amount = Player.GetStatStr(statType, StatFormat.PercentageAddDiff); icon = "perk_new"; iconColor = PerkManager.GetFontRarityColor(Rarity.Uncommon); break;
case PlayerStat.RarityIncreaseRare: title = "Rare Perk Chance"; amount = Player.GetStatStr(statType, StatFormat.PercentageAddDiff); icon = "perk_new"; iconColor = PerkManager.GetFontRarityColor(Rarity.Rare); break;
case PlayerStat.RarityIncreaseEpic: title = "Epic Perk Chance"; amount = Player.GetStatStr(statType, StatFormat.PercentageAddDiff); icon = "perk_new"; iconColor = PerkManager.GetFontRarityColor(Rarity.Epic); break;
case PlayerStat.RarityIncreaseMythic: title = "Mythic Perk Chance"; amount = Player.GetStatStr(statType, StatFormat.PercentageAddDiff); icon = "perk_new"; iconColor = PerkManager.GetFontRarityColor(Rarity.Mythic); break;
case PlayerStat.RarityIncreaseLegendary: title = "Legendary Perk Chance"; amount = Player.GetStatStr(statType, StatFormat.PercentageAddDiff); icon = "perk_new"; iconColor = PerkManager.GetFontRarityColor(Rarity.Legendary); break;
case PlayerStat.RarityIncreaseUnique: title = "Unique Perk Chance"; amount = Player.GetStatStr(statType, StatFormat.PercentageAddDiff); icon = "perk_new"; iconColor = PerkManager.GetFontRarityColor(Rarity.Unique); break;
// case PlayerStat.PerkChanceCommon: title = "COMMON PERK CHANCE"; amount = GetStatStr(statType, StatFormat.PercentageDecimals1); icon = "square"; iconColor = PerkManager.GetFontRarityColor(Rarity.Common, alpha: 1f); break;
// case PlayerStat.PerkChanceUncommon: title = "UNCOMMON PERK CHANCE"; amount = GetStatStr(statType, StatFormat.PercentageDecimals1); icon = "looks_6"; iconColor = PerkManager.GetFontRarityColor(Rarity.Uncommon, alpha: 1f); break;
// case PlayerStat.PerkChanceRare: title = "RARE PERK CHANCE"; amount = GetStatStr(statType, StatFormat.PercentageDecimals1); icon = "looks_5"; iconColor = PerkManager.GetFontRarityColor(Rarity.Rare, alpha: 1f); break;
// case PlayerStat.PerkChanceEpic: title = "EPIC PERK CHANCE"; amount = GetStatStr(statType, StatFormat.PercentageDecimals1); icon = "looks_4"; iconColor = PerkManager.GetFontRarityColor(Rarity.Epic, alpha: 1f); break;
// case PlayerStat.PerkChanceMythic: title = "MYTHIC PERK CHANCE"; amount = GetStatStr(statType, StatFormat.PercentageDecimals1); icon = "looks_3"; iconColor = PerkManager.GetFontRarityColor(Rarity.Mythic, alpha: 1f); break;
// case PlayerStat.PerkChanceLegendary: title = "LEGENDARY PERK CHANCE"; amount = GetStatStr(statType, StatFormat.PercentageDecimals1); icon = "looks_two"; iconColor = PerkManager.GetFontRarityColor(Rarity.Legendary, alpha: 1f); break;
// case PlayerStat.PerkChanceUnique: title = "UNIQUE PERK CHANCE"; amount = GetStatStr(statType, StatFormat.PercentageDecimals2); icon = "looks_one"; iconColor = PerkManager.GetFontRarityColor(Rarity.Unique, alpha: 1f); break;
case PlayerStat.NumRerollsPerLevel: title = "Rerolls Per Level"; amount = Player.GetStatStr(statType, StatFormat.Int); icon = "reroll"; iconColor = new Color(1f); break;
case PlayerStat.ArmorRerollCost: title = "Reroll Armor Cost"; amount = Player.GetStatStr(statType, StatFormat.Int); icon = "reroll_armor_cost"; iconColor = new Color(0.8f, 0.8f, 1f); break;
case PlayerStat.RerollHealDisplay: title = "Reroll HP Gain"; amount = Player.GetStatStr(statType, StatFormat.Decimals1Plus); icon = "reroll_hp"; iconColor = new Color(0.8f, 1f, 0.8f); break;
case PlayerStat.HealthPackExtraHp: title = "Healthpack Bonus HP"; amount = Player.GetStatStr(statType, StatFormat.IntDiff); icon = "healthpack_hp"; iconColor = new Color(0.4f, 1f, 1f); break;
case PlayerStat.CoinAttractRange: title = "Item Attract Range"; amount = Player.GetStatStr(statType, StatFormat.PercentageDiff); icon = "coin_attract"; iconColor = new Color(0.6f, 0.6f, 1f); break;
// case PlayerStat.CoinAttractStrength: title = "ITEM ATTRACT STRENGTH"; amount = Player.GetStatStr(statType, StatFormat.PercentageDiff); icon = "blank"; iconColor = new Color(0.9f, 0.9f, 0.9f); break;
case PlayerStat.XpGainMultiplier: title = "XP Gain"; amount = Player.GetStatStr(statType, StatFormat.PercentageDiff); icon = "xp_gain"; iconColor = new Color(0.5f, 0.3f, 1f); break;
case PlayerStat.XpDamageDisplay: title = "Coin AOE Damage"; amount = Player.GetStatStr(statType, StatFormat.Decimals1); icon = "xp_dmg"; iconColor = new Color(0.4f, 0.4f, 1f); break;
case PlayerStat.CoinHealAmount: title = "Coin HP Gain"; amount = Player.GetStatStr(statType, StatFormat.Decimals1); icon = "xp_hp"; iconColor = new Color(0f, 1f, 0.5f); break;
case PlayerStat.PushStrength: title = "Push Strength"; amount = Player.GetStatStr(statType, StatFormat.PercentageDiff); icon = "push_strength"; iconColor = new Color(0.9f, 0.9f, 0.9f); break;
case PlayerStat.TurnSpeed: title = "Turn Speed"; amount = Player.GetStatStr(statType, StatFormat.PercentageDiff); icon = "turn_speed"; iconColor = new Color(0.9f, 0.9f, 0.9f); break;
// case PlayerStat.DetectionRangeModifier: title = "ENEMY DETECTION RANGE"; amount = Player.GetStatStr(statType, StatFormat.PercentageDiff); icon = "visibility"; iconColor = new Color(0.9f, 0.9f, 0.9f); break;
case PlayerStat.ShootFireIgniteChance: title = "Fire Bullet Chance"; amount = Player.GetStatStr(statType, StatFormat.Percentage); icon = "fire_bullet"; iconColor = new Color(0.9f, 0.9f, 0.9f); break;
case PlayerStat.FireDamage: title = "Fire Damage"; amount = Player.GetStatStr(Player.Stats[statType], StatFormat.Decimals1); icon = "fire"; iconColor = new Color(1f, 0.25f, 0f); break;
case PlayerStat.FireLifetime: title = "Fire Time"; amount = Player.GetStatStr(statType, StatFormat.Seconds1); icon = "fire_lifetime"; iconColor = new Color(1f, 0.5f, 0.25f); break;
case PlayerStat.FireSpreadChance: title = "Fire Spread Chance"; amount = Player.GetStatStr(statType, StatFormat.Percentage); icon = "fire_spread"; iconColor = new Color(1f, 0.2f, 0.6f); break;
case PlayerStat.ShootFreezeChance: title = "Freeze Bullet Chance"; amount = Player.GetStatStr(statType, StatFormat.Percentage); icon = "freeze_bullet"; iconColor = new Color(0.9f, 0.9f, 0.9f); break;
case PlayerStat.FreezeLifetime: title = "Freeze Time"; amount = Player.GetStatStr(statType, StatFormat.Seconds1); icon = "freeze_lifetime"; iconColor = new Color(0.8f, 0.8f, 1f); break;
case PlayerStat.FreezeStrengthDisplay: title = "Freeze Strength"; amount = Player.GetStatStr(statType, StatFormat.PercentageAddDiff); icon = "freeze"; iconColor = new Color(0.7f, 0.7f, 1f); break;
case PlayerStat.FreezeOnMeleeCooldownDisplay: title = "Touch Freeze Cooldown"; amount = Player.GetStatStr(statType, StatFormat.Seconds1); icon = "touch_freeze"; iconColor = new Color(0.9f, 0.9f, 0.9f); break;
case PlayerStat.FreezeFireDamageMultiplier: title = "Fire Damage To Frozen"; amount = Player.GetStatStr(statType, StatFormat.PercentageDiff); icon = "fire_freeze"; iconColor = new Color(0.8f, 0.5f, 1f); break;
case PlayerStat.ShootPoisonChance: title = "Poison Bullet Chance"; amount = Player.GetStatStr(statType, StatFormat.Percentage); icon = "poison_bullet"; iconColor = new Color(0.3f,1f, 0.3f); break;
case PlayerStat.PoisonDamage: title = "Poison Damage"; amount = Player.GetStatStr(Player.Stats[statType], StatFormat.Decimals1); icon = "droplet"; iconColor = new Color(0f, 1f, 0f); break;
case PlayerStat.PoisonFinishDamagePercent: title = "Remove Poison Damage"; amount = Player.GetStatStr(statType, StatFormat.Percentage); icon = "poison_lose"; iconColor = new Color(0f, 0.7f, 0f); break;
case PlayerStat.PoisonDieSpreadChance: title = "Poison Spread Chance"; amount = Player.GetStatStr(statType, StatFormat.Percentage); icon = "poison_spread"; iconColor = new Color(0.4f, 1f, 0.4f); break;
case PlayerStat.FearLifetime: title = "Fear Time"; amount = Player.GetStatStr(statType, StatFormat.Seconds1); icon = "fear_lifetime"; iconColor = new Color(0.6f, 0.3f, 0.9f); break;
case PlayerStat.FearDamageMultiplier: title = "Fear Damage"; amount = Player.GetStatStr(statType, StatFormat.PercentageDiff); icon = "fear_dmg"; iconColor = new Color(0.7f, 0.4f, 1f); break;
case PlayerStat.FearOnMeleeCooldownDisplay: title = "Melee Fear Cooldown"; amount = Player.GetStatStr(statType, StatFormat.Seconds1); icon = "fear_melee"; iconColor = new Color(0.8f, 0.3f, 0.7f); break;
case PlayerStat.FearDamageReductionPercent: title = "Fear Damage Taken"; amount = Player.GetStatStr(statType, StatFormat.PercentageAddDiffInverse); icon = "fear_dmg_reduction"; iconColor = new Color(0.9f, 0.9f, 0.9f); break;
// case PlayerStat.DelayedRecoveryPercentDisplay: title = "DELAYED RECOVERY HP"; amount = Player.GetStatStr(statType, StatFormat.Percentage); icon = "blank"; iconColor = new Color(0.9f, 0.9f, 0.9f); break;
// case PlayerStat.DelayedRecoveryDelayDisplay: title = "DELAYED RECOVERY TIME"; amount = Player.GetStatStr(statType, StatFormat.Seconds1); icon = "blank"; iconColor = new Color(0.9f, 0.9f, 0.9f); break;
case PlayerStat.DashSlashBulletDamagePercent: title = "Dash Slash Damage"; amount = Player.GetStatStr(statType, StatFormat.Percentage); icon = "dash_slash"; iconColor = new Color(0.75f, 0.75f, 1f); break;
case PlayerStat.ExplosionDamageMultiplier: title = "Explosion Damage"; amount = Player.GetStatStr(statType, StatFormat.PercentageDiff); icon = "explosion"; iconColor = new Color(0.75f, 0f, 0f); break;
case PlayerStat.ExplosionSizeMultiplier: title = "Explosion Size"; amount = Player.GetStatStr(statType, StatFormat.PercentageDiff); icon = "explosion_size"; iconColor = new Color(0.75f, 0.3f, 0f); break;
case PlayerStat.RadiusMultiplier: title = "Area Radius"; amount = Player.GetStatStr(statType, StatFormat.PercentageDiff); icon = "area_radius"; iconColor = new Color(0.7f, 0.7f, 1f); break;
case PlayerStat.CameraDistance: title = "Camera Distance"; amount = Player.GetStatStr(statType, StatFormat.PercentageDiff); icon = "camera"; iconColor = new Color(0.9f, 0.9f, 0.9f); break;
case PlayerStat.Scale: title = "Body Size"; amount = Player.GetStatStr(statType, StatFormat.PercentageDiff); icon = "body"; iconColor = new Color(0.9f, 0.9f, 0.5f); break;
case PlayerStat.HealthyUnitDamagePercent: title = "Damage To Full HP Enemy"; amount = Player.GetStatStr(statType, StatFormat.PercentageDiff); icon = "dmg_to_full_hp"; iconColor = new Color(0.7f, 0.9f, 0.8f); break;
case PlayerStat.BackstabBonusDamagePercent: title = "Backstab Damage"; amount = Player.GetStatStr(statType, StatFormat.PercentageAddDiff); icon = "backstab"; iconColor = new Color(1f, 0.9f, 0.6f); break;
case PlayerStat.AlternatePlayerDamagePercent: title = "Tag Team Damage"; amount = Player.GetStatStr(statType, StatFormat.PercentageAddDiff); icon = "tag_team"; iconColor = new Color(0.9f, 1f, 0.9f); break;
// published_with_changes
// local_police
}
if(statType == PlayerStat.FireDamage || statType == PlayerStat.PoisonDamage)
{
var current = Player.Stats[statType];// * Player.GetDamageMultiplierDisplay();
var original = Player.GetOriginalStatValue(statType);
if(current != original)
color = (current < original) ? _colorBad : _colorGood;
}
// else if( statType == PlayerStat.PerkChanceCommon ) { color = Player.Stats[PlayerStat.RarityIncreaseCommon] < Player.OriginalStatValues[PlayerStat.RarityIncreaseCommon] ? _colorGood : Player.Stats[PlayerStat.RarityIncreaseCommon] > Player.OriginalStatValues[PlayerStat.RarityIncreaseCommon] ? _colorBad : _colorDefault; }
// else if( statType == PlayerStat.PerkChanceUncommon ) { color = Player.Stats[PlayerStat.RarityIncreaseUncommon] > Player.OriginalStatValues[PlayerStat.RarityIncreaseUncommon] ? _colorGood : Player.Stats[PlayerStat.RarityIncreaseUncommon] < Player.OriginalStatValues[PlayerStat.RarityIncreaseUncommon] ? _colorBad : _colorDefault; }
// else if( statType == PlayerStat.PerkChanceRare ) { color = Player.Stats[PlayerStat.RarityIncreaseRare] > Player.OriginalStatValues[PlayerStat.RarityIncreaseRare] ? _colorGood : Player.Stats[PlayerStat.RarityIncreaseRare] < Player.OriginalStatValues[PlayerStat.RarityIncreaseRare] ? _colorBad : _colorDefault; }
// else if( statType == PlayerStat.PerkChanceEpic ) { color = Player.Stats[PlayerStat.RarityIncreaseEpic] > Player.OriginalStatValues[PlayerStat.RarityIncreaseEpic] ? _colorGood : Player.Stats[PlayerStat.RarityIncreaseEpic] < Player.OriginalStatValues[PlayerStat.RarityIncreaseEpic] ? _colorBad : _colorDefault; }
// else if( statType == PlayerStat.PerkChanceMythic ) { color = Player.Stats[PlayerStat.RarityIncreaseMythic] > Player.OriginalStatValues[PlayerStat.RarityIncreaseMythic] ? _colorGood : Player.Stats[PlayerStat.RarityIncreaseMythic] < Player.OriginalStatValues[PlayerStat.RarityIncreaseMythic] ? _colorBad : _colorDefault; }
// else if( statType == PlayerStat.PerkChanceLegendary ) { color = Player.Stats[PlayerStat.RarityIncreaseLegendary] > Player.OriginalStatValues[PlayerStat.RarityIncreaseLegendary] ? _colorGood : Player.Stats[PlayerStat.RarityIncreaseLegendary] < Player.OriginalStatValues[PlayerStat.RarityIncreaseLegendary] ? _colorBad : _colorDefault; }
// else if( statType == PlayerStat.PerkChanceUnique ) { color = Player.Stats[PlayerStat.RarityIncreaseUnique] > Player.OriginalStatValues[PlayerStat.RarityIncreaseUnique] ? _colorGood : Player.Stats[PlayerStat.RarityIncreaseUnique] < Player.OriginalStatValues[PlayerStat.RarityIncreaseUnique] ? _colorBad : _colorDefault; }
else if(Player.OriginalStatValues.ContainsKey(statType))
{
var current = Player.Stats[statType];
var original = Player.OriginalStatValues[statType];
if (current < original)
color = IsHigherGood(statType) ? _colorBad : _colorGood;
else if (current > original)
color = IsHigherGood(statType) ? _colorGood : _colorBad;
}
}
bool IsHigherGood(PlayerStat statType)
{
if (statType == PlayerStat.DashCooldown ||
statType == PlayerStat.FreezeTimeScale ||
statType == PlayerStat.Friction ||
statType == PlayerStat.ShotInaccuracy ||
// statType == PlayerStat.DetectionRangeModifier ||
statType == PlayerStat.RarityIncreaseCommon ||
statType == PlayerStat.BulletSpread
)
return false;
return true;
}
public override void OnMouseWheel([Description("The scroll wheel delta. Positive values are scrolling down, negative - up.")] Vector2 value)
{
base.OnMouseWheel(value.y);
//Log.Info($"OnMouseWheel {value} -> {StartIndex} .... {StatDatasToShow.Count} .... {StatDatasToShow.Count - MAX_ROWS}");
if(StatDatasToShow.Count > MAX_ROWS)
StartIndex = Math.Clamp(StartIndex + (int)value.y, 0, StatDatasToShow.Count - MAX_ROWS);
}
public void AddCombinedStat(string name, float current, float original, string icon, StatFormat displayType, Color iconColor)
{
string str = Player.GetStatStr(current, displayType, original);
Color color;
if(current > original)
color = _colorGood;
else if(current < original)
color = _colorBad;
else
color = _colorDefault;
StatDatasToShow.Add(new StatDisplayData(name, str, color, icon, iconColor));
}
public void AddBulletDamageStat()
{
float bulletDamage = Player.GetBulletDamage(isFromClip: true, isLastAmmo: Player.AmmoCount == 0, forDisplay: true);
if(Player.Stats[PlayerStat.NextBulletDamageMult] > 0f)
bulletDamage *= Player.Stats[PlayerStat.NextBulletDamageMult];
bulletDamage *= Player.Stats[PlayerStat.ShotDamageMult];
if(Player.Stats[PlayerStat.BulletRandomDamagePercentMin] > 0f)
StatDatasToShow.Add(new StatDisplayData("Bullet Damage", $"{(bulletDamage * Player.Stats[PlayerStat.BulletRandomDamagePercentMin]).ToString("0.#")}-{(bulletDamage * Player.Stats[PlayerStat.BulletRandomDamagePercentMax]).ToString("0.#")}", _colorGood, "circle", _iconColorDefault));
else
AddCombinedStat("Bullet Damage", bulletDamage, 5f, "bullet", StatFormat.Decimals1, new Color(1f));
}
void AddDamageMultStat()
{
var mult = Player.GetDamageMultiplierDisplay();
if (mult == 1f && !Player.DefaultValueStatsToDisplay.Contains(PlayerStat.OverallDamageMultiplier))
return;
AddCombinedStat("Damage Multiplier", mult, 1f, "dmg_multiplier", StatFormat.PercentageDiff, new Color(1f, 0.6f, 0.6f));
Player.DefaultValueStatsToDisplay.Add(PlayerStat.OverallDamageMultiplier);
}
public void AddNumProjectilesStat()
{
var num = Player.Stats[PlayerStat.NumProjectiles];
if (Player.Stats[PlayerStat.NthShotNumBullets] > 0f && (int)Player.Stats[PlayerStat.TotalShotNum] % (int)Player.Stats[PlayerStat.NthShotReq] == 0)
num += Player.Stats[PlayerStat.NthShotNumBullets];
var numExtra = Player.Stats[PlayerStat.ExtraProjectileNum];
Color color = (num > 1 || numExtra > 0) ? _colorGood : (num < 1 ? _colorBad : _colorDefault);
if (numExtra > 0f)
StatDatasToShow.Add(new StatDisplayData("Bullets Per Shot", $"{num}-{num + numExtra}", color, "num_projectiles", _iconColorDefault));
else
StatDatasToShow.Add(new StatDisplayData("Bullets Per Shot", $"{num}", color, "num_projectiles", _iconColorDefault));
}
public void AddAmmoStat()
{
var num = Player.Stats[PlayerStat.MaxAmmoCount];
Color color = num > 5 ? _colorGood : (num < 5 ? _colorBad : _colorDefault);
StatDatasToShow.Add(new StatDisplayData("Ammo", $"{num}", color, "ammo", new Color(1f)));
}
public void AddNumPierceStat()
{
var num = Player.Stats[PlayerStat.BulletNumPiercing];
var numExtra = Player.Stats[PlayerStat.BulletExtraPierceChance] > 0f ? 1 : 0;
if(num + numExtra == 0 && !Player.DefaultValueStatsToDisplay.Contains(PlayerStat.BulletNumPiercing))
return;
Color color = (num > 0 || numExtra > 0) ? _colorGood : (num < 0 ? _colorBad : _colorDefault);
if(numExtra > 0f)
StatDatasToShow.Add(new StatDisplayData("Pierces", $"{num}-{num + numExtra}", color, "pierce", new Color(1f, 1f, 0.8f)));
else
StatDatasToShow.Add(new StatDisplayData("Pierces", $"{num}", color, "pierce", new Color(1f, 1f, 0.8f)));
Player.DefaultValueStatsToDisplay.Add(PlayerStat.BulletNumPiercing);
}
public void AddNumBounceStat()
{
var num = Player.Stats[PlayerStat.BulletNumBouncing];
var numExtra = Player.Stats[PlayerStat.BulletExtraBounceChance] > 0f ? (int)Player.Stats[PlayerStat.BulletExtraBounceAmount] : 0;
if(num + numExtra == 0 && !Player.DefaultValueStatsToDisplay.Contains(PlayerStat.BulletNumBouncing))
return;
Color color = (num > 0 || numExtra > 0) ? _colorGood : (num < 0 ? _colorBad : _colorDefault);
if(numExtra > 0f)
StatDatasToShow.Add(new StatDisplayData("Bounces", $"{num}-{num + numExtra}", color, "bounce", new Color(0.92f, 0.8f, 1f)));
else
StatDatasToShow.Add(new StatDisplayData("Bounces", $"{num}", color, "bounce", new Color(0.92f, 0.8f, 1f)));
Player.DefaultValueStatsToDisplay.Add(PlayerStat.BulletNumBouncing);
}
void AddAttackSpeedStat()
{
var mult = Player.GetAttackSpeedMultiplier();
if(mult == 1f && !Player.DefaultValueStatsToDisplay.Contains(PlayerStat.AttackSpeed))
return;
AddCombinedStat("Attack Speed", mult, 1f, "attack_speed", StatFormat.PercentageDiff, new Color(1f, 0.6f, 0.6f));
Player.DefaultValueStatsToDisplay.Add(PlayerStat.AttackSpeed);
}
void AddReloadSpeedStat()
{
var mult = Player.GetReloadSpeedMultiplier();
if(mult == 1f && !Player.DefaultValueStatsToDisplay.Contains(PlayerStat.ReloadSpeed))
return;
AddCombinedStat("Reload Speed", mult, 1f, "reload", StatFormat.PercentageDiff, new Color(1f, 0.5f, 0.5f));
Player.DefaultValueStatsToDisplay.Add(PlayerStat.ReloadSpeed);
}
void AddMoveSpeedStat()
{
var mult = Player.GetMoveSpeedMultiplier();
if(mult == 1f && !Player.DefaultValueStatsToDisplay.Contains(PlayerStat.MoveSpeedMultiplier))
return;
AddCombinedStat("Move Speed", mult, 1f, "move", StatFormat.PercentageDiff, new Color(0.5f, 0.5f, 0.7f));
Player.DefaultValueStatsToDisplay.Add(PlayerStat.MoveSpeedMultiplier);
}
void AddMaxHpStat()
{
var amount = Player.Stats[PlayerStat.MaxHp];
if(amount == 100f && !Player.DefaultValueStatsToDisplay.Contains(PlayerStat.MaxHp))
return;
AddCombinedStat("Max Health", amount, 100f, "max_hp", StatFormat.IntDiff, new Color(1f, 0f, 0f));
Player.DefaultValueStatsToDisplay.Add(PlayerStat.MaxHp);
}
void AddHpRegenStat()
{
var amount = Player.GetHpRegenAmount(forDisplay: true);
if(amount == 0f && !Player.DefaultValueStatsToDisplay.Contains(PlayerStat.HpRegenDisplay))
return;
AddCombinedStat("Health Regen", amount, 0f, "hp_regen", StatFormat.PerSecond2, new Color(0f, 1f, 0f));
Player.DefaultValueStatsToDisplay.Add(PlayerStat.HpRegenDisplay);
}
void AddHealEffectivenessStat()
{
var amount = Player.GetHealEffectiveness();
if(amount == 1f && !Player.DefaultValueStatsToDisplay.Contains(PlayerStat.HealEffectiveness))
return;
AddCombinedStat("Healing Received", amount, 1f, "heal_effectiveness", StatFormat.PercentageAddDiff, new Color(0.7f, 1f, 0.7f));
Player.DefaultValueStatsToDisplay.Add(PlayerStat.HealEffectiveness);
}
void AddHpPerKillStat()
{
var amount = Player.Stats[PlayerStat.HpRegenPerKillDisplay];
if(amount == 0f && !Player.DefaultValueStatsToDisplay.Contains(PlayerStat.HpRegenPerKillDisplay))
return;
AddCombinedStat("Health Per Kill", amount, 0f, "vampire", StatFormat.Decimals1Plus, new Color(1f, 0.2f, 0.3f));
Player.DefaultValueStatsToDisplay.Add(PlayerStat.HpRegenPerKillDisplay);
}
void AddDodgeChanceStat()
{
var chance = Player.GetDodgeChance();
if (chance == 0f && !Player.DefaultValueStatsToDisplay.Contains(PlayerStat.DodgeChance))
return;
AddCombinedStat("Dodge Chance", chance, 0f, "dodge", StatFormat.Percentage, new Color(1f));
Player.DefaultValueStatsToDisplay.Add(PlayerStat.DodgeChance);
}
void TitleClicked(PanelEvent e)
{
e.StopPropagation();
Manager.Instance.LocalPlayer.ShouldShowStats = false;
}
}