Files
RuinAdventurer/Scripts/Gameplay/Robots/Robot.cs
T

145 lines
3.1 KiB
C#

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<ProgramNode> nodes = new List<ProgramNode>();
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<ProgramNode> nodes)
{
if (nodes.Count <= 0) return;
this.nodes = new List<ProgramNode>(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;
}
}
}