实现物品系统 (#89)

* 实现物品系统

* 小修改

* 实装魔法/能量消耗减少 添加其他统计
This commit is contained in:
milimoe 2024-09-17 19:44:25 +08:00 committed by GitHub
parent 57219895fb
commit e5e70d5e7a
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
13 changed files with 572 additions and 96 deletions

View File

@ -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
/// </summary>
public Action<string> WriteLine { get; }
/// <summary>
/// 当前的行动顺序
/// </summary>
public List<Character> Queue => _queue;
/// <summary>
/// 当前已死亡的角色顺序(第一个是最早死的)
/// </summary>
@ -337,11 +341,11 @@ namespace Milimoe.FunGame.Core.Api.Utility
// 技能列表
List<Skill> 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<Item> 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<Item> 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<Skill> 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<Skill> 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
/// <summary>
/// 计算角色的数据
/// </summary>
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)} 栏位)");
}
}
}
}

View File

@ -149,7 +149,7 @@ namespace Milimoe.FunGame.Core.Entity
/// <summary>
/// 角色目前被特效施加的控制效果 [ 用于特效判断是否需要在移除特效时更改角色状态 ]
/// </summary>
public Dictionary<Effect, List<EffectControlType>> CharacterEffectControlTypes { get; } = [];
public Dictionary<Effect, List<EffectType>> CharacterEffectTypes { get; } = [];
/// <summary>
/// 角色是否是中立的 [ 战斗相关 ]
@ -804,12 +804,113 @@ namespace Milimoe.FunGame.Core.Entity
MP = Calculation.Round2Digits(MaxMP * pMP);
}
/// <summary>
/// 为角色穿戴装备必须使用此方法而不是自己去给EquipSlot里的物品赋值
/// </summary>
/// <param name="item"></param>
/// <param name="slot"></param>
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;
}
}
/// <summary>
/// 角色的属性发生变化,会影响特殊效果的计算
/// </summary>
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<EffectControlType> types = CharacterEffectControlTypes.Values.SelectMany(list => list);
IEnumerable<EffectType> 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;

View File

@ -8,26 +8,26 @@
/// <summary>
/// 魔法卡包
/// </summary>
public Item? MagicCardPack { get; set; } = null;
public Item? MagicCardPack { get; internal set; } = null;
/// <summary>
/// 武器
/// </summary>
public Item? Weapon { get; set; } = null;
public Item? Weapon { get; internal set; } = null;
/// <summary>
/// 防具
/// </summary>
public Item? Armor { get; set; } = null;
public Item? Armor { get; internal set; } = null;
/// <summary>
/// 鞋子
/// </summary>
public Item? Shoes { get; set; } = null;
public Item? Shoes { get; internal set; } = null;
/// <summary>
/// 饰品1
/// </summary>
public Item? Accessory1 { get; set; } = null;
public Item? Accessory1 { get; internal set; } = null;
/// <summary>
/// 饰品2
/// </summary>
public Item? Accessory2 { get; set; } = null;
public Item? Accessory2 { get; internal set; } = null;
}
}

View File

@ -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
/// <summary>
/// 物品的描述
/// </summary>
public string Description { get; } = "";
public virtual string Description { get; } = "";
/// <summary>
/// 物品的通用描述
/// </summary>
public virtual string GeneralDescription { get; } = "";
/// <summary>
/// 物品类型
@ -25,9 +31,9 @@ namespace Milimoe.FunGame.Core.Entity
public virtual EquipSlotType EquipSlotType { get; set; } = EquipSlotType.None;
/// <summary>
/// 物品的价格
/// 武器类型(如果是武器)
/// </summary>
public double Price { get; set; } = 0;
public virtual WeaponType WeaponType { get; set; } = WeaponType.None;
/// <summary>
/// 快捷键
@ -45,9 +51,80 @@ namespace Milimoe.FunGame.Core.Entity
public bool Enable { get; set; } = true;
/// <summary>
/// 物品所属的角色
/// 是否允许装备
/// </summary>
public Character? Character { get; set; } = null;
public bool Equipable { get; set; } = true;
/// <summary>
/// 是否允许取消装备
/// </summary>
public bool Unequipable { get; set; } = true;
/// <summary>
/// 是否是局内使用的物品(局内是指对角色生效的物品)
/// </summary>
public bool IsInGameItem { get; set; } = true;
/// <summary>
/// 是否允许购买
/// </summary>
public bool IsPurchasable { get; set; } = true;
/// <summary>
/// 物品的价格
/// </summary>
public double Price { get; set; } = 0;
/// <summary>
/// 是否允许出售
/// </summary>
public bool IsSellable { get; set; } = true;
/// <summary>
/// 下次可出售的时间
/// </summary>
public DateTime NextSellableTime { get; set; } = DateTime.MinValue;
/// <summary>
/// 是否允许交易
/// </summary>
public bool IsTradable { get; set; } = true;
/// <summary>
/// 下次可交易的时间
/// </summary>
public DateTime NextTradableTime { get; set; } = DateTime.MinValue;
/// <summary>
/// 剩余使用次数(消耗品才会用到)
/// </summary>
public int RemainUseTimes { get; set; } = 0;
/// <summary>
/// 物品所属的角色(只有装备物品,才需要设置)
/// </summary>
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;
}
}
}
}
/// <summary>
/// 所属的玩家
/// </summary>
public User? User { get; set; } = null;
/// <summary>
/// 物品拥有的技能
@ -55,11 +132,13 @@ namespace Milimoe.FunGame.Core.Entity
public SkillGroup Skills { get; set; } = new();
/// <summary>
/// 当获得物品时
/// 当装备物品时
/// </summary>
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)
{
@ -77,13 +156,41 @@ namespace Milimoe.FunGame.Core.Entity
}
/// <summary>
/// 局内使用物品触发
/// 当取消装备物品时
/// </summary>
public void UseItem(ActionQueue queue, List<Character> enemys, List<Character> teammates)
public void OnItemUnequip()
{
if (Skills.Active != null && Character != null)
if (Character != null)
{
Skills.Active.OnSkillCasted(queue, Character, enemys, teammates);
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;
}
/// <summary>
/// 局内使用物品触发 对某个角色使用
/// </summary>
public void UseItem(ActionQueue queue, Character character, List<Character> enemys, List<Character> teammates)
{
if (Skills.Active != null)
{
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() { }
/// <summary>
/// 显示物品的详细信息
/// </summary>
/// <returns></returns>
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<string> 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();
}
/// <summary>
/// 判断两个物品是否相同 检查Id.Name
/// </summary>
@ -122,5 +276,10 @@ namespace Milimoe.FunGame.Core.Entity
{
return other is Item c && c.Id + "." + c.Name == Id + "." + Name;
}
/// <summary>
/// 所属的角色
/// </summary>
private Character? _character = null;
}
}

View File

@ -13,6 +13,6 @@
/// <summary>
/// 被动技能组
/// </summary>
public HashSet<Skill> Passive { get; set; } = [];
public HashSet<Skill> Passives { get; set; } = [];
}
}

View File

@ -17,9 +17,9 @@ namespace Milimoe.FunGame.Core.Entity
/// <summary>
/// 特殊效果类型<para/>
/// 注意:如果技能特效没有原生施加控制效果,请始终保持此属性为 <see cref="EffectControlType.None"/>。
/// 注意:如果技能特效没有原生施加控制效果,请始终保持此属性为 <see cref="EffectType.None"/>。
/// </summary>
public virtual EffectControlType ControlType { get; } = EffectControlType.None;
public virtual EffectType EffectType { get; } = EffectType.None;
/// <summary>
/// 作用于自身
@ -82,7 +82,7 @@ namespace Milimoe.FunGame.Core.Entity
/// <summary>
/// 此特效的施加者,用于溯源
/// </summary>
public virtual Character? Source { get; } = null;
public virtual Character? Source { get; set; } = null;
/// <summary>
/// 游戏中的行动顺序表实例,在技能效果被触发时,此实例会获得赋值,使用时需要判断其是否存在

View File

@ -15,7 +15,7 @@ namespace Milimoe.FunGame.Core.Entity
/// <summary>
/// 普通攻击说明
/// </summary>
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) : "")}。";
/// <summary>
/// 所属的角色
@ -55,7 +55,7 @@ namespace Milimoe.FunGame.Core.Entity
/// <summary>
/// 硬直时间
/// </summary>
public double HardnessTime { get; } = 10;
public double HardnessTime { get; set; } = 10;
/// <summary>
/// 对目标(或多个目标)发起普通攻击

View File

@ -20,6 +20,11 @@ namespace Milimoe.FunGame.Core.Entity
/// </summary>
public virtual string Description { get; set; } = "";
/// <summary>
/// 技能的通用描述
/// </summary>
public virtual string GeneralDescription { get; set; } = "";
/// <summary>
/// 技能等级,等于 0 时可以称之为尚未学习
/// </summary>
@ -71,35 +76,43 @@ namespace Milimoe.FunGame.Core.Entity
[InitRequired]
public bool IsMagic => SkillType == SkillType.Magic;
/// <summary>
/// 实际魔法消耗 [ 魔法 ]
/// </summary>
public double RealMPCost => Calculation.Round2Digits(Math.Max(0, MPCost * (1 - Calculation.PercentageCheck((Character?.INT ?? 0) * 0.00125))));
/// <summary>
/// 魔法消耗 [ 魔法 ]
/// </summary>
[InitOptional]
public virtual double MPCost { get; } = 0;
public virtual double MPCost { get; set; } = 0;
/// <summary>
/// 基础魔法消耗 [ 魔法 ]
/// 实际吟唱时间 [ 魔法 ]
/// </summary>
[InitOptional]
protected virtual double BaseMPCost { get; } = 0;
public double RealCastTime => Calculation.Round2Digits(Math.Max(0, CastTime * (1 - Calculation.PercentageCheck(Character?.AccelerationCoefficient ?? 0))));
/// <summary>
/// 吟唱时间 [ 魔法 ]
/// </summary>
[InitOptional]
public virtual double CastTime { get; } = 0;
public virtual double CastTime { get; set; } = 0;
/// <summary>
/// 实际能量消耗 [ 战技 ]
/// </summary>
public double RealEPCost => IsSuperSkill ? EPCost : Calculation.Round2Digits(Math.Max(0, EPCost * (1 - Calculation.PercentageCheck((Character?.INT ?? 0) * 0.00075))));
/// <summary>
/// 能量消耗 [ 战技 ]
/// </summary>
[InitOptional]
public virtual double EPCost { get; } = 0;
public virtual double EPCost { get; set; } = 0;
/// <summary>
/// 基础能量消耗 [ 战技 ]
/// 实际冷却时间
/// </summary>
[InitOptional]
protected virtual double BaseEPCost { get; } = 0;
public double RealCD => Calculation.Round2Digits(Math.Max(0, CD * (1 - Character?.CDR ?? 0)));
/// <summary>
/// 冷却时间
@ -116,7 +129,7 @@ namespace Milimoe.FunGame.Core.Entity
/// 硬直时间
/// </summary>
[InitRequired]
public virtual double HardnessTime { get; } = 0;
public virtual double HardnessTime { get; set; } = 0;
/// <summary>
/// 效果列表
@ -238,24 +251,38 @@ namespace Milimoe.FunGame.Core.Entity
builder.AppendLine("效果结束前不可用");
}
if (IsActive)
{
if (SkillType == SkillType.Item)
{
if (RealMPCost > 0)
{
builder.AppendLine("魔法消耗:" + RealMPCost);
}
if (RealEPCost > 0)
{
builder.AppendLine("能量消耗:" + RealEPCost);
}
}
else
{
if (IsSuperSkill)
{
builder.AppendLine("能量消耗:" + EPCost);
builder.AppendLine("能量消耗:" + RealEPCost);
}
else
{
if (IsMagic)
{
builder.AppendLine("魔法消耗:" + MPCost);
builder.AppendLine("吟唱时间:" + CastTime);
builder.AppendLine("魔法消耗:" + RealMPCost);
builder.AppendLine("吟唱时间:" + RealCastTime);
}
else
{
builder.AppendLine("能量消耗:" + EPCost);
builder.AppendLine("能量消耗:" + RealEPCost);
}
}
builder.AppendLine("冷却时间:" + CD);
}
builder.AppendLine("冷却时间:" + RealCD);
builder.AppendLine("硬直时间:" + HardnessTime);
}

View File

@ -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;
}
}

View File

@ -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<Item>(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<Item>(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<Item>(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<Item>(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<Item>(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<Item>(ref reader, options) ?? new();
if (temp.EquipSlotType == Constant.EquipSlotType.Accessory2)
if (temp.EquipSlotType == EquipSlotType.Accessory)
{
result.Accessory2 = temp;
}

View File

@ -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 => "饰品",
_ => ""
};
}
}
}

View File

@ -41,10 +41,15 @@ namespace Milimoe.FunGame.Core.Library.Constant
public static Encoding DefaultEncoding => Encoding.Unicode;
/// <summary>
/// 默认的时间格式
/// 默认的时间格式 yyyy-MM-dd HH:mm:ss.fff
/// </summary>
public static string GeneralDateTimeFormat => "yyyy-MM-dd HH:mm:ss.fff";
/// <summary>
/// yyyy年MM月dd日 HH:mm:ss
/// </summary>
public static string GeneralDateTimeFormatChinese => "yyyy年MM月dd日 HH:mm:ss";
/// <summary>
/// 默认的时间值1970年8月1日8点0分0秒
/// </summary>

View File

@ -198,12 +198,12 @@ namespace Milimoe.FunGame.Core.Library.Constant
SuperSkill,
/// <summary>
/// 被动,编号 4xxx
/// 被动,编号 4xxx物品被动从5xxx开始
/// </summary>
Passive,
/// <summary>
/// 物品的主动技能,编号 5xxx
/// 物品的主动技能,编号 6xxx
/// </summary>
Item
}
@ -211,13 +211,18 @@ namespace Milimoe.FunGame.Core.Library.Constant
/// <summary>
/// 注意:具有控制效果的特效,应该和技能本身的特效(一般此项为None)区分开来。此效果被赋值会改变一些判断的结果。
/// </summary>
public enum EffectControlType
public enum EffectType
{
/// <summary>
/// 无特殊效果
/// </summary>
None,
/// <summary>
/// 这是来自装备的特效
/// </summary>
Item,
/// <summary>
/// 标记,目标受到某些技能的标记
/// </summary>
@ -467,7 +472,23 @@ namespace Milimoe.FunGame.Core.Library.Constant
Others
}
/// <summary>
/// 区别于 <see cref="EquipItemToSlot"/>,这个是定义物品所属的栏位
/// </summary>
public enum EquipSlotType
{
None,
MagicCardPack,
Weapon,
Armor,
Shoes,
Accessory
}
/// <summary>
/// 区别于 <see cref="EquipSlotType"/>,这个是指示物品具体在哪个栏位上
/// </summary>
public enum EquipItemToSlot
{
None,
MagicCardPack,
@ -597,6 +618,69 @@ namespace Milimoe.FunGame.Core.Library.Constant
INT
}
public enum WeaponType
{
/// <summary>
/// 不是武器
/// </summary>
None,
/// <summary>
/// 单手剑
/// </summary>
OneHandedSword,
/// <summary>
/// 双手重剑
/// </summary>
TwoHandedSword,
/// <summary>
/// 弓
/// </summary>
Bow,
/// <summary>
/// 手枪
/// </summary>
Pistol,
/// <summary>
/// 步枪
/// </summary>
Rifle,
/// <summary>
/// 双持短刀
/// </summary>
DualDaggers,
/// <summary>
/// 法器
/// </summary>
Talisman,
/// <summary>
/// 法杖
/// </summary>
Staff,
/// <summary>
/// 长柄
/// </summary>
Polearm,
/// <summary>
/// 拳套
/// </summary>
Gauntlet,
/// <summary>
/// 暗器
/// </summary>
HiddenWeapon
}
public enum ActionType
{
None,