Preliminary rewrite of the loot system
初步重写掉落系统
This commit is contained in:
parent
edaa490b5b
commit
abf03c00a1
|
@ -1,4 +1,8 @@
|
||||||
- id: staff_of_the_undead
|
- id: staff_of_the_undead
|
||||||
scene_path: res://prefab/weapons/staffOfTheUndead.tscn
|
scene_path: res://prefab/weapons/staffOfTheUndead.tscn
|
||||||
icon_path: res://sprites/weapon/staffOfTheUndead.png
|
icon_path: res://sprites/weapon/staffOfTheUndead.png
|
||||||
max_stack_value: 1
|
max_stack_value: 1
|
||||||
|
custom_args:
|
||||||
|
- name: FiringIntervalAsMillisecond
|
||||||
|
type: int
|
||||||
|
value: 1000
|
||||||
|
|
|
@ -23,9 +23,11 @@ log_player_packed_scene_not_exist,玩家预制场景不存在。,Player packed s
|
||||||
log_exit_the_room_debug,节点{0}退出房间{1}。,"Node {0} exits room {1}.",ノード{0}が部屋{1}を退出します。
|
log_exit_the_room_debug,节点{0}退出房间{1}。,"Node {0} exits room {1}.",ノード{0}が部屋{1}を退出します。
|
||||||
log_enter_the_room_debug,节点{0}进入房间{1}。,"Node {0} enters room {1}.",ノード{0}が部屋{1}に入ります。
|
log_enter_the_room_debug,节点{0}进入房间{1}。,"Node {0} enters room {1}.",ノード{0}が部屋{1}に入ります。
|
||||||
log_death_info,生物{0}被{1}击败。,"Creature {0} was defeated by {1}.",生物{0}が{1}によって打ち負かされました。
|
log_death_info,生物{0}被{1}击败。,"Creature {0} was defeated by {1}.",生物{0}が{1}によって打ち負かされました。
|
||||||
|
|
||||||
log_loot_list_has_no_entries,ID为{0}的战利品表,没有指定条目。,"Loot list with ID {0}, no entry specified.",ID{0}の戦利品テーブルは、エントリ指定されていません。
|
log_loot_list_has_no_entries,ID为{0}的战利品表,没有指定条目。,"Loot list with ID {0}, no entry specified.",ID{0}の戦利品テーブルは、エントリ指定されていません。
|
||||||
log_not_within_the_loot_spawn_range,给定的数值{0}没有在战利品{1}的生成范围{2}内。,The given value {0} is not within the spawn range {2} of loot {1}.,与えられた数値{0}は戦利品{1}の生成範囲{2}内にありません。
|
log_not_within_the_loot_spawn_range,给定的数值{0}没有在战利品{1}的生成范围{2}内。,The given value {0} is not within the spawn range {2} of loot {1}.,与えられた数値{0}は戦利品{1}の生成範囲{2}内にありません。
|
||||||
log_loot_data_quantity,有{0}个战利品数据被返回。,{0} loot data was returned.,{0}個の戦利品データが返されます。
|
log_loot_data_quantity,有{0}个战利品数据被返回。,{0} loot data was returned.,{0}個の戦利品データが返されます。
|
||||||
|
log_loot_data_add,生成战利品{0},Add loot {0},戦利品{0}を生成する
|
||||||
|
|
||||||
log_warning_node_cannot_cast_to,创建的物品{0}无法被转型为类型{1},Created items {0} cannot be cast into type {1},作成されたアイテム {0} をタイプ {1} にキャストすることはできません。
|
log_warning_node_cannot_cast_to,创建的物品{0}无法被转型为类型{1},Created items {0} cannot be cast into type {1},作成されたアイテム {0} をタイプ {1} にキャストすることはできません。
|
||||||
|
|
||||||
|
|
|
|
@ -31,10 +31,10 @@ radius = 129.027
|
||||||
collision_layer = 64
|
collision_layer = 64
|
||||||
collision_mask = 38
|
collision_mask = 38
|
||||||
script = ExtResource("1_ubaid")
|
script = ExtResource("1_ubaid")
|
||||||
|
LootListId = "test"
|
||||||
metadata/CampId = "Mazoku"
|
metadata/CampId = "Mazoku"
|
||||||
metadata/MaxHp = 50
|
metadata/MaxHp = 50
|
||||||
metadata/Name = "死灵法师"
|
metadata/Name = "死灵法师"
|
||||||
metadata/LootListId = "Test"
|
|
||||||
|
|
||||||
[node name="CollisionShape2D" type="CollisionShape2D" parent="."]
|
[node name="CollisionShape2D" type="CollisionShape2D" parent="."]
|
||||||
position = Vector2(0, 4)
|
position = Vector2(0, 4)
|
||||||
|
|
|
@ -31,7 +31,7 @@ public static class Config
|
||||||
/// <para>A trophy table for testing</para>
|
/// <para>A trophy table for testing</para>
|
||||||
/// <para>测试用的战利品表</para>
|
/// <para>测试用的战利品表</para>
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public const string Test = "Test";
|
public const string Test = "test";
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
|
|
@ -10,6 +10,7 @@ using ColdMint.scripts.inventory;
|
||||||
using ColdMint.scripts.item;
|
using ColdMint.scripts.item;
|
||||||
using ColdMint.scripts.utils;
|
using ColdMint.scripts.utils;
|
||||||
using ColdMint.scripts.item.weapon;
|
using ColdMint.scripts.item.weapon;
|
||||||
|
using ColdMint.scripts.loot;
|
||||||
|
|
||||||
using Godot;
|
using Godot;
|
||||||
|
|
||||||
|
@ -107,11 +108,7 @@ public partial class CharacterTemplate : CharacterBody2D
|
||||||
|
|
||||||
private DamageNumberNodeSpawn? _damageNumber;
|
private DamageNumberNodeSpawn? _damageNumber;
|
||||||
|
|
||||||
/// <summary>
|
[Export] public string LootListId { get; private set; } = "";
|
||||||
/// <para>Character referenced loot table</para>
|
|
||||||
/// <para>角色引用的战利品表</para>
|
|
||||||
/// </summary>
|
|
||||||
private LootList? _lootList;
|
|
||||||
|
|
||||||
private HealthBar? _healthBar;
|
private HealthBar? _healthBar;
|
||||||
private DateTime _lastDamageTime;
|
private DateTime _lastDamageTime;
|
||||||
|
@ -208,12 +205,6 @@ public partial class CharacterTemplate : CharacterBody2D
|
||||||
CampId = GetMeta("CampId", Config.CampId.Default).AsString();
|
CampId = GetMeta("CampId", Config.CampId.Default).AsString();
|
||||||
MaxHp = GetMeta("MaxHp", Config.DefaultMaxHp).AsInt32();
|
MaxHp = GetMeta("MaxHp", Config.DefaultMaxHp).AsInt32();
|
||||||
var lootListId = GetMeta("LootListId", string.Empty).AsString();
|
var lootListId = GetMeta("LootListId", string.Empty).AsString();
|
||||||
if (!string.IsNullOrEmpty(lootListId))
|
|
||||||
{
|
|
||||||
//If a loot table is specified, get the loot table.
|
|
||||||
//如果指定了战利品表,那么获取战利品表。
|
|
||||||
_lootList = LootListManager.GetLootList(lootListId);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (MaxHp <= 0)
|
if (MaxHp <= 0)
|
||||||
{
|
{
|
||||||
|
@ -461,20 +452,11 @@ public partial class CharacterTemplate : CharacterBody2D
|
||||||
/// </summary>
|
/// </summary>
|
||||||
protected void CreateLootObject()
|
protected void CreateLootObject()
|
||||||
{
|
{
|
||||||
if (_lootList == null)
|
var lootData = LootListManager.GenerateLootData(LootListId);
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
var lootDataArray = _lootList.GenerateLootData();
|
|
||||||
if (lootDataArray.Length == 0)
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
var finalGlobalPosition = GlobalPosition;
|
var finalGlobalPosition = GlobalPosition;
|
||||||
CallDeferred("GenerateLootObjects", this, lootDataArray, finalGlobalPosition);
|
//Todo : change name str to nameof(), like this
|
||||||
|
// CallDeferred(nameof(GenerateLootObjects), this, lootData, finalGlobalPosition);
|
||||||
|
GenerateLootObjects(GetParent(), lootData, finalGlobalPosition);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
@ -482,13 +464,17 @@ public partial class CharacterTemplate : CharacterBody2D
|
||||||
/// <para>生成战利品对象</para>
|
/// <para>生成战利品对象</para>
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="parentNode"></param>
|
/// <param name="parentNode"></param>
|
||||||
/// <param name="lootDataArray"></param>
|
/// <param name="lootData"></param>
|
||||||
/// <param name="position"></param>
|
/// <param name="position"></param>
|
||||||
public void GenerateLootObjects(Node parentNode,
|
public void GenerateLootObjects(Node parentNode,
|
||||||
LootData[] lootDataArray,
|
IEnumerable<LootDatum> lootData,
|
||||||
Vector2 position)
|
Vector2 position)
|
||||||
{
|
{
|
||||||
LootListManager.GenerateLootObjects(parentNode, lootDataArray, position);
|
foreach (var lootDatum in lootData)
|
||||||
|
{
|
||||||
|
var (id, amount) = lootDatum.Value;
|
||||||
|
ItemTypeManager.CreateItems(id, amount, parentNode, position);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
@ -601,14 +587,8 @@ public partial class CharacterTemplate : CharacterBody2D
|
||||||
//Generates a random number that controls the horizontal velocity of thrown items (range: 0.01 to 1)
|
//Generates a random number that controls the horizontal velocity of thrown items (range: 0.01 to 1)
|
||||||
//生成一个随机数,用于控制抛出物品的水平方向速度(范围为:0.01到1)
|
//生成一个随机数,用于控制抛出物品的水平方向速度(范围为:0.01到1)
|
||||||
var percent = GD.Randf() + 0.01f;
|
var percent = GD.Randf() + 0.01f;
|
||||||
if (GD.Randf() > 0.5)
|
var horizontalVelocity = horizontalDirection * percent * GD.Randf() > 0.5 ? 1f : -1f;
|
||||||
{
|
ThrowItem(i, -1, new Vector2(horizontalVelocity, height));
|
||||||
ThrowItem(i, -1, new Vector2(horizontalDirection * percent, height));
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
ThrowItem(i, -1, new Vector2(-horizontalDirection * percent, height));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,9 +0,0 @@
|
||||||
using Godot;
|
|
||||||
|
|
||||||
namespace ColdMint.scripts.inventory;
|
|
||||||
|
|
||||||
public partial class LootData : GodotObject
|
|
||||||
{
|
|
||||||
public string? ResPath { get; set; }
|
|
||||||
public int Quantity { get; set; }
|
|
||||||
}
|
|
|
@ -1,32 +0,0 @@
|
||||||
namespace ColdMint.scripts.inventory;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// <para>Loot entry</para>
|
|
||||||
/// <para>战利品条目</para>
|
|
||||||
/// </summary>
|
|
||||||
public class LootEntry
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// <para>generation probability</para>
|
|
||||||
/// <para>生成概率</para>
|
|
||||||
/// </summary>
|
|
||||||
public double? Chance { get; set; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// <para>Minimum number of generated</para>
|
|
||||||
/// <para>最小生成多少个</para>
|
|
||||||
/// </summary>
|
|
||||||
public int MinQuantity { get; set; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// <para>The maximum number of files to be generated</para>
|
|
||||||
/// <para>最多生成多少个</para>
|
|
||||||
/// </summary>
|
|
||||||
public int MaxQuantity { get; set; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// <para>resources path</para>
|
|
||||||
/// <para>资源路径</para>
|
|
||||||
/// </summary>
|
|
||||||
public string? ResPath { get; set; }
|
|
||||||
}
|
|
|
@ -1,93 +0,0 @@
|
||||||
using System.Collections.Generic;
|
|
||||||
using ColdMint.scripts.debug;
|
|
||||||
using Godot;
|
|
||||||
|
|
||||||
namespace ColdMint.scripts.inventory;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// <para>Loot list</para>
|
|
||||||
/// <para>战利品表</para>
|
|
||||||
/// </summary>
|
|
||||||
public class LootList
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// <para>Id</para>
|
|
||||||
/// <para>战利品表的Id</para>
|
|
||||||
/// </summary>
|
|
||||||
public string? Id { get; set; }
|
|
||||||
|
|
||||||
private List<LootEntry>? _lootEntrieList;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// <para>Add loot entry</para>
|
|
||||||
/// <para>添加战利品条目</para>
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="lootEntry"></param>
|
|
||||||
public void AddLootEntry(LootEntry lootEntry)
|
|
||||||
{
|
|
||||||
if (_lootEntrieList == null)
|
|
||||||
{
|
|
||||||
_lootEntrieList = new List<LootEntry>();
|
|
||||||
}
|
|
||||||
|
|
||||||
_lootEntrieList.Add(lootEntry);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// <para>GenerateLootData</para>
|
|
||||||
/// <para>生成战利品数据</para>
|
|
||||||
/// </summary>
|
|
||||||
/// <returns></returns>
|
|
||||||
public LootData[] GenerateLootData()
|
|
||||||
{
|
|
||||||
var lootDataList = new List<LootData>();
|
|
||||||
if (_lootEntrieList == null)
|
|
||||||
{
|
|
||||||
LogCat.LogWithFormat("loot_list_has_no_entries", Id);
|
|
||||||
return lootDataList.ToArray();
|
|
||||||
}
|
|
||||||
|
|
||||||
foreach (var lootEntry in _lootEntrieList)
|
|
||||||
{
|
|
||||||
var chance = GD.Randf();
|
|
||||||
if (chance > lootEntry.Chance)
|
|
||||||
{
|
|
||||||
//If the random number is greater than the generation probability, skip the current loop.
|
|
||||||
//如果随机数大于生成概率,则跳过当前循环。
|
|
||||||
LogCat.LogWithFormat("not_within_the_loot_spawn_range", chance, lootEntry.ResPath, lootEntry.Chance);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
//We generate a loot data for each loot entry.
|
|
||||||
//我们为每个战利品条目生成一个战利品数据。
|
|
||||||
var quantity = GD.RandRange(lootEntry.MinQuantity, lootEntry.MaxQuantity);
|
|
||||||
var lootData = new LootData
|
|
||||||
{
|
|
||||||
ResPath = lootEntry.ResPath,
|
|
||||||
Quantity = quantity
|
|
||||||
};
|
|
||||||
lootDataList.Add(lootData);
|
|
||||||
}
|
|
||||||
|
|
||||||
LogCat.LogWithFormat("loot_data_quantity", lootDataList.Count);
|
|
||||||
return lootDataList.ToArray();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// <para>Remove loot entry</para>
|
|
||||||
/// <para>移除战利品条目</para>
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="lootEntry"></param>
|
|
||||||
/// <returns></returns>
|
|
||||||
public bool RemoveLootEntry(LootEntry lootEntry)
|
|
||||||
{
|
|
||||||
if (_lootEntrieList == null)
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
return _lootEntrieList.Remove(lootEntry);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,117 +0,0 @@
|
||||||
using System.Collections.Generic;
|
|
||||||
using ColdMint.scripts.utils;
|
|
||||||
using Godot;
|
|
||||||
|
|
||||||
namespace ColdMint.scripts.inventory;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// <para>LootListManager</para>
|
|
||||||
/// <para>战利品表管理器</para>
|
|
||||||
/// </summary>
|
|
||||||
public static class LootListManager
|
|
||||||
{
|
|
||||||
private static Dictionary<string, LootList>? _lootListDictionary;
|
|
||||||
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// <para>Register loot table</para>
|
|
||||||
/// <para>注册战利品表</para>
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="lootList"></param>
|
|
||||||
public static bool RegisterLootList(LootList lootList)
|
|
||||||
{
|
|
||||||
var id = lootList.Id;
|
|
||||||
if (id == null)
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (_lootListDictionary != null) return _lootListDictionary.TryAdd(id, lootList);
|
|
||||||
_lootListDictionary = new Dictionary<string, LootList> { { id, lootList } };
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// <para>Get Loot List</para>
|
|
||||||
/// <para>获取战利品表</para>
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="id"></param>
|
|
||||||
/// <returns></returns>
|
|
||||||
public static LootList? GetLootList(string id)
|
|
||||||
{
|
|
||||||
return _lootListDictionary?.GetValueOrDefault(id);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// <para>Generate loot objects</para>
|
|
||||||
/// <para>生成战利品对象</para>
|
|
||||||
/// </summary>
|
|
||||||
public static void GenerateLootObjects(Node parentNode, LootData[] lootDataArray, Vector2 position)
|
|
||||||
{
|
|
||||||
if (lootDataArray.Length == 0)
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
//Cache the loaded PackedScene object.
|
|
||||||
//缓存已加载的PackedScene对象。
|
|
||||||
Dictionary<string, PackedScene> packedSceneDictionary = new();
|
|
||||||
foreach (var lootData in lootDataArray)
|
|
||||||
{
|
|
||||||
if (string.IsNullOrEmpty(lootData.ResPath) || lootData.Quantity == 0)
|
|
||||||
{
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!packedSceneDictionary.TryGetValue(lootData.ResPath, out var packedScene))
|
|
||||||
{
|
|
||||||
packedScene = GD.Load<PackedScene>(lootData.ResPath);
|
|
||||||
packedSceneDictionary.TryAdd(lootData.ResPath, packedScene);
|
|
||||||
}
|
|
||||||
|
|
||||||
for (var i = 0; i < lootData.Quantity; i++)
|
|
||||||
{
|
|
||||||
//Generate as many loot instance objects as there are loot.
|
|
||||||
//有多少个战利品就生成多少个战利品实例对象。
|
|
||||||
CreateLootInstanceObject(parentNode, packedScene, position);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// <para>Create a loot instance object</para>
|
|
||||||
/// <para>创建战利品实例对象</para>
|
|
||||||
/// </summary>
|
|
||||||
private static void CreateLootInstanceObject(Node parent, PackedScene? packedScene, Vector2 position)
|
|
||||||
{
|
|
||||||
if (packedScene == null)
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
var lootObject = NodeUtils.InstantiatePackedScene<Node2D>(packedScene, parent);
|
|
||||||
if (lootObject == null)
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
lootObject.Position = position;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// <para>Remove loot list</para>
|
|
||||||
/// <para>移除战利品表</para>
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="id"></param>
|
|
||||||
/// <returns></returns>
|
|
||||||
public static bool UnregisterLootList(string id)
|
|
||||||
{
|
|
||||||
if (_lootListDictionary == null)
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
return _lootListDictionary.Remove(id);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,13 +1,9 @@
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
|
||||||
using ColdMint.scripts.debug;
|
|
||||||
using ColdMint.scripts.utils;
|
using ColdMint.scripts.utils;
|
||||||
|
|
||||||
using Godot;
|
using Godot;
|
||||||
|
|
||||||
using YamlDotNet.Serialization;
|
|
||||||
using YamlDotNet.Serialization.NamingConventions;
|
|
||||||
|
|
||||||
namespace ColdMint.scripts.item;
|
namespace ColdMint.scripts.item;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
@ -16,12 +12,6 @@ namespace ColdMint.scripts.item;
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public static class ItemTypeManager
|
public static class ItemTypeManager
|
||||||
{
|
{
|
||||||
/// <summary>
|
|
||||||
/// <para>Register items here</para>
|
|
||||||
/// <para>在这里注册物品</para>
|
|
||||||
/// </summary>
|
|
||||||
public static void StaticRegister() { }
|
|
||||||
|
|
||||||
private static Dictionary<string, ItemType> Registry { get; } = [];
|
private static Dictionary<string, ItemType> Registry { get; } = [];
|
||||||
private static Texture2D DefaultTexture { get; } = new PlaceholderTexture2D();
|
private static Texture2D DefaultTexture { get; } = new PlaceholderTexture2D();
|
||||||
|
|
||||||
|
@ -45,9 +35,66 @@ public static class ItemTypeManager
|
||||||
/// <para>Returns null when the id is not registered.</para>
|
/// <para>Returns null when the id is not registered.</para>
|
||||||
/// <para>当物品id没有注册时返回null</para>
|
/// <para>当物品id没有注册时返回null</para>
|
||||||
/// </returns>
|
/// </returns>
|
||||||
|
/// <seealso cref="NewItems"/><seealso cref="CreateItem"/>
|
||||||
public static IItem? NewItem(string id) =>
|
public static IItem? NewItem(string id) =>
|
||||||
Registry.TryGetValue(id, out var itemType) ? itemType.NewItemFunc() : null;
|
Registry.TryGetValue(id, out var itemType) ? itemType.NewItemFunc() : null;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// <para>Creates new instances in given amount of the item registered to the given id.</para>
|
||||||
|
/// <para>创建给定数量的注册到给定 id 的物品的新实例。</para>
|
||||||
|
/// </summary>
|
||||||
|
/// <returns></returns>
|
||||||
|
/// <seealso cref="NewItem"/><seealso cref="CreateItems"/>
|
||||||
|
public static IList<IItem> NewItems(string id, int amount)
|
||||||
|
{
|
||||||
|
IList<IItem> result = [];
|
||||||
|
for (int i = 0; i < amount; i++)
|
||||||
|
{
|
||||||
|
if (NewItem(id) is { } item) result.Add(item);
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// <para>Creates new instance of the item registered to the given id, and put it into given position in both node tree and 2D space</para>
|
||||||
|
/// <para>创建以给定 id 注册的物品的新实例,并将其放到节点树和二维空间中的给定位置</para>
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="id"></param>
|
||||||
|
/// <param name="parent"></param>
|
||||||
|
/// <param name="position">
|
||||||
|
/// <para>Position in global coordinate</para>
|
||||||
|
/// <para>全局坐标中的位置</para>
|
||||||
|
/// </param>
|
||||||
|
/// <seealso cref="NewItem"/><seealso cref="CreateItems"/>
|
||||||
|
public static void CreateItem(string id, Node? parent = null, Vector2? position = null)
|
||||||
|
{
|
||||||
|
var item = NewItem(id);
|
||||||
|
parent?.AddChild(item as Node);
|
||||||
|
if (item is not Node2D node) return;
|
||||||
|
if (position is { } pos) node.GlobalPosition = pos;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// <para>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</para>
|
||||||
|
/// <para>创建以给定 id 注册的物品的给定数量的新实例,并将其放到节点树和二维空间中的给定位置</para>
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="id"></param>
|
||||||
|
/// <param name="amount"></param>
|
||||||
|
/// <param name="parent"></param>
|
||||||
|
/// <param name="position">
|
||||||
|
/// <para>Position in global coordinate</para>
|
||||||
|
/// <para>全局坐标中的位置</para>
|
||||||
|
/// </param>
|
||||||
|
/// <seealso cref="NewItems"/><seealso cref="CreateItem"/>
|
||||||
|
public static void CreateItems(string id, int amount, Node? parent = null, Vector2? position = null)
|
||||||
|
{
|
||||||
|
for (int i = 0; i < amount; i++)
|
||||||
|
{
|
||||||
|
CreateItem(id, parent, position);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// <para>Get the translated default name of the item type for the given id</para>
|
/// <para>Get the translated default name of the item type for the given id</para>
|
||||||
/// <para>获取指定物品id翻译后的物品名</para>
|
/// <para>获取指定物品id翻译后的物品名</para>
|
||||||
|
|
|
@ -17,6 +17,12 @@ namespace ColdMint.scripts.item;
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public static class ItemTypeRegister
|
public static class ItemTypeRegister
|
||||||
{
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// <para>Register items here</para>
|
||||||
|
/// <para>在这里注册物品</para>
|
||||||
|
/// </summary>
|
||||||
|
public static void StaticRegister() { }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// <para>Register items from yaml file</para>
|
/// <para>Register items from yaml file</para>
|
||||||
/// <para>从文件注册物品</para>
|
/// <para>从文件注册物品</para>
|
||||||
|
|
|
@ -7,6 +7,7 @@ using ColdMint.scripts.deathInfo;
|
||||||
using ColdMint.scripts.debug;
|
using ColdMint.scripts.debug;
|
||||||
using ColdMint.scripts.inventory;
|
using ColdMint.scripts.inventory;
|
||||||
using ColdMint.scripts.item;
|
using ColdMint.scripts.item;
|
||||||
|
using ColdMint.scripts.loot;
|
||||||
using ColdMint.scripts.map;
|
using ColdMint.scripts.map;
|
||||||
using ColdMint.scripts.map.roomInjectionProcessor;
|
using ColdMint.scripts.map.roomInjectionProcessor;
|
||||||
|
|
||||||
|
@ -43,31 +44,6 @@ public partial class MainMenuLoader : UiLoaderTemplate
|
||||||
LogCat.MinLogLevel = LogCat.DisableAllLogLevel;
|
LogCat.MinLogLevel = LogCat.DisableAllLogLevel;
|
||||||
}
|
}
|
||||||
|
|
||||||
//注册测试使用的战利品表
|
|
||||||
if (Config.IsDebug())
|
|
||||||
{
|
|
||||||
var testLootList = new LootList
|
|
||||||
{
|
|
||||||
Id = Config.LootListId.Test
|
|
||||||
};
|
|
||||||
var staffOfTheUndead = new LootEntry
|
|
||||||
{
|
|
||||||
Chance = 0.05f,
|
|
||||||
MaxQuantity = 5,
|
|
||||||
MinQuantity = 1,
|
|
||||||
ResPath = "res://prefab/weapons/staffOfTheUndead.tscn"
|
|
||||||
};
|
|
||||||
testLootList.AddLootEntry(staffOfTheUndead);
|
|
||||||
var packsack = new LootEntry
|
|
||||||
{
|
|
||||||
Chance = 1f,
|
|
||||||
MaxQuantity = 1,
|
|
||||||
MinQuantity = 1,
|
|
||||||
ResPath = "res://prefab/packsacks/packsack.tscn"
|
|
||||||
};
|
|
||||||
testLootList.AddLootEntry(packsack);
|
|
||||||
LootListManager.RegisterLootList(testLootList);
|
|
||||||
}
|
|
||||||
|
|
||||||
DeathInfoGenerator.RegisterDeathInfoHandler(new SelfDeathInfoHandler());
|
DeathInfoGenerator.RegisterDeathInfoHandler(new SelfDeathInfoHandler());
|
||||||
MapGenerator.RegisterRoomInjectionProcessor(new ChanceRoomInjectionProcessor());
|
MapGenerator.RegisterRoomInjectionProcessor(new ChanceRoomInjectionProcessor());
|
||||||
|
@ -82,6 +58,7 @@ public partial class MainMenuLoader : UiLoaderTemplate
|
||||||
Directory.CreateDirectory(dataPath);
|
Directory.CreateDirectory(dataPath);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
//Registered camp
|
//Registered camp
|
||||||
//注册阵营
|
//注册阵营
|
||||||
var defaultCamp = new Camp(Config.CampId.Default)
|
var defaultCamp = new Camp(Config.CampId.Default)
|
||||||
|
@ -94,13 +71,16 @@ public partial class MainMenuLoader : UiLoaderTemplate
|
||||||
var aborigines = new Camp(Config.CampId.Aborigines);
|
var aborigines = new Camp(Config.CampId.Aborigines);
|
||||||
CampManager.AddCamp(aborigines);
|
CampManager.AddCamp(aborigines);
|
||||||
_gameScene = (PackedScene)GD.Load("res://scenes/game.tscn");
|
_gameScene = (PackedScene)GD.Load("res://scenes/game.tscn");
|
||||||
|
|
||||||
//Register ItemTypes from file
|
//Register ItemTypes from file
|
||||||
//从文件注册物品类型
|
//从文件注册物品类型
|
||||||
ItemTypeRegister.RegisterFromFile();
|
ItemTypeRegister.RegisterFromFile();
|
||||||
//Hardcoded ItemTypes Register
|
//Hardcoded ItemTypes Register
|
||||||
//硬编码注册物品类型
|
//硬编码注册物品类型
|
||||||
ItemTypeManager.StaticRegister();
|
ItemTypeRegister.StaticRegister();
|
||||||
|
|
||||||
|
//静态注册掉落表
|
||||||
|
LootRegister.StaticRegister();
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void InitializeUi()
|
public override void InitializeUi()
|
||||||
|
|
8
scripts/loot/LootDatum.cs
Normal file
8
scripts/loot/LootDatum.cs
Normal file
|
@ -0,0 +1,8 @@
|
||||||
|
using Godot;
|
||||||
|
|
||||||
|
namespace ColdMint.scripts.loot;
|
||||||
|
|
||||||
|
public readonly record struct LootDatum(string ItemId, int Quantity)
|
||||||
|
{
|
||||||
|
public (string id, int quantity) Value => (ItemId, Quantity);
|
||||||
|
}
|
68
scripts/loot/LootEntry.cs
Normal file
68
scripts/loot/LootEntry.cs
Normal file
|
@ -0,0 +1,68 @@
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
|
||||||
|
using ColdMint.scripts.utils;
|
||||||
|
|
||||||
|
namespace ColdMint.scripts.loot;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// <para>Loot entry</para>
|
||||||
|
/// <para>战利品条目</para>
|
||||||
|
/// </summary>
|
||||||
|
public readonly struct LootEntry(string itemId,int minQuantity=1,int maxQuantity = 1,int weight = 1)
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// <para>ID of item</para>
|
||||||
|
/// <para>物品ID</para>
|
||||||
|
/// </summary>
|
||||||
|
public string ItemId { get; init; } = itemId;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// <para>Minimum number of generated</para>
|
||||||
|
/// <para>最小生成多少个</para>
|
||||||
|
/// </summary>
|
||||||
|
public int MinQuantity { get; init; } = minQuantity;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// <para>The maximum number of files to be generated</para>
|
||||||
|
/// <para>最多生成多少个</para>
|
||||||
|
/// </summary>
|
||||||
|
public int MaxQuantity { get; init; } = maxQuantity;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// <para>Weight of probability within the drop group</para>
|
||||||
|
/// <para>在掉落组内的生成权重</para>
|
||||||
|
/// </summary>
|
||||||
|
public int Weight { get; init; } = weight;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// <para>Loot Group</para>
|
||||||
|
/// <para>战利品分组</para>
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="Chance"></param>
|
||||||
|
/// <param name="Entries"></param>
|
||||||
|
public readonly record struct LootGroup(double Chance, IEnumerable<LootEntry> Entries)
|
||||||
|
{
|
||||||
|
private int WeightSum { get; } = Entries.Sum(entry => entry.Weight);
|
||||||
|
|
||||||
|
public LootDatum GenerateLootData()
|
||||||
|
{
|
||||||
|
var random = RandomUtils.Instance;
|
||||||
|
var w = random.Next(WeightSum);
|
||||||
|
LootEntry entry = default;
|
||||||
|
foreach (var e in Entries)
|
||||||
|
{
|
||||||
|
w -= e.Weight;
|
||||||
|
if (w < 0)
|
||||||
|
{
|
||||||
|
entry = e;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var quantity = random.Next(entry.MinQuantity, entry.MaxQuantity + 1);
|
||||||
|
|
||||||
|
return new(entry.ItemId, quantity);
|
||||||
|
}
|
||||||
|
}
|
53
scripts/loot/LootList.cs
Normal file
53
scripts/loot/LootList.cs
Normal file
|
@ -0,0 +1,53 @@
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
|
||||||
|
using ColdMint.scripts.debug;
|
||||||
|
using ColdMint.scripts.utils;
|
||||||
|
|
||||||
|
using Godot;
|
||||||
|
|
||||||
|
namespace ColdMint.scripts.loot;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// <para>Loot list</para>
|
||||||
|
/// <para>战利品表</para>
|
||||||
|
/// </summary>
|
||||||
|
public readonly struct LootList(string id, IList<LootGroup> groups)
|
||||||
|
{
|
||||||
|
public string Id { get; } = id;
|
||||||
|
private IList<LootGroup> Groups { get; } = groups;
|
||||||
|
|
||||||
|
private static Random Random => RandomUtils.Instance;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// <para>GenerateLootData</para>
|
||||||
|
/// <para>生成战利品数据</para>
|
||||||
|
/// </summary>
|
||||||
|
/// <returns></returns>
|
||||||
|
public LootDatum[] GenerateLootData()
|
||||||
|
{
|
||||||
|
if (Groups is [])
|
||||||
|
{
|
||||||
|
LogCat.LogWithFormat("loot_list_has_no_entries", Id);
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
|
||||||
|
var lootDataList = new List<LootDatum>();
|
||||||
|
foreach (var group in Groups)
|
||||||
|
{
|
||||||
|
//If the random number is greater than the generation probability, skip the current loop.
|
||||||
|
//如果随机数大于生成概率,则跳过当前循环。
|
||||||
|
var rd = Random.NextDouble();
|
||||||
|
if (rd > group.Chance) continue;
|
||||||
|
|
||||||
|
//We generate a loot data for each loot entry.
|
||||||
|
//我们为每个战利品条目生成一个战利品数据。
|
||||||
|
var datum = group.GenerateLootData();
|
||||||
|
lootDataList.Add(datum);
|
||||||
|
LogCat.LogWithFormat("loot_data_add", datum);
|
||||||
|
}
|
||||||
|
|
||||||
|
LogCat.LogWithFormat("loot_data_quantity", lootDataList.Count);
|
||||||
|
return lootDataList.ToArray();
|
||||||
|
}
|
||||||
|
}
|
51
scripts/loot/LootListManager.cs
Normal file
51
scripts/loot/LootListManager.cs
Normal file
|
@ -0,0 +1,51 @@
|
||||||
|
using System.Collections.Generic;
|
||||||
|
|
||||||
|
using ColdMint.scripts.utils;
|
||||||
|
|
||||||
|
using Godot;
|
||||||
|
|
||||||
|
namespace ColdMint.scripts.loot;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// <para>LootListManager</para>
|
||||||
|
/// <para>战利品表管理器</para>
|
||||||
|
/// </summary>
|
||||||
|
public static class LootListManager
|
||||||
|
{
|
||||||
|
private static Dictionary<string, LootList> LootListDictionary { get; } = [];
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// <para>Register loot table</para>
|
||||||
|
/// <para>注册战利品表</para>
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="lootList"></param>
|
||||||
|
public static bool RegisterLootList(LootList lootList)
|
||||||
|
{
|
||||||
|
var id = lootList.Id;
|
||||||
|
if (id is "") return false;
|
||||||
|
return LootListDictionary.TryAdd(id, lootList);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// <para>Remove loot list</para>
|
||||||
|
/// <para>移除战利品表</para>
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="id"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
public static bool UnregisterLootList(string id)
|
||||||
|
{
|
||||||
|
return LootListDictionary.Remove(id);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// <para>Generate an loot data.</para>
|
||||||
|
/// <para>获取掉落物品</para>
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="id"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
public static IEnumerable<LootDatum> GenerateLootData(string id)
|
||||||
|
{
|
||||||
|
if (!LootListDictionary.TryGetValue(id, out var list)) return [];
|
||||||
|
return list.GenerateLootData();
|
||||||
|
}
|
||||||
|
}
|
30
scripts/loot/LootRegister.cs
Normal file
30
scripts/loot/LootRegister.cs
Normal file
|
@ -0,0 +1,30 @@
|
||||||
|
using System.Collections.Generic;
|
||||||
|
|
||||||
|
namespace ColdMint.scripts.loot;
|
||||||
|
|
||||||
|
public static class LootRegister
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// <para>Register loots hardcoded here</para>
|
||||||
|
/// <para>在这里硬编码地注册掉落表</para>
|
||||||
|
/// </summary>
|
||||||
|
public static void StaticRegister()
|
||||||
|
{
|
||||||
|
//注册测试使用的战利品表
|
||||||
|
if (Config.IsDebug())
|
||||||
|
{
|
||||||
|
IList<LootGroup> lootGroups = [];
|
||||||
|
lootGroups.Add(new LootGroup(1,
|
||||||
|
[
|
||||||
|
new LootEntry("packsack", weight: 2), new LootEntry("staff_of_the_undead", minQuantity: 2, maxQuantity: 4)
|
||||||
|
]));
|
||||||
|
lootGroups.Add(new LootGroup(0.3,
|
||||||
|
[
|
||||||
|
new LootEntry("packsack")
|
||||||
|
]));
|
||||||
|
|
||||||
|
var testLootList = new LootList(Config.LootListId.Test, lootGroups);
|
||||||
|
LootListManager.RegisterLootList(testLootList);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
8
scripts/utils/RandomUtils.cs
Normal file
8
scripts/utils/RandomUtils.cs
Normal file
|
@ -0,0 +1,8 @@
|
||||||
|
using System;
|
||||||
|
|
||||||
|
namespace ColdMint.scripts.utils;
|
||||||
|
|
||||||
|
public static class RandomUtils
|
||||||
|
{
|
||||||
|
public static Random Instance { get; } = new();
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user