< Summary

Information
Class: Safarimacik.Model.Animal
Assembly: Safarimacik
File(s): /builds/szofttech-ab-2025/group-03/safarimacik/model/Animal.cs
Line coverage
99%
Covered lines: 101
Uncovered lines: 1
Coverable lines: 102
Total lines: 167
Line coverage: 99%
Branch coverage
90%
Covered branches: 20
Total branches: 22
Branch coverage: 90.9%
Method coverage

Feature is only available for sponsors

Upgrade to PRO version

Metrics

MethodBranch coverage Crap Score Cyclomatic complexity Line coverage
.ctor(...)100%22100%
get_Lifetime()100%11100%
get_Sex()100%11100%
get_Position()100%11100%
get_TilePosition()100%11100%
get_State()100%11100%
set_State(...)100%11100%
set_TileSpeed(...)100%11100%
.ctor(...)100%11100%
Move(...)100%66100%
IsAdult()100%11100%
SaveFood(...)100%11100%
SaveWater(...)100%11100%
RemoveFoodFromMemory(...)100%11100%
ClosestWater()100%11100%
ClosestFood()100%11100%
Kill()50%22100%
IsHungry()100%11100%
IsThirsty()100%11100%
Age()100%11100%
Crave()100%11100%
Mate()100%11100%
CheckVitals()100%66100%
Drink(...)100%11100%
Eat(...)100%11100%
OnStateChanged()100%22100%
OnStepsTaken(...)100%22100%
OnOffspringSpawned(...)50%22100%

File(s)

/builds/szofttech-ab-2025/group-03/safarimacik/model/Animal.cs

#LineLine coverage
 1using Godot;
 2
 3
 4namespace Safarimacik.Model;
 5
 6
 7/// <summary>
 8/// Base class for all animals.
 9/// </summary>
 10/// This class is abstract and should not be instantiated directly.
 11/// It provides the basic properties and methods for all animals.
 12/// <remarks>
 13/// The Animal class contains properties for hunger, thirst, age, sex, and position.
 14/// It also contains methods for moving, eating, drinking, mating, and checking vitals.
 15/// The sex is true if male.
 16/// </remarks>
 17public abstract class Animal {
 18  private AnimalState _state;
 119  protected double _hunger = 100;
 120  protected double _thirst = 100;
 121  protected float _moveSpeed = 25f;
 122  protected int _age = 0;
 023  protected Func<Vector2, float> _tileSpeed = _ => 0.0f;
 24  protected HashSet<Vector2I> _foods;
 25  protected HashSet<Vector2I> _waters;
 26  protected bool _sex; // true if male
 27  protected Vector2 _position;
 28  protected IRandomGenerator _rng;
 29
 30  public event Action? StateChanged;
 31  public event Action<List<(Vector2, float)>>? StepsTaken;
 32  public event Action<Animal>? OffspringSpawned;
 33  public event Action? LifeEnded;
 34
 135  public int Lifetime => _age;
 136  public bool Sex => _sex;
 137  public Vector2 Position => _position;
 138  public Vector2I TilePosition => new((int)_position.X / 16, (int)_position.Y / 16);
 39  public AnimalState State {
 140    get => _state;
 141    set {
 142      _state = value;
 143      OnStateChanged();
 144    }
 45  }
 46  public Func<Vector2, float> TileSpeed {
 147    set { _tileSpeed = value; }
 48  }
 49
 150  public Animal(Vector2 position) : this(position, new RandomGenerator()) { }
 51
 152  public Animal(Vector2 position, IRandomGenerator rng) {
 153    _foods = [];
 154    _waters = [];
 155    _position = position;
 156    _state = new IdleAnimalState(this);
 157    _sex = new RandomNumberGenerator().Randf() < 0.5;
 158    _rng = rng;
 159    OnStateChanged();
 160  }
 61
 62  /// <summary>
 63  /// Moves the animal through the given route, taking the tilespeed into account. (Should be called each tick.)
 64  /// </summary>
 65  /// <param name="path">List of points the animal moves through</param>
 66  /// <remarks>
 67  /// The method removes points from 'path' that have been reached by the animal during it's movement.
 68  /// </remarks>
 169  public void Move(List<Vector2> path) {
 170    float distanceRemaining = _moveSpeed;
 71
 172    List<(Vector2, float)> stepsTaken = [];
 73
 174    while (distanceRemaining > 0 && path.Count > 0) {
 175      Vector2 nextPoint = path[0];
 176      Vector2 toNext = nextPoint - _position;
 77
 178      if (distanceRemaining >= toNext.Length() / _tileSpeed(_position)) {
 179        _position = nextPoint;
 180        path.RemoveAt(0);
 181        distanceRemaining -= toNext.Length() / _tileSpeed(_position);
 182      } else {
 183        Vector2 direction = toNext.Normalized();
 184        _position += direction * distanceRemaining * _tileSpeed(_position);
 185        distanceRemaining = 0;
 186      }
 187      stepsTaken.Add((_position, _moveSpeed * _tileSpeed(_position)));
 188    }
 189    OnStepsTaken(stepsTaken);
 190  }
 91
 192  public bool IsAdult() {
 193    return _age > 30;
 194  }
 95
 196  public void SaveFood(Vector2I foodPosition) {
 197    _foods.Add(foodPosition);
 198  }
 99
 1100  public void SaveWater(Vector2I waterPosition) {
 1101    _waters.Add(waterPosition);
 1102  }
 103
 1104  public void RemoveFoodFromMemory(Vector2I foodPosition) {
 1105    _foods.Remove(foodPosition);
 1106  }
 107
 1108  public Vector2I ClosestWater() {
 1109    return _waters.MinBy(TilePosition.DistanceTo);
 1110  }
 111
 1112  public Vector2I ClosestFood() {
 1113    return _foods.MinBy(TilePosition.DistanceTo);
 1114  }
 115
 1116  public void Kill() {
 1117    LifeEnded?.Invoke();
 1118  }
 119
 1120  public virtual bool IsHungry() {
 1121    return _hunger < 80;
 1122  }
 123
 1124  public virtual bool IsThirsty() {
 1125    return _thirst < 80;
 1126  }
 127
 1128  public virtual void Age() {
 1129    _age += 1;
 1130  }
 131
 1132  public virtual void Crave() {
 1133    _hunger -= Math.Sqrt(_age) * 0.02 + 0.1;
 1134    _thirst -= Math.Sqrt(_age) * 0.01 + 0.05;
 1135  }
 136
 1137  public virtual void Mate() {
 1138    _hunger -= 30;
 1139    _thirst -= 30;
 1140  }
 141
 1142  public virtual void CheckVitals() {
 1143    if (_hunger <= 0 || _thirst <= 0 || _age >= 1000) {
 1144      Kill();
 1145    }
 1146  }
 147
 1148  public virtual void Drink(double nutrition) {
 1149    _thirst = Math.Max(_thirst + nutrition, 100);
 1150  }
 151
 1152  public virtual void Eat(double nutrition) {
 1153    _hunger = Math.Max(_hunger + nutrition, 100);
 1154  }
 155
 1156  protected void OnStateChanged() {
 1157    StateChanged?.Invoke();
 1158  }
 159
 1160  protected void OnStepsTaken(List<(Vector2, float)> steps) {
 1161    StepsTaken?.Invoke(steps);
 1162  }
 163
 1164  protected void OnOffspringSpawned(Animal offspring) {
 1165    OffspringSpawned?.Invoke(offspring);
 1166  }
 167}