Refactor game state management to use a unified Stat system and update UI labels for production and corruption

This commit is contained in:
2025-08-23 02:44:54 +02:00
parent 2998e4c02a
commit 18312671d7
23 changed files with 298 additions and 109 deletions

View File

@@ -6,24 +6,16 @@ namespace ParasiticGod.Scripts.Core.Effects;
[GlobalClass]
public partial class AddResourceEffect : Effect
{
[Export] public ResourceType TargetResource { get; set; }
[Export] public Stat 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();
}
state.Modify(TargetResource, Value);
}
public override string ToString()
{
return $"Add {Value} to {TargetResource}";
}
}

View File

@@ -5,9 +5,7 @@ namespace ParasiticGod.Scripts.Core.Effects;
[GlobalClass]
public partial class ApplyBuffEffect : Effect
{
public enum BuffTarget { FaithGeneration }
[Export] public BuffTarget TargetStat { get; set; }
[Export] public Stat TargetStat { get; set; }
[Export] public float Multiplier { get; set; } = 2.0f;
[Export] public double Duration { get; set; } = 30.0;
@@ -21,4 +19,9 @@ public partial class ApplyBuffEffect : Effect
gameState.ActiveBuffs.Add(newBuff);
}
public override string ToString()
{
return $"Apply Buff: x{Multiplier} to {TargetStat} for {Duration} seconds";
}
}

View File

@@ -5,32 +5,21 @@ namespace ParasiticGod.Scripts.Core.Effects;
[GlobalClass]
public partial class ConvertResourceEffect : Effect
{
[Export] public ResourceType FromResource { get; set; }
[Export] public Stat FromResource { get; set; }
[Export] public double FromAmount { get; set; }
[Export] public ResourceType ToResource { get; set; }
[Export] public Stat 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
};
if (!(gameState.Get(FromResource) >= FromAmount)) return;
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);
}
gameState.Set(FromResource, gameState.Get(FromResource) - FromAmount);
gameState.Set(ToResource, gameState.Get(ToResource) + ToAmount);
}
public override string ToString()
{
return $"Convert {FromAmount} {FromResource} to {ToAmount} {ToResource}";
}
}

View File

@@ -8,4 +8,9 @@ public partial class DestroySelfEffect : Effect
public override void Execute(GameState gameState)
{
}
public override string ToString()
{
return "";
}
}

View File

@@ -5,4 +5,9 @@ namespace ParasiticGod.Scripts.Core.Effects;
public abstract partial class Effect : Resource
{
public abstract void Execute(GameState gameState);
public override string ToString()
{
return GetType().Name.Replace("Effect", "");
}
}

View File

@@ -5,7 +5,6 @@ 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; }
@@ -14,17 +13,26 @@ public partial class ModifyStatEffect : Effect
public override void Execute(GameState gameState)
{
if (TargetStat == Stat.FaithPerFollower)
switch (Op)
{
switch (Op)
{
case Operation.Add:
gameState.FaithPerFollower += Value;
break;
case Operation.Multiply:
gameState.FaithPerFollower *= Value;
break;
}
case Operation.Add:
var currentValue = gameState.Get(TargetStat);
gameState.Set(TargetStat, currentValue + Value);
break;
case Operation.Multiply:
var currentValueMul = gameState.Get(TargetStat);
gameState.Set(TargetStat, currentValueMul * Value);
break;
}
}
public override string ToString()
{
return Op switch
{
Operation.Add => $"Add {Value} to {TargetStat}",
Operation.Multiply => $"Multiply {TargetStat} by {Value}",
_ => "Unknown Operation"
};
}
}

View File

@@ -1,3 +0,0 @@
namespace ParasiticGod.Scripts.Core.Effects;
public enum ResourceType { Faith, Followers, Corruption }

View File

@@ -1 +0,0 @@
uid://do6aurfs8oif0

View File

@@ -13,4 +13,9 @@ public partial class UnlockMiracleEffect : Effect
{
}
public override string ToString()
{
return $"Unlock miracles: {string.Join(", ", MiraclesToUnlock)}";
}
}

View File

@@ -6,7 +6,16 @@ public class GameLogic
{
public void UpdateGameState(GameState state, double delta)
{
state.Faith += state.FaithPerSecond * delta;
var totalMultiplier = 1.0;
foreach (var buff in state.ActiveBuffs)
{
totalMultiplier *= buff.Multiplier;
}
var faithPerSecond = state.Get(Stat.Followers) * state.Get(Stat.FaithPerFollower) * totalMultiplier;
state.Modify(Stat.Faith, faithPerSecond * delta);
state.Modify(Stat.Production, state.Get(Stat.ProductionPerSecond) * delta);
state.Modify(Stat.Corruption, state.Get(Stat.CorruptionPerSecond) * delta);
for (var i = state.ActiveBuffs.Count - 1; i >= 0; i--)
{
@@ -21,13 +30,13 @@ public class GameLogic
public bool TryToPerformMiracle(GameState state, MiracleDefinition miracle)
{
if (state.Faith < miracle.FaithCost || state.Followers < miracle.FollowersRequired)
if (state.Get(Stat.Faith) < miracle.FaithCost || state.Get(Stat.Followers) < miracle.FollowersRequired)
{
return false;
}
state.Faith -= miracle.FaithCost;
state.Modify(Stat.Faith, -miracle.FaithCost);
if (miracle.Effects != null)
{
foreach (var effect in miracle.Effects)
@@ -35,9 +44,8 @@ public class GameLogic
effect.Execute(state);
}
}
state.Corruption = Math.Clamp(state.Corruption, 0, 100);
state.Set(Stat.Corruption, Math.Clamp(state.Get(Stat.Corruption), 0, 100));
return true;
}
}

View File

@@ -1,3 +1,4 @@
using System;
using System.Collections.Generic;
using ParasiticGod.Scripts.Core.Effects;
@@ -5,23 +6,32 @@ 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;
private readonly Dictionary<Stat, StatData> _stats = new();
public List<Buff> ActiveBuffs { get; } = [];
public double FaithPerSecond
public GameState()
{
get
// Initialize all stats with their default values
foreach (Stat stat in Enum.GetValues(typeof(Stat)))
{
var totalMultiplier = 1.0;
foreach (var buff in ActiveBuffs)
{
totalMultiplier *= buff.Multiplier;
}
return Followers * FaithPerFollower * totalMultiplier;
_stats[stat] = new StatData();
}
Set(Stat.Faith, 50);
Set(Stat.Followers, 40);
Set(Stat.FaithPerFollower, 0.5);
Set(Stat.ProductionPerSecond, 1.0);
Set(Stat.CorruptionPerSecond, 0.1);
}
public double Get(Stat stat) => _stats[stat].Value;
public void Set(Stat stat, double value) => _stats[stat].Set(value);
public void Modify(Stat stat, double delta) => _stats[stat].Set(Get(stat) + delta);
public void Subscribe(Stat stat, Action<double> listener) => _stats[stat].OnChanged += listener;
public void Unsubscribe(Stat stat, Action<double> listener) => _stats[stat].OnChanged -= listener;
}

View File

@@ -7,22 +7,21 @@ public class EffectDto
{
public string Type { get; set; }
// --- For "AddResource" Effect ---
public ResourceType TargetResource { get; set; }
public Stat 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 Stat FromResource { get; set; }
public double FromAmount { get; set; }
public ResourceType ToResource { get; set; }
public Stat ToResource { get; set; }
public double ToAmount { get; set; }
// --- For "ModifyStat" Effect ---
public ModifyStatEffect.Stat TargetStat { get; set; }
public Stat TargetStat { get; set; }
public ModifyStatEffect.Operation Op { get; set; }
public List<string> MiraclesToUnlock { get; set; }

View File

@@ -84,7 +84,7 @@ public static class MiracleLoader
addResourceEffect.Value = effectDto.Value;
break;
case ApplyBuffEffect applyBuffEffect:
applyBuffEffect.TargetStat = effectDto.TargetBuffStat;
applyBuffEffect.TargetStat = effectDto.TargetStat;
applyBuffEffect.Multiplier = effectDto.Multiplier;
applyBuffEffect.Duration = effectDto.Duration;
break;

17
Scripts/Core/Stat.cs Normal file
View File

@@ -0,0 +1,17 @@
namespace ParasiticGod.Scripts.Core;
public enum Stat
{
// Primary Resources
Faith,
Followers,
Corruption,
Production,
// Passive Generation Stats
ProductionPerSecond,
CorruptionPerSecond,
// Modifying Stats
FaithPerFollower
}

1
Scripts/Core/Stat.cs.uid Normal file
View File

@@ -0,0 +1 @@
uid://lc6dt3ct28vk

17
Scripts/Core/StatData.cs Normal file
View File

@@ -0,0 +1,17 @@
using System;
namespace ParasiticGod.Scripts.Core;
public class StatData
{
public double Value { get; private set; }
public event Action<double> OnChanged;
public void Set(double value)
{
if (!(Math.Abs(Value - value) > 0.001)) return;
Value = value;
OnChanged?.Invoke(Value);
}
}

View File

@@ -0,0 +1 @@
uid://cd1q4nlnrgtp1