using System;
using System.Collections.Generic;
using ColdMint.scripts.camp;
using ColdMint.scripts.character;
using ColdMint.scripts.damage;
using ColdMint.scripts.pickable;
using ColdMint.scripts.projectile.decorator;
using Godot;
namespace ColdMint.scripts.projectile;
///
/// Projectile
/// 抛射体
///
public partial class Projectile : CharacterBody2D
{
///
/// life(ms)
/// 子弹的存在时间(毫秒)
///
[Export] public long Life;
//The durability of the projectile
//抛射体的耐久度
//When the projectile hits the object, the durability will be reduced, and when the durability is less than or equal to 0, the projectile will be destroyed
//当抛射体撞击到物体时,会减少耐久度,当耐久度小于等于0时,销毁抛射体
[Export] public double Durability;
[Export] public int MaxDamage;
[Export] public int MinDamage;
[Export] public int DamageType;
///
/// After this time destroy the projectile
/// 超过此时刻销毁抛射体
///
private DateTime? _destructionTime;
///
/// knockback
/// 击退
///
///
///How much force does it have when hitting the character? Unit: Number of cells,The X direction of the force is inferred automatically.
///当击中角色时带有多大的力?单位:格数,力的X方向是自动推断的。
///
[Export] public Vector2 KnockbackForce;
[Export] public float Speed;
///
/// Whether it bounces back after hitting an enemy or a wall
/// 是否撞到敌人或墙壁后反弹
///
[Export] public bool EnableBounce;
///
/// Can it penetrate the wall
/// 是否可以穿透墙壁
///
[Export] public bool IgnoreWall;
private List? _projectileDecorators;
///
/// The master of the weapon
/// 武器的主人
///
public new Node2D? Owner { get; set; }
public override void _Ready()
{
//If the existence time is less than or equal to 0, then it is set to exist for 10 seconds, and projectiles that exist indefinitely are prohibited
//如果存在时间小于等于0,那么设置为存在10秒,禁止无限期存在的抛射体
if (Life <= 0)
{
Life = 10000;
}
_destructionTime = DateTime.Now.AddMilliseconds(Life);
SetCollisionMaskValue(Config.LayerNumber.Wall, !IgnoreWall);
SetCollisionMaskValue(Config.LayerNumber.Floor, !IgnoreWall);
//Platform collision layer is not allowed to collide
//平台碰撞层不可碰撞
SetCollisionMaskValue(Config.LayerNumber.Platform, false);
}
///
/// Add decorator
/// 添加装饰器
///
///
///decorator
///装饰器
///
public void AddProjectileDecorator(IProjectileDecorator decorator)
{
_projectileDecorators ??= [];
_projectileDecorators.Add(decorator);
}
///
/// Remove decorator
/// 移除装饰器
///
///
///decorator
///装饰器
///
///
public bool RemoveProjectileDecorator(IProjectileDecorator decorator)
{
return _projectileDecorators?.Remove(decorator) ?? false;
}
///
/// Detect whether harm is allowed
/// 检测是否允许造成伤害
///
///
///
///
private bool CanCauseHarm(Node2D? owner, Node2D target)
{
//We must know who the owner of the bullet is in order to determine whether it should cause damage or not
//我们必须知道子弹的主人是谁,才能判断是否应该造成伤害
if (owner == null)
{
return false;
}
if (owner is not CharacterTemplate ownerCharacterTemplate)
{
return false;
}
if (target is TileMapLayer)
{
//When we hit the tile, we return true to prevent the bullet from penetrating the tile.
//撞击到瓦片时,我们返回true,是为了防止子弹穿透瓦片。
return true;
}
if (target is PickAbleTemplate pickAbleTemplate)
{
//The picked-up item cannot resist the bullet.
//被拾起的物品无法抵挡子弹。
return !pickAbleTemplate.Picked;
}
if (target is not CharacterTemplate characterTemplate)
{
return false;
}
//First get the owner's camp and compare it with the target camp
//先获取主人的阵营与目标阵营进行比较
var canCauseHarm = CampManager.CanCauseHarm(CampManager.GetCamp(ownerCharacterTemplate.CampId),
CampManager.GetCamp(characterTemplate.CampId));
return canCauseHarm;
}
///
/// Executive injury treatment
/// 执行伤害处理
///
///
///
private void DoDamage(Node2D? owner, Node2D target)
{
if (target is CharacterTemplate characterTemplate)
{
//Allow damage to be caused
//允许造成伤害
var damage = new Damage
{
Attacker = owner,
MaxDamage = MaxDamage,
MinDamage = MinDamage
};
damage.CreateDamage();
damage.MoveLeft = Velocity.X < 0;
damage.Type = DamageType;
var dead = characterTemplate.Damage(damage);
if (dead)
{
//If the character is dead, then call OnKillCharacter
//如果角色死亡了,那么调用OnKillCharacter
InvokeDecorators(decorator => { decorator.OnKillCharacter(owner, characterTemplate); });
}
if (KnockbackForce != Vector2.Zero)
{
//If we set the attack force, then apply the force to the object
//如果我们设置了攻退力,那么将力应用到对象上
var force = new Vector2();
var forceX = Math.Abs(KnockbackForce.X);
if (Velocity.X < 0)
{
//Beat back to port
//向左击退
forceX = -forceX;
}
force.X = forceX * Config.CellSize;
force.Y = KnockbackForce.Y * Config.CellSize;
characterTemplate.AddForce(force);
}
}
else if (target is PickAbleTemplate pickAbleTemplate)
{
if (KnockbackForce != Vector2.Zero)
{
//If we set the attack force, then apply the force to the object
//如果我们设置了攻退力,那么将力应用到对象上
var force = new Vector2();
var forceX = Math.Abs(KnockbackForce.X);
if (Velocity.X < 0)
{
//Beat back to port
//向左击退
forceX = -forceX;
}
force.X = forceX * Config.CellSize;
force.Y = KnockbackForce.Y * Config.CellSize;
pickAbleTemplate.ApplyImpulse(force);
}
}
}
///
/// Call the method of the decorator
/// 调用装饰器的方法
///
///
private void InvokeDecorators(Action projectileDecoratorAction)
{
if (_projectileDecorators == null)
{
return;
}
foreach (var decorator in _projectileDecorators)
{
projectileDecoratorAction(decorator);
}
}
///
/// When beyond the time of existence
/// 当超过存在时间
///
private void OnTimeOut()
{
QueueFree();
}
public override void _Process(double delta)
{
//If the existence time is exceeded, the projectile is destroyed
//如果超过了存在时间,那么销毁抛射体
if (DateTime.Now >= _destructionTime)
{
OnTimeOut();
}
}
public override void _PhysicsProcess(double delta)
{
var collisionInfo = MoveAndCollide(Velocity * (float)delta);
if (collisionInfo != null)
{
//Bump into other objects.
//撞到其他对象。
if (EnableBounce)
{
Velocity = Velocity.Bounce(collisionInfo.GetNormal());
}
//Here we test whether harm is allowed, notice that for TileMap, we directly allow harm.
//这里我们检测是否允许造成伤害,注意对于TileMap,我们直接允许造成伤害。
var godotObject = collisionInfo.GetCollider();
var node = (Node2D)godotObject;
var canCauseHarm = CanCauseHarm(Owner, node);
if (!canCauseHarm)
{
return;
}
DoDamage(Owner, node);
//Please specify in the Mask who the bullet will collide with
//请在Mask内配置子弹会和谁碰撞
//When a bullet hits an object, its durability decreases
//子弹撞击到物体时,耐久度减少
Durability--;
if (Durability <= 0)
{
//When the durability is less than or equal to 0, destroy the bullet
//当耐久度小于等于0时,销毁子弹
QueueFree();
}
}
}
}