mirror of
https://github.com/EggLinks/DanhengServer-OpenSource.git
synced 2026-01-02 20:26:03 +08:00
548 lines
20 KiB
C#
548 lines
20 KiB
C#
using System.Collections.Concurrent;
|
|
using EggLink.DanhengServer.Data;
|
|
using EggLink.DanhengServer.Data.Config;
|
|
using EggLink.DanhengServer.Data.Config.Task;
|
|
using EggLink.DanhengServer.Enums.Avatar;
|
|
using EggLink.DanhengServer.Enums.RogueMagic;
|
|
using EggLink.DanhengServer.Enums.Scene;
|
|
using EggLink.DanhengServer.GameServer.Game.Battle;
|
|
using EggLink.DanhengServer.GameServer.Game.Player;
|
|
using EggLink.DanhengServer.GameServer.Game.RogueMagic;
|
|
using EggLink.DanhengServer.GameServer.Game.Scene;
|
|
using EggLink.DanhengServer.GameServer.Game.Scene.Component;
|
|
using EggLink.DanhengServer.GameServer.Game.Scene.Entity;
|
|
using EggLink.DanhengServer.GameServer.Server.Packet.Send.Scene;
|
|
using EggLink.DanhengServer.Proto;
|
|
using EggLink.DanhengServer.Util;
|
|
|
|
namespace EggLink.DanhengServer.GameServer.Game.Task.AvatarTask;
|
|
|
|
public class AbilityLevelTask(PlayerInstance player)
|
|
{
|
|
public PlayerInstance Player { get; set; } = player;
|
|
|
|
#region Selector
|
|
|
|
public async ValueTask<object> TargetAlias(AbilityLevelParam param)
|
|
{
|
|
await ValueTask.CompletedTask;
|
|
var selector = param.TargetEvaluator!;
|
|
var casterEntity = param.CasterEntity;
|
|
var targetEntities = param.TargetEntities;
|
|
|
|
if (selector is TargetAlias target)
|
|
return target.Alias switch
|
|
{
|
|
"Caster" or "ModifierOwnerEntity" => [casterEntity],
|
|
"ParamEntity" or "AllEnemy" or "AbilityTargetEntity" => targetEntities,
|
|
_ => targetEntities
|
|
};
|
|
|
|
return new List<BaseGameEntity>();
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region Manage
|
|
|
|
public async ValueTask<AbilityLevelResult> TriggerTasks(AdventureAbilityConfigListInfo abilities,
|
|
List<TaskConfigInfo> tasks, BaseGameEntity casterEntity, List<BaseGameEntity> targetEntities,
|
|
SceneCastSkillCsReq req,
|
|
string? modifierName = null)
|
|
{
|
|
BattleInstance? instance = null;
|
|
List<HitMonsterInstance> battleInfos = [];
|
|
foreach (var task in tasks)
|
|
try
|
|
{
|
|
var res = await TriggerTask(new AbilityLevelParam(abilities, task, casterEntity, targetEntities, req,
|
|
modifierName));
|
|
if (res.BattleInfos != null) battleInfos.AddRange(res.BattleInfos);
|
|
|
|
if (res.Instance != null) instance = res.Instance;
|
|
}
|
|
catch (Exception e)
|
|
{
|
|
Logger.GetByClassName().Error("An error occured, ", e);
|
|
}
|
|
|
|
return new AbilityLevelResult(instance, battleInfos);
|
|
}
|
|
|
|
public async ValueTask<AbilityLevelResult> TriggerTask(AbilityLevelParam param)
|
|
{
|
|
try
|
|
{
|
|
var methodName = param.Act.Type.Replace("RPG.GameCore.", "");
|
|
|
|
// try to get from cache
|
|
var method = GetOrCreateExecuteTask(methodName);
|
|
if (method == null) return new AbilityLevelResult();
|
|
|
|
var res = method(param);
|
|
var re = await res;
|
|
if (re is AbilityLevelResult result) return result;
|
|
}
|
|
catch (Exception e)
|
|
{
|
|
Logger.GetByClassName().Error("An error occured, ", e);
|
|
}
|
|
|
|
return new AbilityLevelResult();
|
|
}
|
|
|
|
private ExecuteTask? GetOrCreateExecuteTask(string methodName)
|
|
{
|
|
// try to get from cache
|
|
if (_cachedTasks.TryGetValue(methodName, out var method)) return method;
|
|
var methodProp = GetType().GetMethod(methodName);
|
|
if (methodProp == null) return null;
|
|
|
|
method = (ExecuteTask)Delegate.CreateDelegate(typeof(ExecuteTask), this, methodProp);
|
|
_cachedTasks[methodName] = method; // cached
|
|
|
|
return method;
|
|
}
|
|
|
|
private delegate ValueTask<object> ExecuteTask(AbilityLevelParam param);
|
|
|
|
private readonly ConcurrentDictionary<string, ExecuteTask> _cachedTasks = [];
|
|
|
|
#endregion
|
|
|
|
#region Task
|
|
|
|
public async ValueTask<object> PredicateTaskList(AbilityLevelParam param)
|
|
{
|
|
BattleInstance? instance = null;
|
|
List<HitMonsterInstance> battleInfos = [];
|
|
|
|
if (param.Act is PredicateTaskList predicateTaskList)
|
|
{
|
|
// handle predicateCondition
|
|
var methodName = predicateTaskList.Predicate.Type.Replace("RPG.GameCore.", "");
|
|
|
|
var method = GetOrCreateExecuteTask(methodName);
|
|
var res = true;
|
|
if (method != null)
|
|
{
|
|
var resp = await method(param with { Act = predicateTaskList.Predicate });
|
|
if (resp is not bool r)
|
|
res = false;
|
|
else
|
|
res = predicateTaskList.Predicate.Inverse ? !r : r;
|
|
}
|
|
|
|
if (res)
|
|
foreach (var task in predicateTaskList.SuccessTaskList)
|
|
{
|
|
var result = await TriggerTask(param with { Act = task });
|
|
if (result.BattleInfos != null) battleInfos.AddRange(result.BattleInfos);
|
|
|
|
if (result.Instance != null) instance = result.Instance;
|
|
}
|
|
else
|
|
foreach (var task in predicateTaskList.FailedTaskList)
|
|
{
|
|
var result = await TriggerTask(param with { Act = task });
|
|
if (result.BattleInfos != null) battleInfos.AddRange(result.BattleInfos);
|
|
|
|
if (result.Instance != null) instance = result.Instance;
|
|
}
|
|
}
|
|
|
|
return new AbilityLevelResult(instance, battleInfos);
|
|
}
|
|
|
|
public async ValueTask<object> AdventureTriggerAttack(AbilityLevelParam param)
|
|
{
|
|
BattleInstance? instance = null;
|
|
List<HitMonsterInstance> battleInfos = [];
|
|
|
|
if (param.Act is AdventureTriggerAttack adventureTriggerAttack)
|
|
{
|
|
var methodName = adventureTriggerAttack.AttackTargetType.Type.Replace("RPG.GameCore.", "");
|
|
var method = GetOrCreateExecuteTask(methodName);
|
|
if (method == null) return new AbilityLevelResult();
|
|
var resp = await method(param with { TargetEvaluator = adventureTriggerAttack.AttackTargetType });
|
|
|
|
if (resp is List<BaseGameEntity> target)
|
|
{
|
|
foreach (var task in adventureTriggerAttack.OnAttack)
|
|
{
|
|
var result = await TriggerTask(param with { Act = task });
|
|
if (result.BattleInfos != null) battleInfos.AddRange(result.BattleInfos);
|
|
}
|
|
|
|
if (target.Count > 0 && adventureTriggerAttack.TriggerBattle)
|
|
{
|
|
foreach (var task in adventureTriggerAttack.OnBattle)
|
|
{
|
|
var result = await TriggerTask(param with { Act = task });
|
|
if (result.BattleInfos != null) battleInfos.AddRange(result.BattleInfos);
|
|
}
|
|
|
|
foreach (var entity in param.TargetEntities)
|
|
{
|
|
var type = MonsterBattleType.TriggerBattle;
|
|
if (entity is EntityMonster { IsAlive: false })
|
|
type = MonsterBattleType.DirectDieSkipBattle;
|
|
|
|
battleInfos.Add(new HitMonsterInstance(entity.EntityId, type));
|
|
}
|
|
|
|
instance = await Player.BattleManager!.StartBattle(param.CasterEntity, param.TargetEntities,
|
|
param.Request.SkillIndex == 1);
|
|
}
|
|
}
|
|
}
|
|
|
|
return new AbilityLevelResult(instance, battleInfos);
|
|
}
|
|
|
|
public async ValueTask<object> AddMazeBuff(AbilityLevelParam param)
|
|
{
|
|
BattleInstance? instance = null;
|
|
List<HitMonsterInstance> battleInfos = [];
|
|
|
|
if (param.Act is AddMazeBuff addMazeBuff)
|
|
{
|
|
var methodName = addMazeBuff.TargetType.Type.Replace("RPG.GameCore.", "");
|
|
var method = GetOrCreateExecuteTask(methodName);
|
|
if (method == null) return new AbilityLevelResult();
|
|
var resp = await method(param with { TargetEvaluator = addMazeBuff.TargetType });
|
|
|
|
Dictionary<string, float> dynamic = [];
|
|
foreach (var dynamicValue in addMazeBuff.DynamicValues)
|
|
dynamic.Add(dynamicValue.Key, dynamicValue.Value.GetValue());
|
|
|
|
if (resp is not List<BaseGameEntity> target) return new AbilityLevelResult(instance, battleInfos);
|
|
|
|
foreach (var entity in target)
|
|
await entity.AddBuff(new SceneBuff(addMazeBuff.ID, 1,
|
|
(param.CasterEntity as AvatarSceneInfo)?.AvatarInfo.BaseAvatarId ?? 0,
|
|
addMazeBuff.LifeTime.FixedValue.Value < -1 ? 20 : -1)
|
|
{
|
|
DynamicValues = dynamic
|
|
});
|
|
}
|
|
|
|
return new AbilityLevelResult(instance, battleInfos);
|
|
}
|
|
|
|
public async ValueTask<object> AdventureFireProjectile(AbilityLevelParam param)
|
|
{
|
|
BattleInstance? instance = null;
|
|
List<HitMonsterInstance> battleInfos = [];
|
|
|
|
if (param.Act is AdventureFireProjectile adventureFireProjectile)
|
|
{
|
|
foreach (var task in adventureFireProjectile.OnProjectileHit)
|
|
{
|
|
var result = await TriggerTask(param with { Act = task });
|
|
if (result.BattleInfos != null) battleInfos.AddRange(result.BattleInfos);
|
|
|
|
if (result.Instance != null)
|
|
instance = result.Instance;
|
|
}
|
|
|
|
foreach (var task in adventureFireProjectile.OnProjectileLifetimeFinish)
|
|
{
|
|
var result = await TriggerTask(param with { Act = task });
|
|
if (result.BattleInfos != null) battleInfos.AddRange(result.BattleInfos);
|
|
|
|
if (result.Instance != null)
|
|
instance = result.Instance;
|
|
}
|
|
}
|
|
|
|
return new AbilityLevelResult(instance, battleInfos);
|
|
}
|
|
|
|
public async ValueTask<object> NewAdventureFireProjectile(AbilityLevelParam param)
|
|
{
|
|
BattleInstance? instance = null;
|
|
List<HitMonsterInstance> battleInfos = [];
|
|
|
|
if (param.Act is AdventureFireProjectile adventureFireProjectile)
|
|
{
|
|
foreach (var task in adventureFireProjectile.OnProjectileHit)
|
|
{
|
|
var result = await TriggerTask(param with { Act = task });
|
|
if (result.BattleInfos != null) battleInfos.AddRange(result.BattleInfos);
|
|
|
|
if (result.Instance != null)
|
|
instance = result.Instance;
|
|
}
|
|
|
|
foreach (var task in adventureFireProjectile.OnProjectileLifetimeFinish)
|
|
{
|
|
var result = await TriggerTask(param with { Act = task });
|
|
if (result.BattleInfos != null) battleInfos.AddRange(result.BattleInfos);
|
|
|
|
if (result.Instance != null)
|
|
instance = result.Instance;
|
|
}
|
|
}
|
|
|
|
return new AbilityLevelResult(instance, battleInfos);
|
|
}
|
|
|
|
public async ValueTask<object> CreateSummonUnit(AbilityLevelParam param)
|
|
{
|
|
if (param.Act is CreateSummonUnit createSummonUnit)
|
|
{
|
|
if (!GameData.SummonUnitDataData.TryGetValue(createSummonUnit.SummonUnitID, out var excel))
|
|
return new AbilityLevelResult();
|
|
|
|
if (excel.IsClient) return new AbilityLevelResult();
|
|
|
|
var unit = new EntitySummonUnit
|
|
{
|
|
EntityId = 0,
|
|
CreateAvatarEntityId = param.CasterEntity.EntityId,
|
|
AttachEntityId = excel.ConfigInfo?.AttachPoint == "Origin" ? param.CasterEntity.EntityId : 0,
|
|
SummonUnitId = excel.ID,
|
|
CreateAvatarId = (param.CasterEntity as AvatarSceneInfo)?.AvatarInfo.BaseAvatarId ?? 0,
|
|
LifeTimeMs = createSummonUnit.Duration.FixedValue.Value == -1 ? -1 : 20000,
|
|
TriggerList = excel.ConfigInfo?.TriggerConfig.CustomTriggers ?? [],
|
|
Motion = param.Request.TargetMotion
|
|
};
|
|
|
|
await Player.SceneInstance!.AddSummonUnitEntity(unit);
|
|
}
|
|
|
|
return new AbilityLevelResult();
|
|
}
|
|
|
|
public async ValueTask<object> DestroySummonUnit(AbilityLevelParam param)
|
|
{
|
|
if (param.Act is DestroySummonUnit destroySummonUnit)
|
|
await Player.SceneInstance!.RemoveSummonUnitById(destroySummonUnit.SummonUnit.SummonUnitID); // TODO
|
|
|
|
return new AbilityLevelResult();
|
|
}
|
|
|
|
public async ValueTask<object> AddAdventureModifier(AbilityLevelParam param)
|
|
{
|
|
if (param.Act is AddAdventureModifier addAdventureModifier)
|
|
{
|
|
GameData.AdventureModifierData.TryGetValue(addAdventureModifier.ModifierName, out var modifier);
|
|
if (modifier == null) return new AbilityLevelResult();
|
|
|
|
if (param.CasterEntity is IGameModifier mod) await mod.AddModifier(addAdventureModifier.ModifierName);
|
|
}
|
|
|
|
return new AbilityLevelResult();
|
|
}
|
|
|
|
public async ValueTask<object> RemoveAdventureModifier(AbilityLevelParam param)
|
|
{
|
|
if (param.Act is RemoveAdventureModifier removeAdventureModifier)
|
|
{
|
|
GameData.AdventureModifierData.TryGetValue(removeAdventureModifier.ModifierName, out var modifier);
|
|
if (modifier == null) return new AbilityLevelResult();
|
|
|
|
if (param.CasterEntity is IGameModifier mod) await mod.RemoveModifier(removeAdventureModifier.ModifierName);
|
|
}
|
|
|
|
return new AbilityLevelResult();
|
|
}
|
|
|
|
public async ValueTask<object> RemoveSelfModifier(AbilityLevelParam param)
|
|
{
|
|
if (param.ModifierName != null)
|
|
if (param.CasterEntity is IGameModifier mod)
|
|
await mod.RemoveModifier(param.ModifierName);
|
|
|
|
return new AbilityLevelResult();
|
|
}
|
|
|
|
public async ValueTask<object> RefreshMazeBuffTime(AbilityLevelParam param)
|
|
{
|
|
if (param.Act is RefreshMazeBuffTime refreshMazeBuffTime)
|
|
{
|
|
// get buff
|
|
var buff = param.CasterEntity.BuffList.FirstOrDefault(x => x.BuffId == refreshMazeBuffTime.ID);
|
|
if (buff == null) return new AbilityLevelResult();
|
|
buff.Duration = refreshMazeBuffTime.LifeTime.GetValue();
|
|
await Player.SendPacket(new PacketSyncEntityBuffChangeListScNotify(param.CasterEntity, buff));
|
|
}
|
|
|
|
return new AbilityLevelResult();
|
|
}
|
|
|
|
public async ValueTask<object> AdvModifyMaxMazeMP(AbilityLevelParam param)
|
|
{
|
|
await ValueTask.CompletedTask;
|
|
|
|
if (param.Act is AdvModifyMaxMazeMP advModifyMaxMazeMp)
|
|
switch (advModifyMaxMazeMp.ModifyFunction)
|
|
{
|
|
case PropertyModifyFunctionEnum.Add:
|
|
Player.LineupManager!.LineupData.ExtraMpCount += advModifyMaxMazeMp.ModifyValue.GetValue();
|
|
break;
|
|
case PropertyModifyFunctionEnum.Set:
|
|
Player.LineupManager!.LineupData.ExtraMpCount = advModifyMaxMazeMp.ModifyValue.GetValue() - 5;
|
|
break;
|
|
}
|
|
|
|
return new AbilityLevelResult();
|
|
}
|
|
|
|
public async ValueTask<object> AdventureSetAttackTargetMonsterDie(AbilityLevelParam param)
|
|
{
|
|
var avatar = param.CasterEntity as AvatarSceneInfo;
|
|
if (GameData.AvatarConfigData.TryGetValue(avatar?.AvatarInfo.AvatarId ?? 0, out var excel))
|
|
{
|
|
var adventurePlayerExcel = GameData.AdventurePlayerData.GetValueOrDefault(excel.AdventurePlayerID);
|
|
if (adventurePlayerExcel != null && adventurePlayerExcel.MazeSkillIdList.Count > param.Request.SkillIndex)
|
|
{
|
|
var skill = GameData.MazeSkillData.GetValueOrDefault(
|
|
adventurePlayerExcel.MazeSkillIdList[(int)param.Request.SkillIndex]);
|
|
|
|
await Player.LineupManager!.CostMp(skill?.MPCost ?? 1, param.Request.CastEntityId);
|
|
}
|
|
}
|
|
|
|
foreach (var targetEntity in param.TargetEntities)
|
|
{
|
|
if (targetEntity is not EntityMonster monster) continue;
|
|
|
|
if (monster.MonsterData.Rank < MonsterRankEnum.Elite)
|
|
{
|
|
await monster.Kill();
|
|
|
|
var instance = monster.Scene.Player.RogueManager!.GetRogueInstance();
|
|
switch (instance)
|
|
{
|
|
case null:
|
|
continue;
|
|
case RogueMagicInstance magic:
|
|
await magic.RollMagicUnit(1, 1, [RogueMagicUnitCategoryEnum.Common]);
|
|
break;
|
|
default:
|
|
await instance.RollBuff(1);
|
|
break;
|
|
}
|
|
|
|
await instance.GainMoney(Random.Shared.Next(20, 60));
|
|
}
|
|
}
|
|
|
|
return new AbilityLevelResult();
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region Predicate
|
|
|
|
public async ValueTask<object> ByAllowInstantKill(AbilityLevelParam param)
|
|
{
|
|
await ValueTask.CompletedTask;
|
|
|
|
foreach (var targetEntity in param.TargetEntities)
|
|
if (targetEntity is EntityMonster monster)
|
|
if (monster.MonsterData.Rank < MonsterRankEnum.Elite)
|
|
return true;
|
|
|
|
return false;
|
|
}
|
|
|
|
public async ValueTask<object> ByIsContainAdventureModifier(AbilityLevelParam param)
|
|
{
|
|
await ValueTask.CompletedTask;
|
|
|
|
if (param.Act is ByIsContainAdventureModifier byIsContain)
|
|
{
|
|
// get target
|
|
var result = false;
|
|
var methodName = byIsContain.TargetType.Type.Replace("RPG.GameCore.", "");
|
|
|
|
var method = GetOrCreateExecuteTask(methodName);
|
|
if (method == null) return false;
|
|
|
|
var resp = await method(param with { TargetEvaluator = byIsContain.TargetType });
|
|
|
|
if (resp is List<BaseGameEntity> target)
|
|
foreach (var entity in target)
|
|
{
|
|
if (entity is not IGameModifier modifier) continue;
|
|
if (modifier.Modifiers.Contains(byIsContain.ModifierName))
|
|
{
|
|
result = true;
|
|
break;
|
|
}
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
public async ValueTask<object> AdventureByInMotionState(AbilityLevelParam param)
|
|
{
|
|
await ValueTask.CompletedTask;
|
|
|
|
return true;
|
|
}
|
|
|
|
public async ValueTask<object> AdventureByPlayerCurrentSkillType(AbilityLevelParam param)
|
|
{
|
|
await ValueTask.CompletedTask;
|
|
|
|
if (param.Act is AdventureByPlayerCurrentSkillType byPlayerCurrentSkillType)
|
|
return param.Request.SkillIndex == (uint)byPlayerCurrentSkillType.SkillType;
|
|
|
|
return false;
|
|
}
|
|
|
|
public async ValueTask<object> ByCompareCarryMazebuff(AbilityLevelParam param)
|
|
{
|
|
await ValueTask.CompletedTask;
|
|
|
|
if (param.Act is ByCompareCarryMazebuff byCompareCarryMazebuff)
|
|
return param.CasterEntity.BuffList.Any(x => x.BuffId == byCompareCarryMazebuff.BuffID);
|
|
|
|
return false;
|
|
}
|
|
|
|
public async ValueTask<object> ByAnd(AbilityLevelParam param)
|
|
{
|
|
await ValueTask.CompletedTask;
|
|
|
|
if (param.Act is ByAnd byAnd)
|
|
{
|
|
foreach (var task in byAnd.PredicateList)
|
|
{
|
|
var methodName = task.Type.Replace("RPG.GameCore.", "");
|
|
|
|
var method = GetOrCreateExecuteTask(methodName);
|
|
if (method == null) return false;
|
|
|
|
var resp = await method(param with { Act = task });
|
|
if (resp is not bool res) return false;
|
|
res = task.Inverse ? !res : res;
|
|
if (!res) return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
#endregion
|
|
}
|
|
|
|
public record AbilityLevelResult(BattleInstance? Instance = null, List<HitMonsterInstance>? BattleInfos = null);
|
|
|
|
public record AbilityLevelParam(
|
|
AdventureAbilityConfigListInfo AdventureAbility,
|
|
TaskConfigInfo Act,
|
|
BaseGameEntity CasterEntity,
|
|
List<BaseGameEntity> TargetEntities,
|
|
SceneCastSkillCsReq Request,
|
|
string? ModifierName,
|
|
TargetEvaluator? TargetEvaluator = null); |