s&box Package Code Search
Search C# source code, UI razor templates, shaders, and configs across s&box packages.
link Raw Facepunch API Link: https://public.facepunch.com/sbox/code/search/1/?ident=rakunsoftware.milaine&take=20
Showing code results for query:
*
(38 total matches found)
Game
game
using System;
using Milaine.TreeSkills;
namespace Milaine.Managers;
public sealed class GameManager : Component {
[Property, Title("IdleManager")]
[Feature("General")]
public IdleManager IdleManagerInstance { get; set; }
[Property, Title("InvestmentManager")]
[Feature("General")]
public InvestmentManager InvestmentManagerInstance { get; set; }
[Property, Title("SkillTreeBootstrap")]
[Feature("General")]
public SkillTreeBootstrap SkillTreeBootstrapInstance { get; set; }
[Property, Title("DayNightManager")]
[Feature("General")]
public DayNightManager DayNightManagerInstance { get; set; }
public Action OnLooseGame { get; set; }
public Action OnWinGame { get; set; }
private List<SkillNodeData> skillsUsed = [];
private int maxSkillPoints = 0;
private int skillPoints = 0;
private bool isPlaying = true;
private bool isGameWin = false;
public bool IsGameWin {
get => isGameWin;
}
protected override void OnAwake() {
TreeSkillState.Instance.OnUnlocked += OnUnlocked;
TreeSkillState.Instance.SpendPoint += OnSpendPoint;
TreeSkillState.Instance.GetSkillPoints = GetSkillPoints;
DayNightManagerInstance.OnEndDay += OnEndDay;
InvestmentManagerInstance.OnChange += OnInvestmentManagerChange;
}
protected override void OnDestroy() {
TreeSkillState.Instance.OnUnlocked -= OnUnlocked;
TreeSkillState.Instance.SpendPoint -= OnSpendPoint;
DayNightManagerInstance.OnEndDay -= OnEndDay;
InvestmentManagerInstance.OnChange -= OnInvestmentManagerChange;
}
private void OnEndDay() {
if (DayNightManagerInstance.Day < 5) {
return;
}
isPlaying = false;
isGameWin = false;
OnLooseGame?.Invoke();
}
private void OnInvestmentManagerChange(Portfolio portfolio) {
if (!isPlaying) {
return;
}
int total = (int)portfolio.investment;
int goal = IdleManagerInstance.Goal;
if (total >= goal) {
isPlaying = false;
isGameWin = true;
DayNightManagerInstance.ResetManager();
OnWinGame?.Invoke();
}
}
private void OnUnlocked(SkillNodeData node) {
if (skillsUsed.Contains(node)) {
return;
}
skillsUsed.Add(node);
switch (node.Category) {
case SkillCategory.Dollars:
IdleManagerInstance.ImprovePoint(node.Point);
break;
case SkillCategory.DollarAutomatic:
IdleManagerInstance.ImprovePasiveDollar(node.Point);
break;
case SkillCategory.Wallet:
InvestmentManagerInstance.ImproveWallet(node.Point);
break;
case SkillCategory.Investment:
InvestmentManagerInstance.ImprovePerformance(node.Point);
break;
case SkillCategory.Dividends:
InvestmentManagerInstance.ImproveDividends(node.Point);
break;
case SkillCategory.WalletPlus:
InvestmentManagerInstance.ImproveDeposit(node.Point);
break;
}
}
private int GetSkillPoints() => skillPoints;
private void OnSpendPoint() {
skillPoints--;
}
public void Restart() {
DayNightManagerInstance.Restart();
TreeSkillState.Instance.Restart();
skillsUsed = [];
maxSkillPoints += 1;
skillPoints += maxSkillPoints;
IdleManagerInstance.Restart();
InvestmentManagerInstance.Restart();
}
}
Game
game
namespace Milaine.Managers;
public enum StateMouse {
Relased,
Busy
}
public static class MouseManager {
public static StateMouse State { get; set; } = StateMouse.Relased;
public static void ShowMouse() {
Mouse.Visibility = MouseVisibility.Visible;
}
public static void HideMouse() {
Mouse.Visibility = MouseVisibility.Hidden;
}
}
Game
game
using System;
using Milaine.Interfaces;
namespace Milaine.Managers;
public sealed class DayNightManager : Component, IManager {
// 60 -> seconds
private const int MINUTE = 60;
// 5 mins
private const int MAX_TIME = 5 * MINUTE;
public const int MAX_DAYS = 5;
[Property]
public float DayDuration { get; set; } = MAX_TIME;
[Property]
public int Day { get; set; } = 1;
// hour in 24h
private readonly float startHour = 8f;
private readonly float endHour = 18f;
private bool isDayActive = false;
private TimeUntil timeUntilNight;
public string CurrentTimeString { get; private set; } = "8:00 AM";
public Action OnStartDay;
public Action OnEndDay;
protected override void OnStart() {
StartDay();
}
protected override void OnUpdate() {
if (!isDayActive) {
return;
}
float elapsedSeconds = DayDuration - timeUntilNight;
float progress = MathX.Clamp(elapsedSeconds / DayDuration, 0f, 1f);
float totalVirtualHours = endHour - startHour;
float currentVirtualHour = startHour + (progress * totalVirtualHours);
int hours = (int)MathF.Floor(currentVirtualHour);
int minutes = (int)MathF.Floor((currentVirtualHour - hours) * 60f);
string amPm = hours >= 12 ? "PM" : "AM";
int displayHour = hours % 12;
if (displayHour == 0) {
displayHour = 12;
}
CurrentTimeString = $"{displayHour:D2}:{minutes:D2} {amPm}";
if (timeUntilNight) {
EndDay();
}
}
private void StartDay() {
if (isDayActive) {
return;
}
timeUntilNight = DayDuration;
isDayActive = true;
OnStartDay?.Invoke();
}
private void EndDay() {
ResetManager(deep: false);
OnEndDay?.Invoke();
}
public void ResetManager(bool deep = false) {
if (deep) {
CurrentTimeString = "8:00 AM";
}
isDayActive = false;
}
public void NextDay() {
if (Day >= MAX_DAYS) {
return;
}
Day += 1;
StartDay();
}
public void Restart() {
Day = 1;
StartDay();
}
}
Game
game
using System;
using Milaine.Managers;
namespace Milaine.Room;
public sealed class ClickableButton : Component {
[Property, Group("References")]
public SkinnedModelRenderer Model { get; set; }
[Property, Group("Animation"), Title("Sequence Name")]
public string PressSequence { get; set; } = "press";
[Property, Group("Animation")]
public bool UsesAnimGraph { get; set; } = false;
[Property, Group("Interaction")]
public float MaxClickDistance { get; set; } = 1000f;
[Property, Group("Squish (Scale Z)"), Range(0.1f, 1f)]
public float PressedScale { get; set; } = 0.8f;
[Property, Group("Squish (Scale Z)"), Range(1f, 30f)]
public float ScaleSpeed { get; set; } = 14f;
public Action OnPressed { get; set; }
private bool isHeld;
private Vector3 originalScale;
private float currentScaleFactor = 1f;
protected override void OnStart() {
if (!Model.IsValid()) {
Model = Components.Get<SkinnedModelRenderer>();
}
originalScale = LocalScale;
}
protected override void OnUpdate() {
if (MouseManager.State == StateMouse.Busy) {
return;
}
var camera = Scene.Camera;
if (!camera.IsValid()) {
return;
}
var ray = camera.ScreenPixelToRay(Mouse.Position);
var trace = Scene.Trace.Ray(ray, MaxClickDistance).Run();
bool isHoveredNow = trace.Hit && trace.GameObject == GameObject;
if ((Input.Pressed("attack1") || Input.Pressed("attack2")) && isHoveredNow) {
Press();
isHeld = true;
}
if (Input.Released("attack1") || Input.Released("attack2")) {
isHeld = false;
}
float targetFactor = isHeld ? PressedScale : 1f;
currentScaleFactor = MathX.Lerp(currentScaleFactor, targetFactor, Time.Delta * ScaleSpeed);
LocalScale = new Vector3(originalScale.x, originalScale.y, originalScale.z * currentScaleFactor);
}
public void Press() {
PlayPressAnimation();
Sound.Play("sounds/sound_key_down.sound");
OnPressed?.Invoke();
}
private void PlayPressAnimation() {
if (!Model.IsValid()) {
return;
}
if (UsesAnimGraph) {
Model.Set(PressSequence, true);
} else {
Model.SceneModel.UseAnimGraph = false;
Model.SceneModel.CurrentSequence.Name = PressSequence;
}
}
}
Game
game
namespace Milaine.Room;
public sealed class RoomManager : Component {
[Property]
public List<GameObject> Models { get; set; } = [];
private List<GameObject> ChairChildren = [];
protected override void OnAwake() {
if (Models.Count == 0) {
Log.Warning("Models list is empty");
return;
}
foreach (GameObject gameObject in Models) {
if (!gameObject.IsValid()) {
continue;
}
Prop prop = gameObject.GetComponent<Prop>();
if (!prop.IsValid()) {
continue;
}
prop.IsStatic = true;
if (gameObject.Name == "office_chair") {
gameObject.GetComponent<ModelRenderer>().Destroy();
gameObject.GetComponent<ModelPhysics>().Destroy();
foreach (GameObject obj in gameObject.Children) {
ChairChildren.Add(obj);
}
}
}
}
protected override void OnUpdate() {
if (ChairChildren.Count == 0) {
return;
}
foreach (GameObject gameObject in ChairChildren) {
gameObject.Destroy();
}
ChairChildren = [];
}
}
Game
game
using System;
namespace Milaine.Settings;
public class ConfigurationData {
public string Language { get; set; } = "en";
}
public sealed class Configuration : Component {
private readonly string filename = "settings.cfg";
[Property]
public string Language { get; set; } = "en";
protected override void OnAwake() {
if (!FileSystem.Data.FileExists(filename)) {
SaveConfig();
return;
}
LoadConfig();
}
public void LoadConfig() {
var config = FileSystem.Data.ReadJson<ConfigurationData>(filename);
Language = config.Language;
}
public void SaveConfig() {
try {
var config = new ConfigurationData { Language = Language };
FileSystem.Data.WriteJson(filename, config);
}
catch (Exception ex) {
Log.Warning($"Error to try create configuration file: {ex.Message}");
}
}
}
Game
game
@using Sandbox;
@using Sandbox.UI;
@namespace Milaine.UI
@inherits Panel
<root></root>
@code {
public static FloatingTextManager Instance { get; set; }
public FloatingTextManager()
{
Instance = this;
}
public override void OnDeleted()
{
base.OnDeleted();
if (Instance == this)
{
Instance = null;
}
}
public void Spawn(string text, float screenX, float screenY)
{
var floatingText = AddChild<FloatingText>();
floatingText.Text = text;
floatingText.SpawnX = screenX;
floatingText.SpawnY = screenY;
}
}
<style>
FloatingTextManager {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
pointer-events: none;
}
</style>
Game
game
namespace Milaine.Utils;
public sealed class Outliner : Component {
[Property, Group("Interaction")]
public float MaxClickDistance { get; set; } = 1000f;
[Property, Group("Outline"), Title("Color Hover")]
public Color HoverOutlineColor { get; set; } = Color.White;
[Property, Group("Outline"), Range(0.1f, 10f)]
public float OutlineWidth { get; set; } = 0.5f;
private HighlightOutline outline;
protected override void OnAwake() {
}
protected override void OnStart() {
outline = GameObject.GetOrAddComponent<HighlightOutline>();
outline.Color = Color.Transparent;
outline.Width = OutlineWidth;
}
protected override void OnUpdate() {
var camera = Scene.Camera;
if (!camera.IsValid()) {
return;
}
var ray = camera.ScreenPixelToRay(Mouse.Position);
var trace = Scene.Trace.Ray(ray, MaxClickDistance).Run();
bool isHoveredNow = trace.Hit && trace.GameObject == GameObject;
if (outline.IsValid()) {
outline.Color = isHoveredNow ? HoverOutlineColor : Color.Transparent;
}
}
}
Game
game
@using System.Threading.Tasks;
@using Milaine.Managers;
@using Milaine.Settings;
@using Milaine.UI;
@using Milaine.Utils;
@using Sandbox;
@using Sandbox.UI;
@inherits PanelComponent
@namespace Sandbox
<root>
<header class="header">
<section class="day-manager">
<h2>
@TranslationsInstance.T("milaine.days", data)
@* @Language.GetPhrase("milaine.days", data) *@
</h2>
</section>
<section class="clock">
<p>@DayNightManagerInstance.CurrentTimeString</p>
</section>
</header>
<section class="progress-end-game">
<div class="progress-bar">
<div class="bar" style="width: @(GetPercentage())%;" />
<p>@Formatter.ToDisplay(InvestmentManagerInstance.Total) / @Formatter.ToDisplay(IdleManagerInstance.Goal)</p>
</div>
</section>
<button class="slot" style="pointer-events: @(!isPanelOpened ? "all" : "none");" onclick=@TogglePanel>
<p class="kbd">E</p>
<p class="title">
@TranslationsInstance.T("milaine.tree-skills")
@* #milaine.tree-skills *@
</p>
</button>
<div class="container">
<section class="content">
<Image src="resources/wallet-minimal.png" class="image" style="width: 40px; height: 40px;" />
<p class="headline">[email protected](Dollars)</p>
<FloatingTextManager />
</section>
</div>
@if (isInitializedDay) {
<div class="day-container">
<h2 class="heading-current-day">
@* @Language.GetPhrase("milaine.days", data) *@
@TranslationsInstance.T("milaine.days", data)
</h2>
</div>
}
@if (isGameWin) {
<div
style="background-color: black; position: absolute; top: 0; left: 0; right: 0; bottom: 0; justify-content: center; align-items: center;">
<div style="width: 30%;justify-content:center;align-items:center;">
<p style="font-size: 40px; font-family: 'JetBrains Mono';">
@* #milaine.wingame *@
@TranslationsInstance.T("milaine.wingame")
</p>
</div>
</div>
}
@if (isDayEnd && !isGameWin) {
<div class="day-container night">
<div class="summary-container">
<header class="summary-header">
<div class="summary-title">
<span class="circle" />
<h2 class="normal-font">
@* #milaine.summary.title *@
@TranslationsInstance.T("milaine.summary.title")
</h2>
</div>
<div class="separator" />
</header>
<div class="row">
<div class="form-control nth mblue">
<div class="form-control-header">
<h3 class="normal-font">
@* #milaine.summary.investment *@
@TranslationsInstance.T("milaine.summary.investment")
</h3>
<span class="circle-base circle-blue" />
</div>
<p class="number">
[email protected](InvestmentManagerInstance.Profit)
</p>
</div>
<div class="form-control nth mgreen">
<div class="form-control-header">
<h3 class="normal-font">
@* #milaine.summary.wallet *@
@TranslationsInstance.T("milaine.summary.wallet")
</h3>
<span class="circle-base circle-green" />
</div>
<p class="number">
[email protected](InvestmentManagerInstance.WalletPasive)
</p>
</div>
<div class="form-control nth mred">
<div class="form-control-header">
<h3 class="normal-font">
@* #milaine.summary.dollar-spent *@
@TranslationsInstance.T("milaine.summary.dollar-spent")
</h3>
<span class="circle-base circle-red" />
</div>
<p class="number">
[email protected](IdleManagerInstance.DollarsSpent)
</p>
</div>
</div>
<div class="separator" />
@if (DayNightManagerInstance.Day == DayNightManager.MAX_DAYS) {
<button class="btn-next-action normal-font" onclick=@HandleAgain>
@* #milaine.back-to-past *@
@TranslationsInstance.T("milaine.back-to-past")
</button>
} else {
<button class="btn-next-action normal-font" onclick=@HandleNextDay>
@* #milaine.next-day *@
@TranslationsInstance.T("milaine.next-day")
</button>
}
</div>
</div>
}
<div class="version-manager">
<p>@("v" + VersionManagerInstance.Version.ToString())</p>
</div>
</root>
@code
{
private const float ANIMATION_DURATION = 5f;
[Property, Title("Translations")]
[Feature("Managers")]
public Translations TranslationsInstance { get; set; }
[Property, Title("VersionManager")]
[Feature("Managers")]
public VersionManager VersionManagerInstance { get; set; }
[Property, Title("IdleManager")]
[Feature("Managers")]
public IdleManager IdleManagerInstance { get; set; }
[Property, Title("InvestmentManager")]
[Feature("Managers")]
public InvestmentManager InvestmentManagerInstance { get; set; }
[Property, Title("DayNightManager")]
[Feature("Managers")]
public DayNightManager DayNightManagerInstance { get; set; }
[Property, Title("GameManager")]
[Feature("Managers")]
public GameManager GameManagerInstance { get; set; }
[Property, Title("TreeSkillPanel")]
[Feature("General")]
public TreeSkillPanel TreeSkillPanelInstance { get; set; }
[Property]
[Feature("General")]
public int Dollars { get; set; } = 0;
private bool isPanelOpened = false;
private Dictionary<string, object> data = [];
private bool isInitializedDay = false;
private bool isDayEnd = false;
private bool isGameWin = false;
protected override int BuildHash() => System.HashCode.Combine(Dollars,
DayNightManagerInstance.CurrentTimeString, DayNightManagerInstance.Day, InvestmentManagerInstance.Total
, IdleManagerInstance.DollarsSpent, InvestmentManagerInstance.WalletPasive, InvestmentManagerInstance.Profit);
protected override void OnAwake() {
base.OnStart();
data["Day"] = DayNightManagerInstance.Day;
IdleManagerInstance.OnDeposit += RefreshDeposit;
IdleManagerInstance.OnChange += Refresh;
DayNightManagerInstance.OnStartDay += StartDay;
DayNightManagerInstance.OnEndDay += EndDay;
GameManagerInstance.OnWinGame += OnWinGame;
}
protected override void OnUpdate() {
if (Input.Pressed("use")) {
TogglePanel();
return;
}
if (Input.EscapePressed) {
isPanelOpened = false;
StateHasChanged();
TreeSkillPanelInstance.Close();
}
}
protected override void OnDestroy() {
base.OnDestroy();
IdleManagerInstance.OnDeposit -= RefreshDeposit;
IdleManagerInstance.OnChange -= Refresh;
DayNightManagerInstance.OnStartDay -= StartDay;
DayNightManagerInstance.OnEndDay -= EndDay;
GameManagerInstance.OnWinGame -= OnWinGame;
}
private void OnWinGame() {
isGameWin = GameManagerInstance.IsGameWin;
}
private void TogglePanel() {
isPanelOpened = !isPanelOpened;
StateHasChanged();
Panel.Blur();
if (isPanelOpened) {
TreeSkillPanelInstance.Open();
return;
}
TreeSkillPanelInstance.Close();
}
private string GetPercentage() {
float Total = InvestmentManagerInstance.Total;
float percentage = (Total / IdleManagerInstance.Goal) * 100;
return Pixel.Inv(percentage);
}
private void StartDay() {
isInitializedDay = true;
StateHasChanged();
_ = HideAafterDelay();
}
private void EndDay() {
isDayEnd = true;
StateHasChanged();
}
private void HandleNextDay() {
isDayEnd = false;
DayNightManagerInstance.NextDay();
data["Day"] = DayNightManagerInstance.Day;
StateHasChanged();
StartDay();
}
private async Task HideAafterDelay() {
await Task.DelaySeconds(ANIMATION_DURATION);
isInitializedDay = false;
StateHasChanged();
}
private void Refresh(int dollars, int amount) {
Dollars = dollars;
FloatingTextManager.Instance.Spawn($"+{amount}", 25f, 10f);
}
private void RefreshDeposit() {
Dollars = 0;
}
private void HandleAgain() {
GameManagerInstance.Restart();
}
}
Game
game
@using Milaine.Managers;
@using Milaine.Settings;
@using Sandbox;
@using Sandbox.UI;
@inherits PanelComponent
@namespace Sandbox
<root>
@if (PauseGameInstance.IsOpened) {
<div class="pause-container">
<header class="header">
<DropDown Options=@ModeOptions Value=@SelectedMode ValueChanged=@OnOptionChanged />
</header>
<main>
<div class="container">
<button [email protected]>
@TranslationsInstance.T("milaine.back")
</button>
<button onclick=@ExitGame>
@TranslationsInstance.T("milaine.quit")
</button>
</div>
<div class="credits">
<p>Credits</p>
<p>
Computer Keyboard by Luke (https://sbox.game/luke/office_keyboard)
</p>
<p>
Computer Monitor by Luke (https://sbox.game/luke/monitor_basic)
</p>
<p>
Computer Mouse by Luke (https://sbox.game/luke/computer_mouse)
</p>
<p>
Coffee_cup_01 by Small Box Studio (https://sbox.game/smallboxstudio/coffeecup01)
</p>
<p>
French_fries_02 by Small Box Studio (https://sbox.game/smallboxstudio/frenchfries02)
</p>
<p>
French_fries_02_empty by Small Box Studio (https://sbox.game/smallboxstudio/frenchfries02empty)
</p>
<p>
Stir_fried_noodles_01 by Small Box Studio (https://sbox.game/smallboxstudio/stirfriednoodles01)
</p>
<p>
Stir_fried_noodles_01_close by Small Box Studio (https://sbox.game/smallboxstudio/stirfriednoodles01close)
</p>
</div>>
</main>
</div>
<div class="version-manager">
<p>@("v" + VersionManagerInstance.Version.ToString())</p>
</div>
}
</root>
@code
{
[Property, Title("Translations")]
[Feature("Managers")]
public Translations TranslationsInstance { get; set; }
[Property, Title("VersionManager")]
[Feature("Managers")]
public VersionManager VersionManagerInstance { get; set; }
[Property]
[Feature("Settings")]
public PauseGame PauseGameInstance { get; set; }
public string SelectedMode { get; set; } = "en";
public List<UI.Option> ModeOptions { get; set; } = [
new Option{Title = "English", Value = "en"},
new Option{Title = "Español", Value = "es"},
];
protected override int BuildHash() => System.HashCode.Combine(PauseGameInstance.IsOpened, SelectedMode);
protected override void OnStart() {
base.OnStart();
SelectedMode = TranslationsInstance.language;
}
private void ExitGame() {
if (Application.IsStandalone) {
Game.Close();
return;
}
Game.Disconnect();
}
private void OnOptionChanged(object code) {
SelectedMode = (string)code;
TranslationsInstance.SetLanguage((string)code);
StateHasChanged();
}
}
Game
game
namespace Milaine.Managers;
public sealed class DialoguesManager : Component {
[Property, Title("Dialogues View")]
public PanelComponent DialoguesView { get; set; }
private List<Step> steps = [];
private class Step { }
protected override void OnStart() {
if (!DialoguesView.IsValid()) {
Log.Warning("Need Instances of [DialoguesView]");
}
}
}
Game
game
namespace Milaine.TreeSkills;
public enum SkillCategory {
Dollars,
Wallet,
Investment,
Dividends,
WalletPlus,
DollarAutomatic
}
public class SkillNodeData {
public string Id { get; set; }
public string Name { get; set; }
public string Description { get; set; }
public string KeyDescription { get; set; }
public int Cost { get; set; }
public SkillCategory Category { get; set; }
public float Point { get; set; }
public int Row { get; set; }
public int Column { get; set; }
public string Icon { get; set; } = "🌕";
public bool IsRoot { get; set; }
}
Game
game
namespace Milaine.Constants;
public class VersionConstants {
public const int MAYOR = 0;
public const int MINOR = 9;
public const int PATCH = 1;
}
Game
game
using System;
using Milaine.Interfaces;
namespace Milaine.Managers;
public struct Portfolio(int wallet = 0, float investment = 0, float profit = 0, int shares = 0) {
public int wallet = wallet;
public float investment = investment;
public float profit = profit;
public int shares = shares;
}
public sealed class InvestmentManager : Component, IManager {
public const float DEFAULT_PERFORMANCE = 1.0f;
[Property, Title("DayNightManager")]
[Feature("Managers")]
public DayNightManager DayNightManagerInstance { get; set; }
[Property]
[Feature("General")]
public bool IsDayEnded { get; set; } = false;
[Property]
[Feature("General"), Group("Digital")]
public int Wallet { get; set; } = 0;
[Property]
[Feature("General"), Group("Digital")]
public float Investment { get; set; } = 0;
[Property]
[Feature("General"), Group("Digital")]
public float Profit { get; set; } = 0;
[Property]
[Feature("General"), Group("Digital")]
public int Shares { get; set; } = 0;
public Action<Portfolio> OnChange { get; set; }
private float performance = DEFAULT_PERFORMANCE;
private float acc = 0f;
private float multiplierDeposit = 1.0f;
private bool isAvailablePerformanceWallet = false;
private int performanceWallet = (int)DEFAULT_PERFORMANCE;
private float accDividends = 0f;
private bool isActivatedDividends = false;
private float multiplierDividends = 0.0f;
private int walletPasive = 0;
public float Total {
get => Wallet + Investment;
}
public int WalletPasive {
get => walletPasive;
}
protected override void OnStart() {
DayNightManagerInstance.OnStartDay += DayStartSubscription;
DayNightManagerInstance.OnEndDay += DayNightSubscription;
}
protected override void OnDestroy() {
DayNightManagerInstance.OnStartDay -= DayStartSubscription;
DayNightManagerInstance.OnEndDay -= DayNightSubscription;
}
protected override void OnUpdate() {
if (IsDayEnded) {
return;
}
acc += Time.Delta;
if (acc >= 1.0f) {
if (Investment != 0f) {
Profit += performance;
Investment += performance;
}
if (isAvailablePerformanceWallet) {
Wallet += performanceWallet;
walletPasive += performanceWallet;
}
acc = 0;
}
accDividends += Time.Delta;
if (accDividends >= 5.0f && isActivatedDividends) {
Wallet += (Investment * multiplierDividends).CeilToInt();
accDividends = 0;
}
}
public void Deposit(int dollars) {
Wallet += (multiplierDeposit * dollars).CeilToInt();
OnChange?.Invoke(new Portfolio { wallet = Wallet, investment = Investment, profit = Profit, shares = Shares });
}
public void Invest() {
Investment += Wallet;
Wallet = 0;
OnChange?.Invoke(new Portfolio { wallet = Wallet, investment = Investment, profit = Profit, shares = Shares });
}
private void DayNightSubscription() {
IsDayEnded = true;
}
private void DayStartSubscription() {
IsDayEnded = false;
Profit = 0;
walletPasive = 0;
}
public void ImprovePerformance(float amount) {
performance += amount;
}
public void ImproveWallet(float amount) {
ImproveWallet((int)amount);
}
private void ImproveWallet(int amount) {
if (!isAvailablePerformanceWallet) {
isAvailablePerformanceWallet = true;
}
performanceWallet = amount;
}
public void ImproveDeposit(float amount) {
multiplierDeposit = amount;
}
public void ImproveDividends(float amount) {
if (!isActivatedDividends) {
isActivatedDividends = true;
}
multiplierDividends = amount;
}
public void Restart() {
// reset all stats (wallet, profit, investment, days)
performance = DEFAULT_PERFORMANCE;
multiplierDeposit = 1.0f;
isActivatedDividends = false;
multiplierDividends = 0.0f;
isAvailablePerformanceWallet = false;
performanceWallet = (int)DEFAULT_PERFORMANCE;
walletPasive = 0;
Wallet = 0;
Investment = 0f;
Profit = 0;
Shares = 0;
}
}
Game
game
using Milaine.Utils;
namespace Milaine.Settings;
public sealed class Translations : Component {
[Property, Title("Configuration")]
public Configuration ConfigurationInstance { get; set; }
private Localization localization;
public string language = "en";
protected override void OnAwake() {
localization = new();
language = ConfigurationInstance.Language;
localization.SetLanguage(ConfigurationInstance.Language);
}
public void SetLanguage(string language) {
localization.SetLanguage(language);
this.language = language;
ConfigurationInstance.Language = language;
ConfigurationInstance.SaveConfig();
}
public string T(string token, Dictionary<string, object> data = null) => localization.T(token, data);
}
Game
game
@using System.Text;
@using Milaine.Managers;
@using Milaine.Settings;
@using Milaine.Utils;
@using Sandbox;
@using Sandbox.UI;
@inherits PanelComponent
@namespace Sandbox
<root>
<header>
<div class="container-title">
<Image src="resources/hexagon.png" class="image" style="width: 20px; height: 20px;" />
<h1 class="title">SHARES // WORKS</h1>
</div>
<div class="content" style="pointer-events: @(MouseManager.State == StateMouse.Busy ? "none" : "all");">
<Image src="resources/wallet-minimal.png" class="image" style="width: 20px; height: 20px;" />
<p class="text">[email protected](InvestmentManagerInstance.Wallet)</p>
</div>
</header>
<div class="container">
<section class="card" style="pointer-events: @(MouseManager.State == StateMouse.Busy ? "none" : "all");">
<div class="card-header">
<div class="card-header-wrapper">
@if (InvestmentManagerInstance.Profit == 0) {
<Image src="resources/dot.png" />
}
@if (InvestmentManagerInstance.Profit > 0) {
<Image src="resources/trending-up.png" />
}
@if (InvestmentManagerInstance.Profit < 0) {
<Image src="resources/trending-down.png" />
}
<p class="card-title">
@* #milaine.profit.total *@
@TranslationsInstance.T("milaine.profit.total")
</p>
</div>
<div class=@ClassName()>
@if (InvestmentManagerInstance.Profit == 0) {
<p>
@* #milaine.critical.standard-profit *@
@TranslationsInstance.T("milaine.critical.standard-profit")
</p>
}
@if (InvestmentManagerInstance.Profit < 0) {
<p>
@* #milaine.critical.bad-profit *@
@TranslationsInstance.T("milaine.critical.bad-profit")
</p>
}
@if (InvestmentManagerInstance.Profit > 0) {
<p>
@* #milaine.critical.profit *@
@TranslationsInstance.T("milaine.critical.profit")
</p>
}
</div>
</div>
<div class="card-body">
<div class="investment-container">
<div class="investment-content">
<p
class="investment-text @(InvestmentManagerInstance.Profit == 0 ? "normal" : InvestmentManagerInstance.Profit < 0 ? "bad" : "good")">
@BuildInvestment(InvestmentManagerInstance.Investment)
</p>
@if (InvestmentManagerInstance.Profit > 0) {
<p class="shares">[email protected]</p>
}
</div>
<div class="action">
<button class="btn btn-primary" onclick=@HandleClickInvestment>
@* #milaine.invest *@
@TranslationsInstance.T("milaine.invest")
</button>
<button class="btn btn-secondary" onclick=@HandleClickDeposit>
@* #milaine.deposit *@
@TranslationsInstance.T("milaine.deposit")
</button>
</div>
</div>
</div>
</section>
</div>
</root>
@code
{
[Property, Title("InvestmentManager")]
[Feature("Managers")]
public InvestmentManager InvestmentManagerInstance { get; set; }
[Property, Title("IdleManager")]
[Feature("Managers")]
public IdleManager IdleManagerInstance { get; set; }
[Property, Title("Translations")]
[Feature("Managers")]
public Translations TranslationsInstance { get; set; }
public Dictionary<string, object> Data = [];
protected override int BuildHash() => System.HashCode.Combine(Data, InvestmentManagerInstance.Wallet,
InvestmentManagerInstance.Profit, TranslationsInstance.language, MouseManager.State);
protected override void OnStart() {
if (!InvestmentManagerInstance.IsValid()) {
Log.Warning("Need Instance the InvestmentManager into [InvestmentView]");
return;
}
Refresh();
}
protected override void OnUpdate() {
base.OnUpdate();
if (Input.EscapePressed) {
StateHasChanged();
}
}
public string ClassName() => InvestmentManagerInstance.Profit == 0 ? "tag standard" : InvestmentManagerInstance.Profit
< 0 ? "tag low" : "tag";
private void HandleClickInvestment() {
InvestmentManagerInstance.Invest();
Refresh();
}
private void HandleClickDeposit() {
InvestmentManagerInstance.Deposit(IdleManagerInstance.Dollars);
IdleManagerInstance.Deposit();
Refresh();
}
private string BuildInvestment(float investment) {
StringBuilder sb = new();
float profit = InvestmentManagerInstance.Profit;
if (profit < 0) {
sb.Append("- $");
}
if (profit > 0) {
sb.Append("+ $");
}
sb.Append(Formatter.ToDisplay(investment));
return sb.ToString();
}
private void Refresh() {
Data["WalletValue"] = Formatter.ToDisplayShort(InvestmentManagerInstance.Wallet);
Data["InvestmentValue"] = Formatter.ToDisplay(InvestmentManagerInstance.Investment);
Data["ProfitValue"] = Formatter.ToDisplay(InvestmentManagerInstance.Profit);
Data["SharesValue"] = InvestmentManagerInstance.Shares;
}
}
Game
game
Hud {
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
flex-direction: column;
font-weight: bold;
border-radius: 20px;
color: #fff;
font-size: 25px;
.header {
display: flex;
justify-content: flex-end;
align-items: center;
gap: 50px;
padding: 20px;
.day-manager h2 {
text-align: center;
font-size: 30px;
font-family: "Space Grotesk";
}
.clock {
background-color: rgba(0, 0, 0, 0.5);
color: #fff;
display: flex;
justify-content: center;
align-items: center;
p {
text-align: center;
font-size: 28px;
font-family: "JetBrains Mono";
}
}
}
.container {
position: absolute;
bottom: 50px;
right: 50px;
font-family: "JetBrains Mono";
.content {
padding: 10px 20px;
display: flex;
background-color: rgba(0, 0, 0, 0.5);
border: 1px solid rgba(39, 42, 46, 0.8);
border-radius: 5px;
justify-content: center;
align-items: center;
gap: 10px;
.image {
object-fit: cover;
}
.headline {
color: #00ff66;
}
}
}
.slot {
position: absolute;
bottom: 50px;
right: 300px;
display: flex;
justify-content: center;
align-items: center;
flex-direction: column;
gap: 10px;
border-radius: 5px;
padding: 10px 15px;
background-color: rgba(0, 0, 0, 0.5);
transition: all 300ms ease;
&:hover {
background-color: rgba(0, 0, 0, 0.8);
transition: all 300ms ease;
sound-in: ui.button.over;
}
.kbd {
font-family: "JetBrains Mono";
font-size: 30px;
}
.title {
font-family: "Space Grotesk";
font-size: 21px;
}
}
.progress-end-game {
position: absolute;
width: 70%;
bottom: 50px;
left: 50px;
.progress-bar {
width: 100%;
height: 40px;
padding: 4px;
border-radius: 6px;
overflow: hidden;
background-color: rgba(0, 0, 0, 0.7);
.bar {
height: 100%;
background-image: linear-gradient(to right, #00e55b, #00ff66, #00e3fd);
border-radius: 2px;
}
p {
position: absolute;
font-family: "JetBrains Mono";
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
}
}
}
.day-container {
position: fixed;
top: 0;
left: 0;
right: 0;
bottom: 0;
width: 100%;
height: 100%;
justify-content: center;
align-items: center;
background-color: rgb(7, 9, 11);
opacity: 0;
pointer-events: none;
z-index: 999;
animation-name: morning;
animation-duration: 5s;
animation-timing-function: ease;
animation-fill-mode: forwards;
.heading-current-day {
font-size: 40px;
text-align: center;
font-weight: 700;
font-family: "Space Grotesk";
letter-spacing: 2px;
}
&.night {
flex-direction: column;
animation-name: night;
animation-duration: 2s;
button {
pointer-events: all;
}
}
.summary-container {
width: 35%;
padding: 24px;
border: 1px solid #1e2936;
flex-direction: column;
background-color: rgb(18 23 30 / 0.95);
border-radius: 12px;
overflow: hidden;
box-shadow:
0 0 25px -5px rgba(0, 255, 102, 0.25),
inset 0 0 15px -3px rgba(0, 255, 102, 0.08);
.summary-header {
margin-bottom: 20px;
flex-direction: column;
.summary-title {
display: flex;
align-items: center;
justify-content: flex-start;
gap: 10px;
padding-bottom: 16px;
.circle {
width: 16px;
height: 16px;
border-radius: 50%;
background-color: #00ff66;
}
h2 {
font-family: "Space Grotesk";
font-size: 40px;
}
}
}
.row {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 20px;
gap: 20px;
}
.form-control {
padding: 16px;
background-color: rgb(13 17 22 / 0.9);
border: 1px solid rgb(30 41 54 / 0.7);
border-radius: 8px;
flex-direction: column;
margin-bottom: 20px;
gap: 16px;
pointer-events: all;
transition: all 500ms ease;
&.nth {
flex: 1;
h3 {
font-size: 23px;
}
}
h3 {
font-size: 30px;
color: #94a3b8;
}
.form-control-header {
justify-content: space-between;
align-items: center;
}
&:hover {
transition: all 500ms ease;
&.mgreen {
border-color: #00ff66;
}
&.mblue {
border-color: #00e3fd;
}
&.mred {
border-color: #ff3366;
}
}
}
}
.separator {
width: 100%;
height: 1px;
background-color: rgb(30 41 54 / 0.8);
}
.normal-font {
font-family: "Space Grotesk";
}
.number {
font-family: "JetBrains Mono";
}
.btn-next-action {
flex: 1;
display: flex;
flex-direction: row;
justify-content: center;
align-items: center;
padding: 30px;
background-color: rgb(13 17 22 / 0.9);
border: 1px solid #1e2936;
border-radius: 16px;
margin: 20px 0;
pointer-events: all;
}
.circle-base {
width: 8px;
height: 8px;
border-radius: 50%;
}
.circle-green {
background-color: #00ff66;
}
.circle-blue {
background-color: #00e3fd;
}
.circle-red {
background-color: #ff3366;
}
}
.version-manager {
position: absolute;
top: 20px;
left: 20px;
background-color: rgba(0, 0, 0, 0.5);
p {
color: white;
font-family: "JetBrains Mono";
font-size: 26px;
}
}
}
@keyframes morning {
0% {
opacity: 0;
}
2% {
opacity: 1;
}
60% {
opacity: 1;
}
100% {
opacity: 0;
}
}
@keyframes night {
0% {
opacity: 0;
}
100% {
opacity: 1;
}
}
Game
game
global using Sandbox; global using System.Collections.Generic; global using System.Linq;
Game
game
using System.Globalization;
namespace Milaine.Utils;
public static class Pixel {
public static string Inv(float numb) => numb.ToString(CultureInfo.InvariantCulture);
}
Game
game
using System;
using System.Globalization;
namespace Milaine.Utils;
public static class Formatter {
private static readonly string[] Suffixes = ["", "k", "M", "B", "T", "Qa", "Qi"];
/// <summary>
/// format float numbers from 1000 to 1.000
/// </summary>
/// <param name="val"></param>
/// <returns></returns>
public static string ToDisplay(float val) {
string native = val.ToString("#,##0", CultureInfo.InvariantCulture);
string display = native.Replace(',', '.');
return display;
}
/// <summary>
/// format from 1000 to 1.0K
/// </summary>
/// <param name="val"></param>
/// <returns></returns>
public static string ToDisplayShort(float val) {
double absVal = Math.Abs((double)val);
if (absVal < 1000d) {
return Math.Round(val).ToString(CultureInfo.InvariantCulture);
}
int magnitude = (int)Math.Log(absVal, 1000d);
magnitude = Math.Min(magnitude, Suffixes.Length - 1);
double scaled = val / Math.Pow(1000d, magnitude);
if (Math.Round(scaled, 1) >= 1000d && magnitude < Suffixes.Length - 1) {
magnitude++;
scaled = val / Math.Pow(1000d, magnitude);
}
string number = scaled.ToString("0.0", CultureInfo.InvariantCulture);
return $"{number}{Suffixes[magnitude]}";
}
}
Debug: View Raw JSON Response
{
"TotalCount": 38,
"Files": [
{
"Ident": "rakunsoftware.milaine",
"Path": "Scripts/Managers/GameManager.cs",
"FileName": "GameManager.cs",
"PackageType": "game",
"CodeKind": "Game",
"AssetVersionId": 394495,
"IsPrivate": false,
"Code": "using System;\r\nusing Milaine.TreeSkills;\r\n\r\nnamespace Milaine.Managers;\r\n\r\npublic sealed class GameManager : Component {\r\n [Property, Title(\"IdleManager\")]\r\n [Feature(\"General\")]\r\n public IdleManager IdleManagerInstance { get; set; }\r\n\r\n [Property, Title(\"InvestmentManager\")]\r\n [Feature(\"General\")]\r\n public InvestmentManager InvestmentManagerInstance { get; set; }\r\n\r\n [Property, Title(\"SkillTreeBootstrap\")]\r\n [Feature(\"General\")]\r\n public SkillTreeBootstrap SkillTreeBootstrapInstance { get; set; }\r\n\r\n [Property, Title(\"DayNightManager\")]\r\n [Feature(\"General\")]\r\n public DayNightManager DayNightManagerInstance { get; set; }\r\n\r\n public Action OnLooseGame { get; set; }\r\n public Action OnWinGame { get; set; }\r\n\r\n private List<SkillNodeData> skillsUsed = [];\r\n private int maxSkillPoints = 0;\r\n private int skillPoints = 0;\r\n private bool isPlaying = true;\r\n private bool isGameWin = false;\r\n\r\n public bool IsGameWin {\r\n get => isGameWin;\r\n }\r\n\r\n protected override void OnAwake() {\r\n TreeSkillState.Instance.OnUnlocked += OnUnlocked;\r\n TreeSkillState.Instance.SpendPoint += OnSpendPoint;\r\n TreeSkillState.Instance.GetSkillPoints = GetSkillPoints;\r\n DayNightManagerInstance.OnEndDay += OnEndDay;\r\n InvestmentManagerInstance.OnChange += OnInvestmentManagerChange;\r\n }\r\n\r\n protected override void OnDestroy() {\r\n TreeSkillState.Instance.OnUnlocked -= OnUnlocked;\r\n TreeSkillState.Instance.SpendPoint -= OnSpendPoint;\r\n DayNightManagerInstance.OnEndDay -= OnEndDay;\r\n InvestmentManagerInstance.OnChange -= OnInvestmentManagerChange;\r\n }\r\n\r\n private void OnEndDay() {\r\n if (DayNightManagerInstance.Day < 5) {\r\n return;\r\n }\r\n\r\n isPlaying = false;\r\n isGameWin = false;\r\n OnLooseGame?.Invoke();\r\n }\r\n\r\n private void OnInvestmentManagerChange(Portfolio portfolio) {\r\n if (!isPlaying) {\r\n return;\r\n }\r\n\r\n int total = (int)portfolio.investment;\r\n int goal = IdleManagerInstance.Goal;\r\n\r\n if (total >= goal) {\r\n isPlaying = false;\r\n isGameWin = true;\r\n DayNightManagerInstance.ResetManager();\r\n OnWinGame?.Invoke();\r\n }\r\n }\r\n\r\n private void OnUnlocked(SkillNodeData node) {\r\n if (skillsUsed.Contains(node)) {\r\n return;\r\n }\r\n\r\n skillsUsed.Add(node);\r\n\r\n switch (node.Category) {\r\n case SkillCategory.Dollars:\r\n IdleManagerInstance.ImprovePoint(node.Point);\r\n break;\r\n case SkillCategory.DollarAutomatic:\r\n IdleManagerInstance.ImprovePasiveDollar(node.Point);\r\n break;\r\n case SkillCategory.Wallet:\r\n InvestmentManagerInstance.ImproveWallet(node.Point);\r\n break;\r\n case SkillCategory.Investment:\r\n InvestmentManagerInstance.ImprovePerformance(node.Point);\r\n break;\r\n case SkillCategory.Dividends:\r\n InvestmentManagerInstance.ImproveDividends(node.Point);\r\n break;\r\n case SkillCategory.WalletPlus:\r\n InvestmentManagerInstance.ImproveDeposit(node.Point);\r\n break;\r\n }\r\n }\r\n\r\n private int GetSkillPoints() => skillPoints;\r\n\r\n private void OnSpendPoint() {\r\n skillPoints--;\r\n }\r\n\r\n public void Restart() {\r\n DayNightManagerInstance.Restart();\r\n TreeSkillState.Instance.Restart();\r\n skillsUsed = [];\r\n maxSkillPoints += 1;\r\n skillPoints += maxSkillPoints;\r\n\r\n IdleManagerInstance.Restart();\r\n InvestmentManagerInstance.Restart();\r\n }\r\n}\r\n"
},
{
"Ident": "rakunsoftware.milaine",
"Path": "Scripts/Managers/MouseManager.cs",
"FileName": "MouseManager.cs",
"PackageType": "game",
"CodeKind": "Game",
"AssetVersionId": 394495,
"IsPrivate": false,
"Code": "namespace Milaine.Managers;\r\n\r\npublic enum StateMouse {\r\n Relased,\r\n Busy\r\n}\r\n\r\npublic static class MouseManager {\r\n public static StateMouse State { get; set; } = StateMouse.Relased;\r\n\r\n public static void ShowMouse() {\r\n Mouse.Visibility = MouseVisibility.Visible;\r\n }\r\n\r\n public static void HideMouse() {\r\n Mouse.Visibility = MouseVisibility.Hidden;\r\n }\r\n}\r\n"
},
{
"Ident": "rakunsoftware.milaine",
"Path": "Scripts/Managers/DayNightManager.cs",
"FileName": "DayNightManager.cs",
"PackageType": "game",
"CodeKind": "Game",
"AssetVersionId": 394495,
"IsPrivate": false,
"Code": "using System;\r\nusing Milaine.Interfaces;\r\n\r\nnamespace Milaine.Managers;\r\n\r\npublic sealed class DayNightManager : Component, IManager {\r\n // 60 -> seconds\r\n private const int MINUTE = 60;\r\n // 5 mins\r\n private const int MAX_TIME = 5 * MINUTE;\r\n public const int MAX_DAYS = 5;\r\n\r\n [Property]\r\n public float DayDuration { get; set; } = MAX_TIME;\r\n\r\n [Property]\r\n public int Day { get; set; } = 1;\r\n\r\n // hour in 24h\r\n private readonly float startHour = 8f;\r\n private readonly float endHour = 18f;\r\n\r\n private bool isDayActive = false;\r\n private TimeUntil timeUntilNight;\r\n\r\n public string CurrentTimeString { get; private set; } = \"8:00 AM\";\r\n\r\n public Action OnStartDay;\r\n public Action OnEndDay;\r\n\r\n protected override void OnStart() {\r\n StartDay();\r\n }\r\n\r\n protected override void OnUpdate() {\r\n if (!isDayActive) {\r\n return;\r\n }\r\n\r\n float elapsedSeconds = DayDuration - timeUntilNight;\r\n float progress = MathX.Clamp(elapsedSeconds / DayDuration, 0f, 1f);\r\n float totalVirtualHours = endHour - startHour;\r\n float currentVirtualHour = startHour + (progress * totalVirtualHours);\r\n\r\n int hours = (int)MathF.Floor(currentVirtualHour);\r\n int minutes = (int)MathF.Floor((currentVirtualHour - hours) * 60f);\r\n\r\n string amPm = hours >= 12 ? \"PM\" : \"AM\";\r\n int displayHour = hours % 12;\r\n\r\n if (displayHour == 0) {\r\n displayHour = 12;\r\n }\r\n\r\n CurrentTimeString = $\"{displayHour:D2}:{minutes:D2} {amPm}\";\r\n\r\n if (timeUntilNight) {\r\n EndDay();\r\n }\r\n }\r\n\r\n private void StartDay() {\r\n if (isDayActive) {\r\n return;\r\n }\r\n\r\n timeUntilNight = DayDuration;\r\n isDayActive = true;\r\n\r\n OnStartDay?.Invoke();\r\n }\r\n\r\n private void EndDay() {\r\n ResetManager(deep: false);\r\n OnEndDay?.Invoke();\r\n }\r\n\r\n public void ResetManager(bool deep = false) {\r\n if (deep) {\r\n CurrentTimeString = \"8:00 AM\";\r\n }\r\n\r\n isDayActive = false;\r\n }\r\n\r\n public void NextDay() {\r\n if (Day >= MAX_DAYS) {\r\n return;\r\n }\r\n\r\n Day += 1;\r\n StartDay();\r\n }\r\n\r\n public void Restart() {\r\n Day = 1;\r\n StartDay();\r\n }\r\n}\r\n"
},
{
"Ident": "rakunsoftware.milaine",
"Path": "Scripts/Room/ClickableButton.cs",
"FileName": "ClickableButton.cs",
"PackageType": "game",
"CodeKind": "Game",
"AssetVersionId": 394495,
"IsPrivate": false,
"Code": "using System;\r\nusing Milaine.Managers;\r\n\r\nnamespace Milaine.Room;\r\n\r\npublic sealed class ClickableButton : Component {\r\n [Property, Group(\"References\")]\r\n public SkinnedModelRenderer Model { get; set; }\r\n\r\n [Property, Group(\"Animation\"), Title(\"Sequence Name\")]\r\n public string PressSequence { get; set; } = \"press\";\r\n\r\n [Property, Group(\"Animation\")]\r\n public bool UsesAnimGraph { get; set; } = false;\r\n\r\n [Property, Group(\"Interaction\")]\r\n public float MaxClickDistance { get; set; } = 1000f;\r\n\r\n [Property, Group(\"Squish (Scale Z)\"), Range(0.1f, 1f)]\r\n public float PressedScale { get; set; } = 0.8f;\r\n\r\n [Property, Group(\"Squish (Scale Z)\"), Range(1f, 30f)]\r\n public float ScaleSpeed { get; set; } = 14f;\r\n\r\n public Action OnPressed { get; set; }\r\n\r\n private bool isHeld;\r\n private Vector3 originalScale;\r\n private float currentScaleFactor = 1f;\r\n\r\n protected override void OnStart() {\r\n if (!Model.IsValid()) {\r\n Model = Components.Get<SkinnedModelRenderer>();\r\n }\r\n\r\n originalScale = LocalScale;\r\n }\r\n\r\n protected override void OnUpdate() {\r\n if (MouseManager.State == StateMouse.Busy) {\r\n return;\r\n }\r\n\r\n var camera = Scene.Camera;\r\n\r\n if (!camera.IsValid()) {\r\n return;\r\n }\r\n\r\n var ray = camera.ScreenPixelToRay(Mouse.Position);\r\n var trace = Scene.Trace.Ray(ray, MaxClickDistance).Run();\r\n bool isHoveredNow = trace.Hit && trace.GameObject == GameObject;\r\n\r\n if ((Input.Pressed(\"attack1\") || Input.Pressed(\"attack2\")) && isHoveredNow) {\r\n Press();\r\n isHeld = true;\r\n }\r\n\r\n if (Input.Released(\"attack1\") || Input.Released(\"attack2\")) {\r\n isHeld = false;\r\n }\r\n\r\n float targetFactor = isHeld ? PressedScale : 1f;\r\n currentScaleFactor = MathX.Lerp(currentScaleFactor, targetFactor, Time.Delta * ScaleSpeed);\r\n\r\n LocalScale = new Vector3(originalScale.x, originalScale.y, originalScale.z * currentScaleFactor);\r\n }\r\n\r\n public void Press() {\r\n PlayPressAnimation();\r\n Sound.Play(\"sounds/sound_key_down.sound\");\r\n OnPressed?.Invoke();\r\n }\r\n\r\n private void PlayPressAnimation() {\r\n if (!Model.IsValid()) {\r\n return;\r\n }\r\n\r\n if (UsesAnimGraph) {\r\n Model.Set(PressSequence, true);\r\n } else {\r\n Model.SceneModel.UseAnimGraph = false;\r\n Model.SceneModel.CurrentSequence.Name = PressSequence;\r\n }\r\n }\r\n}\r\n"
},
{
"Ident": "rakunsoftware.milaine",
"Path": "Scripts/Room/RoomManager.cs",
"FileName": "RoomManager.cs",
"PackageType": "game",
"CodeKind": "Game",
"AssetVersionId": 394495,
"IsPrivate": false,
"Code": "namespace Milaine.Room;\r\n\r\npublic sealed class RoomManager : Component {\r\n [Property]\r\n public List<GameObject> Models { get; set; } = [];\r\n\r\n private List<GameObject> ChairChildren = [];\r\n\r\n protected override void OnAwake() {\r\n if (Models.Count == 0) {\r\n Log.Warning(\"Models list is empty\");\r\n return;\r\n }\r\n\r\n foreach (GameObject gameObject in Models) {\r\n if (!gameObject.IsValid()) {\r\n continue;\r\n }\r\n\r\n Prop prop = gameObject.GetComponent<Prop>();\r\n\r\n if (!prop.IsValid()) {\r\n continue;\r\n }\r\n\r\n prop.IsStatic = true;\r\n\r\n if (gameObject.Name == \"office_chair\") {\r\n gameObject.GetComponent<ModelRenderer>().Destroy();\r\n gameObject.GetComponent<ModelPhysics>().Destroy();\r\n\r\n foreach (GameObject obj in gameObject.Children) {\r\n ChairChildren.Add(obj);\r\n }\r\n }\r\n }\r\n\r\n }\r\n\r\n protected override void OnUpdate() {\r\n if (ChairChildren.Count == 0) {\r\n return;\r\n }\r\n\r\n foreach (GameObject gameObject in ChairChildren) {\r\n gameObject.Destroy();\r\n }\r\n\r\n ChairChildren = [];\r\n }\r\n}\r\n"
},
{
"Ident": "rakunsoftware.milaine",
"Path": "Scripts/Settings/Configuration.cs",
"FileName": "Configuration.cs",
"PackageType": "game",
"CodeKind": "Game",
"AssetVersionId": 394495,
"IsPrivate": false,
"Code": "using System;\r\n\r\nnamespace Milaine.Settings;\r\n\r\npublic class ConfigurationData {\r\n public string Language { get; set; } = \"en\";\r\n}\r\n\r\npublic sealed class Configuration : Component {\r\n private readonly string filename = \"settings.cfg\";\r\n\r\n [Property]\r\n public string Language { get; set; } = \"en\";\r\n\r\n protected override void OnAwake() {\r\n if (!FileSystem.Data.FileExists(filename)) {\r\n SaveConfig();\r\n\r\n return;\r\n }\r\n\r\n LoadConfig();\r\n }\r\n\r\n public void LoadConfig() {\r\n var config = FileSystem.Data.ReadJson<ConfigurationData>(filename);\r\n Language = config.Language;\r\n }\r\n\r\n public void SaveConfig() {\r\n try {\r\n var config = new ConfigurationData { Language = Language };\r\n FileSystem.Data.WriteJson(filename, config);\r\n }\r\n catch (Exception ex) {\r\n Log.Warning($\"Error to try create configuration file: {ex.Message}\");\r\n }\r\n }\r\n}\r\n"
},
{
"Ident": "rakunsoftware.milaine",
"Path": "UI/FloatingTextManager/FloatingTextManager.razor",
"FileName": "FloatingTextManager.razor",
"PackageType": "game",
"CodeKind": "Game",
"AssetVersionId": 394495,
"IsPrivate": false,
"Code": "@using Sandbox;\r\n@using Sandbox.UI;\r\n@namespace Milaine.UI\r\n@inherits Panel\r\n\r\n<root></root>\r\n\r\n@code {\r\n public static FloatingTextManager Instance { get; set; }\r\n\r\n public FloatingTextManager()\r\n {\r\n Instance = this;\r\n }\r\n\r\n public override void OnDeleted()\r\n {\r\n base.OnDeleted();\r\n\r\n if (Instance == this)\r\n {\r\n Instance = null;\r\n }\r\n }\r\n\r\n public void Spawn(string text, float screenX, float screenY)\r\n {\r\n var floatingText = AddChild<FloatingText>();\r\n floatingText.Text = text;\r\n floatingText.SpawnX = screenX;\r\n floatingText.SpawnY = screenY;\r\n }\r\n}\r\n\r\n<style>\r\n FloatingTextManager {\r\n position: absolute;\r\n top: 0;\r\n left: 0;\r\n width: 100%;\r\n height: 100%;\r\n pointer-events: none;\r\n }\r\n</style>\r\n"
},
{
"Ident": "rakunsoftware.milaine",
"Path": "Scripts/Utils/Outliner.cs",
"FileName": "Outliner.cs",
"PackageType": "game",
"CodeKind": "Game",
"AssetVersionId": 394495,
"IsPrivate": false,
"Code": "namespace Milaine.Utils;\r\n\r\npublic sealed class Outliner : Component {\r\n [Property, Group(\"Interaction\")]\r\n public float MaxClickDistance { get; set; } = 1000f;\r\n\r\n [Property, Group(\"Outline\"), Title(\"Color Hover\")]\r\n public Color HoverOutlineColor { get; set; } = Color.White;\r\n\r\n [Property, Group(\"Outline\"), Range(0.1f, 10f)]\r\n public float OutlineWidth { get; set; } = 0.5f;\r\n\r\n private HighlightOutline outline;\r\n\r\n protected override void OnAwake() {\r\n }\r\n\r\n protected override void OnStart() {\r\n outline = GameObject.GetOrAddComponent<HighlightOutline>();\r\n outline.Color = Color.Transparent;\r\n outline.Width = OutlineWidth;\r\n }\r\n\r\n protected override void OnUpdate() {\r\n var camera = Scene.Camera;\r\n\r\n if (!camera.IsValid()) {\r\n return;\r\n }\r\n\r\n var ray = camera.ScreenPixelToRay(Mouse.Position);\r\n var trace = Scene.Trace.Ray(ray, MaxClickDistance).Run();\r\n\r\n bool isHoveredNow = trace.Hit && trace.GameObject == GameObject;\r\n\r\n if (outline.IsValid()) {\r\n outline.Color = isHoveredNow ? HoverOutlineColor : Color.Transparent;\r\n }\r\n }\r\n}\r\n"
},
{
"Ident": "rakunsoftware.milaine",
"Path": "UI/Hud/Hud.razor",
"FileName": "Hud.razor",
"PackageType": "game",
"CodeKind": "Game",
"AssetVersionId": 394495,
"IsPrivate": false,
"Code": "@using System.Threading.Tasks;\r\n@using Milaine.Managers;\r\n@using Milaine.Settings;\r\n@using Milaine.UI;\r\n@using Milaine.Utils;\r\n@using Sandbox;\r\n@using Sandbox.UI;\r\n@inherits PanelComponent\r\n@namespace Sandbox\r\n\r\n<root>\r\n <header class=\"header\">\r\n <section class=\"day-manager\">\r\n <h2>\r\n @TranslationsInstance.T(\"milaine.days\", data)\r\n @* @Language.GetPhrase(\"milaine.days\", data) *@\r\n </h2>\r\n </section>\r\n <section class=\"clock\">\r\n <p>@DayNightManagerInstance.CurrentTimeString</p>\r\n </section>\r\n </header>\r\n <section class=\"progress-end-game\">\r\n <div class=\"progress-bar\">\r\n <div class=\"bar\" style=\"width: @(GetPercentage())%;\" />\r\n <p>@Formatter.ToDisplay(InvestmentManagerInstance.Total) / @Formatter.ToDisplay(IdleManagerInstance.Goal)</p>\r\n </div>\r\n </section>\r\n <button class=\"slot\" style=\"pointer-events: @(!isPanelOpened ? \"all\" : \"none\");\" onclick=@TogglePanel>\r\n <p class=\"kbd\">E</p>\r\n <p class=\"title\">\r\n @TranslationsInstance.T(\"milaine.tree-skills\")\r\n @* #milaine.tree-skills *@\r\n </p>\r\n </button>\r\n <div class=\"container\">\r\n <section class=\"content\">\r\n <Image src=\"resources/wallet-minimal.png\" class=\"image\" style=\"width: 40px; height: 40px;\" />\r\n <p class=\"headline\">[email protected](Dollars)</p>\r\n <FloatingTextManager />\r\n </section>\r\n </div>\r\n @if (isInitializedDay) {\r\n <div class=\"day-container\">\r\n <h2 class=\"heading-current-day\">\r\n @* @Language.GetPhrase(\"milaine.days\", data) *@\r\n @TranslationsInstance.T(\"milaine.days\", data)\r\n </h2>\r\n </div>\r\n }\r\n @if (isGameWin) {\r\n <div\r\n style=\"background-color: black; position: absolute; top: 0; left: 0; right: 0; bottom: 0; justify-content: center; align-items: center;\">\r\n <div style=\"width: 30%;justify-content:center;align-items:center;\">\r\n <p style=\"font-size: 40px; font-family: 'JetBrains Mono';\">\r\n @* #milaine.wingame *@\r\n @TranslationsInstance.T(\"milaine.wingame\")\r\n </p>\r\n </div>\r\n </div>\r\n }\r\n\r\n @if (isDayEnd && !isGameWin) {\r\n <div class=\"day-container night\">\r\n <div class=\"summary-container\">\r\n <header class=\"summary-header\">\r\n <div class=\"summary-title\">\r\n <span class=\"circle\" />\r\n <h2 class=\"normal-font\">\r\n @* #milaine.summary.title *@\r\n @TranslationsInstance.T(\"milaine.summary.title\")\r\n </h2>\r\n </div>\r\n <div class=\"separator\" />\r\n </header>\r\n <div class=\"row\">\r\n <div class=\"form-control nth mblue\">\r\n <div class=\"form-control-header\">\r\n <h3 class=\"normal-font\">\r\n @* #milaine.summary.investment *@\r\n @TranslationsInstance.T(\"milaine.summary.investment\")\r\n </h3>\r\n <span class=\"circle-base circle-blue\" />\r\n </div>\r\n <p class=\"number\">\r\n [email protected](InvestmentManagerInstance.Profit)\r\n </p>\r\n </div>\r\n <div class=\"form-control nth mgreen\">\r\n <div class=\"form-control-header\">\r\n <h3 class=\"normal-font\">\r\n @* #milaine.summary.wallet *@\r\n @TranslationsInstance.T(\"milaine.summary.wallet\")\r\n </h3>\r\n <span class=\"circle-base circle-green\" />\r\n </div>\r\n <p class=\"number\">\r\n [email protected](InvestmentManagerInstance.WalletPasive)\r\n </p>\r\n </div>\r\n <div class=\"form-control nth mred\">\r\n <div class=\"form-control-header\">\r\n <h3 class=\"normal-font\">\r\n @* #milaine.summary.dollar-spent *@\r\n @TranslationsInstance.T(\"milaine.summary.dollar-spent\")\r\n </h3>\r\n <span class=\"circle-base circle-red\" />\r\n </div>\r\n <p class=\"number\">\r\n [email protected](IdleManagerInstance.DollarsSpent)\r\n </p>\r\n </div>\r\n </div>\r\n <div class=\"separator\" />\r\n\r\n @if (DayNightManagerInstance.Day == DayNightManager.MAX_DAYS) {\r\n <button class=\"btn-next-action normal-font\" onclick=@HandleAgain>\r\n @* #milaine.back-to-past *@\r\n @TranslationsInstance.T(\"milaine.back-to-past\")\r\n </button>\r\n } else {\r\n <button class=\"btn-next-action normal-font\" onclick=@HandleNextDay>\r\n @* #milaine.next-day *@\r\n @TranslationsInstance.T(\"milaine.next-day\")\r\n </button>\r\n }\r\n </div>\r\n </div>\r\n }\r\n <div class=\"version-manager\">\r\n <p>@(\"v\" + VersionManagerInstance.Version.ToString())</p>\r\n </div>\r\n</root>\r\n\r\n@code\r\n{\r\n private const float ANIMATION_DURATION = 5f;\r\n\r\n [Property, Title(\"Translations\")]\r\n [Feature(\"Managers\")]\r\n public Translations TranslationsInstance { get; set; }\r\n\r\n [Property, Title(\"VersionManager\")]\r\n [Feature(\"Managers\")]\r\n public VersionManager VersionManagerInstance { get; set; }\r\n\r\n [Property, Title(\"IdleManager\")]\r\n [Feature(\"Managers\")]\r\n public IdleManager IdleManagerInstance { get; set; }\r\n\r\n [Property, Title(\"InvestmentManager\")]\r\n [Feature(\"Managers\")]\r\n public InvestmentManager InvestmentManagerInstance { get; set; }\r\n\r\n [Property, Title(\"DayNightManager\")]\r\n [Feature(\"Managers\")]\r\n public DayNightManager DayNightManagerInstance { get; set; }\r\n\r\n [Property, Title(\"GameManager\")]\r\n [Feature(\"Managers\")]\r\n public GameManager GameManagerInstance { get; set; }\r\n\r\n [Property, Title(\"TreeSkillPanel\")]\r\n [Feature(\"General\")]\r\n public TreeSkillPanel TreeSkillPanelInstance { get; set; }\r\n\r\n [Property]\r\n [Feature(\"General\")]\r\n public int Dollars { get; set; } = 0;\r\n\r\n private bool isPanelOpened = false;\r\n\r\n private Dictionary<string, object> data = [];\r\n\r\n private bool isInitializedDay = false;\r\n private bool isDayEnd = false;\r\n\r\n private bool isGameWin = false;\r\n\r\n protected override int BuildHash() => System.HashCode.Combine(Dollars,\r\nDayNightManagerInstance.CurrentTimeString, DayNightManagerInstance.Day, InvestmentManagerInstance.Total\r\n, IdleManagerInstance.DollarsSpent, InvestmentManagerInstance.WalletPasive, InvestmentManagerInstance.Profit);\r\n\r\n protected override void OnAwake() {\r\n base.OnStart();\r\n\r\n data[\"Day\"] = DayNightManagerInstance.Day;\r\n IdleManagerInstance.OnDeposit += RefreshDeposit;\r\n IdleManagerInstance.OnChange += Refresh;\r\n DayNightManagerInstance.OnStartDay += StartDay;\r\n DayNightManagerInstance.OnEndDay += EndDay;\r\n GameManagerInstance.OnWinGame += OnWinGame;\r\n }\r\n\r\n protected override void OnUpdate() {\r\n if (Input.Pressed(\"use\")) {\r\n TogglePanel();\r\n return;\r\n }\r\n\r\n if (Input.EscapePressed) {\r\n isPanelOpened = false;\r\n StateHasChanged();\r\n TreeSkillPanelInstance.Close();\r\n }\r\n }\r\n\r\n protected override void OnDestroy() {\r\n base.OnDestroy();\r\n\r\n IdleManagerInstance.OnDeposit -= RefreshDeposit;\r\n IdleManagerInstance.OnChange -= Refresh;\r\n DayNightManagerInstance.OnStartDay -= StartDay;\r\n DayNightManagerInstance.OnEndDay -= EndDay;\r\n GameManagerInstance.OnWinGame -= OnWinGame;\r\n\r\n }\r\n\r\n private void OnWinGame() {\r\n isGameWin = GameManagerInstance.IsGameWin;\r\n }\r\n\r\n private void TogglePanel() {\r\n isPanelOpened = !isPanelOpened;\r\n StateHasChanged();\r\n\r\n Panel.Blur();\r\n\r\n if (isPanelOpened) {\r\n TreeSkillPanelInstance.Open();\r\n return;\r\n }\r\n\r\n TreeSkillPanelInstance.Close();\r\n }\r\n\r\n private string GetPercentage() {\r\n float Total = InvestmentManagerInstance.Total;\r\n float percentage = (Total / IdleManagerInstance.Goal) * 100;\r\n\r\n return Pixel.Inv(percentage);\r\n }\r\n\r\n private void StartDay() {\r\n isInitializedDay = true;\r\n StateHasChanged();\r\n\r\n _ = HideAafterDelay();\r\n }\r\n\r\n private void EndDay() {\r\n isDayEnd = true;\r\n StateHasChanged();\r\n }\r\n\r\n private void HandleNextDay() {\r\n isDayEnd = false;\r\n DayNightManagerInstance.NextDay();\r\n data[\"Day\"] = DayNightManagerInstance.Day;\r\n StateHasChanged();\r\n StartDay();\r\n }\r\n\r\n private async Task HideAafterDelay() {\r\n await Task.DelaySeconds(ANIMATION_DURATION);\r\n isInitializedDay = false;\r\n StateHasChanged();\r\n }\r\n\r\n private void Refresh(int dollars, int amount) {\r\n Dollars = dollars;\r\n FloatingTextManager.Instance.Spawn($\"+{amount}\", 25f, 10f);\r\n }\r\n\r\n private void RefreshDeposit() {\r\n Dollars = 0;\r\n }\r\n\r\n private void HandleAgain() {\r\n GameManagerInstance.Restart();\r\n }\r\n}\r\n"
},
{
"Ident": "rakunsoftware.milaine",
"Path": "UI/PauseGamePanel/PauseGamePanel.razor",
"FileName": "PauseGamePanel.razor",
"PackageType": "game",
"CodeKind": "Game",
"AssetVersionId": 394495,
"IsPrivate": false,
"Code": "@using Milaine.Managers;\r\n@using Milaine.Settings;\r\n@using Sandbox;\r\n@using Sandbox.UI;\r\n@inherits PanelComponent\r\n@namespace Sandbox\r\n\r\n<root>\r\n @if (PauseGameInstance.IsOpened) {\r\n <div class=\"pause-container\">\r\n <header class=\"header\">\r\n <DropDown Options=@ModeOptions Value=@SelectedMode ValueChanged=@OnOptionChanged />\r\n </header>\r\n <main>\r\n <div class=\"container\">\r\n <button [email protected]>\r\n @TranslationsInstance.T(\"milaine.back\")\r\n </button>\r\n <button onclick=@ExitGame>\r\n @TranslationsInstance.T(\"milaine.quit\")\r\n </button>\r\n </div>\r\n\r\n <div class=\"credits\">\r\n <p>Credits</p>\r\n <p>\r\n Computer Keyboard by Luke (https://sbox.game/luke/office_keyboard)\r\n </p>\r\n <p>\r\n Computer Monitor by Luke (https://sbox.game/luke/monitor_basic)\r\n </p>\r\n <p>\r\n Computer Mouse by Luke (https://sbox.game/luke/computer_mouse)\r\n </p>\r\n <p>\r\n Coffee_cup_01 by Small Box Studio (https://sbox.game/smallboxstudio/coffeecup01)\r\n </p>\r\n <p>\r\n French_fries_02 by Small Box Studio (https://sbox.game/smallboxstudio/frenchfries02)\r\n </p>\r\n <p>\r\n French_fries_02_empty by Small Box Studio (https://sbox.game/smallboxstudio/frenchfries02empty)\r\n </p>\r\n <p>\r\n Stir_fried_noodles_01 by Small Box Studio (https://sbox.game/smallboxstudio/stirfriednoodles01)\r\n </p>\r\n <p>\r\n Stir_fried_noodles_01_close by Small Box Studio (https://sbox.game/smallboxstudio/stirfriednoodles01close)\r\n </p>\r\n </div>>\r\n </main>\r\n </div>\r\n <div class=\"version-manager\">\r\n <p>@(\"v\" + VersionManagerInstance.Version.ToString())</p>\r\n </div>\r\n }\r\n\r\n</root>\r\n\r\n@code\r\n{\r\n [Property, Title(\"Translations\")]\r\n [Feature(\"Managers\")]\r\n public Translations TranslationsInstance { get; set; }\r\n\r\n [Property, Title(\"VersionManager\")]\r\n [Feature(\"Managers\")]\r\n public VersionManager VersionManagerInstance { get; set; }\r\n\r\n [Property]\r\n [Feature(\"Settings\")]\r\n public PauseGame PauseGameInstance { get; set; }\r\n\r\n public string SelectedMode { get; set; } = \"en\";\r\n\r\n public List<UI.Option> ModeOptions { get; set; } = [\r\n new Option{Title = \"English\", Value = \"en\"},\r\n new Option{Title = \"Espa\u00f1ol\", Value = \"es\"},\r\n ];\r\n\r\n protected override int BuildHash() => System.HashCode.Combine(PauseGameInstance.IsOpened, SelectedMode);\r\n\r\n protected override void OnStart() {\r\n base.OnStart();\r\n SelectedMode = TranslationsInstance.language;\r\n }\r\n\r\n private void ExitGame() {\r\n if (Application.IsStandalone) {\r\n Game.Close();\r\n return;\r\n }\r\n\r\n Game.Disconnect();\r\n }\r\n\r\n private void OnOptionChanged(object code) {\r\n SelectedMode = (string)code;\r\n TranslationsInstance.SetLanguage((string)code);\r\n StateHasChanged();\r\n }\r\n}\r\n"
},
{
"Ident": "rakunsoftware.milaine",
"Path": "Scripts/Managers/DialoguesManager.cs",
"FileName": "DialoguesManager.cs",
"PackageType": "game",
"CodeKind": "Game",
"AssetVersionId": 394495,
"IsPrivate": false,
"Code": "namespace Milaine.Managers;\r\n\r\n\r\npublic sealed class DialoguesManager : Component {\r\n [Property, Title(\"Dialogues View\")]\r\n public PanelComponent DialoguesView { get; set; }\r\n\r\n private List<Step> steps = [];\r\n\r\n private class Step { }\r\n\r\n protected override void OnStart() {\r\n if (!DialoguesView.IsValid()) {\r\n Log.Warning(\"Need Instances of [DialoguesView]\");\r\n }\r\n }\r\n}\r\n"
},
{
"Ident": "rakunsoftware.milaine",
"Path": "Scripts/TreeSkills/SkillNodeData.cs",
"FileName": "SkillNodeData.cs",
"PackageType": "game",
"CodeKind": "Game",
"AssetVersionId": 394495,
"IsPrivate": false,
"Code": "namespace Milaine.TreeSkills;\r\n\r\npublic enum SkillCategory {\r\n Dollars,\r\n Wallet,\r\n Investment,\r\n Dividends,\r\n WalletPlus,\r\n DollarAutomatic\r\n}\r\n\r\npublic class SkillNodeData {\r\n public string Id { get; set; }\r\n public string Name { get; set; }\r\n public string Description { get; set; }\r\n public string KeyDescription { get; set; }\r\n public int Cost { get; set; }\r\n public SkillCategory Category { get; set; }\r\n public float Point { get; set; }\r\n\r\n public int Row { get; set; }\r\n public int Column { get; set; }\r\n\r\n public string Icon { get; set; } = \"\ud83c\udf15\";\r\n\r\n public bool IsRoot { get; set; }\r\n}\r\n"
},
{
"Ident": "rakunsoftware.milaine",
"Path": "Scripts/Constants/VersionConstants.cs",
"FileName": "VersionConstants.cs",
"PackageType": "game",
"CodeKind": "Game",
"AssetVersionId": 394495,
"IsPrivate": false,
"Code": "namespace Milaine.Constants;\r\n\r\npublic class VersionConstants {\r\n public const int MAYOR = 0;\r\n public const int MINOR = 9;\r\n public const int PATCH = 1;\r\n}\r\n"
},
{
"Ident": "rakunsoftware.milaine",
"Path": "Scripts/Managers/InvestmentManager.cs",
"FileName": "InvestmentManager.cs",
"PackageType": "game",
"CodeKind": "Game",
"AssetVersionId": 394495,
"IsPrivate": false,
"Code": "using System;\r\nusing Milaine.Interfaces;\r\n\r\nnamespace Milaine.Managers;\r\n\r\npublic struct Portfolio(int wallet = 0, float investment = 0, float profit = 0, int shares = 0) {\r\n public int wallet = wallet;\r\n public float investment = investment;\r\n public float profit = profit;\r\n public int shares = shares;\r\n}\r\n\r\npublic sealed class InvestmentManager : Component, IManager {\r\n public const float DEFAULT_PERFORMANCE = 1.0f;\r\n\r\n [Property, Title(\"DayNightManager\")]\r\n [Feature(\"Managers\")]\r\n public DayNightManager DayNightManagerInstance { get; set; }\r\n\r\n [Property]\r\n [Feature(\"General\")]\r\n public bool IsDayEnded { get; set; } = false;\r\n\r\n [Property]\r\n [Feature(\"General\"), Group(\"Digital\")]\r\n public int Wallet { get; set; } = 0;\r\n\r\n [Property]\r\n [Feature(\"General\"), Group(\"Digital\")]\r\n public float Investment { get; set; } = 0;\r\n\r\n [Property]\r\n [Feature(\"General\"), Group(\"Digital\")]\r\n public float Profit { get; set; } = 0;\r\n\r\n [Property]\r\n [Feature(\"General\"), Group(\"Digital\")]\r\n public int Shares { get; set; } = 0;\r\n\r\n public Action<Portfolio> OnChange { get; set; }\r\n\r\n private float performance = DEFAULT_PERFORMANCE;\r\n private float acc = 0f;\r\n private float multiplierDeposit = 1.0f;\r\n private bool isAvailablePerformanceWallet = false;\r\n private int performanceWallet = (int)DEFAULT_PERFORMANCE;\r\n\r\n private float accDividends = 0f;\r\n private bool isActivatedDividends = false;\r\n private float multiplierDividends = 0.0f;\r\n\r\n private int walletPasive = 0;\r\n\r\n public float Total {\r\n get => Wallet + Investment;\r\n }\r\n\r\n\r\n public int WalletPasive {\r\n get => walletPasive;\r\n }\r\n\r\n protected override void OnStart() {\r\n DayNightManagerInstance.OnStartDay += DayStartSubscription;\r\n DayNightManagerInstance.OnEndDay += DayNightSubscription;\r\n }\r\n\r\n protected override void OnDestroy() {\r\n DayNightManagerInstance.OnStartDay -= DayStartSubscription;\r\n DayNightManagerInstance.OnEndDay -= DayNightSubscription;\r\n }\r\n\r\n protected override void OnUpdate() {\r\n if (IsDayEnded) {\r\n return;\r\n }\r\n\r\n acc += Time.Delta;\r\n\r\n if (acc >= 1.0f) {\r\n if (Investment != 0f) {\r\n Profit += performance;\r\n Investment += performance;\r\n }\r\n\r\n if (isAvailablePerformanceWallet) {\r\n Wallet += performanceWallet;\r\n walletPasive += performanceWallet;\r\n }\r\n\r\n\r\n acc = 0;\r\n }\r\n\r\n accDividends += Time.Delta;\r\n\r\n if (accDividends >= 5.0f && isActivatedDividends) {\r\n Wallet += (Investment * multiplierDividends).CeilToInt();\r\n accDividends = 0;\r\n }\r\n }\r\n\r\n public void Deposit(int dollars) {\r\n Wallet += (multiplierDeposit * dollars).CeilToInt();\r\n OnChange?.Invoke(new Portfolio { wallet = Wallet, investment = Investment, profit = Profit, shares = Shares });\r\n }\r\n\r\n public void Invest() {\r\n Investment += Wallet;\r\n Wallet = 0;\r\n OnChange?.Invoke(new Portfolio { wallet = Wallet, investment = Investment, profit = Profit, shares = Shares });\r\n }\r\n\r\n private void DayNightSubscription() {\r\n IsDayEnded = true;\r\n }\r\n\r\n private void DayStartSubscription() {\r\n IsDayEnded = false;\r\n Profit = 0;\r\n walletPasive = 0;\r\n }\r\n\r\n public void ImprovePerformance(float amount) {\r\n performance += amount;\r\n }\r\n\r\n public void ImproveWallet(float amount) {\r\n ImproveWallet((int)amount);\r\n }\r\n\r\n private void ImproveWallet(int amount) {\r\n if (!isAvailablePerformanceWallet) {\r\n isAvailablePerformanceWallet = true;\r\n }\r\n\r\n performanceWallet = amount;\r\n }\r\n\r\n public void ImproveDeposit(float amount) {\r\n multiplierDeposit = amount;\r\n }\r\n\r\n public void ImproveDividends(float amount) {\r\n if (!isActivatedDividends) {\r\n isActivatedDividends = true;\r\n }\r\n\r\n multiplierDividends = amount;\r\n }\r\n\r\n public void Restart() {\r\n // reset all stats (wallet, profit, investment, days)\r\n performance = DEFAULT_PERFORMANCE;\r\n multiplierDeposit = 1.0f;\r\n isActivatedDividends = false;\r\n multiplierDividends = 0.0f;\r\n isAvailablePerformanceWallet = false;\r\n performanceWallet = (int)DEFAULT_PERFORMANCE;\r\n walletPasive = 0;\r\n Wallet = 0;\r\n Investment = 0f;\r\n Profit = 0;\r\n Shares = 0;\r\n }\r\n}\r\n"
},
{
"Ident": "rakunsoftware.milaine",
"Path": "Scripts/Settings/Translation.cs",
"FileName": "Translation.cs",
"PackageType": "game",
"CodeKind": "Game",
"AssetVersionId": 394495,
"IsPrivate": false,
"Code": "using Milaine.Utils;\r\n\r\nnamespace Milaine.Settings;\r\n\r\npublic sealed class Translations : Component {\r\n [Property, Title(\"Configuration\")]\r\n public Configuration ConfigurationInstance { get; set; }\r\n\r\n private Localization localization;\r\n\r\n public string language = \"en\";\r\n\r\n protected override void OnAwake() {\r\n localization = new();\r\n language = ConfigurationInstance.Language;\r\n localization.SetLanguage(ConfigurationInstance.Language);\r\n }\r\n\r\n public void SetLanguage(string language) {\r\n localization.SetLanguage(language);\r\n\r\n this.language = language;\r\n\r\n ConfigurationInstance.Language = language;\r\n ConfigurationInstance.SaveConfig();\r\n }\r\n\r\n public string T(string token, Dictionary<string, object> data = null) => localization.T(token, data);\r\n}\r\n"
},
{
"Ident": "rakunsoftware.milaine",
"Path": "UI/InvestmentPanel/InvestmentPanel.razor",
"FileName": "InvestmentPanel.razor",
"PackageType": "game",
"CodeKind": "Game",
"AssetVersionId": 394495,
"IsPrivate": false,
"Code": "@using System.Text;\r\n@using Milaine.Managers;\r\n@using Milaine.Settings;\r\n@using Milaine.Utils;\r\n@using Sandbox;\r\n@using Sandbox.UI;\r\n@inherits PanelComponent\r\n@namespace Sandbox\r\n\r\n<root>\r\n <header>\r\n <div class=\"container-title\">\r\n <Image src=\"resources/hexagon.png\" class=\"image\" style=\"width: 20px; height: 20px;\" />\r\n <h1 class=\"title\">SHARES // WORKS</h1>\r\n </div>\r\n <div class=\"content\" style=\"pointer-events: @(MouseManager.State == StateMouse.Busy ? \"none\" : \"all\");\">\r\n <Image src=\"resources/wallet-minimal.png\" class=\"image\" style=\"width: 20px; height: 20px;\" />\r\n <p class=\"text\">[email protected](InvestmentManagerInstance.Wallet)</p>\r\n </div>\r\n </header>\r\n <div class=\"container\">\r\n <section class=\"card\" style=\"pointer-events: @(MouseManager.State == StateMouse.Busy ? \"none\" : \"all\");\">\r\n <div class=\"card-header\">\r\n <div class=\"card-header-wrapper\">\r\n @if (InvestmentManagerInstance.Profit == 0) {\r\n <Image src=\"resources/dot.png\" />\r\n }\r\n @if (InvestmentManagerInstance.Profit > 0) {\r\n <Image src=\"resources/trending-up.png\" />\r\n }\r\n @if (InvestmentManagerInstance.Profit < 0) {\r\n <Image src=\"resources/trending-down.png\" />\r\n }\r\n <p class=\"card-title\">\r\n @* #milaine.profit.total *@\r\n @TranslationsInstance.T(\"milaine.profit.total\")\r\n </p>\r\n </div>\r\n <div class=@ClassName()>\r\n @if (InvestmentManagerInstance.Profit == 0) {\r\n <p>\r\n @* #milaine.critical.standard-profit *@\r\n @TranslationsInstance.T(\"milaine.critical.standard-profit\")\r\n </p>\r\n }\r\n @if (InvestmentManagerInstance.Profit < 0) {\r\n <p>\r\n @* #milaine.critical.bad-profit *@\r\n @TranslationsInstance.T(\"milaine.critical.bad-profit\")\r\n </p>\r\n }\r\n @if (InvestmentManagerInstance.Profit > 0) {\r\n <p>\r\n @* #milaine.critical.profit *@\r\n @TranslationsInstance.T(\"milaine.critical.profit\")\r\n </p>\r\n }\r\n </div>\r\n </div>\r\n <div class=\"card-body\">\r\n <div class=\"investment-container\">\r\n <div class=\"investment-content\">\r\n <p\r\n class=\"investment-text @(InvestmentManagerInstance.Profit == 0 ? \"normal\" : InvestmentManagerInstance.Profit < 0 ? \"bad\" : \"good\")\">\r\n @BuildInvestment(InvestmentManagerInstance.Investment)\r\n </p>\r\n\r\n @if (InvestmentManagerInstance.Profit > 0) {\r\n <p class=\"shares\">[email protected]</p>\r\n }\r\n </div>\r\n <div class=\"action\">\r\n <button class=\"btn btn-primary\" onclick=@HandleClickInvestment>\r\n @* #milaine.invest *@\r\n @TranslationsInstance.T(\"milaine.invest\")\r\n </button>\r\n <button class=\"btn btn-secondary\" onclick=@HandleClickDeposit>\r\n @* #milaine.deposit *@\r\n @TranslationsInstance.T(\"milaine.deposit\")\r\n </button>\r\n </div>\r\n </div>\r\n </div>\r\n </section>\r\n </div>\r\n</root>\r\n\r\n@code\r\n{\r\n [Property, Title(\"InvestmentManager\")]\r\n [Feature(\"Managers\")]\r\n public InvestmentManager InvestmentManagerInstance { get; set; }\r\n\r\n [Property, Title(\"IdleManager\")]\r\n [Feature(\"Managers\")]\r\n public IdleManager IdleManagerInstance { get; set; }\r\n\r\n [Property, Title(\"Translations\")]\r\n [Feature(\"Managers\")]\r\n public Translations TranslationsInstance { get; set; }\r\n\r\n public Dictionary<string, object> Data = [];\r\n\r\n protected override int BuildHash() => System.HashCode.Combine(Data, InvestmentManagerInstance.Wallet,\r\nInvestmentManagerInstance.Profit, TranslationsInstance.language, MouseManager.State);\r\n\r\n protected override void OnStart() {\r\n if (!InvestmentManagerInstance.IsValid()) {\r\n Log.Warning(\"Need Instance the InvestmentManager into [InvestmentView]\");\r\n return;\r\n }\r\n\r\n Refresh();\r\n }\r\n\r\n protected override void OnUpdate() {\r\n base.OnUpdate();\r\n\r\n if (Input.EscapePressed) {\r\n StateHasChanged();\r\n }\r\n }\r\n\r\n public string ClassName() => InvestmentManagerInstance.Profit == 0 ? \"tag standard\" : InvestmentManagerInstance.Profit\r\n< 0 ? \"tag low\" : \"tag\";\r\n\r\n private void HandleClickInvestment() {\r\n InvestmentManagerInstance.Invest();\r\n Refresh();\r\n }\r\n\r\n private void HandleClickDeposit() {\r\n InvestmentManagerInstance.Deposit(IdleManagerInstance.Dollars);\r\n IdleManagerInstance.Deposit();\r\n Refresh();\r\n }\r\n\r\n private string BuildInvestment(float investment) {\r\n StringBuilder sb = new();\r\n float profit = InvestmentManagerInstance.Profit;\r\n\r\n if (profit < 0) {\r\n sb.Append(\"- $\");\r\n }\r\n\r\n if (profit > 0) {\r\n sb.Append(\"+ $\");\r\n }\r\n\r\n sb.Append(Formatter.ToDisplay(investment));\r\n\r\n return sb.ToString();\r\n }\r\n\r\n private void Refresh() {\r\n Data[\"WalletValue\"] = Formatter.ToDisplayShort(InvestmentManagerInstance.Wallet);\r\n Data[\"InvestmentValue\"] = Formatter.ToDisplay(InvestmentManagerInstance.Investment);\r\n Data[\"ProfitValue\"] = Formatter.ToDisplay(InvestmentManagerInstance.Profit);\r\n Data[\"SharesValue\"] = InvestmentManagerInstance.Shares;\r\n }\r\n}\r\n"
},
{
"Ident": "rakunsoftware.milaine",
"Path": "ui/hud/hud.razor.scss",
"FileName": "hud.razor.scss",
"PackageType": "game",
"CodeKind": "Game",
"AssetVersionId": 394495,
"IsPrivate": false,
"Code": "Hud {\r\n position: absolute;\r\n top: 0;\r\n left: 0;\r\n right: 0;\r\n bottom: 0;\r\n flex-direction: column;\r\n font-weight: bold;\r\n border-radius: 20px;\r\n color: #fff;\r\n font-size: 25px;\r\n\r\n .header {\r\n display: flex;\r\n justify-content: flex-end;\r\n align-items: center;\r\n gap: 50px;\r\n padding: 20px;\r\n\r\n .day-manager h2 {\r\n text-align: center;\r\n font-size: 30px;\r\n font-family: \"Space Grotesk\";\r\n }\r\n\r\n .clock {\r\n background-color: rgba(0, 0, 0, 0.5);\r\n color: #fff;\r\n display: flex;\r\n justify-content: center;\r\n align-items: center;\r\n\r\n p {\r\n text-align: center;\r\n font-size: 28px;\r\n font-family: \"JetBrains Mono\";\r\n }\r\n }\r\n }\r\n\r\n .container {\r\n position: absolute;\r\n bottom: 50px;\r\n right: 50px;\r\n font-family: \"JetBrains Mono\";\r\n\r\n .content {\r\n padding: 10px 20px;\r\n display: flex;\r\n background-color: rgba(0, 0, 0, 0.5);\r\n border: 1px solid rgba(39, 42, 46, 0.8);\r\n border-radius: 5px;\r\n justify-content: center;\r\n align-items: center;\r\n gap: 10px;\r\n\r\n .image {\r\n object-fit: cover;\r\n }\r\n\r\n .headline {\r\n color: #00ff66;\r\n }\r\n }\r\n }\r\n\r\n .slot {\r\n position: absolute;\r\n bottom: 50px;\r\n right: 300px;\r\n display: flex;\r\n justify-content: center;\r\n align-items: center;\r\n flex-direction: column;\r\n gap: 10px;\r\n border-radius: 5px;\r\n padding: 10px 15px;\r\n background-color: rgba(0, 0, 0, 0.5);\r\n transition: all 300ms ease;\r\n\r\n &:hover {\r\n background-color: rgba(0, 0, 0, 0.8);\r\n transition: all 300ms ease;\r\n sound-in: ui.button.over;\r\n }\r\n\r\n .kbd {\r\n font-family: \"JetBrains Mono\";\r\n font-size: 30px;\r\n }\r\n\r\n .title {\r\n font-family: \"Space Grotesk\";\r\n font-size: 21px;\r\n }\r\n }\r\n\r\n .progress-end-game {\r\n position: absolute;\r\n width: 70%;\r\n bottom: 50px;\r\n left: 50px;\r\n\r\n .progress-bar {\r\n width: 100%;\r\n height: 40px;\r\n padding: 4px;\r\n border-radius: 6px;\r\n overflow: hidden;\r\n background-color: rgba(0, 0, 0, 0.7);\r\n\r\n .bar {\r\n height: 100%;\r\n background-image: linear-gradient(to right, #00e55b, #00ff66, #00e3fd);\r\n border-radius: 2px;\r\n }\r\n\r\n p {\r\n position: absolute;\r\n font-family: \"JetBrains Mono\";\r\n top: 50%;\r\n left: 50%;\r\n transform: translate(-50%, -50%);\r\n }\r\n }\r\n }\r\n\r\n .day-container {\r\n position: fixed;\r\n top: 0;\r\n left: 0;\r\n right: 0;\r\n bottom: 0;\r\n width: 100%;\r\n height: 100%;\r\n justify-content: center;\r\n align-items: center;\r\n background-color: rgb(7, 9, 11);\r\n opacity: 0;\r\n pointer-events: none;\r\n\r\n z-index: 999;\r\n\r\n animation-name: morning;\r\n animation-duration: 5s;\r\n animation-timing-function: ease;\r\n animation-fill-mode: forwards;\r\n\r\n .heading-current-day {\r\n font-size: 40px;\r\n text-align: center;\r\n font-weight: 700;\r\n font-family: \"Space Grotesk\";\r\n letter-spacing: 2px;\r\n }\r\n\r\n &.night {\r\n flex-direction: column;\r\n\r\n animation-name: night;\r\n animation-duration: 2s;\r\n\r\n button {\r\n pointer-events: all;\r\n }\r\n }\r\n\r\n .summary-container {\r\n width: 35%;\r\n padding: 24px;\r\n border: 1px solid #1e2936;\r\n flex-direction: column;\r\n background-color: rgb(18 23 30 / 0.95);\r\n border-radius: 12px;\r\n overflow: hidden;\r\n box-shadow:\r\n 0 0 25px -5px rgba(0, 255, 102, 0.25),\r\n inset 0 0 15px -3px rgba(0, 255, 102, 0.08);\r\n\r\n .summary-header {\r\n margin-bottom: 20px;\r\n flex-direction: column;\r\n\r\n .summary-title {\r\n display: flex;\r\n align-items: center;\r\n justify-content: flex-start;\r\n gap: 10px;\r\n padding-bottom: 16px;\r\n\r\n .circle {\r\n width: 16px;\r\n height: 16px;\r\n border-radius: 50%;\r\n background-color: #00ff66;\r\n }\r\n\r\n h2 {\r\n font-family: \"Space Grotesk\";\r\n font-size: 40px;\r\n }\r\n }\r\n }\r\n\r\n .row {\r\n display: flex;\r\n justify-content: space-between;\r\n align-items: center;\r\n margin-bottom: 20px;\r\n gap: 20px;\r\n }\r\n\r\n .form-control {\r\n padding: 16px;\r\n background-color: rgb(13 17 22 / 0.9);\r\n border: 1px solid rgb(30 41 54 / 0.7);\r\n border-radius: 8px;\r\n flex-direction: column;\r\n margin-bottom: 20px;\r\n gap: 16px;\r\n pointer-events: all;\r\n\r\n transition: all 500ms ease;\r\n\r\n &.nth {\r\n flex: 1;\r\n\r\n h3 {\r\n font-size: 23px;\r\n }\r\n }\r\n\r\n h3 {\r\n font-size: 30px;\r\n color: #94a3b8;\r\n }\r\n\r\n .form-control-header {\r\n justify-content: space-between;\r\n align-items: center;\r\n }\r\n\r\n &:hover {\r\n transition: all 500ms ease;\r\n\r\n &.mgreen {\r\n border-color: #00ff66;\r\n }\r\n\r\n &.mblue {\r\n border-color: #00e3fd;\r\n }\r\n\r\n &.mred {\r\n border-color: #ff3366;\r\n }\r\n }\r\n }\r\n }\r\n\r\n .separator {\r\n width: 100%;\r\n height: 1px;\r\n background-color: rgb(30 41 54 / 0.8);\r\n }\r\n\r\n .normal-font {\r\n font-family: \"Space Grotesk\";\r\n }\r\n\r\n .number {\r\n font-family: \"JetBrains Mono\";\r\n }\r\n\r\n .btn-next-action {\r\n flex: 1;\r\n display: flex;\r\n flex-direction: row;\r\n justify-content: center;\r\n align-items: center;\r\n padding: 30px;\r\n background-color: rgb(13 17 22 / 0.9);\r\n border: 1px solid #1e2936;\r\n border-radius: 16px;\r\n margin: 20px 0;\r\n\r\n pointer-events: all;\r\n }\r\n\r\n .circle-base {\r\n width: 8px;\r\n height: 8px;\r\n border-radius: 50%;\r\n }\r\n\r\n .circle-green {\r\n background-color: #00ff66;\r\n }\r\n\r\n .circle-blue {\r\n background-color: #00e3fd;\r\n }\r\n\r\n .circle-red {\r\n background-color: #ff3366;\r\n }\r\n }\r\n\r\n .version-manager {\r\n position: absolute;\r\n top: 20px;\r\n left: 20px;\r\n background-color: rgba(0, 0, 0, 0.5);\r\n\r\n p {\r\n color: white;\r\n font-family: \"JetBrains Mono\";\r\n font-size: 26px;\r\n }\r\n }\r\n}\r\n\r\n@keyframes morning {\r\n 0% {\r\n opacity: 0;\r\n }\r\n\r\n 2% {\r\n opacity: 1;\r\n }\r\n\r\n 60% {\r\n opacity: 1;\r\n }\r\n\r\n 100% {\r\n opacity: 0;\r\n }\r\n}\r\n\r\n@keyframes night {\r\n 0% {\r\n opacity: 0;\r\n }\r\n\r\n 100% {\r\n opacity: 1;\r\n }\r\n}\r\n"
},
{
"Ident": "rakunsoftware.milaine",
"Path": "Assembly.cs",
"FileName": "Assembly.cs",
"PackageType": "game",
"CodeKind": "Game",
"AssetVersionId": 394495,
"IsPrivate": false,
"Code": "global using Sandbox;\r\nglobal using System.Collections.Generic;\r\nglobal using System.Linq;\r\n"
},
{
"Ident": "rakunsoftware.milaine",
"Path": "Scripts/Utils/Pixel.cs",
"FileName": "Pixel.cs",
"PackageType": "game",
"CodeKind": "Game",
"AssetVersionId": 394495,
"IsPrivate": false,
"Code": "using System.Globalization;\r\n\r\nnamespace Milaine.Utils;\r\n\r\npublic static class Pixel {\r\n public static string Inv(float numb) => numb.ToString(CultureInfo.InvariantCulture);\r\n}\r\n"
},
{
"Ident": "rakunsoftware.milaine",
"Path": "Scripts/Utils/Formatter.cs",
"FileName": "Formatter.cs",
"PackageType": "game",
"CodeKind": "Game",
"AssetVersionId": 394495,
"IsPrivate": false,
"Code": "using System;\r\nusing System.Globalization;\r\n\r\nnamespace Milaine.Utils;\r\n\r\npublic static class Formatter {\r\n private static readonly string[] Suffixes = [\"\", \"k\", \"M\", \"B\", \"T\", \"Qa\", \"Qi\"];\r\n\r\n /// <summary>\r\n /// format float numbers from 1000 to 1.000\r\n /// </summary>\r\n /// <param name=\"val\"></param>\r\n /// <returns></returns>\r\n public static string ToDisplay(float val) {\r\n string native = val.ToString(\"#,##0\", CultureInfo.InvariantCulture);\r\n string display = native.Replace(',', '.');\r\n\r\n return display;\r\n }\r\n\r\n /// <summary>\r\n /// format from 1000 to 1.0K\r\n /// </summary>\r\n /// <param name=\"val\"></param>\r\n /// <returns></returns>\r\n public static string ToDisplayShort(float val) {\r\n double absVal = Math.Abs((double)val);\r\n\r\n if (absVal < 1000d) {\r\n return Math.Round(val).ToString(CultureInfo.InvariantCulture);\r\n }\r\n\r\n int magnitude = (int)Math.Log(absVal, 1000d);\r\n magnitude = Math.Min(magnitude, Suffixes.Length - 1);\r\n\r\n double scaled = val / Math.Pow(1000d, magnitude);\r\n\r\n if (Math.Round(scaled, 1) >= 1000d && magnitude < Suffixes.Length - 1) {\r\n magnitude++;\r\n scaled = val / Math.Pow(1000d, magnitude);\r\n }\r\n\r\n string number = scaled.ToString(\"0.0\", CultureInfo.InvariantCulture);\r\n\r\n return $\"{number}{Suffixes[magnitude]}\";\r\n }\r\n}\r\n"
}
]
}