AI/Animals/Animal.cs
using HC3.UI;
namespace HC3;
public partial class Animal : Agent, IInspectable, IPlacementObject
{
[Property]
public string Name { get; set; } = "Animal";
[Property]
public int Cost { get; set; } = 0;
[Property, ImageAssetPath]
public string Thumbnail { get; set; }
[Property]
public LineRenderer Line { get; set; }
public string Title => Name;
[Property] public bool IsPlaced { get; set; }
public Group Group => new( "Animal", "Mammals" );
private RealTimeSince _lastEnclosureCheck;
private const float EnclosureCheckInterval = 2.0f;
private Color green = "#2FFF3D";
private Color red => green.WithAlpha( 0f );
Window IInspectable.Select()
{
var inspector = new AnimalInspector();
inspector.Animal = this;
return inspector;
}
public override void Tick()
{
if ( !IsPlaced )
return;
Animate();
// Only check periodically
if ( _lastEnclosureCheck > EnclosureCheckInterval )
{
_lastEnclosureCheck = 0;
UpdateEscapedStatus();
}
if ( IInspectable.Current == this )
{
UpdateSelected();
}
else if ( Line.Enabled )
{
Line.Enabled = false;
}
}
void UpdateSelected()
{
if ( Controller.IsNavigating )
{
Line.Enabled = true;
Line.VectorPoints = Controller.GetNetworkedPath().Select( x => x.WithZ( x.z + 8f ) ).ToList();
var progress = Controller.GetPathProgress();
Line.Color = new Gradient(
[
new Gradient.ColorFrame( 0f, red ),
new Gradient.ColorFrame( progress + 0.0025f, red ),
new Gradient.ColorFrame( progress + 0.02f, green ),
new Gradient.ColorFrame( 1f, green )
] );
}
}
void Animate()
{
if ( Tags.Has( "sleep" ) )
{
SetSequence( "Sleep" );
return;
}
if ( !Tags.Has( "hunt" ) )
{
// Use default animations
UpdateAnimation();
return;
}
if ( !Game.IsPlaying )
return;
if ( Networking.IsHost )
IsMoving = Controller.IsNavigating;
if ( !string.IsNullOrEmpty( _sequenceOverride ) )
{
SetSequence( _sequenceOverride, _sequenceOverrideSpeed );
return;
}
if ( Tags.Has( "eating" ) )
{
SetSequence( "Eating" );
}
else if ( Tags.Has( "attack" ) )
{
SetSequence( "Run_Attack" );
}
if ( IsMoving )
{
SetSequence( Controller.IsRunning ? "Run" : "Walk", WalkSpeed );
}
}
/// <summary>
/// Check if this animal is within a region that has an enclosure AreaTile.
/// Returns true if the animal is in an enclosure, false if it has escaped.
/// </summary>
public bool IsInEnclosure()
{
if ( Controller == null )
return true; // Default to true if we can't check
// Get the cell at the animal's current position
var gridPos = GridManager.WorldToGridPosition( WorldPosition );
var cell = GridManager.Instance?.GetCell( gridPos );
if ( cell == null )
return false;
// Check if this cell contains an enclosure area tile
return cell.GetComponents<AreaTile>()
.Any( area => area.AreaType == AreaType.Enclosure && !area.GhostPreview );
}
/// <summary>
/// Update the "escaped" tag based on whether the animal is in an enclosure
/// </summary>
private void UpdateEscapedStatus()
{
bool inEnclosure = IsInEnclosure();
bool hasEscapedTag = Tags.Has( "escaped" );
if ( !inEnclosure && !hasEscapedTag )
{
// Animal has escaped!
Tags.Set( "escaped", true );
}
else if ( inEnclosure && hasEscapedTag )
{
// Animal is back in an enclosure
Tags.Set( "escaped", false );
}
}
}