npc missions used to get a ServerErrorMessage back. now StartMission builds a LogicGameMode snapshot off the arena tilemap and answers 21903. towers come from assets/locations/*.csv the way initDefaultSector does it: tile coordinates times 500, leader index decided by which half of the map the tower sits in. the two king towers must be there, the client dereferences them without a null check. they live in buildings.csv, not characters.csv. LogicCharacter puts the base object fields fourth, not first. the buff component writes a fixed array sized by the character_buffs row count even with no buffs. training_arena parses to 2 kings, 4 princess towers, 36x64 subtiles. snapshot is 602 bytes over 6 objects. the real client has not seen it yet.
58 lines
1.8 KiB
Rust
58 lines
1.8 KiB
Rust
use titan::Payload;
|
|
use crate::battle::logic_game_object_ref::LogicGameObjectRef;
|
|
use crate::data::LogicDataRef;
|
|
pub const COMPONENT_PASSES: usize = 4;
|
|
pub const OBJECT_TYPE_COUNT: usize = 6;
|
|
pub const CHARACTER_OBJECT_TYPE: i32 = 5;
|
|
#[derive(Debug, Default, Clone, Copy, PartialEq, Eq, Payload)]
|
|
pub struct LogicVector2 {
|
|
#[codec(vint)]
|
|
pub x: i32,
|
|
#[codec(vint)]
|
|
pub y: i32,
|
|
}
|
|
impl LogicVector2 {
|
|
pub fn new(x: i32, y: i32) -> Self {
|
|
Self { x, y }
|
|
}
|
|
}
|
|
#[derive(Debug, Default, Clone, PartialEq, Eq, Payload)]
|
|
pub struct LogicGameObject {
|
|
#[codec(vint)]
|
|
pub field_28: i32,
|
|
#[codec(vint)]
|
|
pub field_56: i32,
|
|
pub position: LogicVector2,
|
|
#[codec(vint)]
|
|
pub owner_index: i32,
|
|
}
|
|
impl LogicGameObject {
|
|
pub fn encode_base(&self, writer: &mut titan::ByteStreamWriter) -> titan::Result<()> {
|
|
<Self as Payload>::encode(self, writer)
|
|
}
|
|
}
|
|
#[derive(Debug, Clone, PartialEq, Eq)]
|
|
pub enum LogicObjectBody {
|
|
Character(Box<crate::battle::logic_character::LogicCharacter>),
|
|
Summoner(Box<crate::battle::logic_character::LogicSummoner>),
|
|
}
|
|
impl LogicObjectBody {
|
|
pub fn encode(&self, writer: &mut titan::ByteStreamWriter) -> titan::Result<()> {
|
|
match self {
|
|
LogicObjectBody::Character(character) => character.encode(writer),
|
|
LogicObjectBody::Summoner(summoner) => summoner.encode(writer),
|
|
}
|
|
}
|
|
}
|
|
#[derive(Debug, Clone, PartialEq, Eq)]
|
|
pub struct LogicGameObjectEntry {
|
|
pub data: LogicDataRef,
|
|
pub global_id: LogicGameObjectRef,
|
|
pub body: LogicObjectBody,
|
|
pub components: [Option<crate::battle::logic_component::LogicComponent>; COMPONENT_PASSES],
|
|
}
|
|
impl LogicGameObjectEntry {
|
|
pub fn object_type(&self) -> i32 {
|
|
self.global_id.0.map(|id| id.class_id - 1).unwrap_or(-1)
|
|
}
|
|
}
|