-- Majora's Mask (U): Camera Control Script -- by Jimmie1717 -- BizHawk 1.11.8.2 -- Controls: -- Home: Toggle Camera Control. -- This also hides the game HUD and stops in-game time. -- -- Page Up/Down: Adjust the Camera's Zoom. -- -- Arrow Keys: Move the Camera's Position on the X and Z Axis. -- Shift + Arrow Keys: Move the Camera's Position on the X and Y Axis. -- This also moves the Camera's Target. (so the camera rotation doesn't change) -- -- Ctrl + Arrow Keys: Move the Camera's Target on the X and Z Axis. -- Ctrl + Shift + Arrow Keys: Move the Camera's Target on the X and Y Axis. -- This will change the Camera's Rotation and distance of what it's looking at. console.clear(); gui.defaultTextBackground(0x00000000); -- Global readWord = memory.read_u16_be; readDWord = memory.read_u32_be; readFloat = memory.readfloat; writeWord = memory.write_u16_be; writeDWord = memory.write_u32_be; writeFloat = memory.writefloat; -- Addresses local time_speed_area = 0x382502; local hud_tranparency = { [0] = 0x3FD76E, [1] = 0x3FD770, [2] = 0x3FD772, [3] = 0x3FD774, [4] = 0x3FD776, [5] = 0x3FD778, [6] = 0x3FD77A }; local camera = { mode = 0x3E6E82, target = { x = 0x3E6D90, y = 0x3E6D94, z = 0x3E6D98, }, position = { x = 0x3E6D9C, y = 0x3E6DA0, z = 0x3E6DA4, }, zoom = 0x3E6E3C }; local camera_data = { mode = nil, target = { x = nil, y = nil, z = nil, }, position = { x = nil, y = nil, z = nil, }, zoom = nil }; local cameraEdit = false; local isPressed = false; -- Anchor and Tranparency for Text Display local x = 0; local y = 375; local transparency = 0xFF000000; -- Draw a String. function drawString(x, y, text, color) gui.drawText(x + 1, y + 1, string.format("%s", text), transparency + 0x000000); gui.drawText(x, y, string.format("%s", text), transparency + color); end -- Draw a String formatted like a value. function drawStringValue(x, y, value, color) gui.drawText(x + 1, y + 1, string.format("% 8s", value), transparency + 0x000000); gui.drawText(x, y, string.format("% 8s", value), transparency + color); end -- Draw an Integer formatted like a value. function drawIntegerValue(x, y, value, color) gui.drawText(x + 1, y + 1, string.format("% 8d", value), transparency + 0x000000); gui.drawText(x, y, string.format("% 8d", value), transparency + color); end -- Draw a Float formatted like a value. function drawFloatValue(x, y, value, color) gui.drawText(x + 1, y + 1, string.format("% 8.1f", value), transparency + 0x000000); gui.drawText(x, y, string.format("% 8.1f", value), transparency + color); end -- Draw Byte from supplied address. function drawByte(x, y, address, color) gui.drawText(x + 1, y + 1, string.format("% 8d", readByte(address)), transparency + 0x000000); gui.drawText(x, y, string.format("% 8d", readByte(address)), transparency + color); end -- Draw Word from supplied address. function drawWord(x, y, address, color) gui.drawText(x + 1, y + 1, string.format("% 8d", readWord(address)), transparency + 0x000000); gui.drawText(x, y, string.format("% 8d", readWord(address)), transparency + color); end -- Draw Double Word from supplied address. function drawDWord(x, y, address, color) gui.drawText(x + 1, y + 1, string.format("% 8d", readDWord(address)), transparency + 0x000000); gui.drawText(x, y, string.format("% 8d", readDWord(address)), transparency + color); end -- Draw Float from supplied address. function drawFloat(x, y, address, color) gui.drawText(x + 1, y + 1, string.format("% 8.1f", readFloat(address, true)), transparency + 0x000000); gui.drawText(x, y, string.format("% 8.1f", readFloat(address, true)), transparency + color); end -- Draw Byte from supplied address in hexadecimal. function drawHexByte(x, y, address, color) gui.drawText(x + 46, y + 1, string.format("%02s", bizstring.hex(readByte(address))), transparency + 0x000000); gui.drawText(x + 45, y, string.format("%02s", bizstring.hex(readByte(address))), transparency + color); end -- Draw Word from supplied address in hexadecimal. function drawHexWord(x, y, address, color) gui.drawText(x + 31, y + 1, string.format("%04s", bizstring.hex(readWord(address))), transparency + 0x000000); gui.drawText(x + 30, y, string.format("%04s", bizstring.hex(readWord(address))), transparency + color); end -- Draw Double Word from supplied address in hexadecimal. function drawHexDWord(x, y, address, color) gui.drawText(x + 1, y + 1, string.format("%08s", bizstring.hex(readDWord(address))), transparency + 0x000000); gui.drawText(x, y, string.format("%08s", bizstring.hex(readDWord(address))), transparency + color); end -- Text Display function textDisplay() drawString(x, y - 18, "Zoom:", 0xFFFFFF); drawFloat(x + 100, y - 18, camera.zoom, 0x80FFFF); --- drawString(x, y, "Position:", 0xFFFFFF); drawString(x, y + 12, " X:", 0xFFFFFF); drawFloat(x + 100, y + 12, camera.position.x, 0x80FFFF); drawString(x, y + 24, " Y:", 0xFFFFFF); drawFloat(x + 100, y + 24, camera.position.y, 0xFF80FF); drawString(x, y + 36, " Z:", 0xFFFFFF); drawFloat(x + 100, y + 36, camera.position.z, 0xFFFF80); --- drawString(x, y + 54, "Target:", 0xFFFFFF); drawString(x, y + 66, " X:", 0xFFFFFF); drawFloat(x + 100, y + 66, camera.target.x, 0x80FFFF); drawString(x, y + 78, " Y:", 0xFFFFFF); drawFloat(x + 100, y + 78, camera.target.y, 0xFF80FF); drawString(x, y + 90, " Z:", 0xFFFFFF); drawFloat(x + 100, y + 90, camera.target.z, 0xFFFF80); end -- Hide/Show HUD function hideHUD(type) local transparency = nil; if (type == true) then transparency = 0x0000; writeWord(time_speed_area, 0x0000); elseif (type == false) then transparency = 0x00FF; writeWord(time_speed_area, 0x0003); end for i = 0, 6, 1 do writeWord(hud_tranparency[i], transparency); end end -- Disable Camera Control on Load Savestate. -- I call this instead of "toggleCamera()" from loading a state -- because apparently "event.onloadstate()" calls the funtion several times??? function disableCamera() cameraEdit = false; setCamera(false); end -- Enable/Disable Camera Control function toggleCamera() isPressed = true; if (cameraEdit == true) then cameraEdit = false; gui.addmessage("Camera Control Disabled."); elseif (cameraEdit == false) then cameraEdit = true; gui.addmessage("Camera Control Enabled."); end setCamera(true); end -- Set the Camera mode and Save/Load it's Position when Enabled/Disabled. function setCamera(disable) if (cameraEdit == true) then camera_data.mode = readWord(camera.mode); camera_data.target.x = readFloat(camera.target.x, true); camera_data.target.y = readFloat(camera.target.y, true); camera_data.target.z = readFloat(camera.target.z, true); camera_data.position.x = readFloat(camera.position.x, true); camera_data.position.y = readFloat(camera.position.y, true); camera_data.position.z = readFloat(camera.position.z, true); camera_data.zoom = readFloat(camera.zoom, true); writeWord(camera.mode, 0x0006); elseif (cameraEdit == false and disable ~= false) then writeWord(camera.mode, camera_data.mode); writeFloat(camera.target.x, camera_data.target.x, true); writeFloat(camera.target.y, camera_data.target.y, true); writeFloat(camera.target.z, camera_data.target.z, true); writeFloat(camera.position.x, camera_data.position.x, true); writeFloat(camera.position.y, camera_data.position.y, true); writeFloat(camera.position.z, camera_data.position.z, true); writeFloat(camera.zoom, camera_data.zoom, true); hideHUD(false); end end -- Update Camera Position/Target. function moveCamera(address, value) local newLocation = readFloat(address, true) + value; if (cameraEdit == true) then writeFloat(address, newLocation, true); end end -- Update Camera Zoom. function zoomCamera(value) local newZoom = readFloat(camera.zoom, true) + value; if (cameraEdit == true) then writeFloat(camera.zoom, newZoom, true); end end -- Core Loop while true do -- Disable if a Savestate is loaded. event.onloadstate(disableCamera); -- Toggle Camera Control if (input.get().Home == true and isPressed == false) then toggleCamera(); -- Zoom Camera elseif (input.get().PageUp == true) then zoomCamera(1); elseif (input.get().PageDown == true) then zoomCamera(-1); -- Move Camera Position elseif (input.get().Ctrl == nil and isPressed == false) then if (input.get().LeftArrow == true) then moveCamera(camera.position.x, 10.0); moveCamera(camera.target.x, 10.0); elseif (input.get().RightArrow == true) then moveCamera(camera.position.x, -10.0); moveCamera(camera.target.x, -10.0); elseif (input.get().UpArrow == true and input.get().Shift == true) then moveCamera(camera.position.y, 10.0); moveCamera(camera.target.y, 10.0); elseif (input.get().DownArrow == true and input.get().Shift == true) then moveCamera(camera.position.y, -10.0); moveCamera(camera.target.y, -10.0); elseif (input.get().UpArrow == true and input.get().Shift == nil) then moveCamera(camera.position.z, 10.0); moveCamera(camera.target.z, 10.0); elseif (input.get().DownArrow == true and input.get().Shift == nil) then moveCamera(camera.position.z, -10.0); moveCamera(camera.target.z, -10.0); end -- Move Camera Target elseif (input.get().Ctrl == true and isPressed == false) then if (input.get().LeftArrow == true) then moveCamera(camera.target.x, 10.0); elseif (input.get().RightArrow == true) then moveCamera(camera.target.x, -10.0); elseif (input.get().UpArrow == true and input.get().Shift == true) then moveCamera(camera.target.y, 10.0); elseif (input.get().DownArrow == true and input.get().Shift == true) then moveCamera(camera.target.y, -10.0); elseif (input.get().UpArrow == true and input.get().Shift == nil) then moveCamera(camera.target.z, 10.0); elseif (input.get().DownArrow == true and input.get().Shift == nil) then moveCamera(camera.target.z, -10.0); end elseif (input.get().Home == nil and input.get().PageUp == nil and input.get().PageDown == nil and input.get().Shift == nil and input.get().Ctrl == nil and input.get().UpArrow == nil and input.get().DownArrow == nil and input.get().LeftArrow == nil and input.get().RightArrow == nil) then isPressed = false; end -- Display Camera Info if (cameraEdit == true) then textDisplay(); hideHUD(true); end emu.frameadvance(); end