diff --git a/Entity/Character/Character.cs b/Entity/Character/Character.cs
index b61706b..82c8dcc 100644
--- a/Entity/Character/Character.cs
+++ b/Entity/Character/Character.cs
@@ -8,7 +8,6 @@ namespace Milimoe.FunGame.Core.Entity
///
/// 角色需要使用 Factory.Get 的方式来构造,并赋值 标记的属性
/// 在使用时仅需要调用 方法即可获得相同对象
- /// 不建议继承
///
public class Character : BaseEntity
{
diff --git a/Entity/Character/Unit.cs b/Entity/Character/Unit.cs
new file mode 100644
index 0000000..d4f72c5
--- /dev/null
+++ b/Entity/Character/Unit.cs
@@ -0,0 +1,481 @@
+using System.Text;
+using Milimoe.FunGame.Core.Api.Utility;
+using Milimoe.FunGame.Core.Library.Constant;
+
+namespace Milimoe.FunGame.Core.Entity
+{
+ ///
+ /// 是一个用于描述生物的单元对象(单位),而 是一种高级单位(单位单位/英雄单位)
+ /// 和单位一样,使用 标记的需要初始赋值的属性
+ ///
+ public class Unit : Character
+ {
+ ///
+ /// 单位名称
+ ///
+ public override string Name { get; set; } = "";
+
+ ///
+ /// 获取单位名称以及所属玩家
+ ///
+ ///
+ public override string ToString()
+ {
+ string str = Name;
+ if (User != null && User.Username != "")
+ {
+ str += "(" + User.Username + ")";
+ }
+ return str;
+ }
+
+ ///
+ /// 获取单位名称以及所属玩家,包含等级
+ ///
+ ///
+ public new string ToStringWithLevel()
+ {
+ string str = Name + " - 等级 " + Level;
+ if (User != null && User.Username != "")
+ {
+ str += "(" + User.Username + ")";
+ }
+ return str;
+ }
+
+ ///
+ /// 获取单位的详细信息
+ ///
+ ///
+ public new string GetInfo(bool showUser = true, bool showGrowth = true, bool showEXP = false)
+ {
+ StringBuilder builder = new();
+
+ builder.AppendLine(showUser ? ToStringWithLevel() : ToStringWithLevelWithOutUser());
+ builder.AppendLine($"等级:{Level} / {General.GameplayEquilibriumConstant.MaxLevel}");
+ double exHP = ExHP + ExHP2 + ExHP3;
+ builder.AppendLine($"生命值:{HP:0.##} / {MaxHP:0.##}" + (exHP != 0 ? $" [{BaseHP:0.##} {(exHP >= 0 ? "+" : "-")} {Math.Abs(exHP):0.##}]" : ""));
+ double exMP = ExMP + ExMP2 + ExMP3;
+ builder.AppendLine($"魔法值:{MP:0.##} / {MaxMP:0.##}" + (exMP != 0 ? $" [{BaseMP:0.##} {(exMP >= 0 ? "+" : "-")} {Math.Abs(exMP):0.##}]" : ""));
+ double exATK = ExATK + ExATK2 + ExATK3;
+ builder.AppendLine($"攻击力:{ATK:0.##}" + (exATK != 0 ? $" [{BaseATK:0.##} {(exATK >= 0 ? "+" : "-")} {Math.Abs(exATK):0.##}]" : ""));
+ double exDEF = ExDEF + ExDEF2 + ExDEF3;
+ builder.AppendLine($"物理护甲:{DEF:0.##}" + (exDEF != 0 ? $" [{BaseDEF:0.##} {(exMP >= 0 ? "+" : "-")} {Math.Abs(exDEF):0.##}]" : "") + $" ({PDR * 100:0.##}%)");
+ double mdf = Calculation.Round4Digits((MDF.None + MDF.Starmark + MDF.PurityNatural + MDF.PurityContemporary +
+ MDF.Bright + MDF.Shadow + MDF.Element + MDF.Fleabane + MDF.Particle) / 9) * 100;
+ if (Calculation.IsApproximatelyZero(mdf)) mdf = 0;
+ builder.AppendLine($"魔法抗性:{mdf:0.##}%(平均)");
+ double exSPD = AGI * General.GameplayEquilibriumConstant.AGItoSPDMultiplier + ExSPD;
+ builder.AppendLine($"行动速度:{SPD:0.##}" + (exSPD != 0 ? $" [{InitialSPD:0.##} {(exSPD >= 0 ? "+" : "-")} {Math.Abs(exSPD):0.##}]" : "") + $" ({ActionCoefficient * 100:0.##}%)");
+ builder.AppendLine($"生命回复:{HR:0.##}" + (ExHR != 0 ? $" [{InitialHR + STR * General.GameplayEquilibriumConstant.STRtoHRFactor:0.##} {(ExHR >= 0 ? "+" : "-")} {Math.Abs(ExHR):0.##}]" : ""));
+ builder.AppendLine($"魔法回复:{MR:0.##}" + (ExMR != 0 ? $" [{InitialMR + INT * General.GameplayEquilibriumConstant.INTtoMRFactor:0.##} {(ExMR >= 0 ? "+" : "-")} {Math.Abs(ExMR):0.##}]" : ""));
+ builder.AppendLine($"暴击率:{CritRate * 100:0.##}%");
+ builder.AppendLine($"暴击伤害:{CritDMG * 100:0.##}%");
+ builder.AppendLine($"闪避率:{EvadeRate * 100:0.##}%");
+ builder.AppendLine($"冷却缩减:{CDR * 100:0.##}%");
+ builder.AppendLine($"加速系数:{AccelerationCoefficient * 100:0.##}%");
+ builder.AppendLine($"物理穿透:{PhysicalPenetration * 100:0.##}%");
+ builder.AppendLine($"魔法穿透:{MagicalPenetration * 100:0.##}%");
+
+ if (CharacterState != CharacterState.Actionable)
+ {
+ builder.AppendLine(CharacterSet.GetCharacterState(CharacterState));
+ }
+
+ if (IsNeutral)
+ {
+ builder.AppendLine("单位是无敌的");
+ }
+
+ if (IsUnselectable)
+ {
+ builder.AppendLine("单位是不可选中的");
+ }
+
+ builder.AppendLine("== 普通攻击 ==");
+ builder.Append(NormalAttack.ToString());
+
+ if (Skills.Count > 0)
+ {
+ builder.AppendLine("== 单位技能 ==");
+ foreach (Skill skill in Skills)
+ {
+ builder.Append(skill.ToString());
+ }
+ }
+
+ if (EquipSlot.Any())
+ {
+ builder.AppendLine("== 装备栏 ==");
+ if (EquipSlot.MagicCardPack != null)
+ {
+ builder.AppendLine($"[{ItemSet.GetQualityTypeName(EquipSlot.MagicCardPack.QualityType)}]" + ItemSet.GetEquipSlotTypeName(EquipSlotType.MagicCardPack) + ":" + EquipSlot.MagicCardPack.Name);
+ builder.AppendLine(EquipSlot.MagicCardPack.Description);
+ }
+ if (EquipSlot.Weapon != null)
+ {
+ builder.AppendLine($"[{ItemSet.GetQualityTypeName(EquipSlot.Weapon.QualityType)}]" + ItemSet.GetEquipSlotTypeName(EquipSlotType.Weapon) + ":" + EquipSlot.Weapon.Name);
+ builder.AppendLine(EquipSlot.Weapon.Description);
+ }
+ if (EquipSlot.Armor != null)
+ {
+ builder.AppendLine($"[{ItemSet.GetQualityTypeName(EquipSlot.Armor.QualityType)}]" + ItemSet.GetEquipSlotTypeName(EquipSlotType.Armor) + ":" + EquipSlot.Armor.Name);
+ builder.AppendLine(EquipSlot.Armor.Description);
+ }
+ if (EquipSlot.Shoes != null)
+ {
+ builder.AppendLine($"[{ItemSet.GetQualityTypeName(EquipSlot.Shoes.QualityType)}]" + ItemSet.GetEquipSlotTypeName(EquipSlotType.Shoes) + ":" + EquipSlot.Shoes.Name);
+ builder.AppendLine(EquipSlot.Shoes.Description);
+ }
+ if (EquipSlot.Accessory1 != null)
+ {
+ builder.AppendLine($"[{ItemSet.GetQualityTypeName(EquipSlot.Accessory1.QualityType)}]" + ItemSet.GetEquipSlotTypeName(EquipSlotType.Accessory1) + ":" + EquipSlot.Accessory1.Name);
+ builder.AppendLine(EquipSlot.Accessory1.Description);
+ }
+ if (EquipSlot.Accessory2 != null)
+ {
+ builder.AppendLine($"[{ItemSet.GetQualityTypeName(EquipSlot.Accessory2.QualityType)}]" + ItemSet.GetEquipSlotTypeName(EquipSlotType.Accessory2) + ":" + EquipSlot.Accessory2.Name);
+ builder.AppendLine(EquipSlot.Accessory2.Description);
+ }
+ }
+
+ if (Items.Count > 0)
+ {
+ builder.AppendLine("== 单位背包 ==");
+ foreach (Item item in Items)
+ {
+ builder.Append(item.ToString());
+ }
+ }
+
+ if (Effects.Where(e => e.EffectType != EffectType.Item).Any())
+ {
+ builder.AppendLine("== 状态栏 ==");
+ foreach (Effect effect in Effects.Where(e => e.EffectType != EffectType.Item))
+ {
+ builder.Append(effect.ToString());
+ }
+ }
+
+ /**
+ * 意义不明(✖)的代码
+ */
+ if (showGrowth == showEXP)
+ {
+ showGrowth.ToString();
+ }
+
+ return builder.ToString();
+ }
+
+ ///
+ /// 获取单位的简略信息
+ ///
+ ///
+ public new string GetSimpleInfo(bool showUser = true, bool showGrowth = true, bool showEXP = false, bool showBasicOnly = false)
+ {
+ StringBuilder builder = new();
+
+ builder.AppendLine(showUser ? ToStringWithLevel() : ToStringWithLevelWithOutUser());
+ builder.AppendLine($"等级:{Level} / {General.GameplayEquilibriumConstant.MaxLevel}");
+ double exHP = ExHP + ExHP2 + ExHP3;
+ builder.AppendLine($"生命值:{HP:0.##} / {MaxHP:0.##}" + (exHP != 0 ? $" [{BaseHP:0.##} {(exHP >= 0 ? "+" : "-")} {Math.Abs(exHP):0.##}]" : ""));
+ double exMP = ExMP + ExMP2 + ExMP3;
+ builder.AppendLine($"魔法值:{MP:0.##} / {MaxMP:0.##}" + (exMP != 0 ? $" [{BaseMP:0.##} {(exMP >= 0 ? "+" : "-")} {Math.Abs(exMP):0.##}]" : ""));
+ double exATK = ExATK + ExATK2 + ExATK3;
+ builder.AppendLine($"攻击力:{ATK:0.##}" + (exATK != 0 ? $" [{BaseATK:0.##} {(exATK >= 0 ? "+" : "-")} {Math.Abs(exATK):0.##}]" : ""));
+ double exDEF = ExDEF + ExDEF2 + ExDEF3;
+ builder.AppendLine($"物理护甲:{DEF:0.##}" + (exDEF != 0 ? $" [{BaseDEF:0.##} {(exMP >= 0 ? "+" : "-")} {Math.Abs(exDEF):0.##}]" : "") + $" ({PDR * 100:0.##}%)");
+ double mdf = Calculation.Round4Digits((MDF.None + MDF.Starmark + MDF.PurityNatural + MDF.PurityContemporary +
+ MDF.Bright + MDF.Shadow + MDF.Element + MDF.Fleabane + MDF.Particle) / 9) * 100;
+ if (Calculation.IsApproximatelyZero(mdf)) mdf = 0;
+ builder.AppendLine($"魔法抗性:{mdf:0.##}%(平均)");
+ double exSPD = AGI * General.GameplayEquilibriumConstant.AGItoSPDMultiplier + ExSPD;
+ builder.AppendLine($"行动速度:{SPD:0.##}" + (exSPD != 0 ? $" [{InitialSPD:0.##} {(exSPD >= 0 ? "+" : "-")} {Math.Abs(exSPD):0.##}]" : "") + $" ({ActionCoefficient * 100:0.##}%)");
+ builder.AppendLine($"生命回复:{HR:0.##}" + (ExHR != 0 ? $" [{InitialHR + STR * General.GameplayEquilibriumConstant.STRtoHRFactor:0.##} {(ExHR >= 0 ? "+" : "-")} {Math.Abs(ExHR):0.##}]" : ""));
+ builder.AppendLine($"魔法回复:{MR:0.##}" + (ExMR != 0 ? $" [{InitialMR + INT * General.GameplayEquilibriumConstant.INTtoMRFactor:0.##} {(ExMR >= 0 ? "+" : "-")} {Math.Abs(ExMR):0.##}]" : ""));
+
+ if (!showBasicOnly)
+ {
+ if (CharacterState != CharacterState.Actionable)
+ {
+ builder.AppendLine(CharacterSet.GetCharacterState(CharacterState));
+ }
+
+ if (IsNeutral)
+ {
+ builder.AppendLine("单位是无敌的");
+ }
+
+ if (IsUnselectable)
+ {
+ builder.AppendLine("单位是不可选中的");
+ }
+
+ if (Skills.Count > 0)
+ {
+ builder.AppendLine("== 单位技能 ==");
+ builder.AppendLine(string.Join(",", Skills.Select(s => s.Name)));
+ }
+
+ if (EquipSlot.Any())
+ {
+ builder.AppendLine("== 已装备槽位 ==");
+ List types = [];
+ if (EquipSlot.MagicCardPack != null)
+ {
+ types.Add(EquipSlotType.MagicCardPack);
+ }
+ if (EquipSlot.Weapon != null)
+ {
+ types.Add(EquipSlotType.Weapon);
+ }
+ if (EquipSlot.Armor != null)
+ {
+ types.Add(EquipSlotType.Armor);
+ }
+ if (EquipSlot.Shoes != null)
+ {
+ types.Add(EquipSlotType.Shoes);
+ }
+ if (EquipSlot.Accessory1 != null)
+ {
+ types.Add(EquipSlotType.Accessory1);
+ }
+ if (EquipSlot.Accessory2 != null)
+ {
+ types.Add(EquipSlotType.Accessory2);
+ }
+ builder.AppendLine(string.Join(",", types.Select(ItemSet.GetEquipSlotTypeName)));
+ }
+
+ if (Effects.Where(e => e.EffectType != EffectType.Item).Any())
+ {
+ builder.AppendLine("== 状态栏 ==");
+ builder.Append(string.Join(",", Effects.Where(e => e.EffectType != EffectType.Item).Select(e => e.Name)));
+ }
+ }
+
+ /**
+ * 意义不明(✖)的代码
+ */
+ if (showGrowth == showEXP)
+ {
+ showGrowth.ToString();
+ }
+
+ return builder.ToString();
+ }
+
+ ///
+ /// 获取战斗状态的信息
+ ///
+ ///
+ ///
+ public new string GetInBattleInfo(double hardnessTimes)
+ {
+ StringBuilder builder = new();
+
+ builder.AppendLine(ToStringWithLevel());
+ double exHP = ExHP + ExHP2 + ExHP3;
+ builder.AppendLine($"生命值:{HP:0.##} / {MaxHP:0.##}" + (exHP != 0 ? $" [{BaseHP:0.##} {(exHP >= 0 ? "+" : "-")} {Math.Abs(exHP):0.##}]" : ""));
+ double exMP = ExMP + ExMP2 + ExMP3;
+ builder.AppendLine($"魔法值:{MP:0.##} / {MaxMP:0.##}" + (exMP != 0 ? $" [{BaseMP:0.##} {(exMP >= 0 ? "+" : "-")} {Math.Abs(exMP):0.##}]" : ""));
+ double exATK = ExATK + ExATK2 + ExATK3;
+ builder.AppendLine($"攻击力:{ATK:0.##}" + (exATK != 0 ? $" [{BaseATK:0.##} {(exATK >= 0 ? "+" : "-")} {Math.Abs(exATK):0.##}]" : ""));
+
+ if (CharacterState != CharacterState.Actionable)
+ {
+ builder.AppendLine(CharacterSet.GetCharacterState(CharacterState));
+ }
+
+ if (IsNeutral)
+ {
+ builder.AppendLine("单位是中立单位,处于无敌状态");
+ }
+
+ if (IsUnselectable)
+ {
+ builder.AppendLine("单位是不可选中的");
+ }
+
+ builder.AppendLine($"硬直时间:{hardnessTimes:0.##}");
+
+ if (Effects.Where(e => e.EffectType != EffectType.Item).Any())
+ {
+ builder.AppendLine("== 状态栏 ==");
+ foreach (Effect effect in Effects.Where(e => e.EffectType != EffectType.Item))
+ {
+ builder.Append(effect.ToString());
+ }
+ }
+
+ return builder.ToString();
+ }
+
+ ///
+ /// 获取战斗状态的信息(简略版)
+ ///
+ ///
+ ///
+ public new string GetSimpleInBattleInfo(double hardnessTimes)
+ {
+ StringBuilder builder = new();
+
+ builder.AppendLine(ToStringWithLevel());
+ double exHP = ExHP + ExHP2 + ExHP3;
+ builder.AppendLine($"生命值:{HP:0.##} / {MaxHP:0.##}" + (exHP != 0 ? $" [{BaseHP:0.##} {(exHP >= 0 ? "+" : "-")} {Math.Abs(exHP):0.##}]" : ""));
+ double exMP = ExMP + ExMP2 + ExMP3;
+ builder.AppendLine($"魔法值:{MP:0.##} / {MaxMP:0.##}" + (exMP != 0 ? $" [{BaseMP:0.##} {(exMP >= 0 ? "+" : "-")} {Math.Abs(exMP):0.##}]" : ""));
+ double exATK = ExATK + ExATK2 + ExATK3;
+ builder.AppendLine($"攻击力:{ATK:0.##}" + (exATK != 0 ? $" [{BaseATK:0.##} {(exATK >= 0 ? "+" : "-")} {Math.Abs(exATK):0.##}]" : ""));
+ builder.AppendLine($"硬直时间:{hardnessTimes:0.##}");
+
+ if (Effects.Where(e => e.EffectType != EffectType.Item).Any())
+ {
+ builder.AppendLine("== 状态栏 ==");
+ builder.Append(string.Join(",", Effects.Where(e => e.EffectType != EffectType.Item).Select(e => e.Name)));
+ }
+
+ return builder.ToString();
+ }
+
+ ///
+ /// 获取单位的技能信息
+ ///
+ ///
+ public new string GetSkillInfo(bool showUser = true)
+ {
+ StringBuilder builder = new();
+
+ builder.AppendLine(showUser ? ToStringWithLevel() : ToStringWithLevelWithOutUser());
+
+ if (CharacterState != CharacterState.Actionable)
+ {
+ builder.AppendLine(CharacterSet.GetCharacterState(CharacterState));
+ }
+
+ if (IsNeutral)
+ {
+ builder.AppendLine("单位是无敌的");
+ }
+
+ if (IsUnselectable)
+ {
+ builder.AppendLine("单位是不可选中的");
+ }
+
+ builder.AppendLine("== 普通攻击 ==");
+ builder.Append(NormalAttack.ToString());
+
+ if (Skills.Count > 0)
+ {
+ builder.AppendLine("== 单位技能 ==");
+ foreach (Skill skill in Skills)
+ {
+ builder.Append(skill.ToString());
+ }
+ }
+
+ if (Effects.Where(e => e.EffectType != EffectType.Item).Any())
+ {
+ builder.AppendLine("== 状态栏 ==");
+ foreach (Effect effect in Effects.Where(e => e.EffectType != EffectType.Item))
+ {
+ builder.Append(effect.ToString());
+ }
+ }
+
+ return builder.ToString();
+ }
+
+ ///
+ /// 获取单位的物品信息
+ ///
+ ///
+ public new string GetItemInfo(bool showUser = true, bool showGrowth = true, bool showEXP = false)
+ {
+ StringBuilder builder = new();
+
+ builder.AppendLine(showUser ? ToStringWithLevel() : ToStringWithLevelWithOutUser());
+ builder.AppendLine($"等级:{Level} / {General.GameplayEquilibriumConstant.MaxLevel}");
+ double exHP = ExHP + ExHP2 + ExHP3;
+ builder.AppendLine($"生命值:{HP:0.##} / {MaxHP:0.##}" + (exHP != 0 ? $" [{BaseHP:0.##} {(exHP >= 0 ? "+" : "-")} {Math.Abs(exHP):0.##}]" : ""));
+ double exMP = ExMP + ExMP2 + ExMP3;
+ builder.AppendLine($"魔法值:{MP:0.##} / {MaxMP:0.##}" + (exMP != 0 ? $" [{BaseMP:0.##} {(exMP >= 0 ? "+" : "-")} {Math.Abs(exMP):0.##}]" : ""));
+ double exATK = ExATK + ExATK2 + ExATK3;
+ builder.AppendLine($"攻击力:{ATK:0.##}" + (exATK != 0 ? $" [{BaseATK:0.##} {(exATK >= 0 ? "+" : "-")} {Math.Abs(exATK):0.##}]" : ""));
+ double exDEF = ExDEF + ExDEF2 + ExDEF3;
+ builder.AppendLine($"物理护甲:{DEF:0.##}" + (exDEF != 0 ? $" [{BaseDEF:0.##} {(exMP >= 0 ? "+" : "-")} {Math.Abs(exDEF):0.##}]" : "") + $" ({PDR * 100:0.##}%)");
+ double mdf = Calculation.Round4Digits((MDF.None + MDF.Starmark + MDF.PurityNatural + MDF.PurityContemporary +
+ MDF.Bright + MDF.Shadow + MDF.Element + MDF.Fleabane + MDF.Particle) / 9) * 100;
+ if (Calculation.IsApproximatelyZero(mdf)) mdf = 0;
+ builder.AppendLine($"魔法抗性:{mdf:0.##}%(平均)");
+ double exSPD = AGI * General.GameplayEquilibriumConstant.AGItoSPDMultiplier + ExSPD;
+ builder.AppendLine($"行动速度:{SPD:0.##}" + (exSPD != 0 ? $" [{InitialSPD:0.##} {(exSPD >= 0 ? "+" : "-")} {Math.Abs(exSPD):0.##}]" : "") + $" ({ActionCoefficient * 100:0.##}%)");
+ builder.AppendLine($"生命回复:{HR:0.##}" + (ExHR != 0 ? $" [{InitialHR + STR * General.GameplayEquilibriumConstant.STRtoHRFactor:0.##} {(ExHR >= 0 ? "+" : "-")} {Math.Abs(ExHR):0.##}]" : ""));
+ builder.AppendLine($"魔法回复:{MR:0.##}" + (ExMR != 0 ? $" [{InitialMR + INT * General.GameplayEquilibriumConstant.INTtoMRFactor:0.##} {(ExMR >= 0 ? "+" : "-")} {Math.Abs(ExMR):0.##}]" : ""));
+ builder.AppendLine($"暴击率:{CritRate * 100:0.##}%");
+ builder.AppendLine($"暴击伤害:{CritDMG * 100:0.##}%");
+ builder.AppendLine($"闪避率:{EvadeRate * 100:0.##}%");
+ builder.AppendLine($"冷却缩减:{CDR * 100:0.##}%");
+ builder.AppendLine($"加速系数:{AccelerationCoefficient * 100:0.##}%");
+ builder.AppendLine($"物理穿透:{PhysicalPenetration * 100:0.##}%");
+ builder.AppendLine($"魔法穿透:{MagicalPenetration * 100:0.##}%");
+
+ if (EquipSlot.Any())
+ {
+ builder.AppendLine("== 装备栏 ==");
+ if (EquipSlot.MagicCardPack != null)
+ {
+ builder.AppendLine($"[{ItemSet.GetQualityTypeName(EquipSlot.MagicCardPack.QualityType)}]" + ItemSet.GetEquipSlotTypeName(EquipSlotType.MagicCardPack) + ":" + EquipSlot.MagicCardPack.Name);
+ builder.AppendLine(EquipSlot.MagicCardPack.Description);
+ }
+ if (EquipSlot.Weapon != null)
+ {
+ builder.AppendLine($"[{ItemSet.GetQualityTypeName(EquipSlot.Weapon.QualityType)}]" + ItemSet.GetEquipSlotTypeName(EquipSlotType.Weapon) + ":" + EquipSlot.Weapon.Name);
+ builder.AppendLine(EquipSlot.Weapon.Description);
+ }
+ if (EquipSlot.Armor != null)
+ {
+ builder.AppendLine($"[{ItemSet.GetQualityTypeName(EquipSlot.Armor.QualityType)}]" + ItemSet.GetEquipSlotTypeName(EquipSlotType.Armor) + ":" + EquipSlot.Armor.Name);
+ builder.AppendLine(EquipSlot.Armor.Description);
+ }
+ if (EquipSlot.Shoes != null)
+ {
+ builder.AppendLine($"[{ItemSet.GetQualityTypeName(EquipSlot.Shoes.QualityType)}]" + ItemSet.GetEquipSlotTypeName(EquipSlotType.Shoes) + ":" + EquipSlot.Shoes.Name);
+ builder.AppendLine(EquipSlot.Shoes.Description);
+ }
+ if (EquipSlot.Accessory1 != null)
+ {
+ builder.AppendLine($"[{ItemSet.GetQualityTypeName(EquipSlot.Accessory1.QualityType)}]" + ItemSet.GetEquipSlotTypeName(EquipSlotType.Accessory1) + ":" + EquipSlot.Accessory1.Name);
+ builder.AppendLine(EquipSlot.Accessory1.Description);
+ }
+ if (EquipSlot.Accessory2 != null)
+ {
+ builder.AppendLine($"[{ItemSet.GetQualityTypeName(EquipSlot.Accessory2.QualityType)}]" + ItemSet.GetEquipSlotTypeName(EquipSlotType.Accessory2) + ":" + EquipSlot.Accessory2.Name);
+ builder.AppendLine(EquipSlot.Accessory2.Description);
+ }
+ }
+
+ if (Items.Count > 0)
+ {
+ builder.AppendLine("== 单位背包 ==");
+ foreach (Item item in Items)
+ {
+ builder.Append(item.ToString());
+ }
+ }
+
+ /**
+ * 意义不明(✖)的代码
+ */
+ if (showGrowth == showEXP)
+ {
+ showGrowth.ToString();
+ }
+
+ return builder.ToString();
+ }
+ }
+}
diff --git a/Entity/System/Activity.cs b/Entity/System/Activity.cs
new file mode 100644
index 0000000..e471d17
--- /dev/null
+++ b/Entity/System/Activity.cs
@@ -0,0 +1,122 @@
+using System.Text;
+using Milimoe.FunGame.Core.Library.Common.Event;
+using Milimoe.FunGame.Core.Library.Constant;
+
+namespace Milimoe.FunGame.Core.Entity
+{
+ public class Activity(long id, string name, DateTime startTime, DateTime endTime)
+ {
+ public long Id { get; set; } = id;
+ public string Name { get; set; } = name;
+ public DateTime StartTime { get; set; } = startTime;
+ public DateTime EndTime { get; set; } = endTime;
+ public ActivityState Status { get; private set; } = ActivityState.Future;
+ public HashSet Quests { get; set; } = [];
+
+ // 事件
+ public event Action? UserAccess;
+ public event Action? UserGetActivityInfo;
+
+ public void UnRegisterUserAccess()
+ {
+ UserAccess = null;
+ }
+
+ public void UnRegisterUserGetActivityInfo()
+ {
+ UserGetActivityInfo = null;
+ }
+
+ public void UpdateState()
+ {
+ ActivityState newState;
+ DateTime now = DateTime.Now;
+ DateTime upComingTime = StartTime.AddHours(-6);
+
+ if (now < upComingTime)
+ {
+ newState = ActivityState.Future;
+ }
+ else if (now >= upComingTime && now < StartTime)
+ {
+ newState = ActivityState.Upcoming;
+ }
+ else if (now >= StartTime && now < EndTime)
+ {
+ newState = ActivityState.InProgress;
+ }
+ else
+ {
+ newState = ActivityState.Ended;
+ }
+
+ if (Status != newState)
+ {
+ Status = newState;
+ foreach (Quest quest in Quests)
+ {
+ if (newState == ActivityState.InProgress)
+ {
+ if (quest.Status == QuestState.NotStarted && quest.QuestType == QuestType.Progressive)
+ {
+ quest.Status = QuestState.InProgress;
+ }
+ }
+ else if (newState == ActivityState.Ended)
+ {
+ if (quest.Status == QuestState.NotStarted || quest.Status == QuestState.InProgress)
+ {
+ quest.Status = QuestState.Missed;
+ }
+ }
+ }
+ }
+ }
+
+ public bool AllowUserAccess(long userId, long questId = 0)
+ {
+ UpdateState();
+ ActivityEventArgs args = new(userId, questId, this);
+ UserAccess?.Invoke(args);
+ return args.AllowAccess;
+ }
+
+ public void GetActivityInfo(long userId, long questId = 0)
+ {
+ UpdateState();
+ ActivityEventArgs args = new(userId, questId, this);
+ UserGetActivityInfo?.Invoke(args);
+ }
+
+ public string ToString(bool showQuests)
+ {
+ UpdateState();
+ StringBuilder builder = new();
+
+ builder.AppendLine($"☆--- [{Name}] ---☆");
+ string status = Status switch
+ {
+ ActivityState.Future => "预告中",
+ ActivityState.Upcoming => "即将开始",
+ ActivityState.InProgress => "进行中",
+ _ => "已结束"
+ };
+ builder.AppendLine($"活动状态:{status}");
+ builder.AppendLine($"开始时间:{StartTime.ToString(General.GeneralDateTimeFormatChinese)}");
+ builder.AppendLine($"结束时间:{EndTime.ToString(General.GeneralDateTimeFormatChinese)}");
+
+ if (showQuests && Quests.Count > 0)
+ {
+ builder.AppendLine("=== 任务列表 ===");
+ builder.AppendLine(string.Join("\r\n", Quests));
+ }
+
+ return builder.ToString().Trim();
+ }
+
+ public override string ToString()
+ {
+ return ToString(true);
+ }
+ }
+}
diff --git a/Entity/System/Quest.cs b/Entity/System/Quest.cs
index b754f56..1d225ac 100644
--- a/Entity/System/Quest.cs
+++ b/Entity/System/Quest.cs
@@ -13,7 +13,26 @@ namespace Milimoe.FunGame.Core.Entity
public double MaterialsAward { get; set; } = 0;
public HashSet- Awards { get; set; } = [];
public Dictionary AwardsCount { get; set; } = [];
- public string AwardsString { get; set; } = "";
+ public string AwardsString
+ {
+ get
+ {
+ List awards = [];
+ if (CreditsAward > 0)
+ {
+ awards.Add($"{General.GameplayEquilibriumConstant.InGameCurrency} * {CreditsAward}");
+ }
+ if (MaterialsAward > 0)
+ {
+ awards.Add($"{General.GameplayEquilibriumConstant.InGameMaterial} * {MaterialsAward}");
+ }
+ foreach (Item item in Awards)
+ {
+ awards.Add($"[{ItemSet.GetQualityTypeName(item.QualityType)}|{ItemSet.GetItemTypeName(item.ItemType)}] {item.Name} * {AwardsCount[item.Name]}");
+ }
+ return string.Join(",", awards);
+ }
+ }
public DateTime? StartTime { get; set; } = null;
public DateTime? SettleTime { get; set; } = null;
public QuestType QuestType { get; set; } = QuestType.Continuous;
@@ -29,21 +48,6 @@ namespace Milimoe.FunGame.Core.Entity
progressString = $"\r\n当前进度:{Progress}/{MaxProgress}";
}
- List awards = [];
- if (CreditsAward > 0)
- {
- awards.Add($"{General.GameplayEquilibriumConstant.InGameCurrency} * {CreditsAward}");
- }
- if (MaterialsAward > 0)
- {
- awards.Add($"{General.GameplayEquilibriumConstant.InGameMaterial} * {MaterialsAward}");
- }
- foreach (Item item in Awards)
- {
- awards.Add($"[{ItemSet.GetQualityTypeName(item.QualityType)}|{ItemSet.GetItemTypeName(item.ItemType)}] {item.Name} * {AwardsCount[item.Name]}");
- }
- AwardsString = string.Join(",", awards);
-
return $"{Id}. {Name}\r\n" +
$"{Description}\r\n" +
(QuestType == QuestType.Continuous ? $"需要时间:{EstimatedMinutes} 分钟\r\n" : "") +
@@ -53,24 +57,13 @@ namespace Milimoe.FunGame.Core.Entity
+ "\r\n"
: "") +
$"完成奖励:{AwardsString}\r\n" +
- $"任务状态:{GetStatus()}" + progressString +
+ $"任务状态:{CommonSet.GetQuestStatus(Status)}" + progressString +
(SettleTime.HasValue ? $"\r\n结算时间:{SettleTime.Value.ToString(General.GeneralDateTimeFormatChinese)}" : "");
}
- private string GetStatus()
- {
- return Status switch
- {
- QuestState.InProgress => "进行中",
- QuestState.Completed => "已完成",
- QuestState.Settled => "已结算",
- _ => "未开始"
- };
- }
-
public override bool Equals(IBaseEntity? other)
{
- return other is Quest && other.Id == Id;
+ return other is Quest && other.GetIdName() == GetIdName();
}
}
}
diff --git a/Library/Common/Event/SendTalkEventArgs.cs b/Library/Common/Event/SendTalkEventArgs.cs
index 2aef9c0..7388751 100644
--- a/Library/Common/Event/SendTalkEventArgs.cs
+++ b/Library/Common/Event/SendTalkEventArgs.cs
@@ -1,12 +1,7 @@
namespace Milimoe.FunGame.Core.Library.Common.Event
{
- public class SendTalkEventArgs : GeneralEventArgs
+ public class SendTalkEventArgs(string message = "") : GeneralEventArgs
{
- public string Message { get; set; } = "";
-
- public SendTalkEventArgs(string message = "")
- {
- this.Message = message;
- }
+ public string Message { get; set; } = message;
}
}
diff --git a/Library/Common/Event/UserActivityEventArgs.cs b/Library/Common/Event/UserActivityEventArgs.cs
index d8786a5..7f12986 100644
--- a/Library/Common/Event/UserActivityEventArgs.cs
+++ b/Library/Common/Event/UserActivityEventArgs.cs
@@ -1,13 +1,16 @@
-using Milimoe.FunGame.Core.Library.Constant;
+using Milimoe.FunGame.Core.Entity;
+using Milimoe.FunGame.Core.Library.Constant;
namespace Milimoe.FunGame.Core.Library.Common.Event
{
- public class UserActivityEventArgs(long userId, ActivityState activityState, DateTime startTime, DateTime endTime) : GeneralEventArgs
+ public class ActivityEventArgs(long userId, long questId, Activity activity) : EventArgs
{
public long UserId { get; } = userId;
- public ActivityState ActivityState { get; } = activityState;
- public DateTime StartTime { get; } = startTime;
- public DateTime EndTime { get; } = endTime;
+ public long QuestId { get; } = questId;
+ public Activity Activity { get; } = activity;
+ public ActivityState ActivityState { get; } = activity.Status;
+ public DateTime StartTime { get; } = activity.StartTime;
+ public DateTime EndTime { get; } = activity.EndTime;
public bool AllowAccess { get; set; } = false;
}
}
diff --git a/Library/Constant/ConstantSet.cs b/Library/Constant/ConstantSet.cs
index 1e6dcb0..9c53918 100644
--- a/Library/Constant/ConstantSet.cs
+++ b/Library/Constant/ConstantSet.cs
@@ -18,6 +18,18 @@ namespace Milimoe.FunGame.Core.Library.Constant
_ => "I/"
};
}
+
+ public static string GetQuestStatus(QuestState status)
+ {
+ return status switch
+ {
+ QuestState.InProgress => "进行中",
+ QuestState.Completed => "已完成",
+ QuestState.Settled => "已结算",
+ QuestState.Missed => "未完成",
+ _ => "未开始"
+ };
+ }
}
///
diff --git a/Library/Constant/StateEnum.cs b/Library/Constant/StateEnum.cs
index db67c8e..49094ad 100644
--- a/Library/Constant/StateEnum.cs
+++ b/Library/Constant/StateEnum.cs
@@ -92,7 +92,8 @@ namespace Milimoe.FunGame.Core.Library.Constant
NotStarted,
InProgress,
Completed,
- Settled
+ Settled,
+ Missed
}
public enum ActivityState
diff --git a/Model/EventCenter.cs b/Model/EventCenter.cs
new file mode 100644
index 0000000..b463ead
--- /dev/null
+++ b/Model/EventCenter.cs
@@ -0,0 +1,134 @@
+using Milimoe.FunGame.Core.Entity;
+using Milimoe.FunGame.Core.Library.Common.Event;
+
+namespace Milimoe.FunGame.Core.Model
+{
+ public class EventCenter
+ {
+ public static EventCenter Instance { get; } = new();
+
+ public Dictionary> Events { get; } = [];
+
+ public Dictionary Stores { get; set; } = [];
+
+ public HashSet this[string name]
+ {
+ get
+ {
+ if (Events.TryGetValue(name, out HashSet? activities) && activities != null)
+ {
+ return activities;
+ }
+ return [];
+ }
+ set
+ {
+ AddOrUpdateEvent(name, value);
+ }
+ }
+
+ public Activity? GetActivity(string eventName, string activityName)
+ {
+ if (Events.TryGetValue(eventName, out HashSet? activities) && activities != null && activities.FirstOrDefault(a => a.Name == activityName) is Activity activity)
+ {
+ return activity;
+ }
+ return null;
+ }
+
+ public void AddOrUpdateEvent(string name, IEnumerable activities)
+ {
+ Events[name] = new(activities);
+ }
+
+ public bool RemoveEvent(string name)
+ {
+ return Events.Remove(name);
+ }
+
+ public Store? GetStore(string name)
+ {
+ if (Stores.TryGetValue(name, out Store? store))
+ {
+ return store;
+ }
+ return null;
+ }
+
+ public void AddOrUpdateStore(string name, Store store)
+ {
+ Stores[name] = store;
+ }
+
+ public bool RemoveStore(string name)
+ {
+ return Stores.Remove(name);
+ }
+
+ public bool AddActivity(string eventName, Activity activity)
+ {
+ if (Events.TryGetValue(eventName, out HashSet? activities) && activities != null)
+ {
+ return activities.Add(activity);
+ }
+ else
+ {
+ Events[eventName] = [activity];
+ }
+ return false;
+ }
+
+ public bool RemoveActivity(string eventName, Activity activity)
+ {
+ if (Events.TryGetValue(eventName, out HashSet? activities) && activities != null)
+ {
+ return activities.Remove(activity);
+ }
+ return false;
+ }
+
+ public void RegisterUserAccessEventHandler(string eventName, Action handler)
+ {
+ if (Events.TryGetValue(eventName, out HashSet? activities) && activities != null)
+ {
+ foreach (Activity activity in activities)
+ {
+ activity.UserAccess += handler;
+ }
+ }
+ }
+
+ public void RegisterUserGetActivityInfoEventHandler(string eventName, Action handler)
+ {
+ if (Events.TryGetValue(eventName, out HashSet? activities) && activities != null)
+ {
+ foreach (Activity activity in activities)
+ {
+ activity.UserGetActivityInfo += handler;
+ }
+ }
+ }
+
+ public void UnRegisterUserAccess(string eventName)
+ {
+ if (Events.TryGetValue(eventName, out HashSet? activities) && activities != null)
+ {
+ foreach (Activity activity in activities)
+ {
+ activity.UnRegisterUserAccess();
+ }
+ }
+ }
+
+ public void UnRegisterUserGetActivityInfo(string eventName)
+ {
+ if (Events.TryGetValue(eventName, out HashSet? activities) && activities != null)
+ {
+ foreach (Activity activity in activities)
+ {
+ activity.UnRegisterUserGetActivityInfo();
+ }
+ }
+ }
+ }
+}