Finished first EA Version #1
@@ -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",
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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 GetResearchTooltip(Research research)
|
||||
private string GetResearchButtonText(Research research, ResearchState state)
|
||||
{
|
||||
if (research.data.Effects == null || research.data.Effects.Count <= 0)
|
||||
{
|
||||
return Research.GetReadableName(research.data.Id);
|
||||
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)
|
||||
{
|
||||
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:");
|
||||
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user