using RPG.GameCore.Enums; using RPG.GameCore.Excel; using RPG.Network.Proto; using RPG.Services.Gameserver.Game.Entity; using RPG.Services.Gameserver.Game.Maze; using RPG.Services.Gameserver.Modules.Attributes; using RPG.Services.Gameserver.Session; namespace RPG.Services.Gameserver.Modules; [GMAlias("adventure")] internal class AdventureModule : BaseModule { private const int StartingEntryId = 2010101; private readonly ExcelTables _excelTables; private readonly MazeManager _mazeManager; public AdventureModule(ModuleManager moduleManager, ExcelTables excelTables, MazeManager mazeManager) : base(moduleManager) { _excelTables = excelTables; _mazeManager = mazeManager; } [GMCommand("maze")] public Task OnGmEnterMaze(PlayerSession session, string[] args) { if (args.Length != 1) return Task.CompletedTask; if (!uint.TryParse(args[0], out uint entryId)) return Task.CompletedTask; MapEntryRow? entry = _excelTables.GetExcelRow(ExcelType.MapEntry, entryId); if (entry == null) return Task.CompletedTask; _mazeManager.EnterMaze(entryId, ModuleManager.Get().Team); Send(session, CmdType.CmdEnterMazeByServerScNotify, new EnterMazeByServerScNotify { Maze = _mazeManager.Maze }); return Task.CompletedTask; } public override Task OnLogin() { ModuleManager.Get().InitStartingLineup(); _mazeManager.SetPlayerUid(ModuleManager.PlayerUID); _mazeManager.EnterMaze(StartingEntryId, ModuleManager.Get().Team); return Task.CompletedTask; } public void OnBattleWin(uint battleMonster, IEnumerable assistMonsters) { if (battleMonster != 0) // 0 - not on-scene battle vs npcmonster, means cocoon or challenge _mazeManager.RemoveEntities(assistMonsters.Append(battleMonster)); } public void OnBattleLost() { _mazeManager.ResetAvatarPosition(); } [OnCommand(CmdType.CmdStartCocoonStageCsReq)] public Task OnCmdStartCocoonStageCsReq(PlayerSession session, ReadOnlyMemory body) { StartCocoonStageCsReq req = StartCocoonStageCsReq.Parser.ParseFrom(body.Span); CocoonRow? cocoonRow = _excelTables.GetExcelRow(ExcelType.Cocoon, req.CocoonId * 10); // CocoonId * 10 + worldLevel if (cocoonRow == null) { Send(session, CmdType.CmdStartCocoonStageScRsp, new StartCocoonStageScRsp { Retcode = Retcode.RET_STAGE_COCOON_PROP_NOT_VALID }); return Task.CompletedTask; } if (req.Wave is < 1 or > 5) { Send(session, CmdType.CmdStartCocoonStageScRsp, new StartCocoonStageScRsp { Retcode = Retcode.RET_STAGE_COCOON_WAVE_NOT_VALID }); return Task.CompletedTask; } BattleModule battleModule = ModuleManager.Get(); battleModule.StartCocoonStage(cocoonRow, req.Wave); Send(session, CmdType.CmdStartCocoonStageScRsp, new StartCocoonStageScRsp { Retcode = Retcode.RET_SUCC, BattleInfo = battleModule.Battle, CocoonId = req.CocoonId, PropEntityId = req.PropEntityId, Wave = req.Wave }); return Task.CompletedTask; } [OnCommand(CmdType.CmdInteractPropCsReq)] public Task OnCmdInteractPropCsReq(PlayerSession session, ReadOnlyMemory body) { InteractPropCsReq req = InteractPropCsReq.Parser.ParseFrom(body.Span); // TODO: interact logic Send(session, CmdType.CmdInteractPropScRsp, new InteractPropScRsp { PropEntityId = req.PropEntityId, Retcode = 0 }); return Task.CompletedTask; } [OnCommand(CmdType.CmdSceneCastSkillCsReq)] public Task OnCmdSceneCastSkillCsReq(PlayerSession session, ReadOnlyMemory body) { SceneCastSkillCsReq req = SceneCastSkillCsReq.Parser.ParseFrom(body.Span); BattleModule battleModule = ModuleManager.Get(); if (_mazeManager.EntityManager.GetEntityById(req.CastEntityId) is NpcMonsterEntity) { battleModule.OnBeingHitByMonster(req.CastEntityId, req.AssistMonsterEntityIdList); } else if (_mazeManager.EntityManager.GetEntityById(req.AbilityTargetEntityId) is NpcMonsterEntity) { battleModule.OnSuccessfulAttack(req.AbilityTargetEntityId, req.AssistMonsterEntityIdList); } Send(session, CmdType.CmdSceneCastSkillScRsp, new SceneCastSkillScRsp { Retcode = 0, BattleInfo = battleModule.Battle ?? new() }); return Task.CompletedTask; } [OnCommand(CmdType.CmdGetCurSceneInfoCsReq)] public Task OnCmdGetCurSceneInfoCsReq(PlayerSession session, ReadOnlyMemory _) { Send(session, CmdType.CmdGetCurSceneInfoScRsp, new GetCurSceneInfoScRsp { Retcode = 0, Scene = _mazeManager.SceneInfo }); return Task.CompletedTask; } [OnCommand(CmdType.CmdGetMazeMapInfoCsReq)] public Task OnCmdGetMazeMapInfoCsReq(PlayerSession session, ReadOnlyMemory body) { GetMazeMapInfoCsReq req = GetMazeMapInfoCsReq.Parser.ParseFrom(body.Span); Send(session, CmdType.CmdGetMazeMapInfoScRsp, new GetMazeMapInfoScRsp { Retcode = 0, EntryId = req.EntryId, // TODO: LightenSectionList = { }, MazeGroupList = { }, MazePropList = { } }); return Task.CompletedTask; } [OnCommand(CmdType.CmdEnterMazeCsReq)] public Task OnCmdEnterMazeCsReq(PlayerSession session, ReadOnlyMemory body) { EnterMazeCsReq req = EnterMazeCsReq.Parser.ParseFrom(body.Span); MapEntryRow? entry = _excelTables.GetExcelRow(ExcelType.MapEntry, req.EntryId); if (entry == null) { Send(session, CmdType.CmdEnterMazeScRsp, new EnterMazeScRsp { Retcode = Retcode.RET_MAZE_MAP_NOT_EXIST }); return Task.CompletedTask; } _mazeManager.EnterMaze(entry.ID, ModuleManager.Get().Team); Send(session, CmdType.CmdEnterMazeScRsp, new EnterMazeScRsp { Retcode = 0, Maze = _mazeManager.Maze }); return Task.CompletedTask; } }