2024-10-04 12:53:34 +00:00
using System.Collections.Generic ;
2024-04-28 13:55:19 +00:00
using ColdMint.scripts.debug ;
2024-10-04 02:21:09 +00:00
using ColdMint.scripts.inventory ;
2024-10-04 12:53:34 +00:00
using ColdMint.scripts.map.events ;
using ColdMint.scripts.projectile ;
2024-10-05 01:13:14 +00:00
using ColdMint.scripts.utils ;
2024-04-28 13:55:19 +00:00
using Godot ;
2024-06-22 11:21:06 +00:00
namespace ColdMint.scripts.weapon ;
2024-04-28 13:55:19 +00:00
2024-06-05 13:38:45 +00:00
/// <summary>
/// <para>Projectile weapons</para>
/// <para>抛射体武器</para>
/// </summary>
/// <remarks>
///<para>These weapons can fire projectiles to attack the enemy.For example: guns and scepters.Generate a bullet to attack the enemy.</para>
///<para>这类武器可发射抛射体,攻击敌人。例如:枪支和法杖。生成一个子弹攻击敌人。</para>
/// </remarks>
2024-04-28 13:55:19 +00:00
public partial class ProjectileWeapon : WeaponTemplate
{
2024-06-05 13:38:45 +00:00
/// <summary>
/// <para>The formation position of the projectile</para>
/// <para>抛射体的生成位置</para>
/// </summary>
2024-05-08 10:22:04 +00:00
private Marker2D ? _marker2D ;
2024-10-04 12:53:34 +00:00
2024-08-11 15:29:23 +00:00
/// <summary>
2024-10-04 02:21:09 +00:00
/// <para>Number of slots for ranged weapons</para>
/// <para>远程武器的槽位数量</para>
2024-08-11 15:29:23 +00:00
/// </summary>
2024-10-05 01:13:14 +00:00
[Export]
private int _numberSlots ;
2024-08-11 15:29:23 +00:00
2024-10-05 01:13:14 +00:00
/// <summary>
/// <para>How many projectiles are generated per fire</para>
/// <para>每次开火生成多少个抛射体</para>
/// </summary>
public int NumberOfProjectiles { get ; set ; } = 1 ;
private readonly List < ISpell > _spells = new ( ) ;
/// <summary>
/// <para>Saves the position of a spell with projectile generation</para>
/// <para>保存具有抛射体生成能力的法术位置</para>
/// </summary>
private readonly List < int > _spellProjectileIndexes = new ( ) ;
/// <summary>
/// <para>Whether to fire spells in sequence</para>
/// <para>是否按顺序发射法术</para>
/// </summary>
[Export]
private bool _fireSequentially ;
/// <summary>
/// <para>The index used the last time a spell was cast</para>
/// <para>上次发射法术时采用的索引</para>
/// </summary>
private int _lastUsedProjectileMagicIndex ;
/// <summary>
/// <para>Get next index</para>
/// <para>获取下次索引</para>
/// </summary>
/// <returns></returns>
private int GetNextProjectileMagicIndex ( )
{
if ( _fireSequentially )
{
_lastUsedProjectileMagicIndex + + ;
if ( _lastUsedProjectileMagicIndex > = _spellProjectileIndexes . Count )
{
return 0 ;
}
return _lastUsedProjectileMagicIndex ;
}
else
{
return RandomUtils . Instance . Next ( 0 , _spellProjectileIndexes . Count ) ;
}
}
/// <summary>
/// <para>Gets the loading range of the spell</para>
/// <para>获取法术的加载范围</para>
/// </summary>
/// <returns></returns>
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
] ;
}
}
2024-10-04 12:53:34 +00:00
2024-10-04 02:21:09 +00:00
public override int ItemType
{
get = > Config . ItemType . ProjectileWeapon ;
}
2024-10-04 12:53:34 +00:00
2024-05-08 10:22:04 +00:00
public override void _Ready ( )
{
base . _Ready ( ) ;
_marker2D = GetNode < Marker2D > ( "Marker2D" ) ;
2024-10-05 02:20:55 +00:00
if ( SelfItemContainer = = null )
{
SelfItemContainer = new UniversalItemContainer ( _numberSlots ) ;
SelfItemContainer . AllowAddingItemByType ( Config . ItemType . Spell ) ;
}
2024-10-04 12:53:34 +00:00
}
2024-10-05 02:20:55 +00:00
/// <summary>
/// <para>Update spell cache</para>
/// <para>更新法术缓存</para>
/// </summary>
/// <remarks>
///<para>This will parse available spells from inside the item container.</para>
///<para>这将从物品容器内解析可用的法术。</para>
/// </remarks>
public void UpdateSpellCache ( )
2024-10-04 12:53:34 +00:00
{
if ( SelfItemContainer = = null )
{
return ;
}
2024-10-05 01:13:14 +00:00
_spells . Clear ( ) ;
_spellProjectileIndexes . Clear ( ) ;
2024-10-04 12:53:34 +00:00
var totalCapacity = SelfItemContainer . GetTotalCapacity ( ) ;
for ( var i = 0 ; i < totalCapacity ; i + + )
{
var item = SelfItemContainer . GetItem ( i ) ;
if ( item = = null )
{
continue ;
}
2024-10-05 01:13:14 +00:00
if ( item is not ISpell spell )
2024-10-04 12:53:34 +00:00
{
continue ;
}
2024-10-05 01:13:14 +00:00
_spells . Add ( spell ) ;
var packedScene = spell . GetProjectile ( ) ;
if ( packedScene ! = null )
{
//Has the ability to generate projectiles.
//拥有抛射体生成能力。
2024-10-05 01:52:53 +00:00
_spellProjectileIndexes . Add ( _spells . Count - 1 ) ;
2024-10-05 01:13:14 +00:00
}
}
}
2024-10-05 02:20:55 +00:00
private void OnItemDataChangeEvent ( ItemDataChangeEvent itemDataChangeEvent )
{
UpdateSpellCache ( ) ;
}
2024-10-05 01:13:14 +00:00
public override void _EnterTree ( )
{
base . _EnterTree ( ) ;
if ( SelfItemContainer ! = null )
{
SelfItemContainer . ItemDataChangeEvent + = OnItemDataChangeEvent ;
2024-10-04 12:53:34 +00:00
}
}
public override void _ExitTree ( )
{
base . _ExitTree ( ) ;
if ( SelfItemContainer ! = null )
{
SelfItemContainer . ItemDataChangeEvent - = OnItemDataChangeEvent ;
}
2024-05-08 10:22:04 +00:00
}
2024-10-05 02:53:07 +00:00
protected override bool DoFire ( Node2D ? owner , Vector2 enemyGlobalPosition )
2024-05-08 10:22:04 +00:00
{
2024-07-24 13:03:24 +00:00
if ( owner = = null )
{
LogCat . LogError ( "owner_is_null" ) ;
2024-10-05 02:53:07 +00:00
return false ;
2024-07-24 13:03:24 +00:00
}
if ( _marker2D = = null )
{
LogCat . LogError ( "marker2d_is_null" ) ;
2024-10-05 02:53:07 +00:00
return false ;
2024-07-24 13:03:24 +00:00
}
2024-06-10 13:05:18 +00:00
2024-09-01 15:24:35 +00:00
if ( GameSceneDepend . ProjectileContainer = = null )
2024-07-24 13:03:24 +00:00
{
LogCat . LogError ( "projectile_container_is_null" ) ;
2024-10-05 02:53:07 +00:00
return false ;
2024-07-24 13:03:24 +00:00
}
2024-10-05 01:13:14 +00:00
if ( _spellProjectileIndexes . Count = = 0 )
{
LogCat . LogError ( "projectile_generate_magic_is_null" ) ;
2024-10-05 02:53:07 +00:00
return false ;
2024-10-05 01:13:14 +00:00
}
var spellScope = GetSpellScope ( ) ;
//The final spell is a projectile generator.
//最后的法术是拥有抛射体生成能力的。
var spellProjectile = _spells [ spellScope [ 1 ] ] ;
var packedScene = spellProjectile . GetProjectile ( ) ;
if ( packedScene = = null )
2024-10-04 12:53:34 +00:00
{
2024-10-05 02:53:07 +00:00
LogCat . LogError ( "projectile_scene_is_null" ) ;
return false ;
2024-10-04 12:53:34 +00:00
}
2024-10-05 08:19:31 +00:00
ModifyWeapon ( spellScope ) ;
2024-10-05 01:13:14 +00:00
for ( var i = 0 ; i < NumberOfProjectiles ; i + + )
{
var projectile = NodeUtils . InstantiatePackedScene < Projectile > ( packedScene ) ;
2024-10-05 02:53:07 +00:00
if ( projectile = = null )
{
LogCat . LogError ( "projectile_is_null" ) ;
2024-10-05 08:19:31 +00:00
RestoreWeapon ( spellScope ) ;
2024-10-05 02:53:07 +00:00
return false ;
}
2024-10-05 08:19:31 +00:00
var velocity = _marker2D . GlobalPosition . DirectionTo ( enemyGlobalPosition ) * projectile . Speed ;
2024-10-05 01:13:14 +00:00
for ( var s = spellScope [ 0 ] ; s < = spellScope [ 1 ] ; s + + )
{
var spell = _spells [ s ] ;
2024-10-05 08:19:31 +00:00
spell . ModifyProjectile ( i , projectile , ref velocity ) ;
2024-10-05 01:13:14 +00:00
}
NodeUtils . CallDeferredAddChild ( GameSceneDepend . ProjectileContainer , projectile ) ;
projectile . Owner = owner ;
projectile . TargetNode = GameSceneDepend . TemporaryTargetNode ;
2024-10-05 08:19:31 +00:00
projectile . Velocity = velocity ;
2024-10-05 01:13:14 +00:00
projectile . Position = _marker2D . GlobalPosition ;
}
2024-10-05 08:19:31 +00:00
RestoreWeapon ( spellScope ) ;
return true ;
}
/// <summary>
/// <para>Modify weapon attributes</para>
/// <para>修改武器属性</para>
/// </summary>
/// <param name="spellScope"></param>
private void ModifyWeapon ( int [ ] spellScope )
{
for ( var i = spellScope [ 0 ] ; i < = spellScope [ 1 ] ; i + + )
{
var spell = _spells [ i ] ;
spell . ModifyWeapon ( this ) ;
}
}
/// <summary>
/// <para>Restores modifications to weapons</para>
/// <para>恢复对武器的修改</para>
/// </summary>
/// <param name="spellScope"></param>
private void RestoreWeapon ( int [ ] spellScope )
{
2024-10-05 01:13:14 +00:00
for ( var i = spellScope [ 0 ] ; i < = spellScope [ 1 ] ; i + + )
{
var spell = _spells [ i ] ;
spell . RestoreWeapon ( this ) ;
}
2024-05-08 10:22:04 +00:00
}
}