Add initial implementation of game mechanics and resources management
This commit is contained in:
29
Scripts/Core/Effects/AddResourceEffect.cs
Normal file
29
Scripts/Core/Effects/AddResourceEffect.cs
Normal file
@@ -0,0 +1,29 @@
|
||||
using System;
|
||||
using Godot;
|
||||
|
||||
namespace ParasiticGod.Scripts.Core.Effects;
|
||||
|
||||
[GlobalClass]
|
||||
public partial class AddResourceEffect : Effect
|
||||
{
|
||||
[Export] public ResourceType TargetResource { get; set; }
|
||||
[Export] public double Value { get; set; }
|
||||
|
||||
public override void Execute(GameState state)
|
||||
{
|
||||
switch (TargetResource)
|
||||
{
|
||||
case ResourceType.Faith:
|
||||
state.Faith += Value;
|
||||
break;
|
||||
case ResourceType.Followers:
|
||||
state.Followers += (long)Value;
|
||||
break;
|
||||
case ResourceType.Corruption:
|
||||
state.Corruption += Value;
|
||||
break;
|
||||
default:
|
||||
throw new ArgumentOutOfRangeException();
|
||||
}
|
||||
}
|
||||
}
|
1
Scripts/Core/Effects/AddResourceEffect.cs.uid
Normal file
1
Scripts/Core/Effects/AddResourceEffect.cs.uid
Normal file
@@ -0,0 +1 @@
|
||||
uid://flyhl4i86han
|
24
Scripts/Core/Effects/ApplyBuffEffect.cs
Normal file
24
Scripts/Core/Effects/ApplyBuffEffect.cs
Normal file
@@ -0,0 +1,24 @@
|
||||
using Godot;
|
||||
|
||||
namespace ParasiticGod.Scripts.Core.Effects;
|
||||
|
||||
[GlobalClass]
|
||||
public partial class ApplyBuffEffect : Effect
|
||||
{
|
||||
public enum BuffTarget { FaithGeneration }
|
||||
|
||||
[Export] public BuffTarget TargetStat { get; set; }
|
||||
[Export] public float Multiplier { get; set; } = 2.0f;
|
||||
[Export] public double Duration { get; set; } = 30.0;
|
||||
|
||||
public override void Execute(GameState gameState)
|
||||
{
|
||||
var newBuff = new Buff
|
||||
{
|
||||
Multiplier = Multiplier,
|
||||
Duration = Duration
|
||||
};
|
||||
|
||||
gameState.ActiveBuffs.Add(newBuff);
|
||||
}
|
||||
}
|
1
Scripts/Core/Effects/ApplyBuffEffect.cs.uid
Normal file
1
Scripts/Core/Effects/ApplyBuffEffect.cs.uid
Normal file
@@ -0,0 +1 @@
|
||||
uid://cmhd8jmckgtep
|
7
Scripts/Core/Effects/Buff.cs
Normal file
7
Scripts/Core/Effects/Buff.cs
Normal file
@@ -0,0 +1,7 @@
|
||||
namespace ParasiticGod.Scripts.Core.Effects;
|
||||
|
||||
public class Buff
|
||||
{
|
||||
public float Multiplier { get; set; } = 1.0f;
|
||||
public double Duration { get; set; }
|
||||
}
|
1
Scripts/Core/Effects/Buff.cs.uid
Normal file
1
Scripts/Core/Effects/Buff.cs.uid
Normal file
@@ -0,0 +1 @@
|
||||
uid://c5fq6vt4uyce2
|
36
Scripts/Core/Effects/ConvertResourceEffect.cs
Normal file
36
Scripts/Core/Effects/ConvertResourceEffect.cs
Normal file
@@ -0,0 +1,36 @@
|
||||
using Godot;
|
||||
|
||||
namespace ParasiticGod.Scripts.Core.Effects;
|
||||
|
||||
[GlobalClass]
|
||||
public partial class ConvertResourceEffect : Effect
|
||||
{
|
||||
[Export] public ResourceType FromResource { get; set; }
|
||||
[Export] public double FromAmount { get; set; }
|
||||
[Export] public ResourceType ToResource { get; set; }
|
||||
[Export] public double ToAmount { get; set; }
|
||||
|
||||
public override void Execute(GameState gameState)
|
||||
{
|
||||
double GetValue(ResourceType type) => type switch {
|
||||
ResourceType.Faith => gameState.Faith,
|
||||
ResourceType.Followers => gameState.Followers,
|
||||
ResourceType.Corruption => gameState.Corruption,
|
||||
_ => 0
|
||||
};
|
||||
|
||||
void SetValue(ResourceType type, double value) {
|
||||
switch(type) {
|
||||
case ResourceType.Faith: gameState.Faith = value; break;
|
||||
case ResourceType.Followers: gameState.Followers = (long)value; break;
|
||||
case ResourceType.Corruption: gameState.Corruption = value; break;
|
||||
}
|
||||
}
|
||||
|
||||
if (GetValue(FromResource) >= FromAmount)
|
||||
{
|
||||
SetValue(FromResource, GetValue(FromResource) - FromAmount);
|
||||
SetValue(ToResource, GetValue(ToResource) + ToAmount);
|
||||
}
|
||||
}
|
||||
}
|
1
Scripts/Core/Effects/ConvertResourceEffect.cs.uid
Normal file
1
Scripts/Core/Effects/ConvertResourceEffect.cs.uid
Normal file
@@ -0,0 +1 @@
|
||||
uid://chiq1n5fde3eo
|
11
Scripts/Core/Effects/DestroySelfEffect.cs
Normal file
11
Scripts/Core/Effects/DestroySelfEffect.cs
Normal file
@@ -0,0 +1,11 @@
|
||||
using Godot;
|
||||
|
||||
namespace ParasiticGod.Scripts.Core.Effects;
|
||||
|
||||
[GlobalClass]
|
||||
public partial class DestroySelfEffect : Effect
|
||||
{
|
||||
public override void Execute(GameState gameState)
|
||||
{
|
||||
}
|
||||
}
|
1
Scripts/Core/Effects/DestroySelfEffect.cs.uid
Normal file
1
Scripts/Core/Effects/DestroySelfEffect.cs.uid
Normal file
@@ -0,0 +1 @@
|
||||
uid://dhnma6yerqpwn
|
8
Scripts/Core/Effects/Effect.cs
Normal file
8
Scripts/Core/Effects/Effect.cs
Normal file
@@ -0,0 +1,8 @@
|
||||
using Godot;
|
||||
|
||||
namespace ParasiticGod.Scripts.Core.Effects;
|
||||
|
||||
public abstract partial class Effect : Resource
|
||||
{
|
||||
public abstract void Execute(GameState gameState);
|
||||
}
|
1
Scripts/Core/Effects/Effect.cs.uid
Normal file
1
Scripts/Core/Effects/Effect.cs.uid
Normal file
@@ -0,0 +1 @@
|
||||
uid://c1futvi1xm03q
|
30
Scripts/Core/Effects/ModifyStatEffect.cs
Normal file
30
Scripts/Core/Effects/ModifyStatEffect.cs
Normal file
@@ -0,0 +1,30 @@
|
||||
using Godot;
|
||||
|
||||
namespace ParasiticGod.Scripts.Core.Effects;
|
||||
|
||||
[GlobalClass]
|
||||
public partial class ModifyStatEffect : Effect
|
||||
{
|
||||
public enum Stat { FaithPerFollower }
|
||||
public enum Operation { Add, Multiply }
|
||||
|
||||
[Export] public Stat TargetStat { get; set; }
|
||||
[Export] public Operation Op { get; set; }
|
||||
[Export] public double Value { get; set; }
|
||||
|
||||
public override void Execute(GameState gameState)
|
||||
{
|
||||
if (TargetStat == Stat.FaithPerFollower)
|
||||
{
|
||||
switch (Op)
|
||||
{
|
||||
case Operation.Add:
|
||||
gameState.FaithPerFollower += Value;
|
||||
break;
|
||||
case Operation.Multiply:
|
||||
gameState.FaithPerFollower *= Value;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
1
Scripts/Core/Effects/ModifyStatEffect.cs.uid
Normal file
1
Scripts/Core/Effects/ModifyStatEffect.cs.uid
Normal file
@@ -0,0 +1 @@
|
||||
uid://dy6avn8snuuq1
|
3
Scripts/Core/Effects/ResourceType.cs
Normal file
3
Scripts/Core/Effects/ResourceType.cs
Normal file
@@ -0,0 +1,3 @@
|
||||
namespace ParasiticGod.Scripts.Core.Effects;
|
||||
|
||||
public enum ResourceType { Faith, Followers, Corruption }
|
1
Scripts/Core/Effects/ResourceType.cs.uid
Normal file
1
Scripts/Core/Effects/ResourceType.cs.uid
Normal file
@@ -0,0 +1 @@
|
||||
uid://do6aurfs8oif0
|
16
Scripts/Core/Effects/UnlockMiracleEffect.cs
Normal file
16
Scripts/Core/Effects/UnlockMiracleEffect.cs
Normal file
@@ -0,0 +1,16 @@
|
||||
using Godot;
|
||||
using Godot.Collections;
|
||||
|
||||
namespace ParasiticGod.Scripts.Core.Effects;
|
||||
|
||||
[GlobalClass]
|
||||
public partial class UnlockMiracleEffect : Effect
|
||||
{
|
||||
[Export]
|
||||
public Array<string> MiraclesToUnlock { get; set; }
|
||||
|
||||
public override void Execute(GameState gameState)
|
||||
{
|
||||
|
||||
}
|
||||
}
|
1
Scripts/Core/Effects/UnlockMiracleEffect.cs.uid
Normal file
1
Scripts/Core/Effects/UnlockMiracleEffect.cs.uid
Normal file
@@ -0,0 +1 @@
|
||||
uid://c1oieyvbcqjcc
|
43
Scripts/Core/GameLogic.cs
Normal file
43
Scripts/Core/GameLogic.cs
Normal file
@@ -0,0 +1,43 @@
|
||||
using System;
|
||||
|
||||
namespace ParasiticGod.Scripts.Core;
|
||||
|
||||
public class GameLogic
|
||||
{
|
||||
public void UpdateGameState(GameState state, double delta)
|
||||
{
|
||||
state.Faith += state.FaithPerSecond * delta;
|
||||
|
||||
for (var i = state.ActiveBuffs.Count - 1; i >= 0; i--)
|
||||
{
|
||||
var buff = state.ActiveBuffs[i];
|
||||
buff.Duration -= delta;
|
||||
if (buff.Duration <= 0)
|
||||
{
|
||||
state.ActiveBuffs.RemoveAt(i);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public bool TryToPerformMiracle(GameState state, MiracleDefinition miracle)
|
||||
{
|
||||
if (state.Faith < miracle.FaithCost || state.Followers < miracle.FollowersRequired)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
state.Faith -= miracle.FaithCost;
|
||||
|
||||
if (miracle.Effects != null)
|
||||
{
|
||||
foreach (var effect in miracle.Effects)
|
||||
{
|
||||
effect.Execute(state);
|
||||
}
|
||||
}
|
||||
|
||||
state.Corruption = Math.Clamp(state.Corruption, 0, 100);
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
1
Scripts/Core/GameLogic.cs.uid
Normal file
1
Scripts/Core/GameLogic.cs.uid
Normal file
@@ -0,0 +1 @@
|
||||
uid://bgnfh4rd780td
|
27
Scripts/Core/GameState.cs
Normal file
27
Scripts/Core/GameState.cs
Normal file
@@ -0,0 +1,27 @@
|
||||
using System.Collections.Generic;
|
||||
using ParasiticGod.Scripts.Core.Effects;
|
||||
|
||||
namespace ParasiticGod.Scripts.Core;
|
||||
|
||||
public class GameState
|
||||
{
|
||||
public double Faith { get; set; } = 50.0;
|
||||
public double FaithPerFollower { get; set; } = 0.5;
|
||||
public long Followers { get; set; } = 40;
|
||||
public double Corruption { get; set; } = 0.0;
|
||||
|
||||
public List<Buff> ActiveBuffs { get; } = [];
|
||||
|
||||
public double FaithPerSecond
|
||||
{
|
||||
get
|
||||
{
|
||||
var totalMultiplier = 1.0;
|
||||
foreach (var buff in ActiveBuffs)
|
||||
{
|
||||
totalMultiplier *= buff.Multiplier;
|
||||
}
|
||||
return Followers * FaithPerFollower * totalMultiplier;
|
||||
}
|
||||
}
|
||||
}
|
1
Scripts/Core/GameState.cs.uid
Normal file
1
Scripts/Core/GameState.cs.uid
Normal file
@@ -0,0 +1 @@
|
||||
uid://d3on25ypcw528
|
1
Scripts/Core/Miracle.cs.uid
Normal file
1
Scripts/Core/Miracle.cs.uid
Normal file
@@ -0,0 +1 @@
|
||||
uid://cerwpe1s25yim
|
18
Scripts/Core/MiracleDefinition.cs
Normal file
18
Scripts/Core/MiracleDefinition.cs
Normal file
@@ -0,0 +1,18 @@
|
||||
using Godot;
|
||||
using Godot.Collections;
|
||||
using ParasiticGod.Scripts.Core.Effects;
|
||||
|
||||
namespace ParasiticGod.Scripts.Core;
|
||||
|
||||
[GlobalClass]
|
||||
public partial class MiracleDefinition : Resource
|
||||
{
|
||||
public string Id { get; set; }
|
||||
public bool UnlockedByDefault { get; set; }
|
||||
|
||||
[Export] public string Name { get; set; }
|
||||
[Export] public double FaithCost { get; set; }
|
||||
[Export] public long FollowersRequired { get; set; }
|
||||
|
||||
[Export] public Array<Effect> Effects { get; set; }
|
||||
}
|
1
Scripts/Core/MiracleDefinition.cs.uid
Normal file
1
Scripts/Core/MiracleDefinition.cs.uid
Normal file
@@ -0,0 +1 @@
|
||||
uid://cfn3mx12xism5
|
38
Scripts/Core/MiracleDto.cs
Normal file
38
Scripts/Core/MiracleDto.cs
Normal file
@@ -0,0 +1,38 @@
|
||||
using System.Collections.Generic;
|
||||
using ParasiticGod.Scripts.Core.Effects;
|
||||
|
||||
namespace ParasiticGod.Scripts.Core;
|
||||
|
||||
public class EffectDto
|
||||
{
|
||||
public string Type { get; set; }
|
||||
// --- For "AddResource" Effect ---
|
||||
public ResourceType TargetResource { get; set; }
|
||||
public double Value { get; set; }
|
||||
|
||||
// --- For "ApplyBuff" Effect ---
|
||||
public ApplyBuffEffect.BuffTarget TargetBuffStat { get; set; }
|
||||
public float Multiplier { get; set; }
|
||||
public double Duration { get; set; }
|
||||
|
||||
// --- For "ConvertResource" Effect ---
|
||||
public ResourceType FromResource { get; set; }
|
||||
public double FromAmount { get; set; }
|
||||
public ResourceType ToResource { get; set; }
|
||||
public double ToAmount { get; set; }
|
||||
|
||||
// --- For "ModifyStat" Effect ---
|
||||
public ModifyStatEffect.Stat TargetStat { get; set; }
|
||||
public ModifyStatEffect.Operation Op { get; set; }
|
||||
|
||||
public List<string> MiraclesToUnlock { get; set; }
|
||||
}
|
||||
|
||||
public class MiracleDto
|
||||
{
|
||||
public string Name { get; set; }
|
||||
public double FaithCost { get; set; }
|
||||
public long FollowersRequired { get; set; }
|
||||
public bool UnlockedByDefault { get; set; }
|
||||
public List<EffectDto> Effects { get; set; }
|
||||
}
|
1
Scripts/Core/MiracleDto.cs.uid
Normal file
1
Scripts/Core/MiracleDto.cs.uid
Normal file
@@ -0,0 +1 @@
|
||||
uid://ba8j34h6ps8di
|
113
Scripts/Core/MiracleLoader.cs
Normal file
113
Scripts/Core/MiracleLoader.cs
Normal file
@@ -0,0 +1,113 @@
|
||||
using System;
|
||||
using System.Text.Json;
|
||||
using Godot;
|
||||
using Godot.Collections;
|
||||
using Newtonsoft.Json;
|
||||
using ParasiticGod.Scripts.Core.Effects;
|
||||
|
||||
namespace ParasiticGod.Scripts.Core;
|
||||
|
||||
public static class MiracleLoader
|
||||
{
|
||||
private static readonly System.Collections.Generic.Dictionary<string, Type> EffectRegistry = new()
|
||||
{
|
||||
{ "AddResource", typeof(AddResourceEffect) },
|
||||
{ "ApplyBuff", typeof(ApplyBuffEffect) },
|
||||
{ "ConvertResource", typeof(ConvertResourceEffect) },
|
||||
{ "ModifyStat", typeof(ModifyStatEffect) },
|
||||
{ "UnlockMiracle", typeof(UnlockMiracleEffect) },
|
||||
{ "DestroySelf", typeof(DestroySelfEffect) }
|
||||
};
|
||||
|
||||
public static System.Collections.Generic.Dictionary<string, MiracleDefinition> LoadMiraclesFromDirectory(string path)
|
||||
{
|
||||
var loadedMiracles = new System.Collections.Generic.Dictionary<string, MiracleDefinition>();
|
||||
using var dir = DirAccess.Open(path);
|
||||
if (dir == null) return loadedMiracles;
|
||||
|
||||
dir.ListDirBegin();
|
||||
var fileName = dir.GetNext();
|
||||
while (!string.IsNullOrEmpty(fileName))
|
||||
{
|
||||
if (!dir.CurrentIsDir() && fileName.EndsWith(".json"))
|
||||
{
|
||||
var filePath = path.PathJoin(fileName);
|
||||
var fileNameNoExt = fileName.GetBaseName();
|
||||
var miracle = LoadMiracleFromFile(filePath, fileNameNoExt); // Pass the ID
|
||||
if (miracle != null)
|
||||
{
|
||||
loadedMiracles.Add(fileNameNoExt, miracle);
|
||||
}
|
||||
}
|
||||
fileName = dir.GetNext();
|
||||
}
|
||||
|
||||
GD.Print($"Loaded {loadedMiracles.Count} miracles from {path}");
|
||||
return loadedMiracles;
|
||||
}
|
||||
|
||||
private static MiracleDefinition LoadMiracleFromFile(string filePath, string miracleId)
|
||||
{
|
||||
var fileContent = FileAccess.GetFileAsString(filePath);
|
||||
if (string.IsNullOrEmpty(fileContent))
|
||||
{
|
||||
GD.PushError($"Failed to read file or file is empty: {filePath}");
|
||||
return null;
|
||||
}
|
||||
|
||||
var miracleDto = JsonConvert.DeserializeObject<MiracleDto>(fileContent);
|
||||
if (miracleDto == null)
|
||||
{
|
||||
GD.PushError($"Failed to deserialize miracle JSON: {filePath}");
|
||||
return null;
|
||||
}
|
||||
|
||||
var miracleDef = new MiracleDefinition
|
||||
{
|
||||
Id = miracleId,
|
||||
UnlockedByDefault = miracleDto.UnlockedByDefault,
|
||||
Name = miracleDto.Name,
|
||||
FaithCost = miracleDto.FaithCost,
|
||||
FollowersRequired = miracleDto.FollowersRequired,
|
||||
Effects = []
|
||||
};
|
||||
|
||||
foreach (var effectDto in miracleDto.Effects)
|
||||
{
|
||||
if (EffectRegistry.TryGetValue(effectDto.Type, out var effectType))
|
||||
{
|
||||
var effectInstance = (Effect)Activator.CreateInstance(effectType);
|
||||
switch (effectInstance)
|
||||
{
|
||||
case AddResourceEffect addResourceEffect:
|
||||
addResourceEffect.TargetResource = effectDto.TargetResource;
|
||||
addResourceEffect.Value = effectDto.Value;
|
||||
break;
|
||||
case ApplyBuffEffect applyBuffEffect:
|
||||
applyBuffEffect.TargetStat = effectDto.TargetBuffStat;
|
||||
applyBuffEffect.Multiplier = effectDto.Multiplier;
|
||||
applyBuffEffect.Duration = effectDto.Duration;
|
||||
break;
|
||||
case ConvertResourceEffect convertResourceEffect:
|
||||
convertResourceEffect.FromResource = effectDto.FromResource;
|
||||
convertResourceEffect.FromAmount = effectDto.FromAmount;
|
||||
convertResourceEffect.ToResource = effectDto.ToResource;
|
||||
convertResourceEffect.ToAmount = effectDto.ToAmount;
|
||||
break;
|
||||
case ModifyStatEffect modifyStatEffect:
|
||||
modifyStatEffect.TargetStat = effectDto.TargetStat;
|
||||
modifyStatEffect.Op = effectDto.Op;
|
||||
modifyStatEffect.Value = effectDto.Value;
|
||||
break;
|
||||
case UnlockMiracleEffect unlockMiracleEffect:
|
||||
unlockMiracleEffect.MiraclesToUnlock = new Array<string>(effectDto.MiraclesToUnlock);
|
||||
break;
|
||||
}
|
||||
|
||||
miracleDef.Effects.Add(effectInstance);
|
||||
}
|
||||
}
|
||||
|
||||
return miracleDef;
|
||||
}
|
||||
}
|
1
Scripts/Core/MiracleLoader.cs.uid
Normal file
1
Scripts/Core/MiracleLoader.cs.uid
Normal file
@@ -0,0 +1 @@
|
||||
uid://bpagwiy55t230
|
10
Scripts/Core/TierDefinition.cs
Normal file
10
Scripts/Core/TierDefinition.cs
Normal file
@@ -0,0 +1,10 @@
|
||||
using Godot;
|
||||
|
||||
namespace ParasiticGod.Scripts.Core;
|
||||
|
||||
[GlobalClass]
|
||||
public partial class TierDefinition : Resource
|
||||
{
|
||||
[Export] public PackedScene Scene { get; private set; }
|
||||
[Export] public long Threshold { get; private set; }
|
||||
}
|
1
Scripts/Core/TierDefinition.cs.uid
Normal file
1
Scripts/Core/TierDefinition.cs.uid
Normal file
@@ -0,0 +1 @@
|
||||
uid://c7hh0cy0yrdt8
|
10
Scripts/Follower.cs
Normal file
10
Scripts/Follower.cs
Normal file
@@ -0,0 +1,10 @@
|
||||
using Godot;
|
||||
|
||||
namespace ParasiticGod.Scripts;
|
||||
|
||||
[GlobalClass]
|
||||
public partial class Follower : Node2D
|
||||
{
|
||||
public enum FollowerTier { Tier1, Tier2, Tier3, Tier4, Tier5 }
|
||||
[Export] public FollowerTier Tier { get; private set; }
|
||||
}
|
1
Scripts/Follower.cs.uid
Normal file
1
Scripts/Follower.cs.uid
Normal file
@@ -0,0 +1 @@
|
||||
uid://cj5libcgnhjml
|
27
Scripts/FollowerMarker.cs
Normal file
27
Scripts/FollowerMarker.cs
Normal file
@@ -0,0 +1,27 @@
|
||||
using Godot;
|
||||
|
||||
namespace ParasiticGod.Scripts;
|
||||
|
||||
[GlobalClass]
|
||||
public partial class FollowerMarker : Marker2D
|
||||
{
|
||||
public bool IsOccupied { get; private set; }
|
||||
public Follower FollowerInstance { get; private set; }
|
||||
|
||||
public void PlaceFollower(Follower followerInstance)
|
||||
{
|
||||
if (IsOccupied) return;
|
||||
AddChild(followerInstance);
|
||||
followerInstance.Position = Vector2.Zero;
|
||||
IsOccupied = true;
|
||||
FollowerInstance = followerInstance;
|
||||
}
|
||||
|
||||
public void RemoveFollower()
|
||||
{
|
||||
if (!IsOccupied) return;
|
||||
FollowerInstance.QueueFree();
|
||||
FollowerInstance = null;
|
||||
IsOccupied = false;
|
||||
}
|
||||
}
|
1
Scripts/FollowerMarker.cs.uid
Normal file
1
Scripts/FollowerMarker.cs.uid
Normal file
@@ -0,0 +1 @@
|
||||
uid://djaf0gv8s7qib
|
116
Scripts/PopulationVisualizer.cs
Normal file
116
Scripts/PopulationVisualizer.cs
Normal file
@@ -0,0 +1,116 @@
|
||||
using System.Collections.Generic;
|
||||
using Godot;
|
||||
using Godot.Collections;
|
||||
using ParasiticGod.Scripts.Core;
|
||||
using ParasiticGod.Scripts.Singletons;
|
||||
|
||||
namespace ParasiticGod.Scripts;
|
||||
|
||||
[GlobalClass]
|
||||
public partial class PopulationVisualizer : Node
|
||||
{
|
||||
[Export] private Node2D _markersContainer;
|
||||
[Export] private int _unitsPerMarker = 5;
|
||||
[Export] private Array<TierDefinition> _tiers;
|
||||
|
||||
private readonly List<FollowerMarker> _markers = [];
|
||||
private long _lastKnownUnitCount = -1;
|
||||
private int _lastKnownTierIndex = -1;
|
||||
private bool _isUpdating = false;
|
||||
|
||||
public override void _Ready()
|
||||
{
|
||||
foreach (var child in _markersContainer.GetChildren())
|
||||
{
|
||||
if (child is FollowerMarker marker)
|
||||
{
|
||||
_markers.Add(marker);
|
||||
}
|
||||
}
|
||||
|
||||
GameBus.Instance.StateChanged += OnStateChanged;
|
||||
}
|
||||
|
||||
public override void _ExitTree()
|
||||
{
|
||||
GameBus.Instance.StateChanged -= OnStateChanged;
|
||||
}
|
||||
|
||||
private void OnStateChanged(GameState newState)
|
||||
{
|
||||
if (_isUpdating) return;
|
||||
|
||||
var currentUnitCount = newState.Followers;
|
||||
|
||||
var currentMarkersToShow = (int)currentUnitCount / _unitsPerMarker;
|
||||
var lastMarkersToShow = (int)_lastKnownUnitCount / _unitsPerMarker;
|
||||
var newTierIndex = GetTierIndex(currentUnitCount);
|
||||
|
||||
if (currentMarkersToShow != lastMarkersToShow || newTierIndex != _lastKnownTierIndex)
|
||||
{
|
||||
UpdateVisualsProgressively(currentUnitCount, newTierIndex);
|
||||
}
|
||||
}
|
||||
|
||||
private int GetTierIndex(long currentUnitCount)
|
||||
{
|
||||
for (var i = _tiers.Count - 1; i >= 0; i--)
|
||||
{
|
||||
if (currentUnitCount >= _tiers[i].Threshold)
|
||||
{
|
||||
return i;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
private async void UpdateVisualsProgressively(long currentUnitCount, int newTierIndex)
|
||||
{
|
||||
_isUpdating = true;
|
||||
|
||||
if (newTierIndex < 0)
|
||||
{
|
||||
_isUpdating = false;
|
||||
return;
|
||||
}
|
||||
|
||||
var followersToShow = (int)currentUnitCount / _unitsPerMarker;
|
||||
var currentTier = _tiers[newTierIndex];
|
||||
|
||||
for (var i = 0; i < _markers.Count; i++)
|
||||
{
|
||||
var marker = _markers[i];
|
||||
var needsChange = false;
|
||||
|
||||
if (i < followersToShow)
|
||||
{
|
||||
// Note: The 'Follower' script would need a way to know its tier index or resource path
|
||||
// to do a perfect comparison. For now, we'll just check for occupancy.
|
||||
if (!marker.IsOccupied || _lastKnownTierIndex != newTierIndex)
|
||||
{
|
||||
if (marker.IsOccupied) marker.RemoveFollower();
|
||||
var followerInstance = currentTier.Scene.Instantiate<Follower>();
|
||||
marker.PlaceFollower(followerInstance);
|
||||
needsChange = true;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (marker.IsOccupied)
|
||||
{
|
||||
marker.RemoveFollower();
|
||||
needsChange = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (needsChange)
|
||||
{
|
||||
await ToSignal(GetTree().CreateTimer(0.1f), SceneTreeTimer.SignalName.Timeout);
|
||||
}
|
||||
}
|
||||
|
||||
_lastKnownUnitCount = currentUnitCount;
|
||||
_lastKnownTierIndex = newTierIndex;
|
||||
_isUpdating = false;
|
||||
}
|
||||
}
|
1
Scripts/PopulationVisualizer.cs.uid
Normal file
1
Scripts/PopulationVisualizer.cs.uid
Normal file
@@ -0,0 +1 @@
|
||||
uid://dj2wyrq07gfp2
|
76
Scripts/Singletons/GameBus.cs
Normal file
76
Scripts/Singletons/GameBus.cs
Normal file
@@ -0,0 +1,76 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Godot;
|
||||
using ParasiticGod.Scripts.Core;
|
||||
using ParasiticGod.Scripts.Core.Effects;
|
||||
|
||||
namespace ParasiticGod.Scripts.Singletons;
|
||||
|
||||
public partial class GameBus : Node
|
||||
{
|
||||
public static GameBus Instance { get; private set; }
|
||||
public Dictionary<string, MiracleDefinition> AllMiracles { get; private set; }
|
||||
|
||||
private readonly GameState _gameState = new();
|
||||
private readonly GameLogic _gameLogic = new();
|
||||
|
||||
public event Action<GameState> StateChanged;
|
||||
public event Action<MiracleDefinition> MiraclePerformed;
|
||||
public event Action<List<MiracleDefinition>> MiraclesUnlocked;
|
||||
public event Action<MiracleDefinition> MiracleCompleted;
|
||||
|
||||
public override void _EnterTree()
|
||||
{
|
||||
Instance = this;
|
||||
AllMiracles = MiracleLoader.LoadMiraclesFromDirectory("user://Mods/Miracles");
|
||||
}
|
||||
|
||||
public override void _ExitTree()
|
||||
{
|
||||
Instance = null;
|
||||
}
|
||||
|
||||
public override void _Process(double delta)
|
||||
{
|
||||
_gameLogic.UpdateGameState(_gameState, delta);
|
||||
StateChanged?.Invoke(_gameState);
|
||||
|
||||
if (_gameState.Corruption >= 100)
|
||||
{
|
||||
GD.Print("The world has died!");
|
||||
GetTree().Quit(); // For now
|
||||
}
|
||||
}
|
||||
|
||||
public void PerformMiracle(MiracleDefinition miracle)
|
||||
{
|
||||
if (_gameLogic.TryToPerformMiracle(_gameState, miracle))
|
||||
{
|
||||
MiraclePerformed?.Invoke(miracle);
|
||||
|
||||
var miraclesToUnlock = new List<MiracleDefinition>();
|
||||
foreach (var effect in miracle.Effects)
|
||||
{
|
||||
if (effect is UnlockMiracleEffect unlockEffect)
|
||||
{
|
||||
foreach (var id in unlockEffect.MiraclesToUnlock)
|
||||
{
|
||||
if (AllMiracles.TryGetValue(id, out var def))
|
||||
{
|
||||
miraclesToUnlock.Add(def);
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (effect is DestroySelfEffect)
|
||||
{
|
||||
MiracleCompleted?.Invoke(miracle);
|
||||
}
|
||||
}
|
||||
|
||||
if (miraclesToUnlock.Count > 0)
|
||||
{
|
||||
MiraclesUnlocked?.Invoke(miraclesToUnlock);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
1
Scripts/Singletons/GameBus.cs.uid
Normal file
1
Scripts/Singletons/GameBus.cs.uid
Normal file
@@ -0,0 +1 @@
|
||||
uid://bxtp262r58pb6
|
Reference in New Issue
Block a user