Merge pull request #96 from argonui/tour

SCED Intro Tour, Part 2
This commit is contained in:
Chr1Z 2022-12-14 12:02:06 +01:00 committed by GitHub
commit 31a471d648
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

View File

@ -5,11 +5,11 @@ do
local internal = { } local internal = { }
-- Base IDs for various tour card UI elements. Actual IDs will have _[playerColor] appended -- Base IDs for various tour card UI elements. Actual IDs will have _[playerColor] appended
local cardId = "tourCard" local CARD_ID = "tourCard"
local narratorId = "tourNarratorImage" local NARRATOR_ID = "tourNarratorImage"
local textId = "tourText" local TEXT_ID = "tourText"
local nextButtonId = "tourNext" local NEXT_BUTTON_ID = "tourNext"
local stopButtonId = "tourStop" local STOP_BUTTON_ID = "tourStop"
-- Table centerpoint for the camera hook object. Camera handling is a bit erratic so it doesn't -- 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 -- always land right where you think it's going to, but it's close
@ -19,107 +19,117 @@ do
z = 0, z = 0,
} }
local cameraHookGuid -- Tracks the current state of the tours. Keyed by player color to keep each player's tour
local currentCardIndex -- separate, will hold the camera hook and current card.
local tourState = { }
-- Kicks off the tour by initializing the card and camera hook. A callback on the hook creation -- Kicks off the tour by initializing the card and camera hook. A callback on the hook creation
-- will then show the first card. -- will then show the first card.
-- @param playerColor Player color to start the tour for ---@param playerColor Player color to start the tour for
TourManager.startTour = function(playerColor) TourManager.startTour = function(playerColor)
currentCardIndex = 1 tourState[playerColor] = {
-- Camera gets really screwy when we finalize if we don't start in ThirdPerson before attaching currentCardIndex = 1
-- to the hook }
Player["White"].setCameraMode("ThirdPerson") -- Camera gets really screwy when we finalize if we don't start settled in ThirdPerson at the
internal.createTourCard("White") -- default position before attaching to the hook. Unfortunately there are no callbacks for when
-- XML update takes time to load, wait for it to finish then create the hook -- the movement is done, but the 2 sec seems to handle it
Wait.condition( Player[playerColor].setCameraMode("ThirdPerson")
function() Player[playerColor].lookAt({position={-22.265,-2.5,5.2575},pitch=64.343,yaw=90.333,distance=104.7})
internal.createCameraHook() Wait.time(function()
end, internal.createTourCard(playerColor)
function() -- XML update to add the new card takes a few frames to load, wait for it to finish then
return not Global.UI.loading -- create the hook
end Wait.condition(
) function()
internal.createCameraHook(playerColor)
end,
function()
return not Global.UI.loading
end
)
end, 2)
end end
-- Shows the next card in the tour script. This method is exposed (rather than being part of -- 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. -- internal) because the XMLUI callbacks expect the method to be on the object directly.
-- @param playerColor Player color to show the next card for ---@param player Player object to show the next card for, provided by XMLUI callback
function nextCard(playerColor) function nextCard(player)
internal.hideCard() internal.hideCard(player.color)
Wait.time(function() Wait.time(function()
currentCardIndex = currentCardIndex + 1 tourState[player.color].currentCardIndex = tourState[player.color].currentCardIndex + 1
if currentCardIndex > #TOUR_SCRIPT then if tourState[player.color].currentCardIndex > #TOUR_SCRIPT then
internal.finalizeTour() internal.finalizeTour(player.color)
else else
internal.showCurrentCard() internal.showCurrentCard(player.color)
end end
end, 0.3) end, 0.3)
end end
-- Ends the tour and cleans up the camera. This method is exposed (rather than being part of -- 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. -- internal) because the XMLUI callbacks expect the method to be on the object directly.
-- @param playerColor Player color to end the tour for ---@param player Player object to end the tour for, provided by XMLUI callback
function stopTour(playerColor) function stopTour(player)
internal.hideCard() internal.hideCard(player.color)
Wait.time(function() Wait.time(function()
internal.finalizeTour() internal.finalizeTour(player.color)
end, 0.3) end, 0.3)
end end
-- Updates the card UI for the script at the current index, moves the camera to the proper -- Updates the card UI for the script at the current index, moves the camera to the proper
-- position, and shows the card. -- position, and shows the card.
-- @param playerColor Player color to show the current card for ---@param playerColor Player color to show the current card for
internal.showCurrentCard = function(playerColor) internal.showCurrentCard = function(playerColor)
internal.updateCardDisplay(currentCardIndex) internal.updateCardDisplay(playerColor)
local hook = getObjectFromGUID(cameraHookGuid) local hook = getObjectFromGUID(tourState[playerColor].cameraHookGuid)
hook.setPositionSmooth(CAMERA_HOME, false, false) hook.setPositionSmooth(CAMERA_HOME, false, false)
local delay = 0.5 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() Wait.time(function()
local lookAtObj = getObjectFromGUID(TOUR_SCRIPT[currentCardIndex].showObj) local lookAtObj = getObjectFromGUID(TOUR_SCRIPT[cardIndex].showObj)
hook.setPositionSmooth(lookAtObj.getPosition(), false, false) hook.setPositionSmooth(lookAtObj.getPosition(), false, false)
end, delay) end, delay)
delay = delay + 0.5 delay = delay + 0.5
end end
Wait.time(function() Global.UI.show(cardId) end, delay) Wait.time(function() Global.UI.show(internal.getUiId(CARD_ID, playerColor)) end, delay)
end end
-- Hides the current card being shown to a player. This can be in preparation for showing the -- Hides the current card being shown to a player. This can be in preparation for showing the
-- next card, or ending the tour. -- next card, or ending the tour.
-- @param playerColor Player color to hide the current card for ---@param playerColor Player color to hide the current card for
internal.hideCard = function(playerColor) internal.hideCard = function(playerColor)
Global.UI.hide(cardId) Global.UI.hide(internal.getUiId(CARD_ID, playerColor))
end end
-- Cleans up all the various resources associated with the tour, and (hopefully) resets the -- Cleans up all the various resources associated with the tour, and (hopefully) resets the
-- camera to the default position. Camera handling is erratic, the final card in the script -- camera to the default position. Camera handling is erratic, the final card in the script
-- should include instructions for the player to fix it. -- should include instructions for the player to fix it.
-- @param playerColor Player color to clean up ---@param playerColor Player color to clean up
internal.finalizeTour = function(playerColor) internal.finalizeTour = function(playerColor)
local cameraHook = getObjectFromGUID(cameraHookGuid) local cameraHook = getObjectFromGUID(tourState[playerColor].cameraHookGuid)
cameraHook.destruct() cameraHook.destruct()
Player["White"].setCameraMode("ThirdPerson") Player[playerColor].setCameraMode("ThirdPerson")
tourState[playerColor] = nil
Wait.frames(function() Wait.frames(function()
-- This resets to the default camera position. If we don't place the camera exactly at the -- This resets to the default camera position. If we don't place the camera exactly at the
-- default, camera controls get weird -- 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, 3)
end end
-- Updates the card UI to show the appropriate narrator and text. -- 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
-- @param playerColor Player color to update card for internal.updateCardDisplay = function(playerColor)
internal.updateCardDisplay = function(index, playerColor) local index = tourState[playerColor].currentCardIndex
Global.UI.setAttribute(narratorId, "image", TOUR_SCRIPT[index].narrator) Global.UI.setAttribute(internal.getUiId(NARRATOR_ID, playerColor), "image", TOUR_SCRIPT[index].narrator)
Global.UI.setAttribute(textId, "text", TOUR_SCRIPT[index].text) Global.UI.setAttribute(internal.getUiId(TEXT_ID, playerColor), "text", TOUR_SCRIPT[index].text)
end end
-- Creates a small, transparent object which the camera will be attached to in order to move the -- Creates a small, transparent object which the camera will be attached to in order to move the
-- user's view around the table. This should be called only at the beginning of the tour. Once -- user's view around the table. This should be called only at the beginning of the tour. Once
-- creation is complete the user's camera will be attached to the hook and the first card will be -- creation is complete the user's camera will be attached to the hook and the first card will be
-- shown. -- shown.
-- @param playerColor Player color to create the hook for ---@param playerColor Player color to create the hook for
internal.createCameraHook = function(playerColor) internal.createCameraHook = function(playerColor)
local hookData = { local hookData = {
Name = "BlockSquare", Name = "BlockSquare",
@ -141,6 +151,7 @@ do
a = 0, a = 0,
}, },
Locked = true, Locked = true,
GMNotes = playerColor
} }
spawnObjectData({ data = hookData, callback_function = internal.onHookCreated }) spawnObjectData({ data = hookData, callback_function = internal.onHookCreated })
@ -148,34 +159,31 @@ do
-- Callback for creation of the camera hook object. Will attach the camera and show the current -- Callback for creation of the camera hook object. Will attach the camera and show the current
-- (presumably first) card. -- (presumably first) card.
-- @param hook Created object ---@param hook Created object
internal.onHookCreated = function(hook) internal.onHookCreated = function(hook)
cameraHookGuid = hook.getGUID() local playerColor = hook.getGMNotes()
Player.White.attachCameraToObject({ tourState[playerColor].cameraHookGuid = hook.getGUID()
Player[playerColor].attachCameraToObject({
object = hook, object = hook,
offset = { x = -20, y = 30, z = 0 } offset = { x = -20, y = 30, z = 0 }
}) })
internal.showCurrentCard() internal.showCurrentCard(playerColor)
end end
-- Creates an XMLUI entry in Global for a player-specific tour card. Dynamically creating this -- 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. -- is somewhat complex, but ensures we can properly handle any player color.
-- @param playerColor Player color to create the card for ---@param playerColor Player color to create the card for
internal.createTourCard = function(playerColor) 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 return
end end
cardId = cardId .. "_" .. playerColor tourCardTemplate.attributes.id = internal.getUiId(CARD_ID, playerColor)
narratorId = narratorId .. "_" .. playerColor
textId = textId .. "_" .. playerColor
nextButtonId = nextButtonId .. "_" .. playerColor
stopButtonId = stopButtonId .. "_" .. playerColor
tourCardTemplate.attributes.id = cardId
tourCardTemplate.attributes.visibility = playerColor tourCardTemplate.attributes.visibility = playerColor
tourCardTemplate.children[1].attributes.id = narratorId tourCardTemplate.children[1].attributes.id = internal.getUiId(NARRATOR_ID, playerColor)
tourCardTemplate.children[2].children[1].attributes.id = textId tourCardTemplate.children[2].children[1].attributes.id = internal.getUiId(TEXT_ID, playerColor)
tourCardTemplate.children[3].attributes.id = nextButtonId tourCardTemplate.children[3].attributes.id = internal.getUiId(NEXT_BUTTON_ID, playerColor)
tourCardTemplate.children[4].attributes.id = stopButtonId tourCardTemplate.children[4].attributes.id = internal.getUiId(STOP_BUTTON_ID, playerColor)
tourCardTemplate.children[3].attributes.onClick = self.getGUID().."/nextCard" tourCardTemplate.children[3].attributes.onClick = self.getGUID().."/nextCard"
tourCardTemplate.children[4].attributes.onClick = self.getGUID().."/stopTour" tourCardTemplate.children[4].attributes.onClick = self.getGUID().."/stopTour"
@ -184,5 +192,9 @@ do
Global.UI.setXmlTable(globalXml) Global.UI.setXmlTable(globalXml)
end end
internal.getUiId = function(baseId, playerColor)
return baseId .. "_" .. playerColor
end
return TourManager return TourManager
end end