Finished first EA Version #1

Merged
Nicola merged 110 commits from dev into main 2026-05-19 20:01:13 +02:00
8 changed files with 119 additions and 39 deletions
Showing only changes of commit 09df4334b9 - Show all commits
+8 -8
View File
@@ -20,7 +20,13 @@
],
"research": "basics",
"crafttime": 4.0,
"texture": "res://Assets/Images/Research/StoneageSymbol.png"
"texture": "res://Assets/Images/Research/StoneageSymbol.png",
"effects": [
{
"stat": "robot_count_increase",
"value": 10
}
]
},
{
"id": "stone_tools",
@@ -36,13 +42,7 @@
],
"research": "stoneage",
"crafttime": 5.0,
"texture": "res://Assets/Images/Items/StoneGearSymbol.png",
"effects": [
{
"stat": "robot_count_increase",
"value": 10
}
]
"texture": "res://Assets/Images/Items/StoneGearSymbol.png"
},
{
"id": "basic_machines",
+1 -1
View File
@@ -5,7 +5,7 @@ public class Inventory
{
public List<Item> items = new List<Item>();
public int maxInventorySize = 16;
public int maxInventorySize = 10;
public event EventHandler OnInventoryUpdate;
public bool AddItem(Item item, int amount)
+16 -4
View File
@@ -15,10 +15,9 @@ public class Research
{
if (!paidResources)
{
foreach (Ingredient ingredient in data.Inputs)
{
GameData.inventory.RemoveItem(ingredient.Item, ingredient.Amount);
}
if (!CanStart()) return ResearchResult.FAILED;
PayResources();
paidResources = true;
}
@@ -31,6 +30,19 @@ public class Research
return ResearchResult.RESEARCHING;
}
public bool CanStart()
{
return GameData.inventory.CanCraft(data.Inputs, 1);
}
public void PayResources()
{
foreach (Ingredient ingredient in data.Inputs)
{
GameData.inventory.RemoveItem(ingredient.Item, ingredient.Amount);
}
}
public void Complete()
{
if (state == ResearchState.RESEARCHED) return;
+5 -5
View File
@@ -4,12 +4,12 @@ using Godot;
public partial class Robot : Node3D
{
private const float EnergyUsePerSecond = 0.2f;
private const float HeatGainPerSecond = 7.5f;
private const float ActiveHeatLossPerSecond = 18f;
private const float IdleHeatLossPerSecond = 9f;
private const float EnergyUsePerSecond = 0.12f;
private const float HeatGainPerSecond = 5f;
private const float ActiveHeatLossPerSecond = 22f;
private const float IdleHeatLossPerSecond = 12f;
private const float CooldownTarget = 35f;
private const float MaintenanceLossPerSecond = 0.04f;
private const float MaintenanceLossPerSecond = 0.025f;
private bool isExecuting = false;
private ProgramNode currentNode;
+9 -9
View File
@@ -2,10 +2,10 @@ using System;
public class SurvivalState
{
private const float HungerDrainPerSecond = 0.035f;
private const float ThirstDrainPerSecond = 0.055f;
private const float PassiveEnergyDrainPerSecond = 0.025f;
private const float AutoConsumeThreshold = 35f;
private const float HungerDrainPerSecond = 0.012f;
private const float ThirstDrainPerSecond = 0.018f;
private const float PassiveEnergyDrainPerSecond = 0.01f;
private const float AutoConsumeThreshold = 30f;
public float hunger = 100f;
public float thirst = 100f;
@@ -48,7 +48,7 @@ public class SurvivalState
if (hunger > AutoConsumeThreshold) return;
if (!GameData.inventory.TryRemoveItem("mushroom", 1)) return;
hunger = Math.Clamp(hunger + 35f, 0f, maxHunger);
hunger = Math.Clamp(hunger + 45f, 0f, maxHunger);
}
private void TryAutoConsumeWater()
@@ -56,7 +56,7 @@ public class SurvivalState
if (thirst > AutoConsumeThreshold) return;
if (!GameData.inventory.TryRemoveItem("water", 1)) return;
thirst = Math.Clamp(thirst + 40f, 0f, maxThirst);
thirst = Math.Clamp(thirst + 50f, 0f, maxThirst);
}
private void TryAutoConsumeEnergy()
@@ -65,19 +65,19 @@ public class SurvivalState
if (GameData.inventory.TryRemoveItem("battery_v2", 1))
{
energy = Math.Clamp(energy + 70f, 0f, maxEnergy);
energy = Math.Clamp(energy + 90f, 0f, maxEnergy);
return;
}
if (GameData.inventory.TryRemoveItem("battery_v1", 1))
{
energy = Math.Clamp(energy + 45f, 0f, maxEnergy);
energy = Math.Clamp(energy + 65f, 0f, maxEnergy);
return;
}
if (GameData.inventory.TryRemoveItem("steam", 1))
{
energy = Math.Clamp(energy + 25f, 0f, maxEnergy);
energy = Math.Clamp(energy + 40f, 0f, maxEnergy);
}
}
+24
View File
@@ -16,6 +16,7 @@ public partial class TestRunner : Node
Run("Robot research effects change robot stats", TestRobotResearchEffects);
Run("Research completion applies effects once", TestResearchCompletionAppliesEffectsOnce);
Run("Research execution pays resources and finishes", TestResearchExecutionPaysResourcesAndFinishes);
Run("Research cannot start without resources", TestResearchCannotStartWithoutResources);
Run("Inventory add failure keeps inventory unchanged", TestInventoryAddFailureKeepsInventoryUnchanged);
Run("Resource extraction and save data roundtrip", TestResourceSaveRoundtrip);
Run("Robot save data roundtrip keeps robot state", TestRobotSaveRoundtrip);
@@ -238,6 +239,29 @@ public partial class TestRunner : Node
AssertEqual(0, GameData.inventory.items.Count, "failed add should not create stacks");
}
private void TestResearchCannotStartWithoutResources()
{
ResearchData researchData = new ResearchData
{
Id = "missing_stones",
Inputs = new List<Ingredient>
{
new Ingredient { Item = "stone", Amount = 3 }
},
Research = "basics",
CraftTime = 1.0,
Texture = "",
Effects = new List<ResearchEffect>()
};
Research research = new Research(researchData);
ResearchResult result = research.Execute(1.0);
AssertFalse(research.CanStart(), "research should not be startable");
AssertEqual(ResearchResult.FAILED, result, "research should fail without resources");
AssertEqual(ResearchState.UNDEFINED, research.state, "research state should stay unchanged");
}
private void TestSplitSaveFilesRoundtrip()
{
GameData.inventory.AddItem(new Item { data = GameData.availableItems["water"] }, 7);
+54 -10
View File
@@ -23,12 +23,20 @@ public partial class ResearchList : PanelContainer
if(currentResearch.Count > 0) toDelete = new List<Research>();
foreach (Research research in currentResearch)
{
if (research.Execute(delta) == ResearchResult.FINISHED)
ResearchResult result = research.Execute(delta);
if (result == ResearchResult.FINISHED)
{
toDelete.Add(research);
RecalculateResearchStates();
SetupGraph();
}
else if (result == ResearchResult.FAILED)
{
research.state = ResearchState.AVAILABLE;
toDelete.Add(research);
RecalculateResearchStates();
SetupGraph();
}
}
foreach (Research delete in toDelete)
{
@@ -133,8 +141,8 @@ public partial class ResearchList : PanelContainer
Button button = new Button
{
Text = "Research",
Disabled = state != ResearchState.AVAILABLE,
Text = GetResearchButtonText(GameData.availableResearch[id], state),
Disabled = state != ResearchState.AVAILABLE || !GameData.availableResearch[id].CanStart(),
TooltipText = tooltipText
};
@@ -171,21 +179,57 @@ public partial class ResearchList : PanelContainer
private void OnResearchPressed(string id)
{
GameData.availableResearch[id].state = ResearchState.RESEARCHING;
currentResearch.Add(GameData.availableResearch[id]);
Research research = GameData.availableResearch[id];
if (!research.CanStart()) return;
if (currentResearch.Contains(research)) return;
research.state = ResearchState.RESEARCHING;
currentResearch.Add(research);
RecalculateResearchStates();
SetupGraph();
}
private string GetResearchButtonText(Research research, ResearchState state)
{
if (state == ResearchState.RESEARCHED) return "Done";
if (state == ResearchState.RESEARCHING) return "Researching";
if (state == ResearchState.LOCKED) return "Locked";
if (!research.CanStart()) return "Missing items";
return "Research";
}
private string GetResearchTooltip(Research research)
{
if (research.data.Effects == null || research.data.Effects.Count <= 0)
{
return Research.GetReadableName(research.data.Id);
}
StringBuilder tooltip = new StringBuilder(Research.GetReadableName(research.data.Id));
tooltip.AppendLine();
tooltip.AppendLine();
tooltip.AppendLine("Costs:");
if (research.data.Inputs.Count <= 0)
{
tooltip.AppendLine("- None");
}
foreach (Ingredient ingredient in research.data.Inputs)
{
tooltip.Append("- ");
tooltip.Append(ItemData.GetReadableName(ingredient.Item));
tooltip.Append(": ");
tooltip.Append(GameData.inventory.GetItemAmount(ingredient.Item));
tooltip.Append("/");
tooltip.AppendLine(ingredient.Amount.ToString());
}
tooltip.AppendLine();
tooltip.Append("Time: ");
tooltip.AppendLine(research.data.CraftTime.ToString("0"));
if (research.data.Effects == null || research.data.Effects.Count <= 0)
{
return tooltip.ToString();
}
tooltip.AppendLine();
tooltip.AppendLine("Effects:");
+2 -2
View File
@@ -304,7 +304,7 @@ public partial class World : Node3D
} while (addedNewItem);
//Step 3: Choose gate items needed based on crafting time and layer it is for (Lower layers -> More advanced items -> More crafting time)
double goalCraftTime = Mathf.Lerp(lowestCraftTime, highestCraftTime, Mathf.Clamp(layer.level/(float)ruinSize, 0, 1));
int ingredientAmount = rand.Next(1, 1 + ruinSize / 2);
int ingredientAmount = Mathf.Clamp(1 + layer.level / 3, 1, 4);
float craftTimeModifier = 0f;
double craftTimeLower, craftTimeUpper;
for (int i = 0; i < ingredientAmount; i++)
@@ -331,7 +331,7 @@ public partial class World : Node3D
layer.gateIngredients.Add(new Ingredient
{
Item = item.Id,
Amount = rand.Next(5 + layer.level, 20 + layer.level)
Amount = rand.Next(3 + layer.level * 2, 9 + layer.level * 4)
});
craftTimeModifier = 0f;
}