#include "d/d_stage_parse.h" #include "common.h" #include "d/a/obj/d_a_obj_base.h" #include "d/d_base.h" #include "d/d_bzs_types.h" #include "d/d_room.h" #include "d/d_sc_game.h" #include "d/d_stage.h" #include "d/d_stage_mgr.h" #include "d/flag/flag_managers.h" #include "d/flag/storyflag_manager.h" #include "f/f_base.h" #include "f/f_profile_name.h" #include "m/m_angle.h" #include "m/m_vec.h" #include "sized_string.h" #include "toBeSorted/actor_info.h" #include "toBeSorted/file_manager.h" struct BzsHeader { /* 0x00 */ u32 mName; /* 0x04 */ u16 mSectionCount; /* 0x08 */ u32 mOffset; }; struct BzsSectionHead { /* 0x00 */ u32 mTag; /* 0x04 */ u16 mCount; /* 0x08 */ u32 mOffset; }; typedef void (*BzsParseFunc)(int roomid, const BzsSectionHead *section); struct BzsTagToParseFunc { /* 0x00 */ u32 mTag; /* 0x04 */ BzsParseFunc mParseFunc; }; #define OFS_TO_PTR(ty, section) \ (reinterpret_cast(reinterpret_cast(section) + section->mOffset)) static void findAndRunStageTagParseFunc( int roomid, const BzsSectionHead *head, const BzsTagToParseFunc *handlerTable, s32 tableSize ); static void handleBzsPcam(int roomid, const BzsSectionHead *section) { dStageMgr_c::GetInstance()->setPcam(OFS_TO_PTR(PCAM, section), section->mCount); } static void handleBzsLyse(int roomid, const BzsSectionHead *section) { dStageMgr_c::GetInstance()->setLyse(OFS_TO_PTR(LYSE, section), section->mCount); dStageMgr_c::GetInstance()->overrideLayer0WithLyse(); } static void handleBzsStif(int roomid, const BzsSectionHead *section) { // section->mCount == 1 dStageMgr_c::GetInstance()->setStif(OFS_TO_PTR(STIF, section)); s16 flagIndex = dStageMgr_c::GetInstance()->getFlagIndex(); FileManager::GetInstance()->setSceneFlagIndex(flagIndex); updateFlagForFlagIndex(flagIndex); } static void handleBzsRmpl(int roomid, const BzsSectionHead *section) { dStageMgr_c::GetInstance()->setRmpl(OFS_TO_PTR(RMPL, section), section->mCount); } static void handleBzsFile(int roomid, const BzsSectionHead *section) { const bzsFILE *file = OFS_TO_PTR(bzsFILE, section); dRoom_c *room = dStage_c::GetInstance()->getRoom(roomid); room->setFile(file, section->mCount); } static void handleBzsLylt(int roomid, const BzsSectionHead *section) { const LYLT *lylt = OFS_TO_PTR(LYLT, section); for (s32 i = 0; i < section->mCount; i++) { if (lylt->layer == dScGame_c::currentSpawnInfo.layer && lylt->demoHigh >= 0) { SizedString<16> demoName; demoName.sprintf("Demo%02d_%02d", lylt->demoHigh, lylt->demoLow); dStageMgr_c::GetInstance()->setDemoName(demoName); dStageMgr_c::GetInstance()->addLayerArcn(dStageMgr_c::GetInstance()->getDemoName()); } lylt++; } } static void handleBzsScen(int roomid, const BzsSectionHead *section) { const SCEN *scen = OFS_TO_PTR(SCEN, section); dRoom_c *room = dStage_c::GetInstance()->getRoom(roomid); room->setScen(scen, section->mCount); } static void handleBzsCam(int roomid, const BzsSectionHead *section) { const CAM *cam = OFS_TO_PTR(CAM, section); dRoom_c *room = dStage_c::GetInstance()->getRoom(roomid); room->setCam(cam, section->mCount); } static void handleBzsEvnt(int roomid, const BzsSectionHead *section) { const EVNT *evnt = OFS_TO_PTR(EVNT, section); dRoom_c *room = dStage_c::GetInstance()->getRoom(roomid); room->setEvnt(evnt, section->mCount); } static void handleBzsPath(int roomid, const BzsSectionHead *section) { const PATH *path = OFS_TO_PTR(PATH, section); dRoom_c *room = dStage_c::GetInstance()->getRoom(roomid); room->setPath(path, section->mCount); } static void handleBzsPnt(int roomid, const BzsSectionHead *section) { const PNT *pnt = OFS_TO_PTR(PNT, section); dRoom_c *room = dStage_c::GetInstance()->getRoom(roomid); room->setPnt(pnt, section->mCount); } static void handleBzsBpnt(int roomid, const BzsSectionHead *section) { const BPNT *bpnt = OFS_TO_PTR(BPNT, section); dRoom_c *room = dStage_c::GetInstance()->getRoom(roomid); room->setBpnt(bpnt, section->mCount); } static void handleBzsSpth(int roomid, const BzsSectionHead *section) { const SPTH *spth = OFS_TO_PTR(SPTH, section); dRoom_c *room = dStage_c::GetInstance()->getRoom(roomid); room->setSpth(spth, section->mCount); } static void handleBzsSpnt(int roomid, const BzsSectionHead *section) { const SPNT *spnt = OFS_TO_PTR(SPNT, section); dRoom_c *room = dStage_c::GetInstance()->getRoom(roomid); room->setSpnt(spnt, section->mCount); } static void handleBzsSbpt(int roomid, const BzsSectionHead *section) { const SBPT *sbpt = OFS_TO_PTR(SBPT, section); dRoom_c *room = dStage_c::GetInstance()->getRoom(roomid); room->setSbpt(sbpt, section->mCount); } static void handleBzsArea(int roomid, const BzsSectionHead *section) { const AREA *area = OFS_TO_PTR(AREA, section); dRoom_c *room = dStage_c::GetInstance()->getRoom(roomid); room->setArea(area, section->mCount); } extern "C" bool fn_8005C5D0(u32); extern "C" void spawnLightObject(); extern "C" void spawnWeatherTag(); static void handleBzsPly(int roomid, const BzsSectionHead *section) { const PLY *ply = OFS_TO_PTR(PLY, section); dRoom_c *room = dStage_c::GetInstance()->getRoom(roomid); room->setPly(ply, section->mCount); if (roomid == dScGame_c::currentSpawnInfo.room) { dScGame_c *sc = dScGame_c::GetInstance(); const mVec3_c *linkPos; const mAng3_c *linkAngle; mAng3_c ang(0, 0, 0); mVec3_c pos; u32 linkActorParams = 0x7FFFFFF; bool param = 0; bool preventSetRespawnInfo = false; u8 reloaderType = dScGame_c::getReloaderType(); if (reloaderType != 0) { FileManager *fileMgr = FileManager::GetInstance(); if (reloaderType == 2) { pos = *FileManager::GetInstance()->getPosT2(); ang.y = fileMgr->getAngleT2(); linkPos = &pos; linkAngle = ∠ linkActorParams = 0x7FFFF1B; } else if (reloaderType == 3) { pos = *FileManager::GetInstance()->getPosT3(); ang.y = fileMgr->getAngleT3(); linkPos = &pos; linkAngle = ∠ if (!StoryflagManager::sInstance->getCounterOrFlag(STORYFLAG_752) && !StoryflagManager::sInstance->getCounterOrFlag(STORYFLAG_RESPAWN_AT_STATUE)) { const PLY *entrance = room->getEntranceById(dScGame_c::currentSpawnInfo.entrance); if (fn_8005C5D0(entrance->linkParams) == true) { linkActorParams = entrance->linkParams; } } } else { if (FileManager::GetInstance()->getEntranceLoadFlagT1() == 0 && dScGame_c::getReloaderType() != 4) { pos = *fileMgr->getPosT1(); ang.y = fileMgr->getAngleT1(); if (fileMgr->fn_8000CC00() == 2) { const PLY *entrance = room->getEntranceById(dScGame_c::currentSpawnInfo.entrance); linkActorParams = entrance->linkParams; } linkPos = &pos; linkAngle = ∠ } else { const PLY *entrance = room->getEntranceById(dScGame_c::currentSpawnInfo.entrance); linkActorParams = entrance->linkParams; linkPos = &entrance->position; linkAngle = &entrance->angle; } } dScGame_c::setReloaderType(0); if (sc->getType0CsFlag() != 0) { sc->setType0CsFlag(0); } } else { if (dScGame_c::GetInstance()->getType0CsFlag() != 0) { preventSetRespawnInfo = true; const LinkReloadInfo &info = dScGame_c::GetInstance()->getLinkReloadInfo(); ang.y = info.mRotY; linkPos = &info.mPosition; linkAngle = ∠ linkActorParams = info.mLinkParams; sc->setType0CsFlag(0); } else if (dScGame_c::GetInstance()->getType0PosFlag() != 0) { const SpawnInfoExt &info = dScGame_c::GetInstance()->getSpawnInfo(); pos = info.mType0Pos; linkPos = &pos; ang.y = info.mType0RotY; linkAngle = ∠ sc->setType0PosFlag(0); } else { const PLY *entrance = room->getEntranceById(dScGame_c::currentSpawnInfo.entrance); linkActorParams = entrance->linkParams; linkPos = &entrance->position; linkAngle = &entrance->angle; param = true; } } // TODO constify args dAcObjBase_c::create( fProfile::PLAYER, -1, linkActorParams, (mVec3_c *)linkPos, (mAng3_c *)linkAngle, nullptr, -1 ); if (!preventSetRespawnInfo) { dScGame_c::GetInstance()->setRespawnInfo(*linkPos, *linkAngle, param); } dStage_c::GetInstance()->handleRoomChange(roomid); dBase_c::createBase(fProfile::CAMERA, dStage_c::GetInstance(), 0, fBase_c::OTHER); spawnLightObject(); spawnWeatherTag(); } } static void handleBzsObjn(int roomid, const BzsSectionHead *section) { const OBJN *objn = OFS_TO_PTR(OBJN, section); const char *buf = reinterpret_cast(objn); for (s32 i = 0; i < section->mCount; i++) { dStageMgr_c::GetInstance()->addObjId(getProfileId2ForName(buf + objn->offset)); objn++; } } static void handleBzsArcn(int roomid, const BzsSectionHead *section) { const ARCN *arcn = OFS_TO_PTR(ARCN, section); const char *buf = reinterpret_cast(arcn); for (s32 i = 0; i < section->mCount; i++) { dStageMgr_c::GetInstance()->addStageArcn(buf + arcn->offset); arcn++; } } static void handleBzsLayerObjn(int roomid, const BzsSectionHead *section) { const OBJN *objn = OFS_TO_PTR(OBJN, section); const char *buf = reinterpret_cast(objn); for (s32 i = 0; i < section->mCount; i++) { u16 id = getProfileId2ForName(buf + objn->offset); dStageMgr_c::GetInstance()->addActorId(id); objn++; } } static void handleBzsLayerArcn(int roomid, const BzsSectionHead *section) { const ARCN *arcn = OFS_TO_PTR(ARCN, section); const char *buf = reinterpret_cast(arcn); for (s32 i = 0; i < section->mCount; i++) { dStageMgr_c::GetInstance()->addLayerArcn(buf + arcn->offset); arcn++; } } static u16 getEnemyDefeatFlagFromId(s32 roomid, u16 id) { u16 val = id & 0x3FF; if (val >= 0x400) { // Interesting condition return -1; } if (roomid == -1) { return val + (0x3F << 10); } return val + (roomid << 10); } static s8 getViewClipIndexFromId(u16 id) { s8 val = (id >> 10) & 0x3F; if (val == 0x3F) { return -1; } return val; } static void handleBzsObj(int roomid, const BzsSectionHead *section) { dStage_c *stage = dStage_c::GetInstance(); const OBJ *obj = OFS_TO_PTR(OBJ, section); for (s32 i = 0; i < section->mCount; i++) { u16 flag = getEnemyDefeatFlagFromId(roomid, obj->id); s8 viewClipIdx = getViewClipIndexFromId(obj->id); if (stage->checkEnemyDefeatFlag(flag)) { dAcObjBase_c::create( obj->name, roomid, obj->params1, &obj->position, &obj->angle, nullptr, obj->params2, flag, viewClipIdx ); } obj++; } } static void handleBzsSobj(int roomid, const BzsSectionHead *section) { dStage_c *stage = dStage_c::GetInstance(); const SOBJ *obj = OFS_TO_PTR(SOBJ, section); for (s32 i = 0; i < section->mCount; i++) { u16 flag = getEnemyDefeatFlagFromId(roomid, obj->id); s8 viewClipIdx = getViewClipIndexFromId(obj->id); if (stage->checkEnemyDefeatFlag(flag)) { dAcObjBase_c::create( obj->name, roomid, obj->params1, &obj->position, &obj->angle, (mVec3_c *)&obj->scale, obj->params2, flag, viewClipIdx ); } obj++; } } static void handleBzsStas(int roomid, const BzsSectionHead *section) { dStage_c *stage = dStage_c::GetInstance(); const SOBJ *obj = OFS_TO_PTR(SOBJ, section); for (s32 i = 0; i < section->mCount; i++) { u16 flag = getEnemyDefeatFlagFromId(roomid, obj->id); s8 viewClipIdx = getViewClipIndexFromId(obj->id); if (stage->checkEnemyDefeatFlag(flag)) { dAcObjBase_c::createActorUnkGroup3( obj->name, roomid, obj->params1, &obj->position, &obj->angle, &obj->scale, obj->params2, flag, viewClipIdx ); } obj++; } } static void parseLayerBzs(int roomid, u32 layer, const LAY *head, const BzsTagToParseFunc *handlerTable, s32 tableSize) { const LAY *lay = head + layer; const BzsSectionHead *newHead = OFS_TO_PTR(BzsSectionHead, lay); for (s32 i = 0; i < lay->mCount; i++) { findAndRunStageTagParseFunc(roomid, newHead++, handlerTable, tableSize); } } static const BzsTagToParseFunc layerHandlers[] = { {'OBJN', handleBzsLayerObjn}, {'ARCN', handleBzsLayerArcn}, }; static void handleBzsLay(int roomid, const BzsSectionHead *section) { const LAY *lay = OFS_TO_PTR(LAY, section); parseLayerBzs(roomid, 0, lay, layerHandlers, ARRAY_LENGTH(layerHandlers)); if (dScGame_c::currentSpawnInfo.layer != 0) { parseLayerBzs(roomid, dScGame_c::currentSpawnInfo.layer, lay, layerHandlers, ARRAY_LENGTH(layerHandlers)); } } static const BzsTagToParseFunc layerHandlers2[] = { {'OBJ ', handleBzsObj}, {'SOBJ', handleBzsSobj}, {'STAG', handleBzsStas}, }; static void handleBzsLay2(int roomid, const BzsSectionHead *section) { const LAY *lay = OFS_TO_PTR(LAY, section); parseLayerBzs(roomid, 0, lay, layerHandlers2, ARRAY_LENGTH(layerHandlers2)); if (dScGame_c::currentSpawnInfo.layer != 0) { parseLayerBzs(roomid, dScGame_c::currentSpawnInfo.layer, lay, layerHandlers2, ARRAY_LENGTH(layerHandlers2)); } } static const BzsTagToParseFunc layerHandlers3[] = { {'OBJS', handleBzsObj}, {'SOBS', handleBzsSobj}, {'STAS', handleBzsStas}, {'SNDT', handleBzsStas}, {'TBOX', handleBzsObj}, {'DOOR', handleBzsObj}, }; static void handleBzsLay3(int roomid, const BzsSectionHead *section) { const LAY *lay = OFS_TO_PTR(LAY, section); parseLayerBzs(roomid, 0, lay, layerHandlers3, ARRAY_LENGTH(layerHandlers3)); if (dScGame_c::currentSpawnInfo.layer != 0) { parseLayerBzs(roomid, dScGame_c::currentSpawnInfo.layer, lay, layerHandlers3, ARRAY_LENGTH(layerHandlers3)); } } static const BzsTagToParseFunc defaultHandlers[] = { {'PCAM', handleBzsPcam}, {'LYSE', handleBzsLyse}, {'STIF', handleBzsStif}, {'RMPL', handleBzsRmpl}, {'SCEN', handleBzsScen}, {'CAM ', handleBzsCam}, {'EVNT', handleBzsEvnt}, {'PATH', handleBzsPath}, {'PNT ', handleBzsPnt}, {'BPNT', handleBzsBpnt}, {'SPTH', handleBzsSpth}, {'SPNT', handleBzsSpnt}, {'SBPT', handleBzsSbpt}, {'AREA', handleBzsArea}, }; static void findAndRunStageTagParseFunc( int roomid, const BzsSectionHead *head, const BzsTagToParseFunc *handlerTable, s32 tableSize ) { if (handlerTable == nullptr) { tableSize = ARRAY_LENGTH(defaultHandlers); handlerTable = defaultHandlers; } while (tableSize > 0) { if (head->mTag == handlerTable->mTag) { handlerTable->mParseFunc(roomid, head); return; } handlerTable++; tableSize--; } } static const BzsTagToParseFunc roomStageHandlers[] = { {'OBJN', handleBzsObjn}, {'ARCN', handleBzsArcn}, }; void parseRoomStageBzs(int roomid, const void *bzs) { const BzsHeader *header = static_cast(bzs); const BzsSectionHead *head = OFS_TO_PTR(BzsSectionHead, header); for (s32 i = 0; i < header->mSectionCount; i++) { findAndRunStageTagParseFunc(roomid, head++, roomStageHandlers, ARRAY_LENGTH(roomStageHandlers)); } } static const BzsTagToParseFunc stageRoomHandlers[] = { {'LYLT', handleBzsLylt}, {'LAY ', handleBzsLay}, }; void parseBzsStageRoom(int roomid, const void *bzs) { const BzsHeader *header = static_cast(bzs); const BzsSectionHead *head = OFS_TO_PTR(BzsSectionHead, header); for (s32 i = 0; i < header->mSectionCount; i++) { findAndRunStageTagParseFunc(roomid, head++, stageRoomHandlers, ARRAY_LENGTH(stageRoomHandlers)); } } void parseStageBzs(int roomid, const void *bzs) { const BzsHeader *header = static_cast(bzs); const BzsSectionHead *head = OFS_TO_PTR(BzsSectionHead, header); for (s32 i = 0; i < header->mSectionCount; i++) { // Run "default handlers" findAndRunStageTagParseFunc(roomid, head++, nullptr, 0); } } static const BzsTagToParseFunc roomHandlers[] = { {'FILE', handleBzsFile}, {'SCEN', handleBzsScen}, {'CAM ', handleBzsCam}, {'EVNT', handleBzsEvnt}, {'PATH', handleBzsPath}, {'PNT ', handleBzsPnt}, {'BPNT', handleBzsBpnt}, {'SPTH', handleBzsSpth}, {'SPNT', handleBzsSpnt}, {'SBPT', handleBzsSbpt}, {'AREA', handleBzsArea}, {'PLY ', handleBzsPly}, }; void parseRoomBzs(int roomid, const void *bzs) { const BzsHeader *header = static_cast(bzs); const BzsSectionHead *head = OFS_TO_PTR(BzsSectionHead, header); for (s32 i = 0; i < header->mSectionCount; i++) { findAndRunStageTagParseFunc(roomid, head++, roomHandlers, ARRAY_LENGTH(roomHandlers)); } } static const BzsTagToParseFunc roomReactivateHandlers[] = { {'SOBJ', handleBzsSobj}, {'STAG', handleBzsStas}, {'LAY ', handleBzsLay2}, }; void parseRoomReactivateBzs(int roomid, const void *bzs) { const BzsHeader *header = static_cast(bzs); const BzsSectionHead *head = OFS_TO_PTR(BzsSectionHead, header); for (s32 i = 0; i < header->mSectionCount; i++) { findAndRunStageTagParseFunc(roomid, head++, roomReactivateHandlers, ARRAY_LENGTH(roomReactivateHandlers)); } } static const BzsTagToParseFunc roomActivateHandlers[] = { {'LAY ', handleBzsLay3}, }; void parseRoomActivateBzs(int roomid, const void *bzs) { const BzsHeader *header = static_cast(bzs); const BzsSectionHead *head = OFS_TO_PTR(BzsSectionHead, header); for (s32 i = 0; i < header->mSectionCount; i++) { findAndRunStageTagParseFunc(roomid, head++, roomActivateHandlers, ARRAY_LENGTH(roomActivateHandlers)); } }