filesystem rework

This commit is contained in:
Rendo 2025-07-19 20:13:34 +05:00
commit 2905db3dce
174 changed files with 93 additions and 353 deletions

54
scripts/entities/Armor.cs Normal file
View file

@ -0,0 +1,54 @@
using Godot;
namespace Newlon.Components;
[GlobalClass]
public partial class Armor : Node
{
[Signal]
public delegate void ArmorDamagedEventHandler(float hp);
[Signal]
public delegate void ArmorLostEventHandler();
[Export]
public float MaxHP { get; private set; }
public float _hp;
private bool _lost = false;
public override void _Ready()
{
_hp = MaxHP;
}
public float RecieveDamage(float damage)
{
if(_lost)
return damage;
float returnAmount = 0;
_hp -= damage;
if(_hp <= 0)
{
returnAmount = -_hp;
_hp = 0;
EmitSignal(SignalName.ArmorLost);
_lost = true;
}
EmitSignal(SignalName.ArmorDamaged,_hp);
return returnAmount;
}
public float Heal(float amount)
{
if(_lost)
return amount;
float returnAmount = 0;
_hp += amount;
if (_hp >= MaxHP)
{
returnAmount = _hp-MaxHP;
_hp = MaxHP;
}
EmitSignal(SignalName.ArmorDamaged,_hp);
return returnAmount;
}
}

View file

@ -0,0 +1 @@
uid://fd4im1fmwc5n

View file

@ -0,0 +1,32 @@
using Godot;
namespace Newlon.Components;
public partial class ArmorHPObserver : Node
{
[Export] private float _threshold = 0.5f;
[Export] private bool _setGreater = false;
[Export] private Armor _observedArmor;
[Signal] public delegate void ThresholdReachedEventHandler();
public override void _Ready()
{
_observedArmor.ArmorDamaged += OnHPChanged;
}
private void OnHPChanged(float delta)
{
if (_setGreater == false && _observedArmor._hp / _observedArmor.MaxHP < _threshold)
{
EmitSignal(SignalName.ThresholdReached);
_observedArmor.ArmorDamaged -= OnHPChanged;
QueueFree();
}
else if (_setGreater && _observedArmor._hp / _observedArmor.MaxHP > _threshold)
{
EmitSignal(SignalName.ThresholdReached);
_observedArmor.ArmorDamaged -= OnHPChanged;
QueueFree();
}
}
}

View file

@ -0,0 +1 @@
uid://d3l8e8ko5r5i3

View file

@ -0,0 +1,33 @@
using Godot;
using Godot.Collections;
namespace Newlon.Components.Zombies;
public partial class DegradingSprite : Sprite2D
{
[Export] private Armor armor;
[Export] private Array<Texture2D> degradationStages;
[Export] private Array<float> thresholdPercentage;
public override void _Ready()
{
armor.ArmorDamaged += OnZombieHPChanged;
}
private void OnZombieHPChanged(float hp)
{
float percent = hp / armor.MaxHP;
for (int i = 0; i < degradationStages.Count; i++)
{
if (percent <= thresholdPercentage[i])
{
Texture = degradationStages[i];
}
else
{
break;
}
}
}
}

View file

@ -0,0 +1 @@
uid://bbw848msxb4re

164
scripts/entities/Entity.cs Normal file
View file

@ -0,0 +1,164 @@
using Godot;
using Godot.Collections;
using Newlon.Systems.Effects;
namespace Newlon.Components;
[GlobalClass]
public partial class Entity : Node2D
{
#region Health points
[Export] public float MaxHP;
public float HP;
[Signal] public delegate void OnHPChangedEventHandler(float deltaHP, Node origin);
[Signal] public delegate void OnDamagedEventHandler();
public virtual void TakeDamage(float amount, Node origin)
{
HP -= amount;
EmitSignal(SignalName.OnHPChanged, -amount, origin);
EmitSignal(SignalName.OnDamaged);
if (HP <= 0)
{
KillByDamage();
}
}
public virtual void Heal(float amount, Node origin)
{
EmitSignal(SignalName.OnHPChanged, amount, origin);
HP += amount;
if (HP > MaxHP) HP = MaxHP;
}
public virtual void KillByDamage()
{
Kill();
}
public virtual void Kill()
{
QueueFree();
}
#endregion
#region Brain
[Export] private AnimationPlayer _player;
[Export] private AnimationTree _tree;
public virtual void DisableBrain()
{
if (_player != null)
_player.ProcessMode = ProcessModeEnum.Pausable;
if (_tree != null)
_tree.ProcessMode = ProcessModeEnum.Pausable;
ProcessMode = ProcessModeEnum.Disabled;
}
public virtual void EnableBrain()
{
if (_player != null)
_player.ProcessMode = ProcessModeEnum.Inherit;
if (_tree != null)
_tree.ProcessMode = ProcessModeEnum.Inherit;
ProcessMode = ProcessModeEnum.Inherit;
}
#endregion
#region Effects
[Export] private Array<Effect> _effectImmunities = new();
[Export] private bool completeInvulnerability = false;
private readonly Dictionary<string, Effect> _activeEffectSlots = new();
private readonly Dictionary<string, Timer> _effectSlotTimers = new();
[Signal] public delegate void EffectStartedEventHandler(Effect what);
[Signal] public delegate void EffectEndedEventHandler(Effect what);
[Signal] public delegate void EffectContinuedEventHandler(Effect what);
public virtual void GiveEffect(Effect what)
{
if (_effectImmunities.Contains(what) || completeInvulnerability)
{
return;
}
string slot = what.Slot;
if (_activeEffectSlots.ContainsKey(slot) == false)
{
InitSlot(slot);
}
if (what == _activeEffectSlots[slot])
{
EmitSignal(SignalName.EffectContinued, what);
}
else
{
EmitSignal(SignalName.EffectStarted, what);
}
if (_activeEffectSlots[slot] != null)
{
_effectSlotTimers[slot].Stop();
_activeEffectSlots[slot].Exit(this);
}
_effectSlotTimers[slot].WaitTime = what.Duration;
_effectSlotTimers[slot].Start();
what.Enter(this);
_activeEffectSlots[slot] = what;
}
private void InitSlot(string key)
{
_activeEffectSlots.Add(key, null);
var timer = new Timer() { Autostart = false, OneShot = true };
AddChild(timer);
timer.Timeout += () => { EndEffectAtSlot(key); };
_effectSlotTimers.Add(key, timer);
}
public void EndEffect(Effect what)
{
EndEffectAtSlot(what.Slot);
}
public void ProcessEffects()
{
foreach (string key in _activeEffectSlots.Keys)
_activeEffectSlots[key]?.Process(this);
}
private void EndEffectAtSlot(string slot)
{
_activeEffectSlots[slot].Exit(this);
_activeEffectSlots[slot] = null;
EmitSignal(SignalName.EffectEnded, _activeEffectSlots[slot]);
}
#endregion
#region LocalTimescale
private float _localTimescale = 1.0f;
[Signal] public delegate void OnLocalTimescaleChangedEventHandler(float scale);
public float LocalTimescale
{
get => _localTimescale;
set
{
_localTimescale = value;
EmitSignal(SignalName.OnLocalTimescaleChanged, _localTimescale);
}
}
#endregion
#region Godot overrides
public override void _Ready()
{
HP = MaxHP;
}
#endregion
}

View file

@ -0,0 +1 @@
uid://3tw88wj1nrj1

View file

@ -0,0 +1,32 @@
using Godot;
namespace Newlon.Components;
public partial class EntityHPObserver : Node
{
[Export] private float _threshold = 0.5f;
[Export] private bool _setGreater = false;
[Export] private Entity _observedEntity;
[Signal] public delegate void ThresholdReachedEventHandler();
public override void _Ready()
{
_observedEntity.OnHPChanged += OnHPChanged;
}
private void OnHPChanged(float delta, Node origin)
{
if (_setGreater == false && _observedEntity.HP / _observedEntity.MaxHP < _threshold)
{
EmitSignal(SignalName.ThresholdReached);
_observedEntity.OnHPChanged -= OnHPChanged;
QueueFree();
}
else if (_setGreater && _observedEntity.HP / _observedEntity.MaxHP > _threshold)
{
EmitSignal(SignalName.ThresholdReached);
_observedEntity.OnHPChanged -= OnHPChanged;
QueueFree();
}
}
}

View file

@ -0,0 +1 @@
uid://dau0tfmlfiqmo

View file

@ -0,0 +1,36 @@
using Godot;
using System;
namespace Newlon.Components;
public partial class FlashComponent : CanvasGroup
{
[Export] private float _flashDuration = 0.1f;
private Tween _tween;
private ShaderMaterial _shaderMaterial;
public override void _Ready()
{
_shaderMaterial = Material as ShaderMaterial;
}
public void DamageFlash(int damage,Node origin)
{
Flash();
}
public void Flash()
{
_tween?.Kill();
_tween = CreateTween();
Action<float> action = SetAmount;
_tween.TweenMethod(Callable.From(action),0.8f,0.0f,_flashDuration);
}
private void SetAmount(float amount)
{
_shaderMaterial.SetShaderParameter("amount",amount);
}
}

View file

@ -0,0 +1 @@
uid://c5vfccegyy01t

View file

@ -0,0 +1,18 @@
using Godot;
using Newlon.Components.Zombies;
namespace Newlon.Components.Plants;
public partial class AreaAttack : Area2D
{
[Export] private int _damage;
public void Attack()
{
foreach (var zombie in GetOverlappingAreas())
{
var zombieData = zombie.GetParent<RuntimeZombieData>();
zombieData?.TakeDamage(_damage,GetParent());
}
}
}

View file

@ -0,0 +1 @@
uid://co7ttejdo2qot

View file

@ -0,0 +1,26 @@
using Godot;
using Newlon.Components.Level;
using Newlon.Components.Zombies;
namespace Newlon.Components.Plants;
public partial class ExplosionComponent : Area2D
{
[Export] private int damage;
[Export] private PackedScene particles;
public void Explode()
{
foreach (var zombie in GetOverlappingAreas())
{
var zombieData = zombie.GetParent<RuntimeZombieData>();
zombieData?.TakeDamage(damage, GetParent());
}
PoolContainer.Instance.SpawnParticles(particles, GetParent<RuntimePlantData>().GlobalPosition);
GetNode<ChannelPlayer>("ExplosionPlayer").Play();
GetParent<RuntimePlantData>().Kill();
}
}

View file

@ -0,0 +1 @@
uid://bhl6o2m3fn4xg

View file

@ -0,0 +1,44 @@
using Godot;
using System.Collections.Generic;
namespace Newlon.Components.Plants;
public partial class Eyesight : Area2D
{
private bool _enemyDetected;
public bool EnemyDetected => _enemyDetected;
private readonly List<Entity> _detectedEntities = new List<Entity>();
private RuntimePlantData _plantData;
public override void _Ready()
{
_plantData = GetParent<RuntimePlantData>();
AreaEntered += OnAreaEntered;
AreaExited += OnAreaExited;
}
public void OnAreaEntered(Area2D area)
{
var entity = area.GetParent<Entity>();
if (entity != null)
{
_detectedEntities.Add(entity);
}
_enemyDetected = _detectedEntities.Count > 0;
}
public void OnAreaExited(Area2D area)
{
var entity = area.GetParent<Entity>();
if (entity != null)
{
if (_detectedEntities.Contains(entity))
{
_detectedEntities.Remove(entity);
}
}
_enemyDetected = _detectedEntities.Count > 0;
}
}

View file

@ -0,0 +1 @@
uid://dn53jvpjyg63l

View file

@ -0,0 +1,18 @@
using Godot;
namespace Newlon.Components.Plants;
public partial class LoseZone : RuntimePlantData
{
public override void TakeDamage(float amount, Node origin)
{
}
public override void Kill()
{
}
}

View file

@ -0,0 +1 @@
uid://c0ov2bq5er0gh

View file

@ -0,0 +1,48 @@
using Godot;
using Newlon.Systems.Effects;
using System.Collections.Generic;
namespace Newlon.Components.Plants;
public partial class NerdusReturnAttack : Area2D
{
private float returnAmount;
[Export] private Effect returnEffect;
[Export] private float bitesToPeas = 1;
public bool triggered = false;
private List<Entity> entities = new();
public override void _Ready()
{
AreaEntered += OnAreaEntered;
AreaExited += OnAreaExited;
}
private void OnAreaEntered(Area2D area)
{
if (area.GetParent() is Entity entity)
{
entities.Add(entity);
}
}
private void OnAreaExited(Area2D area)
{
if (area.GetParent() is Entity entity && entities.Contains(entity))
{
entities.Remove(entity);
}
}
private void OnHPChanged(float delta, Node source)
{
if (delta >= 0) return;
returnAmount -= delta;
triggered = true;
}
public void ReturnAllDamage()
{
foreach (var entity in entities)
{
entity.TakeDamage(returnAmount * bitesToPeas, GetParent<Entity>());
entity.GiveEffect(returnEffect);
}
returnAmount = 0;
triggered = false;
}
}

View file

@ -0,0 +1 @@
uid://dcokqes5wwo3k

View file

@ -0,0 +1,14 @@
using Godot;
namespace Newlon.Components.Plants;
public partial class PlantEyesightLimiter : CollisionShape2D
{
public override void _Process(double delta)
{
if (Shape is SegmentShape2D segment)
{
segment.B = new Vector2(FieldParams.RightFieldBoundary.X - GlobalPosition.X+FieldParams.TileWidth/2.0f, 0);
}
}
}

View file

@ -0,0 +1 @@
uid://hccb0aee0x0o

View file

@ -0,0 +1,21 @@
using Godot;
using Newlon.Components.Level;
namespace Newlon.Components.Plants;
public partial class PlantSunSpawner : Node2D
{
[Export]
private PackedScene _sunScene;
[Export]
private int _amountPerSun;
public void Spawn()
{
var sun = _sunScene.Instantiate<Sun>();
sun.amount = _amountPerSun;
PoolContainer.Instance.Projectiles.AddChild(sun);
sun.GlobalPosition = GlobalPosition;
}
}

View file

@ -0,0 +1 @@
uid://b71gebny84s81

View file

@ -0,0 +1,20 @@
using Godot;
using Newlon.Components.Zombies;
using Newlon.Systems.Effects;
namespace Newlon.Components.Plants;
public partial class ReturnEffect : Node
{
[Export]
private Effect _effectToReturn;
public void OnDamageRecieved(int delta,Node origin)
{
if (delta >= 0) return;
if (origin is RuntimeZombieData zombie)
{
zombie.GiveEffect(_effectToReturn);
}
}
}

View file

@ -0,0 +1 @@
uid://bmtukcq10m8wo

View file

@ -0,0 +1,27 @@
using Godot;
using Newlon.Components.Level;
namespace Newlon.Components.Plants;
//
// Data that plant stores during runtime
//
public partial class RuntimePlantData : Entity
{
[Export]
public string internal_id;
public int Line { get; set; }
public PlantResource Resource;
private AudioStream eatenSound = ResourceLoader.Load<AudioStream>("res://assets/audio/sfx/gulp.mp3");
public override void KillByDamage()
{
AudioSequencer.Play("plant_eaten", eatenSound);
base.KillByDamage();
}
public override void Kill()
{
PoolContainer.Instance.EntityField[Resource.Layer].Remove(GlobalPosition);
QueueFree();
}
}

View file

@ -0,0 +1 @@
uid://dli2i6albvugt

View file

@ -0,0 +1,34 @@
using Godot;
using Newlon.Components.Level;
namespace Newlon.Components.Plants;
// Shoot component of some plants
public partial class Shooter : Node2D
{
[Export] protected PackedScene _projectile;
[Export] protected Timer _timer;
protected RuntimePlantData _plantData;
public override void _Ready()
{
_plantData = GetParent<RuntimePlantData>();
}
public void Shoot()
{
if (_timer.TimeLeft > 0) return;
_timer.Start();
SpawnProjectile();
}
public virtual void SpawnProjectile()
{
var instance = _projectile.Instantiate<Node2D>();
PoolContainer.Instance.Projectiles.AddChild(instance);
instance.GlobalTransform = GlobalTransform;
}
}

View file

@ -0,0 +1 @@
uid://ceprqkraw3v6m

View file

@ -0,0 +1,26 @@
using Godot;
using Newlon.Components.Level;
namespace Newlon.Components.Plants;
public partial class ThreepeaterShooter : Shooter
{
public override void SpawnProjectile()
{
for(int i = -1; i <= 1; i++)
{
if (GetParent<Node2D>().GlobalPosition.Y+i*FieldParams.TileHeight >= FieldParams.RightFieldBoundary.Y || GetParent<Node2D>().GlobalPosition.Y+i*FieldParams.TileHeight <= FieldParams.LeftFieldBoundary.Y)
continue;
var instance = _projectile.Instantiate<Node2D>();
PoolContainer.Instance.Projectiles.AddChild(instance);
instance.GlobalTransform = GlobalTransform;
if(i != 0)
{
var tween = CreateTween().SetEase(Tween.EaseType.Out).SetTrans(Tween.TransitionType.Sine);
tween.TweenProperty(instance,"position:y",instance.Position.Y+i*FieldParams.TileHeight,0.5);
}
}
}
}

View file

@ -0,0 +1 @@
uid://djpc0kvagpadv

View file

@ -0,0 +1,47 @@
using Godot;
using Newlon.Components.Level;
namespace Newlon.Components.Plants.Behaviours;
public partial class AloeBehaviour : BaseBehaviour
{
[Export] private float _hpTreshold = 0.25f;
private Timer _timer;
private bool _charge = true;
public override void _Ready()
{
base._Ready();
_timer = GetNode<Timer>("Timer");
}
public override void _Process(double delta)
{
_tree.Set("parameters/Tree/conditions/charged",_charge);
var checkPos = GetParent<Node2D>().GlobalPosition + Vector2.Right * FieldParams.TileWidth;
if(_charge && PoolContainer.Instance.TryGetEntity(checkPos, out RuntimePlantData plantData))
{
if((float)plantData.HP / (float)plantData.MaxHP < _hpTreshold)
{
_charge = false;
_tree.Set("parameters/Tree/conditions/heal",true);
_timer.Start();
}
}
}
public void Heal()
{
var checkPos = GetParent<Node2D>().GlobalPosition + Vector2.Right * FieldParams.TileWidth;
if (PoolContainer.Instance.TryGetEntity(checkPos, out RuntimePlantData plantData))
{
plantData.Heal(1200 + 0.5f * plantData.MaxHP, GetParent());
}
}
public void OnTimeout()
{
_charge = true;
}
}

View file

@ -0,0 +1 @@
uid://cljytsmqac0w7

View file

@ -0,0 +1,12 @@
using Godot;
namespace Newlon.Components;
public abstract partial class BaseBehaviour : Node
{
protected AnimationTree _tree;
public override void _Ready()
{
_tree = GetNode<AnimationTree>("../AnimationTree");
}
}

View file

@ -0,0 +1 @@
uid://3dbmgnr7qxee

View file

@ -0,0 +1,25 @@
using Godot;
using Godot.Collections;
namespace Newlon.Components.Plants.Behaviours;
public partial class HpBasedBehaviour : BaseBehaviour
{
private RuntimePlantData _data;
[Export] private Array<string> parameters;
public override void _Ready()
{
base._Ready();
_data = GetParent<RuntimePlantData>();
}
public void OnHPChanged(float amount, Node origin)
{
var calc = _data.HP / _data.MaxHP;
foreach (var par in parameters)
{
_tree.Set(par, calc);
}
}
}

View file

@ -0,0 +1 @@
uid://btkmd86pn828y

View file

@ -0,0 +1,16 @@
using Godot;
namespace Newlon.Components.Plants.Behaviours;
public partial class PeashooterBehaviour : BaseBehaviour
{
[Export] private Timer _shootTimer;
[Export] private Eyesight _sight;
public override void _Process(double delta)
{
bool readyToShoot = _sight.EnemyDetected && _shootTimer.TimeLeft <= 0;
_tree.Set("parameters/Tree/conditions/ready",readyToShoot);
}
}

View file

@ -0,0 +1 @@
uid://bdk5iqtw4xbkl

View file

@ -0,0 +1,38 @@
using Godot;
namespace Newlon.Components.Plants.Behaviours;
public partial class PotatomineBehaviour : BaseBehaviour
{
[Export] private Area2D _hitbox;
[Export] private Area2D detectionBox;
[Export] private CollisionShape2D _unprimedShape;
[Export] private CollisionShape2D _primedShape;
private bool _primed = false;
public void Prime()
{
_tree.Set("parameters/Tree/conditions/primed", true);
_hitbox.Monitorable = false;
_primed = true;
_unprimedShape.Disabled = true;
_primedShape.Disabled = false;
if (detectionBox.HasOverlappingAreas())
{
SetupExplosion();
}
}
public void OnAreaEntered(Area2D area)
{
if (_primed == false) return;
SetupExplosion();
}
private void SetupExplosion()
{
_tree.Set("parameters/Tree/conditions/explode", true);
_primed = false;
}
}

View file

@ -0,0 +1 @@
uid://c7qfh4py0uulo

View file

@ -0,0 +1,19 @@
using Godot;
namespace Newlon.Components.Plants.Behaviours;
public partial class SpikeweedBehaviour : BaseBehaviour
{
private int _inCount = 0;
public void OnHitboxEntered(Area2D _area)
{
if (_inCount++ == 0)
_tree.Set("parameters/Tree/blend_position",1);
}
public void OnHitboxExited(Area2D _area)
{
if (--_inCount == 0)
_tree.Set("parameters/Tree/blend_position",0);
}
}

View file

@ -0,0 +1 @@
uid://dqquodxaijmem

View file

@ -0,0 +1,12 @@
using Godot;
namespace Newlon.Components.Plants.Behaviours;
public partial class SunflowerBehaviour : BaseBehaviour
{
public void Timeout()
{
_tree.Set("parameters/Tree/conditions/produce", true);
}
}

View file

@ -0,0 +1 @@
uid://bth7gah4tn7uj

View file

@ -0,0 +1,11 @@
using Godot;
namespace Newlon.Components.Zombies;
public partial class AudioDamage : AudioStreamPlayer2D
{
public void OnDamaged(int amount, Node origin)
{
Play();
}
}

View file

@ -0,0 +1 @@
uid://bsg4utgc0u0vo

View file

@ -0,0 +1,50 @@
using Godot;
using Newlon.Components.Plants;
namespace Newlon.Components.Zombies;
public partial class EatBox : Area2D
{
// Rewrite this class completely when field system will be introduced.
[Export] public FloatModifiers _damage;
[Export]
private AudioStream biteSound = ResourceLoader.Load<AudioStream>("uid://dyid55nhflwyn");
private RuntimePlantData plant;
public bool isEating = false;
public void Bite()
{
if (GetParent<RuntimeZombieData>().AbleToEat)
{
plant?.TakeDamage((int)_damage.GetValue(), GetParent());
AudioSequencer.Play("bite", biteSound);
}
}
public void OnAreaEntered(Area2D area)
{
var parent = area.GetParent();
if (parent != null && parent is RuntimePlantData plantData)
{
plant = plantData;
isEating = true;
}
}
public void OnAreaExited(Area2D area)
{
var parent = area.GetParent();
if (parent == plant)
{
plant = null;
isEating = false;
}
}
}

View file

@ -0,0 +1 @@
uid://dqyony6jxt2p0

View file

@ -0,0 +1,78 @@
using Godot;
namespace Newlon.Components.Zombies;
public partial class RuntimeZombieData : Entity
{
[Export]
private Armor _armor;
[Signal] public delegate void HasBeenKilledEventHandler(RuntimeZombieData who);
[Signal] public delegate void HPChangedMixedEventHandler(float delta);
public bool AbleToEat = true;
public override void _Ready()
{
base._Ready();
OnHPChanged += HPChangedMixedInvokerSource;
LocalTimescale -= (float)GD.Randf() / 100.0f;
}
public override void Heal(float amount, Node origin)
{
if (_armor != null)
{
HP += _armor.Heal(amount);
}
else
HP += amount;
EmitSignal(SignalName.OnHPChanged, amount, origin);
if (HP > MaxHP)
{
HP = MaxHP;
}
}
public override void TakeDamage(float amount, Node origin)
{
if (_armor != null)
{
HP -= _armor.RecieveDamage(amount);
}
else
HP -= amount;
EmitSignal(SignalName.OnHPChanged, -amount, origin);
EmitSignal(SignalName.OnDamaged);
if (HP <= 0)
{
KillByDamage();
}
}
public void HPChangedMixedInvokerSource(float delta, Node source)
{
EmitSignal(SignalName.HPChangedMixed, delta);
}
public void HPChangedMixedInvoker(float delta)
{
EmitSignal(SignalName.HPChangedMixed, -delta);
}
public float GetMaxHPMixed()
{
if (_armor != null)
return MaxHP + _armor.MaxHP;
return MaxHP;
}
#region Death sequence
private bool _killed = false;
public override void KillByDamage()
{
if (_killed) return;
_killed = true;
AbleToEat = false;
EmitSignal(SignalName.HasBeenKilled,this);
}
#endregion
}

View file

@ -0,0 +1 @@
uid://dildme6epx8l4

View file

@ -0,0 +1,24 @@
using Godot;
using Newlon.Components.Zombies;
public partial class ZombieKillHandler : Node
{
[Export] private AnimationTree _tree;
[Export] private CollisionShape2D _collider;
private void OnKilled(RuntimeZombieData who)
{
var tween = CreateTween();
tween.TweenInterval(4.0);
tween.TweenCallback(Callable.From(() =>
{
((AnimationNodeStateMachinePlayback)_tree.Get("parameters/Tree/playback")).Travel("Death");
_collider.Disabled = true;
}));
tween.TweenInterval(3.0);
tween.TweenProperty(who, "modulate",new Color(1, 1, 1, 0),1.0);
tween.TweenCallback(Callable.From(() =>
{
who.Kill();
}));
}
}

View file

@ -0,0 +1 @@
uid://dk32ln8c2574d

View file

@ -0,0 +1,44 @@
using Godot;
namespace Newlon.Components.Zombies;
public partial class ZombieMover : Node
{
[Export]
private FloatModifiers _speed;
[Export]
private float _speedControlMult;
private Node2D _zombie;
public override void _Ready()
{
_zombie = GetParent<Node2D>();
}
public override void _PhysicsProcess(double delta)
{
_zombie.Position -= _zombie.Transform.X
* (float)delta
* FieldParams.TileWidth
* GetParent<RuntimeZombieData>().LocalTimescale
* _speed.GetValue()
* _speedControlMult;
}
public void SetSpeedFlat(float speed)
{
_speed.SetFlat(speed);
}
public void SetSpeedPercentage(float speed)
{
_speed.SetPercentage(speed);
}
public void SetSpeedMult(float speed)
{
_speed.SetMult(speed);
}
public void AddMult(float amount)
{
_speed.ChangeMult(amount);
}
}

View file

@ -0,0 +1 @@
uid://7hdj2k14lfe4

View file

@ -0,0 +1,17 @@
using Godot;
namespace Newlon.Components.Zombies.Behaviours;
public partial class HoboBehaviour : Node
{
[Export] private EatBox _eatBox;
[Export] private AnimationTree _animationTree;
public bool isEating => _eatBox.isEating;
public bool canDestroyed = false;
public void Trashed()
{
canDestroyed = true;
((AnimationNodeStateMachinePlayback)_animationTree.Get("parameters/Tree/playback")).Travel("Destroy");
GetParent<Entity>().LocalTimescale *= 3;
}
}

View file

@ -0,0 +1 @@
uid://c5v2og85t7s6j