const std = @import("std"); const protocol = @import("protocol"); const Session = @import("../Session.zig"); const Packet = @import("../Packet.zig"); const Config = @import("../services/config.zig"); const Data = @import("../data.zig"); const ChallengeData = @import("../services/challenge.zig"); const ArrayList = std.ArrayList; const Allocator = std.mem.Allocator; const CmdID = protocol.CmdID; // function to check the list if true fn isInList(id: u32, list: []const u32) bool { for (list) |item| { if (item == id) { return true; } } return false; } pub const BattleManager = struct { allocator: std.mem.Allocator, pub fn init(allocator: std.mem.Allocator) BattleManager { return BattleManager{ .allocator = allocator }; } pub fn createBattle(self: *BattleManager) !protocol.SceneBattleInfo { const config = try Config.loadGameConfig(self.allocator, "config.json"); var battle = protocol.SceneBattleInfo.init(self.allocator); const BattleBuff = protocol.BattleBuff; // Avatar handler for (config.avatar_config.items, 0..) |avatarConf, idx| { var avatar = protocol.BattleAvatar.init(self.allocator); avatar.id = avatarConf.id; avatar.hp = avatarConf.hp * 100; avatar.sp_bar = .{ .sp_cur = avatarConf.sp * 100, .sp_max = 10000 }; avatar.level = avatarConf.level; avatar.rank = avatarConf.rank; avatar.promotion = avatarConf.promotion; avatar.avatar_type = .AVATAR_FORMAL_TYPE; // Relics for (avatarConf.relics.items) |relic| { const r = try relicCoder(self.allocator, relic.id, relic.level, relic.main_affix_id, relic.stat1, relic.cnt1, relic.step1, relic.stat2, relic.cnt2, relic.step2, relic.stat3, relic.cnt3, relic.step3, relic.stat4, relic.cnt4, relic.step4); try avatar.relic_list.append(r); } // Lightcone (LC) const lc = protocol.BattleEquipment{ .id = avatarConf.lightcone.id, .rank = avatarConf.lightcone.rank, .level = avatarConf.lightcone.level, .promotion = avatarConf.lightcone.promotion, }; try avatar.equipment_list.append(lc); //max trace var talentLevel: u32 = 0; const skill_list: []const u32 = if (isInList(avatar.id, &Data.Rem)) &Data.skills else &Data.skills_old; for (skill_list) |elem| { talentLevel = switch (elem) { 1 => 6, 2...4 => 10, 301, 302 => if (isInList(avatar.id, &Data.Rem)) 6 else 1, else => 1, }; const talent = protocol.AvatarSkillTree{ .point_id = avatar.id * 1000 + elem, .level = talentLevel }; try avatar.skilltree_list.append(talent); } // enable technique if (avatarConf.use_technique) { var targetIndexList = ArrayList(u32).init(self.allocator); try targetIndexList.append(0); //Add new ID when modifying for new patch var buffedAvatarId = avatar.id; if (avatar.id == 8004) { buffedAvatarId = 8003; } else if (avatar.id == 8006) { buffedAvatarId = 8005; } else if (avatar.id == 8008) { buffedAvatarId = 8007; } for (Data.buffs_unlocked) |buffId| { const idPrefix = buffId / 100; if (idPrefix == buffedAvatarId) { var buff = BattleBuff{ .id = buffId, .level = 1, .owner_index = @intCast(idx), .wave_flag = 1, .target_index_list = targetIndexList, .dynamic_values = ArrayList(protocol.BattleBuff.DynamicValuesEntry).init(self.allocator), }; try buff.dynamic_values.append(.{ .key = .{ .Const = "SkillIndex" }, .value = 0 }); try battle.buff_list.append(buff); } } if (isInList(buffedAvatarId, &Data.IgnoreToughness)) { var buff_tough = BattleBuff{ .id = 1000119, //for is_ignore toughness .level = 1, .owner_index = @intCast(idx), .wave_flag = 1, .target_index_list = targetIndexList, .dynamic_values = ArrayList(protocol.BattleBuff.DynamicValuesEntry).init(self.allocator), }; try buff_tough.dynamic_values.append(.{ .key = .{ .Const = "SkillIndex" }, .value = 0 }); try battle.buff_list.append(buff_tough); } if (buffedAvatarId == 1224) { var buff_march = protocol.BattleBuff{ .id = 122401, //for hunt march 7th tech .level = 1, .owner_index = @intCast(idx), .wave_flag = 1, .target_index_list = targetIndexList, .dynamic_values = ArrayList(protocol.BattleBuff.DynamicValuesEntry).init(self.allocator), }; try buff_march.dynamic_values.appendSlice(&[_]protocol.BattleBuff.DynamicValuesEntry{ .{ .key = .{ .Const = "#ADF_1" }, .value = 3 }, .{ .key = .{ .Const = "#ADF_2" }, .value = 3 }, }); try battle.buff_list.append(buff_march); } if (buffedAvatarId == 1310) { var buff_firefly = BattleBuff{ .id = 1000112, //for firefly tech .level = 1, .owner_index = @intCast(idx), .wave_flag = 1, .target_index_list = targetIndexList, .dynamic_values = ArrayList(protocol.BattleBuff.DynamicValuesEntry).init(self.allocator), }; try buff_firefly.dynamic_values.append(.{ .key = .{ .Const = "SkillIndex" }, .value = 0 }); try battle.buff_list.append(buff_firefly); } if (buffedAvatarId == 8007) { var buff_rmc = BattleBuff{ .id = 800701, //for rmc tech .level = 1, .owner_index = @intCast(idx), .wave_flag = 1, .target_index_list = targetIndexList, .dynamic_values = ArrayList(protocol.BattleBuff.DynamicValuesEntry).init(self.allocator), }; try buff_rmc.dynamic_values.append(.{ .key = .{ .Const = "SkillIndex" }, .value = 0 }); try battle.buff_list.append(buff_rmc); } } try battle.pve_avatar_list.append(avatar); } // Basic battle info battle.battle_id = config.battle_config.battle_id; battle.stage_id = config.battle_config.stage_id; battle.logic_random_seed = @intCast(@mod(std.time.timestamp(), 0xFFFFFFFF)); battle.rounds_limit = config.battle_config.cycle_count; battle.monster_wave_length = @intCast(config.battle_config.monster_wave.items.len); battle.world_level = 6; // Monster handler for (config.battle_config.monster_wave.items) |wave| { var monster_wave = protocol.SceneMonsterWave.init(self.allocator); monster_wave.wave_param = protocol.SceneMonsterWaveParam{ .level = config.battle_config.monster_level }; for (wave.items) |mob_id| { try monster_wave.monster_list.append(.{ .monster_id = mob_id }); } try battle.monster_wave_list.append(monster_wave); } // stage blessings for (config.battle_config.blessings.items) |blessing| { var targetIndexList = ArrayList(u32).init(self.allocator); try targetIndexList.append(0); var buff = protocol.BattleBuff{ .id = blessing, .level = 1, .owner_index = 0xffffffff, .wave_flag = 0xffffffff, .target_index_list = targetIndexList, .dynamic_values = ArrayList(protocol.BattleBuff.DynamicValuesEntry).init(self.allocator), }; try buff.dynamic_values.append(.{ .key = .{ .Const = "SkillIndex" }, .value = 0 }); try battle.buff_list.append(buff); } if (isInList(1407, Data.AllAvatars)) { //support Castorice var targetIndexList = ArrayList(u32).init(self.allocator); try targetIndexList.append(0); var mazebuff_data = BattleBuff{ .id = 140703, .level = 1, .owner_index = 1, .wave_flag = @intCast(config.battle_config.monster_wave.items.len), .target_index_list = targetIndexList, .dynamic_values = ArrayList(protocol.BattleBuff.DynamicValuesEntry).init(self.allocator), }; try mazebuff_data.dynamic_values.append(.{ .key = .{ .Const = "SkillIndex" }, .value = 0 }); try battle.buff_list.append(mazebuff_data); } // PF/AS scoring const BattleTargetInfoEntry = protocol.SceneBattleInfo.BattleTargetInfoEntry; battle.battle_target_info = ArrayList(BattleTargetInfoEntry).init(self.allocator); // target hardcode var pfTargetHead = protocol.BattleTargetList{ .battle_target_list = ArrayList(protocol.BattleTarget).init(self.allocator) }; try pfTargetHead.battle_target_list.append(.{ .id = 10002, .progress = 0, .total_progress = 0 }); var pfTargetTail = protocol.BattleTargetList{ .battle_target_list = ArrayList(protocol.BattleTarget).init(self.allocator) }; try pfTargetTail.battle_target_list.append(.{ .id = 2001, .progress = 0, .total_progress = 0 }); try pfTargetTail.battle_target_list.append(.{ .id = 2002, .progress = 0, .total_progress = 0 }); var asTargetHead = protocol.BattleTargetList{ .battle_target_list = ArrayList(protocol.BattleTarget).init(self.allocator) }; try asTargetHead.battle_target_list.append(.{ .id = 90005, .progress = 0, .total_progress = 0 }); switch (battle.stage_id) { // PF 30019000...30019100, 30021000...30021100, 30301000...30319000 => { try battle.battle_target_info.append(.{ .key = 1, .value = pfTargetHead }); // fill blank target for (2..5) |i| { try battle.battle_target_info.append(.{ .key = @intCast(i) }); } try battle.battle_target_info.append(.{ .key = 5, .value = pfTargetTail }); }, // AS 420100...420300 => { try battle.battle_target_info.append(.{ .key = 1, .value = asTargetHead }); }, else => {}, } return battle; } }; pub const ChallegeStageManager = struct { allocator: std.mem.Allocator, pub fn init(allocator: std.mem.Allocator) ChallegeStageManager { return ChallegeStageManager{ .allocator = allocator }; } pub fn createChallegeStage( self: *ChallegeStageManager, ) !protocol.SceneBattleInfo { const config = try Config.loadGameConfig(self.allocator, "config.json"); const stage = try Config.loadStageConfig(self.allocator, "resources/StageConfig.json"); var battle = protocol.SceneBattleInfo.init(self.allocator); const BattleBuff = protocol.BattleBuff; for (stage.stage_config.items) |stageConf| { if (stageConf.stage_id == ChallengeData.challenge_stageID) { for (config.avatar_config.items, 0..) |avatarConf, idx| { var avatar = protocol.BattleAvatar.init(self.allocator); avatar.id = avatarConf.id; avatar.hp = avatarConf.hp * 100; avatar.sp_bar = .{ .sp_cur = avatarConf.sp * 100, .sp_max = 10000 }; avatar.level = avatarConf.level; avatar.rank = avatarConf.rank; avatar.promotion = avatarConf.promotion; avatar.avatar_type = .AVATAR_FORMAL_TYPE; for (avatarConf.relics.items) |relic| { const r = try relicCoder(self.allocator, relic.id, relic.level, relic.main_affix_id, relic.stat1, relic.cnt1, relic.step1, relic.stat2, relic.cnt2, relic.step2, relic.stat3, relic.cnt3, relic.step3, relic.stat4, relic.cnt4, relic.step4); try avatar.relic_list.append(r); } const lc = protocol.BattleEquipment{ .id = avatarConf.lightcone.id, .rank = avatarConf.lightcone.rank, .level = avatarConf.lightcone.level, .promotion = avatarConf.lightcone.promotion, }; try avatar.equipment_list.append(lc); var talentLevel: u32 = 0; const skill_list: []const u32 = if (isInList(avatar.id, &Data.Rem)) &Data.skills else &Data.skills_old; for (skill_list) |elem| { talentLevel = switch (elem) { 1 => 6, 2...4 => 10, 301, 302 => if (isInList(avatar.id, &Data.Rem)) 6 else 1, else => 1, }; const talent = protocol.AvatarSkillTree{ .point_id = avatar.id * 1000 + elem, .level = talentLevel }; try avatar.skilltree_list.append(talent); } if (avatarConf.use_technique) { var targetIndexList = ArrayList(u32).init(self.allocator); try targetIndexList.append(0); var buffedAvatarId = avatar.id; if (avatar.id == 8004) { buffedAvatarId = 8003; } else if (avatar.id == 8006) { buffedAvatarId = 8005; } else if (avatar.id == 8008) { buffedAvatarId = 8007; } for (Data.buffs_unlocked) |buffId| { const idPrefix = buffId / 100; if (idPrefix == buffedAvatarId) { var buff = BattleBuff{ .id = buffId, .level = 1, .owner_index = @intCast(idx), .wave_flag = 1, .target_index_list = targetIndexList, .dynamic_values = ArrayList(protocol.BattleBuff.DynamicValuesEntry).init(self.allocator), }; try buff.dynamic_values.append(.{ .key = .{ .Const = "SkillIndex" }, .value = 0 }); try battle.buff_list.append(buff); } } if (isInList(buffedAvatarId, &Data.IgnoreToughness)) { var buff_tough = BattleBuff{ .id = 1000119, //for is_ignore toughness .level = 1, .owner_index = @intCast(idx), .wave_flag = 1, .target_index_list = targetIndexList, .dynamic_values = ArrayList(protocol.BattleBuff.DynamicValuesEntry).init(self.allocator), }; try buff_tough.dynamic_values.append(.{ .key = .{ .Const = "SkillIndex" }, .value = 0 }); try battle.buff_list.append(buff_tough); } if (buffedAvatarId == 1224) { var buff_march = protocol.BattleBuff{ .id = 122401, //for hunt march 7th tech .level = 1, .owner_index = @intCast(idx), .wave_flag = 1, .target_index_list = targetIndexList, .dynamic_values = ArrayList(protocol.BattleBuff.DynamicValuesEntry).init(self.allocator), }; try buff_march.dynamic_values.appendSlice(&[_]protocol.BattleBuff.DynamicValuesEntry{ .{ .key = .{ .Const = "#ADF_1" }, .value = 3 }, .{ .key = .{ .Const = "#ADF_2" }, .value = 3 }, }); try battle.buff_list.append(buff_march); } if (buffedAvatarId == 1310) { var buff_firefly = BattleBuff{ .id = 1000112, //for firefly tech .level = 1, .owner_index = @intCast(idx), .wave_flag = 1, .target_index_list = targetIndexList, .dynamic_values = ArrayList(protocol.BattleBuff.DynamicValuesEntry).init(self.allocator), }; try buff_firefly.dynamic_values.append(.{ .key = .{ .Const = "SkillIndex" }, .value = 0 }); try battle.buff_list.append(buff_firefly); } if (buffedAvatarId == 8007) { var buff_rmc = BattleBuff{ .id = 800701, //for rmc tech .level = 1, .owner_index = @intCast(idx), .wave_flag = 1, .target_index_list = targetIndexList, .dynamic_values = ArrayList(protocol.BattleBuff.DynamicValuesEntry).init(self.allocator), }; try buff_rmc.dynamic_values.append(.{ .key = .{ .Const = "SkillIndex" }, .value = 0 }); try battle.buff_list.append(buff_rmc); } } try battle.pve_avatar_list.append(avatar); } battle.battle_id = 1; battle.stage_id = stageConf.stage_id; battle.logic_random_seed = @intCast(@mod(std.time.timestamp(), 0xFFFFFFFF)); battle.rounds_limit = if (ChallengeData.challenge_mode != 1) 30 else 4; battle.monster_wave_length = @intCast(stageConf.monster_list.items.len); battle.world_level = 6; // Monster handler for (stageConf.monster_list.items) |wave| { var monster_wave = protocol.SceneMonsterWave.init(self.allocator); monster_wave.wave_param = protocol.SceneMonsterWaveParam{ .level = stageConf.level }; for (wave.items) |mob_id| { try monster_wave.monster_list.append(.{ .monster_id = mob_id }); } try battle.monster_wave_list.append(monster_wave); } // stage blessings for (ChallengeData.challenge_blessing) |blessing| { var targetIndexList = ArrayList(u32).init(self.allocator); try targetIndexList.append(0); var buff = protocol.BattleBuff{ .id = blessing, .level = 1, .owner_index = 0xffffffff, .wave_flag = 0xffffffff, .target_index_list = targetIndexList, .dynamic_values = ArrayList(protocol.BattleBuff.DynamicValuesEntry).init(self.allocator), }; try buff.dynamic_values.append(.{ .key = .{ .Const = "SkillIndex" }, .value = 0 }); try battle.buff_list.append(buff); } if (isInList(1407, Data.AllAvatars)) { //support Castorice var targetIndexList = ArrayList(u32).init(self.allocator); try targetIndexList.append(0); var mazebuff_data = BattleBuff{ .id = 140703, .level = 1, .owner_index = 1, .wave_flag = @intCast(stageConf.monster_list.items.len), .target_index_list = targetIndexList, .dynamic_values = ArrayList(protocol.BattleBuff.DynamicValuesEntry).init(self.allocator), }; try mazebuff_data.dynamic_values.append(.{ .key = .{ .Const = "SkillIndex" }, .value = 0 }); try battle.buff_list.append(mazebuff_data); } // PF/AS scoring const BattleTargetInfoEntry = protocol.SceneBattleInfo.BattleTargetInfoEntry; battle.battle_target_info = ArrayList(BattleTargetInfoEntry).init(self.allocator); // target hardcode var pfTargetHead = protocol.BattleTargetList{ .battle_target_list = ArrayList(protocol.BattleTarget).init(self.allocator) }; try pfTargetHead.battle_target_list.append(.{ .id = 10002, .progress = 0, .total_progress = 0 }); var pfTargetTail = protocol.BattleTargetList{ .battle_target_list = ArrayList(protocol.BattleTarget).init(self.allocator) }; try pfTargetTail.battle_target_list.append(.{ .id = 2001, .progress = 0, .total_progress = 0 }); try pfTargetTail.battle_target_list.append(.{ .id = 2002, .progress = 0, .total_progress = 0 }); var asTargetHead = protocol.BattleTargetList{ .battle_target_list = ArrayList(protocol.BattleTarget).init(self.allocator) }; try asTargetHead.battle_target_list.append(.{ .id = 90005, .progress = 0, .total_progress = 0 }); switch (battle.stage_id) { // PF 30019000...30019100, 30021000...30021100, 30301000...30319000 => { try battle.battle_target_info.append(.{ .key = 1, .value = pfTargetHead }); // fill blank target for (2..5) |i| { try battle.battle_target_info.append(.{ .key = @intCast(i) }); } try battle.battle_target_info.append(.{ .key = 5, .value = pfTargetTail }); }, // AS 420100...420300 => { try battle.battle_target_info.append(.{ .key = 1, .value = asTargetHead }); }, else => {}, } } } return battle; } }; pub fn relicCoder(allocator: Allocator, id: u32, level: u32, main_affix_id: u32, stat1: u32, cnt1: u32, step1: u32, stat2: u32, cnt2: u32, step2: u32, stat3: u32, cnt3: u32, step3: u32, stat4: u32, cnt4: u32, step4: u32) !protocol.BattleRelic { var relic = protocol.BattleRelic{ .id = id, .main_affix_id = main_affix_id, .level = level, .sub_affix_list = ArrayList(protocol.RelicAffix).init(allocator), }; try relic.sub_affix_list.append(protocol.RelicAffix{ .affix_id = stat1, .cnt = cnt1, .step = step1 }); try relic.sub_affix_list.append(protocol.RelicAffix{ .affix_id = stat2, .cnt = cnt2, .step = step2 }); try relic.sub_affix_list.append(protocol.RelicAffix{ .affix_id = stat3, .cnt = cnt3, .step = step3 }); try relic.sub_affix_list.append(protocol.RelicAffix{ .affix_id = stat4, .cnt = cnt4, .step = step4 }); return relic; }