cipher-sr/gameserver/src/manager/battle_mgr.zig
HuLiNap 56085b79df update support v3: config.json
update support v3:   dispatch/src/dispatch.zig
	update support v3:   gameserver/src/data.zig
	update support v3:   gameserver/src/handlers.zig
	update support v3:   gameserver/src/manager/battle_mgr.zig
	update support v3:   gameserver/src/manager/lineup_mgr.zig
	update support v3:   gameserver/src/manager/scene_mgr.zig
	update support v3:   gameserver/src/services/avatar.zig
	update support v3:   gameserver/src/services/battle.zig
	update support v3:   gameserver/src/services/challenge.zig
	update support v3:   gameserver/src/services/config.zig
	update support v3:   gameserver/src/services/events.zig
	update support v3:   gameserver/src/services/lineup.zig
	update support v3:   gameserver/src/services/login.zig
	update support v3:   gameserver/src/services/mail.zig
	update support v3:   gameserver/src/services/mission.zig
	update support v3:   gameserver/src/services/profile.zig
	update support v3:   gameserver/src/services/scene.zig
	update support v3:   hotfix.json
	update support v3:   protocol/build.zig.zon
	update support v3:   resources/ActivityConfig.json
	update support v3:   resources/AvatarPlayerIcon.json
	update support v3:   resources/ChallengeMazeConfig.json
	update support v3:   resources/MainMission.json
	update support v3:   resources/StageConfig.json
	update support v3:   resources/TutorialData.json
	update support v3:   resources/TutorialGuideGroup.json
	update support v3:   resources/res.json
2025-04-21 16:57:34 +07:00

474 lines
24 KiB
Zig

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;
}