using EggLink.DanhengServer.Data; using EggLink.DanhengServer.Data.Excel; using EggLink.DanhengServer.Enums.Rogue; using EggLink.DanhengServer.Enums.RogueMagic; using EggLink.DanhengServer.GameServer.Game.Battle; using EggLink.DanhengServer.GameServer.Game.Player; using EggLink.DanhengServer.GameServer.Game.Rogue; using EggLink.DanhengServer.GameServer.Game.Rogue.Event; using EggLink.DanhengServer.GameServer.Game.RogueMagic.Adventure; using EggLink.DanhengServer.GameServer.Game.RogueMagic.MagicUnit; using EggLink.DanhengServer.GameServer.Game.RogueMagic.Scene; using EggLink.DanhengServer.GameServer.Game.RogueMagic.Scepter; using EggLink.DanhengServer.GameServer.Game.Scene.Entity; using EggLink.DanhengServer.GameServer.Server.Packet.Send.RogueCommon; using EggLink.DanhengServer.GameServer.Server.Packet.Send.RogueMagic; using EggLink.DanhengServer.Proto; using EggLink.DanhengServer.Util; namespace EggLink.DanhengServer.GameServer.Game.RogueMagic; public class RogueMagicInstance : BaseRogueInstance { #region Initializer public RogueMagicInstance(PlayerInstance player, int areaId, List difficultyIds, int styleType) : base(player, RogueSubModeEnum.MagicRogue, 0) { // generate levels AreaExcel = GameData.RogueMagicAreaData.GetValueOrDefault(areaId) ?? throw new Exception("Invalid area id"); // wont be null because of validation in RogueMagicManager foreach (var index in Enumerable.Range(1, AreaExcel.LayerIDList.Count)) { var layerId = AreaExcel.LayerIDList[index - 1]; var levelInstance = new RogueMagicLevelInstance(index, layerId, GameData.RogueMagicLayerIdRoomCountDict.GetValueOrDefault(layerId)); Levels.Add(levelInstance.LayerId, levelInstance); } CurLayerId = AreaExcel.LayerIDList[0]; EventManager = new RogueEventManager(player, this); BaseRerollCount = 0; foreach (var id in difficultyIds) { GameData.RogueMagicDifficultyCompData.TryGetValue(id, out var excel); if (excel != null) DifficultyCompExcels.Add(excel); } foreach (var id in AreaExcel.DifficultyIDList) // need to find a better way to get difficulty excels { GameData.RogueTournDifficultyData.TryGetValue(1000 + id, out var excel); if (excel != null) DifficultyExcels.Add(excel); } StyleType = (RogueMagicStyleTypeEnum)styleType; var t = RollScepter(1, 1); t.AsTask().Wait(); } #endregion #region Properties public RogueMagicAreaExcel AreaExcel { get; set; } public List DifficultyCompExcels { get; set; } = []; public Dictionary Levels { get; set; } = []; public List DifficultyExcels { get; set; } = []; // for battle public int CurLayerId { get; set; } public RogueMagicLevelInstance? CurLevel => Levels.GetValueOrDefault(CurLayerId); public RogueMagicLevelStatus LevelStatus { get; set; } = RogueMagicLevelStatus.Processing; public RogueMagicStyleTypeEnum StyleType { get; set; } public Dictionary RogueScepters { get; set; } = []; public Dictionary RogueMagicUnits { get; set; } = []; public int CurMagicUnitUniqueId { get; set; } = 1; public Dictionary RoomTypeWeight { get; set; } = new() { { RogueMagicRoomTypeEnum.Battle, 15 }, { RogueMagicRoomTypeEnum.Wealth, 4 }, { RogueMagicRoomTypeEnum.Shop, 4 }, { RogueMagicRoomTypeEnum.Event, 7 }, { RogueMagicRoomTypeEnum.Adventure, 60 }, { RogueMagicRoomTypeEnum.Reward, 5 }, { RogueMagicRoomTypeEnum.Elite, 1 } }; #endregion #region Scene public async ValueTask EnterNextLayer(int roomIndex, RogueMagicRoomTypeEnum type) { var curIndex = CurLevel?.LevelIndex ?? 0; if (curIndex == 3) { // last layer return; } CurLayerId = AreaExcel.LayerIDList[curIndex]; await EnterRoom(1, type); } public async ValueTask EnterRoom(int roomIndex, RogueMagicRoomTypeEnum type) { if (CurLevel == null) return; //if (CurLevel.CurRoomIndex == roomIndex) // // same room // return; //if (CurLevel.CurRoomIndex + 1 != roomIndex) // only allow to enter next room // // invalid room // return; if (CurLevel.CurRoom != null) CurLevel.CurRoom.Status = RogueMagicRoomStatus.Finish; // enter room CurLevel.CurRoomIndex = roomIndex; CurLevel.CurRoom?.Init(type); // next room var next = CurLevel.Rooms.Find(x => x.RoomIndex == roomIndex + 1); if (next != null) next.Status = RogueMagicRoomStatus.Inited; // scene var entrance = CurLevel.CurRoom?.Config?.EntranceId ?? 0; var group = CurLevel.CurRoom?.Config?.AnchorGroup ?? 0; var anchor = CurLevel.CurRoom?.Config?.AnchorId ?? 1; // call event EventManager?.OnNextRoom(); foreach (var miracle in RogueMiracles.Values) miracle.OnEnterNextRoom(); await Player.EnterMissionScene(entrance, group, anchor, false); // sync await Player.SendPacket(new PacketRogueMagicLevelInfoUpdateScNotify(this, [CurLevel], [next?.RoomIndex ?? 0, (next?.RoomIndex ?? 0) - 1])); } public async ValueTask QuitRogue() { await Player.EnterMissionScene(801120102, 0, 0, false); Player.RogueMagicManager!.RogueMagicInstance = null; } #endregion #region Scepter public async ValueTask RollScepter(int amount, int level) { var scepterExcels = GameData.RogueMagicScepterData.Values.Where(x => !RogueScepters.ContainsKey(x.ScepterID) && x.ScepterLevel == level).ToList(); for (var i = 0; i < amount; i++) { var menu = new RogueScepterSelectMenu(this); menu.SetScepterPool(scepterExcels); var action = menu.GetActionInstance(); RogueActions.Add(action.QueuePosition, action); await UpdateMenu(action.QueuePosition); } } public async ValueTask HandleScepterSelect(RogueMagicScepter selectScepter, int location) { if (RogueActions.Count == 0) return; var action = RogueActions.First().Value; if (action.RogueScepterSelectMenu != null) { var scepterExcel = action.RogueScepterSelectMenu.Scepters.Find(x => x.ScepterID == selectScepter.ScepterId); if (scepterExcel != null) await AddScepter(scepterExcel); RogueActions.Remove(action.QueuePosition); } await UpdateMenu(); await Player.SendPacket( new PacketHandleRogueCommonPendingActionScRsp(action.QueuePosition, location, selectScepter: true)); } public async ValueTask AddScepter(RogueMagicScepterExcel excel, RogueCommonActionResultSourceType source = RogueCommonActionResultSourceType.Select) { var scepter = new RogueScepterInstance(excel); RogueScepters.Add(excel.ScepterID, scepter); await Player.SendPacket(new PacketSyncRogueCommonActionResultScNotify(RogueSubMode, scepter.ToGetInfo(source))); } public async ValueTask DressScepter(int scepterId, int slot, int unitUniqueId) { var scepter = RogueScepters.GetValueOrDefault(scepterId); if (scepter == null) return; var unit = RogueMagicUnits.GetValueOrDefault(unitUniqueId); if (unit == null) return; // add scepter.AddUnit(slot, unit); await Player.SendPacket(new PacketSyncRogueCommonActionResultScNotify(RogueSubMode, scepter.ToDressInfo(RogueCommonActionResultSourceType.None))); } #endregion #region MagicUnit public async ValueTask RollMagicUnit(int amount, int level, List categories) { var unitExcels = GameData.RogueMagicUnitData.Values.Where(x => !RogueMagicUnits.ContainsKey(x.MagicUnitID) && x.MagicUnitLevel == level && categories.Contains(x.MagicUnitCategory) && x.MagicUnitType != RogueMagicMountTypeEnum.Active).ToList(); for (var i = 0; i < amount; i++) { var menu = new RogueMagicUnitSelectMenu(this); menu.SetPool(unitExcels); var action = menu.GetActionInstance(); RogueActions.Add(action.QueuePosition, action); await UpdateMenu(action.QueuePosition); } } public async ValueTask HandleMagicUnitSelect(RogueMagicGameUnit selectMagicUnit, int location) { if (RogueActions.Count == 0) return; var action = RogueActions.First().Value; if (action.RogueMagicUnitSelectMenu != null) { var unitExcel = action.RogueMagicUnitSelectMenu.MagicUnits.Find(x => x.MagicUnitID == selectMagicUnit.MagicUnitId); if (unitExcel != null) await AddMagicUnit(unitExcel); RogueActions.Remove(action.QueuePosition); } await UpdateMenu(); await Player.SendPacket( new PacketHandleRogueCommonPendingActionScRsp(action.QueuePosition, location, selectMagicUnit: true)); } public async ValueTask AddMagicUnit(RogueMagicUnitExcel excel, RogueCommonActionResultSourceType source = RogueCommonActionResultSourceType.Select) { var unit = new RogueMagicUnitInstance(excel) { UniqueId = CurMagicUnitUniqueId++ }; RogueMagicUnits.Add(unit.UniqueId, unit); await Player.SendPacket(new PacketSyncRogueCommonActionResultScNotify(RogueSubMode, unit.ToGetInfo(source))); } #endregion #region Adventure public async ValueTask HandleStopWolfGunAdventure(List targetIndex, RogueMagicAdventureInstance instance) { if (instance.WolfGunTargets.Count == 0) return; var result = (from index in targetIndex where index >= 0 && index < instance.WolfGunTargets.Count select instance.WolfGunTargets[index]).ToList(); foreach (var target in result) { if (target.IsMoney) { // money await GainMoney(target.TargetId, 2); } else if (target.IsMiracle) { // miracle await AddMiracle(target.TargetId); } else if (target.IsRuanmei) { // ruanmei foreach (var unused in Enumerable.Range(0, 10)) { var unitExcels = GameData.RogueMagicUnitData.Values .Where(x => !RogueMagicUnits.ContainsKey(x.MagicUnitID) && x.MagicUnitLevel == 1 && x.MagicUnitType != RogueMagicMountTypeEnum.Active).ToList(); var unit = unitExcels.RandomElement(); await AddMagicUnit(unit, RogueCommonActionResultSourceType.None); } } } } #endregion #region Handlers public override void OnBattleStart(BattleInstance battle) { base.OnBattleStart(battle); if (DifficultyExcels.Count > 0) { var excel = DifficultyExcels.RandomElement(); if (excel.LevelList.Count > 0) battle.CustomLevel = excel.LevelList.RandomElement(); } battle.MagicInfo = new BattleRogueMagicInfo { ModifierContent = new IGEFNGNCKOG { OJIBOBNAIKH = 5 }, DetailInfo = new BattleRogueMagicDetailInfo { ILAPCDFJHNH = new BattleRogueMagicItemInfo { BattleRoundCount = new BattleRogueMagicRoundCount(), BattleScepterList = { RogueScepters.Select(x => x.Value.ToBattleScepterInfo()) } } } }; } public async ValueTask HitMonsterInAdventure(List monsters) { await ValueTask.CompletedTask; } public override async ValueTask OnBattleEnd(BattleInstance battle, PVEBattleResultCsReq req) { if (battle.BattleEndStatus != BattleEndStatus.BattleEndWin) { // quit return; } if (CurLevel!.CurRoom!.RoomType == RogueMagicRoomTypeEnum.Boss) { await RollScepter(battle.Stages.Count, 1); await RollMagicUnit(battle.Stages.Count, 1, [RogueMagicUnitCategoryEnum.Ultra]); } else { await RollMagicUnit(battle.Stages.Count, 1, [RogueMagicUnitCategoryEnum.Common]); } } public override async ValueTask OnPropDestruct(EntityProp prop) { await base.OnPropDestruct(prop); var inst = CurLevel?.CurRoom?.AdventureInstance; if (inst != null && inst.Excel.AdventureType == RogueAdventureGameplayTypeEnum.RogueDestroyProp) { inst.Score++; await Player.SendPacket(new PacketSyncRogueAdventureRoomInfoScNotify(inst)); } } #endregion #region Serialization public RogueMagicCurInfo ToProto() { var proto = new RogueMagicCurInfo { Lineup = ToLineupInfo(), Level = ToLevelInfo(), ItemValue = ToGameItemValueInfo(), MiracleInfo = ToMiracleInfo(), GameDifficultyInfo = ToDifficultyInfo(), MagicItem = ToMagicItemInfo(), BasicInfo = ToCurAreaInfo(), JDMGJDBMHEJ = new LKJMDOAHGIN() }; return proto; } public RogueTournCurAreaInfo ToCurAreaInfo() { var proto = new RogueTournCurAreaInfo { RogueSubMode = (uint)RogueSubMode, SubAreaId = (uint)AreaExcel.AreaID, PendingAction = RogueActions.Count > 0 ? RogueActions.First().Value.ToProto() : new RogueCommonPendingAction() // to serialize empty action }; return proto; } public RogueMagicGameItemInfo ToMagicItemInfo() { var proto = new RogueMagicGameItemInfo { GameStyleType = (uint)StyleType }; return proto; } public RogueMagicGameDifficultyInfo ToDifficultyInfo() { var proto = new RogueMagicGameDifficultyInfo { DifficultyIdList = { DifficultyCompExcels.Select(x => (uint)x.DifficultyCompID) } }; return proto; } public RogueGameItemValue ToGameItemValueInfo() { return new RogueGameItemValue { VirtualItem = { { 31, (uint)CurMoney } } }; } public RogueTournLineupInfo ToLineupInfo() { return new RogueTournLineupInfo { AvatarIdList = { Player.LineupManager!.GetCurLineup()!.BaseAvatars!.Select(x => (uint)x.BaseAvatarId) }, RogueReviveCost = new ItemCostData { ItemList = { new ItemCost { PileItem = new PileItem { ItemId = 31, ItemNum = (uint)CurReviveCost } } } } }; } public ChessRogueMiracleInfo ToMiracleInfo() { var proto = new ChessRogueMiracleInfo { ChessRogueMiracleInfo_ = new ChessRogueMiracle() }; proto.ChessRogueMiracleInfo_.MiracleList.AddRange(RogueMiracles.Select(x => x.Value.ToGameMiracleProto()) .ToList()); return proto; } public RogueMagicGameLevelInfo ToLevelInfo() { var proto = new RogueMagicGameLevelInfo { Status = LevelStatus, CurLevelIndex = (uint)(CurLevel?.CurRoomIndex ?? 0), Reason = RogueMagicSettleReason.None }; foreach (var levelInstance in Levels.Values) proto.LevelInfoList.Add(levelInstance.ToProto()); return proto; } public RogueMagicCurSceneInfo ToCurSceneInfo() { return new RogueMagicCurSceneInfo { Lineup = Player.LineupManager!.GetCurLineup()!.ToProto(), Scene = Player.SceneInstance!.ToProto(), //RotateInfo = new RogueMapRotateInfo //{ // IsRotate = CurLevel?.CurRoom?.Config?.RotateInfo.IsRotate ?? false, // BJPBAJECKFO = (uint)(CurLevel?.CurRoom?.Config?.RotateInfo.RotateNum ?? 0) // HDEHHKEMOCD //} RotateInfo = new RogueMapRotateInfo() }; } #endregion }