Commit initial BossHealth, DamageNumbers, Horde, ThirdPerson mods
This commit is contained in:
1 parent
7bd44d1d99
commit
9c123865bc
176 files changed
+10367
No files matched your search
@@ -0,0 +1,628 @@
|
||||
using System;
|
||||
using BepInEx;
|
||||
using BepInEx.Configuration;
|
||||
using BepInEx.Logging;
|
||||
using BepInEx.Unity.IL2CPP;
|
||||
using HarmonyLib;
|
||||
using Il2CppInterop.Runtime;
|
||||
using Il2CppInterop.Runtime.Injection;
|
||||
using Skopje.Modding;
|
||||
using UnityEngine;
|
||||
|
||||
namespace Skopje.DamageNumbers
|
||||
{
|
||||
[BepInPlugin(PluginGuid, PluginName, PluginVersion)]
|
||||
public class DamageNumbersPlugin : BasePlugin
|
||||
{
|
||||
public const string PluginGuid = "com.skopje.damagenumbers";
|
||||
public const string PluginName = "Skopje Damage Numbers";
|
||||
public const string PluginVersion = "1.0.0";
|
||||
|
||||
internal static ManualLogSource LogSource;
|
||||
internal static bool ClientRunning;
|
||||
|
||||
internal static ConfigEntry<bool> Enabled;
|
||||
internal static ConfigEntry<bool> OnlyYourDamage;
|
||||
internal static ConfigEntry<float> Lifetime;
|
||||
internal static ConfigEntry<float> Size;
|
||||
|
||||
static Harmony _harmony;
|
||||
static SkopjePlayer _localPlayer;
|
||||
static int _errorLogs;
|
||||
static int _traceLogs;
|
||||
|
||||
const int Recent = 32;
|
||||
static readonly int[] _recentEnemy = new int[Recent];
|
||||
static readonly int[] _recentAmount = new int[Recent];
|
||||
static readonly int[] _recentCell = new int[Recent];
|
||||
static readonly int[] _recentFrame = new int[Recent];
|
||||
static int _recentWrite;
|
||||
|
||||
static Il2CppSystem.Action _onClientStarted;
|
||||
static Il2CppSystem.Action _onClientStopped;
|
||||
static Il2CppSystem.Action<SkopjePlayer> _onPlayerStarted;
|
||||
static Il2CppSystem.Action<SkopjePlayer> _onPlayerStopped;
|
||||
static Il2CppSystem.Action _onGameOver;
|
||||
|
||||
public override void Load()
|
||||
{
|
||||
LogSource = Log;
|
||||
Enabled = Config.Bind("Display", "Enabled", true, "Show floating damage numbers.");
|
||||
OnlyYourDamage = Config.Bind("Display", "OnlyYourDamage", true, "Only show hits dealt by your pawn. Hits with no owner still show.");
|
||||
Lifetime = Config.Bind("Display", "Lifetime", 0.8f, "Seconds each number stays on screen.");
|
||||
Size = Config.Bind("Display", "Size", 1f, "Size multiplier.");
|
||||
|
||||
ClassInjector.RegisterTypeInIl2Cpp<DamageNumbersDisplay>();
|
||||
|
||||
_onClientStarted = ToIl2Cpp(new System.Action(OnClientStarted));
|
||||
_onClientStopped = ToIl2Cpp(new System.Action(OnClientStopped));
|
||||
_onPlayerStarted = ToIl2Cpp<SkopjePlayer>(new System.Action<SkopjePlayer>(OnPlayerStarted));
|
||||
_onPlayerStopped = ToIl2Cpp<SkopjePlayer>(new System.Action<SkopjePlayer>(OnPlayerStopped));
|
||||
_onGameOver = ToIl2Cpp(new System.Action(OnGameOver));
|
||||
|
||||
ModAPI.add_OnClientStarted(_onClientStarted);
|
||||
ModAPI.add_OnClientStopped(_onClientStopped);
|
||||
ModAPI.add_OnPlayerStartedClient(_onPlayerStarted);
|
||||
ModAPI.add_OnPlayerStoppedClient(_onPlayerStopped);
|
||||
ModAPI.add_OnGameOver(_onGameOver);
|
||||
|
||||
_harmony = new Harmony(PluginGuid);
|
||||
Patch(AccessTools.Method(typeof(EnemyControlAStar), nameof(EnemyControlAStar.TakeDamage)), nameof(AfterTakeDamage));
|
||||
// Observers RPC body. Parameter names are stripped, so the postfix binds them by index.
|
||||
Patch(AccessTools.Method(typeof(EnemyControlAStar), "RpcLogic___RpcDamageTaken_3262335728"), nameof(AfterObservedDamage));
|
||||
|
||||
LogSource.LogInfo($"{PluginName} {PluginVersion} loaded.");
|
||||
}
|
||||
|
||||
public override bool Unload()
|
||||
{
|
||||
ClientRunning = false;
|
||||
if (_harmony != null)
|
||||
_harmony.UnpatchSelf();
|
||||
DamageNumbersDisplay.DestroyHost();
|
||||
return true;
|
||||
}
|
||||
|
||||
static void Patch(System.Reflection.MethodInfo method, string postfix)
|
||||
{
|
||||
if (method == null)
|
||||
{
|
||||
LogSource.LogWarning("Damage number hook was not found: " + postfix);
|
||||
return;
|
||||
}
|
||||
|
||||
_harmony.Patch(method, postfix: new HarmonyMethod(typeof(DamageNumbersPlugin), postfix));
|
||||
}
|
||||
|
||||
static void OnClientStarted()
|
||||
{
|
||||
ClientRunning = true;
|
||||
DamageNumbersDisplay.Ensure();
|
||||
LogSource.LogInfo("Damage numbers ready.");
|
||||
}
|
||||
|
||||
static void OnClientStopped()
|
||||
{
|
||||
ClientRunning = false;
|
||||
_localPlayer = null;
|
||||
DamageNumbersDisplay.DestroyHost();
|
||||
}
|
||||
|
||||
static void OnPlayerStarted(SkopjePlayer player)
|
||||
{
|
||||
if (player != null && player.IsOwner)
|
||||
_localPlayer = player;
|
||||
}
|
||||
|
||||
static void OnPlayerStopped(SkopjePlayer player)
|
||||
{
|
||||
if (_localPlayer == player)
|
||||
_localPlayer = null;
|
||||
}
|
||||
|
||||
static void OnGameOver()
|
||||
{
|
||||
DamageNumbersDisplay.Clear();
|
||||
}
|
||||
|
||||
static void AfterTakeDamage(EnemyControlAStar __instance, HitData hitData)
|
||||
{
|
||||
try
|
||||
{
|
||||
Present(__instance, hitData, null, true);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Fail(ex);
|
||||
}
|
||||
}
|
||||
|
||||
static void AfterObservedDamage(
|
||||
EnemyControlAStar __instance,
|
||||
[HarmonyArgument(0)] HitData hitData,
|
||||
[HarmonyArgument(1)] DamageablePart part)
|
||||
{
|
||||
try
|
||||
{
|
||||
Present(__instance, hitData, part, false);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Fail(ex);
|
||||
}
|
||||
}
|
||||
|
||||
static void Present(EnemyControlAStar enemy, HitData hit, DamageablePart part, bool allowLastPart)
|
||||
{
|
||||
if (!ClientRunning || Enabled == null || !Enabled.Value)
|
||||
return;
|
||||
if (enemy == null || hit == null || hit.isDespawn)
|
||||
return;
|
||||
|
||||
DamageType type = hit.DamageType;
|
||||
if (HasFlag(type, DamageType.Enemy) || HasFlag(type, DamageType.Fall))
|
||||
return;
|
||||
if (!IsYourHit(hit))
|
||||
{
|
||||
Trace("skipped somebody else's hit");
|
||||
return;
|
||||
}
|
||||
|
||||
float raw = hit.damageAmount;
|
||||
if (float.IsNaN(raw) || float.IsInfinity(raw) || raw <= 0.01f)
|
||||
return;
|
||||
|
||||
int rawAmount = Mathf.Max(1, Mathf.RoundToInt(raw));
|
||||
Vector3 pos = HitPosition(enemy, hit);
|
||||
if (!Claim(enemy, rawAmount, pos))
|
||||
return;
|
||||
|
||||
if (part == null && allowLastPart && enemy.lastDamagedPart != null)
|
||||
part = enemy.lastDamagedPart.Value;
|
||||
|
||||
bool crit = IsCrit(part);
|
||||
int shown = ShownDamage(raw, crit);
|
||||
DamageTier.Apply(shown, out Color color, out float tierScale);
|
||||
float punch = PunchFor(rawAmount, crit, type) * tierScale;
|
||||
pos += new Vector3(
|
||||
UnityEngine.Random.Range(-0.22f, 0.22f),
|
||||
UnityEngine.Random.Range(0.05f, 0.28f),
|
||||
UnityEngine.Random.Range(-0.22f, 0.22f));
|
||||
|
||||
DamageNumbersDisplay.Ensure();
|
||||
DamageNumbersDisplay.Spawn(pos, shown, color, punch, crit);
|
||||
Trace("hit " + shown + " " + type + (crit ? " crit" : "") + " at " + pos);
|
||||
}
|
||||
|
||||
static bool IsYourHit(HitData hit)
|
||||
{
|
||||
if (OnlyYourDamage == null || !OnlyYourDamage.Value)
|
||||
return true;
|
||||
|
||||
PawnStatus owner = hit.HitOwner;
|
||||
if (owner == null)
|
||||
return true;
|
||||
|
||||
PawnStatus local = LocalPawn();
|
||||
if (local == null)
|
||||
return true;
|
||||
|
||||
return owner.Pointer == local.Pointer;
|
||||
}
|
||||
|
||||
static PawnStatus LocalPawn()
|
||||
{
|
||||
if (_localPlayer == null)
|
||||
_localPlayer = FindLocalPlayer();
|
||||
if (_localPlayer == null)
|
||||
return null;
|
||||
|
||||
try
|
||||
{
|
||||
return _localPlayer.PawnStatus;
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
_localPlayer = null;
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
static SkopjePlayer FindLocalPlayer()
|
||||
{
|
||||
var players = UnityEngine.Object.FindObjectsOfType<SkopjePlayer>();
|
||||
if (players == null)
|
||||
return null;
|
||||
|
||||
for (int i = 0; i < players.Length; i++)
|
||||
{
|
||||
SkopjePlayer player = players[i];
|
||||
if (player != null && player.IsOwner)
|
||||
return player;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
static Vector3 HitPosition(EnemyControlAStar enemy, HitData hit)
|
||||
{
|
||||
Vector3 pos = hit.hitPosition;
|
||||
if (pos.sqrMagnitude > 0.0001f)
|
||||
return pos;
|
||||
|
||||
pos = enemy.lastHitPosition;
|
||||
if (pos.sqrMagnitude > 0.0001f)
|
||||
return pos;
|
||||
|
||||
if (enemy.transform != null)
|
||||
return enemy.transform.position + Vector3.up * 1.4f;
|
||||
return Vector3.up;
|
||||
}
|
||||
|
||||
static bool IsCrit(DamageablePart part)
|
||||
{
|
||||
// part.name goes through UnityEngine.Object and can access-violate on a
|
||||
// networked part that is not a live Unity object. Weakspot fields are enough.
|
||||
if (part == null)
|
||||
return false;
|
||||
|
||||
try
|
||||
{
|
||||
if (part.WeakspotType != WeakspotType.None)
|
||||
return true;
|
||||
return part.PartDamageModifier > 1.05f;
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// Real hits in this game are often 1, 2, or 3. Scale them up so the popup
|
||||
// still tracks the hit, but reads like a chunky score. Crits are doubled.
|
||||
static int ShownDamage(float raw, bool crit)
|
||||
{
|
||||
float scale = crit ? 200f : 100f;
|
||||
float roll = UnityEngine.Random.Range(0.94f, 1.06f);
|
||||
return Mathf.Max(1, Mathf.RoundToInt(raw * scale * roll));
|
||||
}
|
||||
|
||||
static bool Claim(EnemyControlAStar enemy, int amount, Vector3 pos)
|
||||
{
|
||||
int id = enemy.GetInstanceID();
|
||||
int cell = (int)(pos.x * 8f) * 73856093
|
||||
^ (int)(pos.y * 8f) * 19349663
|
||||
^ (int)(pos.z * 8f) * 83492791;
|
||||
int frame = Time.frameCount;
|
||||
for (int i = 0; i < Recent; i++)
|
||||
{
|
||||
if (_recentFrame[i] < frame - 1)
|
||||
continue;
|
||||
if (_recentEnemy[i] == id && _recentAmount[i] == amount && _recentCell[i] == cell)
|
||||
return false;
|
||||
}
|
||||
|
||||
int slot = _recentWrite++ % Recent;
|
||||
if (_recentWrite < 0)
|
||||
_recentWrite = 0;
|
||||
_recentEnemy[slot] = id;
|
||||
_recentAmount[slot] = amount;
|
||||
_recentCell[slot] = cell;
|
||||
_recentFrame[slot] = frame;
|
||||
return true;
|
||||
}
|
||||
|
||||
static float PunchFor(int amount, bool crit, DamageType type)
|
||||
{
|
||||
float punch = 1f + Mathf.Clamp(Mathf.Log10(Mathf.Max(amount, 1)) * 0.14f, 0f, 0.5f);
|
||||
if (crit)
|
||||
punch *= 1.45f;
|
||||
if (HasFlag(type, DamageType.Explosion))
|
||||
punch *= 1.2f;
|
||||
return punch;
|
||||
}
|
||||
|
||||
static bool HasFlag(DamageType value, DamageType flag)
|
||||
{
|
||||
return ((int)value & (int)flag) != 0;
|
||||
}
|
||||
|
||||
static void Fail(Exception ex)
|
||||
{
|
||||
if (_errorLogs++ < 5)
|
||||
LogSource.LogWarning("Damage number failed: " + ex.Message);
|
||||
}
|
||||
|
||||
static void Trace(string message)
|
||||
{
|
||||
if (_traceLogs++ < 8)
|
||||
LogSource.LogInfo(message);
|
||||
}
|
||||
|
||||
static Il2CppSystem.Action ToIl2Cpp(System.Action action)
|
||||
{
|
||||
return DelegateSupport.ConvertDelegate<Il2CppSystem.Action>(action);
|
||||
}
|
||||
|
||||
static Il2CppSystem.Action<T> ToIl2Cpp<T>(System.Action<T> action)
|
||||
{
|
||||
return DelegateSupport.ConvertDelegate<Il2CppSystem.Action<T>>(action);
|
||||
}
|
||||
}
|
||||
|
||||
public class DamageNumbersDisplay : MonoBehaviour
|
||||
{
|
||||
const int Capacity = 48;
|
||||
|
||||
public static DamageNumbersDisplay Instance { get; private set; }
|
||||
|
||||
readonly Number[] _numbers = new Number[Capacity];
|
||||
GUIStyle _style;
|
||||
Camera _camera;
|
||||
float _nextCameraSearch;
|
||||
|
||||
public DamageNumbersDisplay(IntPtr pointer) : base(pointer)
|
||||
{
|
||||
}
|
||||
|
||||
public static void Ensure()
|
||||
{
|
||||
if (Instance != null)
|
||||
return;
|
||||
|
||||
var overlay = new GameObject("DamageNumbersDisplay");
|
||||
UnityEngine.Object.DontDestroyOnLoad(overlay);
|
||||
overlay.AddComponent<DamageNumbersDisplay>();
|
||||
}
|
||||
|
||||
public static void DestroyHost()
|
||||
{
|
||||
if (Instance != null)
|
||||
UnityEngine.Object.Destroy(Instance.gameObject);
|
||||
}
|
||||
|
||||
public static void Clear()
|
||||
{
|
||||
if (Instance == null)
|
||||
return;
|
||||
for (int i = 0; i < Instance._numbers.Length; i++)
|
||||
Instance._numbers[i].Used = false;
|
||||
}
|
||||
|
||||
public static void Spawn(Vector3 worldPos, int amount, Color color, float punch, bool crit)
|
||||
{
|
||||
DamageNumbersDisplay display = Instance;
|
||||
if (display == null)
|
||||
return;
|
||||
|
||||
float life = 0.8f;
|
||||
if (DamageNumbersPlugin.Lifetime != null)
|
||||
life = Mathf.Clamp(DamageNumbersPlugin.Lifetime.Value, 0.25f, 2.5f);
|
||||
if (crit)
|
||||
life *= 1.15f;
|
||||
|
||||
int slot = display.FindSlot();
|
||||
display._numbers[slot] = new Number
|
||||
{
|
||||
Used = true,
|
||||
Origin = worldPos,
|
||||
Drift = new Vector3(
|
||||
UnityEngine.Random.Range(-0.55f, 0.55f),
|
||||
UnityEngine.Random.Range(crit ? 1.15f : 0.9f, crit ? 1.65f : 1.35f),
|
||||
UnityEngine.Random.Range(-0.2f, 0.2f)),
|
||||
Age = 0f,
|
||||
Life = life,
|
||||
Punch = punch,
|
||||
Tilt = UnityEngine.Random.Range(crit ? -18f : -14f, crit ? 18f : 14f),
|
||||
Amount = amount,
|
||||
Color = color,
|
||||
Text = crit ? "CRIT\n" + amount : amount.ToString()
|
||||
};
|
||||
Measure(display._numbers[slot].Text, out display._numbers[slot].Lines, out display._numbers[slot].Longest);
|
||||
}
|
||||
|
||||
static void Measure(string text, out int lines, out int longest)
|
||||
{
|
||||
lines = 1;
|
||||
longest = 0;
|
||||
int run = 0;
|
||||
for (int i = 0; i < text.Length; i++)
|
||||
{
|
||||
if (text[i] == '\n')
|
||||
{
|
||||
lines++;
|
||||
if (run > longest)
|
||||
longest = run;
|
||||
run = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
run++;
|
||||
}
|
||||
}
|
||||
|
||||
if (run > longest)
|
||||
longest = run;
|
||||
}
|
||||
|
||||
int FindSlot()
|
||||
{
|
||||
int oldest = 0;
|
||||
float oldestAge = -1f;
|
||||
for (int i = 0; i < _numbers.Length; i++)
|
||||
{
|
||||
if (!_numbers[i].Used)
|
||||
return i;
|
||||
if (_numbers[i].Age > oldestAge)
|
||||
{
|
||||
oldestAge = _numbers[i].Age;
|
||||
oldest = i;
|
||||
}
|
||||
}
|
||||
|
||||
return oldest;
|
||||
}
|
||||
|
||||
void Awake()
|
||||
{
|
||||
Instance = this;
|
||||
}
|
||||
|
||||
void OnDestroy()
|
||||
{
|
||||
if (Instance == this)
|
||||
Instance = null;
|
||||
}
|
||||
|
||||
void Update()
|
||||
{
|
||||
float step = Time.deltaTime;
|
||||
for (int i = 0; i < _numbers.Length; i++)
|
||||
{
|
||||
if (!_numbers[i].Used)
|
||||
continue;
|
||||
_numbers[i].Age += step;
|
||||
if (_numbers[i].Age >= _numbers[i].Life)
|
||||
_numbers[i].Used = false;
|
||||
}
|
||||
}
|
||||
|
||||
void OnGUI()
|
||||
{
|
||||
Camera cam = CameraNow();
|
||||
if (cam == null)
|
||||
return;
|
||||
|
||||
if (_style == null)
|
||||
{
|
||||
_style = new GUIStyle(GUI.skin.label)
|
||||
{
|
||||
alignment = TextAnchor.MiddleCenter,
|
||||
fontStyle = FontStyle.Bold,
|
||||
richText = false
|
||||
};
|
||||
}
|
||||
|
||||
float size = DamageNumbersPlugin.Size != null
|
||||
? Mathf.Clamp(DamageNumbersPlugin.Size.Value, 0.25f, 4f)
|
||||
: 1f;
|
||||
|
||||
for (int i = 0; i < _numbers.Length; i++)
|
||||
{
|
||||
if (_numbers[i].Used)
|
||||
Draw(cam, _numbers[i], size);
|
||||
}
|
||||
}
|
||||
|
||||
Camera CameraNow()
|
||||
{
|
||||
if (_camera != null && _camera.isActiveAndEnabled)
|
||||
return _camera;
|
||||
if (Time.unscaledTime < _nextCameraSearch)
|
||||
return null;
|
||||
|
||||
_nextCameraSearch = Time.unscaledTime + 0.5f;
|
||||
_camera = Camera.main;
|
||||
if (_camera == null)
|
||||
_camera = UnityEngine.Object.FindObjectOfType<Camera>();
|
||||
return _camera;
|
||||
}
|
||||
|
||||
void Draw(Camera cam, Number number, float size)
|
||||
{
|
||||
float t = Mathf.Clamp01(number.Age / number.Life);
|
||||
float rise = 1f - (1f - t) * (1f - t);
|
||||
Vector3 world = number.Origin + number.Drift * rise;
|
||||
Vector3 screen = cam.WorldToScreenPoint(world);
|
||||
if (screen.z <= 0.05f)
|
||||
return;
|
||||
if (screen.x < -60f || screen.y < -60f || screen.x > Screen.width + 60f || screen.y > Screen.height + 60f)
|
||||
return;
|
||||
|
||||
float dist = Vector3.Distance(cam.transform.position, world);
|
||||
float perspective = Mathf.Clamp(8f / Mathf.Max(dist, 0.75f), 0.4f, 1.8f);
|
||||
float pop = PopScale(t);
|
||||
int font = Mathf.Clamp(Mathf.RoundToInt(36f * perspective * pop * number.Punch * size), 12, 140);
|
||||
|
||||
float alpha = t < 0.62f ? 1f : 1f - (t - 0.62f) / 0.38f;
|
||||
Color color = number.Color;
|
||||
color.a *= alpha;
|
||||
|
||||
float width = font * Mathf.Max(2, number.Longest) * 0.7f + 20f;
|
||||
float height = font * number.Lines + 12f;
|
||||
float x = screen.x - width * 0.5f;
|
||||
float y = Screen.height - screen.y - height * 0.5f;
|
||||
var rect = new Rect(x, y, width, height);
|
||||
var pivot = new Vector2(screen.x, Screen.height - screen.y);
|
||||
|
||||
Matrix4x4 matrix = GUI.matrix;
|
||||
Color previous = GUI.color;
|
||||
_style.fontSize = font;
|
||||
GUIUtility.RotateAroundPivot(number.Tilt * (1f - t), pivot);
|
||||
|
||||
float outline = Mathf.Max(1f, font / 16f);
|
||||
GUI.color = new Color(0f, 0f, 0f, color.a * 0.92f);
|
||||
GUI.Label(new Rect(rect.x - outline, rect.y, rect.width, rect.height), number.Text, _style);
|
||||
GUI.Label(new Rect(rect.x + outline, rect.y, rect.width, rect.height), number.Text, _style);
|
||||
GUI.Label(new Rect(rect.x, rect.y - outline, rect.width, rect.height), number.Text, _style);
|
||||
GUI.Label(new Rect(rect.x, rect.y + outline, rect.width, rect.height), number.Text, _style);
|
||||
GUI.color = color;
|
||||
GUI.Label(rect, number.Text, _style);
|
||||
|
||||
GUI.color = previous;
|
||||
GUI.matrix = matrix;
|
||||
}
|
||||
|
||||
static float PopScale(float t)
|
||||
{
|
||||
if (t < 0.08f)
|
||||
return Mathf.Lerp(0.35f, 1.4f, t / 0.08f);
|
||||
if (t < 0.18f)
|
||||
return Mathf.Lerp(1.4f, 1f, (t - 0.08f) / 0.1f);
|
||||
return 1f;
|
||||
}
|
||||
|
||||
struct Number
|
||||
{
|
||||
public bool Used;
|
||||
public Vector3 Origin;
|
||||
public Vector3 Drift;
|
||||
public float Age;
|
||||
public float Life;
|
||||
public float Punch;
|
||||
public float Tilt;
|
||||
public int Amount;
|
||||
public int Lines;
|
||||
public int Longest;
|
||||
public Color Color;
|
||||
public string Text;
|
||||
}
|
||||
}
|
||||
|
||||
static class DamageTier
|
||||
{
|
||||
// Chosen once per hit. Draw only reads the stored color and punch.
|
||||
static readonly Color White = new Color(1f, 1f, 1f, 1f);
|
||||
static readonly Color LightYellow = new Color(1f, 0.96f, 0.55f, 1f);
|
||||
static readonly Color LightOrange = new Color(1f, 0.74f, 0.38f, 1f);
|
||||
static readonly Color Orange = new Color(1f, 0.48f, 0.08f, 1f);
|
||||
|
||||
public static void Apply(int amount, out Color color, out float sizeScale)
|
||||
{
|
||||
if (amount >= 50)
|
||||
{
|
||||
color = Orange;
|
||||
sizeScale = 1.15f;
|
||||
return;
|
||||
}
|
||||
|
||||
sizeScale = 1f;
|
||||
if (amount >= 40)
|
||||
color = LightOrange;
|
||||
else if (amount >= 25)
|
||||
color = LightYellow;
|
||||
else
|
||||
color = White;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,60 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net6.0</TargetFramework>
|
||||
<LangVersion>latest</LangVersion>
|
||||
<ImplicitUsings>disable</ImplicitUsings>
|
||||
<Nullable>disable</Nullable>
|
||||
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
|
||||
<AssemblyName>Skopje.DamageNumbers</AssemblyName>
|
||||
<RootNamespace>Skopje.DamageNumbers</RootNamespace>
|
||||
<AppendTargetFrameworkToOutputPath>true</AppendTargetFrameworkToOutputPath>
|
||||
<GameDir Condition="'$(GameDir)' == ''">D:\SteamLibrary\steamapps\common\Skopje83</GameDir>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Reference Include="0Harmony">
|
||||
<HintPath>$(GameDir)\BepInEx\core\0Harmony.dll</HintPath>
|
||||
<Private>false</Private>
|
||||
</Reference>
|
||||
<Reference Include="BepInEx.Core">
|
||||
<HintPath>$(GameDir)\BepInEx\core\BepInEx.Core.dll</HintPath>
|
||||
<Private>false</Private>
|
||||
</Reference>
|
||||
<Reference Include="BepInEx.Unity.IL2CPP">
|
||||
<HintPath>$(GameDir)\BepInEx\core\BepInEx.Unity.IL2CPP.dll</HintPath>
|
||||
<Private>false</Private>
|
||||
</Reference>
|
||||
<Reference Include="Il2CppInterop.Runtime">
|
||||
<HintPath>$(GameDir)\BepInEx\core\Il2CppInterop.Runtime.dll</HintPath>
|
||||
<Private>false</Private>
|
||||
</Reference>
|
||||
<Reference Include="Il2Cppmscorlib">
|
||||
<HintPath>$(GameDir)\BepInEx\interop\Il2Cppmscorlib.dll</HintPath>
|
||||
<Private>false</Private>
|
||||
</Reference>
|
||||
<Reference Include="SkopjeAssembly">
|
||||
<HintPath>$(GameDir)\BepInEx\interop\SkopjeAssembly.dll</HintPath>
|
||||
<Private>false</Private>
|
||||
</Reference>
|
||||
<Reference Include="FishNet.Runtime">
|
||||
<HintPath>$(GameDir)\BepInEx\interop\FishNet.Runtime.dll</HintPath>
|
||||
<Private>false</Private>
|
||||
</Reference>
|
||||
<Reference Include="UnityEngine.CoreModule">
|
||||
<HintPath>$(GameDir)\BepInEx\interop\UnityEngine.CoreModule.dll</HintPath>
|
||||
<Private>false</Private>
|
||||
</Reference>
|
||||
<Reference Include="UnityEngine.IMGUIModule">
|
||||
<HintPath>$(GameDir)\BepInEx\interop\UnityEngine.IMGUIModule.dll</HintPath>
|
||||
<Private>false</Private>
|
||||
</Reference>
|
||||
<Reference Include="UnityEngine.TextRenderingModule">
|
||||
<HintPath>$(GameDir)\BepInEx\interop\UnityEngine.TextRenderingModule.dll</HintPath>
|
||||
<Private>false</Private>
|
||||
</Reference>
|
||||
<Reference Include="Archon.SwissArmyLib">
|
||||
<HintPath>$(GameDir)\BepInEx\interop\Archon.SwissArmyLib.dll</HintPath>
|
||||
<Private>false</Private>
|
||||
</Reference>
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
Binary file not shown.
@@ -0,0 +1,23 @@
|
||||
{
|
||||
"runtimeTarget": {
|
||||
"name": ".NETCoreApp,Version=v6.0",
|
||||
"signature": ""
|
||||
},
|
||||
"compilationOptions": {},
|
||||
"targets": {
|
||||
".NETCoreApp,Version=v6.0": {
|
||||
"Skopje.DamageNumbers/1.0.0": {
|
||||
"runtime": {
|
||||
"Skopje.DamageNumbers.dll": {}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"libraries": {
|
||||
"Skopje.DamageNumbers/1.0.0": {
|
||||
"type": "project",
|
||||
"serviceable": false,
|
||||
"sha512": ""
|
||||
}
|
||||
}
|
||||
}
|
||||
Binary file not shown.
Binary file not shown.
@@ -0,0 +1,85 @@
|
||||
{
|
||||
"format": 1,
|
||||
"restore": {
|
||||
"c:\\Users\\andre\\Desktop\\SkopjeMods\\DamageNumbers\\DamageNumbersPlugin.csproj": {}
|
||||
},
|
||||
"projects": {
|
||||
"c:\\Users\\andre\\Desktop\\SkopjeMods\\DamageNumbers\\DamageNumbersPlugin.csproj": {
|
||||
"version": "1.0.0",
|
||||
"restore": {
|
||||
"projectUniqueName": "c:\\Users\\andre\\Desktop\\SkopjeMods\\DamageNumbers\\DamageNumbersPlugin.csproj",
|
||||
"projectName": "Skopje.DamageNumbers",
|
||||
"projectPath": "c:\\Users\\andre\\Desktop\\SkopjeMods\\DamageNumbers\\DamageNumbersPlugin.csproj",
|
||||
"packagesPath": "C:\\Users\\andre\\AppData\\Local\\Temp\\cursor-sandbox-cache\\a0404811fc6e51c4c5761fd11591789f\\nuget",
|
||||
"outputPath": "c:\\Users\\andre\\Desktop\\SkopjeMods\\DamageNumbers\\obj\\",
|
||||
"projectStyle": "PackageReference",
|
||||
"configFilePaths": [
|
||||
"C:\\Users\\andre\\AppData\\Roaming\\NuGet\\NuGet.Config",
|
||||
"C:\\Program Files (x86)\\NuGet\\Config\\Microsoft.VisualStudio.Offline.config"
|
||||
],
|
||||
"originalTargetFrameworks": [
|
||||
"net6.0"
|
||||
],
|
||||
"sources": {
|
||||
"C:\\Program Files (x86)\\Microsoft SDKs\\NuGetPackages\\": {},
|
||||
"https://api.nuget.org/v3/index.json": {}
|
||||
},
|
||||
"frameworks": {
|
||||
"net6.0": {
|
||||
"framework": "net6.0",
|
||||
"targetAlias": "net6.0",
|
||||
"projectReferences": {}
|
||||
}
|
||||
},
|
||||
"warningProperties": {
|
||||
"warnAsError": [
|
||||
"NU1605"
|
||||
]
|
||||
},
|
||||
"restoreAuditProperties": {
|
||||
"enableAudit": "true",
|
||||
"auditLevel": "low",
|
||||
"auditMode": "direct"
|
||||
},
|
||||
"SdkAnalysisLevel": "10.0.300"
|
||||
},
|
||||
"frameworks": {
|
||||
"net6.0": {
|
||||
"framework": "net6.0",
|
||||
"targetAlias": "net6.0",
|
||||
"imports": [
|
||||
"net461",
|
||||
"net462",
|
||||
"net47",
|
||||
"net471",
|
||||
"net472",
|
||||
"net48",
|
||||
"net481"
|
||||
],
|
||||
"assetTargetFallback": true,
|
||||
"warn": true,
|
||||
"downloadDependencies": [
|
||||
{
|
||||
"name": "Microsoft.AspNetCore.App.Ref",
|
||||
"version": "[6.0.36, 6.0.36]"
|
||||
},
|
||||
{
|
||||
"name": "Microsoft.NETCore.App.Ref",
|
||||
"version": "[6.0.36, 6.0.36]"
|
||||
},
|
||||
{
|
||||
"name": "Microsoft.WindowsDesktop.App.Ref",
|
||||
"version": "[6.0.36, 6.0.36]"
|
||||
}
|
||||
],
|
||||
"frameworkReferences": {
|
||||
"Microsoft.NETCore.App": {
|
||||
"privateAssets": "all"
|
||||
}
|
||||
},
|
||||
"runtimeIdentifierGraphPath": "C:\\Program Files\\dotnet\\sdk\\10.0.301\\RuntimeIdentifierGraph.json"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
<?xml version="1.0" encoding="utf-8" standalone="no"?>
|
||||
<Project ToolsVersion="14.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<PropertyGroup Condition=" '$(ExcludeRestorePackageImports)' != 'true' ">
|
||||
<RestoreSuccess Condition=" '$(RestoreSuccess)' == '' ">True</RestoreSuccess>
|
||||
<RestoreTool Condition=" '$(RestoreTool)' == '' ">NuGet</RestoreTool>
|
||||
<ProjectAssetsFile Condition=" '$(ProjectAssetsFile)' == '' ">$(MSBuildThisFileDirectory)project.assets.json</ProjectAssetsFile>
|
||||
<NuGetPackageRoot Condition=" '$(NuGetPackageRoot)' == '' ">$(UserProfile)\AppData\Local\Temp\cursor-sandbox-cache\a0404811fc6e51c4c5761fd11591789f\nuget</NuGetPackageRoot>
|
||||
<NuGetPackageFolders Condition=" '$(NuGetPackageFolders)' == '' ">C:\Users\andre\AppData\Local\Temp\cursor-sandbox-cache\a0404811fc6e51c4c5761fd11591789f\nuget</NuGetPackageFolders>
|
||||
<NuGetProjectStyle Condition=" '$(NuGetProjectStyle)' == '' ">PackageReference</NuGetProjectStyle>
|
||||
<NuGetToolVersion Condition=" '$(NuGetToolVersion)' == '' ">7.0.0</NuGetToolVersion>
|
||||
</PropertyGroup>
|
||||
<ItemGroup Condition=" '$(ExcludeRestorePackageImports)' != 'true' ">
|
||||
<SourceRoot Include="C:\Users\andre\AppData\Local\Temp\cursor-sandbox-cache\a0404811fc6e51c4c5761fd11591789f\nuget\" />
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
@@ -0,0 +1,2 @@
|
||||
<?xml version="1.0" encoding="utf-8" standalone="no"?>
|
||||
<Project ToolsVersion="14.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003" />
|
||||
@@ -0,0 +1,4 @@
|
||||
// <autogenerated />
|
||||
using System;
|
||||
using System.Reflection;
|
||||
[assembly: global::System.Runtime.Versioning.TargetFrameworkAttribute(".NETCoreApp,Version=v6.0", FrameworkDisplayName = ".NET 6.0")]
|
||||
@@ -0,0 +1,22 @@
|
||||
//------------------------------------------------------------------------------
|
||||
// <auto-generated>
|
||||
// This code was generated by a tool.
|
||||
//
|
||||
// Changes to this file may cause incorrect behavior and will be lost if
|
||||
// the code is regenerated.
|
||||
// </auto-generated>
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
using System;
|
||||
using System.Reflection;
|
||||
|
||||
[assembly: System.Reflection.AssemblyCompanyAttribute("Skopje.DamageNumbers")]
|
||||
[assembly: System.Reflection.AssemblyConfigurationAttribute("Release")]
|
||||
[assembly: System.Reflection.AssemblyFileVersionAttribute("1.0.0.0")]
|
||||
[assembly: System.Reflection.AssemblyInformationalVersionAttribute("1.0.0")]
|
||||
[assembly: System.Reflection.AssemblyProductAttribute("Skopje.DamageNumbers")]
|
||||
[assembly: System.Reflection.AssemblyTitleAttribute("Skopje.DamageNumbers")]
|
||||
[assembly: System.Reflection.AssemblyVersionAttribute("1.0.0.0")]
|
||||
|
||||
// Generated by the MSBuild WriteCodeFragment class.
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
a6bbf0f8cbba65e2618b81c6321ac40b204cddd43585a4acfc7f7e5c36244fcc
|
||||
+18
@@ -0,0 +1,18 @@
|
||||
is_global = true
|
||||
build_property.TargetFramework = net6.0
|
||||
build_property.TargetFrameworkIdentifier = .NETCoreApp
|
||||
build_property.TargetFrameworkVersion = v6.0
|
||||
build_property.TargetPlatformMinVersion =
|
||||
build_property.UsingMicrosoftNETSdkWeb =
|
||||
build_property.ProjectTypeGuids =
|
||||
build_property.InvariantGlobalization =
|
||||
build_property.PlatformNeutralAssembly =
|
||||
build_property.EnforceExtendedAnalyzerRules =
|
||||
build_property.EntryPointFilePath =
|
||||
build_property._SupportedPlatformList = Linux,macOS,Windows
|
||||
build_property.RootNamespace = Skopje.DamageNumbers
|
||||
build_property.ProjectDir = c:\Users\andre\Desktop\SkopjeMods\DamageNumbers\
|
||||
build_property.EnableComHosting =
|
||||
build_property.EnableGeneratedComInterfaceComImportInterop =
|
||||
build_property.EffectiveAnalysisLevelStyle = 6.0
|
||||
build_property.EnableCodeStyleSeverity =
|
||||
Binary file not shown.
Binary file not shown.
@@ -0,0 +1 @@
|
||||
86ccfeda65ab3141bba0482e04b1b5751f6561288b86aad71bf1a392c7e22381
|
||||
@@ -0,0 +1,12 @@
|
||||
c:\Users\andre\Desktop\SkopjeMods\DamageNumbers\obj\Release\net6.0\DamageNumbersPlugin.csproj.AssemblyReference.cache
|
||||
c:\Users\andre\Desktop\SkopjeMods\DamageNumbers\obj\Release\net6.0\DamageNumbersPlugin.GeneratedMSBuildEditorConfig.editorconfig
|
||||
c:\Users\andre\Desktop\SkopjeMods\DamageNumbers\obj\Release\net6.0\DamageNumbersPlugin.AssemblyInfoInputs.cache
|
||||
c:\Users\andre\Desktop\SkopjeMods\DamageNumbers\obj\Release\net6.0\DamageNumbersPlugin.AssemblyInfo.cs
|
||||
c:\Users\andre\Desktop\SkopjeMods\DamageNumbers\obj\Release\net6.0\DamageNumbersPlugin.csproj.CoreCompileInputs.cache
|
||||
c:\Users\andre\Desktop\SkopjeMods\DamageNumbers\bin\Release\net6.0\Skopje.DamageNumbers.deps.json
|
||||
c:\Users\andre\Desktop\SkopjeMods\DamageNumbers\bin\Release\net6.0\Skopje.DamageNumbers.dll
|
||||
c:\Users\andre\Desktop\SkopjeMods\DamageNumbers\bin\Release\net6.0\Skopje.DamageNumbers.pdb
|
||||
c:\Users\andre\Desktop\SkopjeMods\DamageNumbers\obj\Release\net6.0\Skopje.DamageNumbers.dll
|
||||
c:\Users\andre\Desktop\SkopjeMods\DamageNumbers\obj\Release\net6.0\refint\Skopje.DamageNumbers.dll
|
||||
c:\Users\andre\Desktop\SkopjeMods\DamageNumbers\obj\Release\net6.0\Skopje.DamageNumbers.pdb
|
||||
c:\Users\andre\Desktop\SkopjeMods\DamageNumbers\obj\Release\net6.0\ref\Skopje.DamageNumbers.dll
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -0,0 +1,90 @@
|
||||
{
|
||||
"version": 4,
|
||||
"targets": {
|
||||
"net6.0": {}
|
||||
},
|
||||
"libraries": {},
|
||||
"projectFileDependencyGroups": {
|
||||
"net6.0": []
|
||||
},
|
||||
"packageFolders": {
|
||||
"C:\\Users\\andre\\AppData\\Local\\Temp\\cursor-sandbox-cache\\a0404811fc6e51c4c5761fd11591789f\\nuget": {}
|
||||
},
|
||||
"project": {
|
||||
"version": "1.0.0",
|
||||
"restore": {
|
||||
"projectUniqueName": "c:\\Users\\andre\\Desktop\\SkopjeMods\\DamageNumbers\\DamageNumbersPlugin.csproj",
|
||||
"projectName": "Skopje.DamageNumbers",
|
||||
"projectPath": "c:\\Users\\andre\\Desktop\\SkopjeMods\\DamageNumbers\\DamageNumbersPlugin.csproj",
|
||||
"packagesPath": "C:\\Users\\andre\\AppData\\Local\\Temp\\cursor-sandbox-cache\\a0404811fc6e51c4c5761fd11591789f\\nuget",
|
||||
"outputPath": "c:\\Users\\andre\\Desktop\\SkopjeMods\\DamageNumbers\\obj\\",
|
||||
"projectStyle": "PackageReference",
|
||||
"configFilePaths": [
|
||||
"C:\\Users\\andre\\AppData\\Roaming\\NuGet\\NuGet.Config",
|
||||
"C:\\Program Files (x86)\\NuGet\\Config\\Microsoft.VisualStudio.Offline.config"
|
||||
],
|
||||
"originalTargetFrameworks": [
|
||||
"net6.0"
|
||||
],
|
||||
"sources": {
|
||||
"C:\\Program Files (x86)\\Microsoft SDKs\\NuGetPackages\\": {},
|
||||
"https://api.nuget.org/v3/index.json": {}
|
||||
},
|
||||
"frameworks": {
|
||||
"net6.0": {
|
||||
"framework": "net6.0",
|
||||
"targetAlias": "net6.0",
|
||||
"projectReferences": {}
|
||||
}
|
||||
},
|
||||
"warningProperties": {
|
||||
"warnAsError": [
|
||||
"NU1605"
|
||||
]
|
||||
},
|
||||
"restoreAuditProperties": {
|
||||
"enableAudit": "true",
|
||||
"auditLevel": "low",
|
||||
"auditMode": "direct"
|
||||
},
|
||||
"SdkAnalysisLevel": "10.0.300"
|
||||
},
|
||||
"frameworks": {
|
||||
"net6.0": {
|
||||
"framework": "net6.0",
|
||||
"targetAlias": "net6.0",
|
||||
"imports": [
|
||||
"net461",
|
||||
"net462",
|
||||
"net47",
|
||||
"net471",
|
||||
"net472",
|
||||
"net48",
|
||||
"net481"
|
||||
],
|
||||
"assetTargetFallback": true,
|
||||
"warn": true,
|
||||
"downloadDependencies": [
|
||||
{
|
||||
"name": "Microsoft.AspNetCore.App.Ref",
|
||||
"version": "[6.0.36, 6.0.36]"
|
||||
},
|
||||
{
|
||||
"name": "Microsoft.NETCore.App.Ref",
|
||||
"version": "[6.0.36, 6.0.36]"
|
||||
},
|
||||
{
|
||||
"name": "Microsoft.WindowsDesktop.App.Ref",
|
||||
"version": "[6.0.36, 6.0.36]"
|
||||
}
|
||||
],
|
||||
"frameworkReferences": {
|
||||
"Microsoft.NETCore.App": {
|
||||
"privateAssets": "all"
|
||||
}
|
||||
},
|
||||
"runtimeIdentifierGraphPath": "C:\\Program Files\\dotnet\\sdk\\10.0.301\\RuntimeIdentifierGraph.json"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
{
|
||||
"version": 2,
|
||||
"dgSpecHash": "KG8aXDVuUAU=",
|
||||
"success": true,
|
||||
"projectFilePath": "c:\\Users\\andre\\Desktop\\SkopjeMods\\DamageNumbers\\DamageNumbersPlugin.csproj",
|
||||
"expectedPackageFiles": [
|
||||
"C:\\Users\\andre\\AppData\\Local\\Temp\\cursor-sandbox-cache\\a0404811fc6e51c4c5761fd11591789f\\nuget\\microsoft.netcore.app.ref\\6.0.36\\microsoft.netcore.app.ref.6.0.36.nupkg.sha512",
|
||||
"C:\\Users\\andre\\AppData\\Local\\Temp\\cursor-sandbox-cache\\a0404811fc6e51c4c5761fd11591789f\\nuget\\microsoft.windowsdesktop.app.ref\\6.0.36\\microsoft.windowsdesktop.app.ref.6.0.36.nupkg.sha512",
|
||||
"C:\\Users\\andre\\AppData\\Local\\Temp\\cursor-sandbox-cache\\a0404811fc6e51c4c5761fd11591789f\\nuget\\microsoft.aspnetcore.app.ref\\6.0.36\\microsoft.aspnetcore.app.ref.6.0.36.nupkg.sha512"
|
||||
],
|
||||
"logs": []
|
||||
}
|
||||
Reference in new issue
Block a user