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