using System; using System.Collections.Generic; 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 CooldownTarget = 35f; private const float MaintenanceLossPerSecond = 0.04f; private List nodes = new List(); private bool isExecuting = false; private ProgramNode currentNode; public string currentProgram; public string currentMessage = ""; public float heat = 0f; public float maintenance = 100f; public bool isCoolingDown = false; public bool isBroken = false; public override void _Process(double delta) { if (isExecuting) { if (CanExecute(delta)) { switch (currentNode.Execute(this, delta)) { case NodeResult.SUCCESS: currentNode = currentNode.nextNode; if (currentNode == null) { isExecuting = false; } break; case NodeResult.FAILURE: isExecuting = false; currentMessage = "(FAILED)" + currentNode.lastExecutionMessage; break; case NodeResult.RUNNING: currentMessage = ""; break; } } } else if (currentMessage.Length <= 0) { CoolDown(delta, IdleHeatLossPerSecond); currentMessage = "No script executing"; } Visible = Math.Round(Math.Abs(Position.Y / GameData.tileHeight), 0) == GameData.visibleLayer; } public void SetupExecution(List nodes) { if (nodes.Count <= 0) return; this.nodes = new List(nodes); isExecuting = true; currentNode = nodes[0]; } public float GetMovementSpeed() { return GameData.robotSpeed * GetWorkEfficiency(); } public float GetWorkEfficiency() { if (isBroken) return 0f; if (maintenance >= 50f) return 1f; return Math.Clamp(0.35f + maintenance / 100f, 0.35f, 1f); } public void Maintain() { maintenance = 100f; isBroken = false; currentMessage = ""; } private bool CanExecute(double delta) { if (GameData.survival.isDead) { currentMessage = "Survival failed"; return false; } if (isBroken) { currentMessage = "Maintenance required"; return false; } if (isCoolingDown) { CoolDown(delta, ActiveHeatLossPerSecond); currentMessage = $"Cooling down ({heat:0}%)"; return false; } if (!GameData.survival.TryConsumeEnergy(EnergyUsePerSecond * (float)delta)) { currentMessage = "Not enough energy"; return false; } heat = Math.Clamp(heat + HeatGainPerSecond * (float)delta, 0f, 100f); maintenance = Math.Clamp(maintenance - MaintenanceLossPerSecond * (float)delta, 0f, 100f); if (heat >= 100f) { isCoolingDown = true; currentMessage = "Overheated"; return false; } if (maintenance <= 0f) { isBroken = true; currentMessage = "Maintenance required"; return false; } return true; } private void CoolDown(double delta, float heatLossPerSecond) { heat = Math.Clamp(heat - heatLossPerSecond * (float)delta, 0f, 100f); if (heat <= CooldownTarget) { isCoolingDown = false; } } }