use titan::{ByteStreamReader, ByteStreamWriter, LogicLong, Payload, Result}; use crate::battle::logic_game_object_manager::LogicGameObjectManager; use crate::battle::logic_game_object_ref::LogicGameObjectRef; use crate::data::LogicDataRef; use crate::model::LogicSpellDeck; pub const BATTLE_TYPE_PVP: i32 = 0; pub const BATTLE_TYPE_NPC: i32 = 1; pub const BATTLE_TYPE_REPLAY: i32 = 3; pub const BATTLE_INT_ARRAY: usize = 8; pub const BATTLE_TRAILING_INTS: usize = 6; #[derive(Debug, Clone, PartialEq, Eq)] pub struct LogicBattle { pub location: LogicDataRef, pub npc: LogicDataRef, pub arena: LogicDataRef, pub account_ids: [LogicLong; 2], pub unknown_20: i32, pub unknown_24: i32, pub counters: [i32; BATTLE_INT_ARRAY], pub battle_type: i32, pub end_counter: i32, pub winner_index: i32, pub battle_ended_called: bool, pub battle_ended_with_timeout: bool, pub unknown_182: bool, pub player_finished_npc_level: bool, pub show_start_hud: bool, pub is_on_overtime: bool, pub objects: LogicGameObjectManager, pub decks: [Option; 2], pub leaders: [LogicGameObjectRef; 2], pub leader_towers: [Vec; 2], pub winner_score_change: i32, pub loser_score_change: i32, pub trailing: [i32; BATTLE_TRAILING_INTS], } impl Default for LogicBattle { fn default() -> Self { Self { location: LogicDataRef::None, npc: LogicDataRef::None, arena: LogicDataRef::None, account_ids: [LogicLong::default(); 2], unknown_20: 0, unknown_24: 0, counters: [0; BATTLE_INT_ARRAY], battle_type: BATTLE_TYPE_NPC, end_counter: 0, winner_index: 0, battle_ended_called: false, battle_ended_with_timeout: false, unknown_182: false, player_finished_npc_level: false, show_start_hud: true, is_on_overtime: false, objects: LogicGameObjectManager::default(), decks: [None, None], leaders: [LogicGameObjectRef::NONE; 2], leader_towers: [Vec::new(), Vec::new()], winner_score_change: 0, loser_score_change: 0, trailing: [0; BATTLE_TRAILING_INTS], } } } impl LogicBattle { pub fn is_npc_battle(&self) -> bool { self.battle_type == BATTLE_TYPE_NPC && !self.npc.is_none() } } impl Payload for LogicBattle { fn encode(&self, writer: &mut ByteStreamWriter) -> Result<()> { self.location.encode(writer)?; self.npc.encode(writer)?; self.arena.encode(writer)?; for account in &self.account_ids { writer.write_vlong(account.high, account.low); } writer.write_vint(self.unknown_20); writer.write_vint(self.unknown_24); for value in self.counters { writer.write_vint(value); } writer.write_vint(self.battle_type); writer.write_vint(self.end_counter); writer.write_vint(self.winner_index); writer.write_boolean(self.battle_ended_called); writer.write_boolean(self.battle_ended_with_timeout); writer.write_boolean(self.unknown_182); writer.write_boolean(self.player_finished_npc_level); writer.write_boolean(self.show_start_hud); writer.write_boolean(self.is_on_overtime); self.objects.encode(writer)?; for deck in &self.decks { match deck { None => writer.write_boolean(false), Some(deck) => { writer.write_boolean(true); deck.encode(writer)?; } } } for leader in &self.leaders { leader.encode(writer)?; } for towers in &self.leader_towers { writer.write_vint(towers.len() as i32); for tower in towers { tower.encode(writer)?; } } if self.battle_ended_called { writer.write_vint(self.winner_score_change); writer.write_vint(self.loser_score_change); } for value in self.trailing { writer.write_vint(value); } Ok(()) } fn decode(reader: &mut ByteStreamReader<'_>) -> Result { let location = LogicDataRef::decode(reader)?; let npc = LogicDataRef::decode(reader)?; let arena = LogicDataRef::decode(reader)?; let account_ids = { let first = reader.read_vlong()?; let second = reader.read_vlong()?; [ LogicLong::new(first.0, first.1), LogicLong::new(second.0, second.1), ] }; let unknown_20 = reader.read_vint()?; let unknown_24 = reader.read_vint()?; let mut counters = [0; BATTLE_INT_ARRAY]; for value in counters.iter_mut() { *value = reader.read_vint()?; } let battle_type = reader.read_vint()?; let end_counter = reader.read_vint()?; let winner_index = reader.read_vint()?; let battle_ended_called = reader.read_boolean()?; let battle_ended_with_timeout = reader.read_boolean()?; let unknown_182 = reader.read_boolean()?; let player_finished_npc_level = reader.read_boolean()?; let show_start_hud = reader.read_boolean()?; let is_on_overtime = reader.read_boolean()?; let objects = LogicGameObjectManager::decode(reader)?; let mut decks = [None, None]; for deck in decks.iter_mut() { if reader.read_boolean()? { *deck = Some(LogicSpellDeck::decode(reader)?); } } let leaders = [ LogicGameObjectRef::decode(reader)?, LogicGameObjectRef::decode(reader)?, ]; let mut leader_towers = [Vec::new(), Vec::new()]; for towers in leader_towers.iter_mut() { let count = reader.read_vint()?.max(0) as usize; for _ in 0..count { towers.push(LogicGameObjectRef::decode(reader)?); } } let (winner_score_change, loser_score_change) = if battle_ended_called { (reader.read_vint()?, reader.read_vint()?) } else { (0, 0) }; let mut trailing = [0; BATTLE_TRAILING_INTS]; for value in trailing.iter_mut() { *value = reader.read_vint()?; } Ok(Self { location, npc, arena, account_ids, unknown_20, unknown_24, counters, battle_type, end_counter, winner_index, battle_ended_called, battle_ended_with_timeout, unknown_182, player_finished_npc_level, show_start_hud, is_on_overtime, objects, decks, leaders, leader_towers, winner_score_change, loser_score_change, trailing, }) } }