using System.Collections.Generic;
using ColdMint.scripts.debug;
using ColdMint.scripts.inventory;
using ColdMint.scripts.map.events;
using ColdMint.scripts.projectile;
using ColdMint.scripts.utils;
using Godot;
namespace ColdMint.scripts.weapon;
///
/// Projectile weapons
/// 抛射体武器
///
///
///These weapons can fire projectiles to attack the enemy.For example: guns and scepters.Generate a bullet to attack the enemy.
///这类武器可发射抛射体,攻击敌人。例如:枪支和法杖。生成一个子弹攻击敌人。
///
public partial class ProjectileWeapon : WeaponTemplate
{
///
/// The formation position of the projectile
/// 抛射体的生成位置
///
private Marker2D? _marker2D;
///
/// Number of slots for ranged weapons
/// 远程武器的槽位数量
///
[Export]
private int _numberSlots;
///
/// How many projectiles are generated per fire
/// 每次开火生成多少个抛射体
///
public int NumberOfProjectiles { get; set; } = 1;
private readonly List _spells = new();
///
/// Saves the position of a spell with projectile generation
/// 保存具有抛射体生成能力的法术位置
///
private readonly List _spellProjectileIndexes = new();
///
/// Whether to fire spells in sequence
/// 是否按顺序发射法术
///
[Export]
private bool _fireSequentially;
///
/// The index used the last time a spell was cast
/// 上次发射法术时采用的索引
///
private int _lastUsedProjectileMagicIndex;
///
/// Get next index
/// 获取下次索引
///
///
private int GetNextProjectileMagicIndex()
{
if (_fireSequentially)
{
_lastUsedProjectileMagicIndex++;
if (_lastUsedProjectileMagicIndex >= _spellProjectileIndexes.Count)
{
return 0;
}
return _lastUsedProjectileMagicIndex;
}
else
{
return RandomUtils.Instance.Next(0, _spellProjectileIndexes.Count);
}
}
///
/// Gets the loading range of the spell
/// 获取法术的加载范围
///
///
private int[] GetSpellScope()
{
var index = GetNextProjectileMagicIndex();
var endIndex = _spellProjectileIndexes[index];
if (index > 0)
{
//And the previous index can set the starting position.(The starting position is increased by 1 to avoid using spells with projectile generation as starting points.)
//还有前面的索引可设定起始位置。(这里起始位置加1是为了避免 具有抛射体生成能力的法术 作为起点。)
var startIndex = _spellProjectileIndexes[index - 1] + 1;
return [startIndex, endIndex];
}
else
{
return
[
0, endIndex
];
}
}
public override int ItemType
{
get => Config.ItemType.ProjectileWeapon;
}
public override void _Ready()
{
base._Ready();
_marker2D = GetNode("Marker2D");
if (SelfItemContainer == null)
{
SelfItemContainer = new UniversalItemContainer(_numberSlots);
SelfItemContainer.AllowAddingItemByType(Config.ItemType.Spell);
}
}
///
/// Update spell cache
/// 更新法术缓存
///
///
///This will parse available spells from inside the item container.
///这将从物品容器内解析可用的法术。
///
public void UpdateSpellCache()
{
if (SelfItemContainer == null)
{
return;
}
_spells.Clear();
_spellProjectileIndexes.Clear();
var totalCapacity = SelfItemContainer.GetTotalCapacity();
for (var i = 0; i < totalCapacity; i++)
{
var item = SelfItemContainer.GetItem(i);
if (item == null)
{
continue;
}
if (item is not ISpell spell)
{
continue;
}
_spells.Add(spell);
var packedScene = spell.GetProjectile();
if (packedScene != null)
{
//Has the ability to generate projectiles.
//拥有抛射体生成能力。
_spellProjectileIndexes.Add(_spells.Count - 1);
}
}
}
private void OnItemDataChangeEvent(ItemDataChangeEvent itemDataChangeEvent)
{
UpdateSpellCache();
}
public override void _EnterTree()
{
base._EnterTree();
if (SelfItemContainer != null)
{
SelfItemContainer.ItemDataChangeEvent += OnItemDataChangeEvent;
}
}
public override void _ExitTree()
{
base._ExitTree();
if (SelfItemContainer != null)
{
SelfItemContainer.ItemDataChangeEvent -= OnItemDataChangeEvent;
}
}
protected override bool DoFire(Node2D? owner, Vector2 enemyGlobalPosition)
{
if (owner == null)
{
LogCat.LogError("owner_is_null");
return false;
}
if (_marker2D == null)
{
LogCat.LogError("marker2d_is_null");
return false;
}
if (GameSceneDepend.ProjectileContainer == null)
{
LogCat.LogError("projectile_container_is_null");
return false;
}
if (_spellProjectileIndexes.Count == 0)
{
LogCat.LogError("projectile_generate_magic_is_null");
return false;
}
var spellScope = GetSpellScope();
//The final spell is a projectile generator.
//最后的法术是拥有抛射体生成能力的。
var spellProjectile = _spells[spellScope[1]];
var packedScene = spellProjectile.GetProjectile();
if (packedScene == null)
{
LogCat.LogError("projectile_scene_is_null");
return false;
}
for (var i = spellScope[0]; i <= spellScope[1]; i++)
{
var spell = _spells[i];
spell.ModifyWeapon(this);
}
for (var i = 0; i < NumberOfProjectiles; i++)
{
var projectile = NodeUtils.InstantiatePackedScene(packedScene);
if (projectile == null)
{
LogCat.LogError("projectile_is_null");
return false;
}
for (var s = spellScope[0]; s <= spellScope[1]; s++)
{
var spell = _spells[s];
spell.ModifyProjectile(projectile);
}
NodeUtils.CallDeferredAddChild(GameSceneDepend.ProjectileContainer, projectile);
projectile.Owner = owner;
projectile.TargetNode = GameSceneDepend.TemporaryTargetNode;
projectile.Velocity =
_marker2D.GlobalPosition.DirectionTo(enemyGlobalPosition) * projectile.Speed;
projectile.Position = _marker2D.GlobalPosition;
}
for (var i = spellScope[0]; i <= spellScope[1]; i++)
{
var spell = _spells[i];
spell.RestoreWeapon(this);
}
return true;
}
}