diff --git a/locals/slogan.csv.import b/locals/slogan.csv.import
index a8a05f0..b4b32ef 100644
--- a/locals/slogan.csv.import
+++ b/locals/slogan.csv.import
@@ -2,14 +2,14 @@
importer="csv_translation"
type="Translation"
-uid="uid://cc0k86apkvut7"
+uid="uid://dl2r1rydlm7pa"
[deps]
-files=["res://locals/slogan.zh.translation", "res://locals/slogan.en.translation", "res://locals/slogan.ja.translation"]
+files=["res://locals/Slogan.zh.translation", "res://locals/Slogan.en.translation", "res://locals/Slogan.ja.translation"]
-source_file="res://locals/slogan.csv"
-dest_files=["res://locals/slogan.zh.translation", "res://locals/slogan.en.translation", "res://locals/slogan.ja.translation"]
+source_file="res://locals/Slogan.csv"
+dest_files=["res://locals/Slogan.zh.translation", "res://locals/Slogan.en.translation", "res://locals/Slogan.ja.translation"]
[params]
diff --git a/prefab/roomTemplates/dungeon/initialRoom.tscn b/prefab/roomTemplates/dungeon/initialRoom.tscn
index ec59b74..1d0de93 100644
--- a/prefab/roomTemplates/dungeon/initialRoom.tscn
+++ b/prefab/roomTemplates/dungeon/initialRoom.tscn
@@ -1,8 +1,9 @@
-[gd_scene load_steps=6 format=3 uid="uid://du5ldsp613fei"]
+[gd_scene load_steps=7 format=3 uid="uid://du5ldsp613fei"]
[ext_resource type="TileSet" uid="uid://c4wpp12rr44hi" path="res://tileSets/dungeon.tres" id="1_rn2om"]
[ext_resource type="Script" path="res://scripts/map/PlayerSpawn.cs" id="2_6p8mv"]
-[ext_resource type="PackedScene" uid="uid://dnnn2xyayiehk" path="res://prefab/weapons/staffOfTheUndead.tscn" id="3_ud0w8"]
+[ext_resource type="Script" path="res://scripts/map/ItemSpawn.cs" id="3_v1tlc"]
+[ext_resource type="Texture2D" uid="uid://b2blj0yf4ohx3" path="res://icon.svg" id="4_psvpu"]
[sub_resource type="RectangleShape2D" id="RectangleShape2D_kiih8"]
size = Vector2(450, 191)
@@ -40,8 +41,14 @@ shape = SubResource("RectangleShape2D_jxmys")
debug_color = Color(0, 0.6, 0.701961, 0.419608)
[node name="Marker2D" type="Marker2D" parent="."]
-position = Vector2(216, 113)
+position = Vector2(221, 134)
script = ExtResource("2_6p8mv")
-[node name="StaffOfTheUndead6" parent="." instance=ExtResource("3_ud0w8")]
-position = Vector2(290, 167)
+[node name="ItemMarker2D" type="Marker2D" parent="."]
+position = Vector2(142, 84)
+script = ExtResource("3_v1tlc")
+ItemId = "staff_of_the_undead"
+
+[node name="Icon" type="Sprite2D" parent="ItemMarker2D"]
+scale = Vector2(0.3, 0.3)
+texture = ExtResource("4_psvpu")
diff --git a/scripts/character/CharacterTemplate.cs b/scripts/character/CharacterTemplate.cs
index 42d4e35..f552894 100644
--- a/scripts/character/CharacterTemplate.cs
+++ b/scripts/character/CharacterTemplate.cs
@@ -492,7 +492,7 @@ public partial class CharacterTemplate : CharacterBody2D
foreach (var lootDatum in lootData)
{
var (id, amount) = lootDatum.Value;
- ItemTypeManager.CreateItems(id, amount, parentNode, position);
+ ItemTypeManager.CreateItems(id, amount, position, parentNode);
}
}
@@ -644,7 +644,7 @@ public partial class CharacterTemplate : CharacterBody2D
}
else
{
- for (int i = 0; i < number && !itemSlotNode.IsEmpty(); i++)
+ for (var i = 0; i < number && !itemSlotNode.IsEmpty(); i++)
{
ThrowOneItem(itemSlotNode, velocity);
}
diff --git a/scripts/inventory/ItemSlotNode.cs b/scripts/inventory/ItemSlotNode.cs
index a422073..7f50852 100644
--- a/scripts/inventory/ItemSlotNode.cs
+++ b/scripts/inventory/ItemSlotNode.cs
@@ -101,6 +101,43 @@ public partial class ItemSlotNode : MarginContainer
return _item;
}
+ ///
+ /// CreateItemInstance
+ /// 创建物品槽内的物品实例
+ ///
+ ///
+ ///number
+ ///数量
+ ///
+ ///
+ ///Newly created item
+ ///新创建的物品
+ ///
+ public IItem? CreateItemInstance(int number)
+ {
+ if (_item is not Node2D node2D)
+ {
+ return null;
+ }
+
+ var duplicate = node2D.Duplicate();
+ if (duplicate is not IItem newItem)
+ {
+ return null;
+ }
+
+ if (number > _item.Quantity)
+ {
+ //The number of item instances created exceeds the current number of items
+ //创建的物品实例数量,超过了当前物品的数量
+ duplicate.QueueFree();
+ return null;
+ }
+
+ newItem.Quantity = number;
+ return newItem;
+ }
+
public override void _DropData(Vector2 atPosition, Variant data)
{
if (_iconTextureRect == null)
@@ -311,6 +348,11 @@ public partial class ItemSlotNode : MarginContainer
var newQuantity = item.Quantity + _item.Quantity;
_item.Quantity = Math.Min(newQuantity, _item.MaxQuantity);
+ if (item is Node2D node2D)
+ {
+ node2D.QueueFree();
+ }
+ UpdateQuantityLabel();
return true;
}
}
\ No newline at end of file
diff --git a/scripts/inventory/ItemType.cs b/scripts/inventory/ItemType.cs
index c1581a8..d2a09cf 100644
--- a/scripts/inventory/ItemType.cs
+++ b/scripts/inventory/ItemType.cs
@@ -3,23 +3,30 @@ using Godot;
namespace ColdMint.scripts.inventory;
-public readonly struct ItemType(string id, Func newItemFunc, Texture2D? icon, int maxStackQuantity)
+public readonly struct ItemType(
+ string id,
+ Func createItemFunc,
+ Texture2D? icon,
+ int maxStackQuantity)
{
///
/// Item id of this type
/// 该类型物品的id
///
public string Id { get; init; } = id;
+
///
/// A function returns a new item instance of this type
/// 用于创建该类型的物品实例的函数
///
- public Func NewItemFunc { get; init; } = newItemFunc;
+ public Func CreateItemFunc { get; init; } = createItemFunc;
+
///
/// Default icon of items of this type
/// 该类型物品的默认图标
///
public Texture2D? Icon { get; init; } = icon;
+
///
/// Max number in item stack of this type
/// 该类型物品的最大堆叠数量
diff --git a/scripts/inventory/ItemTypeManager.cs b/scripts/inventory/ItemTypeManager.cs
index 9da7404..eaf15b7 100644
--- a/scripts/inventory/ItemTypeManager.cs
+++ b/scripts/inventory/ItemTypeManager.cs
@@ -33,69 +33,62 @@ public static class ItemTypeManager
/// Returns null when the id is not registered.
/// 当物品id没有注册时返回null
///
- ///
- public static IItem? NewItem(string id) =>
- Registry.TryGetValue(id, out var itemType) ? itemType.NewItemFunc() : null;
+ ///
+ ///Item Id
+ ///物品Id
+ ///
+ ///
+ ///Default parent
+ ///父节点
+ ///
+ ///
+ ///Enabled by default, whether to place a node into a container node that matches the type of the root node after it is instantiated. If the assignment fails by type, it is placed under the default parent node.
+ ///默认启用,实例化节点后,是否将其放置到与根节点类型相匹配的容器节点内。如果按照类型分配失败,则放置在默认父节点下。
+ ///
+ ///
+ public static IItem? CreateItem(string id, Node? defaultParentNode = null, bool assignedByRootNodeType = true) =>
+ Registry.TryGetValue(id, out var itemType)
+ ? itemType.CreateItemFunc(defaultParentNode, assignedByRootNodeType)
+ : null;
+
///
- /// Creates new instances in given amount of the item registered to the given id.
- /// 创建给定数量的注册到给定 id 的物品的新实例。
+ /// Create multiple new item instances for the given item Id
+ /// 创建多个给定物品Id的新物品实例
///
+ ///
+ ///
+ ///
+ ///
+ ///
///
- ///
- public static IList NewItems(string id, int amount)
+ ///
+ public static IItem?[]? CreateItems(string id, int number, Vector2 globalPosition, Node? defaultParentNode = null,
+ bool assignedByRootNodeType = true)
{
- IList result = [];
- for (int i = 0; i < amount; i++)
+ if (number <= 0)
{
- if (NewItem(id) is { } item) result.Add(item);
+ return null;
}
- return result;
- }
-
- ///
- /// Creates new instance of the item registered to the given id, and put it into given position in both node tree and 2D space
- /// 创建以给定 id 注册的物品的新实例,并将其放到节点树和二维空间中的给定位置
- ///
- ///
- ///
- ///
- /// Position in global coordinate
- /// 全局坐标中的位置
- ///
- ///
- public static IItem? CreateItem(string id, Node? parent = null, Vector2? position = null)
- {
- var item = NewItem(id);
- parent?.CallDeferred(GodotStringNameUtils.AddChild, (item as Node)!);
- if (item is not Node2D node) return item;
- if (position is { } pos) node.GlobalPosition = pos;
- return item;
- }
-
- ///
- /// Creates new instances in given amount of the item registered to the given id, and put them into given position in both node tree and 2D space
- /// 创建以给定 id 注册的物品的给定数量的新实例,并将其放到节点树和二维空间中的给定位置
- ///
- ///
- ///
- ///
- ///
- /// Position in global coordinate
- /// 全局坐标中的位置
- ///
- ///
- public static IList CreateItems(string id, int amount, Node? parent = null, Vector2? position = null)
- {
- IList result = [];
- for (int i = 0; i < amount; i++)
+ var items = new List();
+ for (var i = 0; i < number; i++)
{
- if (CreateItem(id, parent, position) is { } item)
- result.Add(item);
+ var singleItem = CreateItem(id, defaultParentNode, assignedByRootNodeType);
+ if (singleItem == null)
+ {
+ continue;
+ }
+
+ if (singleItem is Node2D node2D)
+ {
+ node2D.GlobalPosition = globalPosition;
+ }
+
+ items.Add(singleItem);
}
- return result;
+ return items.ToArray();
}
///
diff --git a/scripts/inventory/ItemTypeRegister.cs b/scripts/inventory/ItemTypeRegister.cs
index c0fb919..dba3027 100644
--- a/scripts/inventory/ItemTypeRegister.cs
+++ b/scripts/inventory/ItemTypeRegister.cs
@@ -50,7 +50,7 @@ public static class ItemTypeRegister
//将文件解析为项目类型信息
//parse files to item type infos
IEnumerable typeInfos =
- files.SelectMany(file => ParseFile( $"{itemRegsDirPath}/{file}")).ToList();
+ files.SelectMany(file => ParseFile($"{itemRegsDirPath}/{file}")).ToList();
LogCat.LogWithFormat("found_item_types", typeInfos.Count());
//遍历类型信息并注册它们。
@@ -70,8 +70,9 @@ public static class ItemTypeRegister
private static IList ParseFile(string filePath)
{
var yamlFile = FileAccess.Open(filePath, FileAccess.ModeFlags.Read);
- //阅读和反序列化
+
//Read & deserialize
+ //阅读和反序列化
var yamlString = yamlFile.GetAsText();
var typeInfos = YamlSerialization.Deserialize>(yamlString);
yamlFile.Close();
@@ -81,35 +82,32 @@ public static class ItemTypeRegister
private static void RegisterTypeInfo(ItemTypeInfo typeInfo)
{
//Load scene and icon
+ //加载场景和图标
var scene = ResourceLoader.Load(typeInfo.ScenePath);
var icon = ResourceLoader.Load(typeInfo.IconPath);
+
//Create init delegate
- Func newItemFunc;
- if (typeInfo.CustomArgs is null or [])
+ //创建初始化委托
+ Action? setArgs = null;
+ if (typeInfo.CustomArgs != null && typeInfo.CustomArgs.Count > 0)
{
- newItemFunc = () => NodeUtils.InstantiatePackedScene(scene);
- }
- else
- {
- Action? setArgs = null;
foreach (var arg in typeInfo.CustomArgs)
{
setArgs +=
node => node?.SetDeferred(arg.Name, arg.ParseValue());
}
-
- newItemFunc = () =>
- {
- var newItem = NodeUtils.InstantiatePackedScene(scene);
- setArgs?.Invoke(newItem as Node);
- return newItem;
- };
}
+ //构造项目类型,寄存器
//construct item type, register
var itemType = new ItemType(typeInfo.Id,
- newItemFunc,
+ (defaultParentNode, assignedByRootNodeType) =>
+ {
+ var newItem = NodeUtils.InstantiatePackedScene(scene, defaultParentNode, assignedByRootNodeType);
+ setArgs?.Invoke(newItem as Node);
+ return newItem;
+ },
icon, typeInfo.MaxStackValue);
var succeed = ItemTypeManager.Register(itemType);
LogCat.LogWithFormat("register_item", itemType.Id, succeed);
diff --git a/scripts/loot/LootDatum.cs b/scripts/loot/LootDatum.cs
index 457b90d..eda0bea 100644
--- a/scripts/loot/LootDatum.cs
+++ b/scripts/loot/LootDatum.cs
@@ -1,5 +1,11 @@
namespace ColdMint.scripts.loot;
+///
+/// LootDatum
+/// 战利品数据
+///
+///
+///
public readonly record struct LootDatum(string ItemId, int Quantity)
{
public (string id, int quantity) Value => (ItemId, Quantity);
diff --git a/scripts/map/ItemSpawn.cs b/scripts/map/ItemSpawn.cs
new file mode 100644
index 0000000..2598cbc
--- /dev/null
+++ b/scripts/map/ItemSpawn.cs
@@ -0,0 +1,44 @@
+using ColdMint.scripts.debug;
+using ColdMint.scripts.inventory;
+using ColdMint.scripts.map.events;
+using Godot;
+
+namespace ColdMint.scripts.map;
+
+///
+/// ItemSpawn
+/// 物品出生点
+///
+public partial class ItemSpawn : Marker2D
+{
+ [Export] public string? ItemId { get; private set; }
+
+ public override void _Ready()
+ {
+ base._Ready();
+
+ EventManager.MapGenerationCompleteEvent += MapGenerationCompleteEvent;
+ }
+
+ private void MapGenerationCompleteEvent(MapGenerationCompleteEvent mapGenerationCompleteEvent)
+ {
+ //After the map is generated, create the item instance.
+ //当地图生成完成后,创建物品实例。
+ if (ItemId == null)
+ {
+ return;
+ }
+
+ var item = ItemTypeManager.CreateItem(ItemId,this);
+ if (item is Node2D node2D)
+ {
+ node2D.GlobalPosition = GlobalPosition;
+ }
+ }
+
+ public override void _ExitTree()
+ {
+ base._ExitTree();
+ EventManager.MapGenerationCompleteEvent -= MapGenerationCompleteEvent;
+ }
+}
\ No newline at end of file
diff --git a/scripts/utils/NodeUtils.cs b/scripts/utils/NodeUtils.cs
index e6558e9..cd00764 100644
--- a/scripts/utils/NodeUtils.cs
+++ b/scripts/utils/NodeUtils.cs
@@ -250,8 +250,10 @@ public static class NodeUtils
where T : class
{
var node = InstantiatePackedScene(packedScene, defaultParentNode, assignedByRootNodeType);
+ // Check the type conversion and return the result successfully
// 检查类型转化,成功返回结果
if (node is T result) return result;
+ // If the transformation fails, release the created node
//如果转型失败,释放所创建的节点
LogCat.LogWarningWithFormat("warning_node_cannot_cast_to", node, nameof(T));
node.QueueFree();