mirror of
https://github.com/EggLinks/DanhengServer-OpenSource.git
synced 2026-01-02 20:26:03 +08:00
270 lines
10 KiB
C#
270 lines
10 KiB
C#
using EggLink.DanhengServer.Data;
|
|
using EggLink.DanhengServer.Data.Excel;
|
|
using EggLink.DanhengServer.Database;
|
|
using EggLink.DanhengServer.Game.Battle.Skill;
|
|
using EggLink.DanhengServer.Game.Player;
|
|
using EggLink.DanhengServer.Game.Scene.Entity;
|
|
using EggLink.DanhengServer.Proto;
|
|
using EggLink.DanhengServer.Server.Packet.Send.Battle;
|
|
using EggLink.DanhengServer.Server.Packet.Send.Lineup;
|
|
using EggLink.DanhengServer.Util;
|
|
|
|
namespace EggLink.DanhengServer.Game.Battle
|
|
{
|
|
public class BattleManager(PlayerInstance player) : BasePlayerManager(player)
|
|
{
|
|
public void StartBattle(SceneCastSkillCsReq req, MazeSkill skill, int casterAvatarId)
|
|
{
|
|
if (Player.BattleInstance != null) return;
|
|
var targetList = new List<EntityMonster>();
|
|
var propList = new List<EntityProp>();
|
|
if (!skill.TriggerBattle)
|
|
{
|
|
Player.SendPacket(new PacketSceneCastSkillScRsp(req.CastEntityId));
|
|
return;
|
|
}
|
|
if (Player.SceneInstance!.AvatarInfo.ContainsKey((int)req.AttackedByEntityId))
|
|
{
|
|
foreach (var entity in req.HitTargetEntityIdList)
|
|
{
|
|
Player.SceneInstance!.Entities.TryGetValue((int)entity, out var entityInstance);
|
|
if (entityInstance is EntityMonster monster)
|
|
{
|
|
targetList.Add(monster);
|
|
} else if (entityInstance is EntityProp prop)
|
|
{
|
|
propList.Add(prop);
|
|
}
|
|
}
|
|
|
|
foreach (var entity in req.AssistMonsterEntityIdList)
|
|
{
|
|
Player.SceneInstance!.Entities.TryGetValue((int)entity, out var entityInstance);
|
|
if (entityInstance is EntityMonster monster)
|
|
{
|
|
targetList.Add(monster);
|
|
}
|
|
}
|
|
} else
|
|
{
|
|
bool isAmbushed = false;
|
|
foreach (var entity in req.HitTargetEntityIdList)
|
|
{
|
|
if (Player.SceneInstance!.AvatarInfo.ContainsKey((int)entity))
|
|
{
|
|
isAmbushed = true;
|
|
break;
|
|
}
|
|
}
|
|
if (!isAmbushed)
|
|
{
|
|
Player.SendPacket(new PacketSceneCastSkillScRsp(req.CastEntityId));
|
|
return;
|
|
}
|
|
var monsterEntity = Player.SceneInstance!.Entities[(int)req.AttackedByEntityId];
|
|
if (monsterEntity is EntityMonster monster)
|
|
{
|
|
targetList.Add(monster);
|
|
}
|
|
}
|
|
if (targetList.Count == 0 && propList.Count == 0)
|
|
{
|
|
Player.SendPacket(new PacketSceneCastSkillScRsp(req.CastEntityId));
|
|
return;
|
|
}
|
|
foreach (var prop in propList)
|
|
{
|
|
Player.SceneInstance!.RemoveEntity(prop);
|
|
}
|
|
if (targetList.Count > 0)
|
|
{
|
|
// Skill handle
|
|
BattleInstance battleInstance = new(Player, Player.LineupManager!.GetCurLineup()!, targetList)
|
|
{
|
|
WorldLevel = Player.Data.WorldLevel,
|
|
CasterIndex = (int)req.CastEntityId,
|
|
};
|
|
Player.BattleInstance = battleInstance;
|
|
battleInstance.CasterIndex = Player.LineupManager!.GetCurLineup()!.BaseAvatars!.FindIndex(x => x.BaseAvatarId == casterAvatarId);
|
|
skill.OnEnterBattle(battleInstance);
|
|
Player.SendPacket(new PacketSceneCastSkillScRsp(req.CastEntityId, battleInstance));
|
|
} else
|
|
{
|
|
Player.SendPacket(new PacketSceneCastSkillScRsp(req.CastEntityId));
|
|
}
|
|
}
|
|
|
|
public void StartStage(int eventId)
|
|
{
|
|
if (Player.BattleInstance != null) return;
|
|
|
|
GameData.StageConfigData.TryGetValue(eventId, out var stageConfig);
|
|
if (stageConfig == null)
|
|
{
|
|
GameData.StageConfigData.TryGetValue(eventId * 10 + Player.Data.WorldLevel, out stageConfig);
|
|
if (stageConfig == null)
|
|
{
|
|
Player.SendPacket(new PacketSceneEnterStageScRsp());
|
|
return;
|
|
}
|
|
}
|
|
|
|
BattleInstance battleInstance = new(Player, Player.LineupManager!.GetCurLineup()!, [stageConfig])
|
|
{
|
|
WorldLevel = Player.Data.WorldLevel,
|
|
};
|
|
|
|
Player.BattleInstance = battleInstance;
|
|
|
|
Player.SendPacket(new PacketSceneEnterStageScRsp(battleInstance));
|
|
}
|
|
|
|
public void StartCocoonStage(int cocoonId, int wave, int worldLevel)
|
|
{
|
|
if (Player.BattleInstance != null) return;
|
|
|
|
GameData.CocoonConfigData.TryGetValue(cocoonId * 100 + worldLevel, out var config);
|
|
if (config == null)
|
|
{
|
|
Player.SendPacket(new PacketStartCocoonStageScRsp());
|
|
return;
|
|
}
|
|
wave = Math.Min(Math.Max(wave, 1), config.MaxWave);
|
|
|
|
int cost = config.StaminaCost * wave;
|
|
if (Player.Data.Stamina < cost)
|
|
{
|
|
Player.SendPacket(new PacketStartCocoonStageScRsp());
|
|
return;
|
|
}
|
|
|
|
List<StageConfigExcel> stageConfigExcels = [];
|
|
for (int i = 0; i < wave; i++)
|
|
{
|
|
var stageId = config.StageIDList.RandomElement();
|
|
GameData.StageConfigData.TryGetValue(stageId, out var stageConfig);
|
|
if (stageConfig == null) continue;
|
|
|
|
stageConfigExcels.Add(stageConfig);
|
|
}
|
|
|
|
if (stageConfigExcels.Count == 0)
|
|
{
|
|
Player.SendPacket(new PacketStartCocoonStageScRsp());
|
|
return;
|
|
}
|
|
|
|
BattleInstance battleInstance = new(Player, Player.LineupManager!.GetCurLineup()!, stageConfigExcels)
|
|
{
|
|
StaminaCost = cost,
|
|
WorldLevel = config.WorldLevel,
|
|
CocoonWave = wave,
|
|
MappingInfoId = config.MappingInfoID,
|
|
};
|
|
|
|
Player.BattleInstance = battleInstance;
|
|
|
|
Player.SendPacket(new PacketStartCocoonStageScRsp(battleInstance, cocoonId, wave));
|
|
}
|
|
|
|
public void EndBattle(PVEBattleResultCsReq req)
|
|
{
|
|
if (Player.BattleInstance == null)
|
|
{
|
|
Player.SendPacket(new PacketPVEBattleResultScRsp());
|
|
return;
|
|
}
|
|
Player.BattleInstance.BattleEndStatus = req.EndStatus;
|
|
var battle = Player.BattleInstance;
|
|
bool updateStatus = true;
|
|
bool teleportToAnchor = false;
|
|
var minimumHp = 0;
|
|
|
|
switch (req.EndStatus)
|
|
{
|
|
case BattleEndStatus.BattleEndWin:
|
|
// Remove monsters from the map - Could optimize it a little better
|
|
//for (var monster in battle.NpcMonsters)
|
|
//{
|
|
// // Dont remove farmable monsters from the scene when they are defeated
|
|
// if (monster.isFarmElement()) continue;
|
|
// // Remove monster
|
|
// player.SceneInstance.RemoveEntity(monster);
|
|
//}
|
|
// Drops
|
|
// Spend stamina
|
|
if (battle.StaminaCost > 0)
|
|
{
|
|
Player.SpendStamina(battle.StaminaCost);
|
|
}
|
|
break;
|
|
case BattleEndStatus.BattleEndLose:
|
|
// Set avatar hp to 20% if the player's party is downed
|
|
minimumHp = 2000;
|
|
teleportToAnchor = true;
|
|
break;
|
|
default:
|
|
teleportToAnchor = true;
|
|
updateStatus = false;
|
|
break;
|
|
}
|
|
|
|
if (updateStatus)
|
|
{
|
|
var lineup = Player.LineupManager!.GetCurLineup()!;
|
|
// Update battle status
|
|
foreach (var avatar in req.Stt.AvatarBattleList)
|
|
{
|
|
var avatarInstance = Player.AvatarManager!.GetAvatar((int)avatar.Id);
|
|
var prop = avatar.AvatarStatus;
|
|
int curHp = (int)Math.Max(Math.Round(prop.LeftHp / prop.MaxHp * 10000), minimumHp);
|
|
int curSp = (int)prop.LeftSp * 100;
|
|
if (avatarInstance == null)
|
|
{
|
|
GameData.SpecialAvatarData.TryGetValue((int)(avatar.Id * 10 + Player.Data.WorldLevel), out var specialAvatar);
|
|
if (specialAvatar == null) continue;
|
|
specialAvatar.CurHp[Player.Uid] = curHp;
|
|
specialAvatar.CurSp[Player.Uid] = curSp;
|
|
} else
|
|
{
|
|
avatarInstance.SetCurHp(curHp, lineup.LineupType != 0);
|
|
avatarInstance.SetCurSp(curSp, lineup.LineupType != 0);
|
|
}
|
|
}
|
|
|
|
DatabaseHelper.Instance?.UpdateInstance(Player.AvatarManager!.AvatarData!);
|
|
Player.SendPacket(new PacketSyncLineupNotify(lineup));
|
|
}
|
|
if (teleportToAnchor)
|
|
{
|
|
var anchorProp = Player.SceneInstance?.GetNearestSpring(long.MaxValue);
|
|
if (anchorProp != null && anchorProp.PropInfo != null)
|
|
{
|
|
var anchor = Player!.SceneInstance?.FloorInfo?.GetAnchorInfo(
|
|
anchorProp.PropInfo.AnchorGroupID,
|
|
anchorProp.PropInfo.AnchorID
|
|
);
|
|
if (anchor != null)
|
|
{
|
|
Player.MoveTo(anchor.ToPositionProto());
|
|
}
|
|
}
|
|
}
|
|
// call battle end
|
|
Player.MissionManager!.OnBattleFinish(req);
|
|
|
|
// remove monster from the scene
|
|
if (req.EndStatus == BattleEndStatus.BattleEndWin)
|
|
{
|
|
foreach (var monster in battle.EntityMonsters)
|
|
{
|
|
Player.SceneInstance!.RemoveEntity(monster);
|
|
}
|
|
}
|
|
|
|
Player.BattleInstance = null;
|
|
Player.SendPacket(new PacketPVEBattleResultScRsp(req, Player, battle));
|
|
}
|
|
}
|
|
}
|