#include #include // TODO: make "No Deactivation" struct BgActor { u16 def_id; // 0x00 u16 x; // 0x02 u16 y; // 0x04 u8 layer; // 0x06 u8 EXTRA_off; // 0x07 u32 actor_id; // 0x08 }; struct BgActorDef { u32 tilenum; u16 actor; u8 _06[2]; float x; float y; float z; float another_x; float another_y; u32 extra_var; }; struct dBgActorManager_c { u32 vtable; // 0x00 u8 _04[0x34]; // 0x04 BgActor *array; // 0x38 u32 count; // 0x3C u32 type; // 0x40 }; extern dBgActorManager_c *dBgActorManager; extern BgActorDef *BgActorDefs; struct BG_GM_hax { u8 _00[0x8FE64]; float _0x8FE64; float _0x8FE68; float _0x8FE6C; float _0x8FE70; }; extern BG_GM_hax *BG_GM_ptr; // Regular class is 0x3D0. // Let's add stuff to the end just to be safe. // Size is now 0x400 // 80898798 38600400 #define LINEGOD_FUNC_ACTIVATE 0 #define LINEGOD_FUNC_DEACTIVATE 1 struct LineGod { u32 id; // 0x00 u32 settings; // 0x04 u16 name; // 0x08 u8 _0A[6]; // 0x0A u8 _10[0x9C]; // 0x10 float x; // 0xAC float y; // 0xB0 float z; // 0xB4 u8 _B8[0x318]; // 0xB8 u64 eventFlag; // 0x3D0 u8 func; // 0x3D4 u8 width; // 0x3D5 u8 height; // 0x3D6 u8 lastEvState; // 0x3D7 BgActor *ac[8]; // 0x3D8 }; struct EventTable_t { u64 events; // ... }; extern EventTable_t *EventTable; fBase_c *FindActorByID(u32 id); u16 *GetPointerToTile(BG_GM_hax *self, u16 x, u16 y, u16 layer, short *blockID_p, bool unused); void LineGod_BuildList(LineGod *self); bool LineGod_AppendToList(LineGod *self, BgActor *ac); void LineGod_Update(LineGod *self); bool LineGod_Create(LineGod *self) { char eventNum = (self->settings >> 24) & 0xFF; self->eventFlag = (u64)1 << (eventNum - 1); OSReport("LineGod created @%p event %d\n", self, eventNum); //OSReport("Eventnum: %d. Event flag: %08x %08x\n", eventNum, self->eventFlag >> 32, self->eventFlag & 0xFFFFFFFF); self->func = (self->settings) & 1; self->width = (self->settings >> 4) & 15; self->height = (self->settings >> 8) & 15; self->lastEvState = 0xFF; LineGod_BuildList(self); LineGod_Update(self); return true; } bool LineGod_Execute(LineGod *self) { LineGod_Update(self); return true; } void LineGod_BuildList(LineGod *self) { for (int clearIdx = 0; clearIdx < 8; clearIdx++) { self->ac[clearIdx] = 0; } u16 x1 = self->x / 16; u16 x2 = x1 + self->width - 1; u16 y1 = (-self->y) / 16; u16 y2 = y1 + self->height - 1; OSReport("Searching ... %d,%d - %d,%d\n", x1, y1, x2, y2); x1 -= (BG_GM_ptr->_0x8FE64 / 16); x2 -= (BG_GM_ptr->_0x8FE64 / 16); y1 += (BG_GM_ptr->_0x8FE6C / 16); y2 += (BG_GM_ptr->_0x8FE6C / 16); OSReport("Manipulated offsets ... %d,%d - %d,%d\n", x1, y1, x2, y2); OSReport("My array: %p\n", &self->ac[0]); for (int i = 0; i < dBgActorManager->count; i++) { BgActor *ac = &dBgActorManager->array[i]; //OSReport("Actor %p: %d,%d", ac, ac->x, ac->y); if (ac->x >= x1 && ac->x <= x2 && ac->y >= y1 && ac->y <= y2) LineGod_AppendToList(self, ac); } } bool LineGod_AppendToList(LineGod *self, BgActor *ac) { OSReport("Adding %p to the list (pos: %d,%d)\n", ac, ac->x, ac->y); for (int search = 0; search < 8; search++) { if (self->ac[search] == 0) { self->ac[search] = ac; return true; } } return false; } void LineGod_Update(LineGod *self) { //OSReport("%08x%08x", EventTable->events >> 32, EventTable->events & 0xFFFFFFFF); u8 newEvState = 0; if (EventTable->events & self->eventFlag) newEvState = 1; if (newEvState == self->lastEvState) return; u16 x_bias = (BG_GM_ptr->_0x8FE64 / 16); u16 y_bias = -(BG_GM_ptr->_0x8FE6C / 16); OSReport("Event state changed from %d to %d\n", self->lastEvState, newEvState); u8 offState; if (self->func == LINEGOD_FUNC_ACTIVATE) offState = (newEvState == 1) ? 1 : 0; else offState = (newEvState == 1) ? 0 : 1; //OSReport("offState is %d\n", offState); for (int i = 0; i < 8; i++) { if (self->ac[i] != 0) { BgActor *ac = self->ac[i]; //OSReport("Assigning %d to %p->EXTRA_off (actor ID is %d)\n", offState, ac, ac->actor_id); ac->EXTRA_off = offState; if (offState == 1 && ac->actor_id != 0) { fBase_c *assoc_ac = FindActorByID(ac->actor_id); //OSReport("Got actor: %p\n", assoc_ac); if (assoc_ac != 0) assoc_ac->Delete(); ac->actor_id = 0; } u16 *tile = GetPointerToTile(BG_GM_ptr, (ac->x + x_bias) * 16, (ac->y + y_bias) * 16, 0, 0, 0); if (offState == 1) *tile = 0; else *tile = BgActorDefs[ac->def_id].tilenum; //OSReport("def_id: %d; def_ptr: %p\n", ac->def_id, &(BgActorDefs[ac->def_id])); //OSReport("Placed tile %d at %p [%d,%d]\n", *tile, tile, ac->x+x_bias, ac->y+y_bias); } } //OSReport("Success!\n"); self->lastEvState = newEvState; }