#include "global.h" #include "manager.h" #include "flags.h" #include "room.h" #include "area.h" #include "common.h" #include "sound.h" /* * Manager B is used to create fights: * It possibly waits for an inhibitor flag to be set, then spawns a bunch of entities (based on room data). * Once all enemies created this way are dead, it sets a flag. * (There is also a part about changing the music and setting it back when the fight is done, which is song 0x33 (a * fight theme) by default but can be overridden through room data) */ void (*const ManagerB_ActionFuncs[])(Manager*); void ManagerB_Main(Manager* this) { // make a distincion if this is a controller (volumeMasterTarget = 0) or a helper (volumeMasterTarget = 1) ManagerB_ActionFuncs[this->unk_0a](this); } enum ManagerB_State { Init, WaitForFlag, WaitForDone }; void (*const ManagerB_StateFuncs[])(ManagerB*); void ManagerB_Main2(ManagerB* this) { // make a distinction based on the state of this controller ManagerB_StateFuncs[this->manager.action](this); } void ManagerB_LoadFight(Manager*); void ManagerB_Init(ManagerB* this) { // check if the fight was already completed previously (checks the flag that gets set after the fight is done) if (!CheckFlags(this->unk_3e)) { this->manager.action = WaitForFlag; // if there is no flag that needs to be set before the fight is started, start it immediately if (!this->unk_3c) { ManagerB_LoadFight(&this->manager); } SetDefaultPriority((Entity*)this, PRIO_NO_BLOCK); } else { DeleteThisEntity(); } } void ManagerB_WaitForFlag(ManagerB* this) { int tmp; if (CheckFlags(this->unk_3c)) { ManagerB_LoadFight(&this->manager); if (!this->unk_35) { tmp = gRoomVars.field_0x9 ? gRoomVars.field_0x9 : 0x33; this->unk_20 = gArea.bgm; gArea.bgm = tmp; SoundReq(tmp); } sub_080186C0(0xB0F); } } void ManagerB_WaitForDone(ManagerB* this) { // check if all helpers are done if (this->manager.unk_0e) return; // set the completion flag for the fight SetFlag(this->unk_3e); // restore music (if it was set, which apparently is only possible if there's a flag the fight waited for) if (this->unk_3c) { if (!this->unk_35) { gArea.bgm = this->unk_20; SoundReq(gArea.bgm); sub_0801855C(); } } DeleteThisEntity(); } ManagerBHelper* CreateHelper(Manager*); void ManagerBHelper_Monitor(ManagerBHelper*, Entity*, u32); extern Entity* LoadRoomEntity(EntityData*); void ManagerB_LoadFight(Manager* this) { ManagerBHelper* monitor; EntityData* prop; Entity* ent; u32 counter; this->action = 2; this->unk_0e = 0; counter = 0; // Create a helper to keep track of the created entities. monitor = CreateHelper(this); if (!monitor) DeleteThisEntity(); prop = (EntityData*)GetCurrentRoomProperty(this->unk_0b); if (prop) { while (*((u8*)prop) != 0xFF) { ent = LoadRoomEntity(prop++); if (ent && (ent->kind == 3)) { ent->field_0x6c.HALF.HI |= 0x40; ManagerBHelper_Monitor(monitor, ent, counter++); } if (counter >= 7) { counter = 0; monitor = CreateHelper(this); if (!monitor) return; } } } } /* * Create a helper and increment the counter for the number of helpers (unk_0e). * The helper will decrease said counter when it deletes itself (when none of the enemies it monitors remain). */ ManagerBHelper* CreateHelper(Manager* this) { ManagerBHelper* extra; extra = (ManagerBHelper*)GetEmptyManager(); if (extra) { extra->manager.type = 9; extra->manager.subtype = 0xB; extra->manager.unk_0a = 1; extra->manager.parent = this; this->unk_0e++; MemClear(&extra->enemies, 0x20); AppendEntityToList((Entity*)extra, 8); } return extra; } void ManagerBHelper_Monitor(ManagerBHelper* this, Entity* ent, u32 index) { this->enemies[index] = ent; this->manager.unk_0e++; } // case volumeMasterTarget is 1: The manager is a helper void ManagerBHelper_Main(Manager* this) { u8 i, anyRemaining; Entity* current; if (this->action == 0) { this->action = 1; SetDefaultPriority((Entity*)this, PRIO_NO_BLOCK); } // go through and check all monitored enemies. anyRemaining = 0; for (i = 0; i < 8; i++) { if ((current = ((ManagerBHelper*)this)->enemies[i])) { if (!current->next) { ((ManagerBHelper*)this)->enemies[i] = 0; } else { anyRemaining = 1; } } } if (!anyRemaining) { // inform the parent that we're done if (((ManagerB*)this->parent)->manager.unk_0e) { ((ManagerB*)this->parent)->manager.unk_0e--; } DeleteThisEntity(); } } /* * Replace an entity that is currently being monitored with a new one */ void ReplaceMonitoredEntity(Entity* old, Entity* new) { ManagerBHelper* current; Manager* end = (Manager*)&gEntityLists[8]; u32 i; for (current = (ManagerBHelper*)end->next; (Manager*)current != end; current = (ManagerBHelper*)current->manager.next) { if (current->manager.type != 0x9 || current->manager.subtype != 0xB) continue; for (i = 0; i < 8; i++) { if (old == current->enemies[i]) { current->enemies[i] = new; return; } } } } void (*const ManagerB_ActionFuncs[])(Manager*) = { (void (*)(Manager*))ManagerB_Main2, (void (*)(Manager*))ManagerBHelper_Main }; void (*const ManagerB_StateFuncs[])(ManagerB*) = { ManagerB_Init, ManagerB_WaitForFlag, ManagerB_WaitForDone };