using System; using System.Collections.Generic; using System.Threading.Tasks; using ColdMint.scripts.camp; using ColdMint.scripts.damage; using ColdMint.scripts.debug; using ColdMint.scripts.health; using ColdMint.scripts.inventory; using ColdMint.scripts.utils; using ColdMint.scripts.loot; using ColdMint.scripts.pickable; using ColdMint.scripts.weapon; using Godot; using WeaponTemplate = ColdMint.scripts.weapon.WeaponTemplate; namespace ColdMint.scripts.character; /// /// CharacterTemplate /// 角色模板 /// /// ///Behavior shared by all characters ///所有角色共有的行为 /// public partial class CharacterTemplate : CharacterBody2D { // Get the gravity from the project settings to be synced with RigidBody nodes. // 从项目设置中获取与RigidBody节点同步的重力。 protected float Gravity = ProjectSettings.GetSetting("physics/2d/default_gravity").AsSingle(); /// /// How fast the character moves /// 角色的移动速度 /// /// ///How many squares per second? ///每秒移动几格? /// protected const float Speed = 5f; /// /// Speed multiplier /// 速度乘数 /// protected float ProtectedSpeedScale = 1f; /// /// Speed multiplier /// 速度乘数 /// ///Set to 0.5 to move at 50% of the normal speed. ///设置为0.5则以正常速度的50%移动。 /// /// public float SpeedScale { get => ProtectedSpeedScale; set { if (value > 1) { ProtectedSpeedScale = 1; } else { ProtectedSpeedScale = value; } } } protected const float JumpVelocity = -240; public string? ReadOnlyCharacterName => TranslationServerUtils.Translate(CharacterName); [Export] public string? CharacterName; /// /// Can mutate after death /// 是否允许死后变异 /// [Export] public bool CanMutateAfterDeath { get; set; } = true; protected IItemContainer? ProtectedItemContainer; //Item containers are used to store items. //物品容器用于存储物品。 public IItemContainer? ItemContainer { get => ProtectedItemContainer; set { ProtectedItemContainer = value; WhenBindItemContainer(ProtectedItemContainer); } } //Items currently held //当前持有的物品 private Node2D? _currentItem; public Node2D? CurrentItem { get => _currentItem; protected set { _currentItem = value; WhenUpdateCurrentItem(_currentItem); } } /// /// When binding an item container to a character /// 当为角色绑定物品容器时 /// /// protected virtual void WhenBindItemContainer(IItemContainer? itemContainer) { } /// /// When the items the character holds are updated /// 当角色持有的物品更新时 /// /// ///Update finished items ///更新完成后的物品 /// protected virtual void WhenUpdateCurrentItem(Node2D? currentItem) { } //Define a pickup range //定义一个拾起范围 private Area2D? _pickingArea; private AnimatedSprite2D? _animatedSprite2D; //A marker that defines the location of the item //一个标记,定义物品的位置 protected Marker2D? ItemMarker2D; //The original X-coordinate of the item marker //物品标记的原始X坐标 private float _itemMarkerOriginalX; protected float ReadOnlyItemMarkerOriginalX => _itemMarkerOriginalX; //Face left? //面向左边吗 public bool FacingLeft = false; //The force added by the AddForce method //由AddForce方法追加的力 private Vector2 _additionalForce = Vector2.Zero; protected int CurrentHp; //The initial health of the character after creation //角色创建后的初始血量 [Export] private int _initialHp; [Export] protected int MaxHp; /// /// The camp ID of the role /// 角色的阵营ID /// [Export] public string? CampId; private DamageNumberNodeSpawn? _damageNumber; /// /// indestructible /// 是否为无敌的 /// [Export] private bool _indestructible; [Export] public string LootListId { get; private set; } = ""; private HealthBar? _healthBar; private Label? _tipLabel; private DateTime _lastDamageTime; /// /// Pick up all items within range /// 拾捡范围内的所有物品 /// protected List? PickingRangeBodiesList; public Node[] PickingRangeBodies => PickingRangeBodiesList?.ToArray() ?? []; /// /// Full Hp Revive /// 满血复活 /// public void FullHpRevive() { Revive(MaxHp); } /// /// Resurrected character /// 复活角色 /// /// ///Sets the amount of Hp a character has after resurrection ///设置角色复活后拥有的Hp /// public virtual void Revive(int newHp) { //If the new Hp is less than or equal to 0, there is no need to resurrect //如果新的Hp小于等于0,那么不需要复活 if (newHp <= 0) { return; } if (CurrentHp > 0) { //If the current Hp is greater than 0, there is no need to revive //如果当前Hp大于0,那么不需要复活 return; } //Check whether the new Hp is greater than the maximum Hp. If yes, set the current Hp to the maximum Hp. If no, set the current Hp to the new HP //判断新的Hp是否大于最大Hp,若大于那么将当前Hp设置为最大Hp,否则设置为新的Hp CurrentHp = newHp > MaxHp ? MaxHp : newHp; Show(); } /// /// Find the nearest item within the pickup area(Does not include items currently held) /// 在拾捡范围内查找距离最近的物品(不包括当前持有的物品) /// /// public Node2D? FindTheNearestItem() { LogCat.Log("find_nearest_item"); if (PickingRangeBodiesList == null || PickingRangeBodiesList.Count == 0) { return null; } return NodeUtils.GetTheNearestNode(this, PickingRangeBodiesList.ToArray(), true, node => !CanPickItem(node)); } /// /// Get all weapons within range of the pickup /// 获取所有在拾捡范围内的武器 /// /// public WeaponTemplate[] GetCanPickedWeapon() { var weaponTemplates = new List(); foreach (var pickingRangeBody in PickingRangeBodies) { if (pickingRangeBody is not WeaponTemplate weaponTemplate) continue; if (weaponTemplate.Picked) { continue; } weaponTemplates.Add(weaponTemplate); } return weaponTemplates.ToArray(); } public override void _Ready() { base._Ready(); PickingRangeBodiesList = new List(); if (MaxHp <= 0) { MaxHp = Config.DefaultMaxHp; } if (_initialHp <= 0 || _initialHp > MaxHp) { //If the initial health is less than or equal to 0 or greater than the maximum health, then set it to the maximum health //如果初始血量小于等于0或者大于最大血量,那么将其设置为最大血量 _initialHp = MaxHp; } CurrentHp = _initialHp; //The health bar of a creature may be null. //生物的健康条,可能为null。 _healthBar = GetNodeOrNull("HealthBar"); if (_healthBar != null) { _healthBar.MaxValue = MaxHp; } ItemMarker2D = GetNode("ItemMarker2D"); _itemMarkerOriginalX = ItemMarker2D.Position.X; _animatedSprite2D = GetNode("AnimatedSprite2D"); _pickingArea = GetNode("Area2DPickingArea"); _damageNumber = GetNode("DamageNumber") as DamageNumberNodeSpawn; _tipLabel = GetNodeOrNull