Merge pull request #128 from argonui/tour

SCED Intro Tour, Part 5
This commit is contained in:
Buhallin 2022-12-23 23:57:13 -08:00 committed by GitHub
commit ff7ed57bca
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 174 additions and 26 deletions

View File

@ -100,7 +100,7 @@
"URL": "https://i.imgur.com/6MReiEO.png" "URL": "https://i.imgur.com/6MReiEO.png"
}, },
{ {
"Name": "Roland", "Name": "Inv-Roland",
"Type": 0, "Type": 0,
"URL": "https://i.imgur.com/lx6unDY.png" "URL": "https://i.imgur.com/lx6unDY.png"
}, },
@ -113,5 +113,80 @@
"Name": "Exit", "Name": "Exit",
"Type": 0, "Type": 0,
"URL": "https://i.imgur.com/i0VMjPD.png" "URL": "https://i.imgur.com/i0VMjPD.png"
},
{
"Name": "Inv-Mandy",
"Type": 0,
"URL": "https://i.imgur.com/hniMC5g.png"
},
{
"Name": "Inv-Preston",
"Type": 0,
"URL": "https://i.imgur.com/7IoOGjh.png"
},
{
"Name": "Inv-Diana",
"Type": 0,
"URL": "https://i.imgur.com/Tajp04v.png"
},
{
"Name": "Inv-Leo",
"Type": 0,
"URL": "https://i.imgur.com/UUBKRiV.png"
},
{
"Name": "Inv-Daisy",
"Type": 0,
"URL": "https://i.imgur.com/zfqiSJz.png"
},
{
"Name": "Inv-Winifred",
"Type": 0,
"URL": "https://i.imgur.com/vDNy6fD.png"
},
{
"Name": "Inv-Stella",
"Type": 0,
"URL": "https://i.imgur.com/OgIv9N4.png"
},
{
"Name": "Inv-Gloria",
"Type": 0,
"URL": "https://i.imgur.com/xtYVdEL.png"
},
{
"Name": "Inv-Monterey",
"Type": 0,
"URL": "https://i.imgur.com/CWebh2L.png"
},
{
"Name": "Inv-Daniela",
"Type": 0,
"URL": "https://i.imgur.com/XZ35Nnk.png"
},
{
"Name": "Inv-Darrell",
"Type": 0,
"URL": "https://i.imgur.com/rEOtrUp.png"
},
{
"Name": "Inv-Norman",
"Type": 0,
"URL": "https://i.imgur.com/96URPj3.png"
},
{
"Name": "Inv-Finn",
"Type": 0,
"URL": "https://i.imgur.com/NFtlgA1.png"
},
{
"Name": "Inv-Amina",
"Type": 0,
"URL": "https://i.imgur.com/cWhSRN3.png"
},
{
"Name": "Inv-Jacqueline",
"Type": 0,
"URL": "https://i.imgur.com/AFuB9II.png"
} }
] ]

View File

@ -53,7 +53,7 @@ tourCardTemplate = {
tag = "Text", tag = "Text",
attributes = { attributes = {
id = "tourText", id = "tourText",
height = 150, height = 165,
width = 230, width = 230,
rectAlignment = "UpperCenter", rectAlignment = "UpperCenter",
offsetXY = "15 -15", offsetXY = "15 -15",

View File

@ -48,7 +48,7 @@ do
-- 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 String Player color to start the tour for
TourManager.startTour = function(playerColor) TourManager.startTour = function(playerColor)
tourState[playerColor] = { tourState[playerColor] = {
currentCardIndex = 1 currentCardIndex = 1
@ -107,13 +107,17 @@ do
-- 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 String Player color to show the current card for
internal.showCurrentCard = function(playerColor) internal.showCurrentCard = function(playerColor)
internal.updateCardDisplay(playerColor) internal.updateCardDisplay(playerColor)
local hook = getObjectFromGUID(tourState[playerColor].cameraHookGuid) local delay = 0
hook.setPositionSmooth(HOOK_CAMERA_HOME, false, false)
local delay = 0.5
local cardIndex = tourState[playerColor].currentCardIndex local cardIndex = tourState[playerColor].currentCardIndex
local hook = getObjectFromGUID(tourState[playerColor].cameraHookGuid)
if not TOUR_SCRIPT[cardIndex].skipCentering then
hook.setPositionSmooth(HOOK_CAMERA_HOME, false, false)
delay = delay + 0.5
end
local lookPos local lookPos
if TOUR_SCRIPT[cardIndex].showObj ~= nil then if TOUR_SCRIPT[cardIndex].showObj ~= nil then
local lookAtObj = getObjectFromGUID(TOUR_SCRIPT[cardIndex].showObj) local lookAtObj = getObjectFromGUID(TOUR_SCRIPT[cardIndex].showObj)
@ -137,7 +141,7 @@ do
-- 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 String Player color to hide the current card for
internal.hideCard = function(playerColor) internal.hideCard = function(playerColor)
Global.UI.hide(internal.getUiId(CARD_ID, playerColor)) Global.UI.hide(internal.getUiId(CARD_ID, playerColor))
end end
@ -145,7 +149,7 @@ do
-- 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 String Player color to clean up
internal.finalizeTour = function(playerColor) internal.finalizeTour = function(playerColor)
local cameraHook = getObjectFromGUID(tourState[playerColor].cameraHookGuid) local cameraHook = getObjectFromGUID(tourState[playerColor].cameraHookGuid)
cameraHook.destruct() cameraHook.destruct()
@ -157,14 +161,15 @@ do
end end
-- Updates the card UI to show the appropriate card configuration. -- Updates the card UI to show the appropriate card configuration.
---@param playerColor Player color to update card for ---@param playerColor String Player color to update card for
internal.updateCardDisplay = function(playerColor) internal.updateCardDisplay = function(playerColor)
local index = tourState[playerColor].currentCardIndex local index = tourState[playerColor].currentCardIndex
Global.UI.setAttribute(internal.getUiId(LEFT_NARRATOR_ID, playerColor), "image", TOUR_SCRIPT[index].narrator) Global.UI.setAttribute(internal.getUiId(LEFT_NARRATOR_ID, playerColor), "image", "Inv-" .. TOUR_SCRIPT[index].narrator)
Global.UI.setAttribute(internal.getUiId(RIGHT_NARRATOR_ID, playerColor), "image", TOUR_SCRIPT[index].narrator) Global.UI.setAttribute(internal.getUiId(RIGHT_NARRATOR_ID, playerColor), "image", "Inv-" .. TOUR_SCRIPT[index].narrator)
Global.UI.setAttribute(internal.getUiId(TEXT_ID, playerColor), "text", TOUR_SCRIPT[index].text) Global.UI.setAttribute(internal.getUiId(TEXT_ID, playerColor), "text", "\"" .. TOUR_SCRIPT[index].text .. "\"")
local cardPos = TOUR_SCRIPT[index].position or "north" local cardPos = TOUR_SCRIPT[index].position or "north"
Global.UI.setAttribute(internal.getUiId(CARD_ID, playerColor), "position", SCREEN_POSITIONS[cardPos]) Global.UI.setAttribute(internal.getUiId(CARD_ID, playerColor), "position", SCREEN_POSITIONS[cardPos])
Global.UI.setAttribute(internal.getUiId(NEXT_BUTTON_ID, playerColor), "active", index < #TOUR_SCRIPT)
-- Adjust images so the narrator is on the left or right, as defined by the card -- Adjust images so the narrator is on the left or right, as defined by the card
if TOUR_SCRIPT[index].speakerSide == "right" then if TOUR_SCRIPT[index].speakerSide == "right" then
@ -188,7 +193,7 @@ do
-- 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 String Player color to create the hook for
internal.createCameraHook = function(playerColor) internal.createCameraHook = function(playerColor)
local hookData = { local hookData = {
Name = "BlockSquare", Name = "BlockSquare",
@ -231,7 +236,7 @@ do
-- 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 String Player color to create the card for
internal.createTourCard = function(playerColor) internal.createTourCard = function(playerColor)
-- Make sure the card doesn't exist before we create a new one -- Make sure the card doesn't exist before we create a new one
if Global.UI.getAttributes(internal.getUiId(CARD_ID, playerColor)) ~= nil then if Global.UI.getAttributes(internal.getUiId(CARD_ID, playerColor)) ~= nil then

View File

@ -7,24 +7,92 @@ TOUR_SCRIPT = {
position = "center" position = "center"
}, },
{ {
narrator = "Mandy", narrator = "Darrell",
text = "To survive this, you'll need a deck. If it's safely hidden away on ArkhamDB I can look it up for you, and even find the newest version from the ID.", text = "Cameras can be tricky things. Best you leave handling it to the professionals during the tour. Don't try to move the camera until the tour is complete.\n\nOnce we're done, remmeber you can use the 'p' key to switch back to third-person mode, and the spacebar to reset the position.",
showObj = "a28140", position = "center",
distanceFromObj = -10, speakerSide = "right",
position = "west", },
{
narrator = "Daisy",
text = "If you're new to the game, the library here has everything you'll need. I don't much care for guns, but if you're looking for more in-depth tutorials you can find them inside that automatic above the table.",
showObj = "d99993",
distanceFromObj = 20,
position = "north",
speakerSide = "right" speakerSide = "right"
}, },
{ {
narrator = "Daniela", narrator = "Mandy",
text = "If you're like me and prefer the hands-on approach, you can build a deck yourself.\n\nThese containers have all the Level 0 cards for each class. Once you've had a run-in with the horrors lurking out there, you can find higher level cards to the right.", text = "To survive what's coming you'll need a deck. If it's safely hidden away on ArkhamDB you can load it here, and even find the newest version after an upgrade without changing the ID.\n\nNo need to publish all your decks, use 'Private' and you can see it. Just make sure to select 'Make your decks public' in ArkhamDB.",
showObj = "7e47e1", showObj = "a28140",
distanceFromObj = -10, distanceFromObj = -10,
position = "center", position = "west",
}, },
{ {
narrator = "Daniela", narrator = "Daniela",
text = "This is a position test.", text = "I prefer the hands-on approach to building things, if you do too you can build a deck yourself.\n\nThese containers have all the Level 0 cards for each class. Once you've had a run-in with the horrors lurking out there, you can find higher level cards to the right.",
showPos = { x = -40.14, y = -10, z = 4.19 }, showObj = "7e47e1",
distanceFromObj = -10,
position = "south",
speakerSide = "right"
},
{
narrator = "Leo",
text = "We're all here. Those of us who have chosen to stand up to the evils few even know exist. It's a hard, bloody battle and many have fallen. But the world is safe, at least for now.\n\nIf you're building a deck and need investigator cards and our signature tricks, here's where you find them.",
showObj = "899c3a",
distanceFromObj = 10,
position = "northeast",
speakerSide = "right"
},
{
narrator = "Finn",
text = "Ready to face the unknown? We've smuggled shocking revelations and devious enemies from all over the world. Download the campaign you want to play, then Place it on the table to see the scenarios.\n\nJust remember - if it turns out to be too much for you, I was never here.",
showObj = "aca04c",
distanceFromObj = 10,
position = "south", position = "south",
}, },
{
narrator = "Diana",
text = "These symbols on the bottom right are a repository of arcane knowledge, containing all the official content to download plus some deviously creative works from fans. One should beware those who seem too fond of the darkness, but you cannot deny the quality of their efforts.\n\nDon't see anything here? Only promoted players can access these.",
position = "southeast",
},
{
narrator = "Winifred",
text = "No good aviator would fly a plane she didn't know and hadn't tweaked a bit herself. The gear icon contains settings to customize your play experience, from alternate ways to track your clues to a variety of helpers to streamline the game.\n\nEverything here is optional, but who doesn't want to go as fast as they can? Just remember that all settings affect all players, so strap in and trust your pilot!",
position = "southeast",
},
{
narrator = "Amina",
text = "This is the Mythos area. Encounter cards, acts, and agenda will all be placed here while the large map below is where you will be exploring - be sure to set the number of investigators!\n\nYou can count doom on the agenda by clicking the large counter, and the smaller will automatically count doom tokens on the table. The chaos bag is in that book over on the right, and you can add or remove tokens from it whenever you need.",
showPos = { x = -2.85, y = 0, z = 0.55 },
position = "north",
speakerSide = "right"
},
{
narrator = "Gloria",
text = "The evils that lurk in this world are out there, creeping ever closer. When they find you, this will easily draw a card from the encounter deck. The deck will even reshuffle itself when needed, for the enemies we face are unending.",
showPos = { x = -35, y = -20, z = 28 },
position = "west",
},
{
narrator = "Jacqueline",
text = "When the ire of fate finds you and the chaos looms, this large button will draw a chaos token. Click it again to return the token to the bag.\n\nWhether a vision of the future or a curse from the opponents we face, if you need additional tokens a right-click will draw more. I wish you luck, but have a vision of red tentacles reaching for you...",
showPos = { x = -35, y = -20, z = 4.25 },
position = "north",
skipCentering = true,
speakerSide = "right"
},
{
narrator = "Preston",
text = "I can afford to buy what I need, but for those less well-off we've provided an endless pool of tokens to track your game. Simply drag one out of the pools here.\n\nResources are my favorite, of course, but damage and horror are as inevitable as taxes, though I leave those to my bookkeeper. Those tokens can work like counters, use the number keys to change the value.",
showObj = "9fadf9",
position = "north",
skipCentering = true,
speakerSide = "right"
},
{
narrator = "Norman",
text = "That's the end of the tour, but there's much more to discover if you look in the right places. Some cards have helpers on the right-click menu, and every new version adds new content and functions.\n\nDon't be afraid to explore, and best of luck out there! We'll all need it...",
position = "center",
speakerSide = "right"
},
} }