Implement Basic SummonUnit

This commit is contained in:
Somebody
2024-08-29 21:08:50 +08:00
parent f7a8564237
commit 85293dbe11
217 changed files with 1541 additions and 794 deletions

View File

@@ -102,7 +102,7 @@ public class BattleManager(PlayerInstance player) : BasePlayerManager(player)
if (castAvatar != null)
{
skill.OnAttack(Player.SceneInstance!.AvatarInfo[(int)req.AttackedByEntityId], targetList);
skill.OnCast(castAvatar);
skill.OnCast(castAvatar, Player);
}
var triggerBattle = targetList.Any(target => target.IsAlive);

View File

@@ -5,7 +5,7 @@ namespace EggLink.DanhengServer.GameServer.Game.Battle;
public class MazeBuff(int buffID, int buffLevel, int owner)
{
public MazeBuff(SceneBuff buff) : this(buff.BuffID, buff.BuffLevel, 0)
public MazeBuff(SceneBuff buff) : this(buff.BuffId, buff.BuffLevel, 0)
{
Duration = buff.Duration;
OwnerAvatarId = buff.OwnerAvatarId;

View File

@@ -1,4 +1,5 @@
using EggLink.DanhengServer.GameServer.Game.Scene;
using EggLink.DanhengServer.GameServer.Game.Player;
using EggLink.DanhengServer.GameServer.Game.Scene;
using EggLink.DanhengServer.GameServer.Game.Scene.Entity;
namespace EggLink.DanhengServer.GameServer.Game.Battle.Skill.Action;
@@ -15,7 +16,7 @@ public class MazeAddMazeBuff(int buffId, int duration) : IMazeSkillAction
await System.Threading.Tasks.Task.CompletedTask;
}
public async ValueTask OnCast(AvatarSceneInfo avatar)
public async ValueTask OnCast(AvatarSceneInfo avatar, PlayerInstance player)
{
await avatar.AddBuff(new SceneBuff(BuffId, 1, avatar.AvatarInfo.AvatarId, duration));
}

View File

@@ -1,4 +1,5 @@
using EggLink.DanhengServer.Enums.Scene;
using EggLink.DanhengServer.GameServer.Game.Player;
using EggLink.DanhengServer.GameServer.Game.Scene;
using EggLink.DanhengServer.GameServer.Game.Scene.Entity;
@@ -19,7 +20,7 @@ public class MazeSetTargetMonsterDie : IMazeSkillAction
}
}
public async ValueTask OnCast(AvatarSceneInfo avatar)
public async ValueTask OnCast(AvatarSceneInfo avatar, PlayerInstance player)
{
await System.Threading.Tasks.Task.CompletedTask;
}

View File

@@ -0,0 +1,35 @@
using EggLink.DanhengServer.Data.Excel;
using EggLink.DanhengServer.GameServer.Game.Player;
using EggLink.DanhengServer.GameServer.Game.Scene;
using EggLink.DanhengServer.GameServer.Game.Scene.Entity;
using EggLink.DanhengServer.Proto;
namespace EggLink.DanhengServer.GameServer.Game.Battle.Skill.Action;
public class MazeSummonUnit(SummonUnitDataExcel excel, MotionInfo motion) : IMazeSkillAction
{
public async ValueTask OnCast(AvatarSceneInfo avatar, PlayerInstance player)
{
var unit = new EntitySummonUnit
{
EntityID = 0,
CreateAvatarEntityId = avatar.EntityID,
SummonUnitId = excel.ID,
LifeTimeMs = 15000,
TriggerList = excel.ConfigInfo?.TriggerConfig.CustomTriggers ?? [],
Motion = motion
};
await player.SceneInstance!.AddEntity(unit);
}
public async ValueTask OnHitTarget(AvatarSceneInfo avatar, List<EntityMonster> entities)
{
await ValueTask.CompletedTask;
}
public async ValueTask OnAttack(AvatarSceneInfo avatar, List<EntityMonster> entities)
{
await ValueTask.CompletedTask;
}
}

View File

@@ -1,11 +1,12 @@
using EggLink.DanhengServer.GameServer.Game.Scene;
using EggLink.DanhengServer.GameServer.Game.Player;
using EggLink.DanhengServer.GameServer.Game.Scene;
using EggLink.DanhengServer.GameServer.Game.Scene.Entity;
namespace EggLink.DanhengServer.GameServer.Game.Battle.Skill;
public interface IMazeSkillAction
{
public ValueTask OnCast(AvatarSceneInfo avatar);
public ValueTask OnCast(AvatarSceneInfo avatar, PlayerInstance player);
public ValueTask OnHitTarget(AvatarSceneInfo avatar, List<EntityMonster> entities);

View File

@@ -1,21 +1,27 @@
using EggLink.DanhengServer.Data.Config;
using EggLink.DanhengServer.Data;
using EggLink.DanhengServer.Data.Config;
using EggLink.DanhengServer.Data.Excel;
using EggLink.DanhengServer.Enums.Avatar;
using EggLink.DanhengServer.GameServer.Game.Battle.Skill.Action;
using EggLink.DanhengServer.GameServer.Game.Player;
using EggLink.DanhengServer.GameServer.Game.Scene;
using EggLink.DanhengServer.GameServer.Game.Scene.Entity;
using EggLink.DanhengServer.Proto;
namespace EggLink.DanhengServer.GameServer.Game.Battle.Skill;
public class MazeSkill
{
public MazeSkill(List<TaskInfo> taskInfos, bool isSkill = false, AvatarConfigExcel? excel = null)
public MazeSkill(List<TaskInfo> taskInfos, SceneCastSkillCsReq req, bool isSkill = false, AvatarConfigExcel? excel = null)
{
foreach (var task in taskInfos) AddAction(task);
Req = req;
IsMazeSkill = isSkill;
Excel = excel;
foreach (var task in taskInfos) AddAction(task);
}
public SceneCastSkillCsReq Req;
public List<IMazeSkillAction> Actions { get; } = [];
public bool TriggerBattle { get; private set; } = true;
public bool IsMazeSkill { get; } = true;
@@ -38,6 +44,7 @@ public class MazeSkill
case TaskTypeEnum.AdventureModifyTeamPlayerSP:
break;
case TaskTypeEnum.CreateSummonUnit:
Actions.Add(new MazeSummonUnit(GameData.SummonUnitDataData[task.SummonUnitID], Req.TargetMotion));
break;
case TaskTypeEnum.AdventureSetAttackTargetMonsterDie:
Actions.Add(new MazeSetTargetMonsterDie());
@@ -58,9 +65,9 @@ public class MazeSkill
}
}
public void OnCast(AvatarSceneInfo info)
public void OnCast(AvatarSceneInfo info, PlayerInstance player)
{
foreach (var action in Actions) action.OnCast(info);
foreach (var action in Actions) action.OnCast(info, player);
}
public void OnAttack(AvatarSceneInfo info, List<EntityMonster> entities)

View File

@@ -1,21 +1,22 @@
using EggLink.DanhengServer.Data;
using EggLink.DanhengServer.Proto;
namespace EggLink.DanhengServer.GameServer.Game.Battle.Skill;
public static class MazeSkillManager
{
public static MazeSkill GetSkill(int baseAvatarId, int skillIndex)
public static MazeSkill GetSkill(int baseAvatarId, int skillIndex, SceneCastSkillCsReq req)
{
GameData.AvatarConfigData.TryGetValue(baseAvatarId, out var avatarConfig);
MazeSkill mazeSkill = new([]);
MazeSkill mazeSkill = new([], req);
if (avatarConfig == null) return mazeSkill;
if (skillIndex == 0)
// normal atk
mazeSkill = new MazeSkill(avatarConfig.MazeAtk?.OnStart.ToList() ?? [], false, avatarConfig);
mazeSkill = new MazeSkill(avatarConfig.MazeAtk?.OnStart.ToList() ?? [], req, false, avatarConfig);
else
// maze skill
mazeSkill = new MazeSkill(avatarConfig.MazeSkill?.OnStart.ToList() ?? [], true, avatarConfig);
mazeSkill = new MazeSkill(avatarConfig.MazeSkill?.OnStart.ToList() ?? [], req, true, avatarConfig);
return mazeSkill;
}
}

View File

@@ -376,6 +376,9 @@ public class PlayerInstance(PlayerData data)
if (MissionManager != null)
await MissionManager.HandleAllFinishType();
if (SceneInstance != null)
await SceneInstance.OnHeartBeat();
DatabaseHelper.ToSaveUidList.SafeAdd(Uid);
}

View File

@@ -28,6 +28,7 @@ public class EntityMonster(
public List<SceneBuff> BuffList { get; set; } = [];
public SceneBuff? TempBuff { get; set; }
public bool IsAlive { get; private set; } = true;
public bool IsInSummonUnit { get; set; } = false;
public int EventID { get; set; } = info.EventID;
public int CustomStageID { get; set; } = 0;
@@ -40,6 +41,15 @@ public class EntityMonster(
await Scene.Player.SendPacket(new PacketSyncEntityBuffChangeListScNotify(this, buff));
}
public async ValueTask RemoveBuff(int buffId)
{
var buff = BuffList.Find(x => x.BuffId == buffId);
if (buff == null) return;
BuffList.Remove(buff);
await Scene.Player.SendPacket(new PacketSyncEntityBuffChangeListScNotify(this, [buff]));
}
public async ValueTask ApplyBuff(BattleInstance instance)
{
if (TempBuff != null)

View File

@@ -0,0 +1,47 @@
using EggLink.DanhengServer.Data.Config.SummonUnit;
using EggLink.DanhengServer.GameServer.Game.Battle;
using EggLink.DanhengServer.Proto;
using EggLink.DanhengServer.Util;
namespace EggLink.DanhengServer.GameServer.Game.Scene.Entity;
public class EntitySummonUnit : IGameEntity
{
public int EntityID { get; set; }
public int GroupID { get; set; } = 0;
public int CreateAvatarEntityId { get; set; } = 0;
public long CreateTimeMs { get; set; } = Extensions.GetUnixMs();
public int LifeTimeMs { get; set; } = -1;
public int SummonUnitId { get; set; } = 0;
public MotionInfo Motion { get; set; } = new();
public List<UnitCustomTriggerConfigInfo> TriggerList { get; set; } = [];
public async ValueTask AddBuff(SceneBuff buff)
{
await ValueTask.CompletedTask;
}
public async ValueTask ApplyBuff(BattleInstance instance)
{
await ValueTask.CompletedTask;
}
public SceneEntityInfo ToProto()
{
return new SceneEntityInfo
{
EntityId = (uint)EntityID,
GroupId = (uint)GroupID,
Motion = Motion,
SummonUnit = new SceneSummonUnitInfo
{
CasterEntityId = (uint)CreateAvatarEntityId,
CreateTimeMs = (ulong)CreateTimeMs,
LifeTimeMs = LifeTimeMs,
SummonUnitId = (uint)SummonUnitId,
TriggerNameList = { TriggerList.Select(x => x.TriggerName) }
}
};
}
}

View File

@@ -3,16 +3,18 @@ using EggLink.DanhengServer.Util;
namespace EggLink.DanhengServer.GameServer.Game.Scene;
public class SceneBuff(int buffID, int buffLevel, int owner, int duration = -1)
public class SceneBuff(int buffId, int buffLevel, int owner, int duration = -1)
{
public Dictionary<string, float> DynamicValues = [];
public int BuffID { get; } = buffID;
public Dictionary<string, float> DynamicValues { get; set; } = [];
public int BuffId { get; } = buffId;
public int BuffLevel { get; } = buffLevel;
public int OwnerAvatarId { get; } = owner;
public int Duration { get; set; } = duration;
public long CreatedTime { get; set; } = Extensions.GetUnixMs();
public int SummonUnitEntityId { get; set; } = 0;
public bool IsExpired()
{
if (Duration < 0)
@@ -24,13 +26,18 @@ public class SceneBuff(int buffID, int buffLevel, int owner, int duration = -1)
{
var buffInfo = new BuffInfo
{
BuffId = (uint)BuffID,
BuffId = (uint)BuffId,
Level = (uint)BuffLevel,
BaseAvatarId = (uint)OwnerAvatarId,
AddTimeMs = (ulong)CreatedTime,
LifeTime = (ulong)Duration
LifeTime = Duration,
BuffSummonEntityId = (uint)SummonUnitEntityId,
Count = 1
};
foreach (var item in DynamicValues)
buffInfo.DynamicValues.Add(item.Key, item.Value);
return buffInfo;
}
}

View File

@@ -2,6 +2,7 @@
using EggLink.DanhengServer.Data.Config.Scene;
using EggLink.DanhengServer.Data.Excel;
using EggLink.DanhengServer.Database.Avatar;
using EggLink.DanhengServer.Database.Player;
using EggLink.DanhengServer.Enums.Scene;
using EggLink.DanhengServer.GameServer.Game.Activity.Loaders;
using EggLink.DanhengServer.GameServer.Game.Battle;
@@ -174,6 +175,8 @@ public class SceneInstance
public GameModeTypeEnum GameModeType;
public EntitySummonUnit? SummonUnit;
public SceneInstance(PlayerInstance player, MazePlaneExcel excel, int floorId, int entryId)
{
Player = player;
@@ -260,17 +263,15 @@ public class SceneInstance
}
}
;
foreach (var avatar in oldAvatarInfo)
if (AvatarInfo.Values.ToList().FindIndex(x => x.AvatarInfo.AvatarId == avatar.AvatarInfo.AvatarId) == -1)
foreach (var avatar in oldAvatarInfo.Where(avatar => AvatarInfo.Values.ToList().FindIndex(x => x.AvatarInfo.AvatarId == avatar.AvatarInfo.AvatarId) == -1))
{
removeAvatar.Add(new AvatarSceneInfo(new AvatarInfo
{
removeAvatar.Add(new AvatarSceneInfo(new AvatarInfo
{
EntityId = avatar.AvatarInfo.EntityId
}, AvatarType.AvatarFormalType, Player));
avatar.AvatarInfo.EntityId = 0;
sendPacket = true;
}
EntityId = avatar.AvatarInfo.EntityId
}, AvatarType.AvatarFormalType, Player));
avatar.AvatarInfo.EntityId = 0;
sendPacket = true;
}
var leaderAvatarId = Player.LineupManager?.GetCurLineup()?.LeaderAvatarId;
var leaderAvatarSlot = Player.LineupManager?.GetCurLineup()?.BaseAvatars
@@ -306,6 +307,15 @@ public class SceneInstance
if (sendPacket) await Player.SendPacket(new PacketSceneGroupRefreshScNotify(entity));
}
public async ValueTask AddSummonUnitEntity(EntitySummonUnit entity)
{
if (entity.EntityID != 0) return;
entity.EntityID = ++LastEntityId;
// old
await Player.SendPacket(new PacketSceneGroupRefreshScNotify(entity, SummonUnit));
SummonUnit = entity;
}
public async ValueTask RemoveEntity(IGameEntity monster)
{
await RemoveEntity(monster, IsLoaded);
@@ -328,21 +338,121 @@ public class SceneInstance
}
#endregion
#region SummonUnit
public async ValueTask<Retcode> TriggerSummonUnit(string triggerName, List<uint> targetIds)
{
if (SummonUnit == null) return Retcode.RetSceneEntityNotExist;
// check trigger
var trigger = SummonUnit.TriggerList.Find(x => x.TriggerName == triggerName);
if (trigger == null) return Retcode.RetSceneUseSkillFail;
await Player.SendPacket(new PacketRefreshTriggerByClientScNotify(triggerName, (uint)SummonUnit.EntityID, targetIds));
// check target
List<IGameEntity> targetEnter = [];
List<IGameEntity> targetExit = [];
foreach (var targetId in targetIds)
{
if (!Entities.TryGetValue((int)targetId, out var entity)) continue;
EntityMonster? monster = null;
EntityProp? prop = null;
switch (entity)
{
case EntityMonster m:
monster = m;
break;
case EntityProp p:
prop = p;
break;
}
if (monster != null)
{
if (!monster.IsAlive) continue;
if (monster.IsInSummonUnit)
{
// leave
monster.IsInSummonUnit = false;
targetExit.Add(monster);
}
else
{
// enter
monster.IsInSummonUnit = true;
targetEnter.Add(monster);
}
}
if (prop != null)
{
targetEnter.Add(prop);
}
}
if (targetEnter.Count > 0)
{
// enter
var config = trigger.OnTriggerEnter;
Player.TaskManager!.AvatarLevelTask.TriggerTasks(config, targetEnter, SummonUnit);
}
if (targetExit.Count <= 0) return Retcode.RetSucc;
{
// enter
var config = trigger.OnTriggerExit;
Player.TaskManager!.AvatarLevelTask.TriggerTasks(config, targetExit, SummonUnit);
}
return Retcode.RetSucc;
}
public async ValueTask ClearSummonUnit()
{
await Player.SendPacket(new PacketSceneGroupRefreshScNotify(null, SummonUnit));
SummonUnit = null;
}
public async ValueTask OnHeartBeat()
{
if (SummonUnit == null) return;
var endTime = SummonUnit.CreateTimeMs + SummonUnit.LifeTimeMs;
if (endTime < Extensions.GetUnixMs())
{
await ClearSummonUnit();
}
}
#endregion
}
public class AvatarSceneInfo(AvatarInfo avatarInfo, AvatarType avatarType, PlayerInstance Player) : IGameEntity
public class AvatarSceneInfo(AvatarInfo avatarInfo, AvatarType avatarType, PlayerInstance player) : IGameEntity
{
public AvatarInfo AvatarInfo = avatarInfo;
public AvatarType AvatarType = avatarType;
public List<SceneBuff> BuffList = [];
public int EntityID { get; set; } = avatarInfo.EntityId;
public int EntityID
{
get => AvatarInfo.EntityId;
set => AvatarInfo.EntityId = value;
}
public int GroupID { get; set; } = 0;
public async ValueTask AddBuff(SceneBuff buff)
{
var oldBuff = BuffList.Find(x => x.BuffID == buff.BuffID);
var oldBuff = BuffList.Find(x => x.BuffId == buff.BuffId);
if (oldBuff != null)
{
if (oldBuff.IsExpired())
@@ -355,25 +465,24 @@ public class AvatarSceneInfo(AvatarInfo avatarInfo, AvatarType avatarType, Playe
oldBuff.CreatedTime = Extensions.GetUnixMs();
oldBuff.Duration = buff.Duration;
await Player.SendPacket(new PacketSyncEntityBuffChangeListScNotify(this, oldBuff));
await player.SendPacket(new PacketSyncEntityBuffChangeListScNotify(this, oldBuff));
return;
}
}
BuffList.Add(buff);
await Player.SendPacket(new PacketSyncEntityBuffChangeListScNotify(this, buff));
await player.SendPacket(new PacketSyncEntityBuffChangeListScNotify(this, buff));
}
public async ValueTask ApplyBuff(BattleInstance instance)
{
if (BuffList.Count == 0) return;
foreach (var buff in BuffList)
foreach (var buff in BuffList.Where(buff => !buff.IsExpired()))
{
if (buff.IsExpired()) continue;
instance.Buffs.Add(new MazeBuff(buff));
}
await Player.SendPacket(new PacketSyncEntityBuffChangeListScNotify(this, BuffList));
await player.SendPacket(new PacketSyncEntityBuffChangeListScNotify(this, BuffList));
BuffList.Clear();
}

View File

@@ -0,0 +1,97 @@
using EggLink.DanhengServer.Data.Config.Task;
using EggLink.DanhengServer.GameServer.Game.Scene;
using EggLink.DanhengServer.GameServer.Game.Scene.Entity;
using EggLink.DanhengServer.GameServer.Server.Packet.Send.Lineup;
using EggLink.DanhengServer.Proto;
namespace EggLink.DanhengServer.GameServer.Game.Task.AvatarTask;
public class AvatarLevelTask
{
#region Manage
public void TriggerTasks(List<TaskConfigInfo> tasks, List<IGameEntity> targetEntities, EntitySummonUnit? summonUnit)
{
foreach (var task in tasks)
{
TriggerTask(task, targetEntities, summonUnit);
}
}
public void TriggerTask(TaskConfigInfo act, List<IGameEntity> targetEntities, EntitySummonUnit? summonUnit)
{
try
{
var methodName = act.Type.Replace("RPG.GameCore.", "");
var method = GetType().GetMethod(methodName);
if (method != null) _ = method.Invoke(this, [act, targetEntities, summonUnit]);
}
catch
{
}
}
#endregion
#region Task
public async ValueTask AddMazeBuff(TaskConfigInfo act, List<IGameEntity> targetEntities, EntitySummonUnit? summonUnit)
{
if (act is not AddMazeBuff addMazeBuff) return;
var buff = new SceneBuff(addMazeBuff.ID, 1, 0)
{
SummonUnitEntityId = summonUnit?.EntityID ?? 0
};
foreach (var item in addMazeBuff.DynamicValues)
buff.DynamicValues.Add(item.Key, item.Value.GetValue());
foreach (var targetEntity in targetEntities)
{
if (targetEntity is not EntityMonster monster) continue;
await monster.AddBuff(buff);
}
}
public async ValueTask RemoveMazeBuff(TaskConfigInfo act, List<IGameEntity> targetEntities, EntitySummonUnit? summonUnit)
{
if (act is not RemoveMazeBuff removeMazeBuff) return;
foreach (var targetEntity in targetEntities)
{
if (targetEntity is not EntityMonster monster) continue;
await monster.RemoveBuff(removeMazeBuff.ID);
}
}
public async ValueTask TriggerHitProp(TaskConfigInfo act, List<IGameEntity> targetEntities, EntitySummonUnit? summonUnit)
{
foreach (var targetEntity in targetEntities)
{
if (targetEntity is not EntityProp prop) continue;
await prop.Scene.RemoveEntity(prop);
if (prop.Excel.IsMpRecover)
{
await prop.Scene.Player.LineupManager!.GainMp(2, true, SyncLineupReason.SyncReasonMpAddPropHit);
}
else if (prop.Excel.IsHpRecover)
{
prop.Scene.Player.LineupManager!.GetCurLineup()!.Heal(2000, false);
await prop.Scene.Player.SendPacket(new PacketSyncLineupNotify(prop.Scene.Player.LineupManager!.GetCurLineup()!));
}
else
{
prop.Scene.Player.InventoryManager!.HandlePlaneEvent(prop.PropInfo.EventID);
}
prop.Scene.Player.RogueManager!.GetRogueInstance()?.OnPropDestruct(prop);
}
}
#endregion
}

View File

@@ -0,0 +1,5 @@
namespace EggLink.DanhengServer.GameServer.Game.Task.AvatarTask;
public class AvatarTaskTrigger
{
}

View File

@@ -1,4 +1,5 @@
using EggLink.DanhengServer.GameServer.Game.Player;
using EggLink.DanhengServer.GameServer.Game.Task.AvatarTask;
namespace EggLink.DanhengServer.GameServer.Game.Task;
@@ -6,6 +7,7 @@ public class TaskManager(PlayerInstance player) : BasePlayerManager(player)
{
public PerformanceTrigger PerformanceTrigger { get; } = new(player);
public LevelTask LevelTask { get; } = new(player);
public AvatarLevelTask AvatarLevelTask { get; } = new();
public MissionTaskTrigger MissionTaskTrigger { get; } = new(player);
public SceneTaskTrigger SceneTaskTrigger { get; } = new(player);
}