mirror of
https://github.com/project-redbud/FunGame-Core.git
synced 2025-04-23 12:39:35 +08:00
动态工厂可以构造主动技能了;完善技能底层选取逻辑;团队模式完善;优化回合日志 (#99)
* 修复诸多复活角色的问题;添加了更多回合记录 * 完善了底层技能选取目标方法;添加筛选条件列表,使技能能够灵活的选取角色 * 优化死亡结算的逻辑;优化回合记录日志 * 现在动态工厂可以构造主动技能了
This commit is contained in:
parent
3db586cab2
commit
75d1337ce1
@ -675,7 +675,7 @@ namespace Milimoe.FunGame.Core.Api.Utility
|
||||
/// 此方法检查一个 百分比(%) 数值是否存在于 [0,1] 区间
|
||||
/// </summary>
|
||||
/// <param name="value"></param>
|
||||
/// <returns>如果超过0,则返回0;超过1则返回1。</returns>
|
||||
/// <returns>如果低于0,则返回0;超过1则返回1。</returns>
|
||||
public static double PercentageCheck(double value)
|
||||
{
|
||||
return Math.Max(0, Math.Min(value, 1));
|
||||
|
@ -1307,7 +1307,6 @@ namespace Milimoe.FunGame.Core.Entity
|
||||
PrimaryAttribute = PrimaryAttribute,
|
||||
Level = Level,
|
||||
EXP = EXP,
|
||||
CharacterState = CharacterState,
|
||||
InitialHP = InitialHP,
|
||||
ExHP2 = ExHP2,
|
||||
InitialMP = InitialMP,
|
||||
@ -1363,8 +1362,9 @@ namespace Milimoe.FunGame.Core.Entity
|
||||
/// <summary>
|
||||
/// 复活此角色,回复出厂状态
|
||||
/// </summary>
|
||||
/// <param name="original">需要一个原始的角色用于还原状态</param>
|
||||
/// <returns></returns>
|
||||
public void Respawn()
|
||||
public void Respawn(Character original)
|
||||
{
|
||||
Item? mcp = UnEquip(EquipSlotType.MagicCardPack);
|
||||
Item? w = UnEquip(EquipSlotType.Weapon);
|
||||
@ -1374,11 +1374,17 @@ namespace Milimoe.FunGame.Core.Entity
|
||||
Item? ac2 = UnEquip(EquipSlotType.Accessory2);
|
||||
List<Skill> skills = new(Skills);
|
||||
List<Item> items = new(Items);
|
||||
Character c = Copy();
|
||||
Character c = original.Copy();
|
||||
List<Effect> effects = [.. Effects];
|
||||
foreach (Effect e in effects)
|
||||
{
|
||||
e.OnEffectLost(this);
|
||||
}
|
||||
Effects.Clear();
|
||||
Skills.Clear();
|
||||
Items.Clear();
|
||||
Id = c.Id;
|
||||
Guid = original.Guid;
|
||||
Name = c.Name;
|
||||
FirstName = c.FirstName;
|
||||
NickName = c.NickName;
|
||||
@ -1392,6 +1398,10 @@ namespace Milimoe.FunGame.Core.Entity
|
||||
Level = c.Level;
|
||||
EXP = c.EXP;
|
||||
CharacterState = c.CharacterState;
|
||||
CharacterEffectStates.Clear();
|
||||
CharacterEffectTypes.Clear();
|
||||
IsUnselectable = false;
|
||||
UpdateCharacterState();
|
||||
InitialHP = c.InitialHP;
|
||||
ExHP2 = c.ExHP2;
|
||||
InitialMP = c.InitialMP;
|
||||
@ -1432,6 +1442,7 @@ namespace Milimoe.FunGame.Core.Entity
|
||||
Skill newskill = skill.Copy();
|
||||
newskill.Character = this;
|
||||
newskill.Level = skill.Level;
|
||||
newskill.CurrentCD = 0;
|
||||
Skills.Add(newskill);
|
||||
}
|
||||
foreach (Item item in items)
|
||||
|
@ -22,21 +22,6 @@ namespace Milimoe.FunGame.Core.Entity
|
||||
/// </summary>
|
||||
public virtual EffectType EffectType { get; set; } = EffectType.None;
|
||||
|
||||
/// <summary>
|
||||
/// 作用于自身
|
||||
/// </summary>
|
||||
public virtual bool TargetSelf { get; set; } = false;
|
||||
|
||||
/// <summary>
|
||||
/// 作用目标数量
|
||||
/// </summary>
|
||||
public virtual int TargetCount { get; set; } = 0;
|
||||
|
||||
/// <summary>
|
||||
/// 作用范围
|
||||
/// </summary>
|
||||
public virtual double TargetRange { get; set; } = 0;
|
||||
|
||||
/// <summary>
|
||||
/// 持续性的<para/>
|
||||
/// 配合 <see cref="Duration"/> 使用,而不是 <see cref="DurationTurn"/>。
|
||||
@ -232,7 +217,8 @@ namespace Milimoe.FunGame.Core.Entity
|
||||
/// 技能开始吟唱时 [ 爆发技插队可触发此项 ]
|
||||
/// </summary>
|
||||
/// <param name="caster"></param>
|
||||
public virtual void OnSkillCasting(Character caster)
|
||||
/// <param name="targets"></param>
|
||||
public virtual void OnSkillCasting(Character caster, List<Character> targets)
|
||||
{
|
||||
|
||||
}
|
||||
@ -436,6 +422,18 @@ namespace Milimoe.FunGame.Core.Entity
|
||||
return result;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 治疗一个目标 [ 强烈建议使用此方法而不是自行调用 <see cref="IGamingQueue.HealToTarget"/> ]
|
||||
/// </summary>
|
||||
/// <param name="actor"></param>
|
||||
/// <param name="target"></param>
|
||||
/// <param name="heal"></param>
|
||||
/// <param name="canRespawn"></param>
|
||||
public void HealToTarget(Character actor, Character target, double heal, bool canRespawn = false)
|
||||
{
|
||||
GamingQueue?.HealToTarget(actor, target, heal, canRespawn);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 打断施法 [ 尽可能的调用此方法而不是直接调用 <see cref="IGamingQueue.InterruptCasting"/>,以防止中断性变更 ]
|
||||
/// </summary>
|
||||
@ -484,9 +482,6 @@ namespace Milimoe.FunGame.Core.Entity
|
||||
copy.Name = Name;
|
||||
copy.Description = Description;
|
||||
copy.EffectType = EffectType;
|
||||
copy.TargetSelf = TargetSelf;
|
||||
copy.TargetCount = TargetCount;
|
||||
copy.TargetRange = TargetRange;
|
||||
copy.Durative = Durative;
|
||||
copy.Duration = Duration;
|
||||
copy.DurationTurn = DurationTurn;
|
||||
|
@ -15,7 +15,7 @@ namespace Milimoe.FunGame.Core.Entity
|
||||
/// <summary>
|
||||
/// 普通攻击说明
|
||||
/// </summary>
|
||||
public string Description => $"对目标敌人造成 {(1.0 + 0.05 * (Level - 1)) * 100:0.##}% [ {Damage:0.##} ] 点{(IsMagic ? CharacterSet.GetMagicDamageName(MagicType) : "物理伤害")}。";
|
||||
public string Description => $"对目标敌人造成 {(1.0 + 0.05 * (Level - 1)) * 100:0.##}% 攻击力 [ {Damage:0.##} ] 点{(IsMagic ? CharacterSet.GetMagicDamageName(MagicType) : "物理伤害")}。";
|
||||
|
||||
/// <summary>
|
||||
/// 所属的角色
|
||||
@ -66,6 +66,8 @@ namespace Milimoe.FunGame.Core.Entity
|
||||
public void Attack(IGamingQueue queue, Character attacker, params Character[] enemys)
|
||||
{
|
||||
foreach (Character enemy in enemys)
|
||||
{
|
||||
if (enemy.HP > 0)
|
||||
{
|
||||
queue.WriteLine("[ " + Character + $" ] 对 [ {enemy} ] 发起了普通攻击!");
|
||||
double expected = Damage;
|
||||
@ -73,6 +75,7 @@ namespace Milimoe.FunGame.Core.Entity
|
||||
queue.DamageToEnemy(attacker, enemy, damage, true, IsMagic, MagicType, result);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 修改伤害类型
|
||||
@ -95,7 +98,7 @@ namespace Milimoe.FunGame.Core.Entity
|
||||
StringBuilder builder = new();
|
||||
|
||||
builder.AppendLine(Name + " - 等级 " + Level);
|
||||
builder.AppendLine("技能描述:" + Description);
|
||||
builder.AppendLine("描述:" + Description);
|
||||
builder.AppendLine("硬直时间:" + HardnessTime);
|
||||
|
||||
return builder.ToString();
|
||||
|
@ -18,8 +18,92 @@ namespace Milimoe.FunGame.Core.Entity
|
||||
foreach (string str in args.Keys)
|
||||
{
|
||||
Values[str] = args[str];
|
||||
switch (str)
|
||||
switch (str.ToLower())
|
||||
{
|
||||
case "active":
|
||||
if (bool.TryParse(args[str].ToString(), out bool isActive) && isActive)
|
||||
{
|
||||
SkillType = SkillType.Item;
|
||||
}
|
||||
break;
|
||||
case "debuff":
|
||||
if (bool.TryParse(args[str].ToString(), out bool isDebuff) && isDebuff)
|
||||
{
|
||||
IsDebuff = isDebuff;
|
||||
}
|
||||
break;
|
||||
case "self":
|
||||
if (bool.TryParse(args[str].ToString(), out bool self))
|
||||
{
|
||||
CanSelectSelf = self;
|
||||
}
|
||||
break;
|
||||
case "enemy":
|
||||
if (bool.TryParse(args[str].ToString(), out bool enemy))
|
||||
{
|
||||
CanSelectEnemy = enemy;
|
||||
}
|
||||
break;
|
||||
case "teammate":
|
||||
if (bool.TryParse(args[str].ToString(), out bool teammate))
|
||||
{
|
||||
CanSelectTeammate = teammate;
|
||||
}
|
||||
break;
|
||||
case "count":
|
||||
if (int.TryParse(args[str].ToString(), out int count) && count > 0)
|
||||
{
|
||||
CanSelectTargetCount = count;
|
||||
}
|
||||
break;
|
||||
case "range":
|
||||
if (int.TryParse(args[str].ToString(), out int range) && range > 0)
|
||||
{
|
||||
CanSelectTargetRange = range;
|
||||
}
|
||||
break;
|
||||
case "mpcost":
|
||||
if (double.TryParse(args[str].ToString(), out double mpcost) && mpcost > 0)
|
||||
{
|
||||
MPCost = mpcost;
|
||||
}
|
||||
break;
|
||||
case "epcost":
|
||||
if (double.TryParse(args[str].ToString(), out double epcost) && epcost > 0)
|
||||
{
|
||||
EPCost = epcost;
|
||||
}
|
||||
break;
|
||||
case "costall":
|
||||
if (bool.TryParse(args[str].ToString(), out bool costall) && costall)
|
||||
{
|
||||
CostAllEP = costall;
|
||||
}
|
||||
break;
|
||||
case "mincost":
|
||||
if (double.TryParse(args[str].ToString(), out double mincost) && mincost > 0)
|
||||
{
|
||||
MinCostEP = mincost;
|
||||
}
|
||||
break;
|
||||
case "cd":
|
||||
if (double.TryParse(args[str].ToString(), out double cd) && cd > 0)
|
||||
{
|
||||
CD = cd;
|
||||
}
|
||||
break;
|
||||
case "cast":
|
||||
if (double.TryParse(args[str].ToString(), out double cast) && cast > 0)
|
||||
{
|
||||
CastTime = cast;
|
||||
}
|
||||
break;
|
||||
case "ht":
|
||||
if (double.TryParse(args[str].ToString(), out double ht) && ht > 0)
|
||||
{
|
||||
HardnessTime = ht;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
@ -82,11 +82,26 @@ namespace Milimoe.FunGame.Core.Entity
|
||||
[InitRequired]
|
||||
public bool IsMagic => SkillType == SkillType.Magic;
|
||||
|
||||
/// <summary>
|
||||
/// 是否属于 Debuff
|
||||
/// </summary>
|
||||
public bool IsDebuff { get; set; } = false;
|
||||
|
||||
/// <summary>
|
||||
/// 可选取自身
|
||||
/// </summary>
|
||||
public virtual bool CanSelectSelf { get; set; } = false;
|
||||
|
||||
/// <summary>
|
||||
/// 可选取敌对角色
|
||||
/// </summary>
|
||||
public virtual bool CanSelectEnemy { get; set; } = true;
|
||||
|
||||
/// <summary>
|
||||
/// 可选取友方角色
|
||||
/// </summary>
|
||||
public virtual bool CanSelectTeammate { get; set; } = false;
|
||||
|
||||
/// <summary>
|
||||
/// 可选取的作用目标数量
|
||||
/// </summary>
|
||||
@ -97,10 +112,15 @@ namespace Milimoe.FunGame.Core.Entity
|
||||
/// </summary>
|
||||
public virtual double CanSelectTargetRange { get; set; } = 0;
|
||||
|
||||
/// <summary>
|
||||
/// 选取角色的条件
|
||||
/// </summary>
|
||||
public List<Func<Character, bool>> SelectTargetPredicates { get; } = [];
|
||||
|
||||
/// <summary>
|
||||
/// 实际魔法消耗 [ 魔法 ]
|
||||
/// </summary>
|
||||
public double RealMPCost => Math.Max(0, MPCost * (1 - Calculation.PercentageCheck((Character?.INT ?? 0) * 0.00125)));
|
||||
public double RealMPCost => Math.Max(0, MPCost * (1 - Calculation.PercentageCheck((Character?.INT ?? 0) * General.GameplayEquilibriumConstant.INTtoCastMPReduce)));
|
||||
|
||||
/// <summary>
|
||||
/// 魔法消耗 [ 魔法 ]
|
||||
@ -122,7 +142,7 @@ namespace Milimoe.FunGame.Core.Entity
|
||||
/// <summary>
|
||||
/// 实际能量消耗 [ 战技 ]
|
||||
/// </summary>
|
||||
public double RealEPCost => CostAllEP ? Math.Max(MinCostEP, Character?.EP ?? MinCostEP) : (IsSuperSkill ? EPCost : Math.Max(0, EPCost * (1 - Calculation.PercentageCheck((Character?.INT ?? 0) * 0.00075))));
|
||||
public double RealEPCost => CostAllEP ? Math.Max(MinCostEP, Character?.EP ?? MinCostEP) : (IsSuperSkill ? EPCost : Math.Max(0, EPCost * (1 - Calculation.PercentageCheck((Character?.INT ?? 0) * General.GameplayEquilibriumConstant.INTtoCastEPReduce))));
|
||||
|
||||
/// <summary>
|
||||
/// 能量消耗 [ 战技 ]
|
||||
@ -140,10 +160,20 @@ namespace Milimoe.FunGame.Core.Entity
|
||||
/// </summary>
|
||||
public virtual double MinCostEP { get; set; } = 100;
|
||||
|
||||
/// <summary>
|
||||
/// 上一次释放此技能消耗的魔法 [ 魔法 ]
|
||||
/// </summary>
|
||||
public double LastCostMP { get; set; } = 0;
|
||||
|
||||
/// <summary>
|
||||
/// 上一次释放此技能消耗的能量 [ 战技 ]
|
||||
/// </summary>
|
||||
public double LastCostEP { get; set; } = 0;
|
||||
|
||||
/// <summary>
|
||||
/// 实际冷却时间
|
||||
/// </summary>
|
||||
public double RealCD => Math.Max(0, CD * (1 - Character?.CDR ?? 0));
|
||||
public double RealCD => Math.Max(0, CD * (1 - (Character?.CDR ?? 0)));
|
||||
|
||||
/// <summary>
|
||||
/// 冷却时间
|
||||
@ -247,21 +277,37 @@ namespace Milimoe.FunGame.Core.Entity
|
||||
/// <returns></returns>
|
||||
public virtual List<Character> SelectTargets(Character caster, List<Character> enemys, List<Character> teammates)
|
||||
{
|
||||
List<Character> tobeSelected = [];
|
||||
|
||||
if (CanSelectSelf)
|
||||
{
|
||||
return [caster];
|
||||
tobeSelected.Add(caster);
|
||||
}
|
||||
|
||||
if (CanSelectEnemy)
|
||||
{
|
||||
tobeSelected.AddRange(enemys);
|
||||
}
|
||||
if (CanSelectTeammate)
|
||||
{
|
||||
tobeSelected.AddRange(teammates);
|
||||
}
|
||||
|
||||
// 筛选出符合条件的角色
|
||||
tobeSelected = [.. tobeSelected.Where(c => SelectTargetPredicates.All(f => f(c)))];
|
||||
|
||||
List<Character> targets = [];
|
||||
|
||||
if (tobeSelected.Count <= CanSelectTargetCount)
|
||||
{
|
||||
targets.AddRange(tobeSelected);
|
||||
}
|
||||
else
|
||||
{
|
||||
List<Character> targets = [];
|
||||
|
||||
if (enemys.Count <= CanSelectTargetCount)
|
||||
{
|
||||
return [.. enemys];
|
||||
targets.AddRange(tobeSelected.OrderBy(x => Random.Shared.Next()).Take(CanSelectTargetCount));
|
||||
}
|
||||
|
||||
return enemys.OrderBy(x => Random.Shared.Next()).Take(CanSelectTargetCount).ToList();
|
||||
}
|
||||
return [.. targets.Distinct()];
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@ -269,16 +315,26 @@ namespace Milimoe.FunGame.Core.Entity
|
||||
/// </summary>
|
||||
/// <param name="queue"></param>
|
||||
/// <param name="caster"></param>
|
||||
public void OnSkillCasting(IGamingQueue queue, Character caster)
|
||||
/// <param name="targets"></param>
|
||||
public void OnSkillCasting(IGamingQueue queue, Character caster, List<Character> targets)
|
||||
{
|
||||
GamingQueue = queue;
|
||||
foreach (Effect e in Effects)
|
||||
{
|
||||
e.GamingQueue = GamingQueue;
|
||||
e.OnSkillCasting(caster);
|
||||
e.OnSkillCasting(caster, targets);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 技能效果触发前
|
||||
/// </summary>
|
||||
public void BeforeSkillCasted()
|
||||
{
|
||||
LastCostMP = RealMPCost;
|
||||
LastCostEP = RealEPCost;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 触发技能效果
|
||||
/// </summary>
|
||||
|
@ -43,5 +43,6 @@
|
||||
public int LastRank { get; set; } = 0;
|
||||
public double AvgRank { get; set; } = 0;
|
||||
public double Rating { get; set; } = 0;
|
||||
public int MVPs { get; set; } = 0;
|
||||
}
|
||||
}
|
||||
|
@ -1,14 +1,129 @@
|
||||
using Milimoe.FunGame.Core.Library.Constant;
|
||||
using System.Text;
|
||||
using Milimoe.FunGame.Core.Api.Utility;
|
||||
using Milimoe.FunGame.Core.Library.Constant;
|
||||
|
||||
namespace Milimoe.FunGame.Core.Entity.System
|
||||
namespace Milimoe.FunGame.Core.Entity
|
||||
{
|
||||
public class RoundRecord(int round, Character actor)
|
||||
public class RoundRecord(int round)
|
||||
{
|
||||
public int Round { get; set; } = round;
|
||||
public Character Actor { get; set; } = actor;
|
||||
public Character Actor { get; set; } = Factory.GetCharacter();
|
||||
public CharacterActionType ActionType { get; set; } = CharacterActionType.None;
|
||||
public List<Character> Targets { get; set; } = [];
|
||||
public Skill? Skill { get; set; } = null;
|
||||
public string SkillCost { get; set; } = "";
|
||||
public Item? Item { get; set; } = null;
|
||||
public bool HasKill { get; set; } = false;
|
||||
public Dictionary<Character, double> Damages { get; set; } = [];
|
||||
public Dictionary<Character, bool> IsCritical { get; set; } = [];
|
||||
public Dictionary<Character, double> Heals { get; set; } = [];
|
||||
public Dictionary<Character, EffectType> Effects { get; set; } = [];
|
||||
public List<string> ActorContinuousKilling { get; set; } = [];
|
||||
public List<string> DeathContinuousKilling { get; set; } = [];
|
||||
public double CastTime { get; set; } = 0;
|
||||
public double HardnessTime { get; set; } = 0;
|
||||
public Dictionary<Character, double> RespawnCountdowns { get; set; } = [];
|
||||
public List<Character> Respawns { get; set; } = [];
|
||||
public List<Skill> RoundRewards { get; set; } = [];
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
StringBuilder builder = new();
|
||||
|
||||
builder.AppendLine($"=== Round {Round} ===");
|
||||
if (RoundRewards.Count > 0)
|
||||
{
|
||||
builder.AppendLine($"[ {Actor} ] 回合奖励 -> {string.Join(" / ", RoundRewards.Select(s => s.Description)).Trim()}");
|
||||
}
|
||||
if (ActionType == CharacterActionType.NormalAttack || ActionType == CharacterActionType.CastSkill || ActionType == CharacterActionType.CastSuperSkill)
|
||||
{
|
||||
if (ActionType == CharacterActionType.NormalAttack)
|
||||
{
|
||||
builder.Append($"[ {Actor} ] {Actor.NormalAttack.Name} -> ");
|
||||
}
|
||||
else if (ActionType == CharacterActionType.CastSkill || ActionType == CharacterActionType.CastSuperSkill)
|
||||
{
|
||||
if (Skill != null)
|
||||
{
|
||||
builder.Append($"[ {Actor} ] {Skill.Name}({SkillCost})-> ");
|
||||
}
|
||||
else
|
||||
{
|
||||
builder.Append($"释放魔法 -> ");
|
||||
}
|
||||
}
|
||||
builder.AppendLine(string.Join(" / ", GetTargetsState()));
|
||||
if (DeathContinuousKilling.Count > 0) builder.AppendLine($"{string.Join("\r\n", DeathContinuousKilling)}");
|
||||
if (ActorContinuousKilling.Count > 0) builder.AppendLine($"{string.Join("\r\n", ActorContinuousKilling)}");
|
||||
}
|
||||
|
||||
if (ActionType == CharacterActionType.PreCastSkill && Skill != null)
|
||||
{
|
||||
if (Skill.IsMagic)
|
||||
{
|
||||
builder.AppendLine($"[ {Actor} ] 吟唱 [ {Skill.Name} ],持续时间:{CastTime:0.##}");
|
||||
}
|
||||
else
|
||||
{
|
||||
builder.AppendLine($"[ {Actor} ]:{Skill.Name}({SkillCost})-> ");
|
||||
builder.AppendLine(string.Join(" / ", GetTargetsState()));
|
||||
builder.AppendLine($"[ {Actor} ] 回合结束,硬直时间:{HardnessTime:0.##}");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
builder.AppendLine($"[ {Actor} ] 回合结束,硬直时间:{HardnessTime:0.##}");
|
||||
}
|
||||
|
||||
foreach (Character character in RespawnCountdowns.Keys)
|
||||
{
|
||||
builder.AppendLine($"[ {character} ] 进入复活倒计时:{RespawnCountdowns[character]:0.##}");
|
||||
}
|
||||
|
||||
foreach (Character character in Respawns)
|
||||
{
|
||||
builder.AppendLine($"[ {character} ] 复活了");
|
||||
}
|
||||
|
||||
return builder.ToString();
|
||||
}
|
||||
|
||||
private List<string> GetTargetsState()
|
||||
{
|
||||
List<string> strings = [];
|
||||
foreach (Character target in Targets.Distinct())
|
||||
{
|
||||
string hasDamage = "";
|
||||
string hasHeal = "";
|
||||
string hasEffect = "";
|
||||
if (Damages.TryGetValue(target, out double damage))
|
||||
{
|
||||
hasDamage = $"伤害:{damage:0.##}";
|
||||
if (IsCritical.TryGetValue(target, out bool isCritical) && isCritical)
|
||||
{
|
||||
hasDamage = "暴击," + hasDamage;
|
||||
}
|
||||
}
|
||||
if (Heals.TryGetValue(target, out double heals))
|
||||
{
|
||||
hasHeal = $"治疗:{heals:0.##}";
|
||||
}
|
||||
if (Effects.TryGetValue(target, out EffectType effectType))
|
||||
{
|
||||
hasEffect = $"施加:{SkillSet.GetEffectTypeName(effectType)}";
|
||||
}
|
||||
if (ActionType == CharacterActionType.NormalAttack && hasDamage == "")
|
||||
{
|
||||
hasDamage = "完美闪避";
|
||||
}
|
||||
if ((ActionType == CharacterActionType.PreCastSkill || ActionType == CharacterActionType.PreCastSkill || ActionType == CharacterActionType.CastSkill) && hasDamage == "" && target != Actor)
|
||||
{
|
||||
hasDamage = "免疫";
|
||||
}
|
||||
string[] strs = [hasDamage, hasHeal, hasEffect];
|
||||
strings.Add($"[ {target}({string.Join(" / ", strs.Where(s => s != ""))})])");
|
||||
}
|
||||
return strings;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,4 +1,4 @@
|
||||
namespace Milimoe.FunGame.Core.Entity.System
|
||||
namespace Milimoe.FunGame.Core.Entity
|
||||
{
|
||||
public class Season(long id, string name, string description)
|
||||
{
|
||||
|
@ -13,11 +13,26 @@ namespace Milimoe.FunGame.Core.Interface.Base
|
||||
/// </summary>
|
||||
public Action<string> WriteLine { get; }
|
||||
|
||||
/// <summary>
|
||||
/// 原始的角色字典
|
||||
/// </summary>
|
||||
public Dictionary<Guid, Character> Original { get; }
|
||||
|
||||
/// <summary>
|
||||
/// 当前的行动顺序
|
||||
/// </summary>
|
||||
public List<Character> Queue { get; }
|
||||
|
||||
/// <summary>
|
||||
/// 上回合记录
|
||||
/// </summary>
|
||||
public RoundRecord LastRound { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 所有回合的记录
|
||||
/// </summary>
|
||||
public List<RoundRecord> Rounds { get; }
|
||||
|
||||
/// <summary>
|
||||
/// 当前已死亡的角色顺序(第一个是最早死的)
|
||||
/// </summary>
|
||||
@ -63,6 +78,15 @@ namespace Milimoe.FunGame.Core.Interface.Base
|
||||
/// <param name="damageResult"></param>
|
||||
public void DamageToEnemy(Character actor, Character enemy, double damage, bool isNormalAttack, bool isMagicDamage = false, MagicType magicType = MagicType.None, DamageResult damageResult = DamageResult.Normal);
|
||||
|
||||
/// <summary>
|
||||
/// 治疗一个目标
|
||||
/// </summary>
|
||||
/// <param name="actor"></param>
|
||||
/// <param name="target"></param>
|
||||
/// <param name="heal"></param>
|
||||
/// <param name="canRespawn"></param>
|
||||
public void HealToTarget(Character actor, Character target, double heal, bool canRespawn = false);
|
||||
|
||||
/// <summary>
|
||||
/// 计算物理伤害
|
||||
/// </summary>
|
||||
|
@ -41,6 +41,12 @@ namespace Milimoe.FunGame.Core.Library.Common.JsonConverter
|
||||
case nameof(Skill.CanSelectSelf):
|
||||
result.CanSelectSelf = reader.GetBoolean();
|
||||
break;
|
||||
case nameof(Skill.CanSelectEnemy):
|
||||
result.CanSelectEnemy = reader.GetBoolean();
|
||||
break;
|
||||
case nameof(Skill.CanSelectTeammate):
|
||||
result.CanSelectTeammate = reader.GetBoolean();
|
||||
break;
|
||||
case nameof(Skill.CanSelectTargetCount):
|
||||
result.CanSelectTargetCount = reader.GetInt32();
|
||||
break;
|
||||
@ -59,6 +65,12 @@ namespace Milimoe.FunGame.Core.Library.Common.JsonConverter
|
||||
case nameof(Skill.EPCost):
|
||||
result.EPCost = reader.GetDouble();
|
||||
break;
|
||||
case nameof(Skill.CostAllEP):
|
||||
result.CostAllEP = reader.GetBoolean();
|
||||
break;
|
||||
case nameof(Skill.MinCostEP):
|
||||
result.MinCostEP = reader.GetDouble();
|
||||
break;
|
||||
case nameof(Skill.CastTime):
|
||||
result.CastTime = reader.GetDouble();
|
||||
break;
|
||||
@ -100,12 +112,16 @@ namespace Milimoe.FunGame.Core.Library.Common.JsonConverter
|
||||
if (value.Level > 0) writer.WriteNumber(nameof(Skill.Level), value.Level);
|
||||
writer.WriteNumber(nameof(Skill.SkillType), (int)value.SkillType);
|
||||
if (value.CanSelectSelf) writer.WriteBoolean(nameof(Skill.CanSelectSelf), value.CanSelectSelf);
|
||||
if (!value.CanSelectEnemy) writer.WriteBoolean(nameof(Skill.CanSelectEnemy), value.CanSelectEnemy);
|
||||
if (value.CanSelectTeammate) writer.WriteBoolean(nameof(Skill.CanSelectTeammate), value.CanSelectTeammate);
|
||||
if (value.CanSelectTargetCount != 0) writer.WriteNumber(nameof(Skill.CanSelectTargetCount), value.CanSelectTargetCount);
|
||||
if (value.CanSelectTargetRange != 0) writer.WriteNumber(nameof(Skill.CanSelectTargetRange), value.CanSelectTargetRange);
|
||||
if (!value.Enable) writer.WriteBoolean(nameof(Skill.Enable), value.Enable);
|
||||
if (value.IsInEffect) writer.WriteBoolean(nameof(Skill.IsInEffect), value.IsInEffect);
|
||||
if (value.MPCost > 0) writer.WriteNumber(nameof(Skill.MPCost), value.MPCost);
|
||||
if (value.EPCost > 0) writer.WriteNumber(nameof(Skill.EPCost), value.EPCost);
|
||||
if (value.CostAllEP) writer.WriteBoolean(nameof(Skill.CostAllEP), value.CostAllEP);
|
||||
if (value.MinCostEP > 0) writer.WriteNumber(nameof(Skill.MinCostEP), value.MinCostEP);
|
||||
if (value.CastTime > 0) writer.WriteNumber(nameof(Skill.CastTime), value.CastTime);
|
||||
if (value.CD > 0) writer.WriteNumber(nameof(Skill.CD), value.CD);
|
||||
if (value.CurrentCD > 0) writer.WriteNumber(nameof(Skill.CurrentCD), value.CurrentCD);
|
||||
|
@ -521,5 +521,53 @@ namespace Milimoe.FunGame.Core.Library.Constant
|
||||
_ => General.GameplayEquilibriumConstant.MaxPassiveSkillLevel
|
||||
};
|
||||
}
|
||||
|
||||
public static string GetEffectTypeName(EffectType type)
|
||||
{
|
||||
return type switch
|
||||
{
|
||||
EffectType.None => "无特殊效果",
|
||||
EffectType.Item => "装备特效",
|
||||
EffectType.Mark => "标记",
|
||||
EffectType.Stun => "眩晕",
|
||||
EffectType.Freeze => "冰冻",
|
||||
EffectType.Silence => "沉默",
|
||||
EffectType.Root => "定身",
|
||||
EffectType.Fear => "恐惧",
|
||||
EffectType.Sleep => "睡眠",
|
||||
EffectType.Knockback => "击退",
|
||||
EffectType.Knockdown => "击倒",
|
||||
EffectType.Taunt => "嘲讽",
|
||||
EffectType.Slow => "减速",
|
||||
EffectType.Weaken => "衰弱",
|
||||
EffectType.Poison => "中毒",
|
||||
EffectType.Burn => "燃烧",
|
||||
EffectType.Bleed => "流血",
|
||||
EffectType.Blind => "致盲",
|
||||
EffectType.Cripple => "致残",
|
||||
EffectType.Shield => "护盾",
|
||||
EffectType.HealOverTime => "持续治疗",
|
||||
EffectType.Haste => "加速",
|
||||
EffectType.Invulnerable => "无敌",
|
||||
EffectType.Unselectable => "不可选中",
|
||||
EffectType.DamageBoost => "伤害提升",
|
||||
EffectType.DefenseBoost => "防御提升",
|
||||
EffectType.CritBoost => "暴击提升",
|
||||
EffectType.ManaRegen => "魔法恢复",
|
||||
EffectType.ArmorBreak => "破甲",
|
||||
EffectType.MagicResistBreak => "降低魔抗",
|
||||
EffectType.Curse => "诅咒",
|
||||
EffectType.Exhaustion => "疲劳",
|
||||
EffectType.ManaBurn => "魔力燃烧",
|
||||
EffectType.Charm => "魅惑",
|
||||
EffectType.Disarm => "缴械",
|
||||
EffectType.Confusion => "混乱",
|
||||
EffectType.Petrify => "石化",
|
||||
EffectType.SilenceMagic => "法术沉默",
|
||||
EffectType.Banish => "放逐",
|
||||
EffectType.Doom => "毁灭",
|
||||
_ => "未知效果"
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,6 +1,5 @@
|
||||
using Milimoe.FunGame.Core.Api.Utility;
|
||||
using Milimoe.FunGame.Core.Entity;
|
||||
using Milimoe.FunGame.Core.Entity.System;
|
||||
using Milimoe.FunGame.Core.Interface.Base;
|
||||
using Milimoe.FunGame.Core.Library.Constant;
|
||||
|
||||
@ -16,6 +15,11 @@ namespace Milimoe.FunGame.Core.Model
|
||||
/// </summary>
|
||||
public Action<string> WriteLine { get; }
|
||||
|
||||
/// <summary>
|
||||
/// 原始的角色字典
|
||||
/// </summary>
|
||||
public Dictionary<Guid, Character> Original => _original;
|
||||
|
||||
/// <summary>
|
||||
/// 当前的行动顺序
|
||||
/// </summary>
|
||||
@ -82,7 +86,17 @@ namespace Milimoe.FunGame.Core.Model
|
||||
/// <summary>
|
||||
/// 上回合记录
|
||||
/// </summary>
|
||||
public RoundRecord LastRound { get; set; } = new(0, Factory.GetCharacter());
|
||||
public RoundRecord LastRound { get; set; } = new(0);
|
||||
|
||||
/// <summary>
|
||||
/// 所有回合的记录
|
||||
/// </summary>
|
||||
public List<RoundRecord> Rounds { get; } = [];
|
||||
|
||||
/// <summary>
|
||||
/// 原始的角色字典
|
||||
/// </summary>
|
||||
protected readonly Dictionary<Guid, Character> _original = [];
|
||||
|
||||
/// <summary>
|
||||
/// 当前的行动顺序
|
||||
@ -119,6 +133,11 @@ namespace Milimoe.FunGame.Core.Model
|
||||
/// </summary>
|
||||
protected readonly Dictionary<Character, int> _earnedMoney = [];
|
||||
|
||||
/// <summary>
|
||||
/// 角色最高连杀数
|
||||
/// </summary>
|
||||
protected readonly Dictionary<Character, int> _maxContinuousKilling = [];
|
||||
|
||||
/// <summary>
|
||||
/// 角色目前的连杀数
|
||||
/// </summary>
|
||||
@ -154,6 +173,11 @@ namespace Milimoe.FunGame.Core.Model
|
||||
/// </summary>
|
||||
protected readonly Dictionary<Character, double> _respawnCountdown = [];
|
||||
|
||||
/// <summary>
|
||||
/// 当前回合死亡角色
|
||||
/// </summary>
|
||||
protected readonly List<Character> _roundDeaths = [];
|
||||
|
||||
/// <summary>
|
||||
/// 是否是团队模式
|
||||
/// </summary>
|
||||
@ -202,6 +226,15 @@ namespace Milimoe.FunGame.Core.Model
|
||||
/// <param name="characters"></param>
|
||||
public void InitCharacterQueue(List<Character> characters)
|
||||
{
|
||||
// 保存原始的角色信息。用于复活时还原状态
|
||||
foreach (Character character in characters)
|
||||
{
|
||||
Character original = character.Copy();
|
||||
original.Guid = Guid.NewGuid();
|
||||
character.Guid = original.Guid;
|
||||
_original.Add(original.Guid, original);
|
||||
}
|
||||
|
||||
// 初始排序:按速度排序
|
||||
List<IGrouping<double, Character>> groupedBySpeed = [.. characters
|
||||
.GroupBy(c => c.SPD)
|
||||
@ -291,6 +324,7 @@ namespace Milimoe.FunGame.Core.Model
|
||||
public void ClearQueue()
|
||||
{
|
||||
FirstKiller = null;
|
||||
_original.Clear();
|
||||
_queue.Clear();
|
||||
_hardnessTimes.Clear();
|
||||
_assistDamage.Clear();
|
||||
@ -298,6 +332,7 @@ namespace Milimoe.FunGame.Core.Model
|
||||
_cutCount.Clear();
|
||||
_castingSkills.Clear();
|
||||
_castingSuperSkills.Clear();
|
||||
_maxContinuousKilling.Clear();
|
||||
_continuousKilling.Clear();
|
||||
_earnedMoney.Clear();
|
||||
_eliminated.Clear();
|
||||
@ -491,8 +526,8 @@ namespace Milimoe.FunGame.Core.Model
|
||||
/// <returns>是否结束游戏</returns>
|
||||
public bool ProcessTurn(Character character)
|
||||
{
|
||||
TotalRound++;
|
||||
LastRound = new(TotalRound, character);
|
||||
LastRound.Actor = character;
|
||||
_roundDeaths.Clear();
|
||||
|
||||
if (!BeforeTurn(character))
|
||||
{
|
||||
@ -696,7 +731,7 @@ namespace Milimoe.FunGame.Core.Model
|
||||
character.CharacterState = CharacterState.Casting;
|
||||
_castingSkills.Add(character, new(skill, targets));
|
||||
baseTime = skill.CastTime;
|
||||
skill.OnSkillCasting(this, character);
|
||||
skill.OnSkillCasting(this, character, targets);
|
||||
}
|
||||
}
|
||||
else
|
||||
@ -708,12 +743,14 @@ namespace Milimoe.FunGame.Core.Model
|
||||
if (!cancel)
|
||||
{
|
||||
decided = true;
|
||||
skill.OnSkillCasting(this, character);
|
||||
skill.OnSkillCasting(this, character, targets);
|
||||
skill.BeforeSkillCasted();
|
||||
|
||||
character.EP -= cost;
|
||||
baseTime = skill.HardnessTime;
|
||||
skill.CurrentCD = skill.RealCD;
|
||||
skill.Enable = false;
|
||||
LastRound.SkillCost = $"{-cost:0.##} EP";
|
||||
|
||||
WriteLine("[ " + character + $" ] 消耗了 {cost:0.##} 点能量,释放了{(skill.IsSuperSkill ? "爆发技" : "战技")} [ {skill.Name} ]!{(skill.Slogan != "" ? skill.Slogan : "")}");
|
||||
skill.OnSkillCasted(this, character, targets);
|
||||
@ -742,10 +779,13 @@ namespace Milimoe.FunGame.Core.Model
|
||||
// 判断是否能够释放技能
|
||||
if (CheckCanCast(character, skill, out double cost))
|
||||
{
|
||||
skill.BeforeSkillCasted();
|
||||
|
||||
character.MP -= cost;
|
||||
baseTime = skill.HardnessTime;
|
||||
skill.CurrentCD = skill.RealCD;
|
||||
skill.Enable = false;
|
||||
LastRound.SkillCost = $"{-cost:0.##} MP";
|
||||
|
||||
WriteLine("[ " + character + $" ] 消耗了 {cost:0.##} 点魔法值,释放了魔法 [ {skill.Name} ]!{(skill.Slogan != "" ? skill.Slogan : "")}");
|
||||
skill.OnSkillCasted(this, character, targets);
|
||||
@ -779,10 +819,13 @@ namespace Milimoe.FunGame.Core.Model
|
||||
List<Character> targets = SelectTargets(character, skill, enemys, teammates, out _);
|
||||
LastRound.Targets = [.. targets];
|
||||
|
||||
skill.BeforeSkillCasted();
|
||||
|
||||
character.EP -= cost;
|
||||
baseTime = skill.HardnessTime;
|
||||
skill.CurrentCD = skill.RealCD;
|
||||
skill.Enable = false;
|
||||
LastRound.SkillCost = $"{-cost:0.##} EP";
|
||||
|
||||
WriteLine("[ " + character + $" ] 消耗了 {cost:0.##} 点能量值,释放了爆发技 [ {skill.Name} ]!{(skill.Slogan != "" ? skill.Slogan : "")}");
|
||||
skill.OnSkillCasted(this, character, targets);
|
||||
@ -811,13 +854,16 @@ namespace Milimoe.FunGame.Core.Model
|
||||
WriteLine("[ " + character + $" ] 放弃了行动!");
|
||||
}
|
||||
|
||||
LastRound.ActionType = type;
|
||||
|
||||
// 统一在回合结束时处理角色的死亡
|
||||
ProcessCharacterDeath(character);
|
||||
|
||||
if (_isGameEnd)
|
||||
{
|
||||
return _isGameEnd;
|
||||
}
|
||||
|
||||
LastRound.ActionType = type;
|
||||
|
||||
// 减少硬直时间
|
||||
double newHardnessTime = baseTime;
|
||||
if (character.CharacterState != CharacterState.Casting)
|
||||
@ -829,8 +875,10 @@ namespace Milimoe.FunGame.Core.Model
|
||||
{
|
||||
newHardnessTime = Math.Max(0, Calculation.Round2Digits(baseTime * (1 - character.AccelerationCoefficient)));
|
||||
WriteLine("[ " + character + " ] 进行吟唱,持续时间: " + newHardnessTime);
|
||||
LastRound.CastTime = newHardnessTime;
|
||||
}
|
||||
AddCharacter(character, newHardnessTime, isCheckProtected);
|
||||
LastRound.HardnessTime = newHardnessTime;
|
||||
|
||||
// 有人想要插队吗?
|
||||
WillPreCastSuperSkill(character);
|
||||
@ -885,10 +933,38 @@ namespace Milimoe.FunGame.Core.Model
|
||||
|
||||
// 获取第一个角色的硬直时间
|
||||
double timeToReduce = _hardnessTimes[_queue[0]];
|
||||
TotalTime = Calculation.Round2Digits(TotalTime + timeToReduce);
|
||||
// 如果复活时间更快,应该先流逝复活时间
|
||||
if (_respawnCountdown.Count != 0)
|
||||
{
|
||||
double timeToRespawn = _respawnCountdown.Values.Min();
|
||||
if (timeToRespawn < timeToReduce)
|
||||
{
|
||||
timeToReduce = Calculation.Round2Digits(timeToRespawn);
|
||||
}
|
||||
}
|
||||
|
||||
TotalTime = Calculation.Round2Digits(TotalTime + timeToReduce);
|
||||
WriteLine("时间流逝:" + timeToReduce);
|
||||
|
||||
// 减少复活倒计时
|
||||
foreach (Character character in _respawnCountdown.Keys)
|
||||
{
|
||||
_respawnCountdown[character] = Calculation.Round2Digits(_respawnCountdown[character] - timeToReduce);
|
||||
if (_respawnCountdown[character] <= 0)
|
||||
{
|
||||
double hardnessTime = 5;
|
||||
character.Respawn(_original[character.Guid]);
|
||||
WriteLine($"[ {character} ] 已复活!获得 {hardnessTime} 硬直时间。");
|
||||
AddCharacter(character, hardnessTime, false);
|
||||
LastRound.Respawns.Add(character);
|
||||
_respawnCountdown.Remove(character);
|
||||
if (!_respawnTimes.TryAdd(character, 1))
|
||||
{
|
||||
_respawnTimes[character] += 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
foreach (Character character in _queue)
|
||||
{
|
||||
// 减少所有角色的硬直时间
|
||||
@ -970,25 +1046,13 @@ namespace Milimoe.FunGame.Core.Model
|
||||
}
|
||||
}
|
||||
|
||||
// 减少复活倒计时
|
||||
foreach (Character character in _respawnCountdown.Keys)
|
||||
{
|
||||
_respawnCountdown[character] -= timeToReduce;
|
||||
if (_respawnCountdown[character] <= 0)
|
||||
{
|
||||
double hardnessTime = 5;
|
||||
character.Respawn();
|
||||
WriteLine($"[ {character} ] 已复活!获得 {hardnessTime} 硬直时间。");
|
||||
AddCharacter(character, hardnessTime, false);
|
||||
_respawnCountdown.Remove(character);
|
||||
if (!_respawnTimes.TryAdd(character, 1))
|
||||
{
|
||||
_respawnTimes[character] += 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
WriteLine("\r\n");
|
||||
|
||||
// 在时间流逝后,进入下一回合
|
||||
TotalRound++;
|
||||
LastRound = new(TotalRound);
|
||||
Rounds.Add(LastRound);
|
||||
|
||||
return timeToReduce;
|
||||
}
|
||||
|
||||
@ -1010,6 +1074,10 @@ namespace Milimoe.FunGame.Core.Model
|
||||
return;
|
||||
}
|
||||
|
||||
if (!LastRound.IsCritical.TryAdd(enemy, damageResult == DamageResult.Critical) && damageResult == DamageResult.Critical)
|
||||
{
|
||||
LastRound.IsCritical[enemy] = true;
|
||||
}
|
||||
bool isEvaded = damageResult == DamageResult.Evaded;
|
||||
List<Effect> effects = actor.Effects.Union(enemy.Effects).Where(e => e.Level > 0).ToList();
|
||||
foreach (Effect effect in effects)
|
||||
@ -1062,71 +1130,54 @@ namespace Milimoe.FunGame.Core.Model
|
||||
effect.AfterDamageCalculation(actor, enemy, damage, isNormalAttack, isMagicDamage, magicType, damageResult);
|
||||
}
|
||||
|
||||
if (enemy.HP <= 0 && !_eliminated.Contains(enemy))
|
||||
if (enemy.HP <= 0 && !_eliminated.Contains(enemy) && !_respawnCountdown.ContainsKey(enemy))
|
||||
{
|
||||
LastRound.HasKill = true;
|
||||
_roundDeaths.Add(enemy);
|
||||
DeathCalculation(actor, enemy);
|
||||
// 给所有角色的特效广播角色死亡结算
|
||||
effects = _queue.SelectMany(c => c.Effects.Where(e => e.Level > 0)).ToList();
|
||||
foreach (Effect effect in effects)
|
||||
{
|
||||
effect.AfterDeathCalculation(enemy, actor, _continuousKilling, _earnedMoney);
|
||||
}
|
||||
// 将死者移出队列
|
||||
_queue.Remove(enemy);
|
||||
if (_isTeamMode)
|
||||
{
|
||||
Team? killTeam = GetTeam(actor);
|
||||
Team? deathTeam = GetTeam(enemy);
|
||||
if (deathTeam != null)
|
||||
{
|
||||
if (deathTeam.GetActiveCharacters(this).Count == 0)
|
||||
{
|
||||
// 团灭了
|
||||
_eliminatedTeams.Add(deathTeam);
|
||||
_teams.Remove(deathTeam.Name);
|
||||
}
|
||||
else
|
||||
{
|
||||
List<Character> remain = deathTeam.GetActiveTeammates(this, enemy);
|
||||
int remainCount = remain.Count;
|
||||
if (remainCount > 0) WriteLine($"[ {deathTeam} ] 剩余成员:[ {string.Join(" ] / [ ", remain)} ]({remainCount} 人)");
|
||||
}
|
||||
}
|
||||
|
||||
if (killTeam != null)
|
||||
/// <summary>
|
||||
/// 治疗一个目标
|
||||
/// </summary>
|
||||
/// <param name="actor"></param>
|
||||
/// <param name="target"></param>
|
||||
/// <param name="heal"></param>
|
||||
/// <param name="canRespawn"></param>
|
||||
public void HealToTarget(Character actor, Character target, double heal, bool canRespawn = false)
|
||||
{
|
||||
if (MaxScoreToWin > 0 && killTeam.Score >= MaxScoreToWin)
|
||||
if (target.HP == target.MaxHP)
|
||||
{
|
||||
List<Team> combinedTeams = [.. _eliminatedTeams, .. _teams.Values];
|
||||
combinedTeams.Remove(killTeam);
|
||||
_eliminatedTeams.Clear();
|
||||
_eliminatedTeams.AddRange(combinedTeams.OrderByDescending(t => t.Score));
|
||||
EndGameInfo(killTeam);
|
||||
return;
|
||||
}
|
||||
if (!_teams.Keys.Where(str => str != killTeam.Name).Any())
|
||||
|
||||
bool isDead = target.HP <= 0;
|
||||
|
||||
if (heal < 0) heal = 0;
|
||||
if (target.HP > 0 || (isDead && canRespawn))
|
||||
{
|
||||
// 没有其他的团队了,游戏结束
|
||||
EndGameInfo(killTeam);
|
||||
return;
|
||||
}
|
||||
else if (killTeam != null)
|
||||
target.HP += heal;
|
||||
if (!LastRound.Heals.TryAdd(target, heal))
|
||||
{
|
||||
List<Character> actives = killTeam.GetActiveCharacters(this);
|
||||
actives.Add(actor);
|
||||
int remainCount = actives.Count;
|
||||
if (remainCount > 0) WriteLine($"[ {killTeam} ] 剩余成员:[ {string.Join(" ] / [ ", actives)} ]({remainCount} 人)");
|
||||
LastRound.Heals[target] += heal;
|
||||
}
|
||||
}
|
||||
|
||||
if (isDead && canRespawn)
|
||||
{
|
||||
if (target != actor)
|
||||
{
|
||||
WriteLine($"[ {target} ] 被 [ {actor} ] 复苏了,并回复了 {heal:0.##} 点生命值!!");
|
||||
}
|
||||
else
|
||||
{
|
||||
WriteLine($"[ {target} ] 复苏了,并回复了 {heal:0.##} 点生命值!!");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!_queue.Where(c => c != actor).Any())
|
||||
{
|
||||
// 没有其他的角色了,游戏结束
|
||||
EndGameInfo(actor);
|
||||
}
|
||||
}
|
||||
WriteLine($"[ {target} ] 回复了 {heal:0.##} 点生命值!");
|
||||
}
|
||||
}
|
||||
|
||||
@ -1211,10 +1262,10 @@ namespace Milimoe.FunGame.Core.Model
|
||||
double penetratedDEF = (1 - actor.PhysicalPenetration) * enemy.DEF;
|
||||
|
||||
// 物理伤害减免
|
||||
double physicalDamageReduction = penetratedDEF / (penetratedDEF + 120);
|
||||
double physicalDamageReduction = penetratedDEF / (penetratedDEF + General.GameplayEquilibriumConstant.DEFReductionFactor);
|
||||
|
||||
// 最终的物理伤害
|
||||
finalDamage = expectedDamage * (1 - physicalDamageReduction);
|
||||
finalDamage = expectedDamage * (1 - Calculation.PercentageCheck(physicalDamageReduction + enemy.ExPDR));
|
||||
|
||||
// 暴击判定
|
||||
effects = actor.Effects.Where(e => e.Level > 0).ToList();
|
||||
@ -1355,6 +1406,79 @@ namespace Milimoe.FunGame.Core.Model
|
||||
return DamageResult.Normal;
|
||||
}
|
||||
|
||||
public void ProcessCharacterDeath(Character character)
|
||||
{
|
||||
foreach (Character enemy in _roundDeaths)
|
||||
{
|
||||
// 给所有角色的特效广播角色死亡结算
|
||||
List<Effect> effects = _queue.SelectMany(c => c.Effects.Where(e => e.Level > 0)).ToList();
|
||||
foreach (Effect effect in effects)
|
||||
{
|
||||
effect.AfterDeathCalculation(enemy, character, _continuousKilling, _earnedMoney);
|
||||
}
|
||||
// 将死者移出队列
|
||||
_queue.Remove(enemy);
|
||||
if (_isTeamMode)
|
||||
{
|
||||
Team? killTeam = GetTeam(character);
|
||||
Team? deathTeam = GetTeam(enemy);
|
||||
|
||||
if (MaxRespawnTimes != 0)
|
||||
{
|
||||
WriteLine($"\r\n=== 当前死亡竞赛比分 ===\r\n{string.Join("\r\n", Teams.OrderByDescending(kv => kv.Value.Score).Select(kv => kv.Key + ":" + kv.Value.Score + "(剩余存活人数:" + kv.Value.GetActiveCharacters(this).Count + ")"))}");
|
||||
}
|
||||
|
||||
if (deathTeam != null)
|
||||
{
|
||||
List<Character> remain = deathTeam.GetActiveCharacters(this);
|
||||
int remainCount = remain.Count;
|
||||
if (remainCount == 0)
|
||||
{
|
||||
// 团灭了
|
||||
_eliminatedTeams.Add(deathTeam);
|
||||
_teams.Remove(deathTeam.Name);
|
||||
}
|
||||
else if (MaxRespawnTimes == 0)
|
||||
{
|
||||
WriteLine($"[ {deathTeam} ] 剩余成员:[ {string.Join(" ] / [ ", remain)} ]({remainCount} 人)");
|
||||
}
|
||||
}
|
||||
|
||||
if (killTeam != null)
|
||||
{
|
||||
List<Character> actives = killTeam.GetActiveCharacters(this);
|
||||
actives.Add(character);
|
||||
int remainCount = actives.Count;
|
||||
if (remainCount > 0 && MaxRespawnTimes == 0)
|
||||
{
|
||||
WriteLine($"[ {killTeam} ] 剩余成员:[ {string.Join(" ] / [ ", actives)} ]({remainCount} 人)");
|
||||
}
|
||||
if (!_teams.Keys.Where(str => str != killTeam.Name).Any())
|
||||
{
|
||||
// 没有其他的团队了,游戏结束
|
||||
EndGameInfo(killTeam);
|
||||
}
|
||||
if (MaxScoreToWin > 0 && killTeam.Score >= MaxScoreToWin)
|
||||
{
|
||||
List<Team> combinedTeams = [.. _eliminatedTeams, .. _teams.Values];
|
||||
combinedTeams.Remove(killTeam);
|
||||
_eliminatedTeams.Clear();
|
||||
_eliminatedTeams.AddRange(combinedTeams.OrderByDescending(t => t.Score));
|
||||
EndGameInfo(killTeam);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!_queue.Where(c => c != character).Any())
|
||||
{
|
||||
// 没有其他的角色了,游戏结束
|
||||
EndGameInfo(character);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 死亡结算
|
||||
/// </summary>
|
||||
@ -1363,6 +1487,10 @@ namespace Milimoe.FunGame.Core.Model
|
||||
public void DeathCalculation(Character killer, Character death)
|
||||
{
|
||||
if (!_continuousKilling.TryAdd(killer, 1)) _continuousKilling[killer] += 1;
|
||||
if (!_maxContinuousKilling.TryAdd(killer, 1) && _continuousKilling[killer] > _maxContinuousKilling[killer])
|
||||
{
|
||||
_maxContinuousKilling[killer] = _continuousKilling[killer];
|
||||
}
|
||||
_stats[killer].Kills += 1;
|
||||
_stats[death].Deaths += 1;
|
||||
int money = Random.Shared.Next(250, 350);
|
||||
@ -1392,6 +1520,7 @@ namespace Milimoe.FunGame.Core.Model
|
||||
money += (coefficient + 1) * Random.Shared.Next(50, 100);
|
||||
string termination = CharacterSet.GetContinuousKilling(coefficient);
|
||||
string msg = $"[ {killer} ] 终结了 [ {death} ]{(termination != "" ? " 的" + termination : "")},获得 {money} {General.GameplayEquilibriumConstant.InGameCurrency}!";
|
||||
LastRound.DeathContinuousKilling.Add(msg);
|
||||
if (assists.Length > 1)
|
||||
{
|
||||
msg += "助攻:[ " + string.Join(" ] / [ ", assists.Where(c => c != killer)) + " ]";
|
||||
@ -1401,6 +1530,7 @@ namespace Milimoe.FunGame.Core.Model
|
||||
else
|
||||
{
|
||||
string msg = $"[ {killer} ] 杀死了 [ {death} ],获得 {money} {General.GameplayEquilibriumConstant.InGameCurrency}!";
|
||||
LastRound.DeathContinuousKilling.Add(msg);
|
||||
if (assists.Length > 1)
|
||||
{
|
||||
msg += "助攻:[ " + string.Join(" ] / [ ", assists.Where(c => c != killer)) + " ]";
|
||||
@ -1419,21 +1549,27 @@ namespace Milimoe.FunGame.Core.Model
|
||||
|
||||
int kills = _continuousKilling[killer];
|
||||
string continuousKilling = CharacterSet.GetContinuousKilling(kills);
|
||||
string actorContinuousKilling = "";
|
||||
if (kills == 2 || kills == 3)
|
||||
{
|
||||
WriteLine("[ " + killer + " ] 完成了" + continuousKilling + "!");
|
||||
actorContinuousKilling = "[ " + killer + " ] 完成了一次" + continuousKilling + "!";
|
||||
}
|
||||
else if (kills == 4)
|
||||
{
|
||||
WriteLine("[ " + killer + " ] 正在" + continuousKilling + "!");
|
||||
actorContinuousKilling = "[ " + killer + " ] 正在" + continuousKilling + "!";
|
||||
}
|
||||
else if (kills > 4 && kills < 10)
|
||||
{
|
||||
WriteLine("[ " + killer + " ] 已经" + continuousKilling + "!");
|
||||
actorContinuousKilling = "[ " + killer + " ] 已经" + continuousKilling + "!";
|
||||
}
|
||||
else if (kills >= 10)
|
||||
{
|
||||
WriteLine("[ " + killer + " ] 已经" + continuousKilling + "!拜托谁去杀了他吧!!!");
|
||||
actorContinuousKilling = "[ " + killer + " ] 已经" + continuousKilling + "!拜托谁去杀了他吧!!!";
|
||||
}
|
||||
if (actorContinuousKilling != "")
|
||||
{
|
||||
LastRound.ActorContinuousKilling.Add(actorContinuousKilling);
|
||||
WriteLine(actorContinuousKilling);
|
||||
}
|
||||
|
||||
if (!_earnedMoney.TryAdd(killer, money)) _earnedMoney[killer] += money;
|
||||
@ -1467,8 +1603,34 @@ namespace Milimoe.FunGame.Core.Model
|
||||
else
|
||||
{
|
||||
// 进入复活倒计时
|
||||
double respawnTime = Math.Min(90, death.Level * 0.36 + times * 2.77);
|
||||
double respawnTime = Calculation.Round2Digits(Math.Min(90, death.Level * 0.36 + times * 2.77 + kills * Random.Shared.Next(0, 3)));
|
||||
_respawnCountdown.TryAdd(death, respawnTime);
|
||||
LastRound.RespawnCountdowns.TryAdd(death, respawnTime);
|
||||
WriteLine($"[ {death} ] 进入复活倒计时:{respawnTime:0.##} 时间!");
|
||||
}
|
||||
|
||||
// 移除死者的施法
|
||||
_castingSkills.Remove(death);
|
||||
_castingSuperSkills.Remove(death);
|
||||
|
||||
// 因丢失目标而中断施法
|
||||
List<Character> castingSkills = [.. _castingSkills.Keys];
|
||||
foreach (Character caster in castingSkills)
|
||||
{
|
||||
SkillTarget st = _castingSkills[caster];
|
||||
if (st.Targets.Remove(death) && st.Targets.Count == 0)
|
||||
{
|
||||
_castingSkills.Remove(caster);
|
||||
if (caster.CharacterState == CharacterState.Casting)
|
||||
{
|
||||
caster.CharacterState = CharacterState.Actionable;
|
||||
}
|
||||
WriteLine($"[ {caster} ] 终止了 [ {st.Skill.Name} ] 的施法" + (_hardnessTimes[caster] > 3 ? ",并获得了 3 硬直时间的补偿。" : "。"));
|
||||
if (_hardnessTimes[caster] > 3)
|
||||
{
|
||||
_hardnessTimes[caster] = 3;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -1489,7 +1651,7 @@ namespace Milimoe.FunGame.Core.Model
|
||||
CharacterStatistics statistics = CharacterStatistics[ec];
|
||||
string topCharacter = ec.ToString() +
|
||||
(statistics.FirstKills > 0 ? " [ 第一滴血 ]" : "") +
|
||||
(_continuousKilling.TryGetValue(ec, out int kills) && kills > 1 ? $" [ {CharacterSet.GetContinuousKilling(kills)} ]" : "") +
|
||||
(_maxContinuousKilling.TryGetValue(ec, out int kills) && kills > 1 ? $" [ {CharacterSet.GetContinuousKilling(kills)} ]" : "") +
|
||||
(_earnedMoney.TryGetValue(ec, out int earned) ? $" [ 已赚取 {earned} {General.GameplayEquilibriumConstant.InGameCurrency} ]" : "");
|
||||
if (top == 1)
|
||||
{
|
||||
@ -1571,7 +1733,7 @@ namespace Milimoe.FunGame.Core.Model
|
||||
|
||||
string topCharacter = respawning + ec.ToString() +
|
||||
(statistics.FirstKills > 0 ? " [ 第一滴血 ]" : "") +
|
||||
(_continuousKilling.TryGetValue(ec, out int kills) && kills > 1 ? $" [ {CharacterSet.GetContinuousKilling(kills)} ]" : "") +
|
||||
(_maxContinuousKilling.TryGetValue(ec, out int kills) && kills > 1 ? $" [ {CharacterSet.GetContinuousKilling(kills)} ]" : "") +
|
||||
(_earnedMoney.TryGetValue(ec, out int earned) ? $" [ 已赚取 {earned} {General.GameplayEquilibriumConstant.InGameCurrency} ]" : "") +
|
||||
$"({statistics.Kills} / {statistics.Assists}{(MaxRespawnTimes != 0 ? " / " + statistics.Deaths : "")})";
|
||||
topTeam += topCharacter + "\r\n";
|
||||
@ -1671,7 +1833,7 @@ namespace Milimoe.FunGame.Core.Model
|
||||
_hardnessTimes[c] = Calculation.Round2Digits(_hardnessTimes[c] + 0.01);
|
||||
}
|
||||
}
|
||||
skill.OnSkillCasting(this, other);
|
||||
skill.OnSkillCasting(this, other, []);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1779,6 +1941,14 @@ namespace Milimoe.FunGame.Core.Model
|
||||
}
|
||||
statsTaken.TotalTakenDamage = Calculation.Round2Digits(statsTaken.TotalTakenDamage + damage);
|
||||
}
|
||||
if (LastRound.Damages.TryGetValue(characterTaken, out double damageTotal))
|
||||
{
|
||||
LastRound.Damages[characterTaken] = damageTotal + damage;
|
||||
}
|
||||
else
|
||||
{
|
||||
LastRound.Damages[characterTaken] = damage;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@ -1837,6 +2007,10 @@ namespace Milimoe.FunGame.Core.Model
|
||||
cancel = false;
|
||||
if (skill.SkillType == SkillType.SuperSkill) cancel = false;
|
||||
List<Character> targets = skill.SelectTargets(caster, enemys, teammates);
|
||||
if (targets.Count == 0)
|
||||
{
|
||||
cancel = true;
|
||||
}
|
||||
return targets;
|
||||
}
|
||||
|
||||
|
@ -225,6 +225,16 @@
|
||||
/// </summary>
|
||||
public double INTtoMRFactor { get; set; } = 0.1;
|
||||
|
||||
/// <summary>
|
||||
/// 每 1 点智力减少魔法消耗
|
||||
/// </summary>
|
||||
public double INTtoCastMPReduce { get; set; } = 0.00125;
|
||||
|
||||
/// <summary>
|
||||
/// 每 1 点智力减少能量消耗
|
||||
/// </summary>
|
||||
public double INTtoCastEPReduce { get; set; } = 0.00075;
|
||||
|
||||
/// <summary>
|
||||
/// 每 1 点敏捷增加行动速度
|
||||
/// </summary>
|
||||
|
Loading…
x
Reference in New Issue
Block a user