{"TotalCount":55,"Files":[{"Ident":"fpkreastudios.desertpump","Path":".obj/__compiler_extra.cs","FileName":"__compiler_extra.cs","PackageType":"game","CodeKind":"Game","AssetVersionId":338006,"Code":"global using static Sandbox.Internal.GlobalGameNamespace;\r\nglobal using Microsoft.AspNetCore.Components;\r\nglobal using Microsoft.AspNetCore.Components.Rendering;\r\n[assembly: global::System.Reflection.AssemblyMetadata( \u0022AddonTitle\u0022, \u0022Desert Pump\u0022 )]\r\n[assembly: global::System.Reflection.AssemblyMetadata( \u0022AddonIdent\u0022, \u0022desertpump\u0022 )]\r\n[assembly: global::System.Reflection.AssemblyMetadata( \u0022OrgIdent\u0022, \u0022fpkreastudios\u0022 )]\r\n[assembly: global::System.Reflection.AssemblyMetadata( \u0022Ident\u0022, \u0022fpkreastudios.desertpump\u0022 )]\r\n[assembly: global::System.Reflection.AssemblyMetadata( \u0022EngineVersion\u0022, \u002228\u0022 )]\r\n[assembly: global::System.Reflection.AssemblyMetadata( \u0022EngineMinorVersion\u0022, \u00221\u0022 )]\r\n\r\n[assembly: System.Runtime.Versioning.TargetFramework( \u0022.NETCoreApp,Version=v9.0\u0022, FrameworkDisplayName = \u0022.NET 9.0\u0022 )]\r\n[assembly: global::System.Reflection.AssemblyMetadata( \u0022CompileTime\u0022, \u00222026-08-01T14:58:58.6069356Z\u0022 )]\r\n[assembly: global::System.Reflection.AssemblyVersion(\u00220.0.194.0\u0022)]\r\n[assembly: global::System.Reflection.AssemblyFileVersion(\u00220.0.194.0\u0022)]"},{"Ident":"fpkreastudios.desertpump","Path":"Game/DesertPumpGame.cs","FileName":"DesertPumpGame.cs","PackageType":"game","CodeKind":"Game","AssetVersionId":338006,"Code":"namespace DesertPump;\r\n\r\n/// \u003Csummary\u003E\r\n/// The whole game. Holds the money, the water and the current pump, and is the only\r\n/// thing allowed to change them - the HUD just calls into here and renders the result.\r\n/// \u003C/summary\u003E\r\n[Title( \u0022Desert Pump Game\u0022 )]\r\n[Category( \u0022Desert Pump\u0022 )]\r\n[Icon( \u0022water_drop\u0022 )]\r\npublic sealed partial class DesertPumpGame : Component\r\n{\r\n\t/// \u003Csummary\u003EThe active game, so the HUD doesn\u0027t need a wired-up reference.\u003C/summary\u003E\r\n\tpublic static DesertPumpGame Current { get; private set; }\r\n\r\n\t[Property, Group( \u0022Save\u0022 )]\r\n\tpublic bool SaveEnabled { get; set; } = true;\r\n\r\n\t[Property, Group( \u0022Save\u0022 )]\r\n\tpublic string SaveFile { get; set; } = \u0022desertpump.json\u0022;\r\n\r\n\t/// \u003Csummary\u003ESeconds between autosaves. Progress also saves on shutdown.\u003C/summary\u003E\r\n\t[Property, Group( \u0022Save\u0022 ), Range( 2f, 60f )]\r\n\tpublic float SaveInterval { get; set; } = 5f;\r\n\r\n\t/// \u003Csummary\u003ELongest stretch of time away that still pays out idle water.\u003C/summary\u003E\r\n\t[Property, Group( \u0022Save\u0022 ), Range( 0f, 24f )]\r\n\tpublic float MaxIdleHours { get; set; } = 4f;\r\n\r\n\t[Property, Group( \u0022Audio\u0022 )] public SoundEvent PumpSound { get; set; }\r\n\t[Property, Group( \u0022Audio\u0022 )] public SoundEvent SellSound { get; set; }\r\n\t[Property, Group( \u0022Audio\u0022 )] public SoundEvent UpgradeSound { get; set; }\r\n\t[Property, Group( \u0022Audio\u0022 )] public SoundEvent DeniedSound { get; set; }\r\n\r\n\tpublic double Coins { get; private set; }\r\n\tpublic double Water { get; private set; }\r\n\r\n\t/// \u003Csummary\u003EIndex into \u003Csee cref=\u0022PumpModel.All\u0022/\u003E.\u003C/summary\u003E\r\n\tpublic int PumpLevel { get; private set; }\r\n\r\n\t/// \u003Csummary\u003EShop upgrade levels, indexed by \u003Csee cref=\u0022UpgradeKind\u0022/\u003E.\u003C/summary\u003E\r\n\treadonly int[] upgradeLevels = new int[3];\r\n\r\n\tpublic bool Muted =\u003E PumpSettings.Current.Muted;\r\n\r\n\tpublic long TotalPumps { get; private set; }\r\n\tpublic double TotalEarned { get; private set; }\r\n\tpublic double TotalLitresSold { get; private set; }\r\n\r\n\t/// \u003Csummary\u003ELitres the pump produced while the game was closed, for the welcome-back note.\u003C/summary\u003E\r\n\tpublic double IdleCatchUp { get; private set; }\r\n\r\n\tpublic PumpModel CurrentPump =\u003E PumpModel.Get( PumpLevel );\r\n\tpublic PumpTier Tier =\u003E CurrentPump.Tier;\r\n\tpublic PumpModel NextPump =\u003E PumpLevel \u003C PumpModel.MaxIndex ? PumpModel.Get( PumpLevel \u002B 1 ) : null;\r\n\tpublic bool IsMaxed =\u003E NextPump is null;\r\n\r\n\t// ---- effective stats: the tier\u0027s base numbers times whatever the shop has sold you\r\n\r\n\t/// \u003Csummary\u003ETank size including the Water Tank upgrade.\u003C/summary\u003E\r\n\tpublic double TankCapacity =\u003E CurrentPump.Tank * MultiplierOf( UpgradeKind.Storage );\r\n\r\n\t/// \u003Csummary\u003ELitres per manual pump, including Pump Power.\u003C/summary\u003E\r\n\tpublic double LitresPerClick =\u003E CurrentPump.PerClick * MultiplierOf( UpgradeKind.Power );\r\n\r\n\t/// \u003Csummary\u003ECoins per litre, including Market Contacts.\u003C/summary\u003E\r\n\tpublic double PricePerLitre =\u003E CurrentPump.PricePerLitre * MultiplierOf( UpgradeKind.Value );\r\n\r\n\tpublic bool TankFull =\u003E Water \u003E= TankCapacity - 0.0001;\r\n\tpublic float TankFraction =\u003E TankCapacity \u003C= 0 ? 0f : (float)Math.Clamp( Water / TankCapacity, 0d, 1d );\r\n\r\n\t/// \u003Csummary\u003EWhat the tank is worth right now.\u003C/summary\u003E\r\n\tpublic double SaleValue =\u003E Water * PricePerLitre;\r\n\r\n\tpublic bool CanSell =\u003E Water \u003E 0.0001;\r\n\tpublic bool CanUpgrade =\u003E NextPump is not null \u0026\u0026 Coins \u003E= NextPump.Cost;\r\n\r\n\tpublic int LevelOf( UpgradeKind kind ) =\u003E upgradeLevels[(int)kind];\r\n\r\n\tpublic float MultiplierOf( UpgradeKind kind ) =\u003E UpgradeTrack.Get( kind ).MultiplierAt( LevelOf( kind ) );\r\n\r\n\tpublic bool IsMaxLevel( UpgradeKind kind ) =\u003E LevelOf( kind ) \u003E= UpgradeTrack.Get( kind ).MaxLevel;\r\n\r\n\t/// \u003Csummary\u003ECost of the next level, or infinity once the track is maxed.\u003C/summary\u003E\r\n\tpublic double CostOf( UpgradeKind kind )\r\n\t{\r\n\t\treturn IsMaxLevel( kind )\r\n\t\t\t? double.PositiveInfinity\r\n\t\t\t: UpgradeTrack.Get( kind ).CostAt( LevelOf( kind ) );\r\n\t}\r\n\r\n\tpublic bool CanBuy( UpgradeKind kind ) =\u003E !IsMaxLevel( kind ) \u0026\u0026 Coins \u003E= CostOf( kind );\r\n\r\n\t/// \u003Csummary\u003EFired on a successful manual pump, with the litres gained.\u003C/summary\u003E\r\n\tpublic Action\u003Cdouble\u003E Pumped { get; set; }\r\n\r\n\t/// \u003Csummary\u003EFired on a sale, with the coins gained.\u003C/summary\u003E\r\n\tpublic Action\u003Cdouble\u003E Sold { get; set; }\r\n\r\n\t/// \u003Csummary\u003EFired after buying a new pump, with the tier we moved to.\u003C/summary\u003E\r\n\tpublic Action\u003CPumpModel\u003E Upgraded { get; set; }\r\n\r\n\t/// \u003Csummary\u003EFired when an action was refused - tank full, broke, nothing to sell.\u003C/summary\u003E\r\n\tpublic Action\u003Cstring\u003E Refused { get; set; }\r\n\r\n\t/// \u003Csummary\u003EFired after buying a shop upgrade.\u003C/summary\u003E\r\n\tpublic Action\u003CUpgradeTrack\u003E Purchased { get; set; }\r\n\r\n\tTimeSince timeSinceSave;\r\n\r\n\t/// \u003Csummary\u003E\r\n\t/// True once \u003Csee cref=\u0022Load\u0022/\u003E has run, which only happens in play mode. The copy of\r\n\t/// this component living in the editor\u0027s scene never wakes, so it sits on default\r\n\t/// zeroes - and without this guard its shutdown save would write those zeroes straight\r\n\t/// over a real run. Never write state we haven\u0027t read.\r\n\t/// \u003C/summary\u003E\r\n\tbool loaded;\r\n\r\n\tprotected override void OnAwake()\r\n\t{\r\n\t\tCurrent = this;\r\n\t\tLoad();\r\n\t}\r\n\r\n\t/// \u003Csummary\u003E\r\n\t/// Quitting tears the scene down, and which of these fires first depends on how you\r\n\t/// left - closing the window, stopping play mode, or loading another scene. Saving\r\n\t/// from both, plus after every earn and spend, means there\u0027s no way out that loses\r\n\t/// a run.\r\n\t/// \u003C/summary\u003E\r\n\tprotected override void OnDisabled()\r\n\t{\r\n\t\tSave();\r\n\t}\r\n\r\n\tprotected override void OnDestroy()\r\n\t{\r\n\t\tSave();\r\n\r\n\t\tif ( Current == this )\r\n\t\t\tCurrent = null;\r\n\t}\r\n\r\n\tprotected override void OnUpdate()\r\n\t{\r\n\t\t// A code hotload wipes statics without re-running OnAwake, which would leave\r\n\t\t// Current null and the HUD showing \u0022no game in the scene\u0022 for the rest of the\r\n\t\t// session. Cheaper to re-claim it than to debug that every time.\r\n\t\tif ( Current != this ) Current = this;\r\n\r\n\t\t// This is a mouse game - without this the cursor gets locked to the view in\r\n\t\t// play mode and none of the buttons can be clicked.\r\n\t\tMouse.Visibility = MouseVisibility.Visible;\r\n\r\n\t\t// Space bar is a second pump button so you\u0027re not glued to the mouse.\r\n\t\tif ( Input.Pressed( \u0022Jump\u0022 ) )\r\n\t\t{\r\n\t\t\tPump();\r\n\t\t}\r\n\r\n\t\tvar passive = CurrentPump.PerSecond * Time.Delta;\r\n\t\tif ( passive \u003E 0f )\r\n\t\t{\r\n\t\t\tAddWater( passive );\r\n\t\t}\r\n\r\n\t\tTickGusher();\r\n\t\tTickTree();\r\n\r\n\t\tif ( PumpSettings.Current.AutoSell \u0026\u0026 TankFull )\r\n\t\t{\r\n\t\t\tSellAll();\r\n\t\t}\r\n\r\n\t\tif ( SaveEnabled \u0026\u0026 timeSinceSave \u003E SaveInterval )\r\n\t\t{\r\n\t\t\tSave();\r\n\t\t}\r\n\t}\r\n\r\n\t/// \u003Csummary\u003E\r\n\t/// One manual pump. Returns the litres actually gained - zero means the tank was already full.\r\n\t/// \u003C/summary\u003E\r\n\tpublic double Pump()\r\n\t{\r\n\t\tif ( TankFull )\r\n\t\t{\r\n\t\t\tRefuse( \u0022Tank is full - sell your water\u0022 );\r\n\t\t\treturn 0;\r\n\t\t}\r\n\r\n\t\tvar gained = AddWater( LitresPerClick );\r\n\r\n\t\tTotalPumps\u002B\u002B;\r\n\t\tPlay( PumpSound );\r\n\t\tPumped?.Invoke( gained );\r\n\r\n\t\treturn gained;\r\n\t}\r\n\r\n\t/// \u003Csummary\u003E\r\n\t/// Empty the tank into coins. Returns what we earned.\r\n\t/// \u003C/summary\u003E\r\n\tpublic double SellAll()\r\n\t{\r\n\t\tif ( !CanSell )\r\n\t\t{\r\n\t\t\tRefuse( \u0022No water to sell\u0022 );\r\n\t\t\treturn 0;\r\n\t\t}\r\n\r\n\t\tvar litres = Water;\r\n\t\tvar earned = SaleValue;\r\n\r\n\t\tWater = 0;\r\n\t\tCoins \u002B= earned;\r\n\t\tTotalEarned \u002B= earned;\r\n\t\tTotalLitresSold \u002B= litres;\r\n\t\tIdleCatchUp = 0;\r\n\r\n\t\tPlay( SellSound );\r\n\t\tSold?.Invoke( earned );\r\n\t\tSave();\r\n\r\n\t\treturn earned;\r\n\t}\r\n\r\n\t/// \u003Csummary\u003E\r\n\t/// Buy the next pump in the list. Water carries over, clamped to the new tank.\r\n\t/// \u003C/summary\u003E\r\n\tpublic bool BuyNextPump()\r\n\t{\r\n\t\tvar next = NextPump;\r\n\r\n\t\tif ( next is null )\r\n\t\t{\r\n\t\t\tRefuse( \u0022You own every pump in the desert\u0022 );\r\n\t\t\treturn false;\r\n\t\t}\r\n\r\n\t\tif ( Coins \u003C next.Cost )\r\n\t\t{\r\n\t\t\tRefuse( $\u0022Need {Numbers.Short( next.Cost - Coins )} more coins\u0022 );\r\n\t\t\treturn false;\r\n\t\t}\r\n\r\n\t\tCoins -= next.Cost;\r\n\t\tPumpLevel = next.Index;\r\n\t\tWater = Math.Min( Water, TankCapacity );\r\n\r\n\t\tPlay( UpgradeSound );\r\n\t\tUpgraded?.Invoke( next );\r\n\t\tSave();\r\n\r\n\t\treturn true;\r\n\t}\r\n\r\n\t/// \u003Csummary\u003EHand over coins from outside the sell loop - rewards, console commands.\u003C/summary\u003E\r\n\tpublic void AddCoins( double amount )\r\n\t{\r\n\t\t// A NaN or infinity in here poisons the save and every number on screen with\r\n\t\t// no way back, so refuse it at the door rather than storing it.\r\n\t\tif ( amount \u003C= 0 || double.IsNaN( amount ) || double.IsInfinity( amount ) )\r\n\t\t\treturn;\r\n\r\n\t\tCoins \u002B= amount;\r\n\t\tTotalEarned \u002B= amount;\r\n\t}\r\n\r\n\t/// \u003Csummary\u003E\r\n\t/// Buy one level of a shop upgrade. Returns false and complains if you can\u0027t afford it.\r\n\t/// \u003C/summary\u003E\r\n\tpublic bool BuyUpgrade( UpgradeKind kind )\r\n\t{\r\n\t\tvar track = UpgradeTrack.Get( kind );\r\n\r\n\t\tif ( IsMaxLevel( kind ) )\r\n\t\t{\r\n\t\t\tRefuse( $\u0022{track.Name} is fully upgraded\u0022 );\r\n\t\t\treturn false;\r\n\t\t}\r\n\r\n\t\tvar cost = CostOf( kind );\r\n\t\tif ( Coins \u003C cost )\r\n\t\t{\r\n\t\t\tRefuse( $\u0022Need {Numbers.Short( cost - Coins )} more coins\u0022 );\r\n\t\t\treturn false;\r\n\t\t}\r\n\r\n\t\tCoins -= cost;\r\n\t\tupgradeLevels[(int)kind]\u002B\u002B;\r\n\r\n\t\t// A smaller tank than the water in it can\u0027t happen, but a bigger one is free room.\r\n\t\tWater = Math.Min( Water, TankCapacity );\r\n\r\n\t\tPlay( UpgradeSound );\r\n\t\tPurchased?.Invoke( track );\r\n\t\tSave();\r\n\r\n\t\treturn true;\r\n\t}\r\n\r\n\tpublic void ToggleMute()\r\n\t{\r\n\t\tvar settings = PumpSettings.Current;\r\n\r\n\t\tsettings.Muted = !settings.Muted;\r\n\t\tsettings.Save();\r\n\t}\r\n\r\n\t/// \u003Csummary\u003EWipe the save and start over from the hand pump.\u003C/summary\u003E\r\n\tpublic void ResetProgress()\r\n\t{\r\n\t\tCoins = 0;\r\n\t\tWater = 0;\r\n\t\tPumpLevel = 0;\r\n\t\tArray.Clear( upgradeLevels );\r\n\t\townedBackgrounds.Clear();\r\n\t\townedBackgrounds.Add( BackgroundStyle.DefaultId );\r\n\t\tSelectedBackground = BackgroundStyle.DefaultId;\r\n\t\tlastDailyDay = 0;\r\n\t\tDailyStreak = 0;\r\n\t\tTreeHeight = 0;\r\n\t\tTreeWater = 0;\r\n\t\ttreeGrowsAt = 0;\r\n\t\tTotalPumps = 0;\r\n\t\tTotalEarned = 0;\r\n\t\tTotalLitresSold = 0;\r\n\t\tIdleCatchUp = 0;\r\n\r\n\t\tSave();\r\n\t}\r\n\r\n\t/// \u003Csummary\u003EAdds water up to the tank limit and returns how much actually fit.\u003C/summary\u003E\r\n\tdouble AddWater( double amount )\r\n\t{\r\n\t\tvar before = Water;\r\n\t\tWater = Math.Min( TankCapacity, Water \u002B amount );\r\n\r\n\t\treturn Water - before;\r\n\t}\r\n\r\n\tvoid Refuse( string reason )\r\n\t{\r\n\t\tPlay( DeniedSound );\r\n\t\tRefused?.Invoke( reason );\r\n\t}\r\n\r\n\tvoid Play( SoundEvent sound )\r\n\t{\r\n\t\tvar volume = PumpSettings.Current.EffectiveSfx;\r\n\r\n\t\tif ( sound is null || volume \u003C= 0f )\r\n\t\t\treturn;\r\n\r\n\t\tvar handle = Sound.Play( sound, (Sandbox.Audio.Mixer)null );\r\n\r\n\t\tif ( handle.IsValid() )\r\n\t\t{\r\n\t\t\thandle.Volume = volume;\r\n\t\t}\r\n\t}\r\n\r\n\tvoid Load()\r\n\t{\r\n\t\ttimeSinceSave = 0;\r\n\r\n\t\tif ( !SaveEnabled )\r\n\t\t\treturn;\r\n\r\n\t\t// From here on we own the file - a missing save just means a fresh run.\r\n\t\tloaded = true;\r\n\r\n\t\tvar save = FileSystem.Data.ReadJsonOrDefault\u003CPumpSave\u003E( SaveFile, null );\r\n\t\tif ( save is null )\r\n\t\t\treturn;\r\n\r\n\t\t// Stash the run as we found it. One session of history is enough to rescue a\r\n\t\t// player whose save gets eaten by a bug, and it costs one small write per load.\r\n\t\tFileSystem.Data.WriteJson( SaveFile \u002B \u0022.bak\u0022, save );\r\n\r\n\t\tCoins = Math.Max( 0, save.Coins );\r\n\t\tPumpLevel = Math.Clamp( save.PumpLevel, 0, PumpModel.MaxIndex );\r\n\r\n\t\townedBackgrounds.Clear();\r\n\t\townedBackgrounds.Add( BackgroundStyle.DefaultId );\r\n\t\tforeach ( var id in save.OwnedBackgrounds ?? new List\u003Cstring\u003E() )\r\n\t\t{\r\n\t\t\townedBackgrounds.Add( id );\r\n\t\t}\r\n\r\n\t\tSelectedBackground = OwnsBackground( save.SelectedBackground )\r\n\t\t\t? save.SelectedBackground\r\n\t\t\t: BackgroundStyle.DefaultId;\r\n\r\n\t\tlastDailyDay = save.LastDailyDay;\r\n\t\tTreeHeight = Math.Max( 0, save.TreeHeight );\r\n\t\tTreeWater = Math.Max( 0, save.TreeWater );\r\n\t\ttreeGrowsAt = save.TreeGrowsAt;\r\n\t\tDailyStreak = save.DailyStreak;\r\n\r\n\t\tupgradeLevels[(int)UpgradeKind.Storage] = ClampLevel( save.StorageLevel, UpgradeKind.Storage );\r\n\t\tupgradeLevels[(int)UpgradeKind.Power] = ClampLevel( save.PowerLevel, UpgradeKind.Power );\r\n\t\tupgradeLevels[(int)UpgradeKind.Value] = ClampLevel( save.ValueLevel, UpgradeKind.Value );\r\n\r\n\t\t// Levels have to be in before the tank is clamped, or a full tank gets trimmed\r\n\t\t// to the un-upgraded size on every load.\r\n\t\tWater = Math.Clamp( save.Water, 0, TankCapacity );\r\n\t\tTotalPumps = save.TotalPumps;\r\n\t\tTotalEarned = save.TotalEarned;\r\n\t\tTotalLitresSold = save.TotalLitresSold;\r\n\r\n\t\tPayIdleTime( save.SavedAt );\r\n\t}\r\n\r\n\tstatic int ClampLevel( int level, UpgradeKind kind ) =\u003E\r\n\t\tMath.Clamp( level, 0, UpgradeTrack.Get( kind ).MaxLevel );\r\n\r\n\t/// \u003Csummary\u003ERuns the passive pump for the time we were away, capped so it can\u0027t be farmed.\u003C/summary\u003E\r\n\tvoid PayIdleTime( long savedAt )\r\n\t{\r\n\t\tif ( savedAt \u003C= 0 || CurrentPump.PerSecond \u003C= 0f )\r\n\t\t\treturn;\r\n\r\n\t\tvar away = DateTimeOffset.UtcNow.ToUnixTimeSeconds() - savedAt;\r\n\t\tif ( away \u003C= 0 )\r\n\t\t\treturn;\r\n\r\n\t\tvar seconds = Math.Min( away, (long)(MaxIdleHours * 3600f) );\r\n\t\tIdleCatchUp = AddWater( CurrentPump.PerSecond * seconds );\r\n\t}\r\n\r\n\tvoid Save()\r\n\t{\r\n\t\ttimeSinceSave = 0;\r\n\r\n\t\tif ( !SaveEnabled )\r\n\t\t\treturn;\r\n\r\n\t\t// Never overwrite a real run with state we never loaded. See the field comment.\r\n\t\tif ( !loaded )\r\n\t\t\treturn;\r\n\r\n\t\tFileSystem.Data.WriteJson( SaveFile, new PumpSave\r\n\t\t{\r\n\t\t\tCoins = Coins,\r\n\t\t\tWater = Water,\r\n\t\t\tPumpLevel = PumpLevel,\r\n\t\t\tOwnedBackgrounds = ownedBackgrounds.ToList(),\r\n\t\t\tSelectedBackground = SelectedBackground,\r\n\t\t\tLastDailyDay = lastDailyDay,\r\n\t\t\tTreeHeight = TreeHeight,\r\n\t\t\tTreeWater = TreeWater,\r\n\t\t\tTreeGrowsAt = treeGrowsAt,\r\n\t\t\tDailyStreak = DailyStreak,\r\n\t\t\tStorageLevel = LevelOf( UpgradeKind.Storage ),\r\n\t\t\tPowerLevel = LevelOf( UpgradeKind.Power ),\r\n\t\t\tValueLevel = LevelOf( UpgradeKind.Value ),\r\n\t\t\tMuted = Muted,\r\n\t\t\tTotalPumps = TotalPumps,\r\n\t\t\tTotalEarned = TotalEarned,\r\n\t\t\tTotalLitresSold = TotalLitresSold,\r\n\t\t\tSavedAt = DateTimeOffset.UtcNow.ToUnixTimeSeconds()\r\n\t\t} );\r\n\t}\r\n}\r\n"},{"Ident":"fpkreastudios.desertpump","Path":"Game/PumpSettings.cs","FileName":"PumpSettings.cs","PackageType":"game","CodeKind":"Game","AssetVersionId":338006,"Code":"namespace DesertPump;\n\n/// \u003Csummary\u003E\n/// Player preferences. Kept in their own file so wiping a run never costs you your\n/// volume levels, and so they survive a reset.\n/// \u003C/summary\u003E\npublic sealed class PumpSettings\n{\n\tpublic const string FileName = \u0022settings.json\u0022;\n\n\tpublic float MasterVolume { get; set; } = 0.8f;\n\tpublic float MusicVolume { get; set; } = 0.55f;\n\tpublic float SfxVolume { get; set; } = 1f;\n\n\t/// \u003Csummary\u003ESilences everything, music included. The speaker button toggles this.\u003C/summary\u003E\n\tpublic bool Muted { get; set; }\n\n\t/// \u003Csummary\u003EThe little \u0022\u002B12L\u0022 numbers that fly off the pump.\u003C/summary\u003E\n\tpublic bool ShowFloatingNumbers { get; set; } = true;\n\n\t/// \u003Csummary\u003ESell the tank automatically the moment it fills. Off by default.\u003C/summary\u003E\n\tpublic bool AutoSell { get; set; }\n\n\t/// \u003Csummary\u003EFinal multiplier for one-shot effects.\u003C/summary\u003E\n\t[System.Text.Json.Serialization.JsonIgnore]\n\tpublic float EffectiveSfx =\u003E Muted ? 0f : MasterVolume * SfxVolume;\n\n\t/// \u003Csummary\u003EFinal multiplier for the background track.\u003C/summary\u003E\n\t[System.Text.Json.Serialization.JsonIgnore]\n\tpublic float EffectiveMusic =\u003E Muted ? 0f : MasterVolume * MusicVolume;\n\n\tstatic PumpSettings loaded;\n\n\t/// \u003Csummary\u003E\n\t/// The live settings. Lazily read so a code hotload - which clears statics - just\n\t/// picks them back up off disk instead of reverting to defaults.\n\t/// \u003C/summary\u003E\n\tpublic static PumpSettings Current\n\t{\n\t\tget\n\t\t{\n\t\t\tloaded ??= FileSystem.Data.ReadJsonOrDefault\u003CPumpSettings\u003E( FileName, null ) ?? new PumpSettings();\n\t\t\treturn loaded;\n\t\t}\n\t}\n\n\tpublic void Save()\n\t{\n\t\tMasterVolume = Math.Clamp( MasterVolume, 0f, 1f );\n\t\tMusicVolume = Math.Clamp( MusicVolume, 0f, 1f );\n\t\tSfxVolume = Math.Clamp( SfxVolume, 0f, 1f );\n\n\t\tFileSystem.Data.WriteJson( FileName, this );\n\t}\n}\n"},{"Ident":"fpkreastudios.desertpump","Path":"Game/PumpTier.cs","FileName":"PumpTier.cs","PackageType":"game","CodeKind":"Game","AssetVersionId":338006,"Code":"namespace DesertPump;\n\n/// \u003Csummary\u003E\n/// One of the twelve tiers. A tier is nine pumps that share a setting - you finish\n/// the desert before you ever see a glacier.\n/// \u003C/summary\u003E\npublic sealed class PumpTier\n{\n\t/// \u003Csummary\u003E1 to 12, the way the player sees it.\u003C/summary\u003E\n\tpublic int Number { get; init; }\n\n\tpublic string Name { get; init; }\n\tpublic string Tagline { get; init; }\n\n\t/// \u003Csummary\u003EDrives the placeholder pump art for every pump in this tier.\u003C/summary\u003E\n\tpublic Color Tint { get; init; }\n\n\t/// \u003Csummary\u003EThe nine pump names, cheapest first.\u003C/summary\u003E\n\tpublic string[] PumpNames { get; init; }\n\n\tpublic int FirstPumpIndex =\u003E (Number - 1) * PumpsPerTier;\n\tpublic int LastPumpIndex =\u003E FirstPumpIndex \u002B PumpsPerTier - 1;\n\n\tpublic const int PumpsPerTier = 9;\n\n\t/// \u003Csummary\u003ERe-read on hotload so edits apply without restarting - see PumpModel.All.\u003C/summary\u003E\n\t[SkipHotload]\n\tpublic static readonly PumpTier[] All = new PumpTier[]\n\t{\n\t\tnew()\n\t\t{\n\t\t\tNumber = 1,\n\t\t\tName = \u0022Desert Wells\u0022,\n\t\t\tTagline = \u0022Sand, rust, and whatever you can pull up by hand.\u0022,\n\t\t\tTint = new Color( 0.72f, 0.50f, 0.24f ),\n\t\t\tPumpNames = new[]\n\t\t\t{\n\t\t\t\t\u0022Rusty Hand Pump\u0022, \u0022Iron Well Pump\u0022, \u0022Steam Pressure Pump\u0022,\n\t\t\t\t\u0022Diesel Derrick\u0022, \u0022Solar Filtration Rig\u0022, \u0022Oasis Temple Spring\u0022,\n\t\t\t\t\u0022Hydro Tower\u0022, \u0022Vortex Extractor\u0022, \u0022Ancient Geyser Monolith\u0022\n\t\t\t}\n\t\t},\n\t\tnew()\n\t\t{\n\t\t\tNumber = 2,\n\t\t\tName = \u0022The Steamworks\u0022,\n\t\t\tTagline = \u0022Brass, pressure gauges, and a great deal of hissing.\u0022,\n\t\t\tTint = new Color( 0.66f, 0.42f, 0.20f ),\n\t\t\tPumpNames = new[]\n\t\t\t{\n\t\t\t\t\u0022Brass Piston Well\u0022, \u0022Boiler Draw\u0022, \u0022Twin Cylinder Rig\u0022,\n\t\t\t\t\u0022Pressure Cathedral\u0022, \u0022Governor Engine\u0022, \u0022Flywheel Colossus\u0022,\n\t\t\t\t\u0022Condenser Array\u0022, \u0022Turbine Hall\u0022, \u0022The Great Manifold\u0022\n\t\t\t}\n\t\t},\n\t\tnew()\n\t\t{\n\t\t\tNumber = 3,\n\t\t\tName = \u0022Oil Country\u0022,\n\t\t\tTagline = \u0022If it worked for crude, it\u0027ll work for water.\u0022,\n\t\t\tTint = new Color( 0.34f, 0.34f, 0.30f ),\n\t\t\tPumpNames = new[]\n\t\t\t{\n\t\t\t\t\u0022Nodding Donkey\u0022, \u0022Wildcat Rig\u0022, \u0022Slant Drill\u0022,\n\t\t\t\t\u0022Offshore Jacket\u0022, \u0022Deep Casing Pump\u0022, \u0022Fracture Head\u0022,\n\t\t\t\t\u0022Pipeline Junction\u0022, \u0022Refinery Tap\u0022, \u0022The Black Column\u0022\n\t\t\t}\n\t\t},\n\t\tnew()\n\t\t{\n\t\t\tNumber = 4,\n\t\t\tName = \u0022Solar Frontier\u0022,\n\t\t\tTagline = \u0022Free light, endless panels, no moving parts.\u0022,\n\t\t\tTint = new Color( 0.28f, 0.46f, 0.78f ),\n\t\t\tPumpNames = new[]\n\t\t\t{\n\t\t\t\t\u0022Panel Trickle\u0022, \u0022Mirror Trough\u0022, \u0022Heliostat Field\u0022,\n\t\t\t\t\u0022Molten Salt Loop\u0022, \u0022Photovoltaic Mesa\u0022, \u0022Tower of Light\u0022,\n\t\t\t\t\u0022Orbital Reflector\u0022, \u0022Fusion Preheater\u0022, \u0022The Sun Engine\u0022\n\t\t\t}\n\t\t},\n\t\tnew()\n\t\t{\n\t\t\tNumber = 5,\n\t\t\tName = \u0022The Lost Oasis\u0022,\n\t\t\tTagline = \u0022Someone was pumping here long before you.\u0022,\n\t\t\tTint = new Color( 0.86f, 0.70f, 0.26f ),\n\t\t\tPumpNames = new[]\n\t\t\t{\n\t\t\t\t\u0022Sunken Step Well\u0022, \u0022Palm Court Spring\u0022, \u0022Mosaic Cistern\u0022,\n\t\t\t\t\u0022Colonnade Fountain\u0022, \u0022Serpent Aqueduct\u0022, \u0022Sun Disc Basin\u0022,\n\t\t\t\t\u0022Hall of Rains\u0022, \u0022Temple of the Flood\u0022, \u0022The First Spring\u0022\n\t\t\t}\n\t\t},\n\t\tnew()\n\t\t{\n\t\t\tNumber = 6,\n\t\t\tName = \u0022Deep Aquifer\u0022,\n\t\t\tTagline = \u0022Down where the rock has been holding its breath.\u0022,\n\t\t\tTint = new Color( 0.30f, 0.52f, 0.55f ),\n\t\t\tPumpNames = new[]\n\t\t\t{\n\t\t\t\t\u0022Bore Shaft\u0022, \u0022Karst Siphon\u0022, \u0022Cavern Lake Pump\u0022,\n\t\t\t\t\u0022Sinkhole Intake\u0022, \u0022Mantle Straw\u0022, \u0022Pressure Fault\u0022,\n\t\t\t\t\u0022Abyssal Column\u0022, \u0022Tectonic Draw\u0022, \u0022The Sleeping Sea\u0022\n\t\t\t}\n\t\t},\n\t\tnew()\n\t\t{\n\t\t\tNumber = 7,\n\t\t\tName = \u0022Storm Harvest\u0022,\n\t\t\tTagline = \u0022Stop digging. Start taking it out of the sky.\u0022,\n\t\t\tTint = new Color( 0.42f, 0.46f, 0.62f ),\n\t\t\tPumpNames = new[]\n\t\t\t{\n\t\t\t\t\u0022Rain Catcher\u0022, \u0022Cloud Seeder\u0022, \u0022Squall Funnel\u0022,\n\t\t\t\t\u0022Lightning Condenser\u0022, \u0022Monsoon Gate\u0022, \u0022Cyclone Tap\u0022,\n\t\t\t\t\u0022Hurricane Yoke\u0022, \u0022Jet Stream Weir\u0022, \u0022The Storm Crown\u0022\n\t\t\t}\n\t\t},\n\t\tnew()\n\t\t{\n\t\t\tNumber = 8,\n\t\t\tName = \u0022Glacier Melt\u0022,\n\t\t\tTagline = \u0022Ten thousand years of snow, cashed in.\u0022,\n\t\t\tTint = new Color( 0.58f, 0.78f, 0.86f ),\n\t\t\tPumpNames = new[]\n\t\t\t{\n\t\t\t\t\u0022Meltwater Channel\u0022, \u0022Crevasse Pump\u0022, \u0022Ice Core Drill\u0022,\n\t\t\t\t\u0022Moraine Sluice\u0022, \u0022Calving Front Rig\u0022, \u0022Ice Shelf Siphon\u0022,\n\t\t\t\t\u0022Polar Reservoir\u0022, \u0022Continental Thaw\u0022, \u0022The Long Winter Tap\u0022\n\t\t\t}\n\t\t},\n\t\tnew()\n\t\t{\n\t\t\tNumber = 9,\n\t\t\tName = \u0022Ocean Reclaim\u0022,\n\t\t\tTagline = \u0022Salt is just an engineering problem.\u0022,\n\t\t\tTint = new Color( 0.20f, 0.52f, 0.62f ),\n\t\t\tPumpNames = new[]\n\t\t\t{\n\t\t\t\t\u0022Beach Well\u0022, \u0022Reverse Osmosis Bank\u0022, \u0022Desalination Pier\u0022,\n\t\t\t\t\u0022Tidal Intake\u0022, \u0022Trench Pump\u0022, \u0022Current Harness\u0022,\n\t\t\t\t\u0022Abyssal Plain Array\u0022, \u0022Continental Shelf Works\u0022, \u0022The Ocean Engine\u0022\n\t\t\t}\n\t\t},\n\t\tnew()\n\t\t{\n\t\t\tNumber = 10,\n\t\t\tName = \u0022Sky Condensers\u0022,\n\t\t\tTagline = \u0022The whole atmosphere, wrung out like a cloth.\u0022,\n\t\t\tTint = new Color( 0.66f, 0.72f, 0.86f ),\n\t\t\tPumpNames = new[]\n\t\t\t{\n\t\t\t\t\u0022Fog Net\u0022, \u0022Dew Spire\u0022, \u0022Stratosphere Coil\u0022,\n\t\t\t\t\u0022Cloud Anchor\u0022, \u0022Mesosphere Rig\u0022, \u0022Aurora Collector\u0022,\n\t\t\t\t\u0022Orbital Ring Tap\u0022, \u0022Atmospheric Siphon\u0022, \u0022The Great Condenser\u0022\n\t\t\t}\n\t\t},\n\t\tnew()\n\t\t{\n\t\t\tNumber = 11,\n\t\t\tName = \u0022Void Springs\u0022,\n\t\t\tTagline = \u0022The water is coming from somewhere. Don\u0027t ask where.\u0022,\n\t\t\tTint = new Color( 0.52f, 0.36f, 0.78f ),\n\t\t\tPumpNames = new[]\n\t\t\t{\n\t\t\t\t\u0022Rift Trickle\u0022, \u0022Phase Well\u0022, \u0022Folded Space Pump\u0022,\n\t\t\t\t\u0022Null Aquifer\u0022, \u0022Entropy Siphon\u0022, \u0022Singularity Draw\u0022,\n\t\t\t\t\u0022Event Horizon Tap\u0022, \u0022Vacuum Spring\u0022, \u0022The Hollow Between\u0022\n\t\t\t}\n\t\t},\n\t\tnew()\n\t\t{\n\t\t\tNumber = 12,\n\t\t\tName = \u0022Cosmic Wellspring\u0022,\n\t\t\tTagline = \u0022Comets are mostly ice, and there are rather a lot of them.\u0022,\n\t\t\tTint = new Color( 0.30f, 0.80f, 0.92f ),\n\t\t\tPumpNames = new[]\n\t\t\t{\n\t\t\t\t\u0022Comet Harpoon\u0022, \u0022Ring System Skimmer\u0022, \u0022Ice Moon Bore\u0022,\n\t\t\t\t\u0022Nebula Trawler\u0022, \u0022Rogue World Tap\u0022, \u0022Stellar Nursery Pump\u0022,\n\t\t\t\t\u0022Galactic Aqueduct\u0022, \u0022Dark Flow Intake\u0022, \u0022The Wellspring\u0022\n\t\t\t}\n\t\t},\n\t};\n\n\tpublic static int Count =\u003E All.Length;\n\n\t/// \u003Csummary\u003ETotal pumps across every tier.\u003C/summary\u003E\n\tpublic static int TotalPumps =\u003E Count * PumpsPerTier;\n\n\t/// \u003Csummary\u003ETier for a 0-based pump index.\u003C/summary\u003E\n\tpublic static PumpTier ForPump( int pumpIndex ) =\u003E\n\t\tAll[Math.Clamp( pumpIndex / PumpsPerTier, 0, Count - 1 )];\n\n\t/// \u003Csummary\u003ETier by its 1-12 number.\u003C/summary\u003E\n\tpublic static PumpTier Get( int number ) =\u003E All[Math.Clamp( number - 1, 0, Count - 1 )];\n}\n"},{"Ident":"fpkreastudios.desertpump","Path":"styles/base/_navigator.scss","FileName":"_navigator.scss","PackageType":"game","CodeKind":"Game","AssetVersionId":338006,"Code":".navigator-body\r\n{\r\n\t\u0026.hidden\r\n\t{\r\n\t\tdisplay: none;\r\n\t}\r\n}\r\n"},{"Ident":"fpkreastudios.desertpump","Path":"ui/components/packageflairbar.razor.scss","FileName":"packageflairbar.razor.scss","PackageType":"game","CodeKind":"Game","AssetVersionId":338006,"Code":"PackageFlairBar\r\n{\r\n\tposition: absolute;\r\n\ttop: 6px;\r\n\tleft: 6px;\r\n\tz-index: 2;\r\n\tflex-direction: row;\r\n\tgap: 5px;\r\n\tpointer-events: none;\r\n\r\n\t.flair\r\n\t{\r\n\t\tposition: relative;\r\n\t\talign-items: center;\r\n\t\tjustify-content: center;\r\n\t\twidth: 22px;\r\n\t\theight: 22px;\r\n\t\tpointer-events: all;\r\n\t\tborder-radius: 4px;\r\n\t\tcolor: white;\r\n\t\tborder: 1px solid rgba( white, 0.1 );\r\n\t\toutline: 1px solid #0006;\r\n\t\topacity: 0.7;\r\n\r\n\t\t\u0026:hover\r\n\t\t{\r\n\t\t\topacity: 1;\r\n\t\t}\r\n\r\n\t\ticon\r\n\t\t{\r\n\t\t\tfont-size: 15px;\r\n\t\t}\r\n\t}\r\n}\r\n"},{"Ident":"fpkreastudios.desertpump","Path":"styles/base.scss","FileName":"base.scss","PackageType":"game","CodeKind":"Game","AssetVersionId":338006,"Code":"@import \u0022base/_splitcontainer.scss\u0022;\r\n@import \u0022base/_navigator.scss\u0022;\r\n\r\nbutton\r\n{\r\n\tcursor: pointer;\r\n}\r\n\r\nIconPanel\r\n{\r\n\tfont-family: Material Icons;\r\n}\r\n\r\n.is-half\r\n{\r\n\twidth: 50%;\r\n}\r\n\r\n.is-third\r\n{\r\n\twidth: 33%;\r\n}\r\n\r\n.is-quarter\r\n{\r\n\twidth: 25%;\r\n}\r\n\r\nbutton.has-subtitle\r\n{\r\n\tposition: relative;\r\n\tflex-direction: column;\r\n\tjustify-content: flex-start;\r\n\talign-items: flex-start;\r\n\tpadding-left: 40px; // icon space\r\n\r\n\t.iconpanel\r\n\t{\r\n\t\tposition: absolute;\r\n\t\tleft: 5px;\r\n\t\ttop: 0;\r\n\t\tbottom: 0;\r\n\t\talign-items: center;\r\n\t}\r\n\r\n\t.button-label\r\n\t{\r\n\t\tfont-weight: bold;\r\n\t}\r\n\r\n\t.button-subtitle\r\n\t{\r\n\t\tfont-size: 12px;\r\n\t\topacity: 0.5;\r\n\t\tmix-blend-mode: lighten;\r\n\t}\r\n}"},{"Ident":"fpkreastudios.desertpump","Path":"ui/controls/color/coloralphacontrol.cs.scss","FileName":"coloralphacontrol.cs.scss","PackageType":"game","CodeKind":"Game","AssetVersionId":338006,"Code":"ColorAlphaControl\r\n{\r\n\tgap: 0.5rem;\r\n\tflex-grow: 1;\r\n\tpointer-events: all;\r\n\tbackground: linear-gradient( to right, black, white );\r\n\tborder-radius: 4px;\r\n\tpadding: 2px;\r\n\theight: 12px;\r\n\tposition: relative;\r\n\tcursor: pointer;\r\n\tborder: 1px solid #333;\r\n\r\n\t\u0026:hover\r\n\t{\r\n\t\tborder: 1px solid #08f;\r\n\t}\r\n\r\n\t\u0026:active\r\n\t{\r\n\t\tborder: 1px solid #fff;\r\n\t}\r\n\r\n\t.handle\r\n\t{\r\n\t\ttop: -5px;\r\n\t\tbottom: -5px;\r\n\t\taspect-ratio: 1;\r\n\t\tborder-radius: 100px;\r\n\t\tborder: 2px solid #444;\r\n\t\tposition: absolute;\r\n\t\tbackground-color: white;\r\n\t\tbox-shadow: 2px 2px 16px #000a;\r\n\t\ttransform: translateX( -50% );\r\n\t\tpointer-events: none;\r\n\t}\r\n}\r\n"},{"Ident":"fpkreastudios.desertpump","Path":"ui/controls/color/colorpickercontrol.cs.scss","FileName":"colorpickercontrol.cs.scss","PackageType":"game","CodeKind":"Game","AssetVersionId":338006,"Code":"ColorPickerControl\r\n{\r\n\tflex-direction: column;\r\n\tflex-shrink: 0;\r\n\tgap: 0.5rem;\r\n\tmargin: 1rem;\r\n}"},{"Ident":"fpkreastudios.desertpump","Path":"ui/components/packagelist.razor.scss","FileName":"packagelist.razor.scss","PackageType":"game","CodeKind":"Game","AssetVersionId":338006,"Code":".package-list\r\n{\r\n    flex-shrink: 1;\r\n    flex-wrap: wrap;\r\n    flex-grow: 1;\r\n\r\n    h1\r\n    {\r\n        width: 100%;\r\n        margin-top: 50px;\r\n        font-size: 40px;\r\n    }\r\n\r\n    PackageCard\r\n    {\r\n        \u0026:hover\r\n        {\r\n            sound-in: \u0022ui.button.over\u0022;\r\n        }\r\n    }\r\n\r\n    VirtualGrid\r\n    {\r\n        width: 100%;\r\n        height: 100%;\r\n\r\n        .cell\r\n        {\r\n            \r\n        }\r\n    }\r\n}"},{"Ident":"fpkreastudios.desertpump","Path":"ui/treepanel.razor.scss","FileName":"treepanel.razor.scss","PackageType":"game","CodeKind":"Game","AssetVersionId":338006,"Code":"$gold: #f5c542;\r\n$panel: #1b2130;\r\n\r\n.treepanel\r\n{\r\n\tposition: absolute;\r\n\ttop: 0;\r\n\tleft: 0;\r\n\twidth: 100%;\r\n\theight: 100%;\r\n\talign-items: center;\r\n\tjustify-content: center;\r\n\tpointer-events: all;\r\n\r\n\t// Same reason as the shop - without this the HUD paints through the sheet.\r\n\tz-index: 100;\r\n\tfont-family: Poppins;\r\n\tcolor: white;\r\n\r\n\t.scrim\r\n\t{\r\n\t\tposition: absolute;\r\n\t\ttop: 0;\r\n\t\tleft: 0;\r\n\t\twidth: 100%;\r\n\t\theight: 100%;\r\n\t\tbackground-color: rgba( 8, 10, 16, 0.65 );\r\n\t\tpointer-events: all;\r\n\t}\r\n\r\n\t.sheet\r\n\t{\r\n\t\twidth: 560px;\r\n\t\tmax-width: 92%;\r\n\t\tmax-height: 90%;\r\n\t\tflex-direction: column;\r\n\t\tbackground-color: $panel;\r\n\t\tborder-radius: 24px;\r\n\t\tpadding: 22px;\r\n\t\tborder-bottom: 6px solid rgba( 0, 0, 0, 0.4 );\r\n\t\tpointer-events: all;\r\n\t}\r\n\r\n\t.head\r\n\t{\r\n\t\talign-items: center;\r\n\t\tmargin-bottom: 14px;\r\n\r\n\t\t.title\r\n\t\t{\r\n\t\t\tflex-grow: 1;\r\n\t\t\tfont-size: 24px;\r\n\t\t\tfont-weight: 800;\r\n\t\t\tletter-spacing: 2px;\r\n\t\t\talign-items: center;\r\n\r\n\t\t\ti\r\n\t\t\t{\r\n\t\t\t\tfont-family: Material Icons;\r\n\t\t\t\tfont-size: 28px;\r\n\t\t\t\tmargin-right: 10px;\r\n\t\t\t\tcolor: $gold;\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\t.closebtn\r\n\t\t{\r\n\t\t\twidth: 44px;\r\n\t\t\theight: 44px;\r\n\t\t\tborder-radius: 12px;\r\n\t\t\tbackground-color: rgba( 255, 255, 255, 0.08 );\r\n\t\t\talign-items: center;\r\n\t\t\tjustify-content: center;\r\n\t\t\tcursor: pointer;\r\n\t\t\tpointer-events: all;\r\n\r\n\t\t\ti { font-family: Material Icons; font-size: 24px; }\r\n\r\n\t\t\t\u0026:hover { background-color: rgba( 255, 255, 255, 0.18 ); }\r\n\t\t}\r\n\t}\r\n\r\n\t.note\r\n\t{\r\n\t\tfont-size: 13px;\r\n\t\topacity: 0.7;\r\n\t\tbackground-color: rgba( 255, 255, 255, 0.05 );\r\n\t\tborder-radius: 12px;\r\n\t\tpadding: 10px 14px;\r\n\t\tmargin-bottom: 12px;\r\n\t}\r\n\r\n\t.rows\r\n\t{\r\n\t\tflex-direction: column;\r\n\t\toverflow-y: scroll;\r\n\t}\r\n\r\n\t.lbrow\r\n\t{\r\n\t\talign-items: center;\r\n\t\tbackground-color: rgba( 255, 255, 255, 0.05 );\r\n\t\tborder-radius: 14px;\r\n\t\tpadding: 12px 16px;\r\n\t\tmargin-bottom: 8px;\r\n\t\tborder: 2px solid rgba( 0, 0, 0, 0 );\r\n\r\n\t\t.rank\r\n\t\t{\r\n\t\t\twidth: 44px;\r\n\t\t\tfont-size: 20px;\r\n\t\t\tfont-weight: 800;\r\n\t\t\topacity: 0.7;\r\n\t\t}\r\n\r\n\t\t.who\r\n\t\t{\r\n\t\t\tflex-grow: 1;\r\n\t\t\tfont-size: 17px;\r\n\t\t}\r\n\r\n\t\t.score\r\n\t\t{\r\n\t\t\tfont-size: 20px;\r\n\t\t\tfont-weight: 700;\r\n\t\t\talign-items: center;\r\n\r\n\t\t\t.num { font-size: 20px; font-weight: 700; }\r\n\r\n\t\t\t.unit\r\n\t\t\t{\r\n\t\t\t\tfont-size: 12px;\r\n\t\t\t\topacity: 0.6;\r\n\t\t\t\tmargin-left: 6px;\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\t\u0026.gold .rank { color: $gold; opacity: 1; }\r\n\t\t\u0026.silver .rank { color: #cfd6e4; opacity: 1; }\r\n\t\t\u0026.bronze .rank { color: #d09a5c; opacity: 1; }\r\n\r\n\t\t\u0026.me\r\n\t\t{\r\n\t\t\tborder-color: #7fd06f;\r\n\t\t\tbackground-color: rgba( 127, 208, 111, 0.12 );\r\n\t\t}\r\n\t}\r\n\r\n\t.refresh\r\n\t{\r\n\t\talign-self: center;\r\n\t\tmargin-top: 8px;\r\n\t\tpadding: 10px 28px;\r\n\t\tborder-radius: 12px;\r\n\t\tbackground-color: rgba( 255, 255, 255, 0.08 );\r\n\t\tfont-size: 14px;\r\n\t\tfont-weight: 700;\r\n\t\tletter-spacing: 1px;\r\n\t\talign-items: center;\r\n\t\tcursor: pointer;\r\n\t\tpointer-events: all;\r\n\r\n\t\ti\r\n\t\t{\r\n\t\t\tfont-family: Material Icons;\r\n\t\t\tfont-size: 18px;\r\n\t\t\tmargin-right: 8px;\r\n\t\t}\r\n\r\n\t\t\u0026:hover { background-color: rgba( 255, 255, 255, 0.16 ); }\r\n\t}\r\n}\r\n"},{"Ident":"fpkreastudios.desertpump","Path":"UI/TreePanel.razor","FileName":"TreePanel.razor","PackageType":"game","CodeKind":"Game","AssetVersionId":338006,"Code":"@using System\r\n@using Sandbox\r\n@using Sandbox.UI\r\n@namespace DesertPump\r\n@inherits Panel\r\n\r\n\u003Croot class=\u0022treepanel\u0022\u003E\r\n\r\n\t\u003Cdiv class=\u0022scrim\u0022 onclick=\u0022@Close\u0022\u003E\u003C/div\u003E\r\n\r\n\t\u003Cdiv class=\u0022sheet\u0022\u003E\r\n\r\n\t\t\u003Cdiv class=\u0022head\u0022\u003E\r\n\t\t\t\u003Cdiv class=\u0022title\u0022\u003E\u003Ci\u003Eemoji_events\u003C/i\u003E TALLEST TREES\u003C/div\u003E\r\n\t\t\t\u003Cdiv class=\u0022closebtn\u0022 onclick=\u0022@Close\u0022\u003E\u003Ci\u003Eclose\u003C/i\u003E\u003C/div\u003E\r\n\t\t\u003C/div\u003E\r\n\r\n\t\t@if ( Leaderboard.Fetching )\r\n\t\t{\r\n\t\t\t\u003Cdiv class=\u0022note\u0022\u003ELoading the board...\u003C/div\u003E\r\n\t\t}\r\n\t\telse if ( !string.IsNullOrEmpty( Leaderboard.Status ) )\r\n\t\t{\r\n\t\t\t\u003Cdiv class=\u0022note\u0022\u003E@Leaderboard.Status\u003C/div\u003E\r\n\t\t}\r\n\r\n\t\t\u003Cdiv class=\u0022rows\u0022\u003E\r\n\t\t\t@foreach ( var row in Leaderboard.Entries )\r\n\t\t\t{\r\n\t\t\t\t\u003Cdiv class=\u0022lbrow @( row.IsMe ? \u0022me\u0022 : \u0022\u0022 ) @RankClass( row.Rank )\u0022\u003E\r\n\t\t\t\t\t\u003Cdiv class=\u0022rank\u0022\u003E@row.Rank\u003C/div\u003E\r\n\t\t\t\t\t\u003Cdiv class=\u0022who\u0022\u003E@row.Name\u003C/div\u003E\r\n\t\t\t\t\t\u003Cdiv class=\u0022score\u0022\u003E\u003Cspan class=\u0022num\u0022\u003E@row.Height\u003C/span\u003E\u003Cspan class=\u0022unit\u0022\u003Estages\u003C/span\u003E\u003C/div\u003E\r\n\t\t\t\t\u003C/div\u003E\r\n\t\t\t}\r\n\t\t\u003C/div\u003E\r\n\r\n\t\t\u003Cdiv class=\u0022refresh\u0022 onclick=\u0022@Reload\u0022\u003E\r\n\t\t\t\u003Ci\u003Erefresh\u003C/i\u003E REFRESH\r\n\t\t\u003C/div\u003E\r\n\r\n\t\u003C/div\u003E\r\n\r\n\u003C/root\u003E\r\n\r\n@code\r\n{\r\n\tpublic Action OnClose { get; set; }\r\n\r\n\tstatic DesertPumpGame Game =\u003E DesertPumpGame.Current;\r\n\r\n\tprotected override void OnAfterTreeRender( bool firstTime )\r\n\t{\r\n\t\tbase.OnAfterTreeRender( firstTime );\r\n\r\n\t\tif ( firstTime ) Reload();\r\n\t}\r\n\r\n\tvoid Reload()\r\n\t{\r\n\t\tvar name = Connection.Local?.DisplayName;\r\n\t\tif ( string.IsNullOrWhiteSpace( name ) ) name = \u0022You\u0022;\r\n\r\n\t\t_ = Leaderboard.Refresh( Game?.TreeHeight ?? 0, name );\r\n\t\tStateHasChanged();\r\n\t}\r\n\r\n\tstatic string RankClass( int rank ) =\u003E rank switch\r\n\t{\r\n\t\t1 =\u003E \u0022gold\u0022,\r\n\t\t2 =\u003E \u0022silver\u0022,\r\n\t\t3 =\u003E \u0022bronze\u0022,\r\n\t\t_ =\u003E string.Empty\r\n\t};\r\n\r\n\tvoid Close() =\u003E OnClose?.Invoke();\r\n\r\n\tprotected override int BuildHash() =\u003E HashCode.Combine(\r\n\t\tLeaderboard.Entries.Count, Leaderboard.Fetching, Leaderboard.Status, Game?.TreeHeight ?? 0 );\r\n}\r\n"},{"Ident":"fpkreastudios.desertpump","Path":"styles/form/_dropdown.scss","FileName":"_dropdown.scss","PackageType":"game","CodeKind":"Game","AssetVersionId":338006,"Code":"\r\n$primary: red !default;\r\n$primary-alt: white !default;\r\n\r\n$switch-padding: 6px !default;\r\n\r\n.button.popupbutton.dropdown\r\n{\r\n\tcursor: pointer;\r\n\ttransition: all .1s ease-out;\r\n\tposition: relative;\r\n\r\n\t\u003E .dropdown_indicator\r\n\t{\r\n\t\tposition: absolute;\r\n\t\tright: 8px;\r\n\t}\r\n\r\n\t\u0026.open\r\n\t{\r\n\t\tborder-bottom-left-radius: 1px;\r\n\t\tborder-bottom-right-radius: 1px;\r\n\t\ttransition: border-radius 0.2s ease-out;\r\n\t}\r\n}\r\n\r\nselect\r\n{\r\n\tmin-height: 40px;\r\n\r\n\t\u003E option\r\n\t{\r\n\t\tdisplay: none;\r\n\t}\r\n}"},{"Ident":"fpkreastudios.desertpump","Path":"ui/controlsheet/controlsheetgroupheader.cs.scss","FileName":"controlsheetgroupheader.cs.scss","PackageType":"game","CodeKind":"Game","AssetVersionId":338006,"Code":"ControlSheetGroupHeader\r\n{\r\n\tfont-size: 1.33rem;\r\n\tcolor: red;\r\n\tgap: 2px;\r\n\talign-items: center;\r\n\r\n\t\u0026.hidden\r\n\t{\r\n\t\tdisplay: none;\r\n\t}\r\n\r\n\t\u003E .title\r\n\t{\r\n\t\tfont-weight: 600;\r\n\t}\r\n\r\n\t\u0026.has-toggle\r\n\t{\r\n\t\tcursor: pointer;\r\n\t\topacity: 0.8;\r\n\r\n\t\t\u0026:before\r\n\t\t{\r\n\t\t\tcontent: \u0027 \u0027;\r\n\t\t\twidth: 22px;\r\n\t\t\theight: 22px;\r\n\t\t\tbackground-color: #000a;\r\n\t\t\talign-items: center;\r\n\t\t\tjustify-content: center;\r\n\t\t\ttext-align: center;\r\n\t\t\tborder-radius: 5px;\r\n\t\t\tborder: 1px solid #555;\r\n\t\t}\r\n\r\n\t\t\u0026:hover\r\n\t\t{\r\n\t\t\topacity: 1;\r\n\r\n\t\t\t\u0026:before\r\n\t\t\t{\r\n\t\t\t\tborder-color: #888;\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\t\u0026.checked\r\n\t\t{\r\n\t\t\t\u003E .title\r\n\t\t\t{\r\n\t\t\t\tcolor: white;\r\n\t\t\t}\r\n\r\n\t\t\t\u0026:before\r\n\t\t\t{\r\n\t\t\t\tcontent: \u0027\u2713\u0027;\r\n\t\t\t\tfont-weight: bold;\r\n\t\t\t\tcolor: #08f;\r\n\t\t\t\tborder-color: #08f;\r\n\t\t\t}\r\n\t\t}\r\n\t}\r\n}\r\n"},{"Ident":"fpkreastudios.desertpump","Path":"ui/dropdown.cs.scss","FileName":"dropdown.cs.scss","PackageType":"game","CodeKind":"Game","AssetVersionId":338006,"Code":".dropdown\r\n{\r\n\tgap: 2px;\r\n\tflex-grow: 1;\r\n\tcursor: pointer;\r\n\tjustify-content: flex-end;\r\n\talign-items: center;\r\n\tpadding: 0px 12px;\r\n\r\n\t.button-right-column\r\n\t{\r\n\t\tflex-grow: 1;\r\n\t}\r\n}\r\n"},{"Ident":"fpkreastudios.desertpump","Path":"ui/gamehud.razor.scss","FileName":"gamehud.razor.scss","PackageType":"game","CodeKind":"Game","AssetVersionId":338006,"Code":"$sand: #e8bd7a;\r\n$sand-dark: #cf9a4c;\r\n$panel: rgba( 18, 22, 32, 0.72 );\r\n$gold: #f5c542;\r\n$water: #4fb0e8;\r\n\r\n.hud\r\n{\r\n\tposition: absolute;\r\n\ttop: 0;\r\n\tleft: 0;\r\n\twidth: 100%;\r\n\theight: 100%;\r\n\tflex-direction: column;\r\n\tfont-family: Poppins;\r\n\tcolor: white;\r\n\toverflow: hidden;\r\n\r\n\t// s\u0026box does not inherit pointer-events down the tree and the screen root starts\r\n\t// as \u0022none\u0022, so every clickable element sets \u0022all\u0022 for itself. Setting it here\r\n\t// only would leave the whole UI dead to the mouse.\r\n\tpointer-events: all;\r\n}\r\n\r\n// ---------------------------------------------------------------- background\r\n\r\n// Backdrop layers never take the mouse - they sit under the whole screen and would\r\n// otherwise swallow clicks meant for the pump.\r\n.sky,\r\n.sun,\r\n.dune,\r\n.floor\r\n{\r\n\tpointer-events: none;\r\n}\r\n\r\n// The rows that hold clickable things, in case the engine wants the whole ancestor\r\n// chain live rather than inheriting from .hud.\r\n.topbar,\r\n.stage,\r\n.actions,\r\n.collection\r\n{\r\n\tpointer-events: all;\r\n}\r\n\r\n.sky\r\n{\r\n\tposition: absolute;\r\n\ttop: 0;\r\n\tleft: 0;\r\n\twidth: 100%;\r\n\theight: 100%;\r\n\tbackground-image: linear-gradient( to bottom, #4aa3d8 0%, #8fd0ea 38%, #f4d69c 70%, #e9b264 100% );\r\n}\r\n\r\n.sun\r\n{\r\n\tposition: absolute;\r\n\ttop: 70px;\r\n\tright: 160px;\r\n\twidth: 170px;\r\n\theight: 170px;\r\n\tborder-radius: 100%;\r\n\tbackground-color: #ffd84d;\r\n\tbox-shadow: 0px 0px 90px 30px rgba( 255, 216, 77, 0.35 );\r\n}\r\n\r\n// Wide flat ellipses - only the top curve shows, which reads as a dune ridge.\r\n.dune\r\n{\r\n\tposition: absolute;\r\n\tborder-radius: 50%;\r\n\r\n\t\u0026.far\r\n\t{\r\n\t\tleft: -34%;\r\n\t\twidth: 105%;\r\n\t\tbottom: 14%;\r\n\t\theight: 26%;\r\n\t\tbackground-color: $sand;\r\n\t}\r\n\r\n\t\u0026.near\r\n\t{\r\n\t\tleft: 28%;\r\n\t\twidth: 105%;\r\n\t\tbottom: 12%;\r\n\t\theight: 24%;\r\n\t\tbackground-color: $sand;\r\n\t}\r\n}\r\n\r\n// A very wide ellipse, so the horizon is a gentle curve. As a plain rectangle its\r\n// top edge cut a hard straight line across the sky wherever no dune covered it.\r\n.floor\r\n{\r\n\tposition: absolute;\r\n\tbottom: -34%;\r\n\tleft: -25%;\r\n\twidth: 150%;\r\n\theight: 70%;\r\n\tborder-radius: 50%;\r\n\tbackground-color: $sand-dark;\r\n}\r\n\r\n// ---------------------------------------------------------------- top bar\r\n\r\n.topbar\r\n{\r\n\theight: 96px;\r\n\talign-items: center;\r\n\tpadding-left: 28px;\r\n\tpadding-right: 28px;\r\n\tflex-shrink: 0;\r\n}\r\n\r\n.stat\r\n{\r\n\tbackground-color: $panel;\r\n\tborder-radius: 18px;\r\n\tpadding: 10px 18px;\r\n\talign-items: center;\r\n\tmargin-right: 16px;\r\n}\r\n\r\n.coins\r\n{\r\n\t.coin\r\n\t{\r\n\t\twidth: 32px;\r\n\t\theight: 32px;\r\n\t\tborder-radius: 100%;\r\n\t\tbackground-color: $gold;\r\n\t\tborder: 3px solid #a8791a;\r\n\t\tmargin-right: 10px;\r\n\t}\r\n\r\n\t.value\r\n\t{\r\n\t\tfont-size: 30px;\r\n\t\tfont-weight: 700;\r\n\t}\r\n}\r\n\r\n.tankstat\r\n{\r\n\t.tank\r\n\t{\r\n\t\twidth: 26px;\r\n\t\theight: 54px;\r\n\t\tborder-radius: 8px;\r\n\t\tbackground-color: rgba( 255, 255, 255, 0.16 );\r\n\t\tborder: 2px solid rgba( 255, 255, 255, 0.45 );\r\n\t\tmargin-right: 12px;\r\n\t\tflex-direction: column;\r\n\t\tjustify-content: flex-end;\r\n\t\toverflow: hidden;\r\n\t}\r\n\r\n\t.tank-fill\r\n\t{\r\n\t\twidth: 100%;\r\n\t\tbackground-color: $water;\r\n\t\ttransition: height 0.12s linear;\r\n\t}\r\n\r\n\t.tank-text\r\n\t{\r\n\t\tflex-direction: column;\r\n\t}\r\n\r\n\t.value\r\n\t{\r\n\t\tfont-size: 22px;\r\n\t\tfont-weight: 600;\r\n\t}\r\n\r\n\t.unit\r\n\t{\r\n\t\tfont-size: 15px;\r\n\t\topacity: 0.7;\r\n\t}\r\n\r\n\t.sub\r\n\t{\r\n\t\tfont-size: 13px;\r\n\t\topacity: 0.65;\r\n\t}\r\n\r\n\t\u0026.full .tank-fill\r\n\t{\r\n\t\tbackground-color: #ff8b4a;\r\n\t}\r\n\r\n\t\u0026.full .sub\r\n\t{\r\n\t\tcolor: #ffb37a;\r\n\t\topacity: 1;\r\n\t}\r\n}\r\n\r\n.spacer\r\n{\r\n\tflex-grow: 1;\r\n}\r\n\r\n.iconbutton\r\n{\r\n\twidth: 56px;\r\n\theight: 56px;\r\n\tborder-radius: 14px;\r\n\tbackground-color: $panel;\r\n\talign-items: center;\r\n\tjustify-content: center;\r\n\tcursor: pointer;\r\n\tpointer-events: all;\r\n\r\n\ti\r\n\t{\r\n\t\tfont-family: Material Icons;\r\n\t\tfont-size: 30px;\r\n\t}\r\n\r\n\t\u0026:hover\r\n\t{\r\n\t\tbackground-color: rgba( 40, 48, 64, 0.9 );\r\n\t}\r\n\r\n\t\u0026.muted\r\n\t{\r\n\t\tbackground-color: rgba( 200, 110, 40, 0.85 );\r\n\t}\r\n}\r\n\r\n// ---------------------------------------------------------------- stage\r\n\r\n.stage\r\n{\r\n\tflex-grow: 1;\r\n\tflex-direction: column;\r\n\talign-items: center;\r\n\tjustify-content: center;\r\n\tposition: relative;\r\n}\r\n\r\n.pumparea\r\n{\r\n\twidth: 330px;\r\n\theight: 330px;\r\n\talign-items: center;\r\n\tjustify-content: center;\r\n\tposition: relative;\r\n\tcursor: pointer;\r\n\tpointer-events: all;\r\n\ttransition: transform 0.07s ease-out;\r\n\r\n\t.pumpart\r\n\t{\r\n\t\twidth: 100%;\r\n\t\theight: 100%;\r\n\t}\r\n\r\n\t.glow\r\n\t{\r\n\t\tposition: absolute;\r\n\t\twidth: 78%;\r\n\t\theight: 78%;\r\n\t\tborder-radius: 100%;\r\n\t\tbackground-color: rgba( 255, 255, 255, 0.14 );\r\n\t}\r\n\r\n\t.ground\r\n\t{\r\n\t\tposition: absolute;\r\n\t\tbottom: 2%;\r\n\t\twidth: 70%;\r\n\t\theight: 8%;\r\n\t\tborder-radius: 50%;\r\n\t\tbackground-color: rgba( 90, 60, 20, 0.22 );\r\n\t}\r\n\r\n\t\u0026:hover\r\n\t{\r\n\t\ttransform: scale( 1.03 );\r\n\t}\r\n\r\n\t\u0026.pumping\r\n\t{\r\n\t\ttransform: scale( 0.93 );\r\n\t}\r\n\r\n\t\u0026.full .glow\r\n\t{\r\n\t\tbackground-color: rgba( 255, 140, 60, 0.25 );\r\n\t}\r\n}\r\n\r\n.nameplate\r\n{\r\n\tflex-direction: column;\r\n\talign-items: center;\r\n\tmargin-top: 4px;\r\n\tpadding: 10px 30px 14px 30px;\r\n\tborder-radius: 22px;\r\n\tbackground-color: rgba( 16, 20, 30, 0.38 );\r\n\r\n\t.tierno\r\n\t{\r\n\t\tfont-size: 14px;\r\n\t\tletter-spacing: 3px;\r\n\t\topacity: 1;\r\n\t\ttext-shadow: 0px 2px 0px rgba( 0, 0, 0, 0.6 );\r\n\t}\r\n\r\n\t.name\r\n\t{\r\n\t\tfont-size: 40px;\r\n\t\tfont-weight: 800;\r\n\t\ttext-shadow: 0px 3px 0px rgba( 0, 0, 0, 0.35 );\r\n\t}\r\n\r\n\t.tagline\r\n\t{\r\n\t\tfont-size: 16px;\r\n\t\topacity: 1;\r\n\t\ttext-shadow: 0px 2px 0px rgba( 0, 0, 0, 0.55 );\r\n\t}\r\n\r\n\t.perclick\r\n\t{\r\n\t\tmargin-top: 8px;\r\n\t\tfont-size: 15px;\r\n\t\tbackground-color: rgba( 18, 22, 32, 0.55 );\r\n\t\tpadding: 4px 16px;\r\n\t\tborder-radius: 999px;\r\n\t}\r\n}\r\n\r\n.floater\r\n{\r\n\tposition: absolute;\r\n\tleft: 50%;\r\n\tfont-size: 30px;\r\n\tfont-weight: 800;\r\n\tcolor: #d3f0ff;\r\n\ttext-shadow: 0px 2px 0px rgba( 0, 0, 0, 0.45 );\r\n\tpointer-events: none;\r\n\r\n\t\u0026.coin\r\n\t{\r\n\t\tcolor: $gold;\r\n\t}\r\n}\r\n\r\n.toast\r\n{\r\n\tposition: absolute;\r\n\tbottom: 13%;\r\n\tbackground-color: rgba( 18, 22, 32, 0.85 );\r\n\tpadding: 10px 22px;\r\n\tborder-radius: 999px;\r\n\tfont-size: 18px;\r\n\tpointer-events: none;\r\n}\r\n\r\n.idlenote\r\n{\r\n\tposition: absolute;\r\n\ttop: 5%;\r\n\tbackground-color: rgba( 30, 90, 130, 0.85 );\r\n\tpadding: 8px 20px;\r\n\tborder-radius: 999px;\r\n\tfont-size: 16px;\r\n\tpointer-events: none;\r\n}\r\n\r\n// Scoped to the stage on purpose - as a bare \u0022.hint\u0022 this rule reached into the\r\n// settings panel and threw its sub-labels to the bottom of the screen.\r\n.stage .hint\r\n{\r\n\tposition: absolute;\r\n\tbottom: 4%;\r\n\tfont-size: 14px;\r\n\tletter-spacing: 2px;\r\n\topacity: 1;\r\n\tpadding: 5px 16px;\r\n\tborder-radius: 999px;\r\n\tbackground-color: rgba( 16, 20, 30, 0.38 );\r\n\tpointer-events: none;\r\n}\r\n\r\n// ---------------------------------------------------------------- actions\r\n\r\n.actions\r\n{\r\n\theight: 130px;\r\n\talign-items: center;\r\n\tjustify-content: center;\r\n\tflex-shrink: 0;\r\n}\r\n\r\n.bigbutton\r\n{\r\n\twidth: 420px;\r\n\theight: 92px;\r\n\tborder-radius: 22px;\r\n\talign-items: center;\r\n\tpadding: 0px 24px;\r\n\tmargin: 0px 12px;\r\n\tcursor: pointer;\r\n\tpointer-events: all;\r\n\ttransition: transform 0.07s ease-out;\r\n\tborder-bottom: 6px solid rgba( 0, 0, 0, 0.35 );\r\n\r\n\t.btn-icon i\r\n\t{\r\n\t\tfont-family: Material Icons;\r\n\t\tfont-size: 40px;\r\n\t\tmargin-right: 16px;\r\n\t}\r\n\r\n\t.btn-text\r\n\t{\r\n\t\tflex-direction: column;\r\n\t}\r\n\r\n\t.btn-title\r\n\t{\r\n\t\tfont-size: 23px;\r\n\t\tfont-weight: 800;\r\n\t}\r\n\r\n\t.btn-sub\r\n\t{\r\n\t\tfont-size: 16px;\r\n\t\topacity: 0.85;\r\n\t}\r\n\r\n\t\u0026:hover\r\n\t{\r\n\t\ttransform: translateY( -3px );\r\n\t}\r\n\r\n\t\u0026:active\r\n\t{\r\n\t\ttransform: translateY( 2px );\r\n\t}\r\n\r\n\t\u0026.sell\r\n\t{\r\n\t\tbackground-color: #3aa7e0;\r\n\t}\r\n\r\n\t\u0026.buy\r\n\t{\r\n\t\tbackground-color: #f0a92c;\r\n\t}\r\n\r\n\t\u0026.maxed\r\n\t{\r\n\t\tbackground-color: #7a5cc4;\r\n\t\tcursor: default;\r\n\t}\r\n\r\n\t\u0026.disabled\r\n\t{\r\n\t\tbackground-color: #5f6675;\r\n\t\topacity: 0.65;\r\n\t\tcursor: default;\r\n\r\n\t\t\u0026:hover\r\n\t\t{\r\n\t\t\ttransform: translateY( 0px );\r\n\t\t}\r\n\t}\r\n}\r\n\r\n// ---------------------------------------------------------------- collection\r\n\r\n.collection\r\n{\r\n\theight: 170px;\r\n\talign-items: center;\r\n\tjustify-content: center;\r\n\tpadding-bottom: 14px;\r\n\tflex-shrink: 0;\r\n}\r\n\r\n.slot\r\n{\r\n\twidth: 118px;\r\n\theight: 142px;\r\n\tmargin: 0px 6px;\r\n\tpadding: 8px;\r\n\tflex-direction: column;\r\n\talign-items: center;\r\n\tjustify-content: flex-end;\r\n\tborder-radius: 16px;\r\n\tbackground-color: rgba( 18, 22, 32, 0.4 );\r\n\tborder: 3px solid rgba( 0, 0, 0, 0 );\r\n\r\n\t.slotart\r\n\t{\r\n\t\twidth: 100%;\r\n\t\theight: 92px;\r\n\t\tposition: relative;\r\n\t\talign-items: center;\r\n\t\tjustify-content: center;\r\n\t}\r\n\r\n\t.question\r\n\t{\r\n\t\tposition: absolute;\r\n\t\tfont-size: 38px;\r\n\t\tfont-weight: 800;\r\n\t\tcolor: rgba( 255, 255, 255, 0.7 );\r\n\t}\r\n\r\n\t.slotlabel\r\n\t{\r\n\t\tmargin-top: 4px;\r\n\t\tfont-size: 12px;\r\n\t\ttext-align: center;\r\n\t\topacity: 0.9;\r\n\t}\r\n\r\n\t\u0026.owned\r\n\t{\r\n\t\tbackground-color: rgba( 42, 92, 60, 0.5 );\r\n\t}\r\n\r\n\t\u0026.next\r\n\t{\r\n\t\tborder-color: $gold;\r\n\t}\r\n}\r\n\r\n// ---------------------------------------------------------------- fallback\r\n\r\n.missing\r\n{\r\n\tposition: absolute;\r\n\ttop: 40%;\r\n\tleft: 50%;\r\n\tmargin-left: -260px;\r\n\twidth: 520px;\r\n\tflex-direction: column;\r\n\talign-items: center;\r\n\tbackground-color: rgba( 18, 22, 32, 0.85 );\r\n\tborder-radius: 18px;\r\n\tpadding: 24px;\r\n\r\n\t.missing-title\r\n\t{\r\n\t\tfont-size: 22px;\r\n\t\tfont-weight: 700;\r\n\t}\r\n\r\n\t.missing-body\r\n\t{\r\n\t\tfont-size: 15px;\r\n\t\topacity: 0.8;\r\n\t\tmargin-top: 6px;\r\n\t}\r\n}\r\n\r\n// ---------------------------------------------------------------- scenery\r\n\r\n// Extra layers the default scene doesn\u0027t use - each background switches them on.\r\n.stars,\r\n.scenery\r\n{\r\n\tposition: absolute;\r\n\tpointer-events: none;\r\n}\r\n\r\n.stars\r\n{\r\n\ttop: 0;\r\n\tleft: 0;\r\n\twidth: 100%;\r\n\theight: 60%;\r\n\topacity: 0;\r\n}\r\n\r\n.scenery\r\n{\r\n\tbottom: 0;\r\n\tleft: 0;\r\n\twidth: 100%;\r\n\theight: 40%;\r\n\topacity: 0;\r\n}\r\n\r\n// ---- Blood Moon: night dunes under something large and red\r\n\r\n.scene-dusk\r\n{\r\n\t.sky { background-image: linear-gradient( to bottom, #150a24 0%, #241436 40%, #5c2536 78%, #8c3a35 100% ); }\r\n\r\n\t.sun\r\n\t{\r\n\t\tbackground-color: #d94f43;\r\n\t\tbox-shadow: 0px 0px 120px 40px rgba( 217, 79, 67, 0.4 );\r\n\t\twidth: 210px;\r\n\t\theight: 210px;\r\n\t}\r\n\r\n\t.dune.far { background-color: #45283f; }\r\n\t.dune.near { background-color: #45283f; }\r\n\t.floor { background-color: #2c1a2c; }\r\n\r\n\t// a scatter of stars, faked with a few hard-stop gradients\r\n\t.stars\r\n\t{\r\n\t\topacity: 0.9;\r\n\t\tbackground-image: linear-gradient( to bottom, rgba( 255, 255, 255, 0.16 ) 0%, rgba( 255, 255, 255, 0 ) 70% );\r\n\t}\r\n\r\n\t.nameplate .name { text-shadow: 0px 3px 0px rgba( 0, 0, 0, 0.55 ); }\r\n}\r\n\r\n// ---- Green Oasis: you pumped enough that things started growing\r\n\r\n.scene-oasis\r\n{\r\n\t.sky { background-image: linear-gradient( to bottom, #2f8fbf 0%, #6fc6c2 45%, #a9d98d 80%, #6ea84e 100% ); }\r\n\r\n\t.sun\r\n\t{\r\n\t\tbackground-color: #fff2a8;\r\n\t\tbox-shadow: 0px 0px 100px 34px rgba( 255, 242, 168, 0.45 );\r\n\t}\r\n\r\n\t.dune.far { background-color: #67ab55; }\r\n\t.dune.near { background-color: #4f8f3a; }\r\n\t.floor { background-color: #3d7330; }\r\n\r\n\t.scenery\r\n\t{\r\n\t\topacity: 1;\r\n\t\tbackground-image: linear-gradient( to top, rgba( 40, 90, 40, 0.55 ) 0%, rgba( 40, 90, 40, 0 ) 55% );\r\n\t}\r\n}\r\n\r\n// ---- Neon Wastes: the desert, some time after everyone left\r\n\r\n.scene-neon\r\n{\r\n\t.sky { background-image: linear-gradient( to bottom, #12042a 0%, #2a0b45 42%, #7b2062 76%, #ff5fa2 100% ); }\r\n\r\n\t.sun\r\n\t{\r\n\t\tbackground-color: #ff7ac6;\r\n\t\tbox-shadow: 0px 0px 140px 46px rgba( 255, 95, 162, 0.45 );\r\n\t\twidth: 220px;\r\n\t\theight: 220px;\r\n\t}\r\n\r\n\t.dune.far { background-color: #35114f; }\r\n\t.dune.near { background-color: #24093a; }\r\n\t.floor { background-color: #160526; }\r\n\r\n\t.stars\r\n\t{\r\n\t\topacity: 0.8;\r\n\t\tbackground-image: linear-gradient( to bottom, rgba( 255, 255, 255, 0.12 ) 0%, rgba( 255, 255, 255, 0 ) 65% );\r\n\t}\r\n\r\n\t// horizon glow standing in for a synth grid\r\n\t.scenery\r\n\t{\r\n\t\topacity: 1;\r\n\t\tbackground-image: linear-gradient( to top, rgba( 255, 95, 162, 0.35 ) 0%, rgba( 255, 95, 162, 0 ) 40% );\r\n\t}\r\n\r\n\t.nameplate .name { color: #ffd9ec; }\r\n}\r\n\r\n// ---------------------------------------------------------------- tier bar\r\n\r\n.tierbar\r\n{\r\n\twidth: 260px;\r\n\theight: 8px;\r\n\tborder-radius: 999px;\r\n\tbackground-color: rgba( 0, 0, 0, 0.45 );\r\n\tborder: 1px solid rgba( 255, 255, 255, 0.25 );\r\n\tmargin-top: 10px;\r\n\toverflow: hidden;\r\n}\r\n\r\n.tierfill\r\n{\r\n\theight: 100%;\r\n\tbackground-color: $gold;\r\n\ttransition: width 0.2s ease-out;\r\n}\r\n\r\n// ---------------------------------------------------------------- gusher\r\n\r\n.gusher\r\n{\r\n\tposition: absolute;\r\n\twidth: 96px;\r\n\theight: 96px;\r\n\tmargin-left: -48px;\r\n\tmargin-top: -48px;\r\n\talign-items: center;\r\n\tjustify-content: center;\r\n\tcursor: pointer;\r\n\tpointer-events: all;\r\n\tanimation: gusher-bob 1.6s ease-in-out infinite;\r\n\r\n\t// Teardrop rather than a disc, and blue-white rather than yellow - as a glowing\r\n\t// yellow circle it was indistinguishable from the sun behind it.\r\n\t.gusher-drop\r\n\t{\r\n\t\twidth: 46px;\r\n\t\theight: 58px;\r\n\t\tborder-radius: 50% 50% 50% 50%;\r\n\t\tbackground-image: linear-gradient( to bottom, #eaf9ff, #4fb0e8 );\r\n\t\tborder: 3px solid #ffffff;\r\n\t\tbox-shadow: 0px 0px 34px 10px rgba( 79, 176, 232, 0.6 );\r\n\t}\r\n\r\n\t.gusher-ring\r\n\t{\r\n\t\tposition: absolute;\r\n\t\twidth: 92px;\r\n\t\theight: 92px;\r\n\t\tborder-radius: 100%;\r\n\t\tborder: 3px solid rgba( 160, 225, 255, 0.7 );\r\n\t\tanimation: gusher-pulse 1.6s ease-out infinite;\r\n\t}\r\n\r\n\t\u0026:hover .gusher-drop { transform: scale( 1.12 ); }\r\n}\r\n\r\n@keyframes gusher-bob\r\n{\r\n\t0% { transform: translateY( 0px ); }\r\n\t50% { transform: translateY( -12px ); }\r\n\t100% { transform: translateY( 0px ); }\r\n}\r\n\r\n@keyframes gusher-pulse\r\n{\r\n\t0% { transform: scale( 0.7 ); opacity: 0.9; }\r\n\t100% { transform: scale( 1.25 ); opacity: 0; }\r\n}\r\n\r\n// ---------------------------------------------------------------- daily\r\n\r\n.daily\r\n{\r\n\tposition: absolute;\r\n\ttop: 110px;\r\n\tleft: 28px;\r\n\talign-items: center;\r\n\tbackground-color: rgba( 24, 30, 44, 0.9 );\r\n\tborder: 3px solid $gold;\r\n\tborder-radius: 18px;\r\n\tpadding: 12px 20px 12px 14px;\r\n\tcursor: pointer;\r\n\tpointer-events: all;\r\n\tanimation: daily-glow 2.2s ease-in-out infinite;\r\n\r\n\t.daily-icon\r\n\t{\r\n\t\tmargin-right: 12px;\r\n\r\n\t\ti\r\n\t\t{\r\n\t\t\tfont-family: Material Icons;\r\n\t\t\tfont-size: 34px;\r\n\t\t\tcolor: $gold;\r\n\t\t}\r\n\t}\r\n\r\n\t.daily-text { flex-direction: column; }\r\n\t.daily-title { font-size: 16px; font-weight: 800; letter-spacing: 1px; }\r\n\t.daily-sub { font-size: 13px; opacity: 0.8; }\r\n\r\n\t\u0026:hover { transform: scale( 1.03 ); }\r\n}\r\n\r\n@keyframes daily-glow\r\n{\r\n\t0% { box-shadow: 0px 0px 0px 0px rgba( 245, 197, 66, 0.5 ); }\r\n\t50% { box-shadow: 0px 0px 26px 4px rgba( 245, 197, 66, 0.45 ); }\r\n\t100% { box-shadow: 0px 0px 0px 0px rgba( 245, 197, 66, 0.5 ); }\r\n}\r\n\r\n// ---------------------------------------------------------------- the tree\r\n\r\n.treearea\r\n{\r\n\tposition: absolute;\r\n\tleft: 34px;\r\n\tbottom: 14%;\r\n\talign-items: flex-end;\r\n\tpointer-events: all;\r\n}\r\n\r\n.tree\r\n{\r\n\twidth: 96px;\r\n\theight: 150px;\r\n\tposition: relative;\r\n\tcursor: pointer;\r\n\tpointer-events: all;\r\n\ttransition: all 0.25s ease-out;\r\n\r\n\t.mound\r\n\t{\r\n\t\tposition: absolute;\r\n\t\tbottom: 0;\r\n\t\tleft: 12%;\r\n\t\twidth: 76%;\r\n\t\theight: 12%;\r\n\t\tborder-radius: 50%;\r\n\t\tbackground-color: rgba( 90, 60, 20, 0.35 );\r\n\t}\r\n\r\n\t.trunk\r\n\t{\r\n\t\tposition: absolute;\r\n\t\tbottom: 8%;\r\n\t\tleft: 44%;\r\n\t\twidth: 12%;\r\n\t\theight: 26%;\r\n\t\tborder-radius: 4px;\r\n\t\tbackground-color: #7a5230;\r\n\t\ttransition: all 0.25s ease-out;\r\n\t}\r\n\r\n\t.canopy\r\n\t{\r\n\t\tposition: absolute;\r\n\t\tborder-radius: 100%;\r\n\t\tbackground-color: #4f9a45;\r\n\t\topacity: 0;\r\n\t\ttransition: all 0.25s ease-out;\r\n\r\n\t\t\u0026.c1 { left: 26%; bottom: 30%; width: 48%; height: 26%; }\r\n\t\t\u0026.c2 { left: 14%; bottom: 42%; width: 40%; height: 24%; background-color: #5cae50; }\r\n\t\t\u0026.c3 { left: 44%; bottom: 44%; width: 42%; height: 26%; background-color: #438a3b; }\r\n\t}\r\n\r\n\t// A sapling at zero, a full crown by stage 6. Stage 0 still needs to read as a\r\n\t// plant - as a bare stub it was invisible against the sand.\r\n\t\u0026.stage-0\r\n\t{\r\n\t\t.trunk { height: 24%; }\r\n\t\t.canopy.c1 { opacity: 1; transform: scale( 0.34 ); }\r\n\t}\r\n\t\u0026.stage-1 { .trunk { height: 20%; } .canopy.c1 { opacity: 1; transform: scale( 0.6 ); } }\r\n\t\u0026.stage-2 { .trunk { height: 26%; } .canopy.c1 { opacity: 1; transform: scale( 0.8 ); } }\r\n\t\u0026.stage-3 { .trunk { height: 32%; } .canopy { opacity: 1; transform: scale( 0.85 ); } }\r\n\t\u0026.stage-4 { .trunk { height: 38%; } .canopy { opacity: 1; transform: scale( 1 ); } }\r\n\t\u0026.stage-5 { .trunk { height: 44%; } .canopy { opacity: 1; transform: scale( 1.12 ); } }\r\n\t\u0026.stage-6 { .trunk { height: 50%; } .canopy { opacity: 1; transform: scale( 1.25 ); } }\r\n\r\n\t\u0026:hover { transform: scale( 1.05 ); }\r\n\r\n\t\u0026.growing .canopy { animation: tree-sway 3s ease-in-out infinite; }\r\n}\r\n\r\n@keyframes tree-sway\r\n{\r\n\t0% { transform: translateX( -3px ); }\r\n\t50% { transform: translateX( 3px ); }\r\n\t100% { transform: translateX( -3px ); }\r\n}\r\n\r\n.treeinfo\r\n{\r\n\tflex-direction: column;\r\n\tmargin-left: 10px;\r\n\tmargin-bottom: 8px;\r\n\tbackground-color: rgba( 18, 22, 32, 0.7 );\r\n\tborder-radius: 14px;\r\n\tpadding: 10px 12px;\r\n\r\n\t.treeheight\r\n\t{\r\n\t\tfont-size: 15px;\r\n\t\tfont-weight: 700;\r\n\t\talign-items: center;\r\n\r\n\t\ti\r\n\t\t{\r\n\t\t\tfont-family: Material Icons;\r\n\t\t\tfont-size: 18px;\r\n\t\t\tmargin-right: 6px;\r\n\t\t\tcolor: #7fd06f;\r\n\t\t}\r\n\t}\r\n\r\n\t.treebar\r\n\t{\r\n\t\twidth: 130px;\r\n\t\theight: 7px;\r\n\t\tborder-radius: 999px;\r\n\t\tbackground-color: rgba( 0, 0, 0, 0.35 );\r\n\t\tmargin-top: 6px;\r\n\t\toverflow: hidden;\r\n\t}\r\n\r\n\t.treefill\r\n\t{\r\n\t\theight: 100%;\r\n\t\tbackground-color: #7fd06f;\r\n\t\ttransition: width 0.2s ease-out;\r\n\t}\r\n\r\n\t.treestatus\r\n\t{\r\n\t\tfont-size: 12px;\r\n\t\topacity: 0.75;\r\n\t\tmargin-top: 4px;\r\n\r\n\t\t\u0026.growing { color: #7fd06f; opacity: 1; }\r\n\t}\r\n\r\n\t.treebtn\r\n\t{\r\n\t\tmargin-top: 8px;\r\n\t\tpadding: 6px 12px;\r\n\t\tborder-radius: 10px;\r\n\t\tbackground-color: #4f9a45;\r\n\t\tfont-size: 13px;\r\n\t\tfont-weight: 700;\r\n\t\talign-items: center;\r\n\t\tjustify-content: center;\r\n\t\tcursor: pointer;\r\n\t\tpointer-events: all;\r\n\r\n\t\ti\r\n\t\t{\r\n\t\t\tfont-family: Material Icons;\r\n\t\t\tfont-size: 16px;\r\n\t\t\tmargin-right: 6px;\r\n\t\t}\r\n\r\n\t\t\u0026:hover { background-color: #5cae50; }\r\n\r\n\t\t\u0026.board { background-color: #3aa7e0; }\r\n\t\t\u0026.board:hover { background-color: #4bb8f0; }\r\n\r\n\t\t\u0026.disabled\r\n\t\t{\r\n\t\t\tbackground-color: #5f6675;\r\n\t\t\topacity: 0.6;\r\n\t\t\tcursor: default;\r\n\t\t}\r\n\t}\r\n}\r\n"},{"Ident":"fpkreastudios.desertpump","Path":"UI/GameHud.razor","FileName":"GameHud.razor","PackageType":"game","CodeKind":"Game","AssetVersionId":338006,"Code":"@using System\r\n@using System.Globalization\r\n@using Sandbox\r\n@using Sandbox.UI\r\n@namespace DesertPump\r\n@inherits PanelComponent\r\n\r\n\u003Cdiv class=\u0022hud @SceneClass\u0022\u003E\r\n\r\n\t\u003Cdiv class=\u0022sky\u0022\u003E\u003C/div\u003E\r\n\t\u003Cdiv class=\u0022sun\u0022\u003E\u003C/div\u003E\r\n\t\u003Cdiv class=\u0022stars\u0022\u003E\u003C/div\u003E\r\n\t\u003Cdiv class=\u0022floor\u0022\u003E\u003C/div\u003E\r\n\t\u003Cdiv class=\u0022dune far\u0022\u003E\u003C/div\u003E\r\n\t\u003Cdiv class=\u0022dune near\u0022\u003E\u003C/div\u003E\r\n\t\u003Cdiv class=\u0022scenery\u0022\u003E\u003C/div\u003E\r\n\r\n\t@if ( State is null )\r\n\t{\r\n\t\t\u003Cdiv class=\u0022missing\u0022\u003E\r\n\t\t\t\u003Cdiv class=\u0022missing-title\u0022\u003ENo Desert Pump Game in the scene\u003C/div\u003E\r\n\t\t\t\u003Cdiv class=\u0022missing-body\u0022\u003EAdd a \u0022Desert Pump Game\u0022 component to any GameObject.\u003C/div\u003E\r\n\t\t\u003C/div\u003E\r\n\t}\r\n\telse\r\n\t{\r\n\t\t\u003Cdiv class=\u0022topbar\u0022\u003E\r\n\r\n\t\t\t\u003Cdiv class=\u0022stat coins\u0022\u003E\r\n\t\t\t\t\u003Cdiv class=\u0022coin\u0022\u003E\u003C/div\u003E\r\n\t\t\t\t\u003Cdiv class=\u0022value\u0022\u003E@Numbers.Short( State.Coins )\u003C/div\u003E\r\n\t\t\t\u003C/div\u003E\r\n\r\n\t\t\t\u003Cdiv class=\u0022stat tankstat @( State.TankFull ? \u0022full\u0022 : \u0022\u0022 )\u0022\u003E\r\n\t\t\t\t\u003Cdiv class=\u0022tank\u0022\u003E\r\n\t\t\t\t\t\u003Cdiv class=\u0022tank-fill\u0022 style=\u0022@FillStyle()\u0022\u003E\u003C/div\u003E\r\n\t\t\t\t\u003C/div\u003E\r\n\t\t\t\t\u003Cdiv class=\u0022tank-text\u0022\u003E\r\n\t\t\t\t\t\u003Cdiv class=\u0022value\u0022\u003E@Numbers.Short( State.Water )\u003Cspan class=\u0022unit\u0022\u003E / @Numbers.Short( State.TankCapacity )L\u003C/span\u003E\u003C/div\u003E\r\n\t\t\t\t\t\u003Cdiv class=\u0022sub\u0022\u003E@RateText()\u003C/div\u003E\r\n\t\t\t\t\u003C/div\u003E\r\n\t\t\t\u003C/div\u003E\r\n\r\n\t\t\t\u003Cdiv class=\u0022spacer\u0022\u003E\u003C/div\u003E\r\n\r\n\t\t\t\u003Cdiv class=\u0022iconbutton shopbtn @( AnyUpgradeAffordable ? \u0022highlight\u0022 : \u0022\u0022 )\u0022 onclick=\u0022@OpenShop\u0022\u003E\r\n\t\t\t\t\u003Ci\u003Estorefront\u003C/i\u003E\r\n\t\t\t\u003C/div\u003E\r\n\r\n\t\t\t\u003Cdiv class=\u0022iconbutton @( State.Muted ? \u0022muted\u0022 : \u0022\u0022 )\u0022 onclick=\u0022@ToggleMute\u0022\u003E\r\n\t\t\t\t\u003Ci\u003E@( State.Muted ? \u0022volume_off\u0022 : \u0022volume_up\u0022 )\u003C/i\u003E\r\n\t\t\t\u003C/div\u003E\r\n\r\n\t\t\t\u003Cdiv class=\u0022iconbutton\u0022 onclick=\u0022@OpenSettings\u0022\u003E\r\n\t\t\t\t\u003Ci\u003Esettings\u003C/i\u003E\r\n\t\t\t\u003C/div\u003E\r\n\r\n\t\t\u003C/div\u003E\r\n\r\n\t\t\u003Cdiv class=\u0022stage\u0022\u003E\r\n\r\n\t\t\t\u003Cdiv class=\u0022pumparea @PumpAreaClass()\u0022 onclick=\u0022@DoPump\u0022\u003E\r\n\t\t\t\t\u003Cdiv class=\u0022glow\u0022\u003E\u003C/div\u003E\r\n\t\t\t\t\u003CPumpArt TierIndex=\u0022@State.PumpLevel\u0022 Artwork=\u0022@ArtworkFor( State.PumpLevel )\u0022\u003E\u003C/PumpArt\u003E\r\n\t\t\t\t\u003Cdiv class=\u0022ground\u0022\u003E\u003C/div\u003E\r\n\t\t\t\u003C/div\u003E\r\n\r\n\t\t\t\u003Cdiv class=\u0022nameplate\u0022\u003E\r\n\t\t\t\t\u003Cdiv class=\u0022tierno\u0022\u003E@State.CurrentPump.Position \u0026middot; @State.Tier.Name.ToUpper()\u003C/div\u003E\r\n\t\t\t\t\u003Cdiv class=\u0022name\u0022\u003E@State.CurrentPump.Name\u003C/div\u003E\r\n\t\t\t\t\u003Cdiv class=\u0022tagline\u0022\u003E@State.Tier.Tagline\u003C/div\u003E\r\n\t\t\t\t\u003Cdiv class=\u0022tierbar\u0022\u003E\r\n\t\t\t\t\t\u003Cdiv class=\u0022tierfill\u0022 style=\u0022@TierFillStyle()\u0022\u003E\u003C/div\u003E\r\n\t\t\t\t\u003C/div\u003E\r\n\t\t\t\t\u003Cdiv class=\u0022perclick\u0022\u003E\u002B@Numbers.Short( State.LitresPerClick )L per pump - @Numbers.Short( State.PricePerLitre ) @Numbers.Plural( State.PricePerLitre, \u0022coin\u0022, \u0022coins\u0022 ) per litre\u003C/div\u003E\r\n\t\t\t\u003C/div\u003E\r\n\r\n\t\t\t@foreach ( var f in floaters )\r\n\t\t\t{\r\n\t\t\t\t\u003Cdiv class=\u0022floater @( f.Coin ? \u0022coin\u0022 : \u0022\u0022 )\u0022 style=\u0022@FloaterStyle( f )\u0022\u003E@f.Text\u003C/div\u003E\r\n\t\t\t}\r\n\r\n\t\t\t@if ( ShowToast )\r\n\t\t\t{\r\n\t\t\t\t\u003Cdiv class=\u0022toast\u0022\u003E@toast\u003C/div\u003E\r\n\t\t\t}\r\n\r\n\t\t\t@if ( ShowIdleNote )\r\n\t\t\t{\r\n\t\t\t\t\u003Cdiv class=\u0022idlenote\u0022\u003EThe pump made @Numbers.Short( idleNotice )L while you were away\u003C/div\u003E\r\n\t\t\t}\r\n\r\n\t\t\t@if ( State.GusherActive )\r\n\t\t\t{\r\n\t\t\t\t\u003Cdiv class=\u0022gusher\u0022 style=\u0022@GusherStyle()\u0022 onclick=\u0022@ClaimGusher\u0022\u003E\r\n\t\t\t\t\t\u003Cdiv class=\u0022gusher-drop\u0022\u003E\u003C/div\u003E\r\n\t\t\t\t\t\u003Cdiv class=\u0022gusher-ring\u0022\u003E\u003C/div\u003E\r\n\t\t\t\t\u003C/div\u003E\r\n\t\t\t}\r\n\r\n\t\t\t\u003Cdiv class=\u0022treearea\u0022\u003E\r\n\r\n\t\t\t\t\u003Cdiv class=\u0022tree stage-@State.TreeArtStage @( State.TreeIsGrowing ? \u0022growing\u0022 : \u0022\u0022 )\u0022\r\n\t\t\t\t\t onclick=\u0022@DoWaterTree\u0022\u003E\r\n\t\t\t\t\t\u003Cdiv class=\u0022trunk\u0022\u003E\u003C/div\u003E\r\n\t\t\t\t\t\u003Cdiv class=\u0022canopy c1\u0022\u003E\u003C/div\u003E\r\n\t\t\t\t\t\u003Cdiv class=\u0022canopy c2\u0022\u003E\u003C/div\u003E\r\n\t\t\t\t\t\u003Cdiv class=\u0022canopy c3\u0022\u003E\u003C/div\u003E\r\n\t\t\t\t\t\u003Cdiv class=\u0022mound\u0022\u003E\u003C/div\u003E\r\n\t\t\t\t\u003C/div\u003E\r\n\r\n\t\t\t\t\u003Cdiv class=\u0022treeinfo\u0022\u003E\r\n\t\t\t\t\t\u003Cdiv class=\u0022treeheight\u0022\u003E\u003Ci\u003Epark\u003C/i\u003E @State.TreeHeight @( State.TreeHeight == 1 ? \u0022stage\u0022 : \u0022stages\u0022 )\u003C/div\u003E\r\n\r\n\t\t\t\t\t@if ( State.TreeIsGrowing )\r\n\t\t\t\t\t{\r\n\t\t\t\t\t\t\u003Cdiv class=\u0022treestatus growing\u0022\u003EGrowing - @State.TreeTimeLeft\u003C/div\u003E\r\n\t\t\t\t\t}\r\n\t\t\t\t\telse\r\n\t\t\t\t\t{\r\n\t\t\t\t\t\t\u003Cdiv class=\u0022treebar\u0022\u003E\r\n\t\t\t\t\t\t\t\u003Cdiv class=\u0022treefill\u0022 style=\u0022@TreeFillStyle()\u0022\u003E\u003C/div\u003E\r\n\t\t\t\t\t\t\u003C/div\u003E\r\n\t\t\t\t\t\t\u003Cdiv class=\u0022treestatus\u0022\u003E@Numbers.Short( State.TreeWater )/@Numbers.Short( State.TreeWaterNeeded )L\u003C/div\u003E\r\n\t\t\t\t\t}\r\n\r\n\t\t\t\t\t\u003Cdiv class=\u0022treebtn @( State.CanWaterTree ? \u0022\u0022 : \u0022disabled\u0022 )\u0022 onclick=\u0022@DoWaterTree\u0022\u003E\r\n\t\t\t\t\t\t\u003Ci\u003Ewater_drop\u003C/i\u003E WATER\r\n\t\t\t\t\t\u003C/div\u003E\r\n\r\n\t\t\t\t\t\u003Cdiv class=\u0022treebtn board\u0022 onclick=\u0022@OpenTree\u0022\u003E\r\n\t\t\t\t\t\t\u003Ci\u003Eleaderboard\u003C/i\u003E BOARD\r\n\t\t\t\t\t\u003C/div\u003E\r\n\t\t\t\t\u003C/div\u003E\r\n\r\n\t\t\t\u003C/div\u003E\r\n\r\n\t\t\t\u003Cdiv class=\u0022hint\u0022\u003EClick the pump or press SPACE\u003C/div\u003E\r\n\r\n\t\t\u003C/div\u003E\r\n\r\n\t\t@if ( State.CanClaimDaily )\r\n\t\t{\r\n\t\t\t\u003Cdiv class=\u0022daily\u0022 onclick=\u0022@ClaimDaily\u0022\u003E\r\n\t\t\t\t\u003Cdiv class=\u0022daily-icon\u0022\u003E\u003Ci\u003Eredeem\u003C/i\u003E\u003C/div\u003E\r\n\t\t\t\t\u003Cdiv class=\u0022daily-text\u0022\u003E\r\n\t\t\t\t\t\u003Cdiv class=\u0022daily-title\u0022\u003EDAILY BONUS READY\u003C/div\u003E\r\n\t\t\t\t\t\u003Cdiv class=\u0022daily-sub\u0022\u003E@Numbers.Short( State.DailyReward ) coins \u0026middot; day @State.ProjectedDailyStreak streak\u003C/div\u003E\r\n\t\t\t\t\u003C/div\u003E\r\n\t\t\t\u003C/div\u003E\r\n\t\t}\r\n\r\n\t\t\u003Cdiv class=\u0022actions\u0022\u003E\r\n\r\n\t\t\t\u003Cdiv class=\u0022bigbutton sell @( State.CanSell ? \u0022\u0022 : \u0022disabled\u0022 )\u0022 onclick=\u0022@DoSell\u0022\u003E\r\n\t\t\t\t\u003Cdiv class=\u0022btn-icon\u0022\u003E\u003Ci\u003Elocal_drink\u003C/i\u003E\u003C/div\u003E\r\n\t\t\t\t\u003Cdiv class=\u0022btn-text\u0022\u003E\r\n\t\t\t\t\t\u003Cdiv class=\u0022btn-title\u0022\u003ESELL WATER\u003C/div\u003E\r\n\t\t\t\t\t\u003Cdiv class=\u0022btn-sub\u0022\u003E\u002B@Numbers.Short( State.SaleValue ) coins\u003C/div\u003E\r\n\t\t\t\t\u003C/div\u003E\r\n\t\t\t\u003C/div\u003E\r\n\r\n\t\t\t@if ( State.IsMaxed )\r\n\t\t\t{\r\n\t\t\t\t\u003Cdiv class=\u0022bigbutton buy maxed\u0022\u003E\r\n\t\t\t\t\t\u003Cdiv class=\u0022btn-icon\u0022\u003E\u003Ci\u003Eemoji_events\u003C/i\u003E\u003C/div\u003E\r\n\t\t\t\t\t\u003Cdiv class=\u0022btn-text\u0022\u003E\r\n\t\t\t\t\t\t\u003Cdiv class=\u0022btn-title\u0022\u003EALL PUMPS OWNED\u003C/div\u003E\r\n\t\t\t\t\t\t\u003Cdiv class=\u0022btn-sub\u0022\u003Ethe desert is yours\u003C/div\u003E\r\n\t\t\t\t\t\u003C/div\u003E\r\n\t\t\t\t\u003C/div\u003E\r\n\t\t\t}\r\n\t\t\telse\r\n\t\t\t{\r\n\t\t\t\t\u003Cdiv class=\u0022bigbutton buy @( State.CanUpgrade ? \u0022\u0022 : \u0022disabled\u0022 )\u0022 onclick=\u0022@DoBuy\u0022\u003E\r\n\t\t\t\t\t\u003Cdiv class=\u0022btn-icon\u0022\u003E\u003Ci\u003Eupgrade\u003C/i\u003E\u003C/div\u003E\r\n\t\t\t\t\t\u003Cdiv class=\u0022btn-text\u0022\u003E\r\n\t\t\t\t\t\t\u003Cdiv class=\u0022btn-title\u0022\u003EBUY @State.NextPump.Name.ToUpper()\u003C/div\u003E\r\n\t\t\t\t\t\t\u003Cdiv class=\u0022btn-sub\u0022\u003E@Numbers.Short( State.NextPump.Cost ) coins\u003C/div\u003E\r\n\t\t\t\t\t\u003C/div\u003E\r\n\t\t\t\t\u003C/div\u003E\r\n\t\t\t}\r\n\r\n\t\t\u003C/div\u003E\r\n\r\n\t\t\u003Cdiv class=\u0022collection\u0022\u003E\r\n\t\t\t@foreach ( var pump in VisiblePumps )\r\n\t\t\t{\r\n\t\t\t\t\u003Cdiv class=\u0022slot @SlotClass( pump )\u0022\u003E\r\n\t\t\t\t\t\u003Cdiv class=\u0022slotart\u0022\u003E\r\n\t\t\t\t\t\t\u003CPumpArt TierIndex=\u0022@pump.Index\u0022\r\n\t\t\t\t\t\t\t\t Silhouette=\u0022@( pump.Index \u003E State.PumpLevel )\u0022\r\n\t\t\t\t\t\t\t\t Artwork=\u0022@ArtworkFor( pump.Index )\u0022\u003E\u003C/PumpArt\u003E\r\n\t\t\t\t\t\t@if ( pump.Index \u003E State.PumpLevel )\r\n\t\t\t\t\t\t{\r\n\t\t\t\t\t\t\t\u003Cdiv class=\u0022question\u0022\u003E?\u003C/div\u003E\r\n\t\t\t\t\t\t}\r\n\t\t\t\t\t\u003C/div\u003E\r\n\t\t\t\t\t\u003Cdiv class=\u0022slotlabel\u0022\u003E@SlotLabel( pump )\u003C/div\u003E\r\n\t\t\t\t\u003C/div\u003E\r\n\t\t\t}\r\n\t\t\u003C/div\u003E\r\n\r\n\t\t@if ( showShop )\r\n\t\t{\r\n\t\t\t\u003CShopPanel OnClose=\u0022@CloseOverlays\u0022\u003E\u003C/ShopPanel\u003E\r\n\t\t}\r\n\r\n\t\t@if ( showSettings )\r\n\t\t{\r\n\t\t\t\u003CSettingsPanel OnClose=\u0022@CloseOverlays\u0022\u003E\u003C/SettingsPanel\u003E\r\n\t\t}\r\n\r\n\t\t@if ( showTree )\r\n\t\t{\r\n\t\t\t\u003CTreePanel OnClose=\u0022@CloseOverlays\u0022\u003E\u003C/TreePanel\u003E\r\n\t\t}\r\n\t}\r\n\r\n\u003C/div\u003E\r\n\r\n@code\r\n{\r\n\t/// \u003Csummary\u003EOptional - left empty, the HUD finds the game itself.\u003C/summary\u003E\r\n\t[Property] public DesertPumpGame Target { get; set; }\r\n\r\n\t/// \u003Csummary\u003E\r\n\t/// The real pump artwork, one texture per tier in the same order as\r\n\t/// \u003Csee cref=\u0022PumpTier.All\u0022/\u003E. Any slot left empty falls back to placeholder art.\r\n\t/// \u003C/summary\u003E\r\n\t[Property] public List\u003CTexture\u003E PumpArtwork { get; set; } = new();\r\n\r\n\tDesertPumpGame State =\u003E Target.IsValid() ? Target : DesertPumpGame.Current;\r\n\r\n\tconst float FloaterLife = 1.1f;\r\n\tconst float ToastLife = 2.2f;\r\n\tconst float IdleNoticeLife = 8f;\r\n\tconst float PumpAnimLife = 0.16f;\r\n\r\n\tclass Floater\r\n\t{\r\n\t\tpublic string Text;\r\n\t\tpublic float X;\r\n\t\tpublic float Drift;\r\n\t\tpublic bool Coin;\r\n\t\tpublic RealTimeSince Age;\r\n\t}\r\n\r\n\treadonly List\u003CFloater\u003E floaters = new();\r\n\r\n\tstring toast;\r\n\tRealTimeSince toastAge;\r\n\r\n\tdouble idleNotice;\r\n\tRealTimeSince idleAge;\r\n\r\n\tRealTimeSince timeSincePump;\r\n\r\n\t/// \u003Csummary\u003EBumped every frame so floaters get rebuilt while they\u0027re moving.\u003C/summary\u003E\r\n\tint animTick;\r\n\r\n\tbool hooked;\r\n\r\n\tbool showShop;\r\n\tbool showSettings;\r\n\tbool showTree;\r\n\r\n\t/// \u003Csummary\u003EPuts a nudge on the shop button when something in there is affordable.\u003C/summary\u003E\r\n\tbool AnyUpgradeAffordable =\u003E\r\n\t\tState is not null \u0026\u0026 UpgradeTrack.All.Any( x =\u003E State.CanBuy( x.Kind ) );\r\n\r\n\t/// \u003Csummary\u003E\r\n\t/// The strip along the bottom shows the tier you\u0027re in, not all 108 pumps - nine\r\n\t/// slots you can actually finish is a far better carrot than a hundred you can\u0027t.\r\n\t/// \u003C/summary\u003E\r\n\tIEnumerable\u003CPumpModel\u003E VisiblePumps\r\n\t{\r\n\t\tget\r\n\t\t{\r\n\t\t\tif ( State is null ) return Enumerable.Empty\u003CPumpModel\u003E();\r\n\r\n\t\t\tvar first = State.Tier.FirstPumpIndex;\r\n\t\t\treturn PumpModel.All.Skip( first ).Take( PumpTier.PumpsPerTier );\r\n\t\t}\r\n\t}\r\n\r\n\tstring SceneClass =\u003E $\u0022scene-{State?.SelectedBackground ?? BackgroundStyle.DefaultId}\u0022;\r\n\r\n\tvoid OpenShop()\r\n\t{\r\n\t\tshowShop = !showShop;\r\n\t\tshowSettings = false;\r\n\t}\r\n\r\n\tvoid OpenSettings()\r\n\t{\r\n\t\tshowSettings = !showSettings;\r\n\t\tshowShop = false;\r\n\t}\r\n\r\n\tvoid OpenTree()\r\n\t{\r\n\t\tshowTree = !showTree;\r\n\t\tshowShop = false;\r\n\t\tshowSettings = false;\r\n\t}\r\n\r\n\t/// \u003Csummary\u003EOpen a panel from the console, so UI can be inspected without clicking.\u003C/summary\u003E\r\n\tpublic void ShowPanel( string which )\r\n\t{\r\n\t\tshowShop = which is \u0022shop\u0022 or \u0022bg\u0022;\r\n\t\tshowSettings = which == \u0022settings\u0022;\r\n\t\tshowTree = which == \u0022tree\u0022;\r\n\r\n\t\tStateHasChanged();\r\n\t}\r\n\r\n\tvoid CloseOverlays()\r\n\t{\r\n\t\tshowShop = false;\r\n\t\tshowSettings = false;\r\n\t\tshowTree = false;\r\n\t}\r\n\r\n\tstring TreeFillStyle() =\u003E $\u0022width: {N( State.TreeFraction * 100f )}%;\u0022;\r\n\r\n\tvoid DoWaterTree()\r\n\t{\r\n\t\tvar poured = State?.WaterTree() ?? 0;\r\n\t\tif ( poured \u003C= 0 ) return;\r\n\r\n\t\tSpawn( $\u0022-{Numbers.Short( poured )}L\u0022, false );\r\n\r\n\t\ttoast = State.TreeIsGrowing\r\n\t\t\t? $\u0022Tree is growing - back in {State.TreeTimeLeft}\u0022\r\n\t\t\t: $\u0022{Numbers.Short( State.TreeWaterRemaining )}L to go\u0022;\r\n\t\ttoastAge = 0;\r\n\t}\r\n\r\n\tvoid OnTreeGrew( int height )\r\n\t{\r\n\t\ttoast = $\u0022Your tree grew to {height} {( height == 1 ? \u0022stage\u0022 : \u0022stages\u0022 )}\u0022;\r\n\t\ttoastAge = 0;\r\n\t}\r\n\r\n\tbool ShowToast =\u003E !string.IsNullOrEmpty( toast ) \u0026\u0026 toastAge \u003C ToastLife;\r\n\tbool ShowIdleNote =\u003E idleNotice \u003E 0 \u0026\u0026 idleAge \u003C IdleNoticeLife;\r\n\r\n\t/// \u003Csummary\u003E\r\n\t/// The panel a PanelComponent builds for itself defaults to pointer-events: none,\r\n\t/// and no stylesheet rule can reach it - it has no class and a generated type name.\r\n\t/// Left alone it makes every button underneath it dead to the mouse.\r\n\t/// \u003C/summary\u003E\r\n\tprotected override void OnTreeFirstBuilt()\r\n\t{\r\n\t\tbase.OnTreeFirstBuilt();\r\n\r\n\t\tPanel.Style.PointerEvents = PointerEvents.All;\r\n\t}\r\n\r\n\tprotected override void OnStart()\r\n\t{\r\n\t\tHook();\r\n\r\n\t\tif ( State is not null \u0026\u0026 State.IdleCatchUp \u003E 0 )\r\n\t\t{\r\n\t\t\tidleNotice = State.IdleCatchUp;\r\n\t\t\tidleAge = 0;\r\n\t\t}\r\n\t}\r\n\r\n\tprotected override void OnDestroy()\r\n\t{\r\n\t\tUnhook();\r\n\t}\r\n\r\n\tprotected override void OnUpdate()\r\n\t{\r\n\t\t// The game component can come alive after us, so keep trying until it\u0027s there.\r\n\t\tif ( !hooked ) Hook();\r\n\r\n\t\tfloaters.RemoveAll( x =\u003E x.Age \u003E FloaterLife );\r\n\r\n\t\tif ( floaters.Count \u003E 0 || timeSincePump \u003C PumpAnimLife )\r\n\t\t{\r\n\t\t\tanimTick = (int)(RealTime.Now * 30f);\r\n\t\t}\r\n\t}\r\n\r\n\tprotected override int BuildHash()\r\n\t{\r\n\t\tvar state = State;\r\n\t\tif ( state is null ) return 0;\r\n\r\n\t\treturn HashCode.Combine(\r\n\t\t\t(long)state.Coins,\r\n\t\t\t(long)state.Water,\r\n\t\t\tstate.PumpLevel,\r\n\t\t\tstate.Muted,\r\n\t\t\tfloaters.Count,\r\n\t\t\tanimTick,\r\n\t\t\tShowToast,\r\n\t\t\tHashCode.Combine( ShowIdleNote, showShop, showSettings, AnyUpgradeAffordable,\r\n\t\t\t\tstate.GusherActive, state.CanClaimDaily, state.SelectedBackground,\r\n\t\t\t\tHashCode.Combine( showTree, state.TreeHeight, (int)state.TreeWater, (int)state.TreeSecondsLeft ) ) );\r\n\t}\r\n\r\n\tvoid Hook()\r\n\t{\r\n\t\tvar state = State;\r\n\t\tif ( state is null || hooked ) return;\r\n\r\n\t\tstate.Pumped \u002B= OnPumped;\r\n\t\tstate.Sold \u002B= OnSold;\r\n\t\tstate.Upgraded \u002B= OnUpgraded;\r\n\t\tstate.Refused \u002B= OnRefused;\r\n\t\tstate.Purchased \u002B= OnPurchased;\r\n\t\tstate.TreeGrew \u002B= OnTreeGrew;\r\n\r\n\t\thooked = true;\r\n\t}\r\n\r\n\tvoid Unhook()\r\n\t{\r\n\t\tvar state = State;\r\n\t\tif ( state is null || !hooked ) return;\r\n\r\n\t\tstate.Pumped -= OnPumped;\r\n\t\tstate.Sold -= OnSold;\r\n\t\tstate.Upgraded -= OnUpgraded;\r\n\t\tstate.Refused -= OnRefused;\r\n\t\tstate.Purchased -= OnPurchased;\r\n\t\tstate.TreeGrew -= OnTreeGrew;\r\n\r\n\t\thooked = false;\r\n\t}\r\n\r\n\tvoid DoPump() =\u003E State?.Pump();\r\n\tvoid DoSell() =\u003E State?.SellAll();\r\n\tvoid DoBuy() =\u003E State?.BuyNextPump();\r\n\tvoid ToggleMute() =\u003E State?.ToggleMute();\r\n\r\n\tvoid OnPumped( double litres )\r\n\t{\r\n\t\ttimeSincePump = 0;\r\n\t\tSpawn( $\u0022\u002B{Numbers.Short( litres )}L\u0022, false );\r\n\t}\r\n\r\n\tvoid OnSold( double coins )\r\n\t{\r\n\t\tSpawn( $\u0022\u002B{Numbers.Short( coins )}\u0022, true );\r\n\t\ttoast = null;\r\n\t}\r\n\r\n\tvoid OnUpgraded( PumpModel pump )\r\n\t{\r\n\t\ttoast = $\u0022{pump.Name} installed\u0022;\r\n\t\ttoastAge = 0;\r\n\t\tidleNotice = 0;\r\n\t}\r\n\r\n\tvoid OnRefused( string reason )\r\n\t{\r\n\t\ttoast = reason;\r\n\t\ttoastAge = 0;\r\n\t}\r\n\r\n\tvoid OnPurchased( UpgradeTrack track )\r\n\t{\r\n\t\ttoast = $\u0022{track.Name} upgraded\u0022;\r\n\t\ttoastAge = 0;\r\n\t}\r\n\r\n\tvoid Spawn( string text, bool coin )\r\n\t{\r\n\t\tif ( !PumpSettings.Current.ShowFloatingNumbers )\r\n\t\t\treturn;\r\n\r\n\t\t// Keep the list short - a fast clicker can outrun the fade otherwise.\r\n\t\tif ( floaters.Count \u003E 12 ) floaters.RemoveAt( 0 );\r\n\r\n\t\tfloaters.Add( new Floater\r\n\t\t{\r\n\t\t\tText = text,\r\n\t\t\tX = Rand( -70f, 70f ),\r\n\t\t\tDrift = Rand( -18f, 18f ),\r\n\t\t\tCoin = coin,\r\n\t\t\tAge = 0\r\n\t\t} );\r\n\t}\r\n\r\n\tTexture ArtworkFor( int index )\r\n\t{\r\n\t\tif ( PumpArtwork is null ) return null;\r\n\t\tif ( index \u003C 0 || index \u003E= PumpArtwork.Count ) return null;\r\n\r\n\t\treturn PumpArtwork[index];\r\n\t}\r\n\r\n\tstring RateText()\r\n\t{\r\n\t\tvar perSecond = State.CurrentPump.PerSecond;\r\n\r\n\t\treturn perSecond \u003E 0\r\n\t\t\t? $\u0022\u002B{Numbers.Rate( perSecond )}L/s while idle\u0022\r\n\t\t\t: \u0022hand powered\u0022;\r\n\t}\r\n\r\n\tstring PumpAreaClass()\r\n\t{\r\n\t\tvar classes = timeSincePump \u003C PumpAnimLife ? \u0022pumping\u0022 : \u0022\u0022;\r\n\t\tif ( State.TankFull ) classes \u002B= \u0022 full\u0022;\r\n\r\n\t\treturn classes;\r\n\t}\r\n\r\n\tstring SlotClass( PumpModel tier )\r\n\t{\r\n\t\tif ( tier.Index \u003C= State.PumpLevel ) return \u0022owned\u0022;\r\n\r\n\t\treturn tier.Index == State.PumpLevel \u002B 1 ? \u0022locked next\u0022 : \u0022locked\u0022;\r\n\t}\r\n\r\n\tstring SlotLabel( PumpModel tier )\r\n\t{\r\n\t\treturn tier.Index \u003C= State.PumpLevel\r\n\t\t\t? tier.Name\r\n\t\t\t: $\u0022{Numbers.Short( tier.Cost )} {Numbers.Plural( tier.Cost, \u0022coin\u0022, \u0022coins\u0022 )}\u0022;\r\n\t}\r\n\r\n\tstring FillStyle() =\u003E $\u0022height: {N( State.TankFraction * 100f )}%;\u0022;\r\n\r\n\tstring TierFillStyle() =\u003E $\u0022width: {N( State.TierProgress * 100f )}%;\u0022;\r\n\r\n\tstring GusherStyle() =\u003E\r\n\t\t$\u0022left: {N( State.GusherX * 100f )}%; top: {N( State.GusherY * 100f )}%;\u0022;\r\n\r\n\tvoid ClaimGusher()\r\n\t{\r\n\t\tvar won = State?.ClaimGusher() ?? 0;\r\n\t\tif ( won \u003C= 0 ) return;\r\n\r\n\t\tSpawn( $\u0022\u002B{Numbers.Short( won )}\u0022, true );\r\n\t\ttoast = \u0022Gusher! Free coins\u0022;\r\n\t\ttoastAge = 0;\r\n\t}\r\n\r\n\tvoid ClaimDaily()\r\n\t{\r\n\t\tvar won = State?.ClaimDaily() ?? 0;\r\n\t\tif ( won \u003C= 0 ) return;\r\n\r\n\t\tSpawn( $\u0022\u002B{Numbers.Short( won )}\u0022, true );\r\n\t\ttoast = $\u0022Day {State.DailyStreak} streak - come back tomorrow\u0022;\r\n\t\ttoastAge = 0;\r\n\t}\r\n\r\n\tstring FloaterStyle( Floater f )\r\n\t{\r\n\t\tvar t = Math.Clamp( (float)f.Age / FloaterLife, 0f, 1f );\r\n\t\tvar rise = 42f \u002B t * 26f;\r\n\t\tvar fade = 1f - t * t;\r\n\r\n\t\treturn $\u0022margin-left: {N( f.X \u002B f.Drift * t )}px; bottom: {N( rise )}%; opacity: {N( fade )};\u0022;\r\n\t}\r\n\r\n\t/// \u003Csummary\u003EStyle strings need dots for decimals, whatever the machine\u0027s locale says.\u003C/summary\u003E\r\n\tstatic string N( float value ) =\u003E value.ToString( \u00220.##\u0022, CultureInfo.InvariantCulture );\r\n\r\n\tstatic float Rand( float min, float max ) =\u003E min \u002B (float)System.Random.Shared.NextDouble() * (max - min);\r\n}\r\n"},{"Ident":"fpkreastudios.desertpump","Path":"UI/PumpArt.razor","FileName":"PumpArt.razor","PackageType":"game","CodeKind":"Game","AssetVersionId":338006,"Code":"@using System\r\n@using Sandbox\r\n@using Sandbox.UI\r\n@namespace DesertPump\r\n@inherits Panel\r\n\r\n\u003Croot class=\u0022pumpart family-@Family @( Silhouette ? \u0022silhouette\u0022 : \u0022\u0022 )\u0022\u003E\r\n\r\n\t@if ( Artwork is not null )\r\n\t{\r\n\t\t\u003CImage Texture=\u0022@Artwork\u0022 class=\u0022photo\u0022\u003E\u003C/Image\u003E\r\n\t}\r\n\telse\r\n\t{\r\n\t\t\u003Cdiv class=\u0022mound\u0022 style=\u0022background-color: @Shade( 0.55f );\u0022\u003E\u003C/div\u003E\r\n\t\t\u003Cdiv class=\u0022body\u0022 style=\u0022background-color: @Shade( 1f );\u0022\u003E\u003C/div\u003E\r\n\t\t\u003Cdiv class=\u0022head\u0022 style=\u0022background-color: @Shade( 1.25f );\u0022\u003E\u003C/div\u003E\r\n\t\t\u003Cdiv class=\u0022arm\u0022 style=\u0022background-color: @Shade( 1.25f );\u0022\u003E\u003C/div\u003E\r\n\t\t\u003Cdiv class=\u0022spout\u0022 style=\u0022background-color: @Shade( 0.8f );\u0022\u003E\u003C/div\u003E\r\n\t\t\u003Cdiv class=\u0022stream\u0022 style=\u0022background-color: @Water( 1.15f );\u0022\u003E\u003C/div\u003E\r\n\t\t\u003Cdiv class=\u0022pool\u0022 style=\u0022background-color: @Water( 0.75f );\u0022\u003E\u003C/div\u003E\r\n\t}\r\n\r\n\u003C/root\u003E\r\n\r\n@code\r\n{\r\n\t/// \u003Csummary\u003EIndex into \u003Csee cref=\u0022PumpTier.All\u0022/\u003E.\u003C/summary\u003E\r\n\tpublic int TierIndex { get; set; }\r\n\r\n\t/// \u003Csummary\u003EDraw it as a black cut-out, the way locked pumps show in the collection.\u003C/summary\u003E\r\n\tpublic bool Silhouette { get; set; }\r\n\r\n\t/// \u003Csummary\u003EReal artwork. When set it replaces the whole placeholder build-up.\u003C/summary\u003E\r\n\tpublic Texture Artwork { get; set; }\r\n\r\n\tPumpModel Pump =\u003E PumpModel.Get( TierIndex );\r\n\r\n\t/// \u003Csummary\u003EHand pump, rig, or tower - keeps the nine tiers visually distinct.\u003C/summary\u003E\r\n\tint Family =\u003E Pump.Rank \u003C= 3 ? 0 : Pump.Rank \u003C= 6 ? 1 : 2;\r\n\r\n\t/// \u003Csummary\u003ETier colour, brightened or darkened, as a css hex string.\u003C/summary\u003E\r\n\tstring Shade( float multiplier )\r\n\t{\r\n\t\tif ( Silhouette ) return \u0022#0b0d12\u0022;\r\n\r\n\t\tvar c = Pump.Tint;\r\n\r\n\t\treturn new Color(\r\n\t\t\tMath.Clamp( c.r * multiplier, 0f, 1f ),\r\n\t\t\tMath.Clamp( c.g * multiplier, 0f, 1f ),\r\n\t\t\tMath.Clamp( c.b * multiplier, 0f, 1f ) ).Hex;\r\n\t}\r\n\r\n\tstring Water( float multiplier )\r\n\t{\r\n\t\tif ( Silhouette ) return \u0022#0b0d12\u0022;\r\n\r\n\t\treturn new Color(\r\n\t\t\tMath.Clamp( 0.35f * multiplier, 0f, 1f ),\r\n\t\t\tMath.Clamp( 0.72f * multiplier, 0f, 1f ),\r\n\t\t\tMath.Clamp( 0.95f * multiplier, 0f, 1f ) ).Hex;\r\n\t}\r\n\r\n\tprotected override int BuildHash() =\u003E HashCode.Combine( TierIndex, Silhouette, Artwork );\r\n}\r\n"},{"Ident":"fpkreastudios.desertpump","Path":"Game/UpgradeTrack.cs","FileName":"UpgradeTrack.cs","PackageType":"game","CodeKind":"Game","AssetVersionId":338006,"Code":"namespace DesertPump;\r\n\r\npublic enum UpgradeKind\r\n{\r\n\t/// \u003Csummary\u003EBigger tank, so you sell every few minutes instead of every few seconds.\u003C/summary\u003E\r\n\tStorage,\r\n\r\n\t/// \u003Csummary\u003EMore litres per pump.\u003C/summary\u003E\r\n\tPower,\r\n\r\n\t/// \u003Csummary\u003EMore coins per litre.\u003C/summary\u003E\r\n\tValue,\r\n}\r\n\r\n/// \u003Csummary\u003E\r\n/// A shop upgrade you can buy over and over, each level costing more than the last.\r\n/// \u003C/summary\u003E\r\n/// \u003Cremarks\u003E\r\n/// Cost growth deliberately outruns effect growth by a wide margin. A track where the\r\n/// two are close never stops paying for itself, and the economy runs away - the first\r\n/// pass at this balance finished the whole game in two minutes for exactly that reason.\r\n/// \u003C/remarks\u003E\r\npublic sealed class UpgradeTrack\r\n{\r\n\tpublic UpgradeKind Kind { get; init; }\r\n\tpublic string Name { get; init; }\r\n\tpublic string Description { get; init; }\r\n\r\n\t/// \u003Csummary\u003EMaterial icon name.\u003C/summary\u003E\r\n\tpublic string Icon { get; init; }\r\n\r\n\tpublic double BaseCost { get; init; }\r\n\tpublic double CostGrowth { get; init; }\r\n\r\n\t/// \u003Csummary\u003EWhat one level multiplies its stat by.\u003C/summary\u003E\r\n\tpublic float EffectGrowth { get; init; }\r\n\r\n\tpublic int MaxLevel { get; init; }\r\n\r\n\tpublic double CostAt( int level ) =\u003E BaseCost * Math.Pow( CostGrowth, level );\r\n\r\n\tpublic float MultiplierAt( int level ) =\u003E MathF.Pow( EffectGrowth, level );\r\n\r\n\t/// \u003Csummary\u003E\u0022\u002B12%\u0022 - what the next level buys you.\u003C/summary\u003E\r\n\tpublic string PerLevelText =\u003E $\u0022\u002B{(EffectGrowth - 1f) * 100f:0}%\u0022;\r\n\r\n\t/// \u003Csummary\u003ERe-read on hotload so balance edits apply without restarting - see PumpTier.All.\u003C/summary\u003E\r\n\t[SkipHotload]\r\n\tpublic static readonly UpgradeTrack[] All = new UpgradeTrack[]\r\n\t{\r\n\t\tnew()\r\n\t\t{\r\n\t\t\tKind = UpgradeKind.Storage,\r\n\t\t\tName = \u0022Water Tank\u0022,\r\n\t\t\tDescription = \u0022Holds more water, so you can walk away between sales.\u0022,\r\n\t\t\tIcon = \u0022water_drop\u0022,\r\n\t\t\tBaseCost = 150,\r\n\t\t\tCostGrowth = 1.55,\r\n\t\t\tEffectGrowth = 1.12f,\r\n\t\t\tMaxLevel = 200\r\n\t\t},\r\n\t\tnew()\r\n\t\t{\r\n\t\t\tKind = UpgradeKind.Power,\r\n\t\t\tName = \u0022Pump Power\u0022,\r\n\t\t\tDescription = \u0022Every pump pulls up more water.\u0022,\r\n\t\t\tIcon = \u0022fitness_center\u0022,\r\n\t\t\tBaseCost = 250,\r\n\t\t\tCostGrowth = 1.60,\r\n\t\t\tEffectGrowth = 1.06f,\r\n\t\t\tMaxLevel = 200\r\n\t\t},\r\n\t\tnew()\r\n\t\t{\r\n\t\t\tKind = UpgradeKind.Value,\r\n\t\t\tName = \u0022Market Contacts\u0022,\r\n\t\t\tDescription = \u0022People pay better for the same water.\u0022,\r\n\t\t\tIcon = \u0022handshake\u0022,\r\n\t\t\tBaseCost = 400,\r\n\t\t\tCostGrowth = 1.68,\r\n\t\t\tEffectGrowth = 1.05f,\r\n\t\t\tMaxLevel = 200\r\n\t\t},\r\n\t};\r\n\r\n\tpublic static UpgradeTrack Get( UpgradeKind kind ) =\u003E All[(int)kind];\r\n}\r\n"},{"Ident":"fpkreastudios.desertpump","Path":"UI/SettingsPanel.razor","FileName":"SettingsPanel.razor","PackageType":"game","CodeKind":"Game","AssetVersionId":338006,"Code":"@using System\r\n@using Sandbox\r\n@using Sandbox.UI\r\n@namespace DesertPump\r\n@inherits Panel\r\n\r\n\u003Croot class=\u0022settingspanel\u0022\u003E\r\n\r\n\t\u003Cdiv class=\u0022scrim\u0022 onclick=\u0022@Close\u0022\u003E\u003C/div\u003E\r\n\r\n\t\u003Cdiv class=\u0022sheet\u0022\u003E\r\n\r\n\t\t\u003Cdiv class=\u0022head\u0022\u003E\r\n\t\t\t\u003Cdiv class=\u0022title\u0022\u003E\u003Ci\u003Esettings\u003C/i\u003E SETTINGS\u003C/div\u003E\r\n\t\t\t\u003Cdiv class=\u0022closebtn\u0022 onclick=\u0022@Close\u0022\u003E\u003Ci\u003Eclose\u003C/i\u003E\u003C/div\u003E\r\n\t\t\u003C/div\u003E\r\n\r\n\t\t\u003Cdiv class=\u0022group\u0022\u003E\r\n\t\t\t\u003Cdiv class=\u0022grouptitle\u0022\u003EAUDIO\u003C/div\u003E\r\n\r\n\t\t\t\u003Cdiv class=\u0022row\u0022\u003E\r\n\t\t\t\t\u003Cdiv class=\u0022label\u0022\u003EMaster volume\u003C/div\u003E\r\n\t\t\t\t\u003CSliderControl class=\u0022simple\u0022 Value:bind=@Master Min=\u0022@(0f)\u0022 Max=\u0022@(1f)\u0022 Step=\u0022@(0.05f)\u0022\u003E\u003C/SliderControl\u003E\r\n\t\t\t\t\u003Cdiv class=\u0022value\u0022\u003E@Percent( Master )\u003C/div\u003E\r\n\t\t\t\u003C/div\u003E\r\n\r\n\t\t\t\u003Cdiv class=\u0022row\u0022\u003E\r\n\t\t\t\t\u003Cdiv class=\u0022label\u0022\u003EMusic\u003C/div\u003E\r\n\t\t\t\t\u003CSliderControl class=\u0022simple\u0022 Value:bind=@Music Min=\u0022@(0f)\u0022 Max=\u0022@(1f)\u0022 Step=\u0022@(0.05f)\u0022\u003E\u003C/SliderControl\u003E\r\n\t\t\t\t\u003Cdiv class=\u0022value\u0022\u003E@Percent( Music )\u003C/div\u003E\r\n\t\t\t\u003C/div\u003E\r\n\r\n\t\t\t\u003Cdiv class=\u0022row\u0022\u003E\r\n\t\t\t\t\u003Cdiv class=\u0022label\u0022\u003ESound effects\u003C/div\u003E\r\n\t\t\t\t\u003CSliderControl class=\u0022simple\u0022 Value:bind=@Sfx Min=\u0022@(0f)\u0022 Max=\u0022@(1f)\u0022 Step=\u0022@(0.05f)\u0022\u003E\u003C/SliderControl\u003E\r\n\t\t\t\t\u003Cdiv class=\u0022value\u0022\u003E@Percent( Sfx )\u003C/div\u003E\r\n\t\t\t\u003C/div\u003E\r\n\r\n\t\t\t\u003Cdiv class=\u0022row toggle @( Settings.Muted ? \u0022on\u0022 : \u0022\u0022 )\u0022 onclick=\u0022@ToggleMute\u0022\u003E\r\n\t\t\t\t\u003Cdiv class=\u0022label\u0022\u003EMute everything\u003C/div\u003E\r\n\t\t\t\t\u003Cdiv class=\u0022switch\u0022\u003E\u003Cdiv class=\u0022knob\u0022\u003E\u003C/div\u003E\u003C/div\u003E\r\n\t\t\t\u003C/div\u003E\r\n\t\t\u003C/div\u003E\r\n\r\n\t\t\u003Cdiv class=\u0022group\u0022\u003E\r\n\t\t\t\u003Cdiv class=\u0022grouptitle\u0022\u003EGAME\u003C/div\u003E\r\n\r\n\t\t\t\u003Cdiv class=\u0022row toggle @( Settings.AutoSell ? \u0022on\u0022 : \u0022\u0022 )\u0022 onclick=\u0022@ToggleAutoSell\u0022\u003E\r\n\t\t\t\t\u003Cdiv class=\u0022label\u0022\u003E\r\n\t\t\t\t\tAuto-sell when the tank fills\r\n\t\t\t\t\t\u003Cspan class=\u0022sub\u0022\u003EHands off, but you\u0027ll miss the coin sound\u003C/span\u003E\r\n\t\t\t\t\u003C/div\u003E\r\n\t\t\t\t\u003Cdiv class=\u0022switch\u0022\u003E\u003Cdiv class=\u0022knob\u0022\u003E\u003C/div\u003E\u003C/div\u003E\r\n\t\t\t\u003C/div\u003E\r\n\r\n\t\t\t\u003Cdiv class=\u0022row toggle @( Settings.ShowFloatingNumbers ? \u0022on\u0022 : \u0022\u0022 )\u0022 onclick=\u0022@ToggleFloaters\u0022\u003E\r\n\t\t\t\t\u003Cdiv class=\u0022label\u0022\u003E\r\n\t\t\t\t\tFloating numbers\r\n\t\t\t\t\t\u003Cspan class=\u0022sub\u0022\u003EThe little \u002B12L that fly off the pump\u003C/span\u003E\r\n\t\t\t\t\u003C/div\u003E\r\n\t\t\t\t\u003Cdiv class=\u0022switch\u0022\u003E\u003Cdiv class=\u0022knob\u0022\u003E\u003C/div\u003E\u003C/div\u003E\r\n\t\t\t\u003C/div\u003E\r\n\t\t\u003C/div\u003E\r\n\r\n\t\t\u003Cdiv class=\u0022group danger\u0022\u003E\r\n\t\t\t\u003Cdiv class=\u0022grouptitle\u0022\u003EDANGER\u003C/div\u003E\r\n\r\n\t\t\t\u003Cdiv class=\u0022row\u0022\u003E\r\n\t\t\t\t\u003Cdiv class=\u0022label\u0022\u003E\r\n\t\t\t\t\tReset progress\r\n\t\t\t\t\t\u003Cspan class=\u0022sub\u0022\u003EEvery pump, upgrade and coin. Settings are kept.\u003C/span\u003E\r\n\t\t\t\t\u003C/div\u003E\r\n\r\n\t\t\t\t@if ( confirmingReset )\r\n\t\t\t\t{\r\n\t\t\t\t\t\u003Cdiv class=\u0022resetrow\u0022\u003E\r\n\t\t\t\t\t\t\u003Cdiv class=\u0022resetbtn confirm\u0022 onclick=\u0022@DoReset\u0022\u003EYes, wipe it\u003C/div\u003E\r\n\t\t\t\t\t\t\u003Cdiv class=\u0022resetbtn\u0022 onclick=\u0022@( () =\u003E confirmingReset = false )\u0022\u003ECancel\u003C/div\u003E\r\n\t\t\t\t\t\u003C/div\u003E\r\n\t\t\t\t}\r\n\t\t\t\telse\r\n\t\t\t\t{\r\n\t\t\t\t\t\u003Cdiv class=\u0022resetbtn\u0022 onclick=\u0022@( () =\u003E confirmingReset = true )\u0022\u003EReset\u003C/div\u003E\r\n\t\t\t\t}\r\n\t\t\t\u003C/div\u003E\r\n\t\t\u003C/div\u003E\r\n\r\n\t\t\u003Cdiv class=\u0022done\u0022 onclick=\u0022@Close\u0022\u003EDONE\u003C/div\u003E\r\n\r\n\t\u003C/div\u003E\r\n\r\n\u003C/root\u003E\r\n\r\n@code\r\n{\r\n\t/// \u003Csummary\u003ERaised when the player dismisses the settings.\u003C/summary\u003E\r\n\tpublic Action OnClose { get; set; }\r\n\r\n\tstatic PumpSettings Settings =\u003E PumpSettings.Current;\r\n\r\n\tbool confirmingReset;\r\n\r\n\t// Slider bindings. Each setter persists, so a change survives even if the game\r\n\t// is killed rather than closed.\r\n\tfloat Master\r\n\t{\r\n\t\tget =\u003E Settings.MasterVolume;\r\n\t\tset =\u003E Apply( () =\u003E Settings.MasterVolume = value, Settings.MasterVolume == value );\r\n\t}\r\n\r\n\tfloat Music\r\n\t{\r\n\t\tget =\u003E Settings.MusicVolume;\r\n\t\tset =\u003E Apply( () =\u003E Settings.MusicVolume = value, Settings.MusicVolume == value );\r\n\t}\r\n\r\n\tfloat Sfx\r\n\t{\r\n\t\tget =\u003E Settings.SfxVolume;\r\n\t\tset =\u003E Apply( () =\u003E Settings.SfxVolume = value, Settings.SfxVolume == value );\r\n\t}\r\n\r\n\tvoid Apply( Action change, bool unchanged )\r\n\t{\r\n\t\tif ( unchanged ) return;\r\n\r\n\t\tchange();\r\n\t\tSettings.Save();\r\n\t\tStateHasChanged();\r\n\t}\r\n\r\n\tvoid ToggleMute()\r\n\t{\r\n\t\tSettings.Muted = !Settings.Muted;\r\n\t\tSettings.Save();\r\n\t\tStateHasChanged();\r\n\t}\r\n\r\n\tvoid ToggleAutoSell()\r\n\t{\r\n\t\tSettings.AutoSell = !Settings.AutoSell;\r\n\t\tSettings.Save();\r\n\t\tStateHasChanged();\r\n\t}\r\n\r\n\tvoid ToggleFloaters()\r\n\t{\r\n\t\tSettings.ShowFloatingNumbers = !Settings.ShowFloatingNumbers;\r\n\t\tSettings.Save();\r\n\t\tStateHasChanged();\r\n\t}\r\n\r\n\tvoid DoReset()\r\n\t{\r\n\t\tDesertPumpGame.Current?.ResetProgress();\r\n\t\tconfirmingReset = false;\r\n\t\tStateHasChanged();\r\n\t}\r\n\r\n\tvoid Close()\r\n\t{\r\n\t\tconfirmingReset = false;\r\n\t\tOnClose?.Invoke();\r\n\t}\r\n\r\n\tstatic string Percent( float value ) =\u003E $\u0022{value * 100f:0}%\u0022;\r\n\r\n\tprotected override int BuildHash() =\u003E HashCode.Combine(\r\n\t\tSettings.MasterVolume, Settings.MusicVolume, Settings.SfxVolume,\r\n\t\tSettings.Muted, Settings.AutoSell, Settings.ShowFloatingNumbers, confirmingReset );\r\n}\r\n"}]}