From 5d1c7b9c17d87c3820cf73a6c0e33802ba1929fe Mon Sep 17 00:00:00 2001 From: Buhallin Date: Sat, 10 Dec 2022 18:08:24 -0800 Subject: [PATCH] Add multiplayer handling to TourManager Each player will now be tracked independently, and can watch their own tour. --- src/core/tour/TourManager.ttslua | 135 ++++++++++++++++++------------- 1 file changed, 78 insertions(+), 57 deletions(-) diff --git a/src/core/tour/TourManager.ttslua b/src/core/tour/TourManager.ttslua index 9d14b59d..ea5a830b 100644 --- a/src/core/tour/TourManager.ttslua +++ b/src/core/tour/TourManager.ttslua @@ -5,11 +5,11 @@ do local internal = { } -- Base IDs for various tour card UI elements. Actual IDs will have _[playerColor] appended - local cardId = "tourCard" - local narratorId = "tourNarratorImage" - local textId = "tourText" - local nextButtonId = "tourNext" - local stopButtonId = "tourStop" + local CARD_ID = "tourCard" + local NARRATOR_ID = "tourNarratorImage" + local TEXT_ID = "tourText" + local NEXT_BUTTON_ID = "tourNext" + local STOP_BUTTON_ID = "tourStop" -- Table centerpoint for the camera hook object. Camera handling is a bit erratic so it doesn't -- always land right where you think it's going to, but it's close @@ -19,51 +19,59 @@ do z = 0, } - local cameraHookGuid - local currentCardIndex + -- Trackers for the current state. + local tourState = { } + local cameraHookGuid = { } + local currentCardIndex = { } -- Kicks off the tour by initializing the card and camera hook. A callback on the hook creation -- will then show the first card. -- @param playerColor Player color to start the tour for TourManager.startTour = function(playerColor) - currentCardIndex = 1 + log(playerColor) + tourState[playerColor] = { + currentCardIndex = 1 + } -- Camera gets really screwy when we finalize if we don't start in ThirdPerson before attaching -- to the hook - Player["White"].setCameraMode("ThirdPerson") - internal.createTourCard("White") - -- XML update takes time to load, wait for it to finish then create the hook - Wait.condition( - function() - internal.createCameraHook() - end, - function() - return not Global.UI.loading - end - ) + Player[playerColor].setCameraMode("ThirdPerson") + Player[playerColor].lookAt({position={-22.265,-2.5,5.2575},pitch=64.343,yaw=90.333,distance=104.7}) + Wait.time(function() + internal.createTourCard(playerColor) + -- XML update takes time to load, wait for it to finish then create the hook + Wait.condition( + function() + internal.createCameraHook(playerColor) + end, + function() + return not Global.UI.loading + end + ) + end, 2) end -- Shows the next card in the tour script. This method is exposed (rather than being part of -- internal) because the XMLUI callbacks expect the method to be on the object directly. - -- @param playerColor Player color to show the next card for - function nextCard(playerColor) - internal.hideCard() + -- @param player Player object to show the next card for, provided by XMLUI callback + function nextCard(player) + internal.hideCard(player.color) Wait.time(function() - currentCardIndex = currentCardIndex + 1 - if currentCardIndex > #TOUR_SCRIPT then - internal.finalizeTour() + tourState[player.color].currentCardIndex = tourState[player.color].currentCardIndex + 1 + if tourState[player.color].currentCardIndex > #TOUR_SCRIPT then + internal.finalizeTour(player.color) else - internal.showCurrentCard() + internal.showCurrentCard(player.color) end end, 0.3) end -- Ends the tour and cleans up the camera. This method is exposed (rather than being part of -- internal) because the XMLUI callbacks expect the method to be on the object directly. - -- @param playerColor Player color to end the tour for - function stopTour(playerColor) - internal.hideCard() + -- @param player Player object to end the tour for, provided by XMLUI callback + function stopTour(player) + internal.hideCard(player.color) Wait.time(function() - internal.finalizeTour() + internal.finalizeTour(player.color) end, 0.3) end @@ -71,25 +79,26 @@ do -- position, and shows the card. -- @param playerColor Player color to show the current card for internal.showCurrentCard = function(playerColor) - internal.updateCardDisplay(currentCardIndex) - local hook = getObjectFromGUID(cameraHookGuid) + internal.updateCardDisplay(playerColor) + local hook = getObjectFromGUID(tourState[playerColor].cameraHookGuid) hook.setPositionSmooth(CAMERA_HOME, false, false) local delay = 0.5 - if TOUR_SCRIPT[currentCardIndex].showObj ~= nil then + local cardIndex = tourState[playerColor].currentCardIndex + if TOUR_SCRIPT[cardIndex].showObj ~= nil then Wait.time(function() - local lookAtObj = getObjectFromGUID(TOUR_SCRIPT[currentCardIndex].showObj) + local lookAtObj = getObjectFromGUID(TOUR_SCRIPT[cardIndex].showObj) hook.setPositionSmooth(lookAtObj.getPosition(), false, false) end, delay) delay = delay + 0.5 end - Wait.time(function() Global.UI.show(cardId) end, delay) + Wait.time(function() Global.UI.show(internal.getUiId(CARD_ID, playerColor)) end, delay) end -- Hides the current card being shown to a player. This can be in preparation for showing the -- next card, or ending the tour. -- @param playerColor Player color to hide the current card for internal.hideCard = function(playerColor) - Global.UI.hide(cardId) + Global.UI.hide(internal.getUiId(CARD_ID, playerColor)) end -- Cleans up all the various resources associated with the tour, and (hopefully) resets the @@ -97,22 +106,23 @@ do -- should include instructions for the player to fix it. -- @param playerColor Player color to clean up internal.finalizeTour = function(playerColor) - local cameraHook = getObjectFromGUID(cameraHookGuid) + local cameraHook = getObjectFromGUID(tourState[playerColor].cameraHookGuid) cameraHook.destruct() - Player["White"].setCameraMode("ThirdPerson") + Player[playerColor].setCameraMode("ThirdPerson") + tourState[playerColor] = nil Wait.frames(function() -- This resets to the default camera position. If we don't place the camera exactly at the -- default, camera controls get weird - Player["White"].lookAt({position={-22.265,-2.5,5.2575},pitch=64.343,yaw=90.333,distance=104.7}) + Player[playerColor].lookAt({position={-22.265,-2.5,5.2575},pitch=64.343,yaw=90.333,distance=104.7}) end, 3) end -- Updates the card UI to show the appropriate narrator and text. - -- @param index Script entry which should be shown -- @param playerColor Player color to update card for - internal.updateCardDisplay = function(index, playerColor) - Global.UI.setAttribute(narratorId, "image", TOUR_SCRIPT[index].narrator) - Global.UI.setAttribute(textId, "text", TOUR_SCRIPT[index].text) + internal.updateCardDisplay = function(playerColor) + local index = tourState[playerColor].currentCardIndex + Global.UI.setAttribute(internal.getUiId(NARRATOR_ID, playerColor), "image", TOUR_SCRIPT[index].narrator) + Global.UI.setAttribute(internal.getUiId(TEXT_ID, playerColor), "text", TOUR_SCRIPT[index].text) end -- Creates a small, transparent object which the camera will be attached to in order to move the @@ -121,6 +131,8 @@ do -- shown. -- @param playerColor Player color to create the hook for internal.createCameraHook = function(playerColor) + log("Creating") + log(playerColor) local hookData = { Name = "BlockSquare", Transform = { @@ -141,6 +153,7 @@ do a = 0, }, Locked = true, + GMNotes = playerColor } spawnObjectData({ data = hookData, callback_function = internal.onHookCreated }) @@ -150,32 +163,36 @@ do -- (presumably first) card. -- @param hook Created object internal.onHookCreated = function(hook) - cameraHookGuid = hook.getGUID() - Player.White.attachCameraToObject({ + local playerColor = hook.getGMNotes() + log("Hook created") + log(playerColor) + tourState[playerColor].cameraHookGuid = hook.getGUID() + Player[playerColor].attachCameraToObject({ object = hook, offset = { x = -20, y = 30, z = 0 } }) - internal.showCurrentCard() + internal.showCurrentCard(playerColor) end -- Creates an XMLUI entry in Global for a player-specific tour card. Dynamically creating this -- is somewhat complex, but ensures we can properly handle any player color. -- @param playerColor Player color to create the card for internal.createTourCard = function(playerColor) - if Global.UI.getAttributes("cardId_"..playerColor) ~= nil then + -- Make sure the card doesn't exist before we create a new one + if Global.UI.getAttributes(internal.getUiId(CARD_ID, playerColor)) ~= nil then return end - cardId = cardId .. "_" .. playerColor - narratorId = narratorId .. "_" .. playerColor - textId = textId .. "_" .. playerColor - nextButtonId = nextButtonId .. "_" .. playerColor - stopButtonId = stopButtonId .. "_" .. playerColor - tourCardTemplate.attributes.id = cardId + CARD_ID = CARD_ID .. "_" .. playerColor + NARRATOR_ID = NARRATOR_ID .. "_" .. playerColor + TEXT_ID = TEXT_ID .. "_" .. playerColor + NEXT_BUTTON_ID = NEXT_BUTTON_ID .. "_" .. playerColor + STOP_BUTTON_ID = STOP_BUTTON_ID .. "_" .. playerColor + tourCardTemplate.attributes.id = internal.getUiId(CARD_ID, playerColor) tourCardTemplate.attributes.visibility = playerColor - tourCardTemplate.children[1].attributes.id = narratorId - tourCardTemplate.children[2].children[1].attributes.id = textId - tourCardTemplate.children[3].attributes.id = nextButtonId - tourCardTemplate.children[4].attributes.id = stopButtonId + tourCardTemplate.children[1].attributes.id = internal.getUiId(NARRATOR_ID, playerColor) + tourCardTemplate.children[2].children[1].attributes.id = internal.getUiId(TEXT_ID, playerColor) + tourCardTemplate.children[3].attributes.id = internal.getUiId(NEXT_BUTTON_ID, playerColor) + tourCardTemplate.children[4].attributes.id = internal.getUiId(STOP_BUTTON_ID, playerColor) tourCardTemplate.children[3].attributes.onClick = self.getGUID().."/nextCard" tourCardTemplate.children[4].attributes.onClick = self.getGUID().."/stopTour" @@ -184,5 +201,9 @@ do Global.UI.setXmlTable(globalXml) end + internal.getUiId = function(baseId, playerColor) + return baseId .. "_" .. playerColor + end + return TourManager end