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,17 +0,0 @@
using Godot;
using Newlon.Components.Level;
public partial class GameTimer : Timer
{
public void OnLevelStateChanged(RuntimeLevelData.LevelStates state)
{
if (state == RuntimeLevelData.LevelStates.Game)
{
Start();
}
else
{
Stop();
}
}
}

View file

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

View file

@ -1,62 +0,0 @@
using Godot;
using Newlon;
using Newlon.Resources;
using Newlon.Components;
using Newlon.Components.Level;
using Newlon.Components.Plants;
using Newlon.Components.Zombies;
public partial class InitialPackedSceneSpawner : Node
{
public void OnLevelStateChanged(RuntimeLevelData.LevelStates state)
{
if (state == RuntimeLevelData.LevelStates.ChooseYourSeeds)
{
for (int i = 0; i < RuntimeLevelData.LevelResource.initialScenes.Count; i++)
{
var packed = RuntimeLevelData.LevelResource.initialScenes[i];
if (packed == null) continue;
var scene = packed.Instantiate();
if (scene is Node2D node)
{
int x = i % 9;
int y = i / 9;
var position = FieldParams.LeftFieldBoundary + new Vector2((x + 0.5f) * FieldParams.TileWidth, (y + 0.5f) * FieldParams.TileHeight);
if (node is Entity entity)
{
var brainDisabler = new LevelStateBrainDisabler();
entity.DisableBrain();
entity.AddChild(brainDisabler);
if (entity is RuntimeZombieData)
{
PoolContainer.Instance.Zombies.AddChild(node);
node.GlobalPosition = position + new Vector2(0, 0.5f * FieldParams.TileHeight);
}
else if (entity is RuntimePlantData plant)
{
PoolContainer.Instance.Plants.AddChild(plant);
node.GlobalPosition = position;
plant.Resource = GameRegistry.GetEntityByName(plant.Resource.GetInternalID()) as PlantResource;
PoolContainer.Instance.TrySetEntity(plant.GlobalPosition, plant, plant.Resource.Layer);
}
else
{
PoolContainer.Instance.Structures.AddChild(entity);
node.GlobalPosition = position;
PoolContainer.Instance.TrySetEntity(entity.GlobalPosition,entity,1);
}
}
else
{
PoolContainer.Instance.Structures.AddChild(node);
}
}
}
}
}
}

View file

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

View file

@ -1,12 +0,0 @@
using Godot;
using Newlon;
public partial class LeftBoundaryMarker : Marker2D
{
public override void _Ready()
{
FieldParams.LeftFieldBoundary = (Vector2I)GlobalPosition;
QueueFree();
}
}

View file

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

View file

@ -1,69 +0,0 @@
using Godot;
using Newlon.Components.Level;
using Newlon.Resources;
namespace Newlon;
//
// Class that gives access to level data, pools and etc.
//
public partial class LevelController : Node
{
const string REWARD_SCENE_UID = "uid://cwck7e1tt057k";
public static LevelController Instance { get; private set; }
public RewardResource Reward { get; private set; }
private string pathToInitiator;
public override void _EnterTree()
{
Instance = this;
}
public override void _ExitTree()
{
Instance = null;
}
/// <summary>
///
/// </summary>
/// <param name="levelTileset">Scene that will be loaded</param>
/// <param name="levelResource">Execution of level</param>
public void StartLevel(PackedScene levelTileset, AdventureLevelResource levelResource)
{
pathToInitiator = GetTree().CurrentScene.SceneFilePath;
RuntimeLevelData.LevelResource = levelResource;
GetTree().ChangeSceneToPacked(levelTileset);
}
public void RestartLevel()
{
var resource = RuntimeLevelData.LevelResource;
GetTree().ReloadCurrentScene();
RuntimeLevelData.LevelResource = resource;
}
public void EndLevel()
{
RuntimeLevelData.LevelResource = null;
if (Reward != null)
{
GetTree().ChangeSceneToFile(REWARD_SCENE_UID);
}
else
{
ReturnToInitiator();
}
}
public void ReturnToInitiator()
{
if (pathToInitiator == null) return;
GetTree().ChangeSceneToFile(pathToInitiator);
pathToInitiator = null;
}
public void SetReward(RewardResource reward)
{
Reward = reward;
}
}

View file

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

View file

@ -1,198 +0,0 @@
using Godot;
using Newlon.Components.Zombies;
using System.Collections.Generic;
using Newlon.Resources;
using Newlon.Components.Droppables;
namespace Newlon.Components.Level;
[GlobalClass]
public partial class LevelRunner : Node
{
private AdventureLevelResource resource;
private int waveIndex = -1;
private bool hugeWaveApproaching = false;
private bool rewardGiven = false;
public float waveHealth = 0;
public float waveHealthMax = 0;
public int aliveZombies = 0;
public List<RuntimeZombieData> zombies = [];
[Export] private MoneyReward defaultReward;
[Export] private RowSpawner rowSpawner;
[Export] private Timer waveTimer;
[Export] private float approachNotificationTime;
[Export] private AnimationPlayer player;
[Export] private Node rewardParent;
[Export] private AudioStream firstWaveSound;
[Signal] public delegate void ResourceChangedEventHandler(AdventureLevelResource resource);
[Signal] public delegate void WaveChangedEventHandler(int to);
[Signal] public delegate void HugeWaveApproachingCallbackEventHandler();
[Signal] public delegate void HugeWaveInitiatedEventHandler(int waveNumber);
[Signal] public delegate void FinalWaveInitiatedEventHandler();
public override void _Ready()
{
waveTimer.Timeout += SummonWave;
}
public override void _Process(double delta)
{
if (RuntimeLevelData.Instance.GetLevelState() != RuntimeLevelData.LevelStates.Game) return;
if (waveIndex == resource.waves.Count - 1) return;
if (waveTimer.TimeLeft < approachNotificationTime && resource.waves[waveIndex + 1].isHugeWave && hugeWaveApproaching == false)
{
hugeWaveApproaching = true;
EmitSignal(SignalName.HugeWaveApproachingCallback);
}
if (rewardGiven == false && waveIndex == resource.waves.Count && PoolContainer.Instance.Zombies.GetChildCount() == 0)
{
SpawnReward(GetViewport().GetCamera2D().GlobalPosition);
}
}
public void SetLevelResource(AdventureLevelResource data)
{
resource = data;
waveTimer.Stop();
waveTimer.WaitTime = resource.initialWaveDelay;
waveTimer.Start();
EmitSignal(SignalName.ResourceChanged, resource);
}
private void SummonWave()
{
waveIndex += 1;
hugeWaveApproaching = false;
EmitSignal(SignalName.WaveChanged, waveIndex);
if (resource.waves[waveIndex].isHugeWave) EmitSignal(SignalName.HugeWaveInitiated, waveIndex);
rowSpawner.Add(resource.waves[waveIndex].zombiesOrdered);
ClearZombies();
if (waveIndex == resource.waves.Count - 1)
{
EmitSignal(SignalName.FinalWaveInitiated);
return;
}
if (waveIndex == 0)
{
AudioSequencer.Play("fl_wave", firstWaveSound);
}
waveTimer.WaitTime = resource.waves[waveIndex].customWaveDelay > 0 ? resource.waves[waveIndex].customWaveDelay : resource.standardWaveDelay;
waveTimer.Start();
}
private void OnHPChanged(EntitySignalContext context)
{
waveHealth = 0;
foreach (var zombie in zombies)
{
if (zombie != null)
{
waveHealth += zombie.GetHPMixed();
}
}
if (waveIndex == resource.waves.Count - 1) return;
if (waveHealth / waveHealthMax <= resource.wavePercentage)
{
if (resource.waves[waveIndex + 1].isHugeWave && waveTimer.TimeLeft > 6)
{
waveTimer.WaitTime = 6;
waveTimer.Start();
ClearZombies();
}
else
{
waveTimer.Stop();
SummonWave();
}
}
}
public void ClearZombies()
{
foreach (var zom in zombies)
{
if (zom != null)
{
zom.HPChangedMixed -= OnHPChanged;
}
}
waveHealthMax = 0;
waveHealth = waveHealthMax;
zombies.Clear();
}
public void AddZombie(RuntimeZombieData zombie)
{
zombies.Add(zombie);
waveHealthMax += zombie.GetMaxHPMixed();
waveHealth = waveHealthMax;
zombie.HPChangedMixed += OnHPChanged;
if (waveIndex == resource.waves.Count - 1)
{
aliveZombies+=1;
zombie.HasBeenKilled += OnLastZombieKilled;
}
}
private void OnLastZombieKilled(Entity who)
{
aliveZombies -= 1;
if (aliveZombies > 0) return;
SpawnReward(who.GlobalPosition);
}
private void SpawnReward(Vector2 where)
{
rewardGiven = true;
RuntimeLevelData.Instance.SetLevelState(RuntimeLevelData.LevelStates.Win);
DroppableItem reward;
if (resource.reward.Redeem())
{
reward = resource.reward.Scene.Instantiate<DroppableItem>();
LevelController.Instance.SetReward(resource.reward);
}
else
{
defaultReward.Redeem();
reward = defaultReward.Scene.Instantiate<DroppableItem>();
LevelController.Instance.SetReward(defaultReward);
}
if (reward is DroppableSeedpacket seedpacket && resource.reward is PlantReward plantReward)
{
seedpacket.plant = plantReward.Plant;
}
Callable.From(() =>
{
rewardParent.AddChild(reward);
reward.GlobalPosition = where + Vector2.Up * FieldParams.TileHeight * 0.5f;
var dropmover = new DropMover();
reward.AddChild(dropmover);
}).CallDeferred();
reward.PickedUp += () =>
{
player.Play("win");
var tween = CreateTween();
var camera = GetViewport().GetCamera2D();
tween.TweenProperty(reward, "global_position", camera.GlobalPosition, 4.0);
tween.Parallel().TweenProperty(reward, "global_scale", new Vector2(3.0f, 3.0f), 4.0);
tween.TweenInterval(1.0);
tween.TweenCallback(Callable.From(LevelController.Instance.EndLevel));
reward.InputPickable = false;
};
}
}

View file

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

View file

@ -1,19 +0,0 @@
using Godot;
using Newlon.Components;
using Newlon.Components.Level;
[GlobalClass]
public partial class LevelStateBrainDisabler : Node
{
public override void _Ready()
{
RuntimeLevelData.Instance.OnLevelStateChanged += OnLevelStateChanged;
}
public void OnLevelStateChanged(RuntimeLevelData.LevelStates state)
{
if (state == RuntimeLevelData.LevelStates.Game)
{
GetParent<Entity>().EnableBrain();
}
}
}

View file

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

View file

@ -1,33 +0,0 @@
using Godot;
using Newlon.Components.Zombies;
namespace Newlon.Components.Level;
public partial class LoseCheckbox : Area2D
{
[Export] private CanvasLayer gameOverLayer;
[Export] private AnimationPlayer fadeAnimation;
public override void _Ready()
{
AreaEntered += OnAreaEntered;
}
private void OnAreaEntered(Area2D area)
{
var parent = area.GetParent();
if (parent != null && parent is RuntimeZombieData zombieData)
{
if (zombieData.HP <= 0) return;
RuntimeLevelData.Instance.SetLevelState(RuntimeLevelData.LevelStates.Loose);
Engine.TimeScale = 1.0;
fadeAnimation.Play("loose");
GetTree().Paused = true;
PhysicsServer2D.SetActive(true);
Callable.From(()=>
{
zombieData.Reparent(gameOverLayer);
}).CallDeferred();
}
}
}

View file

@ -1 +0,0 @@
uid://812ldoyxd5n5

View file

@ -1,112 +0,0 @@
using Godot;
using Newlon.Components.GUI.Seedpackets;
using Newlon.Components.Plants;
using Newlon.Resources;
namespace Newlon.Components.Level;
public partial class PlantField : Node2D
{
private Node2D _plantSetter;
private GridEntityResource _resource;
private Seedpacket _slot;
private bool _previousCanPlace;
private ChannelPlayer player;
[Export] private PackedScene particles;
public static PlantField Instance { get; private set; }
public override void _Ready()
{
Instance = this;
_plantSetter = GetChild<Node2D>(0);
player = GetNode<ChannelPlayer>("PlantPlayer");
}
public void SetPlant(Seedpacket slot, GridEntityResource resource)
{
_resource = resource;
_slot = slot;
if (resource == null)
{
foreach (var child in _plantSetter.GetChildren())
child.QueueFree();
}
else
{
var scene = resource.Scene.Instantiate<Node2D>();
_plantSetter.AddChild(scene);
scene.UseParentMaterial = true;
}
}
public void ResetPlant()
{
SetPlant(null, null);
}
public override void _Process(double delta)
{
// Getting and storing global mouse position, setting plant-poiner to it
var mouse_pos = Cursor.GetCursorPosition();
_plantSetter.GlobalPosition = mouse_pos;
// Getting position in grid coordinates
var expected_pos = (_plantSetter.GlobalPosition / FieldParams.Tile).Ceil() * FieldParams.Tile - new Vector2(20, 14);
// Checking for boundaries
bool inBoundary = expected_pos.X > FieldParams.LeftFieldBoundary.X && expected_pos.X < FieldParams.RightFieldBoundary.X && expected_pos.Y > FieldParams.LeftFieldBoundary.Y && expected_pos.Y < FieldParams.RightFieldBoundary.Y;
bool canPlace = _resource != null
&& inBoundary
&& PoolContainer.Instance.IsPositionVacant(expected_pos,_resource.Layer)
&& RuntimeLevelData.Instance.CheckSpendSun((int)_resource.Cost);
// Setting visuals
if (_previousCanPlace != canPlace)
{
if (canPlace)
{
Material.Set("shader_parameter/amount", 0);
}
else
{
Material.Set("shader_parameter/amount", 1);
}
Cursor.Instance.plant = canPlace;
}
_previousCanPlace = canPlace;
if (canPlace)
_plantSetter.GlobalPosition = expected_pos;
}
public override void _UnhandledInput(InputEvent @event)
{
if (@event.IsActionPressed("cancel_action") && _slot != null)
{
ResetPlant();
}
if (@event.IsActionPressed("primary_action") && _previousCanPlace)
{
GetViewport().SetInputAsHandled();
var plant = _resource.Scene.Instantiate<RuntimePlantData>();
PoolContainer.Instance.Plants.AddChild(plant);
plant.GlobalPosition = (_plantSetter.GlobalPosition / FieldParams.Tile).Ceil() * FieldParams.Tile - new Vector2(20, 14);
plant.Resource = (PlantResource)_resource;
PoolContainer.Instance.TrySetEntity(plant.GlobalPosition,plant,_resource.Layer);
RuntimeLevelData.Instance.SpendSun((int)_resource.Cost);
PoolContainer.Instance.SpawnParticles(particles, plant.GlobalPosition + Vector2.Down * FieldParams.TileHeight / 2.0f);
player.Play();
// Unfocusing and recharging slot
_slot.Recharge();
ResetPlant();
}
}
}

View file

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

View file

@ -1,74 +0,0 @@
using Godot;
using System.Collections.Generic;
using Newlon.Particles;
namespace Newlon.Components.Level;
//
// PoolContainer contains nodes that contain different elemnts that generate during runtime
// Is not pool in traditional sense, but named like that to prevent repetition
//
public partial class PoolContainer : Node2D
{
[Export]
public Node2D Zombies { get; private set; }
[Export]
public Node2D Plants { get; private set; }
[Export]
public Node2D Projectiles { get; private set; }
[Export]
public Node2D Structures { get; private set; }
[Export]
public Node2D Particles { get; private set; }
public static PoolContainer Instance { get; private set; }
//public Dictionary<Vector2, Entity>[] EntityField = { new(), new(), new() };
private readonly Entity[,] EntityField = new Entity[3,FieldParams.ColumnsCount * FieldParams.RowsCount];
public override void _EnterTree()
{
Instance = this;
}
public bool TryGetEntity<T>(Vector2 positionVector, out T result, int layer = 1) where T : Entity
{
var position = VectorToIndex(positionVector);
result = EntityField[layer, position] as T;
return EntityField[layer,position] != null
&& result != null;
}
public bool TrySetEntity(Vector2 positionVector, Entity whatToSet, int layer = 1)
{
var position = VectorToIndex(positionVector);
if (IsPositionVacant(positionVector, layer) == false) return false;
EntityField[layer, position] = whatToSet;
return true;
}
public bool IsPositionVacant(Vector2 positionVector, int layer = 1)
{
return EntityField[layer, VectorToIndex(positionVector)] == null;
}
public void RemoveEntity(Vector2 positionVector, int layer = 1)
{
EntityField[layer, VectorToIndex(positionVector)] = null;
}
public static int VectorToIndex(Vector2 vector)
{
var intedVec = (vector - FieldParams.LeftFieldBoundary) / FieldParams.Tile;
return (int)intedVec.X + (int)intedVec.Y * FieldParams.ColumnsCount;
}
public void SpawnParticles(PackedScene particles, Vector2 position, float rotation = 0)
{
var emitter = particles.Instantiate<StandardParticles>();
Instance.Particles.AddChild(emitter);
emitter.GlobalPosition = position;
emitter.GlobalRotation = rotation;
}
public void SpawnParticles(PackedScene particles, Transform2D transform)
{
var emitter = particles.Instantiate<StandardParticles>();
Instance.Particles.AddChild(emitter);
emitter.GlobalTransform = transform;
}
}

View file

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

View file

@ -1,12 +0,0 @@
using Godot;
using Newlon;
public partial class RightBoundaryMarker : Marker2D
{
public override void _Ready()
{
FieldParams.RightFieldBoundary = (Vector2I)GlobalPosition;
QueueFree();
}
}

View file

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

View file

@ -1,102 +0,0 @@
using System;
using Godot;
using Newlon.Components.GUI;
namespace Newlon.Components.Level;
public partial class RuntimeLevelData : Node
{
public enum LevelStates
{
ChooseYourSeeds,
Pregame,
Game,
Win,
Loose
}
public int SunCount { get; private set; } = 0;
[Export]
private LevelRunner levelRunner;
[Export]
private AnimationPlayer player;
[Signal]
public delegate void OnLevelStateChangedEventHandler(LevelStates state);
public static RuntimeLevelData Instance { get; private set; }
public static AdventureLevelResource LevelResource { get; set; }
private LevelStates _currentState = LevelStates.ChooseYourSeeds;
public override void _EnterTree()
{
Instance = this;
}
public override void _Ready()
{
Engine.TimeScale = 1.0;
SunCount = LevelResource.startSun;
SunCounter.UpdateInstantly();
SetLevelState(LevelStates.ChooseYourSeeds);
}
#region Sun
public void AddSun(int amount, bool update = true)
{
SunCount += amount;
if (update)
SunCounter.Update();
}
public void SpendSun(int amount, bool update = true)
{
SunCount -= amount;
if (update)
SunCounter.Update();
}
public bool CheckSpendSun(int amount)
{
if (SunCount - amount < 0) return false;
return true;
}
#endregion
public void SetLevelState(LevelStates state)
{
EmitSignal(SignalName.OnLevelStateChanged, (int)state);
_currentState = state;
switch (_currentState)
{
case LevelStates.ChooseYourSeeds:
player.Play("CYS_Sequence");
break;
case LevelStates.Pregame:
player.Play("PG_Sequence");
break;
case LevelStates.Game:
GetTree().Paused = false;
levelRunner.SetLevelResource(LevelResource);
break;
case LevelStates.Win:
break;
case LevelStates.Loose:
break;
}
}
public LevelStates GetLevelState()
{
return _currentState;
}
//private Array<PlantResource> _selectedPlants;
//private bool _selected;
//public Array<PlantResource> GetSelectedPlants();
//public bool TrySelectPlants(Array<PlantResource>);
//public void ResetSelection();
}

View file

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

View file

@ -1,29 +0,0 @@
using Godot;
using Newlon.Projectiles;
namespace Newlon.Components.Level;
public partial class SunSpawner : Node
{
[Export]
public int MinSun = 25;
[Export]
public int MaxSun = 25;
[Export]
private PackedScene SunScene;
public void Spawn()
{
float x = GD.Randf() * 9 * FieldParams.TileWidth;
uint y = GD.Randi() % 5;
var sun = SunScene.Instantiate<Sun>();
PoolContainer.Instance.Projectiles.AddChild(sun);
sun.GlobalPosition = new Vector2(FieldParams.LeftFieldBoundary.X + x, -90);
var moveTween = CreateTween();
moveTween.TweenProperty(sun, "global_position", new Vector2(FieldParams.LeftFieldBoundary.X + x,
FieldParams.LeftFieldBoundary.Y + FieldParams.TileHeight * y + FieldParams.TileHeight / 2.0f), 9 - y);
}
}

View file

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

View file

@ -1,54 +0,0 @@
using Godot;
using System.Collections.Generic;
using Newlon.Components.Zombies;
using Godot.Collections;
using Newlon.Resources;
namespace Newlon.Components.Level;
[GlobalClass]
public partial class RowSpawner : Node2D
{
private Queue<RowSpawn> queue = [];
[Export] private Timer delayTimer;
[Export] private LevelRunner runner;
public override void _Ready()
{
delayTimer.Timeout += FormSquad;
}
private void FormSquad()
{
if (queue.Count == 0) return;
var row = queue.Dequeue();
for (int i = 0; i < row.zombies.Count; i++)
{
if (row.zombies[i] != null)
Spawn(row.zombies[i], i+1);
}
if (queue.Count == 0) delayTimer.Stop();
}
private void Spawn(ZombieResource resource, int lane)
{
RuntimeZombieData zombie = resource.Scene.Instantiate<RuntimeZombieData>();
PoolContainer.Instance.Zombies.AddChild(zombie);
zombie.GlobalPosition = new Vector2(GlobalPosition.X, FieldParams.LeftFieldBoundary.Y + lane * FieldParams.TileHeight);
runner.AddZombie(zombie);
}
public void Add(Array<RowSpawn> rowSpawns)
{
foreach (var spawn in rowSpawns)
{
queue.Enqueue(spawn);
}
delayTimer.Start();
}
}

View file

@ -1 +0,0 @@
uid://84gvlkflxdhk

View file

@ -1,172 +0,0 @@
using System.Collections.Generic;
using Godot;
using Godot.Collections;
using Newlon;
using Newlon.Resources;
public partial class SurvivalZombieSpawner : Node
{
// Zombie pools
// Points from pools go in that order: support -> tank -> horde -> bank
// Horde pool is allowed to shrink during runtime
[Export] private Array<string> supportPool;
[Export] private Array<string> tankPool;
[Export] private Array<string> hordePool;
private List<ZombieResource> cachedSupportPool;
private List<ZombieResource> cachedTankPool;
private List<ZombieResource> cachedHordePool;
private float minSupportPoints;
private float minTankPoints;
private float minHordePoints;
[Export] private float points = 0;
[Export] private float huge_wave_points;
[Export] private Curve velocity_curve;
private float velocity = 0;
[Export] private double time = 0.0;
private float fin_a;
private RandomNumberGenerator rng = new();
public override void _Ready()
{
rng.Randomize();
cachedSupportPool = LoadFromRegistry(supportPool);
cachedTankPool = LoadFromRegistry(tankPool);
cachedHordePool = LoadFromRegistry(hordePool);
cachedTankPool.Sort((x, y) =>
{
return (int)(x.Cost - y.Cost);
});
cachedHordePool.Sort((x, y) =>
{
return (int)(x.Cost - y.Cost);
});
minSupportPoints = cachedSupportPool[0].Cost;
minTankPoints = cachedTankPool[0].Cost;
minHordePoints = cachedHordePool[0].Cost;
fin_a = (velocity_curve.Sample(velocity_curve.MaxDomain) - velocity_curve.Sample(velocity_curve.MaxDomain - 0.001f)) / 0.001f;
}
public override void _Process(double delta)
{
points += velocity * (float)delta;
if (time > velocity_curve.MaxDomain)
{
velocity += fin_a * (float)delta;
}
else
{
velocity = velocity_curve.Sample((float)time);
}
time += delta;
}
public void SummonWave()
{
bool big_wave = false;
if ((int)time % 300 == 0)
{
points += velocity/velocity_curve.Sample((float)time)*huge_wave_points;
big_wave = true;
}
float support_points = points * 0.2f;
float tank_points = points * 0.5f;
float horde_points = points * 0.3f;
points = 0;
List<ZombieResource> wave = [];
var remaining = SummonTank(tank_points, wave);
support_points += remaining * 0.8f;
horde_points += remaining * 0.2f;
horde_points += SummonSupport(support_points, wave);
points += SummonHorde(horde_points, wave, big_wave);
wave.Sort((x, y) => { return rng.RandiRange(-1, 1); });
foreach (var zom in wave)
{
ZombieSequencer.Instance.Add(zom.GetInternalID());
}
big_wave = false;
}
private float SummonSupport(float given_points, List<ZombieResource> wave)
{
if (cachedSupportPool.Count == 0)
{
return given_points;
}
while (given_points >= minSupportPoints)
{
var chosen_zombie = cachedSupportPool[rng.RandiRange(0, cachedSupportPool.Count - 1)];
if (given_points - chosen_zombie.Cost >= 0)
{
wave.Add(chosen_zombie);
given_points -= chosen_zombie.Cost;
}
}
return given_points;
}
private float SummonTank(float given_points, List<ZombieResource> wave)
{
if (cachedTankPool.Count == 0)
{
return given_points;
}
int zombieIndex = cachedTankPool.Count - 1;
while (given_points >= minSupportPoints && zombieIndex > -1)
{
if (cachedTankPool[zombieIndex].Cost > given_points)
{
zombieIndex--;
continue;
}
var chosen_zombie = cachedTankPool[zombieIndex];
wave.Add(chosen_zombie);
given_points -= chosen_zombie.Cost;
}
return given_points;
}
private float SummonHorde(float given_points, List<ZombieResource> wave, bool is_big)
{
if (cachedHordePool.Count == 0)
{
return given_points;
}
while (is_big == false && cachedHordePool.Count > 1 && cachedHordePool[1].Cost * 15 <= given_points)
{
cachedHordePool.RemoveAt(0);
minHordePoints = cachedHordePool[0].Cost;
}
while (given_points >= minHordePoints)
{
var chosen_zombie = cachedHordePool[rng.RandiRange(0, cachedHordePool.Count - 1)];
if (given_points - chosen_zombie.Cost >= 0)
{
wave.Add(chosen_zombie);
given_points -= chosen_zombie.Cost;
}
}
return given_points;
}
private List<ZombieResource> LoadFromRegistry(Array<string> pool)
{
List<ZombieResource> list = [];
foreach (var res in pool)
{
list.Add(GameRegistry.GetEntityByName(res) as ZombieResource);
}
return list;
}
}

View file

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

View file

@ -1,90 +0,0 @@
using System.Collections.Generic;
using Godot;
using Newlon;
using Newlon.Components.Level;
using Newlon.Components.Zombies;
public partial class ZombieSequencer : Node2D
{
public static ZombieSequencer Instance { get; private set; }
private Queue<string> queue = [];
private RandomNumberGenerator rng = new();
private bool turbo = false;
[Export] private Timer spawnTimer;
[Export] private Timer waveTimer;
private double startSpawnTime;
public override void _Ready()
{
rng.Randomize();
Instance = this;
startSpawnTime = spawnTimer.WaitTime;
}
private void FormSquad()
{
if (queue.Count == 0) return;
int count = rng.RandiRange(1, queue.Count > 5 ? 5 : queue.Count);
if (count == 5)
{
Spawn(queue.Dequeue(), 1);
Spawn(queue.Dequeue(), 2);
Spawn(queue.Dequeue(), 3);
Spawn(queue.Dequeue(), 4);
Spawn(queue.Dequeue(), 5);
}
List<int> list = [];
while (list.Count < count)
{
int lane = rng.RandiRange(1, 5);
if (list.Contains(lane) == true)
{
continue;
}
list.Add(lane);
}
foreach (int lane in list)
{
if (queue.Count > 0)
Spawn(queue.Dequeue(), lane);
}
}
private void Spawn(string id, int lane)
{
RuntimeZombieData zombie = GameRegistry.GetEntityByName(id).Scene.Instantiate<RuntimeZombieData>();
PoolContainer.Instance.Zombies.AddChild(zombie);
zombie.GlobalPosition = new Vector2(GlobalPosition.X, FieldParams.RightFieldBoundary.Y - (lane - 1) * FieldParams.TileHeight);
}
public void Add(string id)
{
queue.Enqueue(id);
}
public override void _Process(double delta)
{
if (turbo == false && queue.Count > waveTimer.WaitTime / startSpawnTime * 5.0)
{
spawnTimer.WaitTime = waveTimer.WaitTime / queue.Count;
turbo = true;
}
else if(turbo && queue.Count == 0)
{
spawnTimer.WaitTime = startSpawnTime;
turbo = false;
}
}
public void DebugClearQueue()
{
queue.Clear();
}
}

View file

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