fix the LogicGameObject field mapping

the base object writes owner index, component mask, position and z, in
that order. we had the first field unnamed and were writing the owner
into the z slot, so every object belonged to player 0, and the mask slot
carried a zero.

the mask matters: getHitpointComponent tests bit 2 of it before touching
components[2], so a zero mask made every tower report no hitpoints,
LogicCharacter::isAlive fell through to the z field, shouldDestruct went
true and the towers were destroyed on the first tick - which then hit
"cant find summoner tower" in LogicBattle::removeGameObjectReferences.

entries are built through LogicGameObjectEntry::new now so the mask is
derived from the component array and cannot drift from it.

also rename the first character flag after what sets it: kamikaze
death and morph both raise it right before the object is removed.
This commit is contained in:
WiseDev 2026-08-23 11:17:10 +03:00
parent bc04651a73
commit 6c5295bc07
3 changed files with 36 additions and 10 deletions

View file

@ -110,11 +110,11 @@ impl BattleBuilder {
} else {
LogicObjectBody::Character(Box::new(character))
};
LogicGameObjectEntry {
LogicGameObjectEntry::new(
data,
global_id: LogicGameObjectRef::of(CHARACTER_OBJECT_TYPE + 1, instance),
LogicGameObjectRef::of(CHARACTER_OBJECT_TYPE + 1, instance),
body,
components: [
[
Some(LogicComponent::Combat(LogicCombatComponent::default())),
None,
Some(LogicComponent::Hitpoint(LogicHitpointComponent::healthy(
@ -124,7 +124,7 @@ impl BattleBuilder {
self.buff_type_count,
))),
],
}
)
}
pub fn build(
&self,

View file

@ -6,7 +6,7 @@ pub const DEFAULT_SIZE: i32 = 100;
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct LogicCharacter {
pub level_index: i32,
pub flag_160: bool,
pub is_destroyed: bool,
pub is_leader: bool,
pub base: LogicGameObject,
pub direction: LogicVector2,
@ -29,7 +29,7 @@ impl Default for LogicCharacter {
fn default() -> Self {
Self {
level_index: 0,
flag_160: false,
is_destroyed: false,
is_leader: false,
base: LogicGameObject::default(),
direction: LogicVector2::new(0, DIRECTION_BOTTOM),
@ -53,7 +53,7 @@ impl Default for LogicCharacter {
impl LogicCharacter {
pub fn encode(&self, writer: &mut ByteStreamWriter) -> Result<()> {
writer.write_vint(self.level_index);
writer.write_boolean(self.flag_160);
writer.write_boolean(self.is_destroyed);
writer.write_boolean(self.is_leader);
self.base.encode_base(writer)?;
writer.write_vint(self.direction.x);

View file

@ -19,12 +19,12 @@ impl LogicVector2 {
#[derive(Debug, Default, Clone, PartialEq, Eq, Payload)]
pub struct LogicGameObject {
#[codec(vint)]
pub field_28: i32,
pub owner_index: i32,
#[codec(vint)]
pub field_56: i32,
pub component_mask: i32,
pub position: LogicVector2,
#[codec(vint)]
pub owner_index: i32,
pub z: i32,
}
impl LogicGameObject {
pub fn encode_base(&self, writer: &mut titan::ByteStreamWriter) -> titan::Result<()> {
@ -37,6 +37,12 @@ pub enum LogicObjectBody {
Summoner(Box<crate::battle::logic_character::LogicSummoner>),
}
impl LogicObjectBody {
pub fn base_mut(&mut self) -> &mut LogicGameObject {
match self {
LogicObjectBody::Character(character) => &mut character.base,
LogicObjectBody::Summoner(summoner) => &mut summoner.character.base,
}
}
pub fn encode(&self, writer: &mut titan::ByteStreamWriter) -> titan::Result<()> {
match self {
LogicObjectBody::Character(character) => character.encode(writer),
@ -52,6 +58,26 @@ pub struct LogicGameObjectEntry {
pub components: [Option<crate::battle::logic_component::LogicComponent>; COMPONENT_PASSES],
}
impl LogicGameObjectEntry {
pub fn new(
data: LogicDataRef,
global_id: LogicGameObjectRef,
mut body: LogicObjectBody,
components: [Option<crate::battle::logic_component::LogicComponent>; COMPONENT_PASSES],
) -> Self {
let mut component_mask = 0;
for (index, component) in components.iter().enumerate() {
if component.is_some() {
component_mask |= 1 << index;
}
}
body.base_mut().component_mask = component_mask;
Self {
data,
global_id,
body,
components,
}
}
pub fn object_type(&self) -> i32 {
self.global_id.0.map(|id| id.class_id - 1).unwrap_or(-1)
}