diff --git a/locals/DeathInfo.csv b/locals/DeathInfo.csv new file mode 100644 index 0000000..e626ff2 --- /dev/null +++ b/locals/DeathInfo.csv @@ -0,0 +1,5 @@ +id,zh,en,jp +#kill self +#自杀 +death_info_self_1,{0}误伤了自己。,{0} accidentally shot himself.,{0}誤って自分を傷つけました。 +death_info_self_2,{0}忘记了瞄准。,{0} forgot to aim.,{0}照準を忘れました。 \ No newline at end of file diff --git a/locals/DeathInfo.csv.import b/locals/DeathInfo.csv.import new file mode 100644 index 0000000..8c94551 --- /dev/null +++ b/locals/DeathInfo.csv.import @@ -0,0 +1,17 @@ +[remap] + +importer="csv_translation" +type="Translation" +uid="uid://dwx0hwuy0uqio" + +[deps] + +files=["res://locals/DeathInfo.zh.translation", "res://locals/DeathInfo.en.translation", "res://locals/DeathInfo.jp.translation"] + +source_file="res://locals/DeathInfo.csv" +dest_files=["res://locals/DeathInfo.zh.translation", "res://locals/DeathInfo.en.translation", "res://locals/DeathInfo.jp.translation"] + +[params] + +compress=true +delimiter=0 diff --git a/locals/DeathInfo.en.translation b/locals/DeathInfo.en.translation new file mode 100644 index 0000000..5fc8b9c Binary files /dev/null and b/locals/DeathInfo.en.translation differ diff --git a/locals/DeathInfo.jp.translation b/locals/DeathInfo.jp.translation new file mode 100644 index 0000000..66927b8 Binary files /dev/null and b/locals/DeathInfo.jp.translation differ diff --git a/locals/DeathInfo.zh.translation b/locals/DeathInfo.zh.translation new file mode 100644 index 0000000..26abed9 Binary files /dev/null and b/locals/DeathInfo.zh.translation differ diff --git a/project.godot b/project.godot index f17d619..8181c51 100644 --- a/project.godot +++ b/project.godot @@ -146,7 +146,7 @@ hotbar_previous={ [internationalization] -locale/translations=PackedStringArray("res://locals/UI.en.translation", "res://locals/UI.zh.translation", "res://locals/Log.en.translation", "res://locals/Log.zh.translation", "res://locals/Weapon.en.translation", "res://locals/Weapon.zh.translation", "res://locals/InputMapping.en.translation", "res://locals/InputMapping.zh.translation", "res://locals/InputMapping.jp.translation", "res://locals/Log.jp.translation", "res://locals/UI.jp.translation", "res://locals/Weapon.jp.translation", "res://locals/Slogan.en.translation", "res://locals/Slogan.jp.translation", "res://locals/Slogan.zh.translation") +locale/translations=PackedStringArray("res://locals/UI.en.translation", "res://locals/UI.zh.translation", "res://locals/Log.en.translation", "res://locals/Log.zh.translation", "res://locals/Weapon.en.translation", "res://locals/Weapon.zh.translation", "res://locals/InputMapping.en.translation", "res://locals/InputMapping.zh.translation", "res://locals/InputMapping.jp.translation", "res://locals/Log.jp.translation", "res://locals/UI.jp.translation", "res://locals/Weapon.jp.translation", "res://locals/Slogan.en.translation", "res://locals/Slogan.jp.translation", "res://locals/Slogan.zh.translation", "res://locals/DeathInfo.en.translation", "res://locals/DeathInfo.jp.translation", "res://locals/DeathInfo.zh.translation") [layer_names] diff --git a/scenes/gameOverMenu.tscn b/scenes/gameOverMenu.tscn index 6382439..5dfefd4 100644 --- a/scenes/gameOverMenu.tscn +++ b/scenes/gameOverMenu.tscn @@ -55,6 +55,6 @@ layout_mode = 2 theme_override_constants/margin_top = 10 theme_override_constants/margin_bottom = 150 -[node name="Button" type="Button" parent="CenterContainer/VBoxContainer/MarginContainer2"] +[node name="RestartButton" type="Button" parent="CenterContainer/VBoxContainer/MarginContainer2"] layout_mode = 2 text = "restart" diff --git a/scripts/EventManager.cs b/scripts/EventManager.cs index 641a95a..e22d7af 100644 --- a/scripts/EventManager.cs +++ b/scripts/EventManager.cs @@ -11,8 +11,18 @@ public class EventManager /// public static Action? AiCharacterGenerateEvent; + /// + /// Game Over Event + /// 游戏结束事件 + /// public static Action? GameOverEvent; + /// + /// Events when the game is replayed + /// 游戏重玩时的事件 + /// + public static Action? GameReplayEvent; + /// /// Map starts generating events /// 地图开始生成的事件 diff --git a/scripts/behaviorTree/ai/AiPickNode.cs b/scripts/behaviorTree/ai/AiPickNode.cs index 806087e..12ffdfd 100644 --- a/scripts/behaviorTree/ai/AiPickNode.cs +++ b/scripts/behaviorTree/ai/AiPickNode.cs @@ -45,8 +45,7 @@ public class AiPickNode : BehaviorTreeNodeTemplate { //If it's a weapon //如果是武器 - var distance = weaponTemplate.GlobalPosition - Character.GlobalPosition; - var distanceLength = distance.Length(); + var distanceLength = weaponTemplate.GlobalPosition.DistanceTo(Character.GlobalPosition); if (distanceLength < closestDistance) { closestDistance = distanceLength; diff --git a/scripts/character/CharacterTemplate.cs b/scripts/character/CharacterTemplate.cs index 5ddd4bf..5fc984f 100644 --- a/scripts/character/CharacterTemplate.cs +++ b/scripts/character/CharacterTemplate.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; +using System.Threading.Tasks; using ColdMint.scripts.camp; using ColdMint.scripts.damage; using ColdMint.scripts.debug; @@ -100,7 +101,7 @@ public partial class CharacterTemplate : CharacterBody2D //角色创建后的初始血量 private int _initialHp; - protected int MaxHp; + public int MaxHp; /// /// The camp ID of the role @@ -121,6 +122,34 @@ public partial class CharacterTemplate : CharacterBody2D public Node[] PickingRangeBodies => PickingRangeBodiesList?.ToArray() ?? Array.Empty(); + /// + /// Resurrected character + /// 复活角色 + /// + /// + ///Sets the amount of Hp a character has after resurrection + ///设置角色复活后拥有的Hp + /// + public 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; + } + + CurrentHp = newHp; + Visible = true; + } + /// /// Find the nearest item within the pick up area(Does not include items currently held) /// 在拾捡范围内查找距离最近的物品(不包括当前持有的物品) @@ -433,7 +462,7 @@ public partial class CharacterTemplate : CharacterBody2D /// 处理角色死亡的事件 /// /// - protected virtual void OnDie(DamageTemplate damageTemplate) + protected virtual Task OnDie(DamageTemplate damageTemplate) { //If the attacker is not empty and the role name is not empty, then the role death message is printed //如果攻击者不为空,且角色名不为空,那么打印角色死亡信息 @@ -451,6 +480,7 @@ public partial class CharacterTemplate : CharacterBody2D } QueueFree(); + return Task.CompletedTask; } /// diff --git a/scripts/character/Player.cs b/scripts/character/Player.cs index bea515b..2c754d9 100644 --- a/scripts/character/Player.cs +++ b/scripts/character/Player.cs @@ -1,6 +1,8 @@ using System; using System.Text; +using System.Threading.Tasks; using ColdMint.scripts.damage; +using ColdMint.scripts.deathInfo; using ColdMint.scripts.map.events; using ColdMint.scripts.utils; using ColdMint.scripts.weapon; @@ -153,6 +155,11 @@ public partial class Player : CharacterTemplate protected override void HookPhysicsProcess(ref Vector2 velocity, double delta) { + if (!Visible) + { + return; + } + //When the collision state between the platform detection ray and the platform changes //在平台检测射线与平台碰撞状态改变时 if (_platformDetectionRayCast2D != null && _platformDetectionRayCast2D.IsColliding() != _collidingWithPlatform) @@ -315,6 +322,11 @@ public partial class Player : CharacterTemplate public override void _Process(double delta) { + if (!Visible) + { + return; + } + AimTheCurrentItemAtAPoint(GetGlobalMousePosition()); var itemMarker2DPosition = Vector2.Zero; if (ItemMarker2D != null) @@ -366,18 +378,21 @@ public partial class Player : CharacterTemplate } } - protected override void OnDie(DamageTemplate damageTemplate) + protected override async Task OnDie(DamageTemplate damageTemplate) { - if (EventManager.GameOverEvent != null) + Visible = false; + if (EventManager.GameOverEvent == null) { - var gameOverEvent = new GameOverEvent - { - DeathInfo = "\"白纸\"失手将自己杀死。" - }; - EventManager.GameOverEvent(gameOverEvent); + return; } - Visible = false; + var gameOverEvent = new GameOverEvent(); + if (damageTemplate.Attacker != null) + { + gameOverEvent.DeathInfo = await DeathInfoGenerator.GenerateDeathInfo(this, damageTemplate.Attacker); + } + + EventManager.GameOverEvent.Invoke(gameOverEvent); } protected override void EnterThePickingRangeBody(Node node) diff --git a/scripts/deathInfo/DeathInfoGenerator.cs b/scripts/deathInfo/DeathInfoGenerator.cs new file mode 100644 index 0000000..b829ec4 --- /dev/null +++ b/scripts/deathInfo/DeathInfoGenerator.cs @@ -0,0 +1,81 @@ +using System.Collections.Generic; +using System.Threading.Tasks; +using ColdMint.scripts.character; +using ColdMint.scripts.utils; +using Godot; + +namespace ColdMint.scripts.deathInfo; + +public static class DeathInfoGenerator +{ + private static List? _deathInfoHandlers; + + /// + /// Register the death message handler + /// 注册死亡信息处理器 + /// + /// + public static void RegisterDeathInfoHandler(IDeathInfoHandler deathInfoHandler) + { + _deathInfoHandlers ??= new List(); + _deathInfoHandlers.Add(deathInfoHandler); + } + + /// + /// Unregister the death message handler + /// 取消注册死亡信息处理器 + /// + /// + public static void UnregisterDeathInfoHandler(IDeathInfoHandler deathInfoHandler) + { + if (_deathInfoHandlers == null) + { + return; + } + + _deathInfoHandlers.Remove(deathInfoHandler); + } + + /// + /// Generate death info + /// 生成死亡信息 + /// + /// + /// + /// + public static async Task GenerateDeathInfo(Player victim, Node killer) + { + var victimName = victim.ReadOnlyCharacterName ?? victim.Name; + string killerName = killer.Name; + if (killer is CharacterTemplate characterTemplate) + { + killerName = characterTemplate.ReadOnlyCharacterName ?? killer.Name; + } + if (_deathInfoHandlers == null || _deathInfoHandlers.Count == 0) + { + return GenerateDefaultDeathInfo(victimName, killerName) ?? string.Empty; + } + foreach (var deathInfoHandler in _deathInfoHandlers) + { + var deathInfo = await deathInfoHandler.GenerateDeathInfo(victimName, killerName, victim, killer); + if (!string.IsNullOrEmpty(deathInfo)) + { + return deathInfo; + } + } + + return GenerateDefaultDeathInfo(victimName, killerName) ?? string.Empty; + } + + /// + /// Generate a default death message + /// 生成默认的死亡信息 + /// + /// + /// + /// + private static string? GenerateDefaultDeathInfo(string victimName, string killerName) + { + return TranslationServerUtils.TranslateWithFormat("death_info", victimName, killerName); + } +} \ No newline at end of file diff --git a/scripts/deathInfo/IDeathInfoHandler.cs b/scripts/deathInfo/IDeathInfoHandler.cs new file mode 100644 index 0000000..55bd52f --- /dev/null +++ b/scripts/deathInfo/IDeathInfoHandler.cs @@ -0,0 +1,35 @@ +using System.Threading.Tasks; +using ColdMint.scripts.character; +using Godot; + +namespace ColdMint.scripts.deathInfo; + +/// +/// Death information processor +/// 死亡信息处理器 +/// +public interface IDeathInfoHandler +{ + /// + /// Generate death info + /// 生成死亡信息 + /// + /// + ///victimName + ///受害者名称 + /// + /// + ///KillerName + ///杀手名称 + /// + /// + /// victim + /// 受害者 + /// + /// + /// Killer + /// 杀手 + /// + /// + public Task GenerateDeathInfo(string victimName, string killerName, Player victim, Node killer); +} \ No newline at end of file diff --git a/scripts/deathInfo/SelfDeathInfoHandler.cs b/scripts/deathInfo/SelfDeathInfoHandler.cs new file mode 100644 index 0000000..2914933 --- /dev/null +++ b/scripts/deathInfo/SelfDeathInfoHandler.cs @@ -0,0 +1,25 @@ +using System.Threading.Tasks; +using ColdMint.scripts.character; +using ColdMint.scripts.utils; +using Godot; + +namespace ColdMint.scripts.deathInfo; + +/// +/// Deal with the message that your game failed due to accidental injury +/// 处理自己误伤导致游戏失败的信息 +/// +public class SelfDeathInfoHandler : IDeathInfoHandler +{ + private const string Prefix = "death_info_self_"; + private const int Length = 2; + + public Task GenerateDeathInfo(string victimName, string killerName, Player victim, Node killer) + { + if (victim != killer) return Task.FromResult(null); + var index = GD.Randi() % Length + 1; + return Task.FromResult( + TranslationServerUtils.TranslateWithFormat(Prefix + index, victimName, killerName)); + + } +} \ No newline at end of file diff --git a/scripts/loader/uiLoader/GameOverLoaderMenuLoader.cs b/scripts/loader/uiLoader/GameOverLoaderMenuLoader.cs index a1fedc9..77c1836 100644 --- a/scripts/loader/uiLoader/GameOverLoaderMenuLoader.cs +++ b/scripts/loader/uiLoader/GameOverLoaderMenuLoader.cs @@ -11,6 +11,7 @@ namespace ColdMint.scripts.loader.uiLoader; public partial class GameOverLoaderMenuLoader : UiLoaderTemplate { private Label? _deathInfoLabel; + private Button? _restartButton; public override void InitializeUi() { @@ -19,11 +20,25 @@ public partial class GameOverLoaderMenuLoader : UiLoaderTemplate public override void InitializeData() { + _restartButton = GetNodeOrNull