diff --git a/Api/Utility/ActionQueue.cs b/Api/Utility/ActionQueue.cs index e00746a..cc919f7 100644 --- a/Api/Utility/ActionQueue.cs +++ b/Api/Utility/ActionQueue.cs @@ -1,5 +1,4 @@ using Milimoe.FunGame.Core.Entity; -using Milimoe.FunGame.Core.Interface.Entity; using Milimoe.FunGame.Core.Library.Constant; namespace Milimoe.FunGame.Core.Api.Utility @@ -14,6 +13,11 @@ namespace Milimoe.FunGame.Core.Api.Utility /// public Action WriteLine { get; } + /// + /// 当前的行动顺序 + /// + public List Queue => _queue; + /// /// 当前已死亡的角色顺序(第一个是最早死的) /// @@ -337,11 +341,11 @@ namespace Milimoe.FunGame.Core.Api.Utility // 技能列表 List skills = [.. character.Skills.Where(s => s.Level > 0 && s.SkillType != SkillType.Passive && s.Enable && !s.IsInEffect && s.CurrentCD == 0 && - (((s.SkillType == SkillType.SuperSkill || s.SkillType == SkillType.Skill) && s.EPCost <= character.EP) || (s.SkillType == SkillType.Magic && s.MPCost <= character.MP)))]; + (((s.SkillType == SkillType.SuperSkill || s.SkillType == SkillType.Skill) && s.RealEPCost <= character.EP) || (s.SkillType == SkillType.Magic && s.RealMPCost <= character.MP)))]; // 物品列表 - List items = [.. character.Items.Where(i => i.IsActive && i.Skills.Active != null && i.Enable && - i.Skills.Active.SkillType == SkillType.Item && i.Skills.Active.Enable && !i.Skills.Active.IsInEffect && i.Skills.Active.CurrentCD == 0 && i.Skills.Active.MPCost <= character.MP && i.Skills.Active.EPCost <= character.EP)]; + List items = [.. character.Items.Where(i => i.IsActive && i.Skills.Active != null && i.Enable && i.IsInGameItem && + i.Skills.Active.SkillType == SkillType.Item && i.Skills.Active.Enable && !i.Skills.Active.IsInEffect && i.Skills.Active.CurrentCD == 0 && i.Skills.Active.RealMPCost <= character.MP && i.Skills.Active.RealEPCost <= character.EP)]; // 作出了什么行动 CharacterActionType type = CharacterActionType.None; @@ -508,7 +512,7 @@ namespace Milimoe.FunGame.Core.Api.Utility character.EP = Calculation.Round2Digits(character.EP - cost); baseTime = skill.HardnessTime; - skill.CurrentCD = Calculation.Round2Digits(Math.Max(1, skill.CD * (1 - character.CDR))); + skill.CurrentCD = skill.RealCD; skill.Enable = false; WriteLine("[ " + character + $" ] 消耗了 {cost:0.##} 点能量,释放了{(skill.IsSuperSkill ? "爆发技" : "战技")} {skill.Name}!"); @@ -533,7 +537,7 @@ namespace Milimoe.FunGame.Core.Api.Utility { character.MP = Calculation.Round2Digits(character.MP - cost); baseTime = skill.HardnessTime; - skill.CurrentCD = Calculation.Round2Digits(Math.Max(1, skill.CD * (1 - character.CDR))); + skill.CurrentCD = skill.RealCD; skill.Enable = false; WriteLine("[ " + character + $" ] 消耗了 {cost:0.##} 点魔法值,释放了技能 {skill.Name}!"); @@ -563,7 +567,7 @@ namespace Milimoe.FunGame.Core.Api.Utility { character.EP = Calculation.Round2Digits(character.EP - cost); baseTime = skill.HardnessTime; - skill.CurrentCD = Calculation.Round2Digits(Math.Max(1, skill.CD * (1 - character.CDR))); + skill.CurrentCD = skill.RealCD; skill.Enable = false; WriteLine("[ " + character + $" ] 消耗了 {cost:0.##} 点能量值,释放了爆发技 {skill.Name}!"); @@ -617,7 +621,7 @@ namespace Milimoe.FunGame.Core.Api.Utility effect.OnTurnEnd(character); // 自身被动不会考虑 - if (effect.ControlType == EffectControlType.None && effect.Skill.SkillType == SkillType.Passive) + if (effect.EffectType == EffectType.None && effect.Skill.SkillType == SkillType.Passive) { continue; } @@ -727,7 +731,7 @@ namespace Milimoe.FunGame.Core.Api.Utility effect.OnTimeElapsed(character, timeToReduce); // 自身被动不会考虑 - if (effect.ControlType == EffectControlType.None && effect.Skill.SkillType == SkillType.Passive) + if (effect.EffectType == EffectType.None && effect.Skill.SkillType == SkillType.Passive) { continue; } @@ -777,14 +781,14 @@ namespace Milimoe.FunGame.Core.Api.Utility if (damage < 0) damage = 0; if (isMagicDamage) { - string dmgType = CharacterSet.GetMagicName(magicType); + string dmgType = CharacterSet.GetMagicDamageName(magicType); WriteLine("[ " + enemy + $" ] 受到了 {damage} 点{dmgType}!"); } else WriteLine("[ " + enemy + $" ] 受到了 {damage} 点物理伤害!"); enemy.HP = Calculation.Round2Digits(enemy.HP - damage); // 统计伤害 - CalculateCharacterDamageStatistics(actor, damage, isMagicDamage); + CalculateCharacterDamageStatistics(actor, enemy, damage, isMagicDamage); // 计算助攻 _assistDamage[actor][enemy] += damage; @@ -1007,6 +1011,8 @@ namespace Milimoe.FunGame.Core.Api.Utility public void DeathCalculation(Character killer, Character death) { if (!_continuousKilling.TryAdd(killer, 1)) _continuousKilling[killer] += 1; + _stats[killer].Kills += 1; + _stats[death].Deaths += 1; int money = new Random().Next(250, 350); Character[] assists = _assistDamage.Keys.Where(c => c != death && _assistDamage[c].GetPercentage(death) > 0.10).ToArray(); @@ -1020,6 +1026,7 @@ namespace Milimoe.FunGame.Core.Api.Utility if (assist != killer) { if (!_earnedMoney.TryAdd(assist, cmoney)) _earnedMoney[assist] += cmoney; + _stats[assist].Assists += 1; } else { @@ -1030,7 +1037,7 @@ namespace Milimoe.FunGame.Core.Api.Utility // 终结击杀的奖励仍然是全额的 if (_continuousKilling.TryGetValue(death, out int coefficient) && coefficient > 1) { - money += (coefficient + 1) * new Random().Next(100, 200); + money += (coefficient + 1) * new Random().Next(50, 100); string termination = CharacterSet.GetContinuousKilling(coefficient); string msg = $"[ {killer} ] 终结了 [ {death} ]{(termination != "" ? " 的" + termination : "")},获得 {money} 金钱!"; if (assists.Length > 1) @@ -1120,7 +1127,7 @@ namespace Milimoe.FunGame.Core.Api.Utility { if (skill.SkillType == SkillType.Magic) { - cost = skill.MPCost; + cost = skill.RealMPCost; if (cost > 0 && cost <= caster.MP) { return true; @@ -1132,7 +1139,7 @@ namespace Milimoe.FunGame.Core.Api.Utility } else { - cost = skill.EPCost; + cost = skill.RealEPCost; if (cost > 0 && cost <= caster.EP) { return true; @@ -1158,7 +1165,7 @@ namespace Milimoe.FunGame.Core.Api.Utility // 有 65% 欲望插队 if (new Random().NextDouble() < 0.65) { - List skills = other.Skills.Where(s => s.Level > 0 && s.SkillType == SkillType.SuperSkill && s.Enable && !s.IsInEffect && s.CurrentCD == 0 && other.EP >= s.EPCost).ToList(); + List skills = other.Skills.Where(s => s.Level > 0 && s.SkillType == SkillType.SuperSkill && s.Enable && !s.IsInEffect && s.CurrentCD == 0 && other.EP >= s.RealEPCost).ToList(); if (skills.Count > 0) { Skill skill = skills[new Random().Next(skills.Count)]; @@ -1254,7 +1261,7 @@ namespace Milimoe.FunGame.Core.Api.Utility /// /// 计算角色的数据 /// - public void CalculateCharacterDamageStatistics(Character character, double damage, bool isMagic) + public void CalculateCharacterDamageStatistics(Character character, Character characterTaken, double damage, bool isMagic) { if (_stats.TryGetValue(character, out CharacterStatistics? stats) && stats != null) { @@ -1268,6 +1275,30 @@ namespace Milimoe.FunGame.Core.Api.Utility } stats.TotalDamage = Calculation.Round2Digits(stats.TotalDamage + damage); } + if (_stats.TryGetValue(characterTaken, out CharacterStatistics? statsTaken) && statsTaken != null) + { + if (isMagic) + { + statsTaken.TotalTakenMagicDamage = Calculation.Round2Digits(statsTaken.TotalTakenMagicDamage + damage); + } + else + { + statsTaken.TotalTakenPhysicalDamage = Calculation.Round2Digits(statsTaken.TotalTakenPhysicalDamage + damage); + } + statsTaken.TotalTakenDamage = Calculation.Round2Digits(statsTaken.TotalTakenDamage + damage); + } + } + + public void Equip(Character character, EquipItemToSlot type, Item item) + { + if (character.Equip(item, type)) + { + WriteLine($"[ {character} ] 装备了 [ {item.Name} ]。({ItemSet.GetEquipSlotTypeName(type)} 栏位)"); + } + else + { + WriteLine($"[ {character} ] 取消装备了 [ {item.Name} ]。({ItemSet.GetEquipSlotTypeName(type)} 栏位)"); + } } } } diff --git a/Entity/Character/Character.cs b/Entity/Character/Character.cs index d9e9cd9..d4b9dbf 100644 --- a/Entity/Character/Character.cs +++ b/Entity/Character/Character.cs @@ -149,7 +149,7 @@ namespace Milimoe.FunGame.Core.Entity /// /// 角色目前被特效施加的控制效果 [ 用于特效判断是否需要在移除特效时更改角色状态 ] /// - public Dictionary> CharacterEffectControlTypes { get; } = []; + public Dictionary> CharacterEffectTypes { get; } = []; /// /// 角色是否是中立的 [ 战斗相关 ] @@ -804,12 +804,113 @@ namespace Milimoe.FunGame.Core.Entity MP = Calculation.Round2Digits(MaxMP * pMP); } + /// + /// 为角色穿戴装备(必须使用此方法而不是自己去给EquipSlot里的物品赋值) + /// + /// + /// + public bool Equip(Item item, EquipItemToSlot slot) + { + bool result = false; + double pastHP = HP; + double pastMaxHP = MaxHP; + double pastMP = MP; + double pastMaxMP = MaxMP; + switch (slot) + { + case EquipItemToSlot.MagicCardPack: + if (item.ItemType == ItemType.MagicCardPack) + { + UnEquip(EquipItemToSlot.MagicCardPack); + EquipSlot.MagicCardPack = item; + result = true; + } + break; + case EquipItemToSlot.Weapon: + if (item.ItemType == ItemType.Weapon) + { + UnEquip(EquipItemToSlot.Weapon); + EquipSlot.Weapon = item; + item.OnItemEquip(this); + result = true; + } + break; + case EquipItemToSlot.Armor: + if (item.ItemType == ItemType.Armor) + { + UnEquip(EquipItemToSlot.Armor); + EquipSlot.Armor = item; + item.OnItemEquip(this); + result = true; + } + break; + case EquipItemToSlot.Shoes: + if (item.ItemType == ItemType.Shoes) + { + UnEquip(EquipItemToSlot.Shoes); + EquipSlot.Shoes = item; + item.OnItemEquip(this); + result = true; + } + break; + case EquipItemToSlot.Accessory1: + if (item.ItemType == ItemType.Accessory) + { + UnEquip(EquipItemToSlot.Accessory1); + EquipSlot.Accessory1 = item; + item.OnItemEquip(this); + result = true; + } + break; + case EquipItemToSlot.Accessory2: + if (item.ItemType == ItemType.Accessory) + { + UnEquip(EquipItemToSlot.Accessory2); + EquipSlot.Accessory2 = item; + item.OnItemEquip(this); + result = true; + } + break; + } + if (result) + { + OnAttributeChanged(); + Recovery(pastHP, pastMP, pastMaxHP, pastMaxMP); + } + return result; + } + + public void UnEquip(EquipItemToSlot type) + { + switch (type) + { + case EquipItemToSlot.MagicCardPack: + EquipSlot.MagicCardPack?.OnItemUnequip(); + break; + case EquipItemToSlot.Weapon: + EquipSlot.Weapon?.OnItemUnequip(); + break; + case EquipItemToSlot.Armor: + EquipSlot.Armor?.OnItemUnequip(); + break; + case EquipItemToSlot.Shoes: + EquipSlot.Shoes?.OnItemUnequip(); + break; + case EquipItemToSlot.Accessory1: + EquipSlot.Accessory1?.OnItemUnequip(); + break; + case EquipItemToSlot.Accessory2: + EquipSlot.Accessory2?.OnItemUnequip(); + break; + } + } + /// /// 角色的属性发生变化,会影响特殊效果的计算 /// public void OnAttributeChanged() { - foreach (Effect effect in Effects) + foreach (Effect effect in Effects.Where(e => e.Level > 0).ToList()) { effect.OnAttributeChanged(this); } @@ -896,25 +997,27 @@ namespace Milimoe.FunGame.Core.Entity builder.AppendLine($"魔法值:{MP} / {MaxMP}" + (ExMP + ExMP2 > 0 ? $" [{BaseMP} + {ExMP + ExMP2}]" : "")); builder.AppendLine($"能量值:{EP} / 200"); builder.AppendLine($"攻击力:{ATK}" + (ExATK + ExATK2 > 0 ? $" [{BaseATK} + {ExATK + ExATK2}]" : "")); - builder.AppendLine($"物理护甲:{DEF}" + (ExDEF + ExDEF2 > 0 ? $" [{BaseDEF} + {ExDEF + ExDEF2}]" : "") + $" ({PDR * 100:f2}%)"); + builder.AppendLine($"物理护甲:{DEF}" + (ExDEF + ExDEF2 > 0 ? $" [{BaseDEF} + {ExDEF + ExDEF2}]" : "") + $" ({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); - builder.AppendLine($"魔法抗性:{mdf * 100:f2}%(平均)"); + builder.AppendLine($"魔法抗性:{mdf * 100:0.##}%(平均)"); double exSPD = Calculation.Round2Digits(AGI * 0.65 + ExSPD); - builder.AppendLine($"行动速度:{SPD}" + (exSPD > 0 ? $" [{InitialSPD} + {exSPD}]" : "") + $" ({ActionCoefficient * 100:f2}%)"); + builder.AppendLine($"行动速度:{SPD}" + (exSPD > 0 ? $" [{InitialSPD} + {exSPD}]" : "") + $" ({ActionCoefficient * 100:0.##}%)"); builder.AppendLine($"核心属性:{CharacterSet.GetPrimaryAttributeName(PrimaryAttribute)}"); builder.AppendLine($"力量:{STR}" + (ExSTR > 0 ? $" [{BaseSTR} + {ExSTR}]" : "")); builder.AppendLine($"敏捷:{AGI}" + (ExAGI > 0 ? $" [{BaseAGI} + {ExAGI}]" : "")); builder.AppendLine($"智力:{INT}" + (ExINT > 0 ? $" [{BaseINT} + {ExINT}]" : "")); builder.AppendLine($"生命回复:{HR}" + (ExHR > 0 ? $" [{Calculation.Round2Digits(InitialHR + STR * 0.25)} + {ExHR}]" : "")); builder.AppendLine($"魔法回复:{MR}" + (ExMR > 0 ? $" [{Calculation.Round2Digits(InitialMR + INT * 0.1)} + {ExMR}]" : "")); - builder.AppendLine($"暴击率:{CritRate * 100:f2}%"); - builder.AppendLine($"暴击伤害:{CritDMG * 100:f2}%"); - builder.AppendLine($"闪避率:{EvadeRate * 100:f2}%"); - builder.AppendLine($"冷却缩减:{CDR * 100:f2}%"); - builder.AppendLine($"加速系数:{AccelerationCoefficient * 100:f2}%"); - builder.AppendLine($"物理穿透:{PhysicalPenetration * 100:f2}%"); - builder.AppendLine($"魔法穿透:{MagicalPenetration * 100:f2}%"); + 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.##}%"); + builder.AppendLine($"魔法消耗减少:{INT * 0.00125 * 100:0.##}%"); + builder.AppendLine($"能量消耗减少:{INT * 0.00075 * 100:0.##}%"); if (CharacterState != CharacterState.Actionable) { @@ -945,17 +1048,43 @@ namespace Milimoe.FunGame.Core.Entity if (Items.Count > 0) { - builder.AppendLine("== 角色物品 =="); - foreach (Item item in Items) + builder.AppendLine("== 装备栏 =="); + if (EquipSlot.MagicCardPack != null) { - builder.Append(item.ToString()); + builder.AppendLine(ItemSet.GetEquipSlotTypeName(EquipItemToSlot.MagicCardPack) + ":" + EquipSlot.MagicCardPack.Name); + builder.AppendLine(EquipSlot.MagicCardPack.Description); + } + if (EquipSlot.Weapon != null) + { + builder.AppendLine(ItemSet.GetEquipSlotTypeName(EquipItemToSlot.Weapon) + ":" + EquipSlot.Weapon.Name); + builder.AppendLine(EquipSlot.Weapon.Description); + } + if (EquipSlot.Armor != null) + { + builder.AppendLine(ItemSet.GetEquipSlotTypeName(EquipItemToSlot.Armor) + ":" + EquipSlot.Armor.Name); + builder.AppendLine(EquipSlot.Armor.Description); + } + if (EquipSlot.Shoes != null) + { + builder.AppendLine(ItemSet.GetEquipSlotTypeName(EquipItemToSlot.Shoes) + ":" + EquipSlot.Shoes.Name); + builder.AppendLine(EquipSlot.Shoes.Description); + } + if (EquipSlot.Accessory1 != null) + { + builder.AppendLine(ItemSet.GetEquipSlotTypeName(EquipItemToSlot.Accessory1) + ":" + EquipSlot.Accessory1.Name); + builder.AppendLine(EquipSlot.Accessory1.Description); + } + if (EquipSlot.Accessory2 != null) + { + builder.AppendLine(ItemSet.GetEquipSlotTypeName(EquipItemToSlot.Accessory2) + ":" + EquipSlot.Accessory2.Name); + builder.AppendLine(EquipSlot.Accessory2.Description); } } if (Effects.Count > 0) { builder.AppendLine("== 状态栏 =="); - foreach (Effect effect in Effects) + foreach (Effect effect in Effects.Where(e => e.EffectType != EffectType.Item)) { builder.Append(effect.ToString()); } @@ -1000,7 +1129,7 @@ namespace Milimoe.FunGame.Core.Entity if (Effects.Count > 0) { builder.AppendLine("== 状态栏 =="); - foreach (Effect effect in Effects) + foreach (Effect effect in Effects.Where(e => e.EffectType != EffectType.Item)) { builder.Append(effect.ToString()); } @@ -1027,9 +1156,9 @@ namespace Milimoe.FunGame.Core.Entity isBattleRestricted = states.Any(state => state == CharacterState.BattleRestricted); isSkillRestricted = states.Any(state => state == CharacterState.SkillRestricted); - IEnumerable types = CharacterEffectControlTypes.Values.SelectMany(list => list); + IEnumerable types = CharacterEffectTypes.Values.SelectMany(list => list); // 判断角色的控制效果 - IsUnselectable = types.Any(type => type == EffectControlType.Unselectable); + IsUnselectable = types.Any(type => type == EffectType.Unselectable); bool isControl = isNotActionable || isActionRestricted || isBattleRestricted || isSkillRestricted; bool isCasting = CharacterState == CharacterState.Casting; diff --git a/Entity/Character/EquipSlot.cs b/Entity/Character/EquipSlot.cs index 1a6894e..0e0256f 100644 --- a/Entity/Character/EquipSlot.cs +++ b/Entity/Character/EquipSlot.cs @@ -8,26 +8,26 @@ /// /// 魔法卡包 /// - public Item? MagicCardPack { get; set; } = null; + public Item? MagicCardPack { get; internal set; } = null; /// /// 武器 /// - public Item? Weapon { get; set; } = null; + public Item? Weapon { get; internal set; } = null; /// /// 防具 /// - public Item? Armor { get; set; } = null; + public Item? Armor { get; internal set; } = null; /// /// 鞋子 /// - public Item? Shoes { get; set; } = null; + public Item? Shoes { get; internal set; } = null; /// /// 饰品1 /// - public Item? Accessory1 { get; set; } = null; + public Item? Accessory1 { get; internal set; } = null; /// /// 饰品2 /// - public Item? Accessory2 { get; set; } = null; + public Item? Accessory2 { get; internal set; } = null; } } diff --git a/Entity/Item/Item.cs b/Entity/Item/Item.cs index 8a88cbe..2e88668 100644 --- a/Entity/Item/Item.cs +++ b/Entity/Item/Item.cs @@ -1,4 +1,5 @@ -using Milimoe.FunGame.Core.Api.Utility; +using System.Text; +using Milimoe.FunGame.Core.Api.Utility; using Milimoe.FunGame.Core.Interface.Entity; using Milimoe.FunGame.Core.Library.Constant; @@ -12,7 +13,12 @@ namespace Milimoe.FunGame.Core.Entity /// /// 物品的描述 /// - public string Description { get; } = ""; + public virtual string Description { get; } = ""; + + /// + /// 物品的通用描述 + /// + public virtual string GeneralDescription { get; } = ""; /// /// 物品类型 @@ -23,11 +29,11 @@ namespace Milimoe.FunGame.Core.Entity /// 物品槽位 /// public virtual EquipSlotType EquipSlotType { get; set; } = EquipSlotType.None; - + /// - /// 物品的价格 + /// 武器类型(如果是武器) /// - public double Price { get; set; } = 0; + public virtual WeaponType WeaponType { get; set; } = WeaponType.None; /// /// 快捷键 @@ -43,11 +49,82 @@ namespace Milimoe.FunGame.Core.Entity /// 是否可用(涉及冷却和禁用等) /// public bool Enable { get; set; } = true; + + /// + /// 是否允许装备 + /// + public bool Equipable { get; set; } = true; + + /// + /// 是否允许取消装备 + /// + public bool Unequipable { get; set; } = true; /// - /// 物品所属的角色 + /// 是否是局内使用的物品(局内是指对角色生效的物品) /// - public Character? Character { get; set; } = null; + public bool IsInGameItem { get; set; } = true; + + /// + /// 是否允许购买 + /// + public bool IsPurchasable { get; set; } = true; + + /// + /// 物品的价格 + /// + public double Price { get; set; } = 0; + + /// + /// 是否允许出售 + /// + public bool IsSellable { get; set; } = true; + + /// + /// 下次可出售的时间 + /// + public DateTime NextSellableTime { get; set; } = DateTime.MinValue; + + /// + /// 是否允许交易 + /// + public bool IsTradable { get; set; } = true; + + /// + /// 下次可交易的时间 + /// + public DateTime NextTradableTime { get; set; } = DateTime.MinValue; + + /// + /// 剩余使用次数(消耗品才会用到) + /// + public int RemainUseTimes { get; set; } = 0; + + /// + /// 物品所属的角色(只有装备物品,才需要设置) + /// + public Character? Character + { + get => _character; + set + { + _character = value; + if (Skills.Active != null) Skills.Active.Character = _character; + foreach (Skill skill in Skills.Passives) + { + skill.Character = _character; + foreach (Effect e in skill.Effects) + { + e.Source = _character; + } + } + } + } + + /// + /// 所属的玩家 + /// + public User? User { get; set; } = null; /// /// 物品拥有的技能 @@ -55,11 +132,13 @@ namespace Milimoe.FunGame.Core.Entity public SkillGroup Skills { get; set; } = new(); /// - /// 当获得物品时 + /// 当装备物品时 /// - public void OnItemGained() + public void OnItemEquip(Character character) { - foreach (Skill skill in Skills.Passive) + Character = character; + Character.Items.Add(this); + foreach (Skill skill in Skills.Passives) { if (!skill.IsActive && skill.Level > 0) { @@ -75,15 +154,43 @@ namespace Milimoe.FunGame.Core.Entity } } } + + /// + /// 当取消装备物品时 + /// + public void OnItemUnequip() + { + if (Character != null) + { + if (Skills.Active != null) + { + foreach (Effect e in Character.Effects.Where(e => e.Skill == Skills.Active && e.Level > 0).ToList()) + { + Character.Effects.Remove(e); + e.OnEffectLost(Character); + } + } + foreach (Skill skill in Skills.Passives) + { + foreach (Effect e in Character.Effects.Where(e => e.Skill == skill && e.Level > 0).ToList()) + { + Character.Effects.Remove(e); + e.OnEffectLost(Character); + } + } + Character.Items.Remove(this); + } + Character = null; + } /// - /// 局内使用物品触发 + /// 局内使用物品触发 对某个角色使用 /// - public void UseItem(ActionQueue queue, List enemys, List teammates) + public void UseItem(ActionQueue queue, Character character, List enemys, List teammates) { - if (Skills.Active != null && Character != null) + if (Skills.Active != null) { - Skills.Active.OnSkillCasted(queue, Character, enemys, teammates); + Skills.Active.OnSkillCasted(queue, character, enemys, teammates); } OnItemUsed(); } @@ -105,14 +212,61 @@ namespace Milimoe.FunGame.Core.Entity } - protected Item(ItemType type, EquipSlotType slot = EquipSlotType.None) + protected Item(ItemType type, bool isInGame = true, EquipSlotType slot = EquipSlotType.None) { ItemType = type; + IsInGameItem = isInGame; EquipSlotType = slot; } internal Item() { } + /// + /// 显示物品的详细信息 + /// + /// + public override string ToString() + { + StringBuilder builder = new(); + + builder.AppendLine($"【{Name}】"); + builder.AppendLine($"{ItemSet.GetItemTypeName(ItemType)}" + (IsPurchasable && Price > 0 ? $" 售价:{Price}" : "")); + + if (RemainUseTimes > 0) + { + builder.AppendLine($"剩余可用次数:{RemainUseTimes}"); + } + + List sellandtrade = [""]; + if (IsSellable) + { + sellandtrade.Add("可出售"); + } + if (IsTradable) + { + sellandtrade.Add("可交易"); + } + builder.AppendLine(string.Join(" ", sellandtrade).Trim()); + + if (!IsSellable && NextSellableTime != DateTime.MinValue) + { + builder.AppendLine($"此物品将在 {NextSellableTime.ToString(General.GeneralDateTimeFormatChinese)} 后可出售"); + } + + if (!IsTradable && NextTradableTime != DateTime.MinValue) + { + builder.AppendLine($"此物品将在 {NextTradableTime.ToString(General.GeneralDateTimeFormatChinese)} 后可交易"); + } + + if (Skills.Active != null) builder.AppendLine($"{Skills.Active.ToString()}"); + foreach (Skill skill in Skills.Passives) + { + builder.AppendLine($"{skill.ToString()}"); + } + + return builder.ToString(); + } + /// /// 判断两个物品是否相同 检查Id.Name /// @@ -122,5 +276,10 @@ namespace Milimoe.FunGame.Core.Entity { return other is Item c && c.Id + "." + c.Name == Id + "." + Name; } + + /// + /// 所属的角色 + /// + private Character? _character = null; } } diff --git a/Entity/Item/SkillGroup.cs b/Entity/Item/SkillGroup.cs index af95058..7eb4649 100644 --- a/Entity/Item/SkillGroup.cs +++ b/Entity/Item/SkillGroup.cs @@ -13,6 +13,6 @@ /// /// 被动技能组 /// - public HashSet Passive { get; set; } = []; + public HashSet Passives { get; set; } = []; } } diff --git a/Entity/Skill/Effect.cs b/Entity/Skill/Effect.cs index 8b9d1e6..0297050 100644 --- a/Entity/Skill/Effect.cs +++ b/Entity/Skill/Effect.cs @@ -17,9 +17,9 @@ namespace Milimoe.FunGame.Core.Entity /// /// 特殊效果类型 - /// 注意:如果技能特效没有原生施加控制效果,请始终保持此属性为 。 + /// 注意:如果技能特效没有原生施加控制效果,请始终保持此属性为 。 /// - public virtual EffectControlType ControlType { get; } = EffectControlType.None; + public virtual EffectType EffectType { get; } = EffectType.None; /// /// 作用于自身 @@ -82,7 +82,7 @@ namespace Milimoe.FunGame.Core.Entity /// /// 此特效的施加者,用于溯源 /// - public virtual Character? Source { get; } = null; + public virtual Character? Source { get; set; } = null; /// /// 游戏中的行动顺序表实例,在技能效果被触发时,此实例会获得赋值,使用时需要判断其是否存在 diff --git a/Entity/Skill/NormalAttack.cs b/Entity/Skill/NormalAttack.cs index eb79d22..152b3ac 100644 --- a/Entity/Skill/NormalAttack.cs +++ b/Entity/Skill/NormalAttack.cs @@ -15,7 +15,7 @@ namespace Milimoe.FunGame.Core.Entity /// /// 普通攻击说明 /// - public string Description => $"对目标敌人造成 {Calculation.Round4Digits((1.0 + 0.05 * (Level - 1)) * 100)}% [ {Damage} ] 点{(IsMagic ? CharacterSet.GetMagicName(MagicType) : "物理伤害")}。"; + public string Description => $"对目标敌人造成 {Calculation.Round4Digits((1.0 + 0.05 * (Level - 1)) * 100)}% [ {Damage} ] 点{(IsMagic ? CharacterSet.GetMagicDamageName(MagicType) : "物理伤害")}。"; /// /// 所属的角色 @@ -55,7 +55,7 @@ namespace Milimoe.FunGame.Core.Entity /// /// 硬直时间 /// - public double HardnessTime { get; } = 10; + public double HardnessTime { get; set; } = 10; /// /// 对目标(或多个目标)发起普通攻击 diff --git a/Entity/Skill/Skill.cs b/Entity/Skill/Skill.cs index 21a8426..4969903 100644 --- a/Entity/Skill/Skill.cs +++ b/Entity/Skill/Skill.cs @@ -19,6 +19,11 @@ namespace Milimoe.FunGame.Core.Entity /// 技能描述 /// public virtual string Description { get; set; } = ""; + + /// + /// 技能的通用描述 + /// + public virtual string GeneralDescription { get; set; } = ""; /// /// 技能等级,等于 0 时可以称之为尚未学习 @@ -71,35 +76,43 @@ namespace Milimoe.FunGame.Core.Entity [InitRequired] public bool IsMagic => SkillType == SkillType.Magic; + /// + /// 实际魔法消耗 [ 魔法 ] + /// + public double RealMPCost => Calculation.Round2Digits(Math.Max(0, MPCost * (1 - Calculation.PercentageCheck((Character?.INT ?? 0) * 0.00125)))); + /// /// 魔法消耗 [ 魔法 ] /// [InitOptional] - public virtual double MPCost { get; } = 0; + public virtual double MPCost { get; set; } = 0; /// - /// 基础魔法消耗 [ 魔法 ] + /// 实际吟唱时间 [ 魔法 ] /// - [InitOptional] - protected virtual double BaseMPCost { get; } = 0; + public double RealCastTime => Calculation.Round2Digits(Math.Max(0, CastTime * (1 - Calculation.PercentageCheck(Character?.AccelerationCoefficient ?? 0)))); /// /// 吟唱时间 [ 魔法 ] /// [InitOptional] - public virtual double CastTime { get; } = 0; + public virtual double CastTime { get; set; } = 0; + + /// + /// 实际能量消耗 [ 战技 ] + /// + public double RealEPCost => IsSuperSkill ? EPCost : Calculation.Round2Digits(Math.Max(0, EPCost * (1 - Calculation.PercentageCheck((Character?.INT ?? 0) * 0.00075)))); /// /// 能量消耗 [ 战技 ] /// [InitOptional] - public virtual double EPCost { get; } = 0; + public virtual double EPCost { get; set; } = 0; /// - /// 基础能量消耗 [ 战技 ] + /// 实际冷却时间 /// - [InitOptional] - protected virtual double BaseEPCost { get; } = 0; + public double RealCD => Calculation.Round2Digits(Math.Max(0, CD * (1 - Character?.CDR ?? 0))); /// /// 冷却时间 @@ -116,7 +129,7 @@ namespace Milimoe.FunGame.Core.Entity /// 硬直时间 /// [InitRequired] - public virtual double HardnessTime { get; } = 0; + public virtual double HardnessTime { get; set; } = 0; /// /// 效果列表 @@ -239,23 +252,37 @@ namespace Milimoe.FunGame.Core.Entity } if (IsActive) { - if (IsSuperSkill) + if (SkillType == SkillType.Item) { - builder.AppendLine("能量消耗:" + EPCost); + if (RealMPCost > 0) + { + builder.AppendLine("魔法消耗:" + RealMPCost); + } + if (RealEPCost > 0) + { + builder.AppendLine("能量消耗:" + RealEPCost); + } } else { - if (IsMagic) + if (IsSuperSkill) { - builder.AppendLine("魔法消耗:" + MPCost); - builder.AppendLine("吟唱时间:" + CastTime); + builder.AppendLine("能量消耗:" + RealEPCost); } else { - builder.AppendLine("能量消耗:" + EPCost); + if (IsMagic) + { + builder.AppendLine("魔法消耗:" + RealMPCost); + builder.AppendLine("吟唱时间:" + RealCastTime); + } + else + { + builder.AppendLine("能量消耗:" + RealEPCost); + } } } - builder.AppendLine("冷却时间:" + CD); + builder.AppendLine("冷却时间:" + RealCD); builder.AppendLine("硬直时间:" + HardnessTime); } diff --git a/Entity/Statistics/CharacterStatistics.cs b/Entity/Statistics/CharacterStatistics.cs index 88e9e87..fc41131 100644 --- a/Entity/Statistics/CharacterStatistics.cs +++ b/Entity/Statistics/CharacterStatistics.cs @@ -6,6 +6,10 @@ public double TotalPhysicalDamage { get; set; } = 0; public double TotalMagicDamage { get; set; } = 0; public double TotalRealDamage { get; set; } = 0; + public double TotalTakenDamage { get; set; } = 0; + public double TotalTakenPhysicalDamage { get; set; } = 0; + public double TotalTakenMagicDamage { get; set; } = 0; + public double TotalTakenRealDamage { get; set; } = 0; public double AvgDamage { get; set; } = 0; public double AvgPhysicalDamage { get; set; } = 0; public double AvgMagicDamage { get; set; } = 0; @@ -21,12 +25,12 @@ public double DamagePerSecond { get; set; } = 0; public double TotalEarnedMoney { get; set; } = 0; public double AvgEarnedMoney { get; set; } = 0; - public double Kills { get; set; } = 0; - public double Deaths { get; set; } = 0; - public double Assists { get; set; } = 0; - public double Plays { get; set; } = 0; - public double Wins { get; set; } = 0; - public double Loses { get; set; } = 0; + public int Kills { get; set; } = 0; + public int Deaths { get; set; } = 0; + public int Assists { get; set; } = 0; + public int Plays { get; set; } = 0; + public int Wins { get; set; } = 0; + public int Loses { get; set; } = 0; public double Winrates { get; set; } = 0; } } diff --git a/Library/Common/JsonConverter/EquipSlotConverter.cs b/Library/Common/JsonConverter/EquipSlotConverter.cs index 41ad97e..b567c09 100644 --- a/Library/Common/JsonConverter/EquipSlotConverter.cs +++ b/Library/Common/JsonConverter/EquipSlotConverter.cs @@ -2,6 +2,7 @@ using Milimoe.FunGame.Core.Api.Utility; using Milimoe.FunGame.Core.Entity; using Milimoe.FunGame.Core.Library.Common.Architecture; +using Milimoe.FunGame.Core.Library.Constant; namespace Milimoe.FunGame.Core.Library.Common.JsonConverter { @@ -19,42 +20,42 @@ namespace Milimoe.FunGame.Core.Library.Common.JsonConverter { case nameof(EquipSlot.MagicCardPack): temp = NetworkUtility.JsonDeserialize(ref reader, options) ?? new(); - if (temp.EquipSlotType == Constant.EquipSlotType.MagicCardPack) + if (temp.EquipSlotType == EquipSlotType.MagicCardPack) { result.MagicCardPack = temp; } break; case nameof(EquipSlot.Weapon): temp = NetworkUtility.JsonDeserialize(ref reader, options) ?? new(); - if (temp.EquipSlotType == Constant.EquipSlotType.Weapon) + if (temp.EquipSlotType == EquipSlotType.Weapon) { result.Weapon = temp; } break; case nameof(EquipSlot.Armor): temp = NetworkUtility.JsonDeserialize(ref reader, options) ?? new(); - if (temp.EquipSlotType == Constant.EquipSlotType.Armor) + if (temp.EquipSlotType == EquipSlotType.Armor) { result.Armor = temp; } break; case nameof(EquipSlot.Shoes): temp = NetworkUtility.JsonDeserialize(ref reader, options) ?? new(); - if (temp.EquipSlotType == Constant.EquipSlotType.Shoes) + if (temp.EquipSlotType == EquipSlotType.Shoes) { result.Shoes = temp; } break; case nameof(EquipSlot.Accessory1): temp = NetworkUtility.JsonDeserialize(ref reader, options) ?? new(); - if (temp.EquipSlotType == Constant.EquipSlotType.Accessory1) + if (temp.EquipSlotType == EquipSlotType.Accessory) { result.Accessory1 = temp; } break; case nameof(EquipSlot.Accessory2): temp = NetworkUtility.JsonDeserialize(ref reader, options) ?? new(); - if (temp.EquipSlotType == Constant.EquipSlotType.Accessory2) + if (temp.EquipSlotType == EquipSlotType.Accessory) { result.Accessory2 = temp; } diff --git a/Library/Constant/ConstantSet.cs b/Library/Constant/ConstantSet.cs index 1c514ce..96ef5ae 100644 --- a/Library/Constant/ConstantSet.cs +++ b/Library/Constant/ConstantSet.cs @@ -308,7 +308,7 @@ namespace Milimoe.FunGame.Core.Library.Constant }; } - public static string GetMagicName(MagicType type) + public static string GetMagicDamageName(MagicType type) { return type switch { @@ -358,4 +358,40 @@ namespace Milimoe.FunGame.Core.Library.Constant }; } } + + public class ItemSet + { + public static string GetItemTypeName(ItemType type) + { + return type switch + { + ItemType.MagicCardPack => "魔法卡包", + ItemType.Weapon => "武器", + ItemType.Armor => "防具", + ItemType.Shoes => "鞋子", + ItemType.Accessory => "饰品", + ItemType.Consumable => "消耗品", + ItemType.Collectible => "收藏品", + ItemType.SpecialItem => "特殊物品", + ItemType.QuestItem => "任务物品", + ItemType.GiftBox => "礼包", + ItemType.Others => "其他", + _ => "" + }; + } + + public static string GetEquipSlotTypeName(EquipItemToSlot type) + { + return type switch + { + EquipItemToSlot.MagicCardPack => "魔法卡包", + EquipItemToSlot.Weapon => "武器", + EquipItemToSlot.Armor => "防具", + EquipItemToSlot.Shoes => "鞋子", + EquipItemToSlot.Accessory1 => "饰品1", + EquipItemToSlot.Accessory2 => "饰品", + _ => "" + }; + } + } } diff --git a/Library/Constant/General.cs b/Library/Constant/General.cs index d7163b1..4229a5f 100644 --- a/Library/Constant/General.cs +++ b/Library/Constant/General.cs @@ -41,9 +41,14 @@ namespace Milimoe.FunGame.Core.Library.Constant public static Encoding DefaultEncoding => Encoding.Unicode; /// - /// 默认的时间格式 + /// 默认的时间格式 yyyy-MM-dd HH:mm:ss.fff /// public static string GeneralDateTimeFormat => "yyyy-MM-dd HH:mm:ss.fff"; + + /// + /// yyyy年MM月dd日 HH:mm:ss + /// + public static string GeneralDateTimeFormatChinese => "yyyy年MM月dd日 HH:mm:ss"; /// /// 默认的时间值(1970年8月1日8点0分0秒) diff --git a/Library/Constant/TypeEnum.cs b/Library/Constant/TypeEnum.cs index ae35bce..d37e8c3 100644 --- a/Library/Constant/TypeEnum.cs +++ b/Library/Constant/TypeEnum.cs @@ -198,12 +198,12 @@ namespace Milimoe.FunGame.Core.Library.Constant SuperSkill, /// - /// 被动,编号 4xxx + /// 被动,编号 4xxx(物品被动从5xxx开始) /// Passive, /// - /// 物品的主动技能,编号 5xxx + /// 物品的主动技能,编号 6xxx /// Item } @@ -211,12 +211,17 @@ namespace Milimoe.FunGame.Core.Library.Constant /// /// 注意:具有控制效果的特效,应该和技能本身的特效(一般此项为None)区分开来。此效果被赋值会改变一些判断的结果。 /// - public enum EffectControlType + public enum EffectType { /// /// 无特殊效果 /// None, + + /// + /// 这是来自装备的特效 + /// + Item, /// /// 标记,目标受到某些技能的标记 @@ -467,7 +472,23 @@ namespace Milimoe.FunGame.Core.Library.Constant Others } + /// + /// 区别于 ,这个是定义物品所属的栏位 + /// public enum EquipSlotType + { + None, + MagicCardPack, + Weapon, + Armor, + Shoes, + Accessory + } + + /// + /// 区别于 ,这个是指示物品具体在哪个栏位上 + /// + public enum EquipItemToSlot { None, MagicCardPack, @@ -597,6 +618,69 @@ namespace Milimoe.FunGame.Core.Library.Constant INT } + public enum WeaponType + { + /// + /// 不是武器 + /// + None, + + /// + /// 单手剑 + /// + OneHandedSword, + + /// + /// 双手重剑 + /// + TwoHandedSword, + + /// + /// 弓 + /// + Bow, + + /// + /// 手枪 + /// + Pistol, + + /// + /// 步枪 + /// + Rifle, + + /// + /// 双持短刀 + /// + DualDaggers, + + /// + /// 法器 + /// + Talisman, + + /// + /// 法杖 + /// + Staff, + + /// + /// 长柄 + /// + Polearm, + + /// + /// 拳套 + /// + Gauntlet, + + /// + /// 暗器 + /// + HiddenWeapon + } + public enum ActionType { None,