Compare commits
1 Commits
dev
..
ad65698773
| Author | SHA1 | Date | |
|---|---|---|---|
| ad65698773 |
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -15,10 +15,3 @@ script = ExtResource("2_j80uv")
|
|||||||
[node name="CollisionShape3D" type="CollisionShape3D" parent="." unique_id=1405728816]
|
[node name="CollisionShape3D" type="CollisionShape3D" parent="." unique_id=1405728816]
|
||||||
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, -0.05883789, 0.29821777, -0.01171875)
|
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, -0.05883789, 0.29821777, -0.01171875)
|
||||||
shape = SubResource("BoxShape3D_vquur")
|
shape = SubResource("BoxShape3D_vquur")
|
||||||
|
|
||||||
[node name="SpotLight3D" type="SpotLight3D" parent="." unique_id=1638370223]
|
|
||||||
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0.37939095, -0.31055498)
|
|
||||||
light_energy = 16.0
|
|
||||||
spot_range = 4.0
|
|
||||||
spot_attenuation = 0.0
|
|
||||||
spot_angle = 75.0
|
|
||||||
|
|||||||
@@ -96,28 +96,4 @@ public class RobotSaveData
|
|||||||
public float Maintenance { get; set; }
|
public float Maintenance { get; set; }
|
||||||
public bool IsCoolingDown { get; set; }
|
public bool IsCoolingDown { get; set; }
|
||||||
public bool IsBroken { get; set; }
|
public bool IsBroken { get; set; }
|
||||||
public List<NodeSaveData> RunningProgramNodes { get; set; }
|
|
||||||
public string ProgramStartNode { get; set; }
|
|
||||||
public string CurrentNode { get; set; }
|
|
||||||
public bool IsExecuting { get; set; }
|
|
||||||
}
|
|
||||||
|
|
||||||
public class NodeSaveData
|
|
||||||
{
|
|
||||||
public string NodeType { get; set; }
|
|
||||||
public string EditorNodeId { get; set; }
|
|
||||||
public string NextEditorNodeId { get; set; }
|
|
||||||
public string NegativeEditorNodeId { get; set; }
|
|
||||||
public string NodeContent { get; set; }
|
|
||||||
public string LastExecutionMessage { get; set; }
|
|
||||||
public string ItemId { get; set; }
|
|
||||||
public string Comparator { get; set; }
|
|
||||||
public int Amount { get; set; }
|
|
||||||
public int AmountExecuted { get; set; }
|
|
||||||
public double ElapsedCraftTime { get; set; }
|
|
||||||
public int AmountCrafted { get; set; }
|
|
||||||
public bool HasTargetPosition { get; set; }
|
|
||||||
public int TargetX { get; set; }
|
|
||||||
public int TargetY { get; set; }
|
|
||||||
public int TargetZ { get; set; }
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -137,6 +137,7 @@ public static class SaveGameDataApplier
|
|||||||
|
|
||||||
Tile tile = layer.tiles[savedTile.X, savedTile.Y];
|
Tile tile = layer.tiles[savedTile.X, savedTile.Y];
|
||||||
tile.collapsedMesh = savedTile.CollapsedMesh;
|
tile.collapsedMesh = savedTile.CollapsedMesh;
|
||||||
|
tile.containsLight = savedTile.ContainsLight;
|
||||||
tile.containsDecoration = savedTile.ContainsDecoration;
|
tile.containsDecoration = savedTile.ContainsDecoration;
|
||||||
tile.containsResource = savedTile.ContainsResource;
|
tile.containsResource = savedTile.ContainsResource;
|
||||||
tile.wasVisited = savedTile.WasVisited;
|
tile.wasVisited = savedTile.WasVisited;
|
||||||
|
|||||||
@@ -135,6 +135,7 @@ public static class SaveGameDataFactory
|
|||||||
X = tile.GridPosition.X,
|
X = tile.GridPosition.X,
|
||||||
Y = tile.GridPosition.Y,
|
Y = tile.GridPosition.Y,
|
||||||
CollapsedMesh = tile.collapsedMesh,
|
CollapsedMesh = tile.collapsedMesh,
|
||||||
|
ContainsLight = tile.containsLight,
|
||||||
ContainsDecoration = tile.containsDecoration,
|
ContainsDecoration = tile.containsDecoration,
|
||||||
ContainsResource = tile.containsResource,
|
ContainsResource = tile.containsResource,
|
||||||
WasVisited = tile.wasVisited,
|
WasVisited = tile.wasVisited,
|
||||||
|
|||||||
@@ -55,32 +55,4 @@ public class CraftNode : ProgramNode
|
|||||||
{
|
{
|
||||||
return $"Name: {DisplayText}, Item: {(selectedItem == null ? "Empty" : selectedItem.data.Id)}, Amount: {amount}";
|
return $"Name: {DisplayText}, Item: {(selectedItem == null ? "Empty" : selectedItem.data.Id)}, Amount: {amount}";
|
||||||
}
|
}
|
||||||
|
|
||||||
public override NodeSaveData CreateSaveData()
|
|
||||||
{
|
|
||||||
NodeSaveData saveData = base.CreateSaveData();
|
|
||||||
saveData.ItemId = selectedItem?.data.Id;
|
|
||||||
saveData.Amount = amount;
|
|
||||||
if (selectedItem != null)
|
|
||||||
{
|
|
||||||
saveData.ElapsedCraftTime = selectedItem.elapsedCraftTime;
|
|
||||||
saveData.AmountCrafted = selectedItem.amountCrafted;
|
|
||||||
}
|
|
||||||
return saveData;
|
|
||||||
}
|
|
||||||
|
|
||||||
public override void Load(NodeSaveData saveData)
|
|
||||||
{
|
|
||||||
base.Load(saveData);
|
|
||||||
amount = saveData.Amount;
|
|
||||||
if (string.IsNullOrEmpty(saveData.ItemId)) return;
|
|
||||||
if (!GameData.availableItems.ContainsKey(saveData.ItemId)) return;
|
|
||||||
|
|
||||||
selectedItem = new Item
|
|
||||||
{
|
|
||||||
data = GameData.availableItems[saveData.ItemId],
|
|
||||||
elapsedCraftTime = saveData.ElapsedCraftTime,
|
|
||||||
amountCrafted = saveData.AmountCrafted
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,7 +7,6 @@ public class ExploreNode : ProgramNode
|
|||||||
public Vector3 startPosition;
|
public Vector3 startPosition;
|
||||||
public Vector3I targetPosition;
|
public Vector3I targetPosition;
|
||||||
public List<Vector3> pathPoints;
|
public List<Vector3> pathPoints;
|
||||||
public bool hasTargetPosition;
|
|
||||||
|
|
||||||
public ExploreNode()
|
public ExploreNode()
|
||||||
{
|
{
|
||||||
@@ -17,7 +16,7 @@ public class ExploreNode : ProgramNode
|
|||||||
|
|
||||||
public override NodeResult Execute(Robot robot, double delta)
|
public override NodeResult Execute(Robot robot, double delta)
|
||||||
{
|
{
|
||||||
if (pathPoints == null && !hasTargetPosition && !TrySelectTarget())
|
if (pathPoints == null && !TrySelectTarget())
|
||||||
{
|
{
|
||||||
lastExecutionMessage = "No tiles left to explore";
|
lastExecutionMessage = "No tiles left to explore";
|
||||||
return NodeResult.SUCCESS;
|
return NodeResult.SUCCESS;
|
||||||
@@ -42,18 +41,18 @@ public class ExploreNode : ProgramNode
|
|||||||
private bool TrySelectTarget()
|
private bool TrySelectTarget()
|
||||||
{
|
{
|
||||||
int safetyCounter = 0;
|
int safetyCounter = 0;
|
||||||
|
int layerRange = Math.Max(GameData.lowestLayer, 1);
|
||||||
int maximumAttempts = (int)Math.Pow(GameData.layerSize, 2) * 2;
|
int maximumAttempts = (int)Math.Pow(GameData.layerSize, 2) * 2;
|
||||||
|
|
||||||
while (safetyCounter <= maximumAttempts)
|
while (safetyCounter <= maximumAttempts)
|
||||||
{
|
{
|
||||||
targetPosition = new Vector3I(
|
targetPosition = new Vector3I(
|
||||||
GameData.rand.Next(GameData.layerSize),
|
GameData.rand.Next(GameData.layerSize),
|
||||||
GameData.rand.Next(GameData.lowestLayer + 1),
|
GameData.rand.Next(layerRange),
|
||||||
GameData.rand.Next(GameData.layerSize)
|
GameData.rand.Next(GameData.layerSize)
|
||||||
);
|
);
|
||||||
if (!GameData.map[targetPosition.Y].tiles[targetPosition.X, targetPosition.Z].wasVisited)
|
if (!GameData.map[targetPosition.Y].tiles[targetPosition.X, targetPosition.Z].wasVisited)
|
||||||
{
|
{
|
||||||
hasTargetPosition = true;
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -96,7 +95,6 @@ public class ExploreNode : ProgramNode
|
|||||||
|
|
||||||
lastExecutionMessage = "Current exploration finished";
|
lastExecutionMessage = "Current exploration finished";
|
||||||
pathPoints = null;
|
pathPoints = null;
|
||||||
hasTargetPosition = false;
|
|
||||||
return NodeResult.RUNNING;
|
return NodeResult.RUNNING;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -122,8 +120,7 @@ public class ExploreNode : ProgramNode
|
|||||||
{
|
{
|
||||||
return new ExploreNode
|
return new ExploreNode
|
||||||
{
|
{
|
||||||
targetPosition = targetPosition,
|
targetPosition = targetPosition
|
||||||
hasTargetPosition = hasTargetPosition
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -131,27 +128,4 @@ public class ExploreNode : ProgramNode
|
|||||||
{
|
{
|
||||||
return $"Name: {DisplayText}";
|
return $"Name: {DisplayText}";
|
||||||
}
|
}
|
||||||
|
|
||||||
public override NodeSaveData CreateSaveData()
|
|
||||||
{
|
|
||||||
NodeSaveData saveData = base.CreateSaveData();
|
|
||||||
saveData.TargetX = targetPosition.X;
|
|
||||||
saveData.TargetY = targetPosition.Y;
|
|
||||||
saveData.TargetZ = targetPosition.Z;
|
|
||||||
saveData.HasTargetPosition = hasTargetPosition || pathPoints != null;
|
|
||||||
return saveData;
|
|
||||||
}
|
|
||||||
|
|
||||||
public override void Load(NodeSaveData saveData)
|
|
||||||
{
|
|
||||||
base.Load(saveData);
|
|
||||||
hasTargetPosition = saveData.HasTargetPosition;
|
|
||||||
if (!hasTargetPosition) return;
|
|
||||||
|
|
||||||
targetPosition = new Vector3I(
|
|
||||||
saveData.TargetX,
|
|
||||||
saveData.TargetY,
|
|
||||||
saveData.TargetZ
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -14,12 +14,12 @@ public class ForNode : ProgramNode
|
|||||||
public override NodeResult Execute(Robot robot, double delta)
|
public override NodeResult Execute(Robot robot, double delta)
|
||||||
{
|
{
|
||||||
bool isConditionFulfilled = DetermineCondition();
|
bool isConditionFulfilled = DetermineCondition();
|
||||||
|
amountExecuted++;
|
||||||
if (isConditionFulfilled)
|
if (isConditionFulfilled)
|
||||||
{
|
{
|
||||||
amountExecuted = 0;
|
amountExecuted = 0;
|
||||||
}
|
}
|
||||||
amountExecuted++;
|
return isConditionFulfilled ? NodeResult.SUCCESS : NodeResult.CONDITIONFALSE;
|
||||||
return isConditionFulfilled ? NodeResult.CONDITIONFALSE : NodeResult.SUCCESS;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private bool DetermineCondition()
|
private bool DetermineCondition()
|
||||||
@@ -42,21 +42,6 @@ public class ForNode : ProgramNode
|
|||||||
return $"Name: {DisplayText}, AmountExecuted: {amountExecuted}, Amount: {amount}";
|
return $"Name: {DisplayText}, AmountExecuted: {amountExecuted}, Amount: {amount}";
|
||||||
}
|
}
|
||||||
|
|
||||||
public override NodeSaveData CreateSaveData()
|
|
||||||
{
|
|
||||||
NodeSaveData saveData = base.CreateSaveData();
|
|
||||||
saveData.Amount = amount;
|
|
||||||
saveData.AmountExecuted = amountExecuted;
|
|
||||||
return saveData;
|
|
||||||
}
|
|
||||||
|
|
||||||
public override void Load(NodeSaveData saveData)
|
|
||||||
{
|
|
||||||
base.Load(saveData);
|
|
||||||
amount = saveData.Amount;
|
|
||||||
amountExecuted = saveData.AmountExecuted;
|
|
||||||
}
|
|
||||||
|
|
||||||
public override void SetNextNode(
|
public override void SetNextNode(
|
||||||
List<Godot.Collections.Dictionary> connections,
|
List<Godot.Collections.Dictionary> connections,
|
||||||
Dictionary<StringName, ProgramNode> availableNodes
|
Dictionary<StringName, ProgramNode> availableNodes
|
||||||
|
|||||||
@@ -60,26 +60,6 @@ public class IfNode : ProgramNode
|
|||||||
return $"Name: {DisplayText}, Item: {(selectedItem == null ? "Empty" : selectedItem.data.Id)}, Comparator: {comparator}, Amount: {amount}";
|
return $"Name: {DisplayText}, Item: {(selectedItem == null ? "Empty" : selectedItem.data.Id)}, Comparator: {comparator}, Amount: {amount}";
|
||||||
}
|
}
|
||||||
|
|
||||||
public override NodeSaveData CreateSaveData()
|
|
||||||
{
|
|
||||||
NodeSaveData saveData = base.CreateSaveData();
|
|
||||||
saveData.ItemId = selectedItem?.data.Id;
|
|
||||||
saveData.Comparator = comparator;
|
|
||||||
saveData.Amount = amount;
|
|
||||||
return saveData;
|
|
||||||
}
|
|
||||||
|
|
||||||
public override void Load(NodeSaveData saveData)
|
|
||||||
{
|
|
||||||
base.Load(saveData);
|
|
||||||
amount = saveData.Amount;
|
|
||||||
comparator = saveData.Comparator;
|
|
||||||
if (string.IsNullOrEmpty(saveData.ItemId)) return;
|
|
||||||
if (!GameData.availableItems.ContainsKey(saveData.ItemId)) return;
|
|
||||||
|
|
||||||
selectedItem = new Item { data = GameData.availableItems[saveData.ItemId] };
|
|
||||||
}
|
|
||||||
|
|
||||||
public override void SetNextNode(
|
public override void SetNextNode(
|
||||||
List<Godot.Collections.Dictionary> connections,
|
List<Godot.Collections.Dictionary> connections,
|
||||||
Dictionary<StringName, ProgramNode> availableNodes
|
Dictionary<StringName, ProgramNode> availableNodes
|
||||||
|
|||||||
@@ -98,26 +98,4 @@ public class MoveNode : ProgramNode
|
|||||||
{
|
{
|
||||||
return $"Name: {DisplayText}, Position: ({targetPosition.X}|{targetPosition.Y}|{targetPosition.Z})";
|
return $"Name: {DisplayText}, Position: ({targetPosition.X}|{targetPosition.Y}|{targetPosition.Z})";
|
||||||
}
|
}
|
||||||
|
|
||||||
public override NodeSaveData CreateSaveData()
|
|
||||||
{
|
|
||||||
NodeSaveData saveData = base.CreateSaveData();
|
|
||||||
saveData.TargetX = targetPosition.X;
|
|
||||||
saveData.TargetY = targetPosition.Y;
|
|
||||||
saveData.TargetZ = targetPosition.Z;
|
|
||||||
saveData.HasTargetPosition = true;
|
|
||||||
return saveData;
|
|
||||||
}
|
|
||||||
|
|
||||||
public override void Load(NodeSaveData saveData)
|
|
||||||
{
|
|
||||||
base.Load(saveData);
|
|
||||||
if (!saveData.HasTargetPosition) return;
|
|
||||||
|
|
||||||
targetPosition = new Vector3I(
|
|
||||||
saveData.TargetX,
|
|
||||||
saveData.TargetY,
|
|
||||||
saveData.TargetZ
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -14,52 +14,6 @@ public abstract class ProgramNode
|
|||||||
public abstract ProgramNode Duplicate();
|
public abstract ProgramNode Duplicate();
|
||||||
public abstract string Save();
|
public abstract string Save();
|
||||||
|
|
||||||
public virtual NodeSaveData CreateSaveData()
|
|
||||||
{
|
|
||||||
return new NodeSaveData
|
|
||||||
{
|
|
||||||
NodeType = DisplayText,
|
|
||||||
EditorNodeId = EditorNodeId,
|
|
||||||
NextEditorNodeId = nextNode?.EditorNodeId,
|
|
||||||
NegativeEditorNodeId = NegativeNode?.EditorNodeId,
|
|
||||||
NodeContent = Save(),
|
|
||||||
LastExecutionMessage = lastExecutionMessage
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
public virtual void Load(NodeSaveData saveData)
|
|
||||||
{
|
|
||||||
EditorNodeId = saveData.EditorNodeId;
|
|
||||||
lastExecutionMessage = saveData.LastExecutionMessage;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void RestoreConnections(
|
|
||||||
NodeSaveData saveData,
|
|
||||||
Dictionary<string, ProgramNode> availableNodes
|
|
||||||
)
|
|
||||||
{
|
|
||||||
nextNode = GetSavedConnection(saveData.NextEditorNodeId, availableNodes);
|
|
||||||
NegativeNode = GetSavedConnection(saveData.NegativeEditorNodeId, availableNodes);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static ProgramNode CreateFromSaveData(NodeSaveData saveData)
|
|
||||||
{
|
|
||||||
return saveData.NodeType?.ToLower() switch
|
|
||||||
{
|
|
||||||
"start" => new StartNode(),
|
|
||||||
"move" => new MoveNode(),
|
|
||||||
"explore" => new ExploreNode(),
|
|
||||||
"harvest" => new HarvestNode(),
|
|
||||||
"craft" => new CraftNode(),
|
|
||||||
"if" => new IfNode(),
|
|
||||||
"while" => new WhileNode(),
|
|
||||||
"for" => new ForNode(),
|
|
||||||
"maintain" => new MaintainNode(),
|
|
||||||
"sacrifice" => new SacrificeNode(),
|
|
||||||
_ => null
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
public ProgramNode DuplicateForRuntime(string editorNodeId)
|
public ProgramNode DuplicateForRuntime(string editorNodeId)
|
||||||
{
|
{
|
||||||
ProgramNode duplicate = Duplicate();
|
ProgramNode duplicate = Duplicate();
|
||||||
@@ -111,15 +65,4 @@ public abstract class ProgramNode
|
|||||||
|
|
||||||
return availableNodes[nodeName];
|
return availableNodes[nodeName];
|
||||||
}
|
}
|
||||||
|
|
||||||
private ProgramNode GetSavedConnection(
|
|
||||||
string nodeId,
|
|
||||||
Dictionary<string, ProgramNode> availableNodes
|
|
||||||
)
|
|
||||||
{
|
|
||||||
if (string.IsNullOrEmpty(nodeId)) return null;
|
|
||||||
if (!availableNodes.ContainsKey(nodeId)) return null;
|
|
||||||
|
|
||||||
return availableNodes[nodeId];
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -60,26 +60,6 @@ public class WhileNode : ProgramNode
|
|||||||
return $"Name: {DisplayText}, Item: {(selectedItem == null ? "Empty" : selectedItem.data.Id)}, Comparator: {comparator}, Amount: {amount}";
|
return $"Name: {DisplayText}, Item: {(selectedItem == null ? "Empty" : selectedItem.data.Id)}, Comparator: {comparator}, Amount: {amount}";
|
||||||
}
|
}
|
||||||
|
|
||||||
public override NodeSaveData CreateSaveData()
|
|
||||||
{
|
|
||||||
NodeSaveData saveData = base.CreateSaveData();
|
|
||||||
saveData.ItemId = selectedItem?.data.Id;
|
|
||||||
saveData.Comparator = comparator;
|
|
||||||
saveData.Amount = amount;
|
|
||||||
return saveData;
|
|
||||||
}
|
|
||||||
|
|
||||||
public override void Load(NodeSaveData saveData)
|
|
||||||
{
|
|
||||||
base.Load(saveData);
|
|
||||||
amount = saveData.Amount;
|
|
||||||
comparator = saveData.Comparator;
|
|
||||||
if (string.IsNullOrEmpty(saveData.ItemId)) return;
|
|
||||||
if (!GameData.availableItems.ContainsKey(saveData.ItemId)) return;
|
|
||||||
|
|
||||||
selectedItem = new Item { data = GameData.availableItems[saveData.ItemId] };
|
|
||||||
}
|
|
||||||
|
|
||||||
public override void SetNextNode(
|
public override void SetNextNode(
|
||||||
List<Godot.Collections.Dictionary> connections,
|
List<Godot.Collections.Dictionary> connections,
|
||||||
Dictionary<StringName, ProgramNode> availableNodes
|
Dictionary<StringName, ProgramNode> availableNodes
|
||||||
|
|||||||
@@ -23,7 +23,6 @@ public partial class Robot : Node3D
|
|||||||
public bool isBroken = false;
|
public bool isBroken = false;
|
||||||
public string robotType = "iron_robot";
|
public string robotType = "iron_robot";
|
||||||
public bool showOnMap = true;
|
public bool showOnMap = true;
|
||||||
public List<ProgramNode> nodes = new List<ProgramNode>();
|
|
||||||
|
|
||||||
private RobotTypeStats TypeStats =>
|
private RobotTypeStats TypeStats =>
|
||||||
GameData.robotStats.RobotTypes.TryGetValue(robotType, out RobotTypeStats stats)
|
GameData.robotStats.RobotTypes.TryGetValue(robotType, out RobotTypeStats stats)
|
||||||
@@ -108,7 +107,6 @@ public partial class Robot : Node3D
|
|||||||
programStartNode = nodes[0];
|
programStartNode = nodes[0];
|
||||||
currentNode = nodes[0];
|
currentNode = nodes[0];
|
||||||
currentMessage = "";
|
currentMessage = "";
|
||||||
this.nodes = nodes;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void StopExecution(string message)
|
public void StopExecution(string message)
|
||||||
@@ -175,11 +173,7 @@ public partial class Robot : Node3D
|
|||||||
Heat = heat,
|
Heat = heat,
|
||||||
Maintenance = maintenance,
|
Maintenance = maintenance,
|
||||||
IsCoolingDown = isCoolingDown,
|
IsCoolingDown = isCoolingDown,
|
||||||
IsBroken = isBroken,
|
IsBroken = isBroken
|
||||||
RunningProgramNodes = CreateProgramSaveData(),
|
|
||||||
ProgramStartNode = programStartNode?.EditorNodeId,
|
|
||||||
CurrentNode = currentNode?.EditorNodeId,
|
|
||||||
IsExecuting = isExecuting
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -194,7 +188,6 @@ public partial class Robot : Node3D
|
|||||||
maintenance = saveData.Maintenance;
|
maintenance = saveData.Maintenance;
|
||||||
isCoolingDown = saveData.IsCoolingDown;
|
isCoolingDown = saveData.IsCoolingDown;
|
||||||
isBroken = saveData.IsBroken;
|
isBroken = saveData.IsBroken;
|
||||||
LoadProgramState(saveData);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private bool CanExecute(double delta)
|
private bool CanExecute(double delta)
|
||||||
@@ -290,78 +283,4 @@ public partial class Robot : Node3D
|
|||||||
isCoolingDown = false;
|
isCoolingDown = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private List<NodeSaveData> CreateProgramSaveData()
|
|
||||||
{
|
|
||||||
List<NodeSaveData> result = new List<NodeSaveData>();
|
|
||||||
if (nodes == null) return result;
|
|
||||||
|
|
||||||
foreach (ProgramNode node in nodes)
|
|
||||||
{
|
|
||||||
if (node == null) continue;
|
|
||||||
result.Add(node.CreateSaveData());
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void LoadProgramState(RobotSaveData saveData)
|
|
||||||
{
|
|
||||||
nodes = new List<ProgramNode>();
|
|
||||||
programStartNode = null;
|
|
||||||
currentNode = null;
|
|
||||||
isExecuting = false;
|
|
||||||
|
|
||||||
if (saveData.RunningProgramNodes == null || saveData.RunningProgramNodes.Count <= 0)
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
Dictionary<string, ProgramNode> loadedNodes = new Dictionary<string, ProgramNode>();
|
|
||||||
foreach (NodeSaveData nodeSaveData in saveData.RunningProgramNodes)
|
|
||||||
{
|
|
||||||
ProgramNode node = ProgramNode.CreateFromSaveData(nodeSaveData);
|
|
||||||
if (node == null) continue;
|
|
||||||
|
|
||||||
node.Load(nodeSaveData);
|
|
||||||
nodes.Add(node);
|
|
||||||
|
|
||||||
if (!string.IsNullOrEmpty(node.EditorNodeId) && !loadedNodes.ContainsKey(node.EditorNodeId))
|
|
||||||
{
|
|
||||||
loadedNodes.Add(node.EditorNodeId, node);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
foreach (NodeSaveData nodeSaveData in saveData.RunningProgramNodes)
|
|
||||||
{
|
|
||||||
if (string.IsNullOrEmpty(nodeSaveData.EditorNodeId)) continue;
|
|
||||||
if (!loadedNodes.ContainsKey(nodeSaveData.EditorNodeId)) continue;
|
|
||||||
|
|
||||||
loadedNodes[nodeSaveData.EditorNodeId].RestoreConnections(nodeSaveData, loadedNodes);
|
|
||||||
}
|
|
||||||
|
|
||||||
programStartNode = GetLoadedNode(saveData.ProgramStartNode, loadedNodes);
|
|
||||||
if (programStartNode == null && nodes.Count > 0)
|
|
||||||
{
|
|
||||||
programStartNode = nodes[0];
|
|
||||||
}
|
|
||||||
|
|
||||||
currentNode = GetLoadedNode(saveData.CurrentNode, loadedNodes);
|
|
||||||
if (currentNode == null)
|
|
||||||
{
|
|
||||||
currentNode = programStartNode;
|
|
||||||
}
|
|
||||||
|
|
||||||
isExecuting = saveData.IsExecuting && currentNode != null;
|
|
||||||
}
|
|
||||||
|
|
||||||
private ProgramNode GetLoadedNode(
|
|
||||||
string nodeId,
|
|
||||||
Dictionary<string, ProgramNode> loadedNodes
|
|
||||||
)
|
|
||||||
{
|
|
||||||
if (string.IsNullOrEmpty(nodeId)) return null;
|
|
||||||
if (!loadedNodes.ContainsKey(nodeId)) return null;
|
|
||||||
|
|
||||||
return loadedNodes[nodeId];
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -24,7 +24,7 @@ public class SurvivalState
|
|||||||
|
|
||||||
public void Update(double delta)
|
public void Update(double delta)
|
||||||
{
|
{
|
||||||
if (isDead || GameData.debugMode) return;
|
if (isDead) return;
|
||||||
|
|
||||||
elapsedSeconds += delta;
|
elapsedSeconds += delta;
|
||||||
float drainModifier = IsInGracePeriod() ? 0.35f : 1f;
|
float drainModifier = IsInGracePeriod() ? 0.35f : 1f;
|
||||||
|
|||||||
@@ -23,7 +23,6 @@ public partial class TestRunner : Node
|
|||||||
Run("Resource extraction and save data roundtrip", TestResourceSaveRoundtrip);
|
Run("Resource extraction and save data roundtrip", TestResourceSaveRoundtrip);
|
||||||
Run("Endless resources extract slower", TestEndlessResourcesExtractSlower);
|
Run("Endless resources extract slower", TestEndlessResourcesExtractSlower);
|
||||||
Run("Robot save data roundtrip keeps robot state", TestRobotSaveRoundtrip);
|
Run("Robot save data roundtrip keeps robot state", TestRobotSaveRoundtrip);
|
||||||
Run("Robot save data roundtrip keeps running program", TestRobotProgramSaveRoundtrip);
|
|
||||||
Run("Maintain node consumes matching gear", TestMaintainNodeConsumesMatchingGear);
|
Run("Maintain node consumes matching gear", TestMaintainNodeConsumesMatchingGear);
|
||||||
Run("Sacrifice node makes resource endless", TestSacrificeNodeMakesResourceEndless);
|
Run("Sacrifice node makes resource endless", TestSacrificeNodeMakesResourceEndless);
|
||||||
Run("No robot recovery detects loss", TestNoRobotRecoveryDetectsLoss);
|
Run("No robot recovery detects loss", TestNoRobotRecoveryDetectsLoss);
|
||||||
@@ -230,66 +229,6 @@ public partial class TestRunner : Node
|
|||||||
AssertTrue(loadedRobot.isCoolingDown, "robot cooling state");
|
AssertTrue(loadedRobot.isCoolingDown, "robot cooling state");
|
||||||
}
|
}
|
||||||
|
|
||||||
private void TestRobotProgramSaveRoundtrip()
|
|
||||||
{
|
|
||||||
StartNode startNode = new StartNode { EditorNodeId = "start" };
|
|
||||||
ForNode forNode = new ForNode
|
|
||||||
{
|
|
||||||
EditorNodeId = "loop",
|
|
||||||
amount = 3,
|
|
||||||
amountExecuted = 2
|
|
||||||
};
|
|
||||||
CraftNode craftNode = new CraftNode
|
|
||||||
{
|
|
||||||
EditorNodeId = "craft",
|
|
||||||
selectedItem = new Item
|
|
||||||
{
|
|
||||||
data = GameData.availableItems["stone"],
|
|
||||||
elapsedCraftTime = 0.5,
|
|
||||||
amountCrafted = 1
|
|
||||||
},
|
|
||||||
amount = 2
|
|
||||||
};
|
|
||||||
HarvestNode harvestNode = new HarvestNode { EditorNodeId = "done" };
|
|
||||||
|
|
||||||
startNode.nextNode = forNode;
|
|
||||||
forNode.nextNode = craftNode;
|
|
||||||
forNode.NegativeNode = harvestNode;
|
|
||||||
craftNode.nextNode = forNode;
|
|
||||||
|
|
||||||
Robot robot = new Robot
|
|
||||||
{
|
|
||||||
Name = "Loop Bot",
|
|
||||||
currentProgram = "Looping",
|
|
||||||
isExecuting = true,
|
|
||||||
programStartNode = startNode,
|
|
||||||
currentNode = craftNode,
|
|
||||||
nodes = new List<ProgramNode> { startNode, forNode, craftNode, harvestNode }
|
|
||||||
};
|
|
||||||
|
|
||||||
RobotSaveData saveData = robot.CreateSaveData();
|
|
||||||
Robot loadedRobot = new Robot();
|
|
||||||
loadedRobot.LoadSaveData(saveData);
|
|
||||||
|
|
||||||
AssertTrue(loadedRobot.isExecuting, "loaded robot should still execute");
|
|
||||||
AssertEqual("craft", loadedRobot.currentNode.EditorNodeId, "current node id");
|
|
||||||
AssertEqual("start", loadedRobot.programStartNode.EditorNodeId, "start node id");
|
|
||||||
AssertEqual(4, loadedRobot.nodes.Count, "loaded node count");
|
|
||||||
|
|
||||||
ForNode loadedForNode = loadedRobot.nodes[1] as ForNode;
|
|
||||||
CraftNode loadedCraftNode = loadedRobot.nodes[2] as CraftNode;
|
|
||||||
|
|
||||||
AssertEqual(3, loadedForNode.amount, "for amount");
|
|
||||||
AssertEqual(2, loadedForNode.amountExecuted, "for amount executed");
|
|
||||||
AssertTrue(ReferenceEquals(loadedCraftNode, loadedForNode.nextNode), "for success branch");
|
|
||||||
AssertTrue(ReferenceEquals(loadedRobot.nodes[3], loadedForNode.NegativeNode), "for negative branch");
|
|
||||||
AssertTrue(ReferenceEquals(loadedForNode, loadedCraftNode.nextNode), "craft loops back");
|
|
||||||
AssertEqual("stone", loadedCraftNode.selectedItem.data.Id, "craft item");
|
|
||||||
AssertEqual(2, loadedCraftNode.amount, "craft amount");
|
|
||||||
AssertClose(0.5f, (float)loadedCraftNode.selectedItem.elapsedCraftTime, 0.001f, "craft elapsed");
|
|
||||||
AssertEqual(1, loadedCraftNode.selectedItem.amountCrafted, "craft crafted amount");
|
|
||||||
}
|
|
||||||
|
|
||||||
private void TestMaintainNodeConsumesMatchingGear()
|
private void TestMaintainNodeConsumesMatchingGear()
|
||||||
{
|
{
|
||||||
Robot robot = new Robot
|
Robot robot = new Robot
|
||||||
@@ -536,9 +475,9 @@ public partial class TestRunner : Node
|
|||||||
amount = 2
|
amount = 2
|
||||||
};
|
};
|
||||||
|
|
||||||
AssertEqual(NodeResult.SUCCESS, node.Execute(null, 0), "first iteration");
|
AssertEqual(NodeResult.CONDITIONFALSE, node.Execute(null, 0), "first iteration");
|
||||||
AssertEqual(NodeResult.SUCCESS, node.Execute(null, 0), "second iteration");
|
AssertEqual(NodeResult.CONDITIONFALSE, node.Execute(null, 0), "second iteration");
|
||||||
AssertEqual(NodeResult.CONDITIONFALSE, node.Execute(null, 0), "loop finished");
|
AssertEqual(NodeResult.SUCCESS, node.Execute(null, 0), "loop finished");
|
||||||
}
|
}
|
||||||
|
|
||||||
private void TestRuntimeNodeKeepsEditorIdWithoutSharingState()
|
private void TestRuntimeNodeKeepsEditorIdWithoutSharingState()
|
||||||
|
|||||||
@@ -39,7 +39,6 @@ public partial class CodingWindow : PanelContainer
|
|||||||
|
|
||||||
if (focused is LineEdit || focused is TextEdit) return;
|
if (focused is LineEdit || focused is TextEdit) return;
|
||||||
if (selectedNode == null) return;
|
if (selectedNode == null) return;
|
||||||
if (selectedNode == highlightedNode) highlightedNode = null;
|
|
||||||
editorWindow.RemoveChild(selectedNode);
|
editorWindow.RemoveChild(selectedNode);
|
||||||
selectedNode.QueueFree();
|
selectedNode.QueueFree();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -101,11 +101,10 @@ public partial class RobotList : PanelContainer
|
|||||||
robot.Position = GameData.map[0].tiles[0, 0].Position;
|
robot.Position = GameData.map[0].tiles[0, 0].Position;
|
||||||
robot.robotType = spawnId;
|
robot.robotType = spawnId;
|
||||||
GetNode("/root/Main/World").AddChild(robot);
|
GetNode("/root/Main/World").AddChild(robot);
|
||||||
LightHandler.lights.Add(robot.GetNode("./SpotLight3D") as SpotLight3D);
|
|
||||||
robot.Name = $"Robot #{GameData.robots.Count}";
|
robot.Name = $"Robot #{GameData.robots.Count}";
|
||||||
GameData.robots.Add(robot);
|
GameData.robots.Add(robot);
|
||||||
spawnId = "";
|
spawnId = "";
|
||||||
LightHandler.RedrawLights(GameData.lightColor);
|
|
||||||
ReloadRobots();
|
ReloadRobots();
|
||||||
ReloadSelectableRobots();
|
ReloadSelectableRobots();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -49,7 +49,6 @@ public partial class TutorialBubble : PanelContainer
|
|||||||
"The inventory (Default: [I]) stores everything your robots collect. Gates and research both consume items from it.",
|
"The inventory (Default: [I]) stores everything your robots collect. Gates and research both consume items from it.",
|
||||||
"Each gate blocks the next layer. When you have the required items, use Open Gate in the top bar.",
|
"Each gate blocks the next layer. When you have the required items, use Open Gate in the top bar.",
|
||||||
"The required ingredients can be found by hovering over the Open Gate button.",
|
"The required ingredients can be found by hovering over the Open Gate button.",
|
||||||
"You can swap between layers using the [Q] (up one layer) and [E] (down one layer) keys.",
|
|
||||||
"The map (Default: [M]) shows what your robots have discovered. Exploration matters because resources are hidden in the ruin.",
|
"The map (Default: [M]) shows what your robots have discovered. Exploration matters because resources are hidden in the ruin.",
|
||||||
"Deeper layers contain more advanced resources. Unlocking the gate at the lowest point allows you to leave the ruin.",
|
"Deeper layers contain more advanced resources. Unlocking the gate at the lowest point allows you to leave the ruin.",
|
||||||
"Be careful: resources are not endless at the beginning. Converting a robot to a drill unit with Sacrifice makes them endless.",
|
"Be careful: resources are not endless at the beginning. Converting a robot to a drill unit with Sacrifice makes them endless.",
|
||||||
|
|||||||
@@ -3,13 +3,13 @@ using System.Collections.Generic;
|
|||||||
|
|
||||||
public static class LightHandler
|
public static class LightHandler
|
||||||
{
|
{
|
||||||
public static List<SpotLight3D> lights = new List<SpotLight3D>();
|
public static List<OmniLight3D> lights = new List<OmniLight3D>();
|
||||||
|
|
||||||
public static void RedrawLights(Color color)
|
public static void RedrawLights(Color color)
|
||||||
{
|
{
|
||||||
List<SpotLight3D> availableLights = new List<SpotLight3D>();
|
List<OmniLight3D> availableLights = new List<OmniLight3D>();
|
||||||
|
|
||||||
foreach (SpotLight3D light in lights)
|
foreach (OmniLight3D light in lights)
|
||||||
{
|
{
|
||||||
if (!GodotObject.IsInstanceValid(light)) continue;
|
if (!GodotObject.IsInstanceValid(light)) continue;
|
||||||
|
|
||||||
|
|||||||
@@ -270,11 +270,6 @@ public partial class Map : PanelContainer
|
|||||||
tooltipText += GetRobotTooltip(robotsOnTile, tooltipText.Length > 0);
|
tooltipText += GetRobotTooltip(robotsOnTile, tooltipText.Length > 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (tile.collapsedMesh == "gate" && tile.wasVisited)
|
|
||||||
{
|
|
||||||
tileTexture = AddBorder(tileTexture, Colors.Red, RobotBorderWidth);
|
|
||||||
}
|
|
||||||
|
|
||||||
texture.Texture = tileTexture;
|
texture.Texture = tileTexture;
|
||||||
texture.TooltipText = tooltipText;
|
texture.TooltipText = tooltipText;
|
||||||
}
|
}
|
||||||
|
|||||||
+28
-2
@@ -11,7 +11,7 @@ public partial class Tile
|
|||||||
public Vector2I GridPosition;
|
public Vector2I GridPosition;
|
||||||
public Node3D ContentNode;
|
public Node3D ContentNode;
|
||||||
|
|
||||||
public bool containsDecoration, containsResource;
|
public bool containsLight, containsDecoration, containsResource;
|
||||||
public GameResource resource;
|
public GameResource resource;
|
||||||
public bool wasVisited;
|
public bool wasVisited;
|
||||||
public event EventHandler OnTileVisited;
|
public event EventHandler OnTileVisited;
|
||||||
@@ -74,6 +74,7 @@ public partial class Tile
|
|||||||
public void Reset(Dictionary<string, MeshInstance3D> tileMeshes)
|
public void Reset(Dictionary<string, MeshInstance3D> tileMeshes)
|
||||||
{
|
{
|
||||||
collapsedMesh = null;
|
collapsedMesh = null;
|
||||||
|
containsLight = false;
|
||||||
containsDecoration = false;
|
containsDecoration = false;
|
||||||
containsResource = false;
|
containsResource = false;
|
||||||
resource = null;
|
resource = null;
|
||||||
@@ -85,11 +86,36 @@ public partial class Tile
|
|||||||
{
|
{
|
||||||
foreach (Placeholder placeholder in placeholders)
|
foreach (Placeholder placeholder in placeholders)
|
||||||
{
|
{
|
||||||
if (containsResource && placeholder.name == "resource") SpawnResource(contentMeshes["resource"], placeholder, transform);
|
if (containsLight && placeholder.name == "light") SpawnLight(contentMeshes["light"], placeholder, transform);
|
||||||
|
else if (containsResource && placeholder.name == "resource") SpawnResource(contentMeshes["resource"], placeholder, transform);
|
||||||
else if (containsDecoration && placeholder.name != "light" && placeholder.name != "resource") SpawnDecorations(contentMeshes, placeholder, transform);
|
else if (containsDecoration && placeholder.name != "light" && placeholder.name != "resource") SpawnDecorations(contentMeshes, placeholder, transform);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void SpawnLight(MeshInstance3D lightMesh, Placeholder placeholder, Transform3D transform)
|
||||||
|
{
|
||||||
|
MeshInstance3D light = new MeshInstance3D
|
||||||
|
{
|
||||||
|
Mesh = lightMesh.Mesh,
|
||||||
|
Position = placeholder.transform.Origin
|
||||||
|
};
|
||||||
|
OmniLight3D lightSource = new OmniLight3D()
|
||||||
|
{
|
||||||
|
OmniAttenuation = 2f,
|
||||||
|
LightColor = GameData.lightColor,
|
||||||
|
ShadowEnabled = true,
|
||||||
|
LightEnergy = 100f,
|
||||||
|
LightIndirectEnergy = 1.5f,
|
||||||
|
OmniRange = 20f,
|
||||||
|
Position = placeholder.transform.Origin
|
||||||
|
};
|
||||||
|
lightSource.Position.MoveToward(transform.Origin, 0.1f);
|
||||||
|
LightHandler.lights.Add(lightSource);
|
||||||
|
light.AddChild(lightSource);
|
||||||
|
ContentNode.AddChild(light);
|
||||||
|
light.LookAt(transform.Origin, Vector3.Up);
|
||||||
|
}
|
||||||
|
|
||||||
private void SpawnResource(MeshInstance3D resourceMesh, Placeholder placeholder, Transform3D transform)
|
private void SpawnResource(MeshInstance3D resourceMesh, Placeholder placeholder, Transform3D transform)
|
||||||
{
|
{
|
||||||
MeshInstance3D resource = new MeshInstance3D
|
MeshInstance3D resource = new MeshInstance3D
|
||||||
|
|||||||
+18
-2
@@ -142,8 +142,6 @@ public partial class World : Node3D
|
|||||||
robot.Position = map[0].tiles[0, 0].Position;
|
robot.Position = map[0].tiles[0, 0].Position;
|
||||||
AddChild(robot);
|
AddChild(robot);
|
||||||
robots.Add(robot);
|
robots.Add(robot);
|
||||||
LightHandler.lights.Add(robot.GetNode("./SpotLight3D") as SpotLight3D);
|
|
||||||
LightHandler.RedrawLights(lightColor);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void SpawnSavedRobots(List<RobotSaveData> savedRobots)
|
private void SpawnSavedRobots(List<RobotSaveData> savedRobots)
|
||||||
@@ -195,6 +193,7 @@ public partial class World : Node3D
|
|||||||
{
|
{
|
||||||
map[0].tiles[0, 0].wasVisited = true;
|
map[0].tiles[0, 0].wasVisited = true;
|
||||||
map[0].tiles[0, 0].containsDecoration = true;
|
map[0].tiles[0, 0].containsDecoration = true;
|
||||||
|
map[0].tiles[0, 0].containsLight = true;
|
||||||
map[0].tiles[0, 0].containsResource = false;
|
map[0].tiles[0, 0].containsResource = false;
|
||||||
map[0].tiles[0, 0].ContentNode.Visible = true;
|
map[0].tiles[0, 0].ContentNode.Visible = true;
|
||||||
}
|
}
|
||||||
@@ -235,10 +234,22 @@ public partial class World : Node3D
|
|||||||
private void DistributeTileContent(Layer layer)
|
private void DistributeTileContent(Layer layer)
|
||||||
{
|
{
|
||||||
int currentDecoration = 0;
|
int currentDecoration = 0;
|
||||||
|
int currentLight = 0;
|
||||||
int currentResource = 0;
|
int currentResource = 0;
|
||||||
|
|
||||||
int posX, posY;
|
int posX, posY;
|
||||||
|
|
||||||
|
while (currentLight < layerSize * 3)
|
||||||
|
{
|
||||||
|
posX = rand.Next(layerSize);
|
||||||
|
posY = rand.Next(layerSize);
|
||||||
|
if (CannotContainLight(layer.tiles[posX, posY])) continue;
|
||||||
|
if (layer.tiles[posX, posY].containsLight) continue;
|
||||||
|
|
||||||
|
layer.tiles[posX, posY].containsLight = true;
|
||||||
|
currentLight++;
|
||||||
|
}
|
||||||
|
|
||||||
while (currentDecoration < layerSize)
|
while (currentDecoration < layerSize)
|
||||||
{
|
{
|
||||||
posX = rand.Next(layerSize);
|
posX = rand.Next(layerSize);
|
||||||
@@ -262,6 +273,11 @@ public partial class World : Node3D
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private bool CannotContainLight(Tile tile)
|
||||||
|
{
|
||||||
|
return tile.collapsedMesh == "junction" || tile.collapsedMesh == "gate";
|
||||||
|
}
|
||||||
|
|
||||||
private void HandleRenderData(List<TileRenderData> renderData)
|
private void HandleRenderData(List<TileRenderData> renderData)
|
||||||
{
|
{
|
||||||
multiMeshHandler.Build(renderData);
|
multiMeshHandler.Build(renderData);
|
||||||
|
|||||||
Reference in New Issue
Block a user