diff --git a/locals/Log.csv b/locals/Log.csv index a23920f..365619d 100644 --- a/locals/Log.csv +++ b/locals/Log.csv @@ -113,4 +113,4 @@ log_enter_the_screen,进入屏幕。,Enter screen,画面に移動。 log_exit_the_screen,退出屏幕。,Exit screen,画面を終了します。 log_failed_to_create_room_preview,创建{0}的房间预览图失败。,Failed to create a room preview of the {0}.,{0}の部屋のプレビューを作成できませんでした。 log_generated_item_is_empty,生成的物品{0}是空的吗{1}。,Generated item {0} is empty {1}.,生成したアイテム{0}は空ですか{1}。 -log_magics_is_null,法术列表是空的。,The spell list is empty.,スペルリストは空です。 \ No newline at end of file +log_projectile_generate_magic_is_null,没有装填可提供抛射体的法术。,There is no reload spell that provides projectiles.,射出体を提供するスペルを装填していません。 \ No newline at end of file diff --git a/prefab/magics/curseOfTheUndead.tscn b/prefab/magics/curseOfTheUndead.tscn index 11e4248..f25cbde 100644 --- a/prefab/magics/curseOfTheUndead.tscn +++ b/prefab/magics/curseOfTheUndead.tscn @@ -1,6 +1,6 @@ [gd_scene load_steps=6 format=3 uid="uid://crthy8a50a4t"] -[ext_resource type="Script" path="res://scripts/pickable/MagicPickAble.cs" id="1_5mane"] +[ext_resource type="Script" path="res://scripts/spell/SpellPickAble.cs" id="1_v0grp"] [ext_resource type="AudioStream" uid="uid://cak6chjjsu7wo" path="res://sounds/fire.wav" id="4_ffr2k"] [ext_resource type="Texture2D" uid="uid://bbcjkyrsx88av" path="res://sprites/projectile/curseOfTheUndead.png" id="4_y6nkf"] @@ -14,8 +14,8 @@ size = Vector2(20, 20.75) collision_layer = 8 collision_mask = 34 angular_damp = -1.0 -script = ExtResource("1_5mane") -UniqueIcon = ExtResource("4_y6nkf") +script = ExtResource("1_v0grp") +_projectilePath = "res://prefab/projectile/curseOfTheUndead.tscn" [node name="DamageArea2D" type="Area2D" parent="."] collision_layer = 8 diff --git a/prefab/weapons/StaffNecromancy.tscn b/prefab/weapons/StaffNecromancy.tscn index 0dd8ae1..044f4d2 100644 --- a/prefab/weapons/StaffNecromancy.tscn +++ b/prefab/weapons/StaffNecromancy.tscn @@ -16,7 +16,7 @@ collision_layer = 8 collision_mask = 34 angular_damp = -1.0 script = ExtResource("1_w8hhv") -NumberSlots = 5 +_numberSlots = 5 FiringIntervalAsMillisecond = 300 _recoilStrength = 5 UniqueIcon = ExtResource("3_31iau") diff --git a/scenes/game.tscn b/scenes/game.tscn index d6bda67..3ac7420 100644 --- a/scenes/game.tscn +++ b/scenes/game.tscn @@ -118,7 +118,7 @@ visible = false [node name="WeaponContainer" type="Node2D" parent="."] -[node name="MagicContainer" type="Node2D" parent="."] +[node name="SpellContainer" type="Node2D" parent="."] [node name="PlayerContainer" type="Node2D" parent="."] diff --git a/scripts/Config.cs b/scripts/Config.cs index dece38c..dc1ae4f 100644 --- a/scripts/Config.cs +++ b/scripts/Config.cs @@ -227,14 +227,14 @@ public static class Config public const int ProjectileWeapon = 3; /// - /// Magic + /// Spell /// 法术 /// /// ///Type of special item used in Projectile weapons ///用于远程武器内的特殊物品类型 /// - public const int Magic = 4; + public const int Spell = 4; } /// diff --git a/scripts/GameSceneDepend.cs b/scripts/GameSceneDepend.cs index 3821978..e791f30 100644 --- a/scripts/GameSceneDepend.cs +++ b/scripts/GameSceneDepend.cs @@ -50,10 +50,10 @@ public static class GameSceneDepend public static Node2D? ProjectileContainer { get; set; } /// - /// MagicContainer + /// SpellContainer /// 法术容器 /// - public static Node2D? MagicContainer { get; set; } + public static Node2D? SpellContainer { get; set; } /// /// WeaponContainer diff --git a/scripts/loader/sceneLoader/GameSceneLoader.cs b/scripts/loader/sceneLoader/GameSceneLoader.cs index bf56c32..e85e6fe 100644 --- a/scripts/loader/sceneLoader/GameSceneLoader.cs +++ b/scripts/loader/sceneLoader/GameSceneLoader.cs @@ -47,8 +47,8 @@ public partial class GameSceneLoader : SceneLoaderTemplate GameSceneDepend.ProjectileContainer = projectileContainer; //Load magic container //加载魔术容器 - var magicContainer = GetNode("MagicContainer"); - GameSceneDepend.MagicContainer = magicContainer; + var magicContainer = GetNode("SpellContainer"); + GameSceneDepend.SpellContainer = magicContainer; //Load Packsack container //加载背包容器 var packsackContainer = GetNode("PacksackContainer"); diff --git a/scripts/projectile/IMagic.cs b/scripts/projectile/ISpell.cs similarity index 95% rename from scripts/projectile/IMagic.cs rename to scripts/projectile/ISpell.cs index d984f71..87b4186 100644 --- a/scripts/projectile/IMagic.cs +++ b/scripts/projectile/ISpell.cs @@ -4,14 +4,14 @@ using Godot; namespace ColdMint.scripts.projectile; /// -/// Magic +/// Spell /// 法术 /// /// ///For projectile weapons ///用于抛射体武器 /// -public interface IMagic +public interface ISpell { /// /// GetProjectile diff --git a/scripts/pickable/MagicPickAble.cs b/scripts/spell/SpellPickAble.cs similarity index 83% rename from scripts/pickable/MagicPickAble.cs rename to scripts/spell/SpellPickAble.cs index 6e547cd..683407d 100644 --- a/scripts/pickable/MagicPickAble.cs +++ b/scripts/spell/SpellPickAble.cs @@ -1,8 +1,9 @@ +using ColdMint.scripts.pickable; using ColdMint.scripts.projectile; using ColdMint.scripts.weapon; using Godot; -namespace ColdMint.scripts.pickable; +namespace ColdMint.scripts.spell; /// /// magic @@ -12,8 +13,9 @@ namespace ColdMint.scripts.pickable; ///For projectile weapons ///用于抛射体武器 /// -public partial class MagicPickAble : PickAbleTemplate, IMagic +public partial class SpellPickAble : PickAbleTemplate, ISpell { + [Export] private string? _projectilePath; private PackedScene? _projectileScene; @@ -28,7 +30,7 @@ public partial class MagicPickAble : PickAbleTemplate, IMagic public override int ItemType { - get => Config.ItemType.Magic; + get => Config.ItemType.Spell; } public PackedScene? GetProjectile() diff --git a/scripts/utils/NodeUtils.cs b/scripts/utils/NodeUtils.cs index 89a7e34..bdccc12 100644 --- a/scripts/utils/NodeUtils.cs +++ b/scripts/utils/NodeUtils.cs @@ -235,9 +235,9 @@ public static class NodeUtils return GameSceneDepend.ProjectileContainer; } - if (GameSceneDepend.MagicContainer != null && childNode is IMagic) + if (GameSceneDepend.SpellContainer != null && childNode is ISpell) { - return GameSceneDepend.MagicContainer; + return GameSceneDepend.SpellContainer; } if (GameSceneDepend.WeaponContainer != null && childNode is WeaponTemplate) diff --git a/scripts/weapon/ProjectileWeapon.cs b/scripts/weapon/ProjectileWeapon.cs index 04e21ff..c284fcd 100644 --- a/scripts/weapon/ProjectileWeapon.cs +++ b/scripts/weapon/ProjectileWeapon.cs @@ -3,6 +3,7 @@ using ColdMint.scripts.debug; using ColdMint.scripts.inventory; using ColdMint.scripts.map.events; using ColdMint.scripts.projectile; +using ColdMint.scripts.utils; using Godot; namespace ColdMint.scripts.weapon; @@ -27,9 +28,81 @@ public partial class ProjectileWeapon : WeaponTemplate /// Number of slots for ranged weapons /// 远程武器的槽位数量 /// - [Export] public int NumberSlots { get; set; } + [Export] + private int _numberSlots; - private readonly List _magics = new(); + /// + /// How many projectiles are generated per fire + /// 每次开火生成多少个抛射体 + /// + public int NumberOfProjectiles { get; set; } = 1; + + private readonly List _spells = new(); + /// + /// Saves the position of a spell with projectile generation + /// 保存具有抛射体生成能力的法术位置 + /// + private readonly List _spellProjectileIndexes = new(); + + /// + /// Whether to fire spells in sequence + /// 是否按顺序发射法术 + /// + [Export] + private bool _fireSequentially; + + /// + /// The index used the last time a spell was cast + /// 上次发射法术时采用的索引 + /// + private int _lastUsedProjectileMagicIndex; + + /// + /// Get next index + /// 获取下次索引 + /// + /// + private int GetNextProjectileMagicIndex() + { + if (_fireSequentially) + { + _lastUsedProjectileMagicIndex++; + if (_lastUsedProjectileMagicIndex >= _spellProjectileIndexes.Count) + { + return 0; + } + return _lastUsedProjectileMagicIndex; + } + else + { + return RandomUtils.Instance.Next(0, _spellProjectileIndexes.Count); + } + } + + /// + /// Gets the loading range of the spell + /// 获取法术的加载范围 + /// + /// + 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 + ]; + } + } public override int ItemType { @@ -40,9 +113,8 @@ public partial class ProjectileWeapon : WeaponTemplate { base._Ready(); _marker2D = GetNode("Marker2D"); - SelfItemContainer = new UniversalItemContainer(NumberSlots); - SelfItemContainer.AllowAddingItemByType(Config.ItemType.Magic); - SelfItemContainer.ItemDataChangeEvent += OnItemDataChangeEvent; + SelfItemContainer = new UniversalItemContainer(_numberSlots); + SelfItemContainer.AllowAddingItemByType(Config.ItemType.Spell); } private void OnItemDataChangeEvent(ItemDataChangeEvent itemDataChangeEvent) @@ -51,7 +123,8 @@ public partial class ProjectileWeapon : WeaponTemplate { return; } - _magics.Clear(); + _spells.Clear(); + _spellProjectileIndexes.Clear(); var totalCapacity = SelfItemContainer.GetTotalCapacity(); for (var i = 0; i < totalCapacity; i++) { @@ -60,11 +133,27 @@ public partial class ProjectileWeapon : WeaponTemplate { continue; } - if (item is not IMagic magic) + if (item is not ISpell spell) { continue; } - _magics.Add(magic); + _spells.Add(spell); + var packedScene = spell.GetProjectile(); + if (packedScene != null) + { + //Has the ability to generate projectiles. + //拥有抛射体生成能力。 + _spellProjectileIndexes.Add(i); + } + } + } + + public override void _EnterTree() + { + base._EnterTree(); + if (SelfItemContainer != null) + { + SelfItemContainer.ItemDataChangeEvent += OnItemDataChangeEvent; } } @@ -96,10 +185,45 @@ public partial class ProjectileWeapon : WeaponTemplate LogCat.LogError("projectile_container_is_null"); return; } - if (_magics.Count == 0) + if (_spellProjectileIndexes.Count == 0) { - LogCat.LogError("magics_is_null"); + LogCat.LogError("projectile_generate_magic_is_null"); return; } + var spellScope = GetSpellScope(); + //The final spell is a projectile generator. + //最后的法术是拥有抛射体生成能力的。 + var spellProjectile = _spells[spellScope[1]]; + var packedScene = spellProjectile.GetProjectile(); + if (packedScene == null) + { + return; + } + for (var i = spellScope[0]; i <= spellScope[1]; i++) + { + var spell = _spells[i]; + spell.ModifyWeapon(this); + } + for (var i = 0; i < NumberOfProjectiles; i++) + { + var projectile = NodeUtils.InstantiatePackedScene(packedScene); + if (projectile == null) return; + for (var s = spellScope[0]; s <= spellScope[1]; s++) + { + var spell = _spells[s]; + spell.ModifyProjectile(projectile); + } + NodeUtils.CallDeferredAddChild(GameSceneDepend.ProjectileContainer, projectile); + projectile.Owner = owner; + projectile.TargetNode = GameSceneDepend.TemporaryTargetNode; + projectile.Velocity = + _marker2D.GlobalPosition.DirectionTo(enemyGlobalPosition) * projectile.Speed; + projectile.Position = _marker2D.GlobalPosition; + } + for (var i = spellScope[0]; i <= spellScope[1]; i++) + { + var spell = _spells[i]; + spell.RestoreWeapon(this); + } } } \ No newline at end of file