2024-04-28 13:55:19 +00:00
using System ;
using ColdMint.scripts.camp ;
using ColdMint.scripts.character ;
using ColdMint.scripts.damage ;
using ColdMint.scripts.inventory ;
using Godot ;
namespace ColdMint.scripts.weapon ;
/// <summary>
/// <para>WeaponTemplate</para>
/// <para>武器模板</para>
/// </summary>
2024-04-29 15:25:03 +00:00
public partial class WeaponTemplate : RigidBody2D , IItem
2024-04-28 13:55:19 +00:00
{
2024-06-05 13:38:45 +00:00
private float _gravity = ProjectSettings . GetSetting ( "physics/2d/default_gravity" ) . AsSingle ( ) ;
2024-04-28 13:55:19 +00:00
2024-05-08 10:22:04 +00:00
public string? Id { get ; set ; }
2024-04-29 15:25:03 +00:00
public int Quantity { get ; set ; }
public int MaxStackQuantity { get ; set ; }
2024-05-08 10:22:04 +00:00
public Texture2D ? Icon { get ; set ; }
public new string? Name { get ; set ; }
public string? Description { get ; set ; }
public Action < IItem > ? OnUse { get ; set ; }
public Func < IItem , Node > ? OnInstantiation { get ; set ; }
2024-04-28 13:55:19 +00:00
/// <summary>
/// <para>Owner</para>
/// <para>主人</para>
/// </summary>
2024-05-08 10:22:04 +00:00
public new Node2D ? Owner { get ; set ; }
2024-04-28 13:55:19 +00:00
/// <summary>
/// <para>Enabled contact injury</para>
/// <para>启用接触伤害</para>
/// </summary>
public bool EnableContactInjury ;
private int _minContactInjury ;
private int _maxContactInjury ;
private DateTime ? _lastFiringTime ;
2024-06-05 13:38:45 +00:00
/// <summary>
/// <para>Firing interval</para>
/// <para>开火间隔</para>
/// </summary>
2024-04-28 13:55:19 +00:00
private TimeSpan _firingInterval ;
2024-04-29 15:25:03 +00:00
2024-04-28 13:55:19 +00:00
/// <summary>
/// <para>The recoil of the weapon</para>
/// <para>武器的后坐力</para>
/// </summary>
/// <remarks>
///<para>When the weapon is fired, how much recoil is applied to the user, in units: the number of cells, and the X direction of the force is automatically inferred.</para>
///<para>武器开火, 要对使用者施加多大的后坐力, 单位: 格数, 力的X方向是自动推断的。</para>
/// </remarks>
private Vector2 _recoil ;
2024-06-05 13:38:45 +00:00
/// <summary>
/// <para>This area represents the collision range of the weapon, and when other nodes enter this area, they will deal damage.</para>
/// <para>这个区域表示武器的碰撞范围,当其他节点进入此区域时,会造成伤害。</para>
/// </summary>
2024-05-07 11:36:06 +00:00
private Area2D ? _area2D ;
2024-04-28 13:55:19 +00:00
2024-05-08 10:22:04 +00:00
protected RayCast2D ? RayCast2D ;
2024-04-28 13:55:19 +00:00
public override void _Ready ( )
{
2024-05-08 10:22:04 +00:00
RayCast2D = GetNode < RayCast2D > ( "RayCast2D" ) ;
2024-04-28 13:55:19 +00:00
_area2D = GetNode < Area2D > ( "Area2D" ) ;
_area2D . BodyEntered + = OnBodyEnter ;
2024-04-29 15:25:03 +00:00
Id = GetMeta ( "ID" , "1" ) . AsString ( ) ;
Quantity = GetMeta ( "Quantity" , "1" ) . AsInt32 ( ) ;
MaxStackQuantity = GetMeta ( "MaxStackQuantity" , Config . MaxStackQuantity ) . AsInt32 ( ) ;
Icon = GetMeta ( "Icon" , "" ) . As < Texture2D > ( ) ;
Name = GetMeta ( "Name" , "" ) . AsString ( ) ;
2024-05-08 10:22:04 +00:00
Description = GetMeta ( "Description" , "" ) . AsString ( ) ;
2024-04-28 13:55:19 +00:00
_firingInterval = TimeSpan . FromMilliseconds ( GetMeta ( "FiringInterval" , "100" ) . AsInt64 ( ) ) ;
_minContactInjury = GetMeta ( "MinContactInjury" , "1" ) . AsInt32 ( ) ;
_maxContactInjury = GetMeta ( "MaxContactInjury" , "2" ) . AsInt32 ( ) ;
_recoil = GetMeta ( "Recoil" , Vector2 . Zero ) . AsVector2 ( ) ;
}
/// <summary>
/// <para>Use weapons against the enemy</para>
/// <para>使用武器砸敌人</para>
/// </summary>
/// <param name="node"></param>
private void OnBodyEnter ( Node node )
{
if ( ! EnableContactInjury )
{
return ;
}
if ( Owner = = null )
{
return ;
}
if ( Owner is not CharacterTemplate ownerCharacterTemplate )
{
return ;
}
if ( node is not CharacterTemplate characterTemplate )
{
return ;
}
//Determine if your side can cause damage
//判断所属的阵营是否可以造成伤害
var canCauseHarm = CampManager . CanCauseHarm ( CampManager . GetCamp ( ownerCharacterTemplate . CampId ) ,
CampManager . GetCamp ( characterTemplate . CampId ) ) ;
if ( ! canCauseHarm )
{
return ;
}
//If allowed to cause harm
//如果允许造成伤害
var damage = new Damage
{
MaxDamage = Math . Abs ( _maxContactInjury ) ,
2024-05-30 14:49:54 +00:00
MinDamage = Math . Abs ( _minContactInjury ) ,
Attacker = ownerCharacterTemplate
2024-04-28 13:55:19 +00:00
} ;
damage . CreateDamage ( ) ;
damage . MoveLeft = LinearVelocity . X < 0 ;
damage . Type = Config . DamageType . Physical ;
characterTemplate . Damage ( damage ) ;
2024-06-05 13:38:45 +00:00
//Can only cause one collision damage.
//仅能造成一次碰撞伤害。
EnableContactInjury = false ;
2024-04-28 13:55:19 +00:00
}
/// <summary>
/// <para>翻转武器</para>
/// </summary>
2024-05-07 11:36:06 +00:00
/// <param name="facingLeft"></param>
public void Flip ( bool facingLeft )
2024-04-28 13:55:19 +00:00
{
}
public override void _PhysicsProcess ( double delta )
{
base . _PhysicsProcess ( delta ) ;
2024-05-08 10:22:04 +00:00
if ( RayCast2D ! = null )
2024-04-28 13:55:19 +00:00
{
2024-05-08 10:22:04 +00:00
if ( RayCast2D . IsColliding ( ) )
{
//If the weapon hits the ground, we disable physical damage.
//如果武器落到地面了,我们禁用物理伤害。
EnableContactInjury = false ;
//Items can be pushed by the player when they are on the ground
//当物品在地面上时,可被玩家推动
SetCollisionMaskValue ( Config . LayerNumber . Player , true ) ;
}
else
{
SetCollisionMaskValue ( Config . LayerNumber . Player , false ) ;
}
2024-04-28 13:55:19 +00:00
}
}
/// <summary>
/// <para>Discharge of the weapon</para>
/// <para>武器开火</para>
/// </summary>
/// <remarks>
///<param name="owner">
///<para>owner</para>
///<para>武器所有者</para>
/// </param>
/// <param name="enemyGlobalPosition">
///<para>enemyGlobalPosition</para>
///<para>敌人所在位置</para>
/// </param>
/// </remarks>
2024-05-08 10:22:04 +00:00
public void Fire ( Node2D ? owner , Vector2 enemyGlobalPosition )
2024-04-28 13:55:19 +00:00
{
var nowTime = DateTime . Now ;
2024-06-04 14:23:06 +00:00
//If the present time minus the time of the last fire is less than the interval between fires, it means that the fire cannot be fired yet.
//如果现在时间减去上次开火时间小于开火间隔,说明还不能开火。
if ( _lastFiringTime ! = null & & nowTime - _lastFiringTime < _firingInterval )
2024-04-28 13:55:19 +00:00
{
2024-06-04 14:23:06 +00:00
return ;
}
if ( owner is CharacterTemplate characterTemplate )
{
//We check the recoil of the weapon before each firing.
//我们在每次开火之前,检查武器的后坐力。
if ( _recoil ! = Vector2 . Zero )
2024-04-28 13:55:19 +00:00
{
2024-06-04 14:23:06 +00:00
var force = new Vector2 ( ) ;
var forceX = Math . Abs ( _recoil . X ) ;
if ( Math . Abs ( RotationDegrees ) < 90 )
2024-04-28 13:55:19 +00:00
{
2024-06-04 14:23:06 +00:00
//The weapon goes to the right and we apply a recoil to the left
//武器朝向右边我们向左施加后坐力
forceX = - forceX ;
2024-04-28 13:55:19 +00:00
}
2024-06-04 14:23:06 +00:00
force . X = forceX * Config . CellSize ;
force . Y = _recoil . Y * Config . CellSize ;
characterTemplate . AddForce ( force ) ;
}
2024-04-28 13:55:19 +00:00
}
2024-06-04 14:23:06 +00:00
DoFire ( owner , enemyGlobalPosition ) ;
_lastFiringTime = nowTime ;
2024-04-28 13:55:19 +00:00
}
/// <summary>
/// <para>Execute fire</para>
/// <para>执行开火</para>
/// </summary>
2024-05-08 10:22:04 +00:00
protected virtual void DoFire ( Node2D ? owner , Vector2 enemyGlobalPosition )
2024-04-28 13:55:19 +00:00
{
}
}