brand new start

This commit is contained in:
Rendo 2025-08-01 02:47:32 +05:00
commit f15f38bfc4
464 changed files with 5 additions and 20007 deletions

View file

@ -1,56 +0,0 @@
using Godot;
using Newlon.Components.Level;
namespace Newlon;
public partial class Cursor : Node2D
{
#region Textures
private readonly Texture2D defaultArrow = ResourceLoader.Load<Texture2D>("uid://c20dwjohaljdk");
private readonly Texture2D defaultPoint = ResourceLoader.Load<Texture2D>("uid://cw0rqtl8ulndd");
private readonly Texture2D shovelArrow = ResourceLoader.Load<Texture2D>("uid://dq375kjjo17g2");
private readonly Texture2D plantArrow = ResourceLoader.Load<Texture2D>("uid://dx123mhv4oee");
#endregion
public static Cursor Instance { get; private set; }
public bool shovel = false;
public bool plant = false;
public static CursorMode Mode = CursorMode.Mouse;
private float sensitivity = 200.0f;
public enum CursorMode
{
Mouse,
Gamepad
}
public override void _EnterTree()
{
Instance = this;
}
public override void _Process(double delta)
{
switch (Mode)
{
case CursorMode.Mouse:
break;
case CursorMode.Gamepad:
if (GamepadHandler.Instance.IsGamepadControlled == false) return;
var vector = Input.GetVector("cursor_left", "cursor_right", "cursor_up", "cursor_down");
if (vector == Vector2.Zero) return;
var set_position = GetGlobalMousePosition() + vector * (float)delta * sensitivity / (float)Engine.TimeScale;
GetViewport().WarpMouse(GetGlobalTransformWithCanvas() * set_position);
break;
}
}
public static Vector2 GetCursorPosition()
{
return Instance.GetGlobalMousePosition();
}
}

View file

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

View file

@ -1,14 +0,0 @@
using Godot;
namespace Newlon;
public static class LON
{
public static void ForceFinishTween(Tween tween)
{
if (tween == null) return;
tween.Pause();
tween.CustomStep(Mathf.Inf);
}
}

View file

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

View file

@ -1,101 +0,0 @@
using Godot;
using Newlon.Resources;
using System.Text.Json;
using System.Collections.Generic;
namespace Newlon;
public partial class SaveSerializer : Node
{
const string SAVE_PATH = "user://save.json";
public override void _Ready()
{
GetTree().AutoAcceptQuit = false;
LoadGame();
}
public override void _Notification(int what)
{
if (what == NotificationWMCloseRequest)
{
SaveGame();
GetTree().Quit();
}
}
public static void SaveGame()
{
var access = FileAccess.Open(SAVE_PATH, FileAccess.ModeFlags.Write);
var playerProgress = PlayerProgress.Instance;
var save = new SaveData
{
SFXVolume = (float)Settings.SFX,
MusicVolume = (float)Settings.Music,
SplashSeen = Settings.Splash,
Money = playerProgress.Money,
SeedpacketSlots = playerProgress.MaxSeedpackets,
PlayerPlants = [],
SaveGameVersion = (string)ProjectSettings.GetSetting("application/config/version")
};
foreach (var plant in playerProgress.PlayerPlants)
{
save.PlayerPlants.Add(plant.GetInternalID());
}
access.StoreString(JsonSerializer.Serialize<SaveData>(save));
access.Close();
}
public static void LoadGame()
{
if (FileAccess.FileExists(SAVE_PATH) == false)
{
InitiateCleanSave();
return;
}
var access = FileAccess.Open(SAVE_PATH, FileAccess.ModeFlags.Read);
var parsed = JsonSerializer.Deserialize<SaveData>(access.GetAsText());
Settings.SFX = parsed.SFXVolume;
Settings.Music = parsed.MusicVolume;
Settings.Splash = parsed.SplashSeen;
AudioServer.SetBusVolumeDb(2, Mathf.LinearToDb(Mathf.Exp((float)Settings.SFX) - 1));
AudioServer.SetBusVolumeDb(1, Mathf.LinearToDb(Mathf.Exp((float)Settings.Music) - 1));
var playerProgress = PlayerProgress.Instance;
playerProgress.MaxSeedpackets = parsed.SeedpacketSlots;
playerProgress.PlayerPlants = [];
foreach (var plantId in parsed.PlayerPlants)
{
playerProgress.PlayerPlants.Add((PlantResource)GameRegistry.GetEntityByName(plantId));
}
access.Close();
}
private static void InitiateCleanSave()
{
PlayerProgress.Instance.PlayerPlants = new List<PlantResource>([(PlantResource)GameRegistry.GetEntityByName("peashooter")]);
PlayerProgress.Instance.Money = 0;
SaveGame();
}
private partial class SaveData
{
public float SFXVolume { get; set; }
public float MusicVolume { get; set; }
public string SaveGameVersion { get; set; }
public bool SplashSeen { get; set; }
public List<string> PlayerPlants { get; set; }
public int Money { get; set; } = 0;
public int SeedpacketSlots { get; set; } = 6;
public List<string> FinishedLevels { get; set; } = new();
}
}

View file

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

View file

@ -1,17 +0,0 @@
using Godot;
namespace Newlon.Components;
public partial class TimeScalableAnimationTree : AnimationTree
{
[Export] private Entity entity;
public override void _Ready()
{
entity.OnLocalTimescaleChanged += OnTimescaleChanged;
}
private void OnTimescaleChanged(float timescale)
{
Set("parameters/TimeScale/scale", timescale);
}
}

View file

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

View file

@ -1,21 +0,0 @@
using Godot;
namespace Newlon.Components;
public partial class TimeScalableTimer : Timer
{
[Export] private Entity entity;
private float internal_timescale;
public override void _Ready()
{
internal_timescale = entity.LocalTimescale;
entity.OnLocalTimescaleChanged += OnTimescaleChanged;
}
private void OnTimescaleChanged(float timescale)
{
WaitTime *= internal_timescale / timescale;
internal_timescale = timescale;
}
}

View file

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

View file

@ -1,94 +0,0 @@
using Godot;
using Godot.Collections;
public partial class AudioSequencer : Node
{
private static AudioSequencer instance;
[Export]private Dictionary<string, AudioStreamPlayer> channels = [];
[Export]private Dictionary<string, bool> channelProcess = [];
[Export]private Dictionary<string, ChannelSettings> channelSettings = [];
[Export]
private ChannelSettings standardSettings;
public override void _Ready()
{
instance = this;
}
public static bool IsChannelPlaying(string id)
{
if (instance.channels.ContainsKey(id) == false)
{
instance.InitiateChannel(id);
return false;
}
if (instance.channelSettings[id].restartTreshold == 0)
return false;
if (instance.channelSettings[id].restartTreshold < 0)
return instance.channelProcess[id];
return instance.channelProcess[id] && instance.channels[id].GetPlaybackPosition() < instance.channelSettings[id].restartTreshold / Engine.TimeScale;
}
public static void Play(string id, AudioStream what, ChannelSettings settings = null)
{
if (IsChannelPlaying(id)) return;
if (settings != null) ChangeSettings(id, settings);
instance.PlayAtChannel(id, what);
}
public static void ChangeSettings(string id, ChannelSettings settings)
{
if (instance.channels.ContainsKey(id) == false)
{
instance.InitiateChannel(id, settings);
return;
}
if (settings == null)
{
instance.channelSettings[id] = instance.standardSettings;
return;
}
instance.channelSettings[id] = settings;
}
private AudioStreamPlayer InitiateChannel(string id, ChannelSettings settings = null)
{
AudioStreamPlayer player = new();
AddChild(player);
channels.Add(id, player);
channelProcess.Add(id, false);
player.Name = id;
player.MaxPolyphony = 5;
player.Bus = "SFXBus";
player.Finished += () => { MarkChannel(id, false); };
if (settings != null)
{
channelSettings.Add(id, settings);
}
else
{
channelSettings.Add(id, standardSettings);
}
return player;
}
private void PlayAtChannel(string id, AudioStream what)
{
channels[id].Stream = what;
channels[id].Play();
MarkChannel(id, true);
}
private void MarkChannel(string id, bool how)
{
channelProcess[id] = how;
}
}

View file

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

View file

@ -1,42 +0,0 @@
using Godot;
using Newlon;
public partial class AudioSlider : HSlider
{
enum TYPE
{
SFX,
MUSIC
}
[Export] private TYPE affects;
public override void _Ready()
{
ValueChanged += OnValueChanged;
if (affects == TYPE.SFX)
{
SetValueNoSignal(Settings.SFX);
}
else
{
SetValueNoSignal(Settings.Music);
}
}
private void OnValueChanged(double value)
{
if (affects == TYPE.SFX)
{
var volume = Mathf.LinearToDb(Mathf.Exp((float)value) - 1); ;
Settings.SFX = value;
AudioServer.SetBusVolumeDb(2, volume);
}
else
{
var volume = Mathf.LinearToDb(Mathf.Exp((float)value) - 1); ;
Settings.Music = value;
AudioServer.SetBusVolumeDb(1, volume);
}
}
}

View file

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

View file

@ -1,16 +0,0 @@
using Godot;
[GlobalClass]
public partial class ChannelPlayer : Node
{
[Export] private ChannelSettings settings;
[Export] private AudioStream audioStream;
[Export] private string channel;
public void Play()
{
AudioSequencer.Play(channel, audioStream);
if (settings != null)
AudioSequencer.ChangeSettings(channel, settings);
}
}

View file

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

View file

@ -1,35 +0,0 @@
using Godot;
using Godot.Collections;
[GlobalClass]
public partial class ChannelPlaylist : Node
{
[Export] private Array<AudioStream> playlist;
[Export] private Array<string> channels;
[Export] private ChannelSettings channelSettings;
private int internal_index = 0;
public void Play()
{
AudioSequencer.Play(channels[internal_index], playlist[internal_index]);
}
public void SetIndex(int index)
{
internal_index = index;
if (internal_index >= playlist.Count)
{
internal_index = 0;
}
else if (internal_index < 0)
{
internal_index = playlist.Count - 1;
}
}
public void Next()
{
SetIndex(internal_index + 1);
}
}

View file

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

View file

@ -1,7 +0,0 @@
using Godot;
[GlobalClass]
public partial class ChannelSettings : Resource
{
[Export] public float restartTreshold;
}

View file

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

View file

@ -1,24 +0,0 @@
using Godot;
using Newlon.Components.Level;
public partial class ChooseYourSeedsMusic : AudioStreamPlayer
{
public override void _Ready()
{
RuntimeLevelData.Instance.OnLevelStateChanged += OnLevelStateChanged;
}
private void OnLevelStateChanged(RuntimeLevelData.LevelStates state)
{
if (state == RuntimeLevelData.LevelStates.ChooseYourSeeds)
{
Play();
}
else
{
var tween = CreateTween();
tween.TweenProperty(this, "volume_linear", 0, 1);
tween.TweenCallback(Callable.From(Stop));
}
}
}

View file

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

View file

@ -1,29 +0,0 @@
using Godot;
using Godot.Collections;
using System.Collections.Generic;
using Newlon.Components;
using Newlon.Systems.Effects;
public partial class EffectBasedPlayer : Node
{
[Export] public Array<Effect> effectsToMap;
[Export] public Array<AudioStream> streamsToMapTo;
[Export] public Array<ChannelSettings> streamSettings;
private System.Collections.Generic.Dictionary<Effect, (AudioStream,ChannelSettings)> effectToAudioMap = new();
public override void _Ready()
{
GetParent<Entity>().EffectStarted += OnEffectStarted;
for (int i = 0; i < effectsToMap.Count; i++)
{
effectToAudioMap.Add(effectsToMap[i], (streamsToMapTo[i],streamSettings[i]));
}
}
public void OnEffectStarted(Effect what)
{
if (effectToAudioMap.ContainsKey(what) == false) return;
AudioSequencer.Play(what.Slot, effectToAudioMap[what].Item1);
AudioSequencer.ChangeSettings(what.Slot, effectToAudioMap[what].Item2);
}
}

View file

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

View file

@ -1,41 +0,0 @@
using Godot;
using Newlon.Components.Level;
using System;
public partial class MusicTransitioner : AudioStreamPlayer
{
private AudioStreamPlaybackInteractive playback;
private Timer timer;
public override void _Ready()
{
RuntimeLevelData.Instance.OnLevelStateChanged += OnLevelStateChanged;
timer = GetNode<Timer>("Timer");
}
private void OnLevelStateChanged(RuntimeLevelData.LevelStates state)
{
if (state == RuntimeLevelData.LevelStates.Game)
{
Play();
playback = (AudioStreamPlaybackInteractive)GetStreamPlayback();
VolumeLinear = 1;
}
else
{
var tween = CreateTween();
tween.TweenProperty(this, "volume_linear", 0, 1);
tween.TweenCallback(Callable.From(Stop));
}
}
public void OnHugeWaveApproaching()
{
playback.SwitchToClip(1);
timer.Start();
}
public void OnTimerTimeout()
{
playback.SwitchToClip(0);
}
}

View file

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

View file

@ -1,20 +0,0 @@
using Godot;
using Newlon.Components.Level;
namespace Newlon.Debug;
public partial class Cheats : Node
{
public override void _Input(InputEvent @event)
{
if (OS.IsDebugBuild() == false) return;
if (@event.IsActionPressed("cheat_add_sun"))
{
RuntimeLevelData.Instance.AddSun(50);
}
if (@event.IsActionPressed("cheat_unlock_all"))
{
PlayerProgress.Instance.PlayerPlants = GameRegistry.GetPlants();
}
}
}

View file

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

View file

@ -1,20 +0,0 @@
using Godot;
using System;
namespace Newlon.Debug;
//
// Debug tool to check time since clock loaded
//
public partial class Clock : Label
{
private ulong _time = 0;
public override void _Process(double delta)
{
_time += (ulong)(delta*1000);
ulong seconds = _time / 1000 % 60;
ulong minutes = seconds / 60 % 60;
Text = minutes.ToString()+":"+seconds.ToString();
}
}

View file

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

View file

@ -1,32 +0,0 @@
using Godot;
namespace Newlon.Components.Droppables;
public partial class DropMover : Node
{
public float ySpeed = -200.0f;
public float xSpeed = 150.0f;
private float stop_y;
private Node2D parent;
private Vector2 velocity;
private float gravity;
public override void _Ready()
{
parent = GetParent<Node2D>();
stop_y = ((parent.GlobalPosition / FieldParams.Tile).Ceil() * FieldParams.Tile).Y;
gravity = (float)ProjectSettings.GetSetting("physics/2d/default_gravity");
velocity = new Vector2((GD.Randf() - 0.5f) * xSpeed, ySpeed);
}
public override void _Process(double delta)
{
if (parent.GlobalPosition.Y >= stop_y) QueueFree();
velocity += Vector2.Down * gravity * (float)delta;
parent.GlobalPosition += velocity * (float)delta;
}
}

View file

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

View file

@ -1,30 +0,0 @@
using Godot;
namespace Newlon.Components.Droppables;
[GlobalClass]
public partial class DroppableItem : Area2D
{
[Signal] public delegate void PickedUpEventHandler();
public override void _MouseEnter()
{
if (GamepadHandler.Instance.IsGamepadControlled)
{
GetViewport().SetInputAsHandled();
PickUp();
EmitSignal(SignalName.PickedUp);
}
}
public override void _InputEvent(Viewport viewport, InputEvent @event, int shapeIdx)
{
if (@event.IsActionPressed("primary_action"))
{
GetViewport().SetInputAsHandled();
PickUp();
EmitSignal(SignalName.PickedUp);
}
}
public virtual void PickUp() {}
}

View file

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

View file

@ -1,22 +0,0 @@
using Godot;
using Newlon.Resources;
namespace Newlon.Components.Droppables;
public partial class DroppableSeedpacket : DroppableItem
{
public PlantResource plant;
[Export] private Label _cost;
[Export] private TextureRect _icon;
[Export] private TextureRect _packet;
public override void _Ready()
{
_cost.Text = plant.Cost.ToString();
_icon.Texture = plant.Preview;
if (plant.CustomFrame != null)
{
_packet.Texture = plant.CustomFrame.frame;
_cost.LabelSettings = plant.CustomFrame.font;
}
}
}

View file

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

View file

@ -1,17 +0,0 @@
using Godot;
public partial class AnimationStatistics : Node
{
[Export]
private string animationName;
[Export]
private string trackToFind;
private float invokationsPerSecond;
public override void _Ready()
{
var animation = GetParent<AnimationPlayer>().GetAnimation(animationName);
var track_id = animation.FindTrack(trackToFind,Animation.TrackType.Method);
invokationsPerSecond = animation.TrackGetKeyCount(track_id)/ animation.Length;
}
}

View file

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

View file

@ -1,21 +0,0 @@
using Godot;
using Newlon.Systems.Effects;
namespace Newlon.Components;
public partial class AreaOfEffect : Area2D
{
[Export] public Effect givenEffect;
public override void _Ready()
{
AreaEntered += OnAreaEntered;
}
public void OnAreaEntered(Area2D what)
{
if (what.GetParent() is Entity entity)
{
entity.GiveEffect(givenEffect);
}
}
}

View file

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

View file

@ -1,65 +0,0 @@
using Godot;
namespace Newlon.Components;
[GlobalClass]
public partial class Armor : Node
{
[Signal]
public delegate void DamagedEventHandler();
[Signal]
public delegate void HpChangedEventHandler(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 = damage - _hp;
if (returnAmount < 0)
returnAmount = 0;
if (_hp - damage <= 0)
{
var delta = _hp;
_hp = 0;
EmitSignal(SignalName.HpChanged, -delta);
EmitSignal(SignalName.Damaged);
EmitSignal(SignalName.ArmorLost);
_lost = true;
}
else
{
_hp -= damage;
EmitSignal(SignalName.HpChanged, -damage);
EmitSignal(SignalName.Damaged);
}
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.HpChanged,_hp);
return returnAmount;
}
}

View file

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

View file

@ -1,32 +0,0 @@
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.Damaged += OnDamaged;
}
private void OnDamaged()
{
if (_setGreater == false && _observedArmor._hp / _observedArmor.MaxHP < _threshold)
{
EmitSignal(SignalName.ThresholdReached);
_observedArmor.Damaged -= OnDamaged;
QueueFree();
}
else if (_setGreater && _observedArmor._hp / _observedArmor.MaxHP > _threshold)
{
EmitSignal(SignalName.ThresholdReached);
_observedArmor.Damaged -= OnDamaged;
QueueFree();
}
}
}

View file

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

View file

@ -1,33 +0,0 @@
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.Damaged += OnDamaged;
}
private void OnDamaged()
{
float percent = armor._hp / armor.MaxHP;
for (int i = 0; i < degradationStages.Count; i++)
{
if (percent <= thresholdPercentage[i])
{
Texture = degradationStages[i];
}
else
{
break;
}
}
}
}

View file

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

View file

@ -1,218 +0,0 @@
using Godot;
using Godot.Collections;
using Newlon.Components.Level;
using Newlon.Systems.Effects;
namespace Newlon.Components;
[GlobalClass]
public partial class Entity : Node2D
{
#region Health points
[Export] public float MaxHP;
[Export]public float HP;
[Signal] public delegate void OnHPChangedEventHandler(EntitySignalContext context);
[Signal] public delegate void OnDamagedEventHandler();
[Signal] public delegate void HasBeenKilledEventHandler(Entity who);
public virtual void TakeDamage(float amount, Node origin)
{
if (amount > 0)
EmitSignal(SignalName.OnDamaged);
var context = new EntitySignalContext()
{
target = this,
source = (Entity)origin,
actionAmount = amount
};
if (HP - amount <= 0)
{
context.deltaHP = -HP;
EmitSignal(SignalName.OnHPChanged, context);
HP = 0;
KillByDamage();
}
else
{
context.deltaHP = -amount;
HP -= amount;
EmitSignal(SignalName.OnHPChanged, context);
}
}
public virtual void Heal(float amount, Node origin)
{
var context = new EntitySignalContext()
{
target = this,
source = (Entity)origin,
actionAmount = amount
};
if (HP + amount > MaxHP)
{
context.deltaHP = MaxHP - HP;
EmitSignal(SignalName.OnHPChanged, context);
HP = MaxHP;
}
else
{
context.deltaHP = amount;
HP += amount;
EmitSignal(SignalName.OnHPChanged, context);
}
}
public bool Killed = false;
public virtual void KillByDamage()
{
if (Killed) return;
Killed = true;
EmitSignal(SignalName.HasBeenKilled,this);
ClearEffects();
Kill();
}
public virtual void Kill()
{
QueueFree();
}
#endregion
#region Brain
[Export] private AnimationPlayer _player;
[Export] private AnimationTree _tree;
private bool forceToggledBrain = false;
private bool brainEnabled = true;
public virtual void DisableBrain(bool force = true)
{
if (brainEnabled == false) return;
if (_player != null)
_player.ProcessMode = ProcessModeEnum.Pausable;
if (_tree != null)
_tree.ProcessMode = ProcessModeEnum.Pausable;
ProcessMode = ProcessModeEnum.Disabled;
forceToggledBrain = force;
brainEnabled = false;
}
public virtual void EnableBrain(bool force = true)
{
if (brainEnabled) return;
if (_player != null)
_player.ProcessMode = ProcessModeEnum.Inherit;
if (_tree != null)
_tree.ProcessMode = ProcessModeEnum.Inherit;
ProcessMode = ProcessModeEnum.Inherit;
forceToggledBrain = force;
brainEnabled = true;
}
#endregion
#region Effects
[Export] private Array<Effect> _effectImmunities = new();
[Export] private bool completeInvulnerability = false;
private readonly Dictionary<string, EffectHandler> effectHandlers = 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 (what == null ||
Killed ||
completeInvulnerability || _effectImmunities.Contains(what))
return;
var slot = what.Slot;
if (effectHandlers.ContainsKey(slot) == false)
InitSlot(slot);
if (effectHandlers[slot].HandledEffect == what)
{
effectHandlers[slot].Restart();
}
else
{
effectHandlers[slot].HandledEffect = what;
effectHandlers[slot].Start();
}
}
public void EndEffect(Effect what)
{
EndEffectAtSlot(what.Slot);
}
public Tween CreateTweenEffect(Effect effect)
{
Tween tween = CreateTween();
effectHandlers[effect.Slot].EffectTween = tween;
return tween;
}
protected void ClearEffects()
{
foreach (var slot in effectHandlers.Keys)
{
effectHandlers[slot].End();
}
}
private void InitSlot(string key)
{
effectHandlers.Add(key, new EffectHandler());
effectHandlers[key].handler = this;
effectHandlers[key].EffectTimer = new();
AddChild(effectHandlers[key].EffectTimer);
effectHandlers[key].EffectTimer.Name = key + "Timer";
effectHandlers[key].EffectTimer.Timeout += () => { EndEffectAtSlot(key); };
}
public void ProcessEffects()
{
foreach (var slot in effectHandlers.Keys)
{
effectHandlers[slot].Process();
}
}
private void EndEffectAtSlot(string slot)
{
EmitSignal(SignalName.EffectEnded, effectHandlers[slot].HandledEffect);
effectHandlers[slot].End();
}
#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;
if (RuntimeLevelData.Instance != null)
{
if (RuntimeLevelData.Instance.GetLevelState() != RuntimeLevelData.LevelStates.Game) DisableBrain(false);
}
}
#endregion
}

View file

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

View file

@ -1,32 +0,0 @@
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(EntitySignalContext context)
{
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

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

View file

@ -1,11 +0,0 @@
using Godot;
namespace Newlon.Components;
public partial class EntitySignalContext : RefCounted
{
public Node source;
public Entity target;
public float actionAmount;
public float deltaHP;
}

View file

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

View file

@ -1,51 +0,0 @@
using Godot;
using Newlon.Components;
public partial class FlashShaderController : Node
{
[Export] public float flashTime = 0.5f;
[Export]
private ShaderMaterial shaderMaterial;
private uint toggleStack = 0;
private Tween flashTween;
public void DamageFlash()
{
Flash();
}
public void Flash(float customFlashTime = 0)
{
if (flashTween != null)
flashTween.Kill();
var time = flashTime;
if (customFlashTime > 0)
time = customFlashTime;
flashTween = CreateTween();
flashTween.TweenMethod(Callable.From<float>(SetBlend), 1.0, 0.0, time);
}
public void Select()
{
toggleStack++;
UpdateSelected();
}
public void Deselect()
{
toggleStack--;
UpdateSelected();
}
private void SetBlend(float blend)
{
shaderMaterial.SetShaderParameter("blend", blend);
}
private void UpdateSelected()
{
if (toggleStack > 0)
{
shaderMaterial.SetShaderParameter("selected", true);
}
else
{
shaderMaterial.SetShaderParameter("selected", false);
}
}
}

View file

@ -1 +0,0 @@
uid://30pbgasu64aw

View file

@ -1,14 +0,0 @@
using Godot;
namespace Newlon.Components;
public partial class InvulnerableEntity : Entity
{
public override void TakeDamage(float amount, Node origin)
{
}
public override void Heal(float amount, Node origin)
{
}
}

View file

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

View file

@ -1,18 +0,0 @@
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

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

View file

@ -1,60 +0,0 @@
using Godot;
namespace Newlon.Components.Plants;
public partial class DragAction : Node
{
[Signal] public delegate void DragBeginEventHandler();
[Signal] public delegate void DragEndEventHandler(bool aborted);
private bool dragging = false;
private bool toggle = false;
private bool can_end = false;
private bool mouseIn = false;
public override void _Ready()
{
GetParent<Area2D>().MouseEntered += OnMouseEntered;
GetParent<Area2D>().MouseExited += OnMouseExited;
}
public void OnMouseEntered()
{
mouseIn = true;
}
public void OnMouseExited()
{
mouseIn = false;
}
public override void _Input(InputEvent @event)
{
if (mouseIn && @event.IsActionPressed("primary_action"))
{
dragging = true;
toggle = false;
can_end = false;
EmitSignal(SignalName.DragBegin);
GetTree().CreateTimer(0.2, ignoreTimeScale: true).Timeout += OnToggleTimeout;
GetViewport().SetInputAsHandled();
}
if (dragging && can_end && (toggle == false && @event.IsActionReleased("primary_action") || (toggle == true && @event.IsActionPressed("primary_action"))))
{
dragging = false;
EmitSignal(SignalName.DragEnd,false);
GetViewport().SetInputAsHandled();
}
if (dragging && @event.IsActionPressed("cancel_action"))
{
dragging = false;
EmitSignal(SignalName.DragEnd,true);
}
}
public void OnToggleTimeout()
{
can_end = true;
if (Input.IsActionPressed("primary_action") == false)
{
toggle = true;
}
}
}

View file

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

View file

@ -1,26 +0,0 @@
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

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

View file

@ -1,44 +0,0 @@
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

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

View file

@ -1,18 +0,0 @@
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

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

View file

@ -1,48 +0,0 @@
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(EntitySignalContext context)
{
if (context.deltaHP >= 0) return;
returnAmount -= context.deltaHP;
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

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

View file

@ -1,14 +0,0 @@
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

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

View file

@ -1,27 +0,0 @@
using Godot;
using Newlon.Projectiles;
using Newlon.Components.Level;
using Newlon.Components.Droppables;
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;
var mover = new DropMover();
sun.AddChild(mover);
}
}

View file

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

View file

@ -1,20 +0,0 @@
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(EntitySignalContext context)
{
if (context.deltaHP >= 0) return;
if (context.source is RuntimeZombieData zombie)
{
zombie.GiveEffect(_effectToReturn);
}
}
}

View file

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

View file

@ -1,26 +0,0 @@
using Godot;
using Newlon.Components.Level;
using Newlon.Resources;
namespace Newlon.Components.Plants;
//
// Data that plant stores during runtime
//
public partial class RuntimePlantData : Entity
{
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.RemoveEntity(GlobalPosition, Resource.Layer);
QueueFree();
}
}

View file

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

View file

@ -1,34 +0,0 @@
using Godot;
using Newlon.Components.Level;
namespace Newlon.Components.Plants;
// Shoot component of some plants
public partial class Shooter : Node2D
{
[Export] public PackedScene _projectile { get; protected set;}
[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

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

View file

@ -1,26 +0,0 @@
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

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

View file

@ -1,51 +0,0 @@
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;
private PackedScene particlesPacked = ResourceLoader.Load<PackedScene>("uid://b3na62o5pu1gt");
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(300, GetParent());
var particles = particlesPacked.Instantiate<Node2D>();
PoolContainer.Instance.Particles.AddChild(particles);
particles.GlobalPosition = plantData.GlobalPosition;
}
}
public void OnTimeout()
{
_charge = true;
}
}

View file

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

View file

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

View file

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

View file

@ -1,18 +0,0 @@
using Godot;
using Godot.Collections;
namespace Newlon.Components.Plants.Behaviours;
public partial class HpBasedBehaviour : BaseBehaviour
{
[Export] private Array<string> parameters;
public void OnHPChanged(EntitySignalContext context)
{
var calc = context.target.HP / context.target.MaxHP;
foreach (var par in parameters)
{
_tree.Set(par, calc);
}
}
}

View file

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

View file

@ -1,16 +0,0 @@
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

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

View file

@ -1,38 +0,0 @@
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

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

View file

@ -1,45 +0,0 @@
using Godot;
namespace Newlon.Components.Plants;
public partial class SnipachBehaviour : BaseBehaviour
{
[Export] public AreaAttack attackBox;
[Export] public Timer timer;
[Export] public Timer guardTimer;
private bool dragging = false;
public void OnDragBegin()
{
if (timer.TimeLeft > 0 || guardTimer.TimeLeft > 0) return;
dragging = true;
attackBox.Visible = dragging;
}
public void OnDragEnd(bool aborted)
{
if (dragging == false) return;
dragging = false;
attackBox.Visible = dragging;
if (aborted) return;
attackBox.Attack();
timer.Start();
}
public override void _PhysicsProcess(double delta)
{
if (dragging)
{
attackBox.GlobalPosition = (Cursor.GetCursorPosition() / FieldParams.Tile).Ceil() * FieldParams.Tile - new Vector2(20, 14);
}
if (timer.TimeLeft > 0)
{
GetParent<Node2D>().Modulate = Colors.DeepSkyBlue;
}
else
{
GetParent<Node2D>().Modulate = Colors.White;
}
}
}

View file

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

View file

@ -1,19 +0,0 @@
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

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

View file

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

View file

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

View file

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

View file

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

View file

@ -1,51 +0,0 @@
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 float Damage => _damage.GetValue();
public bool isEating = false;
public void Bite()
{
if (GetParent<RuntimeZombieData>().AbleToEat)
{
plant?.TakeDamage(Damage, 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

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

Some files were not shown because too many files have changed in this diff Show more