单位/召唤物技能实现和测试

This commit is contained in:
milimoe 2026-01-13 23:44:38 +08:00
parent 6dfa7ccb4a
commit ea0120e768
Signed by: milimoe
GPG Key ID: 9554D37E4B8991D0
20 changed files with 466 additions and 96 deletions

View File

@ -269,6 +269,9 @@
= 4129,
= 4130,
= 4131,
= 4132
= 4132,
= 4133,
= 4134,
= 4135
}
}

View File

@ -0,0 +1,25 @@
using Milimoe.FunGame.Core.Entity;
using Milimoe.FunGame.Core.Library.Constant;
using Oshima.FunGame.OshimaModules.Effects.OpenEffects;
namespace Oshima.FunGame.OshimaModules.Effects.PassiveEffects
{
public class : Effect
{
public override long Id => (long)PassiveEffectID.;
public override string Name => "宫监手标记";
public override string Description => $"此角色持有宫监手标记。来自:[ {Source} ]";
public override EffectType EffectType => EffectType.Mark;
public override bool IsDebuff => true;
public override Character Source => _sourceCharacter;
public override DispelledType DispelledType { get; set; } = DispelledType.Weak;
private readonly Character _sourceCharacter;
public (Skill skill, Character sourceCharacter) : base(skill)
{
GamingQueue = skill.GamingQueue;
_sourceCharacter = sourceCharacter;
}
}
}

View File

@ -64,7 +64,7 @@ namespace Oshima.FunGame.OshimaModules.Effects.PassiveEffects
return CharacterActionType.EndTurn;
}
public override void AfterDeathCalculation(Character death, Character? killer, Dictionary<Character, int> continuousKilling, Dictionary<Character, int> earnedMoney)
public override void AfterDeathCalculation(Character death, Character? killer, Dictionary<Character, int> continuousKilling, Dictionary<Character, int> earnedMoney, Character[] assists)
{
if (death == _targetCharacter)
{

View File

@ -0,0 +1,25 @@
using Milimoe.FunGame.Core.Entity;
using Milimoe.FunGame.Core.Library.Constant;
using Oshima.FunGame.OshimaModules.Effects.OpenEffects;
namespace Oshima.FunGame.OshimaModules.Effects.PassiveEffects
{
public class : Effect
{
public override long Id => (long)PassiveEffectID.;
public override string Name => "时雨标记";
public override string Description => $"此角色持有时雨标记。来自:[ {Source} ]";
public override EffectType EffectType => EffectType.Mark;
public override bool IsDebuff => true;
public override Character Source => _sourceCharacter;
public override DispelledType DispelledType { get; set; } = DispelledType.Weak;
private readonly Character _sourceCharacter;
public (Skill skill, Character sourceCharacter) : base(skill)
{
GamingQueue = skill.GamingQueue;
_sourceCharacter = sourceCharacter;
}
}
}

View File

@ -0,0 +1,26 @@
using Milimoe.FunGame.Core.Entity;
using Milimoe.FunGame.Core.Library.Constant;
using Oshima.FunGame.OshimaModules.Effects.OpenEffects;
namespace Oshima.FunGame.OshimaModules.Effects.PassiveEffects
{
public class : Effect
{
public override long Id => (long)PassiveEffectID.;
public override string Name => "长期监视";
public override string Description => $"此角色正在被长期监视。来自:[ {Source} ]";
public override EffectType EffectType => EffectType.Mark;
public override bool IsDebuff => true;
public override bool DurativeWithoutDuration => true;
public override Character Source => _sourceCharacter;
public override DispelledType DispelledType => DispelledType.CannotBeDispelled;
private readonly Character _sourceCharacter;
public (Skill skill, Character sourceCharacter) : base(skill)
{
GamingQueue = skill.GamingQueue;
_sourceCharacter = sourceCharacter;
}
}
}

View File

@ -1,4 +1,5 @@
using System.Collections.Concurrent;
using System.Text;
using Milimoe.FunGame.Core.Entity;
using Milimoe.FunGame.Core.Library.Constant;
using Oshima.Core.Constant;
@ -631,5 +632,26 @@ namespace Oshima.FunGame.OshimaModules.Models
"隅隆隐婚婶婉颇颈绩绪续骑绰绳维绵绷绸综绽绿缀巢琴琳琢琼斑替揍款堪塔搭" +
"堰揩越趁趋超揽堤提博揭喜彭揣插揪搜煮援搀裁搁搓搂搅壹握搔揉斯期欺联葫" +
"散惹葬募葛董葡敬葱蒋蒂落韩朝辜葵棒棱棋椰植森焚椅椒棵棍椎棉";
public static string GenerateRandomChineseUserName()
{
StringBuilder name = new();
// 随机姓
string lastname = FunGameConstant.CommonSurnames[Random.Shared.Next(FunGameConstant.CommonSurnames.Length)];
name.Append(lastname);
// 随机生成名字长度2到5个字
int nameLength = Random.Shared.Next(1, 2);
for (int i = 0; i < nameLength; i++)
{
// 从常用汉字集中随机选择一个汉字
char chineseCharacter = FunGameConstant.CommonChineseCharacters[Random.Shared.Next(FunGameConstant.CommonChineseCharacters.Length)];
name.Append(chineseCharacter);
}
return name.ToString();
}
}
}

View File

@ -8,7 +8,7 @@ namespace Oshima.FunGame.OshimaModules.Skills
{
public override long Id => (long)SuperSkillID.;
public override string Name => "全军出击";
public override string Description => Effects.Count > 0 ? Effects.First().Description : "";
public override string Description => Effects.Count > 0 ? (()Effects.First()).GeneralDescription : "";
public override string DispelDescription => Effects.Count > 0 ? Effects.First().DispelDescription : "";
public override double EPCost => 100;
public override double CD => 80;
@ -22,29 +22,112 @@ namespace Oshima.FunGame.OshimaModules.Skills
}
}
public class (Skill skill) : Effect(skill)
public class : Effect
{
public override long Id => Skill.Id;
public override string Name => Skill.Name;
public override string Description => $"将雇佣兵数量立即补全至 {雇佣兵团特效.最大数量} 名,持续 {持续时间} 秒。每名雇佣兵额外为{Skill.SkillOwner()}提供 {攻击力 * 100:0.##}% 攻击力和 {行动速度:0.##} 点行动速度、{加速系数 * 100:0.##}% 加速系数、{冷却缩减 * 100:0.##}% 冷却缩减,每名雇佣兵提升 {攻击力提升 * 100:0.##}% 攻击力。";
public override string Description { get; set; } = "";
public override DispelledType DispelledType => DispelledType.CannotBeDispelled;
public string GeneralDescription => $"将雇佣兵数量立即补全至 {雇佣兵团特效.最大数量} 名,每名雇佣兵的生命值回复至满并提升 {攻击力提升 * 100:0.##}% 攻击力。在 {持续时间} {GameplayEquilibriumConstant.InGameTime}内,场上的每名雇佣兵额外为{Skill.SkillOwner()}提供 {攻击力 * 100:0.##}% 攻击力和 {行动速度:0.##} 点行动速度、{加速系数 * 100:0.##}% 加速系数、{冷却缩减 * 100:0.##}% 冷却缩减。";
public double => 30 + 3 * (Skill.Level - 1);
public const double = 0.05;
public const double = 0.05;
public const double = 0.05;
public const double = 25;
public double => 20 + 2 * (Skill.Level - 1);
public const double = 0.04;
public const double = 0.03;
public const double = 0.03;
public const double = 30;
public const double = 0.4;
private double = 0;
private double = 0;
private double = 0;
private double = 0;
public (Skill skill) : base(skill)
{
Description = GeneralDescription;
}
public override void OnTimeElapsed(Character character, double elapsed)
{
(character);
}
public override void OnEffectLost(Character character)
{
Skill.IsInEffect = false;
(character);
}
public override void OnSkillCasted(Character caster, List<Character> targets, List<Grid> grids, Dictionary<string, object> others)
{
Skill.IsInEffect = true;
RemainDuration = Duration;
if (!caster.Effects.Contains(this))
{
caster.Effects.Add(this);
OnEffectGained(caster);
}
if (caster.Effects.FirstOrDefault(e => e is ) is e)
{
e.Skill.CurrentCD = 0;
e.Skill.Enable = true;
int count = e..Count;
if (count < .)
{
do
{
count = e.(caster);
}
while (count < .);
}
foreach ( gyb in e.)
{
gyb.Recovery();
gyb.ExATKPercentage += 0.05;
}
}
(caster);
GamingQueue?.LastRound.AddApplyEffects(caster, EffectType.CritBoost, EffectType.PenetrationBoost);
}
public void (Character character)
{
if ( != 0)
{
character.ExATKPercentage -= ;
= 0;
}
if ( != 0)
{
character.ExSPD -= ;
= 0;
}
if ( != 0)
{
character.ExAccelerationCoefficient -= ;
= 0;
}
if ( != 0)
{
character.ExCDR -= ;
= 0;
}
if (!Skill.IsInEffect)
{
return;
}
if (character.Effects.FirstOrDefault(e => e is ) is e)
{
int count = e..Count;
= * count;
= * count;
= * count;
= * count;
character.ExATKPercentage += ;
character.ExSPD += ;
character.ExAccelerationCoefficient += ;
character.ExCDR += ;
Description = $"{GeneralDescription}(当前雇佣兵数量:{count},攻击力提升:{实际攻击力提升 * 100:0.##}% [ {character.BaseATK * 实际攻击力提升:0.##} ] 点,行动速度提升:{实际行动速度提升:0.##} 点,加速系数提升:{实际加速系数提升 * 100:0.##}%,冷却缩减提升:{实际冷却缩减提升 * 100:0.##}%";
}
}
}
}

View File

@ -1,5 +1,7 @@
using Milimoe.FunGame.Core.Entity;
using Milimoe.FunGame.Core.Library.Common.Addon;
using Milimoe.FunGame.Core.Library.Constant;
using Oshima.FunGame.OshimaModules.Models;
namespace Oshima.FunGame.OshimaModules.Skills
{
@ -25,23 +27,124 @@ namespace Oshima.FunGame.OshimaModules.Skills
public override long Id => Skill.Id;
public override string Name => Skill.Name;
public override string Description => $"{Skill.SkillOwner()}在场上时,会召唤数名雇佣兵协助战斗,初始数量为 {最小数量} 名,雇佣兵具有独立的回合,生命值为{Skill.SkillOwner()}的 {生命值比例 * 100:0.##}% [ {Skill.Character?.MaxHP * 生命值比例:0.##} ],攻击力为{Skill.SkillOwner()}的 {攻击力比例 * 100:0.##}% 基础攻击力 [ {Skill.Character?.BaseATK * 攻击力比例:0.##} ]" +
$"完整继承其他能力值(暴击率、闪避率等)。当{Skill.SkillOwner()}参与击杀时,便会临时产生一名额外的雇佣兵,持续 {持续时间} 秒。场上最多可以存在 {最大数量} 名雇佣兵,达到数量后不再产生新的雇佣兵;当不足 {最小数量} 名雇佣兵时,{补充间隔} 秒后会重新补充一名雇佣兵。";
$"完整继承其他能力值(暴击率、闪避率等)。当{Skill.SkillOwner()}参与击杀时,便会临时产生一名额外的雇佣兵。场上最多可以存在 {最大数量} 名雇佣兵,达到数量后不再产生新的雇佣兵;当不足 {最小数量} 名雇佣兵时,{补充间隔} {GameplayEquilibriumConstant.InGameTime}后会重新补充一名雇佣兵。" +
(.Count < && Skill.CurrentCD > 0 ? $"(下次补充:{Skill.CurrentCD} {GameplayEquilibriumConstant.InGameTime}后)" : "");
public const int = 2;
public const int = 7;
public const int = 30;
public const int = 20;
public const double = 0.3;
public const double = 0.4;
public List<> { get; } = [];
public const int = 2;
public const int = 5;
public const int = 20;
public const double = 0.25;
public const double = 0.4;
public override void OnEffectGained(Character character)
public override void AfterDeathCalculation(Character death, Character? killer, Dictionary<Character, int> continuousKilling, Dictionary<Character, int> earnedMoney, Character[] assists)
{
if (death is gyb)
{
.Remove(gyb);
if (.Count < && Skill.CurrentCD == 0)
{
Skill.CurrentCD = ;
Skill.Enable = false;
}
}
if (death == Skill.Character)
{
OnEffectLost(death);
}
if (Skill.Character != null && death != Skill.Character && (killer == Skill.Character || assists.Contains(Skill.Character)) && .Count < )
{
(Skill.Character);
}
}
public override void OnTurnStart(Character character, List<Character> enemys, List<Character> teammates, List<Skill> skills, List<Item> items)
{
(character);
}
public override void OnTimeElapsed(Character character, double elapsed)
{
if (character == Skill.Character)
{
(character);
}
}
public override void OnEffectLost(Character character)
{
if (GamingQueue != null)
{
if (GamingQueue is Milimoe.FunGame.Core.Model.GamingQueue queue)
{
if (queue.Map != null) queue.RemoveCharacterFromMap();
else queue.RemoveCharacterFromQueue();
}
.Clear();
WriteLine($"[ {character} ] 的雇佣兵团已消散!");
}
}
public void (Character character)
{
int count = .Count;
if (count < && Skill.Enable)
{
do
{
count = (character);
}
while (count < );
}
}
public int (Character character)
{
gyb = new(character, FunGameConstant.GenerateRandomChineseUserName())
{
Level = 1,
InitialHP = character.MaxHP * ,
InitialATK = character.BaseATK * ,
ExCritRate = character.CritRate - GameplayEquilibriumConstant.CritRate,
ExCritDMG = character.CritDMG - GameplayEquilibriumConstant.CritDMG,
ExEvadeRate = character.EvadeRate - GameplayEquilibriumConstant.EvadeRate,
InitialSPD = character.SPD,
InitialDEF = character.DEF,
InitialHR = character.HR,
InitialMR = character.MR,
Lifesteal = character.Lifesteal,
ExPDR = character.PDR,
PhysicalPenetration = character.PhysicalPenetration,
MagicalPenetration = character.MagicalPenetration
};
gyb.MDF.AddAllValue(character.MDF.Avg);
gyb.Recovery();
.Add(gyb);
// 添加到地图/队列
if (GamingQueue != null)
{
if (GamingQueue.Map is GameMap map)
{
Grid? current = map.GetCharacterCurrentGrid(character);
if (current != null)
{
List<Grid> nearbyGrids = map.GetGridsByRange(current, 5, false);
Grid? target = nearbyGrids.OrderBy(g => GameMap.CalculateManhattanDistance(g, current)).FirstOrDefault();
if (target != null)
{
map.SetCharacterCurrentGrid(gyb, target);
WriteLine($"[ {character} ] 召唤了雇佣兵 ({target.X}, {target.Y}, {target.Z}) !");
}
}
}
GamingQueue.Queue.Add(gyb);
GamingQueue.ChangeCharacterHardnessTime(gyb, 5, false, false);
}
return .Count;
}
}
}

View File

@ -17,7 +17,7 @@ namespace Oshima.FunGame.OshimaModules.Skills
public override bool CanSelectSelf => false;
public override bool CanSelectEnemy => true;
public override bool CanSelectTeammate => false;
public override int CanSelectTargetCount => 2;
public override int CanSelectTargetCount => 3;
public override bool IsNonDirectional => true;
public override int CanSelectTargetRange => 3;
@ -39,10 +39,10 @@ namespace Oshima.FunGame.OshimaModules.Skills
public override MagicType MagicType => Skill.Character?.MagicType ?? MagicType.None;
public override ImmuneType IgnoreImmune => ImmuneType.All;
public string => $"对受到标记的目标造成伤害时将产生爆炸,爆炸将产生 {分裂伤害系数 * 100:0.##}% 分裂伤害。分裂伤害为全图索敌,会优先分裂至个在持续时间内对{Skill.SkillOwner()}造成伤害最多的敌人,若没有符合条件的敌人或敌人数量不足,则将分裂至被标记的敌人,或至多个随机的敌人。";
public string => $"对受到标记的目标造成伤害时将产生爆炸,爆炸将产生 {分裂伤害系数 * 100:0.##}% 分裂伤害。分裂伤害为全图索敌,会优先分裂至个在持续时间内对{Skill.SkillOwner()}造成伤害最多的敌人,若没有符合条件的敌人或敌人数量不足,则将分裂至被标记的敌人,或至多个随机的敌人。";
public double => 180 + 240 * (Skill.Level - 1);
public double => 25 + 2 * (Skill.Level - 1);
public double => 0.4 + 0.07 * (Skill.Level - 1);
public double => 0.4 + 0.08 * (Skill.Level - 1);
public double => 0.6 * (Skill.Character?.BaseSTR ?? 0);
public Dictionary<Character, double> { get; set; } = [];
@ -115,19 +115,19 @@ namespace Oshima.FunGame.OshimaModules.Skills
public void (Character character, Character enemy, double damage, DamageType damageType, MagicType magicType)
{
List<Character> targets = [];
targets.AddRange(.Where(w => w.Key != character && w.Key != enemy && w.Key.HP > 0).OrderByDescending(o => o.Value).Select(s => s.Key).Take(2));
if (targets.Count < 2)
targets.AddRange(.Where(w => w.Key != character && w.Key != enemy && w.Key.HP > 0).OrderByDescending(o => o.Value).Select(s => s.Key).Take(3));
if (targets.Count < 3)
{
int count = 2 - targets.Count;
int count = 3 - targets.Count;
// 获取所有敌人
List<Character> allEnemys = [];
if (GamingQueue != null)
{
allEnemys = [.. GamingQueue.GetEnemies(character).Where(c => c != character && c != enemy && !targets.Contains(c) && c.HP > 0)];
targets.AddRange(allEnemys.Where(c => c.Effects.Any(e => e is )).Take(count));
if (targets.Count < 2)
if (targets.Count < 3)
{
count = 2 - targets.Count;
count = 3 - targets.Count;
targets.AddRange(allEnemys.OrderBy(o => Random.Shared.Next()).Take(count));
}
}

View File

@ -34,21 +34,21 @@ namespace Oshima.FunGame.OshimaModules.Skills
public override long Id => Skill.Id;
public override string Name => Skill.Name;
public override string Description => $"{Skill.SkillOwner()}已经看透了生命的真谛。{Skill.SkillOwner()}的最大生命值减少 20%,并获得破釜沉舟特效。破釜沉舟:生命值高于 40% 时,受到额外的 [ {高于40额外伤害下限}{高于40额外伤害上限}% ] 伤害,获得 [ 累计所受伤害的 {高于40的加成下限}{高于40的加成上限}% ] 伤害加成;生命值低于等于 40% 时,不会受到额外的伤害,并且获得 [ 累计受到的伤害 {低于40的加成下限}{低于40的加成上限}% ] 的伤害加成。" +
$"在没有累计任何受到伤害的时候,将获得 {常规伤害加成 * 100:0.##}% 伤害加成和 {常规生命偷取 * 100:0.##}% 生命偷取。通过累计受到伤害发动破釜沉舟时,目标的闪避检定获得 40% 的减值,并立即清除累计受到的伤害。" + ( > 0 ? $"(当前累计受到伤害:{累计受到的伤害:0.##}" : "");
$"在没有累计任何受到伤害的时候,将获得 {常规伤害加成 * 100:0.##}% 伤害加成和 {常规生命偷取 * 100:0.##}% 生命偷取。通过累计受到伤害发动破釜沉舟时,目标的闪避检定获得 30% 的减值,并立即清除累计受到的伤害。" + ( > 0 ? $"(当前累计受到伤害:{累计受到的伤害:0.##}" : "");
private bool = false;
private double = 0;
private double = 0;
private double HP = 0;
private double = 0;
private readonly double = 0.4;
private readonly double = 0.2;
private readonly double = 0.35;
private readonly double = 0.1;
private readonly int 40 = 40;
private readonly int 40 = 20;
private readonly int 40 = 90;
private readonly int 40 = 60;
private readonly int 40 = 160;
private readonly int 40 = 120;
private readonly int 40 = 80;
private readonly int 40 = 50;
private readonly int 40 = 120;
private readonly int 40 = 90;
private double (double damage)
{
@ -122,7 +122,7 @@ namespace Oshima.FunGame.OshimaModules.Skills
if ( && actor == Skill.Character)
{
= false;
throwingBonus -= 0.4;
throwingBonus -= 0.3;
}
return true;
}

View File

@ -162,13 +162,14 @@ namespace Oshima.FunGame.OshimaModules.Skills
List<Character> allTeammates = [];
if (GamingQueue != null)
{
allEnemys = [.. GamingQueue.GetEnemies(caster).Where(c => c != caster && c.HP > 0)];
allTeammates = [.. GamingQueue.GetTeammates(caster).Where(c => c != caster && c.HP > 0)];
allEnemys = [.. GamingQueue.GetEnemies(caster).Where(c => c != caster && GamingQueue.Queue.Contains(c))];
allTeammates = [.. GamingQueue.GetTeammates(caster).Where(c => c != caster && GamingQueue.Queue.Contains(c))];
}
foreach (Character enemy in allEnemys)
{
Effect e = new (Skill, caster, caster, true, Duration, 0)
{
ExemptionType = PrimaryAttribute.AGI,
DispelledType = DispelledType.Strong
};
if (enemy.AGI <= caster.AGI || (enemy.AGI > caster.AGI && !CheckExemption(caster, enemy, e)))

View File

@ -1,5 +1,6 @@
using Milimoe.FunGame.Core.Entity;
using Milimoe.FunGame.Core.Library.Constant;
using Oshima.FunGame.OshimaModules.Effects.PassiveEffects;
namespace Oshima.FunGame.OshimaModules.Skills
{
@ -24,8 +25,9 @@ namespace Oshima.FunGame.OshimaModules.Skills
{
public override long Id => Skill.Id;
public override string Name => Skill.Name;
public override string Description => $"当场上有角色死亡时,如果该角色死于技能,则{Skill.SkillOwner()}获得该技能的使用权持续 3 回合;如果该角色死于普通攻击,则{Skill.SkillOwner()}的普通攻击将转为魔法伤害并且无视闪避,持续 3 回合。" +
$"然后给予击杀者时雨标记,如果击杀者为队友,{Skill.SkillOwner()}对其的治疗加成提升 100%,并且使其能够攻击{Skill.SkillOwner()},攻击{Skill.SkillOwner()}时,视为对{Skill.SkillOwner()}治疗,治疗值基于伤害值的 50%;如果为敌人,{Skill.SkillOwner()}对其的伤害加成提升 200%,并且使其能够攻击其队友。时雨标记持续 3 回合。";
public override string Description => $"{Skill.SkillOwner()}进入 [ {nameof(长期监视)} ] 状态,时刻监视着场上的一举一动。当场上有角色死亡时,如果该角色死于技能,则{Skill.SkillOwner()}复制该技能获得使用权,持续 3 回合,该复制品没有冷却时间;如果该角色死于普通攻击,则{Skill.SkillOwner()}的普通攻击将转为魔法伤害并且无视闪避,持续 3 回合。" +
$"接着,{Skill.SkillOwner()}给予击杀者 [ {nameof(时雨标记)} ]。{Skill.SkillOwner()}在造成魔法伤害时,会基于伤害值的 50% 治疗持有标记的友方角色;{Skill.SkillOwner()}与所有持有标记的友方角色对持有标记的敌方角色的伤害加成提升 100%,并且使持有标记的敌方角色在持续时间内的回合开始阶段,有 60% 概率陷入混乱。" +
$"混乱:进入行动受限状态,失控并随机行动,且在进行攻击指令时,可能会选取友方角色为目标。时雨标记持续 3 回合。";
public override void OnEffectGained(Character character)
{

View File

@ -8,7 +8,7 @@ namespace Oshima.FunGame.OshimaModules.Skills
{
public override long Id => (long)SuperSkillID.;
public override string Name => "放监";
public override string Description => Effects.Count > 0 ? Effects.First().Description : "";
public override string Description => Effects.Count > 0 ? (()Effects.First()). : "";
public override string DispelDescription => Effects.Count > 0 ? Effects.First().DispelDescription : "";
public override double EPCost => 100;
public override double CD => 65;
@ -22,14 +22,23 @@ namespace Oshima.FunGame.OshimaModules.Skills
}
}
public class (Skill skill) : Effect(skill)
public class : Effect
{
public override long Id => Skill.Id;
public override string Name => Skill.Name;
public override string Description => $"使时雨标记变得不可驱散,并且延长至 5 回合。持有标记的角色,必须完成以下任务来消除标记,否则将在标记消失时受到基于{Skill.SkillOwner()} 660% 核心属性 + 100% 攻击力 [ {Skill.Character?.PrimaryAttributeValue * 6.6 + Skill.Character?.ATK:0.##} ] 的魔法伤害(该伤害必定暴击):\r\n" +
$"1. 如果是敌人,则必须攻击一次队友,此伤害必定暴击且无视闪避;如果是队友,必须攻击一次{Skill.SkillOwner()},治疗加成再度提升 100%。\r\n2. 对{Skill.SkillOwner()}释放一个指向性技能,{Skill.SkillOwner()}将此技能效果无效化并且获得该技能的使用权持续 4 回合。\r\n此技能对队友的伤害将不会导致队友死亡。";
public override string Description { get; set; } = "";
public override DispelledType DispelledType => DispelledType.CannotBeDispelled;
public string => $"使场上现有的时雨标记变得不可驱散,并且刷新为持续 3 回合。并给予持有时雨标记的敌方角色 [ 宫监手标记 ],宫监手标记不可驱散,持续 3 回合。持有宫监手标记的角色,必须完成以下两个任务以消除标记,否则将在标记消失时受到基于{Skill.SkillOwner()} {核心属性系数 * 100:0.##}% 核心属性 + {攻击力系数 * 100:0.##}% 攻击力 [ {Skill.Character?.PrimaryAttributeValue * 核心属性系数 + Skill.Character?.ATK * 攻击力系数:0.##} ] 的真实伤害:\r\n" +
$"1. 使用 [ 普通攻击 ] 攻击一次队友,此伤害必定暴击且无视闪避;\r\n2. 对{Skill.SkillOwner()}释放一个指向性技能,{Skill.SkillOwner()}将此技能效果无效化并且复制该技能获得使用权持续 4 回合,该复制品没有冷却时间。";
public double => 1.1 * Skill.Level;
public double => 0.4 + 0.2 * (Skill.Level - 1);
public (Skill skill) : base(skill)
{
Description = ;
}
public override void OnSkillCasted(Character caster, List<Character> targets, List<Grid> grids, Dictionary<string, object> others)
{
RemainDuration = Duration;

View File

@ -1,5 +1,6 @@
using Milimoe.FunGame.Core.Entity;
using Milimoe.FunGame.Core.Library.Constant;
using Oshima.FunGame.OshimaModules.Effects.OpenEffects;
namespace Oshima.FunGame.OshimaModules.Skills
{
@ -24,49 +25,99 @@ namespace Oshima.FunGame.OshimaModules.Skills
{
public override long Id => Skill.Id;
public override string Name => Skill.Name;
public override string Description => $"每次造成伤害或受到伤害时,进行投掷检定,结果为偶数时,造成的伤害提升 {伤害提升 * 100:0.##}%,受到伤害减少 {伤害减少 * 100:0.##}%反之不产生任何效果。";
public override string Description => $"每次造成伤害或受到伤害时,进行投掷检定,结果为偶数时,造成的伤害提升 {伤害提升 * 100:0.##}%,受到伤害减少 {伤害减少 * 100:0.##}%结果为奇数时,该回合提升 {奇数平衡性提升 * 100:0.##}% 暴击率和闪避率、{奇数平衡性提升 * 100:0.##}% 魔法抗性,并将下一次伤害提升 {奇数伤害提升 * 100:0.##}% 或减免 {奇数伤害减少 * 100:0.##}% 下一次受到伤害,若下一次投掷结果为偶数,将叠加该效果。";
public bool { get; set; } = false;
public double { get; set; } = 1;
public double { get; set; } = 0.5;
public bool { get; set; } = false;
public bool { get; set; } = false;
public double { get; set; } = 0.8;
public double { get; set; } = 0.4;
public double { get; set; } = 0.1;
public double { get; set; } = 0.3;
public double { get; set; } = 0.15;
public override double AlterActualDamageAfterCalculation(Character character, Character enemy, double damage, bool isNormalAttack, DamageType damageType, MagicType magicType, DamageResult damageResult, ref bool isEvaded, Dictionary<Effect, double> totalDamageBonus)
{
double bouns = 0;
if (character == Skill.Character)
double bonus = 0;
if (character != Skill.Character && enemy != Skill.Character)
{
bool result = || (! && Random.Shared.Next(10) % 2 == 0);
WriteLine($"[ {character} ] 的八卦阵投掷结果为:{(result ? "" : "")}。");
if (damage > 0 && result)
return bonus;
}
if ()
{
= false;
if (character == Skill.Character)
{
Character c = character;
if (character == Skill.Character)
bonus = damage * ;
WriteLine($"[ {Skill.Character} ] 发动了八卦阵!伤害提升了 {Math.Abs(bonus):0.##} 点!");
}
else if (enemy == Skill.Character)
{
bonus = -(damage * );
WriteLine($"[ {Skill.Character} ] 发动了八卦阵!伤害减少了 {Math.Abs(bonus):0.##} 点!");
}
}
bool result = || (! && Random.Shared.Next(10) % 2 == 0);
WriteLine($"[ {Skill.Character} ] 的八卦阵投掷结果为:{(result ? "" : "")}。");
if (damage > 0 && result)
{
if (character == Skill.Character)
{
bonus += damage * ;
WriteLine($"[ {Skill.Character} ] 发动了八卦阵!伤害提升了 {Math.Abs(bonus):0.##} 点!");
}
else if (enemy == Skill.Character)
{
bonus += -(damage * );
WriteLine($"[ {Skill.Character} ] 发动了八卦阵!伤害减少了 {Math.Abs(bonus):0.##} 点!");
}
if ()
{
WriteLine($"[ {Skill.Character} ] 发动了归元环!冷却时间减少了 {归元环特效.冷却时间减少 * 100:0.##}%");
foreach (Skill s in Skill.Character.Skills)
{
bouns = damage * ;
WriteLine($"[ {character} ] 发动了八卦阵!伤害提升了 {Math.Abs(bouns):0.##} 点!");
}
else if (enemy == Skill.Character)
{
c = enemy;
bouns = -(damage * );
WriteLine($"[ {character} ] 发动了八卦阵!伤害减少了 {Math.Abs(bouns):0.##} 点!");
}
if ()
{
WriteLine($"[ {character} ] 发动了归元环!冷却时间减少了 20%");
foreach (Skill s in c.Skills)
s.CurrentCD -= s.CD * .;
if (s.CurrentCD < 0)
{
s.CurrentCD -= s.CD * .;
if (s.CurrentCD < 0)
{
s.CurrentCD = 0;
s.Enable = true;
}
s.CurrentCD = 0;
s.Enable = true;
}
}
}
}
return bouns;
else
{
if (!)
{
= true;
Effect e = new DynamicsEffect(Skill, new()
{
{ "excr", },
{ "exer", },
{ "mdftype", (int)MagicType.None },
{ "mdfvalue", }
}, Skill.Character)
{
Name = "八卦阵·奇数效果",
Durative = false,
DurationTurn = 1,
RemainDurationTurn = 1
};
Skill.Character.Effects.Add(e);
e.OnEffectGained(Skill.Character);
WriteLine($"[ {Skill.Character} ] 发动了八卦阵!该回合提升 {奇数平衡性提升 * 100:0.##}% 暴击率和闪避率、{奇数平衡性提升 * 100:0.##}% 魔法抗性!");
}
if (!)
{
= true;
}
}
return bonus;
}
public override void OnTurnEnd(Character character)
{
= false;
}
}
}

View File

@ -31,7 +31,7 @@ namespace Oshima.FunGame.OshimaModules.Skills
public override double Duration => 30;
public override DispelledType DispelledType => DispelledType.CannotBeDispelled;
public const double = 0.2;
public const double = 0.1;
public override void OnEffectGained(Character character)
{

View File

@ -53,7 +53,7 @@ namespace Oshima.FunGame.OshimaModules.Skills
}
}
public override void AfterDeathCalculation(Character death, Character? killer, Dictionary<Character, int> continuousKilling, Dictionary<Character, int> earnedMoney)
public override void AfterDeathCalculation(Character death, Character? killer, Dictionary<Character, int> continuousKilling, Dictionary<Character, int> earnedMoney, Character[] assists)
{
if (death == Skill.Character && > 0)
{

View File

@ -4,6 +4,7 @@ namespace Oshima.FunGame.OshimaModules.Units
{
public class RegionUnit : Unit
{
public override bool IsUnit => false; // 不走单位判断
public HashSet<Func<Region, bool>> GenerationPredicates { get; } = [];
public RegionUnit(long id, string name, params IEnumerable<Func<Region, bool>> predicates)

View File

@ -0,0 +1,22 @@
using Milimoe.FunGame.Core.Entity;
namespace Oshima.FunGame.OshimaModules
{
public class : Unit
{
public override string Name => "雇佣兵";
public override string ToString()
{
return NickName;
}
public (Character master, string name) : base()
{
NickName = $"雇佣兵{name}{master}";
Master = master;
ExATR = master.ExATR - master.ATR;
ExMOV = master.ExMOV - master.MOV;
}
}
}

View File

@ -1897,24 +1897,23 @@ namespace Oshima.FunGame.OshimaServers.Service
double teamTotalHeal = allStats?.Sum(s => s.TotalHeal + s.TotalShield) ?? heal;
int playerCount = allStats?.Length ?? 1;
double dmgShare = dmg / Math.Max(1, teamTotalDmg);
double dmgShare = dmg / Math.Max(2.3, teamTotalDmg);
double healShare = heal / Math.Max(1, teamTotalHeal);
double roleContribution = Math.Max(dmgShare, healShare) * playerCount * 0.4;
double roleScore = Math.Min(0.8, roleContribution);
double roleContribution = Math.Max(dmgShare, healShare) * playerCount * 0.6;
double roleScore = Math.Min(1.0, roleContribution);
double kdaRatio = (k * 1.3 + a * 0.3) / (d + 1.5);
double kdaScore = Math.Min(0.6, (kdaRatio / 3.0) * 0.4);
double kdaRatio = (k * 1.4 + a * 0.2) / (d + 1.8);
double kdaScore = Math.Min(1.0, (kdaRatio / 3.0) * 0.4);
double ccScore = Math.Min(0.1, (cc / 60.0) * 0.05);
double tankScore = Math.Min(0.1, (taken / (d + 1) / 10000.0) * 0.1);
double ccScore = Math.Min(0.10, (cc / 60.0) * 0.05);
double tankScore = Math.Min(0.10, (taken / (d + 1) / 10000.0) * 0.1);
double totalRating = roleScore + kdaScore + ccScore + tankScore;
double avgDeaths = allStats?.Average(s => s.Deaths) ?? d;
if (d > avgDeaths && kdaRatio < 1.0) totalRating *= 0.75;
totalRating += 0.25;
return Math.Round(Math.Max(0.01, totalRating), 2);
return Math.Round(Math.Max(0.01, totalRating), 4);
}
else
{
@ -1923,19 +1922,19 @@ namespace Oshima.FunGame.OshimaServers.Service
double maxKills = allStats?.Max(s => s.Kills) ?? k;
double maxDmg = allStats?.Max(s => s.TotalDamage + s.TotalTrueDamage * 0.2) ?? dmg;
double rankScore = ((totalPlayers - rank + 1.0) / totalPlayers) * 0.6;
double rankScore = ((totalPlayers - rank + 1.0) / totalPlayers) * 0.8;
double killPart = (k * 1.5 + a * 0.3) / Math.Max(1, maxKills + 1);
double dmgPart = (dmg / Math.Max(1, maxDmg * 1.2)) * 0.1;
double combatScore = Math.Min(0.4, killPart * 0.3 + dmgPart);
double killPart = (k * 1.7 + a * 0.1) / Math.Max(1, maxKills + 1);
double dmgPart = (dmg / Math.Max(1, maxDmg * 1.8)) * 0.1;
double combatScore = Math.Min(0.8, killPart * 0.4 + dmgPart);
double utilityScore = Math.Min(0.05, (cc / 60.0) * 0.02 + (heal / Math.Max(1, maxDmg)) * 0.03);
double utilityScore = Math.Min(0.2, (cc / 60.0) * 0.04 + (heal / Math.Max(1, maxDmg)) * 0.05);
double totalRating = rankScore + combatScore + utilityScore;
if (k == 0)
{
totalRating *= 0.7;
totalRating *= 0.6;
}
if (rank == 1 && k > 0)
@ -1945,11 +1944,10 @@ namespace Oshima.FunGame.OshimaServers.Service
if (rank > 5 && k >= maxKills * 0.8 && k > 0)
{
totalRating += 0.25;
totalRating += 0.15;
}
totalRating += 0.25;
return Math.Round(Math.Max(0.01, totalRating), 2);
return Math.Round(Math.Max(0.01, totalRating), 4);
}
}

View File

@ -2,9 +2,7 @@
using System.Text;
using System.Text.Json;
using Milimoe.FunGame.Core.Api.Utility;
using Milimoe.FunGame.Core.Controller;
using Milimoe.FunGame.Core.Entity;
using Milimoe.FunGame.Core.Interface.Base;
using Milimoe.FunGame.Core.Library.Common.Addon;
using Milimoe.FunGame.Core.Library.Constant;
using Milimoe.FunGame.Core.Model;
@ -472,6 +470,7 @@ namespace Oshima.FunGame.OshimaServers.Service
mvpBuilder.AppendLine($"总承受伤害:{stats.TotalTakenDamage:0.##} / 总承受物理伤害:{stats.TotalTakenPhysicalDamage:0.##} / 总承受魔法伤害:{stats.TotalTakenMagicDamage:0.##}");
if (stats.TotalTrueDamage > 0 || stats.TotalTakenTrueDamage > 0) mvpBuilder.AppendLine($"总计真实伤害:{stats.TotalTrueDamage:0.##} / 总承受真实伤害:{stats.TotalTakenTrueDamage:0.##}");
mvpBuilder.AppendLine($"每秒伤害:{stats.DamagePerSecond:0.##} / 每回合伤害:{stats.DamagePerTurn:0.##}");
if (actionQueue.IsDebug) WriteLine(mvp.GetInfo());
}
int top = isWeb ? actionQueue.CharacterStatistics.Count : 0; // 回执多少个角色的统计信息
@ -687,7 +686,7 @@ namespace Oshima.FunGame.OshimaServers.Service
}
}
private static bool ActionQueue_CharacterDeath(GamingQueue queue, Character current, Character death)
private static bool ActionQueue_CharacterDeath(GamingQueue queue, Character current, Character death, Character[] assists)
{
death.Items.Clear();
return true;