诸多更新和问题修复 (#97)

* 添加 OpenFactory,可以动态扩展技能和物品

* 修改 Effect 的反序列化解析;增加对闪避/暴击判定的先前事件编程接口

* 补充魔法伤害的判定

* 装备系统优化;角色的复制问题修复

* 添加物品品质;更新装备饰品替换机制;添加第一滴血、团队模式

* 添加技能选取

* 添加团队死斗模式
This commit is contained in:
milimoe 2024-11-04 09:30:26 +08:00 committed by GitHub
parent 60ae91e488
commit 3db586cab2
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
42 changed files with 1869 additions and 609 deletions

View File

@ -1,7 +1,7 @@
using Milimoe.FunGame.Core.Entity; using Milimoe.FunGame.Core.Entity;
using Milimoe.FunGame.Core.Interface.Base; using Milimoe.FunGame.Core.Interface.Base;
namespace Milimoe.FunGame.Core.Api.Factory namespace Milimoe.FunGame.Core.Api.EntityFactory
{ {
internal class CharacterFactory : IFactory<Character> internal class CharacterFactory : IFactory<Character>
{ {

View File

@ -1,7 +1,7 @@
using Milimoe.FunGame.Core.Entity; using Milimoe.FunGame.Core.Entity;
using Milimoe.FunGame.Core.Interface.Base; using Milimoe.FunGame.Core.Interface.Base;
namespace Milimoe.FunGame.Core.Api.Factory namespace Milimoe.FunGame.Core.Api.EntityFactory
{ {
internal class EffectFactory : IFactory<Effect> internal class EffectFactory : IFactory<Effect>
{ {

View File

@ -2,7 +2,7 @@
using Milimoe.FunGame.Core.Interface.Base; using Milimoe.FunGame.Core.Interface.Base;
using Milimoe.FunGame.Core.Library.Constant; using Milimoe.FunGame.Core.Library.Constant;
namespace Milimoe.FunGame.Core.Api.Factory namespace Milimoe.FunGame.Core.Api.EntityFactory
{ {
internal class InventoryFactory : IFactory<Inventory> internal class InventoryFactory : IFactory<Inventory>
{ {

View File

@ -1,7 +1,7 @@
using Milimoe.FunGame.Core.Entity; using Milimoe.FunGame.Core.Entity;
using Milimoe.FunGame.Core.Interface.Base; using Milimoe.FunGame.Core.Interface.Base;
namespace Milimoe.FunGame.Core.Api.Factory namespace Milimoe.FunGame.Core.Api.EntityFactory
{ {
internal class ItemFactory : IFactory<Item> internal class ItemFactory : IFactory<Item>
{ {

View File

@ -2,7 +2,7 @@
using Milimoe.FunGame.Core.Interface.Base; using Milimoe.FunGame.Core.Interface.Base;
using Milimoe.FunGame.Core.Library.Constant; using Milimoe.FunGame.Core.Library.Constant;
namespace Milimoe.FunGame.Core.Api.Factory namespace Milimoe.FunGame.Core.Api.EntityFactory
{ {
internal class RoomFactory : IFactory<Room> internal class RoomFactory : IFactory<Room>
{ {

View File

@ -1,7 +1,7 @@
using Milimoe.FunGame.Core.Entity; using Milimoe.FunGame.Core.Entity;
using Milimoe.FunGame.Core.Interface.Base; using Milimoe.FunGame.Core.Interface.Base;
namespace Milimoe.FunGame.Core.Api.Factory namespace Milimoe.FunGame.Core.Api.EntityFactory
{ {
internal class SkillFactory : IFactory<Skill> internal class SkillFactory : IFactory<Skill>
{ {

View File

@ -2,7 +2,7 @@ using Milimoe.FunGame.Core.Entity;
using Milimoe.FunGame.Core.Interface.Base; using Milimoe.FunGame.Core.Interface.Base;
using Milimoe.FunGame.Core.Library.Constant; using Milimoe.FunGame.Core.Library.Constant;
namespace Milimoe.FunGame.Core.Api.Factory namespace Milimoe.FunGame.Core.Api.EntityFactory
{ {
internal class UserFactory : IFactory<User> internal class UserFactory : IFactory<User>
{ {

View File

@ -0,0 +1,20 @@
using Milimoe.FunGame.Core.Api.Utility;
using Milimoe.FunGame.Core.Entity;
namespace Milimoe.FunGame.Core.Api.OpenEntityAdapter
{
public class OpenItemAdapter
{
public static void Adaptation<T>(EntityModuleConfig<T> config) where T : BaseEntity
{
foreach (string key in config.Keys)
{
if (config[key] is Item prev)
{
Item next = prev.Copy();
if (next is T t) config[key] = t;
}
}
}
}
}

View File

@ -0,0 +1,20 @@
using Milimoe.FunGame.Core.Api.Utility;
using Milimoe.FunGame.Core.Entity;
namespace Milimoe.FunGame.Core.Api.OpenEntityAdapter
{
public class OpenSkillAdapter
{
public static void Adaptation<T>(EntityModuleConfig<T> config) where T : BaseEntity
{
foreach (string key in config.Keys)
{
if (config[key] is Skill prev)
{
Skill next = prev.Copy();
if (next is T t) config[key] = t;
}
}
}
}
}

View File

@ -4,7 +4,7 @@ using Milimoe.FunGame.Core.Library.Constant;
namespace Milimoe.FunGame.Core.Api.Utility namespace Milimoe.FunGame.Core.Api.Utility
{ {
/// <summary> /// <summary>
/// 简易的实体模组配置文件生成器<para/> /// 简易的实体模组配置文件生成器,适用范围:动态扩展技能和物品、保存玩家的存档<para/>
/// 仅支持继承了 <see cref="BaseEntity"/> 的实体类型,每个 <see cref="EntityModuleConfig{T}"/> 仅保存一种实体类型的数据 /// 仅支持继承了 <see cref="BaseEntity"/> 的实体类型,每个 <see cref="EntityModuleConfig{T}"/> 仅保存一种实体类型的数据
/// <para/>文件会保存为:程序目录/configs/<see cref="ModuleName"/>/<see cref="FileName"/>.json /// <para/>文件会保存为:程序目录/configs/<see cref="ModuleName"/>/<see cref="FileName"/>.json
/// </summary> /// </summary>

View File

@ -1,5 +1,6 @@
using System.Data; using System.Data;
using Milimoe.FunGame.Core.Api.Factory; using Milimoe.FunGame.Core.Api.EntityFactory;
using Milimoe.FunGame.Core.Api.OpenEntityAdapter;
using Milimoe.FunGame.Core.Entity; using Milimoe.FunGame.Core.Entity;
using Milimoe.FunGame.Core.Library.Constant; using Milimoe.FunGame.Core.Library.Constant;
using Milimoe.FunGame.Core.Library.SQLScript.Entity; using Milimoe.FunGame.Core.Library.SQLScript.Entity;
@ -8,6 +9,194 @@ namespace Milimoe.FunGame.Core.Api.Utility
{ {
public class Factory public class Factory
{ {
/// <summary>
/// 支持动态扩展的工厂实例
/// </summary>
public static Factory OpenFactory { get; } = new();
private Factory()
{
}
internal HashSet<EntityFactoryDelegate<Character>> CharacterFactories { get; } = [];
internal HashSet<EntityFactoryDelegate<Inventory>> InventoryFactories { get; } = [];
internal HashSet<EntityFactoryDelegate<Skill>> SkillFactories { get; } = [];
internal HashSet<EntityFactoryDelegate<Effect>> EffectFactories { get; } = [];
internal HashSet<EntityFactoryDelegate<Item>> ItemFactories { get; } = [];
internal HashSet<EntityFactoryDelegate<Room>> RoomFactories { get; } = [];
internal HashSet<EntityFactoryDelegate<User>> UserFactories { get; } = [];
public delegate T? EntityFactoryDelegate<T>(long id, string name, Dictionary<string, object> args);
/// <summary>
/// 注册工厂方法
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="d"></param>
public void RegisterFactory<T>(EntityFactoryDelegate<T> d)
{
if (typeof(T) == typeof(Character) && d is EntityFactoryDelegate<Character> character)
{
CharacterFactories.Add(character);
}
if (typeof(T) == typeof(Inventory) && d is EntityFactoryDelegate<Inventory> inventory)
{
InventoryFactories.Add(inventory);
}
if (typeof(T) == typeof(Skill) && d is EntityFactoryDelegate<Skill> skill)
{
SkillFactories.Add(skill);
}
if (typeof(T) == typeof(Effect) && d is EntityFactoryDelegate<Effect> effect)
{
EffectFactories.Add(effect);
}
if (typeof(T) == typeof(Item) && d is EntityFactoryDelegate<Item> item)
{
ItemFactories.Add(item);
}
if (typeof(T) == typeof(Room) && d is EntityFactoryDelegate<Room> room)
{
RoomFactories.Add(room);
}
if (typeof(T) == typeof(User) && d is EntityFactoryDelegate<User> user)
{
UserFactories.Add(user);
}
}
/// <summary>
/// 构造一个实体实例
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="id"></param>
/// <param name="name"></param>
/// <param name="args"></param>
/// <returns></returns>
/// <exception cref="NotSupportedInstanceClassException"></exception>
public T GetInstance<T>(long id, string name, Dictionary<string, object> args)
{
if (typeof(T) == typeof(Character))
{
foreach (EntityFactoryDelegate<Character> d in CharacterFactories)
{
if (d.Invoke(id, name, args) is T character)
{
return character;
}
}
return (T)(object)GetCharacter();
}
if (typeof(T) == typeof(Inventory))
{
foreach (EntityFactoryDelegate<Inventory> d in InventoryFactories)
{
if (d.Invoke(id, name, args) is T inventory)
{
return inventory;
}
}
return (T)(object)GetInventory();
}
if (typeof(T) == typeof(Skill))
{
foreach (EntityFactoryDelegate<Skill> d in SkillFactories)
{
if (d.Invoke(id, name, args) is T skill)
{
return skill;
}
}
return (T)(object)new OpenSkill(id, name, args);
}
if (typeof(T) == typeof(Effect))
{
foreach (EntityFactoryDelegate<Effect> d in EffectFactories)
{
if (d.Invoke(id, name, args) is T effect)
{
return effect;
}
}
return (T)(object)GetEffect();
}
if (typeof(T) == typeof(Item))
{
foreach (EntityFactoryDelegate<Item> d in ItemFactories)
{
if (d.Invoke(id, name, args) is T item)
{
return item;
}
}
return (T)(object)GetItem();
}
if (typeof(T) == typeof(Room))
{
foreach (EntityFactoryDelegate<Room> d in RoomFactories)
{
if (d.Invoke(id, name, args) is T room)
{
return room;
}
}
return (T)(object)GetRoom();
}
if (typeof(T) == typeof(User))
{
foreach (EntityFactoryDelegate<User> d in UserFactories)
{
if (d.Invoke(id, name, args) is T user)
{
return user;
}
}
return (T)(object)GetUser();
}
throw new NotSupportedInstanceClassException();
}
/// <summary>
/// 此方法使用 <see cref="EntityModuleConfig{T}"/> 取得一个实体字典
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="module_name"></param>
/// <param name="file_name"></param>
/// <returns></returns>
public static Dictionary<string, T> GetGameModuleInstances<T>(string module_name, string file_name) where T : BaseEntity
{
EntityModuleConfig<T> config = new(module_name, file_name);
config.LoadConfig();
if (typeof(T) == typeof(Skill))
{
OpenSkillAdapter.Adaptation(config);
}
if (typeof(T) == typeof(Item))
{
OpenItemAdapter.Adaptation(config);
}
return config;
}
/// <summary>
/// 使用 <see cref="EntityModuleConfig{T}"/> 构造一个实体字典并保存
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="module_name"></param>
/// <param name="file_name"></param>
/// <param name="dict"></param>
/// <returns></returns>
public static void CreateGameModuleEntityConfig<T>(string module_name, string file_name, Dictionary<string, T> dict) where T : BaseEntity
{
EntityModuleConfig<T> config = new(module_name, file_name);
foreach (string key in dict.Keys)
{
config[key] = dict[key];
}
config.SaveConfig();
}
private readonly static CharacterFactory CharacterFactory = new(); private readonly static CharacterFactory CharacterFactory = new();
private readonly static InventoryFactory InventoryFactory = new(); private readonly static InventoryFactory InventoryFactory = new();
private readonly static SkillFactory SkillFactory = new(); private readonly static SkillFactory SkillFactory = new();
@ -152,7 +341,7 @@ namespace Milimoe.FunGame.Core.Api.Utility
/// 获取大厅(-1号房 /// 获取大厅(-1号房
/// </summary> /// </summary>
/// <returns></returns> /// <returns></returns>
internal static Room GetHall() public static Room GetHall()
{ {
return RoomFactory.Create(); return RoomFactory.Create();
} }

View File

@ -1,4 +1,3 @@
using System.Collections;
using Milimoe.FunGame.Core.Library.Common.Addon; using Milimoe.FunGame.Core.Library.Common.Addon;
using Milimoe.FunGame.Core.Library.Constant; using Milimoe.FunGame.Core.Library.Constant;
using Milimoe.FunGame.Core.Service; using Milimoe.FunGame.Core.Service;

View File

@ -1,5 +1,4 @@
using System.Collections; using Milimoe.FunGame.Core.Api.Transmittal;
using Milimoe.FunGame.Core.Api.Transmittal;
using Milimoe.FunGame.Core.Interface.Addons; using Milimoe.FunGame.Core.Interface.Addons;
using Milimoe.FunGame.Core.Library.Constant; using Milimoe.FunGame.Core.Library.Constant;

View File

@ -809,7 +809,7 @@ namespace Milimoe.FunGame.Core.Entity
/// </summary> /// </summary>
/// <param name="item"></param> /// <param name="item"></param>
/// <param name="slot"></param> /// <param name="slot"></param>
public bool Equip(Item item, EquipItemToSlot slot) public bool Equip(Item item, EquipSlotType slot)
{ {
bool result = false; bool result = false;
double pastHP = HP; double pastHP = HP;
@ -818,57 +818,59 @@ namespace Milimoe.FunGame.Core.Entity
double pastMaxMP = MaxMP; double pastMaxMP = MaxMP;
switch (slot) switch (slot)
{ {
case EquipItemToSlot.MagicCardPack: case EquipSlotType.MagicCardPack:
if (item.ItemType == ItemType.MagicCardPack) if (item.ItemType == ItemType.MagicCardPack)
{ {
UnEquip(EquipItemToSlot.MagicCardPack); UnEquip(EquipSlotType.MagicCardPack);
EquipSlot.MagicCardPack = item; EquipSlot.MagicCardPack = item;
item.OnItemEquip(this, EquipItemToSlot.MagicCardPack); item.OnItemEquip(this, EquipSlotType.MagicCardPack);
result = true; result = true;
} }
break; break;
case EquipItemToSlot.Weapon: case EquipSlotType.Weapon:
if (item.ItemType == ItemType.Weapon) if (item.ItemType == ItemType.Weapon)
{ {
UnEquip(EquipItemToSlot.Weapon); UnEquip(EquipSlotType.Weapon);
EquipSlot.Weapon = item; EquipSlot.Weapon = item;
item.OnItemEquip(this, EquipItemToSlot.Weapon); item.OnItemEquip(this, EquipSlotType.Weapon);
result = true; result = true;
} }
break; break;
case EquipItemToSlot.Armor: case EquipSlotType.Armor:
if (item.ItemType == ItemType.Armor) if (item.ItemType == ItemType.Armor)
{ {
UnEquip(EquipItemToSlot.Armor); UnEquip(EquipSlotType.Armor);
EquipSlot.Armor = item; EquipSlot.Armor = item;
item.OnItemEquip(this, EquipItemToSlot.Armor); item.OnItemEquip(this, EquipSlotType.Armor);
result = true; result = true;
} }
break; break;
case EquipItemToSlot.Shoes: case EquipSlotType.Shoes:
if (item.ItemType == ItemType.Shoes) if (item.ItemType == ItemType.Shoes)
{ {
UnEquip(EquipItemToSlot.Shoes); UnEquip(EquipSlotType.Shoes);
EquipSlot.Shoes = item; EquipSlot.Shoes = item;
item.OnItemEquip(this, EquipItemToSlot.Shoes); item.OnItemEquip(this, EquipSlotType.Shoes);
result = true; result = true;
} }
break; break;
case EquipItemToSlot.Accessory1: case EquipSlotType.Accessory1:
if (item.ItemType == ItemType.Accessory) if (item.ItemType == ItemType.Accessory)
{ {
UnEquip(EquipItemToSlot.Accessory1); UnEquip(EquipSlotType.Accessory1);
EquipSlot.Accessory1 = item; EquipSlot.Accessory1 = item;
item.OnItemEquip(this, EquipItemToSlot.Accessory1); EquipSlot.LastEquipSlotType = EquipSlotType.Accessory1;
item.OnItemEquip(this, EquipSlotType.Accessory1);
result = true; result = true;
} }
break; break;
case EquipItemToSlot.Accessory2: case EquipSlotType.Accessory2:
if (item.ItemType == ItemType.Accessory) if (item.ItemType == ItemType.Accessory)
{ {
UnEquip(EquipItemToSlot.Accessory2); UnEquip(EquipSlotType.Accessory2);
EquipSlot.Accessory2 = item; EquipSlot.Accessory2 = item;
item.OnItemEquip(this, EquipItemToSlot.Accessory2); EquipSlot.LastEquipSlotType = EquipSlotType.Accessory2;
item.OnItemEquip(this, EquipSlotType.Accessory2);
result = true; result = true;
} }
break; break;
@ -891,21 +893,29 @@ namespace Milimoe.FunGame.Core.Entity
switch (item.ItemType) switch (item.ItemType)
{ {
case ItemType.MagicCardPack: case ItemType.MagicCardPack:
return Equip(item, EquipItemToSlot.MagicCardPack); return Equip(item, EquipSlotType.MagicCardPack);
case ItemType.Weapon: case ItemType.Weapon:
return Equip(item, EquipItemToSlot.Weapon); return Equip(item, EquipSlotType.Weapon);
case ItemType.Armor: case ItemType.Armor:
return Equip(item, EquipItemToSlot.Armor); return Equip(item, EquipSlotType.Armor);
case ItemType.Shoes: case ItemType.Shoes:
return Equip(item, EquipItemToSlot.Shoes); return Equip(item, EquipSlotType.Shoes);
case ItemType.Accessory: case ItemType.Accessory:
if (EquipSlot.Accessory1 != null && EquipSlot.Accessory2 is null) if (EquipSlot.Accessory1 is null)
{ {
return Equip(item, EquipItemToSlot.Accessory2); return Equip(item, EquipSlotType.Accessory1);
}
else if (EquipSlot.Accessory1 != null && EquipSlot.Accessory2 is null)
{
return Equip(item, EquipSlotType.Accessory2);
}
else if (EquipSlot.Accessory1 != null && EquipSlot.Accessory2 != null && EquipSlot.LastEquipSlotType == EquipSlotType.Accessory1)
{
return Equip(item, EquipSlotType.Accessory2);
} }
else else
{ {
return Equip(item, EquipItemToSlot.Accessory1); return Equip(item, EquipSlotType.Accessory1);
} }
} }
return false; return false;
@ -916,51 +926,51 @@ namespace Milimoe.FunGame.Core.Entity
/// </summary> /// </summary>
/// <param name="type"></param> /// <param name="type"></param>
/// <returns></returns> /// <returns></returns>
public Item? UnEquip(EquipItemToSlot type) public Item? UnEquip(EquipSlotType type)
{ {
Item? result = null; Item? result = null;
switch (type) switch (type)
{ {
case EquipItemToSlot.MagicCardPack: case EquipSlotType.MagicCardPack:
if (EquipSlot.MagicCardPack != null) if (EquipSlot.MagicCardPack != null)
{ {
result = EquipSlot.MagicCardPack; result = EquipSlot.MagicCardPack;
EquipSlot.MagicCardPack.OnItemUnEquip(EquipItemToSlot.MagicCardPack); EquipSlot.MagicCardPack.OnItemUnEquip(EquipSlotType.MagicCardPack);
} }
break; break;
case EquipItemToSlot.Weapon: case EquipSlotType.Weapon:
if (EquipSlot.Weapon != null) if (EquipSlot.Weapon != null)
{ {
result = EquipSlot.Weapon; result = EquipSlot.Weapon;
EquipSlot.Weapon.OnItemUnEquip(EquipItemToSlot.Weapon); EquipSlot.Weapon.OnItemUnEquip(EquipSlotType.Weapon);
} }
break; break;
case EquipItemToSlot.Armor: case EquipSlotType.Armor:
if (EquipSlot.Armor != null) if (EquipSlot.Armor != null)
{ {
result = EquipSlot.Armor; result = EquipSlot.Armor;
EquipSlot.Armor.OnItemUnEquip(EquipItemToSlot.Armor); EquipSlot.Armor.OnItemUnEquip(EquipSlotType.Armor);
} }
break; break;
case EquipItemToSlot.Shoes: case EquipSlotType.Shoes:
if (EquipSlot.Shoes != null) if (EquipSlot.Shoes != null)
{ {
result = EquipSlot.Shoes; result = EquipSlot.Shoes;
EquipSlot.Shoes.OnItemUnEquip(EquipItemToSlot.Shoes); EquipSlot.Shoes.OnItemUnEquip(EquipSlotType.Shoes);
} }
break; break;
case EquipItemToSlot.Accessory1: case EquipSlotType.Accessory1:
if (EquipSlot.Accessory1 != null) if (EquipSlot.Accessory1 != null)
{ {
result = EquipSlot.Accessory1; result = EquipSlot.Accessory1;
EquipSlot.Accessory1.OnItemUnEquip(EquipItemToSlot.Accessory1); EquipSlot.Accessory1.OnItemUnEquip(EquipSlotType.Accessory1);
} }
break; break;
case EquipItemToSlot.Accessory2: case EquipSlotType.Accessory2:
if (EquipSlot.Accessory2 != null) if (EquipSlot.Accessory2 != null)
{ {
result = EquipSlot.Accessory2; result = EquipSlot.Accessory2;
EquipSlot.Accessory2.OnItemUnEquip(EquipItemToSlot.Accessory2); EquipSlot.Accessory2.OnItemUnEquip(EquipSlotType.Accessory2);
} }
break; break;
} }
@ -1128,32 +1138,32 @@ namespace Milimoe.FunGame.Core.Entity
builder.AppendLine("== 装备栏 =="); builder.AppendLine("== 装备栏 ==");
if (EquipSlot.MagicCardPack != null) if (EquipSlot.MagicCardPack != null)
{ {
builder.AppendLine(ItemSet.GetEquipItemToSlotTypeName(EquipItemToSlot.MagicCardPack) + "" + EquipSlot.MagicCardPack.Name); builder.AppendLine(ItemSet.GetEquipSlotTypeName(EquipSlotType.MagicCardPack) + "" + EquipSlot.MagicCardPack.Name);
builder.AppendLine(EquipSlot.MagicCardPack.Description); builder.AppendLine(EquipSlot.MagicCardPack.Description);
} }
if (EquipSlot.Weapon != null) if (EquipSlot.Weapon != null)
{ {
builder.AppendLine(ItemSet.GetEquipItemToSlotTypeName(EquipItemToSlot.Weapon) + "" + EquipSlot.Weapon.Name); builder.AppendLine(ItemSet.GetEquipSlotTypeName(EquipSlotType.Weapon) + "" + EquipSlot.Weapon.Name);
builder.AppendLine(EquipSlot.Weapon.Description); builder.AppendLine(EquipSlot.Weapon.Description);
} }
if (EquipSlot.Armor != null) if (EquipSlot.Armor != null)
{ {
builder.AppendLine(ItemSet.GetEquipItemToSlotTypeName(EquipItemToSlot.Armor) + "" + EquipSlot.Armor.Name); builder.AppendLine(ItemSet.GetEquipSlotTypeName(EquipSlotType.Armor) + "" + EquipSlot.Armor.Name);
builder.AppendLine(EquipSlot.Armor.Description); builder.AppendLine(EquipSlot.Armor.Description);
} }
if (EquipSlot.Shoes != null) if (EquipSlot.Shoes != null)
{ {
builder.AppendLine(ItemSet.GetEquipItemToSlotTypeName(EquipItemToSlot.Shoes) + "" + EquipSlot.Shoes.Name); builder.AppendLine(ItemSet.GetEquipSlotTypeName(EquipSlotType.Shoes) + "" + EquipSlot.Shoes.Name);
builder.AppendLine(EquipSlot.Shoes.Description); builder.AppendLine(EquipSlot.Shoes.Description);
} }
if (EquipSlot.Accessory1 != null) if (EquipSlot.Accessory1 != null)
{ {
builder.AppendLine(ItemSet.GetEquipItemToSlotTypeName(EquipItemToSlot.Accessory1) + "" + EquipSlot.Accessory1.Name); builder.AppendLine(ItemSet.GetEquipSlotTypeName(EquipSlotType.Accessory1) + "" + EquipSlot.Accessory1.Name);
builder.AppendLine(EquipSlot.Accessory1.Description); builder.AppendLine(EquipSlot.Accessory1.Description);
} }
if (EquipSlot.Accessory2 != null) if (EquipSlot.Accessory2 != null)
{ {
builder.AppendLine(ItemSet.GetEquipItemToSlotTypeName(EquipItemToSlot.Accessory2) + "" + EquipSlot.Accessory2.Name); builder.AppendLine(ItemSet.GetEquipSlotTypeName(EquipSlotType.Accessory2) + "" + EquipSlot.Accessory2.Name);
builder.AppendLine(EquipSlot.Accessory2.Description); builder.AppendLine(EquipSlot.Accessory2.Description);
} }
} }
@ -1288,7 +1298,7 @@ namespace Milimoe.FunGame.Core.Entity
Name = Name, Name = Name,
FirstName = FirstName, FirstName = FirstName,
NickName = NickName, NickName = NickName,
Profile = Profile, Profile = Profile.Copy(),
MagicType = MagicType, MagicType = MagicType,
FirstRoleType = FirstRoleType, FirstRoleType = FirstRoleType,
SecondRoleType = SecondRoleType, SecondRoleType = SecondRoleType,
@ -1307,7 +1317,7 @@ namespace Milimoe.FunGame.Core.Entity
ExATK2 = ExATK2, ExATK2 = ExATK2,
InitialDEF = InitialDEF, InitialDEF = InitialDEF,
ExDEF2 = ExDEF2, ExDEF2 = ExDEF2,
MDF = MDF, MDF = MDF.Copy(),
PhysicalPenetration = PhysicalPenetration, PhysicalPenetration = PhysicalPenetration,
MagicalPenetration = MagicalPenetration, MagicalPenetration = MagicalPenetration,
InitialHR = InitialHR, InitialHR = InitialHR,
@ -1349,5 +1359,94 @@ namespace Milimoe.FunGame.Core.Entity
c.Recovery(); c.Recovery();
return c; return c;
} }
/// <summary>
/// 复活此角色,回复出厂状态
/// </summary>
/// <returns></returns>
public void Respawn()
{
Item? mcp = UnEquip(EquipSlotType.MagicCardPack);
Item? w = UnEquip(EquipSlotType.Weapon);
Item? a = UnEquip(EquipSlotType.Armor);
Item? s = UnEquip(EquipSlotType.Shoes);
Item? ac1 = UnEquip(EquipSlotType.Accessory1);
Item? ac2 = UnEquip(EquipSlotType.Accessory2);
List<Skill> skills = new(Skills);
List<Item> items = new(Items);
Character c = Copy();
Effects.Clear();
Skills.Clear();
Items.Clear();
Id = c.Id;
Name = c.Name;
FirstName = c.FirstName;
NickName = c.NickName;
Profile = c.Profile.Copy();
MagicType = c.MagicType;
FirstRoleType = c.FirstRoleType;
SecondRoleType = c.SecondRoleType;
ThirdRoleType = c.ThirdRoleType;
Promotion = c.Promotion;
PrimaryAttribute = c.PrimaryAttribute;
Level = c.Level;
EXP = c.EXP;
CharacterState = c.CharacterState;
InitialHP = c.InitialHP;
ExHP2 = c.ExHP2;
InitialMP = c.InitialMP;
ExMP2 = c.ExMP2;
EP = c.EP;
InitialATK = c.InitialATK;
ExATK2 = c.ExATK2;
InitialDEF = c.InitialDEF;
ExDEF2 = c.ExDEF2;
MDF = c.MDF.Copy();
PhysicalPenetration = c.PhysicalPenetration;
MagicalPenetration = c.MagicalPenetration;
InitialHR = c.InitialHR;
ExHR = c.ExHR;
InitialMR = c.InitialMR;
ExMR = c.ExMR;
ER = c.ER;
InitialSTR = c.InitialSTR;
InitialAGI = c.InitialAGI;
InitialINT = c.InitialINT;
ExSTR = c.ExSTR;
ExAGI = c.ExAGI;
ExINT = c.ExINT;
STRGrowth = c.STRGrowth;
AGIGrowth = c.AGIGrowth;
INTGrowth = c.INTGrowth;
InitialSPD = c.InitialSPD;
ExSPD = c.ExSPD;
ExActionCoefficient = c.ExActionCoefficient;
AccelerationCoefficient = c.AccelerationCoefficient;
ExCDR = c.ExCDR;
ATR = c.ATR;
ExCritRate = c.ExCritRate;
ExCritDMG = c.ExCritDMG;
ExEvadeRate = c.ExEvadeRate;
foreach (Skill skill in skills)
{
Skill newskill = skill.Copy();
newskill.Character = this;
newskill.Level = skill.Level;
Skills.Add(newskill);
}
foreach (Item item in items)
{
Item newitem = item.Copy(true);
newitem.Character = this;
Items.Add(newitem);
}
if (mcp != null) Equip(mcp);
if (w != null) Equip(w);
if (a != null) Equip(a);
if (s != null) Equip(s);
if (ac1 != null) Equip(ac1);
if (ac2 != null) Equip(ac2);
Recovery(0D);
}
} }
} }

View File

@ -64,5 +64,24 @@ namespace Milimoe.FunGame.Core.Entity
/// 角色的故事 /// 角色的故事
/// </summary> /// </summary>
public Dictionary<string, string> Stories { get; set; } = []; public Dictionary<string, string> Stories { get; set; } = [];
/// <summary>
/// 复制一个角色资料
/// </summary>
/// <returns></returns>
public CharacterProfile Copy()
{
return new(Name, FirstName, NickName)
{
Birthplace = Birthplace,
Birthday = Birthday,
Status = Status,
Affiliation = Affiliation,
Sex = Sex,
Height = Height,
Weight = Weight,
Stories = new(Stories)
};
}
} }
} }

View File

@ -32,6 +32,11 @@ namespace Milimoe.FunGame.Core.Entity
/// </summary> /// </summary>
public Item? Accessory2 { get; internal set; } = null; public Item? Accessory2 { get; internal set; } = null;
/// <summary>
/// 上一次装备的饰品槽
/// </summary>
public EquipSlotType LastEquipSlotType { get; internal set; } = EquipSlotType.Accessory1;
/// <summary> /// <summary>
/// 是否有任意装备 /// 是否有任意装备
/// </summary> /// </summary>
@ -40,38 +45,5 @@ namespace Milimoe.FunGame.Core.Entity
{ {
return MagicCardPack != null || Weapon != null || Armor != null || Shoes != null || Accessory1 != null || Accessory2 != null; return MagicCardPack != null || Weapon != null || Armor != null || Shoes != null || Accessory1 != null || Accessory2 != null;
} }
/// <summary>
/// 获取物品所装备的栏位
/// </summary>
/// <returns></returns>
public EquipItemToSlot GetEquipItemToSlot(Item item)
{
if (MagicCardPack == item)
{
return EquipItemToSlot.MagicCardPack;
}
else if (Weapon == item)
{
return EquipItemToSlot.Weapon;
}
else if (Armor == item)
{
return EquipItemToSlot.Armor;
}
else if (Shoes == item)
{
return EquipItemToSlot.Shoes;
}
else if (Accessory1 == item)
{
return EquipItemToSlot.Accessory1;
}
else if (Accessory2 == item)
{
return EquipItemToSlot.Accessory2;
}
return EquipItemToSlot.None;
}
} }
} }

View File

@ -14,5 +14,58 @@
public double Element { get; set; } = 0; public double Element { get; set; } = 0;
public double Fleabane { get; set; } = 0; public double Fleabane { get; set; } = 0;
public double Particle { get; set; } = 0; public double Particle { get; set; } = 0;
/// <summary>
/// 对所有抗性赋值
/// </summary>
/// <param name="value"></param>
/// <param name="assignment"></param>
public void SetAllValue(double value, bool assignment = true)
{
if (assignment)
{
None = value;
Particle = value;
Fleabane = value;
Element = value;
Shadow = value;
Bright = value;
PurityContemporary = value;
PurityNatural = value;
Starmark = value;
}
else
{
None += value;
Particle += value;
Fleabane += value;
Element += value;
Shadow += value;
Bright += value;
PurityContemporary += value;
PurityNatural += value;
Starmark += value;
}
}
/// <summary>
/// 复制一个魔法抗性对象
/// </summary>
/// <returns></returns>
public MagicResistance Copy()
{
return new()
{
None = None,
Starmark = Starmark,
PurityNatural = PurityNatural,
PurityContemporary = PurityContemporary,
Bright = Bright,
Shadow = Shadow,
Element = Element,
Fleabane = Fleabane,
Particle = Particle
};
}
} }
} }

View File

@ -1,7 +1,8 @@
using System.Text; using System.Net.NetworkInformation;
using System.Text;
using Milimoe.FunGame.Core.Api.Utility;
using Milimoe.FunGame.Core.Interface.Base; using Milimoe.FunGame.Core.Interface.Base;
using Milimoe.FunGame.Core.Interface.Entity; using Milimoe.FunGame.Core.Interface.Entity;
using Milimoe.FunGame.Core.Library.Common.Addon;
using Milimoe.FunGame.Core.Library.Constant; using Milimoe.FunGame.Core.Library.Constant;
namespace Milimoe.FunGame.Core.Entity namespace Milimoe.FunGame.Core.Entity
@ -42,7 +43,7 @@ namespace Milimoe.FunGame.Core.Entity
public bool Unequipable { get; set; } = true; public bool Unequipable { get; set; } = true;
/// <summary> /// <summary>
/// 装备槽位 /// 当前装备槽位
/// </summary> /// </summary>
public virtual EquipSlotType EquipSlotType { get; set; } = EquipSlotType.None; public virtual EquipSlotType EquipSlotType { get; set; } = EquipSlotType.None;
@ -51,6 +52,21 @@ namespace Milimoe.FunGame.Core.Entity
/// </summary> /// </summary>
public virtual WeaponType WeaponType { get; set; } = WeaponType.None; public virtual WeaponType WeaponType { get; set; } = WeaponType.None;
/// <summary>
/// 品质类型
/// </summary>
public virtual QualityType QualityType { get; set; } = QualityType.White;
/// <summary>
/// 稀有度类型
/// </summary>
public virtual RarityType RarityType { get; set; } = RarityType.OneStar;
/// <summary>
/// 物品评级
/// </summary>
public virtual ItemRankType RankType { get; set; } = ItemRankType.D;
/// <summary> /// <summary>
/// 快捷键 /// 快捷键
/// </summary> /// </summary>
@ -140,9 +156,10 @@ namespace Milimoe.FunGame.Core.Entity
/// <summary> /// <summary>
/// 当装备物品时 /// 当装备物品时
/// </summary> /// </summary>
public void OnItemEquip(Character character, EquipItemToSlot type) public void OnItemEquip(Character character, EquipSlotType type)
{ {
Character = character; Character = character;
EquipSlotType = type;
foreach (Skill skill in Skills.Passives) foreach (Skill skill in Skills.Passives)
{ {
if (!skill.IsActive && skill.Level > 0) if (!skill.IsActive && skill.Level > 0)
@ -164,13 +181,14 @@ namespace Milimoe.FunGame.Core.Entity
/// <summary> /// <summary>
/// 当取消装备物品时 /// 当取消装备物品时
/// </summary> /// </summary>
public void OnItemUnEquip(EquipItemToSlot type) public void OnItemUnEquip(EquipSlotType type)
{ {
if (Character != null) if (Character != null)
{ {
if (Skills.Active != null) if (Skills.Active != null)
{ {
foreach (Effect e in Character.Effects.Where(e => e.Skill == Skills.Active && e.Level > 0).ToList()) List<Effect> effects = Character.Effects.Where(e => e.Skill == Skills.Active && e.Level > 0).ToList();
foreach (Effect e in effects)
{ {
Character.Effects.Remove(e); Character.Effects.Remove(e);
e.OnEffectLost(Character); e.OnEffectLost(Character);
@ -178,7 +196,8 @@ namespace Milimoe.FunGame.Core.Entity
} }
foreach (Skill skill in Skills.Passives) foreach (Skill skill in Skills.Passives)
{ {
foreach (Effect e in Character.Effects.Where(e => e.Skill == skill && e.Level > 0).ToList()) List<Effect> effects = Character.Effects.Where(e => e.Skill == skill && e.Level > 0).ToList();
foreach (Effect e in effects)
{ {
Character.Effects.Remove(e); Character.Effects.Remove(e);
e.OnEffectLost(Character); e.OnEffectLost(Character);
@ -186,28 +205,42 @@ namespace Milimoe.FunGame.Core.Entity
} }
switch (type) switch (type)
{ {
case EquipItemToSlot.MagicCardPack: case EquipSlotType.MagicCardPack:
Character.EquipSlot.MagicCardPack = null; Character.EquipSlot.MagicCardPack = null;
break; break;
case EquipItemToSlot.Weapon: case EquipSlotType.Weapon:
Character.EquipSlot.Weapon = null; Character.EquipSlot.Weapon = null;
break; break;
case EquipItemToSlot.Armor: case EquipSlotType.Armor:
Character.EquipSlot.Armor = null; Character.EquipSlot.Armor = null;
break; break;
case EquipItemToSlot.Shoes: case EquipSlotType.Shoes:
Character.EquipSlot.Shoes = null; Character.EquipSlot.Shoes = null;
break; break;
case EquipItemToSlot.Accessory1: case EquipSlotType.Accessory1:
Character.EquipSlot.Accessory1 = null; Character.EquipSlot.Accessory1 = null;
break; break;
case EquipItemToSlot.Accessory2: case EquipSlotType.Accessory2:
Character.EquipSlot.Accessory2 = null; Character.EquipSlot.Accessory2 = null;
break; break;
} }
OnItemUnEquipped(Character, this, type); OnItemUnEquipped(Character, this, type);
} }
Character = null; Character = null;
EquipSlotType = EquipSlotType.None;
}
/// <summary>
/// 设置游戏内的行动顺序表实例
/// </summary>
/// <param name="queue"></param>
public void SetGamingQueue(IGamingQueue queue)
{
if (Skills.Active != null) Skills.Active.GamingQueue = queue;
foreach (Skill skill in Skills.Passives)
{
skill.GamingQueue = queue;
}
} }
/// <summary> /// <summary>
@ -215,8 +248,19 @@ namespace Milimoe.FunGame.Core.Entity
/// </summary> /// </summary>
public void UseItem(IGamingQueue queue, Character character, List<Character> enemys, List<Character> teammates) public void UseItem(IGamingQueue queue, Character character, List<Character> enemys, List<Character> teammates)
{ {
OnItemUsed(character, this); bool cancel = false;
Skills.Active?.OnSkillCasted(queue, character, enemys, teammates); bool used = false;
if (Skills.Active != null)
{
Skill skill = Skills.Active;
List<Character> targets = queue.SelectTargets(character, skill, enemys, teammates, out cancel);
if (!cancel)
{
skill.OnSkillCasted(queue, character, targets);
used = true;
}
}
OnItemUsed(character, this, cancel, used);
} }
/// <summary> /// <summary>
@ -232,7 +276,9 @@ namespace Milimoe.FunGame.Core.Entity
/// </summary> /// </summary>
/// <param name="character"></param> /// <param name="character"></param>
/// <param name="item"></param> /// <param name="item"></param>
public virtual void OnItemUsed(Character character, Item item) /// <param name="cancel"></param>
/// <param name="used"></param>
public virtual void OnItemUsed(Character character, Item item, bool cancel, bool used)
{ {
} }
@ -253,7 +299,7 @@ namespace Milimoe.FunGame.Core.Entity
/// <param name="character"></param> /// <param name="character"></param>
/// <param name="item"></param> /// <param name="item"></param>
/// <param name="type"></param> /// <param name="type"></param>
public virtual void OnItemEquipped(Character character, Item item, EquipItemToSlot type) public virtual void OnItemEquipped(Character character, Item item, EquipSlotType type)
{ {
} }
@ -264,17 +310,16 @@ namespace Milimoe.FunGame.Core.Entity
/// <param name="character"></param> /// <param name="character"></param>
/// <param name="item"></param> /// <param name="item"></param>
/// <param name="type"></param> /// <param name="type"></param>
public virtual void OnItemUnEquipped(Character character, Item item, EquipItemToSlot type) public virtual void OnItemUnEquipped(Character character, Item item, EquipSlotType type)
{ {
} }
protected Item(ItemType type, bool isInGame = true, EquipSlotType slot = EquipSlotType.None) protected Item(ItemType type, bool isInGame = true)
{ {
ItemType = type; ItemType = type;
IsInGameItem = isInGame; IsInGameItem = isInGame;
EquipSlotType = slot;
} }
internal Item() { } internal Item() { }
@ -307,7 +352,7 @@ namespace Milimoe.FunGame.Core.Entity
StringBuilder builder = new(); StringBuilder builder = new();
builder.AppendLine($"【{Name}】"); builder.AppendLine($"【{Name}】");
builder.AppendLine($"{ItemSet.GetItemTypeName(ItemType)}" + (IsPurchasable && Price > 0 ? $" 售价:{Price}" : "")); builder.AppendLine($"{ItemSet.GetItemTypeName(ItemType) + (ItemType == ItemType.Weapon && WeaponType != WeaponType.None ? "-" + ItemSet.GetWeaponTypeName(WeaponType) : "")}" + (IsPurchasable && Price > 0 ? $" 售价:{Price}" : ""));
if (RemainUseTimes > 0) if (RemainUseTimes > 0)
{ {
@ -369,61 +414,83 @@ namespace Milimoe.FunGame.Core.Entity
} }
/// <summary> /// <summary>
/// 设置一些属性给从 <see cref="ItemModule"/> 新建来的 <paramref name="newbyItemModule"/><para/> /// 设置一些属性给从工厂构造出来的 <paramref name="newbyFactory"/> 对象
/// 对于还原存档而言,在使用 JSON 反序列化 Item且从 <see cref="ItemModule.GetItem"/> 中获取了实例后,需要使用此方法复制给新实例
/// </summary> /// </summary>
/// <param name="newbyItemModule"></param> /// <param name="newbyFactory"></param>
public void SetPropertyToItemModuleNew(Item newbyItemModule) public void SetPropertyToItemModuleNew(Item newbyFactory)
{ {
newbyItemModule.WeaponType = WeaponType; newbyFactory.WeaponType = WeaponType;
newbyItemModule.EquipSlotType = EquipSlotType; newbyFactory.EquipSlotType = EquipSlotType;
newbyItemModule.Equipable = Equipable; newbyFactory.Equipable = Equipable;
newbyItemModule.IsPurchasable = IsPurchasable; newbyFactory.IsPurchasable = IsPurchasable;
newbyItemModule.Price = Price; newbyFactory.Price = Price;
newbyItemModule.IsSellable = IsSellable; newbyFactory.IsSellable = IsSellable;
newbyItemModule.NextSellableTime = NextSellableTime; newbyFactory.NextSellableTime = NextSellableTime;
newbyItemModule.IsTradable = IsTradable; newbyFactory.IsTradable = IsTradable;
newbyItemModule.NextTradableTime = NextTradableTime; newbyFactory.NextTradableTime = NextTradableTime;
} }
/// <summary> /// <summary>
/// 复制一个物品 /// 复制一个物品
/// </summary> /// </summary>
/// <returns></returns> /// <returns></returns>
public Item Copy() public Item Copy(bool copyLevel = false)
{ {
Item item = new() Item item = Factory.OpenFactory.GetInstance<Item>(Id, Name, []);
{ SetPropertyToItemModuleNew(item);
Id = Id, item.Id = Id;
Name = Name, item.Name = Name;
Description = Description, item.Description = Description;
GeneralDescription = GeneralDescription, item.GeneralDescription = GeneralDescription;
ItemType = ItemType, item.BackgroundStory = BackgroundStory;
Equipable = Equipable, item.ItemType = ItemType;
Unequipable = Unequipable, item.Equipable = Equipable;
EquipSlotType = EquipSlotType, item.Unequipable = Unequipable;
WeaponType = WeaponType, item.WeaponType = WeaponType;
Key = Key, item.QualityType = QualityType;
Enable = Enable, item.RarityType = RarityType;
IsInGameItem = IsInGameItem, item.RankType = RankType;
IsPurchasable = IsPurchasable, item.Key = Key;
Price = Price, item.Enable = Enable;
IsSellable = IsSellable, item.IsInGameItem = IsInGameItem;
NextSellableTime = NextSellableTime, item.IsPurchasable = IsPurchasable;
IsTradable = IsTradable, item.Price = Price;
NextTradableTime = NextTradableTime, item.IsSellable = IsSellable;
RemainUseTimes = RemainUseTimes, item.NextSellableTime = NextSellableTime;
}; item.IsTradable = IsTradable;
item.NextTradableTime = NextTradableTime;
item.RemainUseTimes = RemainUseTimes;
item.Skills.Active = Skills.Active?.Copy(); item.Skills.Active = Skills.Active?.Copy();
if (item.Skills.Active != null && copyLevel)
{
item.Skills.Active.Level = Skills.Active?.Level ?? 0;
}
foreach (Skill skill in Skills.Passives) foreach (Skill skill in Skills.Passives)
{ {
Skill newskill = skill.Copy(); Skill newskill = skill.Copy();
newskill.Item = item; newskill.Item = item;
newskill.Level = copyLevel ? skill.Level : 0;
item.Skills.Passives.Add(newskill); item.Skills.Passives.Add(newskill);
} }
return item; return item;
} }
/// <summary>
/// 设置所有技能的等级
/// </summary>
/// <param name="level"></param>
public void SetLevel(int level)
{
if (Skills.Active != null)
{
Skills.Active.Level = level;
}
foreach (Skill skill in Skills.Passives)
{
skill.Level = level;
}
}
/// <summary> /// <summary>
/// 所属的角色 /// 所属的角色
/// </summary> /// </summary>

View File

@ -90,6 +90,11 @@ namespace Milimoe.FunGame.Core.Entity
/// </summary> /// </summary>
public IGamingQueue? GamingQueue { get; set; } = null; public IGamingQueue? GamingQueue { get; set; } = null;
/// <summary>
/// 用于动态扩展特效的参数
/// </summary>
public Dictionary<string, object> Values { get; } = [];
/// <summary> /// <summary>
/// 输出文本或日志 /// 输出文本或日志
/// </summary> /// </summary>
@ -102,9 +107,16 @@ namespace Milimoe.FunGame.Core.Entity
} }
} }
protected Effect(Skill skill) protected Effect(Skill skill, Dictionary<string, object>? args = null)
{ {
Skill = skill; Skill = skill;
if (args != null)
{
foreach (string key in args.Keys)
{
Values[key] = args[key];
}
}
} }
internal Effect() internal Effect()
@ -240,10 +252,9 @@ namespace Milimoe.FunGame.Core.Entity
/// 吟唱结束后释放技能(魔法)/ 直接释放技能(战技/爆发技) /// 吟唱结束后释放技能(魔法)/ 直接释放技能(战技/爆发技)
/// </summary> /// </summary>
/// <param name="caster"></param> /// <param name="caster"></param>
/// <param name="enemys"></param> /// <param name="targets"></param>
/// <param name="teammates"></param>
/// <param name="others"></param> /// <param name="others"></param>
public virtual void OnSkillCasted(Character caster, List<Character> enemys, List<Character> teammates, Dictionary<string, object> others) public virtual void OnSkillCasted(Character caster, List<Character> targets, Dictionary<string, object> others)
{ {
} }
@ -323,6 +334,17 @@ namespace Milimoe.FunGame.Core.Entity
} }
/// <summary>
/// 闪避检定前触发
/// </summary>
/// <param name="character"></param>
/// <param name="throwingBonus"></param>
/// <returns>返回 false 表示不进行闪避检定</returns>
public virtual bool BeforeEvadeCheck(Character character, ref double throwingBonus)
{
return true;
}
/// <summary> /// <summary>
/// 在触发闪避时 /// 在触发闪避时
/// </summary> /// </summary>
@ -335,6 +357,17 @@ namespace Milimoe.FunGame.Core.Entity
return false; return false;
} }
/// <summary>
/// 暴击检定前触发
/// </summary>
/// <param name="character"></param>
/// <param name="throwingBonus"></param>
/// <returns>返回 false 表示不进行暴击检定</returns>
public virtual bool BeforeCriticalCheck(Character character, ref double throwingBonus)
{
return true;
}
/// <summary> /// <summary>
/// 在触发暴击时 /// 在触发暴击时
/// </summary> /// </summary>
@ -441,20 +474,24 @@ namespace Milimoe.FunGame.Core.Entity
/// <returns></returns> /// <returns></returns>
public Effect Copy(Skill skill) public Effect Copy(Skill skill)
{ {
Effect copy = new(skill) Dictionary<string, object> args = new()
{ {
EffectType = EffectType, { "skill", skill },
TargetSelf = TargetSelf, { "values", Values }
TargetCount = TargetCount,
TargetRange = TargetRange,
Durative = Durative,
Duration = Duration,
DurationTurn = DurationTurn,
MagicType = MagicType,
Description = Description,
GamingQueue = GamingQueue
}; };
Effect copy = Factory.OpenFactory.GetInstance<Effect>(Id, Name, args);
copy.Id = Id;
copy.Name = Name;
copy.Description = Description;
copy.EffectType = EffectType;
copy.TargetSelf = TargetSelf;
copy.TargetCount = TargetCount;
copy.TargetRange = TargetRange;
copy.Durative = Durative;
copy.Duration = Duration;
copy.DurationTurn = DurationTurn;
copy.MagicType = MagicType;
copy.GamingQueue = GamingQueue;
return copy; return copy;
} }

34
Entity/Skill/OpenSkill.cs Normal file
View File

@ -0,0 +1,34 @@
using Milimoe.FunGame.Core.Library.Constant;
namespace Milimoe.FunGame.Core.Entity
{
/// <summary>
/// 用于动态扩展技能,<see cref="Description"/> 返回所有特效的描述
/// </summary>
public class OpenSkill : Skill
{
public override long Id { get; set; }
public override string Name { get; set; }
public override string Description => string.Join("\r\n", Effects);
public OpenSkill(long id, string name, Dictionary<string, object> args, Character? character = null) : base(SkillType.Passive, character)
{
Id = id;
Name = name;
foreach (string str in args.Keys)
{
Values[str] = args[str];
switch (str)
{
default:
break;
}
}
}
public override IEnumerable<Effect> AddInactiveEffectToCharacter()
{
return Effects;
}
}
}

View File

@ -2,7 +2,6 @@
using Milimoe.FunGame.Core.Api.Utility; using Milimoe.FunGame.Core.Api.Utility;
using Milimoe.FunGame.Core.Interface.Base; using Milimoe.FunGame.Core.Interface.Base;
using Milimoe.FunGame.Core.Interface.Entity; using Milimoe.FunGame.Core.Interface.Entity;
using Milimoe.FunGame.Core.Library.Common.Addon;
using Milimoe.FunGame.Core.Library.Constant; using Milimoe.FunGame.Core.Library.Constant;
namespace Milimoe.FunGame.Core.Entity namespace Milimoe.FunGame.Core.Entity
@ -27,6 +26,11 @@ namespace Milimoe.FunGame.Core.Entity
/// </summary> /// </summary>
public virtual string GeneralDescription { get; set; } = ""; public virtual string GeneralDescription { get; set; } = "";
/// <summary>
/// 释放技能时的口号
/// </summary>
public virtual string Slogan { get; set; } = "";
/// <summary> /// <summary>
/// 技能等级,等于 0 时可以称之为尚未学习 /// 技能等级,等于 0 时可以称之为尚未学习
/// </summary> /// </summary>
@ -78,6 +82,21 @@ namespace Milimoe.FunGame.Core.Entity
[InitRequired] [InitRequired]
public bool IsMagic => SkillType == SkillType.Magic; public bool IsMagic => SkillType == SkillType.Magic;
/// <summary>
/// 可选取自身
/// </summary>
public virtual bool CanSelectSelf { get; set; } = false;
/// <summary>
/// 可选取的作用目标数量
/// </summary>
public virtual int CanSelectTargetCount { get; set; } = 1;
/// <summary>
/// 可选取的作用范围
/// </summary>
public virtual double CanSelectTargetRange { get; set; } = 0;
/// <summary> /// <summary>
/// 实际魔法消耗 [ 魔法 ] /// 实际魔法消耗 [ 魔法 ]
/// </summary> /// </summary>
@ -103,7 +122,7 @@ namespace Milimoe.FunGame.Core.Entity
/// <summary> /// <summary>
/// 实际能量消耗 [ 战技 ] /// 实际能量消耗 [ 战技 ]
/// </summary> /// </summary>
public double RealEPCost => IsSuperSkill ? EPCost : Math.Max(0, EPCost * (1 - Calculation.PercentageCheck((Character?.INT ?? 0) * 0.00075))); public double RealEPCost => CostAllEP ? Math.Max(MinCostEP, Character?.EP ?? MinCostEP) : (IsSuperSkill ? EPCost : Math.Max(0, EPCost * (1 - Calculation.PercentageCheck((Character?.INT ?? 0) * 0.00075))));
/// <summary> /// <summary>
/// 能量消耗 [ 战技 ] /// 能量消耗 [ 战技 ]
@ -111,6 +130,16 @@ namespace Milimoe.FunGame.Core.Entity
[InitOptional] [InitOptional]
public virtual double EPCost { get; set; } = 0; public virtual double EPCost { get; set; } = 0;
/// <summary>
/// 消耗所有能量 [ 战技 ]
/// </summary>
public virtual bool CostAllEP { get; set; } = false;
/// <summary>
/// 消耗所有能量的最小能量限制 [ 战技 ] 默认值100
/// </summary>
public virtual double MinCostEP { get; set; } = 100;
/// <summary> /// <summary>
/// 实际冷却时间 /// 实际冷却时间
/// </summary> /// </summary>
@ -139,9 +168,9 @@ namespace Milimoe.FunGame.Core.Entity
public HashSet<Effect> Effects { get; } = []; public HashSet<Effect> Effects { get; } = [];
/// <summary> /// <summary>
/// 其他参数 /// 用于动态扩展技能的参数
/// </summary> /// </summary>
public Dictionary<string, object> OtherArgs { get; } = []; public Dictionary<string, object> Values { get; } = [];
/// <summary> /// <summary>
/// 游戏中的行动顺序表实例,在技能效果被触发时,此实例会获得赋值,使用时需要判断其是否存在 /// 游戏中的行动顺序表实例,在技能效果被触发时,此实例会获得赋值,使用时需要判断其是否存在
@ -170,15 +199,14 @@ namespace Milimoe.FunGame.Core.Entity
internal Skill() { } internal Skill() { }
/// <summary> /// <summary>
/// 设置一些属性给从 <see cref="SkillModule"/> 新建来的 <paramref name="newbySkillModule"/><para/> /// 设置一些属性给从工厂构造出来的 <paramref name="newbyFactory"/> 对象
/// 对于还原存档而言,在使用 JSON 反序列化 Skill且从 <see cref="SkillModule.GetSkill"/> 中获取了实例后,需要使用此方法复制给新实例
/// </summary> /// </summary>
/// <param name="newbySkillModule"></param> /// <param name="newbyFactory"></param>
public void SetPropertyToItemModuleNew(Skill newbySkillModule) public void SetPropertyToItemModuleNew(Skill newbyFactory)
{ {
newbySkillModule.Enable = Enable; newbyFactory.Enable = Enable;
newbySkillModule.IsInEffect = IsInEffect; newbyFactory.IsInEffect = IsInEffect;
newbySkillModule.CurrentCD = CurrentCD; newbyFactory.CurrentCD = CurrentCD;
} }
/// <summary> /// <summary>
@ -210,9 +238,37 @@ namespace Milimoe.FunGame.Core.Entity
OnLevelUp(); OnLevelUp();
} }
/// <summary>
/// 选取技能目标
/// </summary>
/// <param name="caster"></param>
/// <param name="enemys"></param>
/// <param name="teammates"></param>
/// <returns></returns>
public virtual List<Character> SelectTargets(Character caster, List<Character> enemys, List<Character> teammates)
{
if (CanSelectSelf)
{
return [caster];
}
else
{
List<Character> targets = [];
if (enemys.Count <= CanSelectTargetCount)
{
return [.. enemys];
}
return enemys.OrderBy(x => Random.Shared.Next()).Take(CanSelectTargetCount).ToList();
}
}
/// <summary> /// <summary>
/// 技能开始吟唱时 [ 吟唱魔法、释放战技和爆发技、预释放爆发技均可触发 ] /// 技能开始吟唱时 [ 吟唱魔法、释放战技和爆发技、预释放爆发技均可触发 ]
/// </summary> /// </summary>
/// <param name="queue"></param>
/// <param name="caster"></param>
public void OnSkillCasting(IGamingQueue queue, Character caster) public void OnSkillCasting(IGamingQueue queue, Character caster)
{ {
GamingQueue = queue; GamingQueue = queue;
@ -226,13 +282,16 @@ namespace Milimoe.FunGame.Core.Entity
/// <summary> /// <summary>
/// 触发技能效果 /// 触发技能效果
/// </summary> /// </summary>
public void OnSkillCasted(IGamingQueue queue, Character caster, List<Character> enemys, List<Character> teammates) /// <param name="queue"></param>
/// <param name="caster"></param>
/// <param name="targets"></param>
public void OnSkillCasted(IGamingQueue queue, Character caster, List<Character> targets)
{ {
GamingQueue = queue; GamingQueue = queue;
foreach (Effect e in Effects) foreach (Effect e in Effects)
{ {
e.GamingQueue = GamingQueue; e.GamingQueue = GamingQueue;
e.OnSkillCasted(caster, enemys, teammates, OtherArgs); e.OnSkillCasted(caster, targets, Values);
} }
} }
@ -333,27 +392,33 @@ namespace Milimoe.FunGame.Core.Entity
/// <returns></returns> /// <returns></returns>
public Skill Copy() public Skill Copy()
{ {
Skill s = new() Dictionary<string, object> args = new()
{ {
Id = Id, { "values", Values }
Name = Name,
Description = Description,
GeneralDescription = GeneralDescription,
SkillType = SkillType,
MPCost = MPCost,
CastTime = CastTime,
EPCost = EPCost,
CD = CD,
CurrentCD = CurrentCD,
HardnessTime = HardnessTime,
GamingQueue = GamingQueue
}; };
foreach (Effect e in Effects) Skill skill = Factory.OpenFactory.GetInstance<Skill>(Id, Name, args);
SetPropertyToItemModuleNew(skill);
skill.Id = Id;
skill.Name = Name;
skill.Description = Description;
skill.GeneralDescription = GeneralDescription;
skill.SkillType = SkillType;
skill.MPCost = MPCost;
skill.CastTime = CastTime;
skill.EPCost = EPCost;
skill.CD = CD;
skill.CurrentCD = CurrentCD;
skill.HardnessTime = HardnessTime;
skill.GamingQueue = GamingQueue;
if (skill is OpenSkill)
{ {
Effect neweffect = e.Copy(s); foreach (Effect e in Effects)
s.Effects.Add(neweffect); {
Effect neweffect = e.Copy(skill);
skill.Effects.Add(neweffect);
}
} }
return s; return skill;
} }
/// <summary> /// <summary>

View File

@ -0,0 +1,8 @@
namespace Milimoe.FunGame.Core.Entity
{
public struct SkillTarget(Skill skill, List<Character> targets)
{
public Skill Skill { get; set; } = skill;
public List<Character> Targets { get; set; } = targets;
}
}

View File

@ -32,6 +32,8 @@
public int Kills { get; set; } = 0; public int Kills { get; set; } = 0;
public int Deaths { get; set; } = 0; public int Deaths { get; set; } = 0;
public int Assists { get; set; } = 0; public int Assists { get; set; } = 0;
public int FirstKills { get; set; } = 0;
public int FirstDeaths { get; set; } = 0;
public int Plays { get; set; } = 0; public int Plays { get; set; } = 0;
public int Wins { get; set; } = 0; public int Wins { get; set; } = 0;
public int Top3s { get; set; } = 0; public int Top3s { get; set; } = 0;
@ -40,5 +42,6 @@
public double Top3rates { get; set; } = 0; public double Top3rates { get; set; } = 0;
public int LastRank { get; set; } = 0; public int LastRank { get; set; } = 0;
public double AvgRank { get; set; } = 0; public double AvgRank { get; set; } = 0;
public double Rating { get; set; } = 0;
} }
} }

View File

@ -0,0 +1,14 @@
using Milimoe.FunGame.Core.Library.Constant;
namespace Milimoe.FunGame.Core.Entity.System
{
public class RoundRecord(int round, Character actor)
{
public int Round { get; set; } = round;
public Character Actor { get; set; } = actor;
public CharacterActionType ActionType { get; set; } = CharacterActionType.None;
public List<Character> Targets { get; set; } = [];
public Skill? Skill { get; set; } = null;
public Item? Item { get; set; } = null;
}
}

39
Entity/System/Team.cs Normal file
View File

@ -0,0 +1,39 @@
using Milimoe.FunGame.Core.Interface.Base;
namespace Milimoe.FunGame.Core.Entity
{
public class Team(string name, IEnumerable<Character> charaters)
{
public Guid Id { get; set; } = Guid.Empty;
public string Name { get; set; } = name;
public List<Character> Members { get; } = new(charaters);
public int Score { get; set; } = 0;
public bool IsWinner { get; set; } = false;
public int Count => Members.Count;
public List<Character> GetActiveCharacters(IGamingQueue queue)
{
return [.. Members.Where(queue.Queue.Contains)];
}
public List<Character> GetTeammates(Character character)
{
return [.. Members.Where(c => c != character)];
}
public List<Character> GetActiveTeammates(IGamingQueue queue, Character character)
{
return [.. Members.Where(c => queue.Queue.Contains(c) && c != character)];
}
public bool IsOnThisTeam(Character character)
{
return Members.Contains(character);
}
public override string ToString()
{
return Name;
}
}
}

View File

@ -99,5 +99,27 @@ namespace Milimoe.FunGame.Core.Interface.Base
/// <param name="caster"></param> /// <param name="caster"></param>
/// <param name="interrupter"></param> /// <param name="interrupter"></param>
public void InterruptCasting(Character caster, Character interrupter); public void InterruptCasting(Character caster, Character interrupter);
/// <summary>
/// 选取技能目标
/// </summary>
/// <param name="caster"></param>
/// <param name="skill"></param>
/// <param name="enemys"></param>
/// <param name="teammates"></param>
/// <param name="cancel"></param>
/// <returns></returns>
public List<Character> SelectTargets(Character caster, Skill skill, List<Character> enemys, List<Character> teammates, out bool cancel);
/// <summary>
/// 选取普通攻击目标
/// </summary>
/// <param name="character"></param>
/// <param name="attack"></param>
/// <param name="enemys"></param>
/// <param name="teammates"></param>
/// <param name="cancel"></param>
/// <returns></returns>
public List<Character> SelectTargets(Character character, NormalAttack attack, List<Character> enemys, List<Character> teammates, out bool cancel);
} }
} }

View File

@ -1,4 +1,5 @@
using Milimoe.FunGame.Core.Entity; using Milimoe.FunGame.Core.Api.Utility;
using Milimoe.FunGame.Core.Entity;
using Milimoe.FunGame.Core.Interface.Addons; using Milimoe.FunGame.Core.Interface.Addons;
namespace Milimoe.FunGame.Core.Library.Common.Addon namespace Milimoe.FunGame.Core.Library.Common.Addon
@ -28,7 +29,7 @@ namespace Milimoe.FunGame.Core.Library.Common.Addon
/// <summary> /// <summary>
/// 此模组中包含的角色 /// 此模组中包含的角色
/// </summary> /// </summary>
public abstract List<Character> Characters { get; } public abstract Dictionary<string, Character> Characters { get; }
/// <summary> /// <summary>
/// 加载标记 /// 加载标记
@ -49,12 +50,28 @@ namespace Milimoe.FunGame.Core.Library.Common.Addon
{ {
// 模组加载后,不允许再次加载此模组 // 模组加载后,不允许再次加载此模组
IsLoaded = true; IsLoaded = true;
// 注册工厂
Factory.OpenFactory.RegisterFactory(EntityFactory());
// 如果加载后需要执行代码请重写AfterLoad方法 // 如果加载后需要执行代码请重写AfterLoad方法
AfterLoad(); AfterLoad();
} }
return IsLoaded; return IsLoaded;
} }
/// <summary>
/// 注册工厂
/// </summary>
protected virtual Factory.EntityFactoryDelegate<Character> EntityFactory()
{
return (id, name, args) =>
{
Character c = Factory.GetCharacter();
c.Id = id;
c.Name = name;
return c;
};
}
/// <summary> /// <summary>
/// 模组加载后需要做的事 /// 模组加载后需要做的事
/// </summary> /// </summary>

View File

@ -251,11 +251,11 @@ namespace Milimoe.FunGame.Core.Library.Common.Addon.Example
public override string Author => "FunGamer"; public override string Author => "FunGamer";
public override List<Character> Characters public override Dictionary<string, Character> Characters
{ {
get get
{ {
List<Character> list = []; Dictionary<string, Character> dict = [];
// 构建一个你想要的角色 // 构建一个你想要的角色
Character c = Factory.GetCharacter(); Character c = Factory.GetCharacter();
c.Name = "Oshima"; c.Name = "Oshima";
@ -268,8 +268,8 @@ namespace Milimoe.FunGame.Core.Library.Common.Addon.Example
c.InitialINT = 5; c.InitialINT = 5;
c.InitialATK = 100; c.InitialATK = 100;
c.InitialDEF = 10; c.InitialDEF = 10;
list.Add(c); dict.Add(c.Name, c);
return list; return dict;
} }
} }
} }
@ -287,20 +287,31 @@ namespace Milimoe.FunGame.Core.Library.Common.Addon.Example
public override string Author => "FunGamer"; public override string Author => "FunGamer";
public override List<Skill> Skills public override Dictionary<string, Skill> Skills
{ {
get get
{ {
List<Skill> list = []; Dictionary<string, Skill> dict = [];
// 技能应该在GameModule中新建类继承Skill实现再自行构造。 // 技能应该在GameModule中新建类继承Skill实现再自行构造。
return list; return dict;
} }
} }
public override Skill? GetSkill(long id, string name, SkillType type) protected override Factory.EntityFactoryDelegate<Skill> SkillFactory()
{ {
// 此方法将根据id和name返回一个你继承实现了的类对象。 // 注册一个工厂根据id和name返回一个你继承实现了的类对象。
return Factory.GetSkill(); return (id, name, args) =>
{
return null;
};
}
protected override Factory.EntityFactoryDelegate<Effect> EffectFactory()
{
return (id, name, args) =>
{
return null;
};
} }
} }
@ -317,20 +328,23 @@ namespace Milimoe.FunGame.Core.Library.Common.Addon.Example
public override string Author => "FunGamer"; public override string Author => "FunGamer";
public override List<Item> Items public override Dictionary<string, Item> Items
{ {
get get
{ {
List<Item> list = []; Dictionary<string, Item> dict = [];
// 物品应该在GameModule中新建类继承Item实现再自行构造。 // 物品应该在GameModule中新建类继承Item实现再自行构造。
return list; return dict;
} }
} }
public override Item? GetItem(long id, string name, ItemType type) protected override Factory.EntityFactoryDelegate<Item> ItemFactory()
{ {
// 此方法将根据id和name返回一个你继承实现了的类对象。 // 注册一个工厂根据id和name返回一个你继承实现了的类对象。
return Factory.GetItem(); return (id, name, args) =>
{
return null;
};
} }
} }
} }

View File

@ -42,19 +42,19 @@ namespace Milimoe.FunGame.Core.Library.Common.Addon
/// 实际使用的角色组对象<para/> /// 实际使用的角色组对象<para/>
/// 请使用 <see cref="GetDependencies"/> 自动填充,不要自己添加 /// 请使用 <see cref="GetDependencies"/> 自动填充,不要自己添加
/// </summary> /// </summary>
public List<Character> Characters { get; } = []; public Dictionary<string, Character> Characters { get; } = [];
/// <summary> /// <summary>
/// 实际使用的技能组对象<para/> /// 实际使用的技能组对象<para/>
/// 请使用 <see cref="GetDependencies"/> 自动填充,不要自己添加 /// 请使用 <see cref="GetDependencies"/> 自动填充,不要自己添加
/// </summary> /// </summary>
public List<Skill> Skills { get; } = []; public Dictionary<string, Skill> Skills { get; } = [];
/// <summary> /// <summary>
/// 实际使用的物品组对象<para/> /// 实际使用的物品组对象<para/>
/// 请使用 <see cref="GetDependencies"/> 自动填充,不要自己添加 /// 请使用 <see cref="GetDependencies"/> 自动填充,不要自己添加
/// </summary> /// </summary>
public List<Item> Items { get; } = []; public Dictionary<string, Item> Items { get; } = [];
/// <summary> /// <summary>
/// 获得所有的依赖项<para/> /// 获得所有的依赖项<para/>
@ -69,15 +69,24 @@ namespace Milimoe.FunGame.Core.Library.Common.Addon
Maps.AddRange(loader.Maps.Keys.Where(MapsDepend.Contains).Select(str => loader.Maps[str])); Maps.AddRange(loader.Maps.Keys.Where(MapsDepend.Contains).Select(str => loader.Maps[str]));
foreach (CharacterModule modules in loader.Characters.Keys.Where(CharactersDepend.Contains).Select(str => loader.Characters[str])) foreach (CharacterModule modules in loader.Characters.Keys.Where(CharactersDepend.Contains).Select(str => loader.Characters[str]))
{ {
Characters.AddRange(modules.Characters); foreach (string key in modules.Characters.Keys)
{
Characters[key] = modules.Characters[key];
}
} }
foreach (SkillModule modules in loader.Skills.Keys.Where(SkillsDepend.Contains).Select(str => loader.Skills[str])) foreach (SkillModule modules in loader.Skills.Keys.Where(SkillsDepend.Contains).Select(str => loader.Skills[str]))
{ {
Skills.AddRange(modules.Skills); foreach (string key in modules.Skills.Keys)
{
Skills[key] = modules.Skills[key];
}
} }
foreach (ItemModule modules in loader.Items.Keys.Where(ItemsDepend.Contains).Select(str => loader.Items[str])) foreach (ItemModule modules in loader.Items.Keys.Where(ItemsDepend.Contains).Select(str => loader.Items[str]))
{ {
Items.AddRange(modules.Items); foreach (string key in modules.Items.Keys)
{
Items[key] = modules.Items[key];
}
} }
} }
} }

View File

@ -1,7 +1,6 @@
using Milimoe.FunGame.Core.Api.Utility; using Milimoe.FunGame.Core.Api.Utility;
using Milimoe.FunGame.Core.Entity; using Milimoe.FunGame.Core.Entity;
using Milimoe.FunGame.Core.Interface.Addons; using Milimoe.FunGame.Core.Interface.Addons;
using Milimoe.FunGame.Core.Library.Constant;
namespace Milimoe.FunGame.Core.Library.Common.Addon namespace Milimoe.FunGame.Core.Library.Common.Addon
{ {
@ -30,25 +29,13 @@ namespace Milimoe.FunGame.Core.Library.Common.Addon
/// <summary> /// <summary>
/// 此模组中包含的物品 /// 此模组中包含的物品
/// </summary> /// </summary>
public abstract List<Item> Items { get; } public abstract Dictionary<string, Item> Items { get; }
/// <summary> /// <summary>
/// 加载标记 /// 加载标记
/// </summary> /// </summary>
private bool IsLoaded = false; private bool IsLoaded = false;
/// <summary>
/// [可选实现] 在使用 <see cref="EntityModuleConfig{Item}"/> 后,可以按 id + name + type 来匹配已编码的物品
/// </summary>
/// <param name="id"></param>
/// <param name="name"></param>
/// <param name="type"></param>
/// <returns></returns>
public virtual Item? GetItem(long id, string name, ItemType type)
{
return null;
}
/// <summary> /// <summary>
/// 加载模组 /// 加载模组
/// </summary> /// </summary>
@ -63,12 +50,19 @@ namespace Milimoe.FunGame.Core.Library.Common.Addon
{ {
// 模组加载后,不允许再次加载此模组 // 模组加载后,不允许再次加载此模组
IsLoaded = true; IsLoaded = true;
// 注册工厂
Factory.OpenFactory.RegisterFactory(ItemFactory());
// 如果加载后需要执行代码请重写AfterLoad方法 // 如果加载后需要执行代码请重写AfterLoad方法
AfterLoad(); AfterLoad();
} }
return IsLoaded; return IsLoaded;
} }
/// <summary>
/// 注册工厂
/// </summary>
protected abstract Factory.EntityFactoryDelegate<Item> ItemFactory();
/// <summary> /// <summary>
/// 模组加载后需要做的事 /// 模组加载后需要做的事
/// </summary> /// </summary>

View File

@ -1,7 +1,6 @@
using Milimoe.FunGame.Core.Api.Utility; using Milimoe.FunGame.Core.Api.Utility;
using Milimoe.FunGame.Core.Entity; using Milimoe.FunGame.Core.Entity;
using Milimoe.FunGame.Core.Interface.Addons; using Milimoe.FunGame.Core.Interface.Addons;
using Milimoe.FunGame.Core.Library.Constant;
namespace Milimoe.FunGame.Core.Library.Common.Addon namespace Milimoe.FunGame.Core.Library.Common.Addon
{ {
@ -30,25 +29,13 @@ namespace Milimoe.FunGame.Core.Library.Common.Addon
/// <summary> /// <summary>
/// 此模组中包含的技能 /// 此模组中包含的技能
/// </summary> /// </summary>
public abstract List<Skill> Skills { get; } public abstract Dictionary<string, Skill> Skills { get; }
/// <summary> /// <summary>
/// 加载标记 /// 加载标记
/// </summary> /// </summary>
private bool IsLoaded = false; private bool IsLoaded = false;
/// <summary>
/// [可选实现] 在使用 <see cref="EntityModuleConfig{Skill}"/> 后,可以按 id + name + type 来匹配已编码的技能
/// </summary>
/// <param name="id"></param>
/// <param name="name"></param>
/// <param name="type"></param>
/// <returns></returns>
public virtual Skill? GetSkill(long id, string name, SkillType type)
{
return null;
}
/// <summary> /// <summary>
/// 加载模组 /// 加载模组
/// </summary> /// </summary>
@ -63,12 +50,25 @@ namespace Milimoe.FunGame.Core.Library.Common.Addon
{ {
// 模组加载后,不允许再次加载此模组 // 模组加载后,不允许再次加载此模组
IsLoaded = true; IsLoaded = true;
// 注册工厂
Factory.OpenFactory.RegisterFactory(SkillFactory());
Factory.OpenFactory.RegisterFactory(EffectFactory());
// 如果加载后需要执行代码请重写AfterLoad方法 // 如果加载后需要执行代码请重写AfterLoad方法
AfterLoad(); AfterLoad();
} }
return IsLoaded; return IsLoaded;
} }
/// <summary>
/// 注册工厂
/// </summary>
protected abstract Factory.EntityFactoryDelegate<Skill> SkillFactory();
/// <summary>
/// 注册工厂(特效类)
/// </summary>
protected abstract Factory.EntityFactoryDelegate<Effect> EffectFactory();
/// <summary> /// <summary>
/// 模组加载后需要做的事 /// 模组加载后需要做的事
/// </summary> /// </summary>

View File

@ -21,6 +21,20 @@ namespace Milimoe.FunGame.Core.Library.Common.JsonConverter
case nameof(Effect.Name): case nameof(Effect.Name):
result.Name = reader.GetString() ?? ""; result.Name = reader.GetString() ?? "";
break; break;
default:
if (reader.TokenType == JsonTokenType.Number)
{
result.Values[propertyName] = reader.GetDouble();
}
else if (reader.TokenType == JsonTokenType.String)
{
result.Values[propertyName] = reader.GetString() ?? "";
}
else if (reader.TokenType == JsonTokenType.True || reader.TokenType == JsonTokenType.False)
{
result.Values[propertyName] = reader.GetBoolean();
}
break;
} }
} }
@ -31,6 +45,28 @@ namespace Milimoe.FunGame.Core.Library.Common.JsonConverter
writer.WriteNumber(nameof(Effect.Id), (int)value.Id); writer.WriteNumber(nameof(Effect.Id), (int)value.Id);
writer.WriteString(nameof(Effect.Name), value.Name); writer.WriteString(nameof(Effect.Name), value.Name);
foreach (var kvp in value.Values)
{
switch (kvp.Value)
{
case int intValue:
writer.WriteNumber(kvp.Key, intValue);
break;
case double doubleValue:
writer.WriteNumber(kvp.Key, doubleValue);
break;
case bool boolValue:
writer.WriteBoolean(kvp.Key, boolValue);
break;
case string strValue:
writer.WriteString(kvp.Key, strValue);
break;
default:
JsonSerializer.Serialize(writer, kvp.Value, options);
break;
}
}
writer.WriteEndObject(); writer.WriteEndObject();
} }
} }

View File

@ -48,14 +48,14 @@ namespace Milimoe.FunGame.Core.Library.Common.JsonConverter
break; break;
case nameof(EquipSlot.Accessory1): case nameof(EquipSlot.Accessory1):
temp = NetworkUtility.JsonDeserialize<Item>(ref reader, options) ?? new(); temp = NetworkUtility.JsonDeserialize<Item>(ref reader, options) ?? new();
if (temp.EquipSlotType == EquipSlotType.Accessory) if (temp.EquipSlotType == EquipSlotType.Accessory1)
{ {
result.Accessory1 = temp; result.Accessory1 = temp;
} }
break; break;
case nameof(EquipSlot.Accessory2): case nameof(EquipSlot.Accessory2):
temp = NetworkUtility.JsonDeserialize<Item>(ref reader, options) ?? new(); temp = NetworkUtility.JsonDeserialize<Item>(ref reader, options) ?? new();
if (temp.EquipSlotType == EquipSlotType.Accessory) if (temp.EquipSlotType == EquipSlotType.Accessory2)
{ {
result.Accessory2 = temp; result.Accessory2 = temp;
} }

View File

@ -41,6 +41,15 @@ namespace Milimoe.FunGame.Core.Library.Common.JsonConverter
case nameof(Item.EquipSlotType): case nameof(Item.EquipSlotType):
result.EquipSlotType = (EquipSlotType)reader.GetInt32(); result.EquipSlotType = (EquipSlotType)reader.GetInt32();
break; break;
case nameof(Item.QualityType):
result.QualityType = (QualityType)reader.GetInt32();
break;
case nameof(Item.RarityType):
result.RarityType = (RarityType)reader.GetInt32();
break;
case nameof(Item.RankType):
result.RankType = (ItemRankType)reader.GetInt32();
break;
case nameof(Item.IsInGameItem): case nameof(Item.IsInGameItem):
result.IsInGameItem = reader.GetBoolean(); result.IsInGameItem = reader.GetBoolean();
break; break;
@ -101,6 +110,9 @@ namespace Milimoe.FunGame.Core.Library.Common.JsonConverter
writer.WriteNumber(nameof(Item.ItemType), (int)value.ItemType); writer.WriteNumber(nameof(Item.ItemType), (int)value.ItemType);
writer.WriteNumber(nameof(Item.WeaponType), (int)value.WeaponType); writer.WriteNumber(nameof(Item.WeaponType), (int)value.WeaponType);
writer.WriteNumber(nameof(Item.EquipSlotType), (int)value.EquipSlotType); writer.WriteNumber(nameof(Item.EquipSlotType), (int)value.EquipSlotType);
writer.WriteNumber(nameof(Item.QualityType), (int)value.QualityType);
writer.WriteNumber(nameof(Item.RarityType), (int)value.RarityType);
writer.WriteNumber(nameof(Item.RankType), (int)value.RankType);
writer.WriteBoolean(nameof(Item.IsInGameItem), value.IsInGameItem); writer.WriteBoolean(nameof(Item.IsInGameItem), value.IsInGameItem);
writer.WriteBoolean(nameof(Item.Equipable), value.Equipable); writer.WriteBoolean(nameof(Item.Equipable), value.Equipable);
writer.WriteBoolean(nameof(Item.IsPurchasable), value.IsPurchasable); writer.WriteBoolean(nameof(Item.IsPurchasable), value.IsPurchasable);

View File

@ -10,7 +10,7 @@ namespace Milimoe.FunGame.Core.Library.Common.JsonConverter
{ {
public override Skill NewInstance() public override Skill NewInstance()
{ {
return new(); return new OpenSkill(0, "", []);
} }
public override void ReadPropertyName(ref Utf8JsonReader reader, string propertyName, JsonSerializerOptions options, ref Skill result) public override void ReadPropertyName(ref Utf8JsonReader reader, string propertyName, JsonSerializerOptions options, ref Skill result)
@ -29,12 +29,24 @@ namespace Milimoe.FunGame.Core.Library.Common.JsonConverter
case nameof(Skill.GeneralDescription): case nameof(Skill.GeneralDescription):
result.GeneralDescription = reader.GetString() ?? ""; result.GeneralDescription = reader.GetString() ?? "";
break; break;
case nameof(Skill.Slogan):
result.Slogan = reader.GetString() ?? "";
break;
case nameof(Skill.Level): case nameof(Skill.Level):
result.Level = reader.GetInt32(); result.Level = reader.GetInt32();
break; break;
case nameof(Skill.SkillType): case nameof(Skill.SkillType):
result.SkillType = (SkillType)reader.GetInt32(); result.SkillType = (SkillType)reader.GetInt32();
break; break;
case nameof(Skill.CanSelectSelf):
result.CanSelectSelf = reader.GetBoolean();
break;
case nameof(Skill.CanSelectTargetCount):
result.CanSelectTargetCount = reader.GetInt32();
break;
case nameof(Skill.CanSelectTargetRange):
result.CanSelectTargetRange = reader.GetInt32();
break;
case nameof(Skill.Enable): case nameof(Skill.Enable):
result.Enable = reader.GetBoolean(); result.Enable = reader.GetBoolean();
break; break;
@ -66,11 +78,11 @@ namespace Milimoe.FunGame.Core.Library.Common.JsonConverter
result.Effects.Add(effect); result.Effects.Add(effect);
} }
break; break;
case nameof(Skill.OtherArgs): case nameof(Skill.Values):
Dictionary<string, object> others = NetworkUtility.JsonDeserialize<Dictionary<string, object>>(ref reader, options) ?? []; Dictionary<string, object> values = NetworkUtility.JsonDeserialize<Dictionary<string, object>>(ref reader, options) ?? [];
foreach (string key in others.Keys) foreach (string key in values.Keys)
{ {
result.OtherArgs.Add(key, others[key]); result.Values.Add(key, values[key]);
} }
break; break;
} }
@ -84,8 +96,12 @@ namespace Milimoe.FunGame.Core.Library.Common.JsonConverter
writer.WriteString(nameof(Skill.Name), value.Name); writer.WriteString(nameof(Skill.Name), value.Name);
writer.WriteString(nameof(Skill.Description), value.Description); writer.WriteString(nameof(Skill.Description), value.Description);
if (value.GeneralDescription.Length > 0) writer.WriteString(nameof(Skill.GeneralDescription), value.GeneralDescription); if (value.GeneralDescription.Length > 0) writer.WriteString(nameof(Skill.GeneralDescription), value.GeneralDescription);
if (value.Slogan.Length > 0) writer.WriteString(nameof(Skill.Slogan), value.Slogan);
if (value.Level > 0) writer.WriteNumber(nameof(Skill.Level), value.Level); if (value.Level > 0) writer.WriteNumber(nameof(Skill.Level), value.Level);
writer.WriteNumber(nameof(Skill.SkillType), (int)value.SkillType); writer.WriteNumber(nameof(Skill.SkillType), (int)value.SkillType);
if (value.CanSelectSelf) writer.WriteBoolean(nameof(Skill.CanSelectSelf), value.CanSelectSelf);
if (value.CanSelectTargetCount != 0) writer.WriteNumber(nameof(Skill.CanSelectTargetCount), value.CanSelectTargetCount);
if (value.CanSelectTargetRange != 0) writer.WriteNumber(nameof(Skill.CanSelectTargetRange), value.CanSelectTargetRange);
if (!value.Enable) writer.WriteBoolean(nameof(Skill.Enable), value.Enable); if (!value.Enable) writer.WriteBoolean(nameof(Skill.Enable), value.Enable);
if (value.IsInEffect) writer.WriteBoolean(nameof(Skill.IsInEffect), value.IsInEffect); if (value.IsInEffect) writer.WriteBoolean(nameof(Skill.IsInEffect), value.IsInEffect);
if (value.MPCost > 0) writer.WriteNumber(nameof(Skill.MPCost), value.MPCost); if (value.MPCost > 0) writer.WriteNumber(nameof(Skill.MPCost), value.MPCost);
@ -96,8 +112,8 @@ namespace Milimoe.FunGame.Core.Library.Common.JsonConverter
if (value.HardnessTime > 0) writer.WriteNumber(nameof(Skill.HardnessTime), value.HardnessTime); if (value.HardnessTime > 0) writer.WriteNumber(nameof(Skill.HardnessTime), value.HardnessTime);
writer.WritePropertyName(nameof(Skill.Effects)); writer.WritePropertyName(nameof(Skill.Effects));
JsonSerializer.Serialize(writer, value.Effects, options); JsonSerializer.Serialize(writer, value.Effects, options);
writer.WritePropertyName(nameof(Skill.OtherArgs)); writer.WritePropertyName(nameof(Skill.Values));
JsonSerializer.Serialize(writer, value.OtherArgs, options); JsonSerializer.Serialize(writer, value.Values, options);
writer.WriteEndObject(); writer.WriteEndObject();
} }

View File

@ -325,6 +325,22 @@ namespace Milimoe.FunGame.Core.Library.Constant
}; };
} }
public static string GetMagicResistanceName(MagicType type)
{
return type switch
{
MagicType.Starmark => "星痕抗性",
MagicType.PurityNatural => "现代结晶抗性",
MagicType.PurityContemporary => "纯粹结晶抗性",
MagicType.Bright => "光抗性",
MagicType.Shadow => "影抗性",
MagicType.Element => "元素抗性",
MagicType.Fleabane => "紫宛抗性",
MagicType.Particle => "时空抗性",
_ => "魔法抗性",
};
}
public static string GetContinuousKilling(int kills) public static string GetContinuousKilling(int kills)
{ {
if (kills > 10) return "超越神的杀戮"; if (kills > 10) return "超越神的杀戮";
@ -447,7 +463,8 @@ namespace Milimoe.FunGame.Core.Library.Constant
EquipSlotType.Weapon => "武器", EquipSlotType.Weapon => "武器",
EquipSlotType.Armor => "防具", EquipSlotType.Armor => "防具",
EquipSlotType.Shoes => "鞋子", EquipSlotType.Shoes => "鞋子",
EquipSlotType.Accessory => "饰品", EquipSlotType.Accessory1 => "饰品1",
EquipSlotType.Accessory2 => "饰品2",
_ => "" _ => ""
}; };
} }
@ -460,38 +477,11 @@ namespace Milimoe.FunGame.Core.Library.Constant
"武器" => EquipSlotType.Weapon, "武器" => EquipSlotType.Weapon,
"防具" => EquipSlotType.Armor, "防具" => EquipSlotType.Armor,
"鞋子" => EquipSlotType.Shoes, "鞋子" => EquipSlotType.Shoes,
"饰品" => EquipSlotType.Accessory, "饰品1" => EquipSlotType.Accessory1,
"饰品2" => EquipSlotType.Accessory2,
_ => EquipSlotType.None _ => EquipSlotType.None
}; };
} }
public static string GetEquipItemToSlotTypeName(EquipItemToSlot type)
{
return type switch
{
EquipItemToSlot.MagicCardPack => "魔法卡包",
EquipItemToSlot.Weapon => "武器",
EquipItemToSlot.Armor => "防具",
EquipItemToSlot.Shoes => "鞋子",
EquipItemToSlot.Accessory1 => "饰品1",
EquipItemToSlot.Accessory2 => "饰品2",
_ => ""
};
}
public static EquipItemToSlot GetEquipItemToSlotTypeFromName(string name)
{
return name switch
{
"魔法卡包" => EquipItemToSlot.MagicCardPack,
"武器" => EquipItemToSlot.Weapon,
"防具" => EquipItemToSlot.Armor,
"鞋子" => EquipItemToSlot.Shoes,
"饰品1" => EquipItemToSlot.Accessory1,
"饰品2" => EquipItemToSlot.Accessory2,
_ => EquipItemToSlot.None
};
}
} }
public class SkillSet public class SkillSet

View File

@ -1,4 +1,5 @@
using System.Text; using System.Text;
using Milimoe.FunGame.Core.Api.Utility;
using Milimoe.FunGame.Core.Entity; using Milimoe.FunGame.Core.Entity;
using Milimoe.FunGame.Core.Model; using Milimoe.FunGame.Core.Model;
@ -11,6 +12,11 @@ namespace Milimoe.FunGame.Core.Library.Constant
{ {
#region Static Variable #region Static Variable
/// <summary>
/// 支持动态扩展的工厂实例
/// </summary>
public static Factory OpenFactory { get; } = Factory.OpenFactory;
/// <summary> /// <summary>
/// 空的实体类 用于object返回 /// 空的实体类 用于object返回
/// </summary> /// </summary>

View File

@ -479,22 +479,9 @@ namespace Milimoe.FunGame.Core.Library.Constant
} }
/// <summary> /// <summary>
/// 区别于 <see cref="EquipItemToSlot"/>,这个是定义物品所属的栏位 /// 指示物品在哪个栏位上
/// </summary> /// </summary>
public enum EquipSlotType public enum EquipSlotType
{
None,
MagicCardPack,
Weapon,
Armor,
Shoes,
Accessory
}
/// <summary>
/// 区别于 <see cref="EquipSlotType"/>,这个是指示物品具体在哪个栏位上
/// </summary>
public enum EquipItemToSlot
{ {
None, None,
MagicCardPack, MagicCardPack,
@ -759,7 +746,7 @@ namespace Milimoe.FunGame.Core.Library.Constant
D D
} }
public enum ItemQualityType public enum QualityType
{ {
White, White,
Green, Green,
@ -769,7 +756,7 @@ namespace Milimoe.FunGame.Core.Library.Constant
Red Red
} }
public enum ItemRarityType public enum RarityType
{ {
OneStar, OneStar,
TwoStar, TwoStar,

View File

@ -179,4 +179,9 @@
{ {
public override string Message => "必须以异步方式读取数据 (#10036)"; public override string Message => "必须以异步方式读取数据 (#10036)";
} }
public class NotSupportedInstanceClassException : Exception
{
public override string Message => "试图构造一个不支持的类的实例 (#10037)";
}
} }

File diff suppressed because it is too large Load Diff

View File

@ -168,7 +168,7 @@
/// <summary> /// <summary>
/// 魔法值增长因子 /// 魔法值增长因子
/// </summary> /// </summary>
public double MPGrowthFactor { get; set; } = 1.5; public double MPGrowthFactor { get; set; } = 0.14;
/// <summary> /// <summary>
/// 每级增加基础攻击力 /// 每级增加基础攻击力

View File

@ -1,4 +1,3 @@
using System;
using System.Reflection; using System.Reflection;
using Milimoe.FunGame.Core.Interface.Addons; using Milimoe.FunGame.Core.Interface.Addons;
using Milimoe.FunGame.Core.Library.Common.Addon; using Milimoe.FunGame.Core.Library.Common.Addon;