#include "BenPort.h" #include "global.h" #include #include #include #include #include #include #include "2s2h/GameInteractor/GameInteractor.h" #include "2s2h/resource/type/Scene.h" #include "2s2h/resource/type/CollisionHeader.h" #include "2s2h/resource/type/Path.h" #include "2s2h/resource/type/scenecommand/SetCameraSettings.h" #include "2s2h/resource/type/scenecommand/SetCutscenes.h" #include "2s2h/resource/type/scenecommand/SetStartPositionList.h" #include "2s2h/resource/type/scenecommand/SetActorList.h" #include "2s2h/resource/type/scenecommand/SetCollisionHeader.h" #include "2s2h/resource/type/scenecommand/SetRoomList.h" #include "2s2h/resource/type/scenecommand/SetEntranceList.h" #include "2s2h/resource/type/scenecommand/SetSpecialObjects.h" #include "2s2h/resource/type/scenecommand/SetRoomBehavior.h" #include "2s2h/resource/type/scenecommand/SetMesh.h" #include "2s2h/resource/type/scenecommand/SetObjectList.h" #include "2s2h/resource/type/scenecommand/SetLightList.h" #include "2s2h/resource/type/scenecommand/SetLightingSettings.h" #include "2s2h/resource/type/scenecommand/SetPathways.h" #include "2s2h/resource/type/scenecommand/SetTransitionActorList.h" #include "2s2h/resource/type/scenecommand/SetSkyboxSettings.h" #include "2s2h/resource/type/scenecommand/SetSkyboxModifier.h" #include "2s2h/resource/type/scenecommand/SetTimeSettings.h" #include "2s2h/resource/type/scenecommand/SetWindSettings.h" #include "2s2h/resource/type/scenecommand/SetSoundSettings.h" #include "2s2h/resource/type/scenecommand/SetEchoSettings.h" #include "2s2h/resource/type/scenecommand/SetAlternateHeaders.h" #include "2s2h/resource/type/scenecommand/SetActorCutsceneList.h" #include "2s2h/resource/type/scenecommand/SetAnimatedMaterialList.h" #include "2s2h/resource/type/scenecommand/SetMinimapList.h" #include "2s2h/resource/type/scenecommand/SetMinimapChests.h" #include "2s2h/resource/type/scenecommand/SetCsCamera.h" s32 OTRScene_ExecuteCommands(PlayState* play, SOH::Scene* scene); void Scene_CommandSpawnList(PlayState* play, SOH::ISceneCommand* cmd) { SOH::SetStartPositionList* list = (SOH::SetStartPositionList*)cmd; ActorEntry* entries = (ActorEntry*)(list->GetRawPointer()); s32 loadedCount; s16 playerObjectId; void* objectPtr; play->linkActorEntry = &entries[play->setupEntranceList[play->curSpawn].spawn]; if ((PLAYER_GET_START_MODE(play->linkActorEntry) == PLAYER_START_MODE_TELESCOPE) || ((gSaveContext.respawnFlag == 2) && (gSaveContext.respawn[RESPAWN_MODE_RETURN].playerParams == PLAYER_PARAMS(0xFF, PLAYER_START_MODE_TELESCOPE)))) { // Skull Kid Object Object_SpawnPersistent(&play->objectCtx, OBJECT_STK); return; } loadedCount = Object_SpawnPersistent(&play->objectCtx, OBJECT_LINK_CHILD); objectPtr = play->objectCtx.slots[play->objectCtx.numEntries].segment; play->objectCtx.numEntries = loadedCount; play->objectCtx.numPersistentEntries = loadedCount; playerObjectId = gPlayerFormObjectIds[GET_PLAYER_FORM]; gActorOverlayTable[0].profile->objectId = playerObjectId; Object_SpawnPersistent(&play->objectCtx, playerObjectId); play->objectCtx.slots[play->objectCtx.numEntries].segment = objectPtr; } void Scene_CommandActorList(PlayState* play, SOH::ISceneCommand* cmd) { SOH::SetActorList* list = (SOH::SetActorList*)cmd; play->numSetupActors = list->numActors; play->actorCtx.halfDaysBit = 0; play->setupActorList = (ActorEntry*)list->GetRawPointer(); } void Scene_CommandActorCutsceneCamList(PlayState* play, SOH::ISceneCommand* cmd) { SOH::SetCsCamera* cams = (SOH::SetCsCamera*)cmd; play->actorCsCamList = (ActorCsCamInfo*)cams->GetPointer(); } void Scene_CommandCollisionHeader(PlayState* play, SOH::ISceneCommand* cmd) { SOH::SetCollisionHeader* colHeader = (SOH::SetCollisionHeader*)cmd; BgCheck_Allocate(&play->colCtx, play, (CollisionHeader*)colHeader->GetRawPointer()); } void Scene_CommandRoomList(PlayState* play, SOH::ISceneCommand* cmd) { SOH::SetRoomList* list = (SOH::SetRoomList*)cmd; play->roomList.count = list->numRooms; play->roomList.romFiles = (RomFile*)list->GetPointer(); } void Scene_CommandWindSettings(PlayState* play, SOH::ISceneCommand* cmd) { SOH::SetWindSettings* settings = (SOH::SetWindSettings*)cmd; play->envCtx.windDirection.x = settings->settings.windWest; play->envCtx.windDirection.y = settings->settings.windVertical; play->envCtx.windDirection.z = settings->settings.windSouth; play->envCtx.windSpeed = settings->settings.windSpeed; } void Scene_CommandEntranceList(PlayState* play, SOH::ISceneCommand* cmd) { SOH::SetEntranceList* list = (SOH::SetEntranceList*)cmd; play->setupEntranceList = (EntranceEntry*)list->GetRawPointer(); } void Scene_CommandSpecialFiles(PlayState* play, SOH::ISceneCommand* cmd) { SOH::SetSpecialObjects* specialObjList = (SOH::SetSpecialObjects*)cmd; // static RomFile naviQuestHintFiles[2] = { // { SEGMENT_ROM_START(elf_message_field), SEGMENT_ROM_END(elf_message_field) }, // { SEGMENT_ROM_START(elf_message_ydan), SEGMENT_ROM_END(elf_message_ydan) }, // }; if (specialObjList->specialObjects.globalObject != 0) { play->objectCtx.subKeepSlot = Object_SpawnPersistent(&play->objectCtx, specialObjList->specialObjects.globalObject); // ZRET TODO: Segment number enum? // gSegments[0x05] = OS_K0_TO_PHYSICAL(play->objectCtx.slots[play->objectCtx.subKeepSlot].segment); } // BENTODO: Figure out if the following section is needed for something // if (specialObjList->specialObjects.elfMessage != NAVI_QUEST_HINTS_NONE) { // play->naviQuestHints = Play_LoadFile(play, &naviQuestHintFiles[specialObjList->specialObjects.elfMessage - // 1]); // } } void Scene_CommandRoomBehavior(PlayState* play, SOH::ISceneCommand* cmd) { SOH::SetRoomBehaviorMM* behavior = (SOH::SetRoomBehaviorMM*)cmd; play->roomCtx.curRoom.type = behavior->roomBehavior.gameplayFlags; play->roomCtx.curRoom.environmentType = behavior->roomBehavior.currRoomUnk2; play->roomCtx.curRoom.lensMode = behavior->roomBehavior.currRoomUnk5; play->msgCtx.unk12044 = behavior->roomBehavior.msgCtxUnk; play->roomCtx.curRoom.enablePosLights = behavior->roomBehavior.enablePointLights; play->envCtx.stormState = behavior->roomBehavior.kankyoContextUnkE2; // play->roomCtx.curRoom.type = behavior->roomBehavior.gameplayFlags; // play->roomCtx.curRoom.environmentType = behavior->roomBehavior.gameplayFlags2 & 0xFF; // play->roomCtx.curRoom.lensMode = (behavior->roomBehavior.gameplayFlags2 >> 8) & 1; // play->msgCtx.unk12044 = (behavior->roomBehavior.gameplayFlags2 >> 0xA) & 1; // play->roomCtx.curRoom.enablePosLights = (behavior->roomBehavior.gameplayFlags2 >> 0xB) & 1; // play->envCtx.stormState = (behavior->roomBehavior.gameplayFlags2 >> 0xC) & 1; } void Scene_Command09(PlayState* play, SOH::ISceneCommand* cmd) { // Empty in z_scene.c } void Scene_CommandMesh(PlayState* play, SOH::ISceneCommand* cmd) { SOH::SetMesh* mesh = (SOH::SetMesh*)cmd; play->roomCtx.curRoom.roomShape = (RoomShape*)mesh->GetRawPointer(); } void Scene_CommandObjectList(PlayState* play, SOH::ISceneCommand* cmd) { SOH::SetObjectList* objList = (SOH::SetObjectList*)cmd; s32 i; s32 j; s32 k; // #region 2S2H [Port] Cleaner version of decomps loops for nicer presentation // Loop until a mismatch in the object lists // Then clear all object ids past that in the context object list and kill actors for those objects for (i = play->objectCtx.numPersistentEntries, k = 0; i < play->objectCtx.numEntries; i++, k++) { if (k >= objList->objects.size() || play->objectCtx.slots[i].id != objList->objects[k]) { for (j = i; j < play->objectCtx.numEntries; j++) { play->objectCtx.slots[j].id = 0; } Actor_KillAllWithMissingObject(play, &play->actorCtx); break; } } // Continuing from the last index, add the remaining object ids from the command object list for (; k < objList->objects.size(); i++, k++) { play->objectCtx.slots[i].id = -objList->objects[k]; } play->objectCtx.numEntries = i; // #endregion // Original Compatible Code Commented // s32 i; // s32 j; // s32 k; // ObjectEntry* firstObject; // ObjectEntry* entry; // ObjectEntry* invalidatedEntry; // s16* objectEntry; // void* nextPtr; // s16* objectEntry = (s16*)objList->GetRawPointer(); // k = 0; // i = play->objectCtx.numPersistentEntries; // entry = &play->objectCtx.slots[i]; // firstObject = &play->objectCtx.slots[0]; // while (i < play->objectCtx.numEntries) { // if (entry->id != *objectEntry) { // invalidatedEntry = &play->objectCtx.slots[i]; // for (j = i; j < play->objectCtx.numEntries; j++) { // invalidatedEntry->id = 0; // invalidatedEntry++; // } // play->objectCtx.numEntries = i; // Actor_KillAllWithMissingObject(play, &play->actorCtx); // continue; // } // i++; // k++; // objectEntry++; // entry++; // } // while (k < objList->objects.size()) { // nextPtr = func_8012F73C(&play->objectCtx, i, *objectEntry); // if (i < ARRAY_COUNT(play->objectCtx.slots) - 1) { // firstObject[i + 1].segment = nextPtr; // } // i++; // k++; // objectEntry++; // } // play->objectCtx.numEntries = i; } void Scene_CommandLightList(PlayState* play, SOH::ISceneCommand* cmd) { SOH::SetLightList* lightList = (SOH::SetLightList*)cmd; for (unsigned int i = 0; i < lightList->numLights; i++) { LightContext_InsertLight(play, &play->lightCtx, (LightInfo*)&lightList->lightList[i]); } } void Scene_CommandPathList(PlayState* play, SOH::ISceneCommand* cmd) { SOH::SetPathwaysMM* paths = (SOH::SetPathwaysMM*)cmd; play->setupPathList = (Path*)paths->GetPointer()[0]; } void Scene_CommandTransiActorList(PlayState* play, SOH::ISceneCommand* cmd) { SOH::SetTransitionActorList* list = (SOH::SetTransitionActorList*)cmd; play->transitionActors.count = list->numTransitionActors; play->transitionActors.list = (TransitionActorEntry*)list->GetRawPointer(); MapDisp_InitTransitionActorData(play, play->transitionActors.count, play->transitionActors.list); } void Scene_CommandEnvLightSettings(PlayState* play, SOH::ISceneCommand* cmd) { SOH::SetLightingSettings* lightSettings = (SOH::SetLightingSettings*)cmd; play->envCtx.numLightSettings = lightSettings->settings.size(); play->envCtx.lightSettingsList = (EnvLightSettings*)lightSettings->GetRawPointer(); } void Scene_CommandTimeSettings(PlayState* play, SOH::ISceneCommand* cmd) { SOH::SetTimeSettings* settings = (SOH::SetTimeSettings*)cmd; if ((settings->settings.hour != 0xFF) && (settings->settings.minute != 0xFF)) { gSaveContext.skyboxTime = gSaveContext.save.time = CLOCK_TIME_ALT2_F(settings->settings.hour, settings->settings.minute); } if (settings->settings.timeIncrement != 0xFF) { play->envCtx.sceneTimeSpeed = settings->settings.timeIncrement; } else { play->envCtx.sceneTimeSpeed = 0; } // Increase time speed during first cycle if (GameInteractor_Should(VB_FASTER_FIRST_CYCLE, (gSaveContext.save.saveInfo.inventory.items[SLOT_OCARINA] == ITEM_NONE) && (play->envCtx.sceneTimeSpeed != 0))) { play->envCtx.sceneTimeSpeed = 5; } if (gSaveContext.sunsSongState == SUNSSONG_INACTIVE) { R_TIME_SPEED = play->envCtx.sceneTimeSpeed; } play->envCtx.sunPos.x = -(Math_SinS(CURRENT_TIME - CLOCK_TIME(12, 0)) * 120.0f) * 25.0f; play->envCtx.sunPos.y = (Math_CosS(CURRENT_TIME - CLOCK_TIME(12, 0)) * 120.0f) * 25.0f; play->envCtx.sunPos.z = (Math_CosS(CURRENT_TIME - CLOCK_TIME(12, 0)) * 20.0f) * 25.0f; if ((play->envCtx.sceneTimeSpeed == 0) && (gSaveContext.save.cutsceneIndex < 0xFFF0)) { gSaveContext.skyboxTime = CURRENT_TIME; if ((gSaveContext.skyboxTime >= CLOCK_TIME(4, 0)) && (gSaveContext.skyboxTime < CLOCK_TIME(6, 30))) { gSaveContext.skyboxTime = CLOCK_TIME(5, 0); } else if ((gSaveContext.skyboxTime >= CLOCK_TIME(6, 30)) && (gSaveContext.skyboxTime < CLOCK_TIME(8, 0))) { gSaveContext.skyboxTime = CLOCK_TIME(8, 0); } else if ((gSaveContext.skyboxTime >= CLOCK_TIME(16, 0)) && (gSaveContext.skyboxTime < CLOCK_TIME(17, 0))) { gSaveContext.skyboxTime = CLOCK_TIME(17, 0); } else if ((gSaveContext.skyboxTime >= CLOCK_TIME(18, 0)) && (gSaveContext.skyboxTime < CLOCK_TIME(19, 0))) { gSaveContext.skyboxTime = CLOCK_TIME(19, 0); } } } void Scene_CommandSkyboxSettings(PlayState* play, SOH::ISceneCommand* cmd) { SOH::SetSkyboxSettings* settings = (SOH::SetSkyboxSettings*)cmd; play->skyboxId = settings->settings.skyboxId & 3; // BENTODO z_scene.c reads from skyboxSettings.skyboxConfig not weather // Settings uses names from OOT play->envCtx.skyboxConfig = play->envCtx.changeSkyboxNextConfig = settings->settings.weather; play->envCtx.lightMode = settings->settings.indoors; // Scene_LoadAreaTextures(play, settings->settings.) } void Scene_CommandSkyboxDisables(PlayState* play, SOH::ISceneCommand* cmd) { SOH::SetSkyboxModifier* mod = (SOH::SetSkyboxModifier*)cmd; play->envCtx.skyboxDisabled = mod->modifier.skyboxDisabled; play->envCtx.sunDisabled = mod->modifier.sunMoonDisabled; } void Scene_CommandExitList(PlayState* play, SOH::ISceneCommand* cmd) { play->setupExitList = (u16*)cmd->GetRawPointer(); } void Scene_CommandSoundSettings(PlayState* play, SOH::ISceneCommand* cmd) { SOH::SetSoundSettings* settings = (SOH::SetSoundSettings*)cmd; play->sceneSequences.seqId = settings->settings.seqId; play->sceneSequences.ambienceId = settings->settings.natureAmbienceId; if (gSaveContext.seqId == NA_BGM_DISABLED || AudioSeq_GetActiveSeqId(SEQ_PLAYER_BGM_MAIN) == NA_BGM_FINAL_HOURS) { Audio_SetSpec(settings->settings.reverb); // BENTODO Verify if this should be reverb } } void Scene_CommandEchoSetting(PlayState* play, SOH::ISceneCommand* cmd) { SOH::SetEchoSettings* echo = (SOH::SetEchoSettings*)cmd; play->roomCtx.curRoom.echo = echo->settings.echo; } void Scene_CommandCutsceneScriptList(PlayState* play, SOH::ISceneCommand* cmd) { SOH::SetCutscenesMM* cs = (SOH::SetCutscenesMM*)cmd; play->csCtx.scriptListCount = cs->entries.size(); // BENTODO do this the right way with get pointer play->csCtx.scriptList = (CutsceneScriptEntry*)cs->entries.data(); } static bool shouldEndSceneCommands = false; void Scene_CommandAltHeaderList(PlayState* play, SOH::ISceneCommand* cmd) { SOH::SetAlternateHeaders* headers = (SOH::SetAlternateHeaders*)cmd; if (gSaveContext.sceneLayer != 0) { SOH::Scene* desiredHeader = std::static_pointer_cast(headers->headers[gSaveContext.sceneLayer - 1]).get(); if (desiredHeader != nullptr) { OTRScene_ExecuteCommands(play, desiredHeader); // 2S2H [Port] The original source would grab the next command after the alternate header list // and change the command id to SCENE_CMD_ID_END. We can't modify LUS resources, so we'll just // set a flag to end the scene commands shouldEndSceneCommands = true; } } } void Scene_CommandSetRegionVisitedFlag(PlayState* play, SOH::ISceneCommand* cmd) { s16 j = 0; s16 i = 0; while (true) { if (gSceneIdsPerRegion[i][j] == 0xFFFF) { i++; j = 0; if (i == REGION_MAX) { break; } } if (play->sceneId == gSceneIdsPerRegion[i][j]) { break; } j++; } if (i < REGION_MAX) { gSaveContext.save.saveInfo.regionsVisited = (gBitFlags[i] | gSaveContext.save.saveInfo.regionsVisited) | gSaveContext.save.saveInfo.regionsVisited; } } void Scene_CommandAnimatedMaterials(PlayState* play, SOH::ISceneCommand* cmd) { SOH::SetAnimatedMaterialList* list = (SOH::SetAnimatedMaterialList*)cmd; play->sceneMaterialAnims = (AnimatedMaterial*)list->mat; } void Scene_CommandCutsceneList(PlayState* play, SOH::ISceneCommand* cmd) { SOH::SetActorCutsceneList* list = (SOH::SetActorCutsceneList*)cmd; CutsceneManager_Init(play, (ActorCutscene*)list->GetPointer(), list->entries.size()); } void Scene_CommandMiniMap(PlayState* play, SOH::ISceneCommand* cmd) { SOH::SetMinimapList* list = (SOH::SetMinimapList*)cmd; MapDisp_Init(play); MapDisp_InitMapData(play, list->GetPointer()); } void Scene_Command1D(PlayState* play, SOH::ISceneCommand* cmd) { } void Scene_CommandMiniMapCompassInfo(PlayState* play, SOH::ISceneCommand* cmd) { SOH::SetMinimapChests* chests = (SOH::SetMinimapChests*)cmd; MapDisp_InitChestData(play, chests->chests.size(), chests->GetPointer()); } void (*sSceneCmdHandlersOTR[SCENE_CMD_MAX])(PlayState*, SOH::ISceneCommand*) = { Scene_CommandSpawnList, // SCENE_CMD_ID_SPAWN_LIST Scene_CommandActorList, // SCENE_CMD_ID_ACTOR_LIST Scene_CommandActorCutsceneCamList, // SCENE_CMD_ID_ACTOR_CUTSCENE_CAM_LIST Scene_CommandCollisionHeader, // SCENE_CMD_ID_COL_HEADER Scene_CommandRoomList, // SCENE_CMD_ID_ROOM_LIST Scene_CommandWindSettings, // SCENE_CMD_ID_WIND_SETTINGS Scene_CommandEntranceList, // SCENE_CMD_ID_ENTRANCE_LIST Scene_CommandSpecialFiles, // SCENE_CMD_ID_SPECIAL_FILES Scene_CommandRoomBehavior, // SCENE_CMD_ID_ROOM_BEHAVIOR Scene_Command09, // SCENE_CMD_ID_UNK_09 Scene_CommandMesh, // SCENE_CMD_ID_ROOM_SHAPE Scene_CommandObjectList, // SCENE_CMD_ID_OBJECT_LIST Scene_CommandLightList, // SCENE_CMD_ID_LIGHT_LIST Scene_CommandPathList, // SCENE_CMD_ID_PATH_LIST Scene_CommandTransiActorList, // SCENE_CMD_ID_TRANSI_ACTOR_LIST Scene_CommandEnvLightSettings, // SCENE_CMD_ID_ENV_LIGHT_SETTINGS Scene_CommandTimeSettings, // SCENE_CMD_ID_TIME_SETTINGS Scene_CommandSkyboxSettings, // SCENE_CMD_ID_SKYBOX_SETTINGS Scene_CommandSkyboxDisables, // SCENE_CMD_ID_SKYBOX_DISABLES Scene_CommandExitList, // SCENE_CMD_ID_EXIT_LIST NULL, // SCENE_CMD_ID_END Scene_CommandSoundSettings, // SCENE_CMD_ID_SOUND_SETTINGS Scene_CommandEchoSetting, // SCENE_CMD_ID_ECHO_SETTINGS Scene_CommandCutsceneScriptList, // SCENE_CMD_ID_CUTSCENE_SCRIPT_LIST Scene_CommandAltHeaderList, // SCENE_CMD_ID_ALTERNATE_HEADER_LIST Scene_CommandSetRegionVisitedFlag, // SCENE_CMD_ID_SET_REGION_VISITED Scene_CommandAnimatedMaterials, // SCENE_CMD_ID_ANIMATED_MATERIAL_LIST Scene_CommandCutsceneList, // SCENE_CMD_ID_ACTOR_CUTSCENE_LIST Scene_CommandMiniMap, // SCENE_CMD_ID_MINIMAP_INFO Scene_Command1D, // SCENE_CMD_ID_UNUSED_1D Scene_CommandMiniMapCompassInfo, // SCENE_CMD_ID_MINIMAP_COMPASS_ICON_INFO }; s32 OTRScene_ExecuteCommands(PlayState* play, SOH::Scene* scene) { SOH::SceneCommandID cmdId; shouldEndSceneCommands = false; for (int i = 0; i < scene->commands.size(); i++) { auto sceneCmd = scene->commands[i]; cmdId = sceneCmd->cmdId; // 2S2H [Port] This opcode is not in the original game. Its a special command for OTRs, for supporting multiple // games if (cmdId == SOH::SceneCommandID::SetCutscenesMM) { cmdId = SOH::SceneCommandID::SetCutscenes; } // 2S2H [Port] shouldEndSceneCommands is set when an alternate header list is found if (cmdId == SOH::SceneCommandID::EndMarker || shouldEndSceneCommands) { shouldEndSceneCommands = false; break; } if (cmdId < SOH::SceneCommandID::SetCutscenesMM) { sSceneCmdHandlersOTR[(int)cmdId](play, sceneCmd.get()); } } return 0; } extern "C" s32 OTRfunc_8009728C(PlayState* play, RoomContext* roomCtx, s32 roomNum) { u32 size; if (roomCtx->status == 0) { roomCtx->prevRoom = roomCtx->curRoom; roomCtx->curRoom.num = roomNum; roomCtx->curRoom.segment = NULL; roomCtx->status = 1; // assert(roomNum < play->roomList.count); if (roomNum >= play->roomList.count) return 0; // UH OH size = play->roomList.romFiles[roomNum].vromEnd - play->roomList.romFiles[roomNum].vromStart; // roomCtx->roomRequestAddr = // (void*)((uintptr_t)roomCtx->roomMemPages[roomCtx->activeBufPage] - ((size + 8) * roomCtx->activeBufPage + // 7)); // DmaMgr_SendRequest2(&roomCtx->dmaRequest, roomCtx->unk_34, play->roomList.romFiles[roomNum].vromStart, size, // 0, //&roomCtx->loadQueue, NULL, __FILE__, __LINE__); auto roomData = std::static_pointer_cast(ResourceLoad(play->roomList.romFiles[roomNum].fileName)); roomCtx->status = 1; roomCtx->roomRequestAddr = roomData.get(); roomCtx->activeBufPage ^= 1; GameInteractor_ExecuteOnRoomInit(play->sceneId, roomCtx->curRoom.num); return 1; } return 0; }