const std = @import("std"); const protocol = @import("protocol"); const Session = @import("../Session.zig"); const Packet = @import("../Packet.zig"); const Config = @import("config.zig"); const Data = @import("../data.zig"); const ChallengeData = @import("challenge.zig"); const BattleManager = @import("../manager/battle_mgr.zig").BattleManager; const ChallegeStageManager = @import("../manager/battle_mgr.zig").ChallegeStageManager; const NodeCheck = @import("../commands/value.zig"); const ArrayList = std.ArrayList; const Allocator = std.mem.Allocator; const CmdID = protocol.CmdID; const log = std.log.scoped(.scene_service); // Function to check if an ID is in a list fn isInList(id: u32, list: []const u32) bool { for (list) |item| { if (item == id) { return true; } } return false; } pub var on_battle: bool = false; pub fn onStartCocoonStage(session: *Session, packet: *const Packet, allocator: Allocator) !void { const req = try packet.getProto(protocol.StartCocoonStageCsReq, allocator); var battle_mgr = BattleManager.init(allocator); const battle = try battle_mgr.createBattle(); on_battle = true; try session.send(CmdID.CmdStartCocoonStageScRsp, protocol.StartCocoonStageScRsp{ .retcode = 0, .cocoon_id = req.cocoon_id, .prop_entity_id = req.prop_entity_id, .wave = req.wave, .battle_info = battle, }); } pub fn onQuickStartCocoonStage(session: *Session, packet: *const Packet, allocator: Allocator) !void { const req = try packet.getProto(protocol.QuickStartCocoonStageCsReq, allocator); var battle_mgr = BattleManager.init(allocator); const battle = try battle_mgr.createBattle(); on_battle = true; try session.send(CmdID.CmdQuickStartCocoonStageScRsp, protocol.QuickStartCocoonStageScRsp{ .retcode = 0, .cocoon_id = req.cocoon_id, .wave = req.wave, .battle_info = battle, }); } pub fn onQuickStartFarmElement(session: *Session, packet: *const Packet, allocator: Allocator) !void { const req = try packet.getProto(protocol.QuickStartFarmElementCsReq, allocator); var battle_mgr = BattleManager.init(allocator); const battle = try battle_mgr.createBattle(); on_battle = true; try session.send(CmdID.CmdQuickStartFarmElementScRsp, protocol.QuickStartFarmElementScRsp{ .retcode = 0, .world_level = req.world_level, .JDANOKNHNHL = req.JDANOKNHNHL, .battle_info = battle, }); } pub fn onStartBattleCollege(session: *Session, packet: *const Packet, allocator: Allocator) !void { const req = try packet.getProto(protocol.StartBattleCollegeCsReq, allocator); var battle_mgr = BattleManager.init(allocator); const battle = try battle_mgr.createBattle(); on_battle = true; try session.send(CmdID.CmdStartBattleCollegeScRsp, protocol.StartBattleCollegeScRsp{ .retcode = 0, .id = req.id, .battle_info = battle, }); } pub fn onSceneCastSkill(session: *Session, packet: *const Packet, allocator: Allocator) !void { var battle_mgr = BattleManager.init(allocator); const battle = try battle_mgr.createBattle(); var challege_mgr = ChallegeStageManager.init(allocator); const challenge = try challege_mgr.createChallegeStage(); const req = try packet.getProto(protocol.SceneCastSkillCsReq, allocator); var battle_info: ?protocol.SceneBattleInfo = null; var monster_battle_info_list = ArrayList(protocol.HitMonsterBattleInfo).init(allocator); Highlight("SKILL INDEX: {}", .{req.skill_index}); Highlight("ATTACKED BY ENTITY ID: {}", .{req.attacked_by_entity_id}); const is_challenge = ChallengeData.on_challenge; for (req.assist_monster_entity_id_list.items) |id| { const attacker_id = req.attacked_by_entity_id; const skill_index = req.skill_index; const bt = getBattleType(id, attacker_id, skill_index, is_challenge); if (is_challenge) { if ((attacker_id <= 1000) or (id < 1000)) { Highlight("CHALLENGE, MONSTER ENTITY ID: {} -> {}", .{ id, bt }); try monster_battle_info_list.append(.{ .target_monster_entity_id = id, .monster_battle_type = bt, }); if (bt == protocol.MonsterBattleType.MONSTER_BATTLE_TYPE_TRIGGER_BATTLE) { battle_info = challenge; } } } else { if ((attacker_id <= 1000 or attacker_id > 1000000) or (id < 1000 or id > 1000000)) { Highlight("BATTLE, MONSTER ENTITY ID: {} -> {}", .{ id, bt }); try monster_battle_info_list.append(.{ .target_monster_entity_id = id, .monster_battle_type = bt, }); if (bt == protocol.MonsterBattleType.MONSTER_BATTLE_TYPE_TRIGGER_BATTLE) { battle_info = battle; on_battle = true; } } } } try session.send(CmdID.CmdSceneCastSkillScRsp, protocol.SceneCastSkillScRsp{ .retcode = 0, .cast_entity_id = req.cast_entity_id, .monster_battle_info = monster_battle_info_list, .battle_info = battle_info, }); } pub fn onGetCurBattleInfo(session: *Session, _: *const Packet, allocator: Allocator) !void { var battle_mgr = BattleManager.init(allocator); const battle = try battle_mgr.createBattle(); var challege_mgr = ChallegeStageManager.init(allocator); const challenge = try challege_mgr.createChallegeStage(); var rsp = protocol.GetCurBattleInfoScRsp.init(allocator); rsp.battle_info = if (ChallengeData.on_challenge == true) challenge else if (on_battle == true) battle else null; rsp.retcode = 0; try session.send(CmdID.CmdGetCurBattleInfoScRsp, rsp); } pub fn onPVEBattleResult(session: *Session, packet: *const Packet, allocator: Allocator) !void { const req = try packet.getProto(protocol.PVEBattleResultCsReq, allocator); var rsp = protocol.PVEBattleResultScRsp.init(allocator); rsp.battle_id = req.battle_id; rsp.end_status = req.end_status; rsp.stage_id = req.stage_id; on_battle = false; try session.send(CmdID.CmdPVEBattleResultScRsp, rsp); } pub fn onSceneCastSkillCostMp(session: *Session, packet: *const Packet, allocator: Allocator) !void { const req = try packet.getProto(protocol.SceneCastSkillCostMpCsReq, allocator); try session.send(CmdID.CmdSceneCastSkillCostMpScRsp, protocol.SceneCastSkillCostMpScRsp{ .retcode = 0, .cast_entity_id = req.cast_entity_id, }); } pub fn onSyncClientResVersion(session: *Session, packet: *const Packet, allocator: Allocator) !void { const req = try packet.getProto(protocol.SyncClientResVersionCsReq, allocator); std.debug.print("CLIENT RES VERSION: {}\n", .{req.client_res_version}); try session.send(CmdID.CmdSyncClientResVersionScRsp, protocol.SyncClientResVersionScRsp{ .retcode = 0, .client_res_version = req.client_res_version, }); } fn Highlight(comptime msg: []const u8, args: anytype) void { std.debug.print("\x1b[33m", .{}); std.debug.print(msg, args); std.debug.print("\x1b[0m\n", .{}); } fn getBattleType(id: u32, attacker_id: u32, skill_index: u32, is_challenge: bool) protocol.MonsterBattleType { if (skill_index != 1) { return protocol.MonsterBattleType.MONSTER_BATTLE_TYPE_TRIGGER_BATTLE; } if (attacker_id >= 1 and attacker_id <= 1000) { return protocol.MonsterBattleType.MONSTER_BATTLE_TYPE_TRIGGER_BATTLE; } if (attacker_id >= 100000) { const attacker_offset = attacker_id - 100000; if (isInList(attacker_offset, &Data.IgnoreBattle)) { return protocol.MonsterBattleType.MONSTER_BATTLE_TYPE_NO_BATTLE; } if (isInList(attacker_offset, &Data.SkipBattle)) { if (is_challenge) { return protocol.MonsterBattleType.MONSTER_BATTLE_TYPE_TRIGGER_BATTLE; } else { if (id > 1000000) { return protocol.MonsterBattleType.MONSTER_BATTLE_TYPE_TRIGGER_BATTLE; } else { return protocol.MonsterBattleType.MONSTER_BATTLE_TYPE_DIRECT_DIE_SKIP_BATTLE; } } } } return protocol.MonsterBattleType.MONSTER_BATTLE_TYPE_TRIGGER_BATTLE; }