diff --git a/src/game-lib/Lib/RandomGen.cs b/src/game-lib/Lib/RandomGen.cs index 7d2d7bda..f9eab914 100644 --- a/src/game-lib/Lib/RandomGen.cs +++ b/src/game-lib/Lib/RandomGen.cs @@ -10,6 +10,7 @@ namespace UfoGameLib.Lib; public class RandomGen : IRandomGen { private readonly Random _random; + private const int DoubleRollPrecision = 1000000; public RandomGen(Random? random = null) { @@ -44,13 +45,14 @@ public int Roll(int @base, int min, int max) return @base + Roll(min, max); } + public double RollDouble(double min, double max) { Contract.Assert(min <= max); - int intMin = (int)(min * 10000); - int intMax = (int)(max * 10000); + int intMin = (int)(min * DoubleRollPrecision); + int intMax = (int)(max * DoubleRollPrecision); int intRoll = Roll(intMin, intMax); - return intRoll / 10000d; + return intRoll / (double)DoubleRollPrecision; } public int Roll(Range range) diff --git a/src/game-lib/Model/Faction.cs b/src/game-lib/Model/Faction.cs index 68666631..9133ea00 100644 --- a/src/game-lib/Model/Faction.cs +++ b/src/game-lib/Model/Faction.cs @@ -138,16 +138,15 @@ public List CreateMissionSites( public void AdvanceTime(List successfulMissions) { - Power = Math.Max(0, Power - successfulMissions.Sum(mission => mission.Site.Modifiers.PowerDamageReward)); - - PowerClimb = Math.Max( - 0, - PowerClimb - successfulMissions.Sum(mission => mission.Site.Modifiers.PowerClimbDamageReward)); - - PowerAcceleration = Math.Max( - 0, - PowerAcceleration - - successfulMissions.Sum(mission => mission.Site.Modifiers.PowerAccelerationDamageReward)); + int powerDamage = successfulMissions.Sum(mission => mission.Site.Modifiers.PowerDamageReward); + Power = Math.Max(0, Power - powerDamage); + + int powerClimbDamage = successfulMissions.Sum(mission => mission.Site.Modifiers.PowerClimbDamageReward); + PowerClimb = Math.Max(0, PowerClimb - powerClimbDamage); + + int powerAccelerationDamage = + successfulMissions.Sum(mission => mission.Site.Modifiers.PowerAccelerationDamageReward); + PowerAcceleration = Math.Max(0, PowerAcceleration - powerAccelerationDamage); if (Power == 0) return; diff --git a/src/game-lib/State/GameStateJsonConverter.cs b/src/game-lib/State/GameStateJsonConverter.cs index 8695671a..3e43bdfc 100644 --- a/src/game-lib/State/GameStateJsonConverter.cs +++ b/src/game-lib/State/GameStateJsonConverter.cs @@ -74,11 +74,15 @@ public static JsonSerializerOptions JsonSerializerOptions() // [2] https://learn.microsoft.com/en-us/dotnet/standard/serialization/system-text-json/custom-contracts IgnoreReadOnlyProperties = false, - // The JsonStringEnumConverter allows serialization of enums as string instead of integers. - // Reference: - // https://learn.microsoft.com/en-us/dotnet/standard/serialization/system-text-json/customize-properties?pivots=dotnet-7-0#enums-as-strings - // https://stackoverflow.com/a/58234964/986533 - Converters = { new JsonStringEnumConverter() }, + Converters = + { + // The JsonStringEnumConverter allows serialization of enums as string instead of integers. + // Reference: + // https://learn.microsoft.com/en-us/dotnet/standard/serialization/system-text-json/customize-properties?pivots=dotnet-7-0#enums-as-strings + // https://stackoverflow.com/a/58234964/986533 + new JsonStringEnumConverter(), + new DoubleDecimalConverter(decimalPlaces: 6) + }, // Required for the ASP.NET Core API to be able to use the default deserializer to deserialize // an instance of GameState. It matches the behavior of JsonSerializerDefaults.Web @@ -91,7 +95,7 @@ public static JsonSerializerOptions JsonSerializerOptions() public override void Write(Utf8JsonWriter writer, GameState value, JsonSerializerOptions options) { JsonNode gameStateNode = JsonSerializer.SerializeToNode(value, SerializationOptions)!; - + ReplaceArrayObjectsPropertiesWithRefs( parent: gameStateNode, objJsonArrayName: nameof(GameState.Missions), @@ -138,7 +142,7 @@ public override GameState Read(ref Utf8JsonReader reader, Type typeToConvert, Js Agents terminatedAgents = Deserialize>(gameStateNode, nameof(GameState.TerminatedAgents)).ToAgents(terminated: true); - + var missions = new Missions( DeserializeObjArrayWithDepRefProps( objJsonArray: JsonArray(gameStateNode, nameof(GameState.Missions)), @@ -161,7 +165,7 @@ public override GameState Read(ref Utf8JsonReader reader, Type typeToConvert, Js deps: missions, (agentObj, mission) => new Agent( - id: DeserializeInt(agentObj,nameof(Agent.Id)), + id: DeserializeInt(agentObj, nameof(Agent.Id)), turnHired: DeserializeInt(agentObj, nameof(Agent.TurnHired)), currentState: DeserializeEnum(agentObj, nameof(Agent.CurrentState)), currentMission: mission, diff --git a/src/lib/Json/DoubleDecimalConverter.cs b/src/lib/Json/DoubleDecimalConverter.cs new file mode 100644 index 00000000..20739222 --- /dev/null +++ b/src/lib/Json/DoubleDecimalConverter.cs @@ -0,0 +1,31 @@ +using System; +using System.Text.Json; +using System.Text.Json.Serialization; + +namespace Lib.Json; + +public class DoubleDecimalConverter : JsonConverter +{ + private readonly int _decimalPlaces; + + public DoubleDecimalConverter(int decimalPlaces) + { + if (decimalPlaces < 0) + { + throw new ArgumentException($"Decimal places ({decimalPlaces}) must be non-negative."); + } + _decimalPlaces = decimalPlaces; + } + + public override double Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) + { + return reader.GetDouble(); + } + + public override void Write(Utf8JsonWriter writer, double value, JsonSerializerOptions options) + { + // Limit the number of decimal places + double roundedValue = Math.Round(value, _decimalPlaces); + writer.WriteNumberValue(roundedValue); + } +} \ No newline at end of file