optimization

This commit is contained in:
Chr1Z93 2023-02-04 00:36:46 +01:00
parent 77d0339354
commit 8bef677eda
3 changed files with 142 additions and 94 deletions

View File

@ -141,13 +141,17 @@ function onObjectPickUp(player, object)
if showLocationLinks() and isInPlayArea(object) and object.getGMNotes() ~= nil and object.getGMNotes() ~= "" then
local pickedUpGuid = object.getGUID()
local metadata = JSON.decode(object.getGMNotes()) or { }
if (metadata.type == "Location") then
if metadata.type == "Location" then
-- onCollisionExit sometimes comes 1 frame after onObjectPickUp (rather than before it or in
-- the same frame). This causes a mismatch in the data between dragging the on-table, and
-- that one frame draws connectors on the card which then show up as shadows for snap points.
-- Waiting ensures we always do thing in the expected Exit->PickUp order
Wait.frames(function()
draggingGuids[pickedUpGuid] = metadata
if object.is_face_down then
draggingGuids[pickedUpGuid] = metadata.locationBack
else
draggingGuids[pickedUpGuid] = metadata.locationFront
end
rebuildConnectionList()
end, 2)
end
@ -187,12 +191,20 @@ end
function maybeTrackLocation(card)
-- Collision checks for any part of the card overlap, but our other tracking is centerpoint
-- Ignore any collision where the centerpoint isn't in the area
if showLocationLinks() and isInPlayArea(card) then
if isInPlayArea(card) then
local metadata = JSON.decode(card.getGMNotes()) or { }
if metadata.type == "Location" then
locations[card.getGUID()] = metadata
rebuildConnectionList()
drawBaseConnections()
if card.is_face_down then
locations[card.getGUID()] = metadata.locationBack
else
locations[card.getGUID()] = metadata.locationFront
end
-- only draw connection lines for not-excluded scenarios
if showLocationLinks() then
rebuildConnectionList()
drawBaseConnections()
end
end
end
end
@ -238,20 +250,20 @@ function rebuildConnectionList()
-- Build a list of cards with each icon as their location ID
for cardId, metadata in pairs(draggingGuids) do
buildLocListByIcon(cardId, iconCardList)
buildLocListByIcon(cardId, iconCardList, metadata)
end
for cardId, metadata in pairs(locations) do
buildLocListByIcon(cardId, iconCardList)
buildLocListByIcon(cardId, iconCardList, metadata)
end
-- Pair up all the icons
locationConnections = { }
for cardId, metadata in pairs(draggingGuids) do
buildConnection(cardId, iconCardList)
buildConnection(cardId, iconCardList, metadata)
end
for cardId, metadata in pairs(locations) do
if draggingGuids[cardId] == nil then
buildConnection(cardId, iconCardList)
buildConnection(cardId, iconCardList, metadata)
end
end
end
@ -259,15 +271,14 @@ end
-- Extracts the card's icon string into a list of individual location icons
---@param cardID String GUID of the card to pull the icon data from
---@param iconCardList Table A table of icon->GUID list. Mutable, will be updated by this method
function buildLocListByIcon(cardId, iconCardList)
local card = getObjectFromGUID(cardId)
local locData = getLocationData(card)
---@param locData Table A table containing the metadata for the card (for the correct side)
function buildLocListByIcon(cardId, iconCardList, locData)
if locData ~= nil and locData.icons ~= nil then
for icon in string.gmatch(locData.icons, "%a+") do
if iconCardList[icon] == nil then
iconCardList[icon] = { }
end
table.insert(iconCardList[icon], card.getGUID())
table.insert(iconCardList[icon], cardId)
end
end
end
@ -276,25 +287,24 @@ end
-- Playarea's locationConnections table.
---@param cardId String GUID of the card to build the connections for
---@param iconCardList Table A table of icon->GUID List. Used to find matching icons for connections.
function buildConnection(cardId, iconCardList)
local card = getObjectFromGUID(cardId)
local locData = getLocationData(card)
---@param locData Table A table containing the metadata for the card (for the correct side)
function buildConnection(cardId, iconCardList, locData)
if locData ~= nil and locData.connections ~= nil then
locationConnections[card.getGUID()] = { }
locationConnections[cardId] = { }
for icon in string.gmatch(locData.connections, "%a+") do
if iconCardList[icon] ~= nil then
for _, connectedGuid in ipairs(iconCardList[icon]) do
-- If the reciprocal exists, convert it to BiDi, otherwise add as a one-way
if locationConnections[connectedGuid] ~= nil
and locationConnections[connectedGuid][card.getGUID()] == ONE_WAY then
locationConnections[connectedGuid][card.getGUID()] = BIDIRECTIONAL
locationConnections[card.getGUID()][connectedGuid] = nil
and locationConnections[connectedGuid][cardId] == ONE_WAY then
locationConnections[connectedGuid][cardId] = BIDIRECTIONAL
locationConnections[cardId][connectedGuid] = nil
else
if locationConnections[connectedGuid] == nil then
locationConnections[connectedGuid] = { }
end
locationConnections[card.getGUID()][connectedGuid] = ONE_WAY
locationConnections[connectedGuid][card.getGUID()] = INCOMING_ONE_WAY
locationConnections[cardId][connectedGuid] = ONE_WAY
locationConnections[connectedGuid][cardId] = INCOMING_ONE_WAY
end
end
end
@ -302,22 +312,6 @@ function buildConnection(cardId, iconCardList)
end
end
-- Helper method to extract the location metadata from a card based on whether it's front or back
-- is showing.
---@param card String Card object to extract data from
---@return. Table with either the locationFront or locationBack metadata structure, or nil if the
-- metadata doesn't exist
function getLocationData(card)
if card == nil then
return nil
end
if card.is_face_down then
return JSON.decode(card.getGMNotes()).locationBack
else
return JSON.decode(card.getGMNotes()).locationFront
end
end
-- Draws the lines for connections currently in locationConnections but not in draggingGuids.
-- Constructed vectors will be set to the playmat
function drawBaseConnections()
@ -552,6 +546,48 @@ function setLimitSnapsByType(matchTypes)
self.setSnapPoints(snaps)
end
-- count victory points on locations in play area
---@return. Returns the total amount of VP found in the play area
function countVP()
local totalVP = 0
for cardId, metadata in pairs(locations) do
if metadata ~= nil then
local cardVP = tonumber(metadata.victory) or 0
if cardVP ~= 0 and not cardHasClues(cardId) then
totalVP = totalVP + cardVP
end
end
end
return totalVP
end
-- checks if a card has clues on it, returns true if clues are on it
---@param cardId String GUID of the card to check for clues
function cardHasClues(cardId)
local card = getObjectFromGUID(cardId)
for _, v in ipairs(searchOnObj(card)) do
local obj = v.hit_object
if obj.memo == "clueDoom" and obj.is_face_down == false then
return true
end
end
return false
end
-- searches on an object (by using its bounds)
---@param obj Object Object to search on
function searchOnObj(obj)
return Physics.cast({
direction = { 0, 1, 0 },
max_distance = 0.5,
type = 3,
size = obj.getBounds().size,
origin = obj.getPosition()
})
end
-- rebuilds local snap points (could be useful in the future again)
function buildSnaps()
local upperleft = { x = 1.53, z = -1.09}

View File

@ -55,6 +55,11 @@ do
{ container = container, object = object })
end
-- counts the VP on locations in the play area
PlayAreaApi.countVP = function()
return getObjectFromGUID(PLAY_AREA_GUID).call("countVP")
end
-- Checks if an object is in the play area (returns true or false)
PlayAreaApi.isInPlayArea = function(object)
return getObjectFromGUID(PLAY_AREA_GUID).call("isInPlayArea", object)

View File

@ -1,11 +1,8 @@
local playAreaApi = require("core/PlayAreaApi")
local pendingCall = false
local messageSent = {}
local victoryPoints = {
display = 0,
playArea = 0
}
-- button creation when loading the game
function onLoad()
-- index 0: VP - "Display"
local buttonParameters = {}
@ -17,7 +14,7 @@ function onLoad()
buttonParameters.height = 0
buttonParameters.font_size = 600
buttonParameters.font_color = { 1, 1, 1 }
buttonParameters.position = { x = -0.71, y = 0.06, z = -0.69 }
buttonParameters.position = { x = -0.72, y = 0.06, z = -0.69 }
self.createButton(buttonParameters)
-- index 1: VP - "Play Area"
@ -25,63 +22,91 @@ function onLoad()
self.createButton(buttonParameters)
-- index 2: VP - "Total"
buttonParameters.position.x = 1.685
buttonParameters.position.x = 1.69
self.createButton(buttonParameters)
-- update the display label once
Wait.time(updateCount, 1)
end
-- automatically update when cards are dropped or removed
---------------------------------------------------------
-- events with descriptions
---------------------------------------------------------
-- dropping an object on the victory display
function onCollisionEnter()
updateCount()
-- stop if there is already an update call running
if pendingCall then return end
pendingCall = true
Wait.time(updateCount, 0.2)
end
-- removing an object from the victory display
function onCollisionExit()
updateCount()
-- stop if there is already an update call running
if pendingCall then return end
pendingCall = true
Wait.time(updateCount, 0.2)
end
-- picking a clue or location up
function onObjectPickUp(_, obj)
maybeUpdate(obj)
end
-- dropping a clue or location
function onObjectDrop(_, obj)
maybeUpdate(obj, 1)
end
-- flipping a clue/doom or location
function onObjectRotate(obj, _, flip, _, _, oldFlip)
if flip == oldFlip then return end
maybeUpdate(obj, 1, true)
end
-- destroying a clue or location
function onObjectDestroy(obj)
maybeUpdate(obj)
end
---------------------------------------------------------
-- main functionality
---------------------------------------------------------
function maybeUpdate(obj, delay, flipped)
-- stop if there is already an update call running
if pendingCall then return end
-- stop if obj is nil (by e.g. dropping a clue onto another and making a stack)
if obj == nil then return end
if obj.memo ~= "clueDoom" then return end
if obj.is_face_down == true and flipped ~= true then return end
if not playAreaApi.isInPlayArea(obj) then return end
delay = tonumber(delay) or 0
Wait.time(function() updateCount() end, delay)
end
function isClue(obj)
return obj.memo == "clueDoom" and obj.is_face_down == false
end
-- works as a sinkhole for all refresh calls
function updateCount()
if not pendingCall then
pendingCall = true
Wait.time(function() updateCountNow() end, 0.2)
-- only continue for clues / doom tokens or locations
if obj.hasTag("Location") then
elseif obj.memo == "clueDoom" then
-- only continue if the clue side is up or a doom token is being flipped
if obj.is_face_down == true and flipped ~= true then return end
else
return
end
-- only continue if the obj in in the play area
if not playAreaApi.isInPlayArea(obj) then return end
-- set this flag to limit function calls (will be reset by "updateCount")
pendingCall = true
-- update the count with delay (or 0 if no delay is provided)
-- this is needed to let tokens drop on the card
delay = tonumber(delay) or 0
Wait.time(updateCount, delay + 0.2)
end
function updateCountNow()
-- counts the VP in the victory display and request the VP count from the play area
function updateCount()
local victoryPoints = {}
victoryPoints.display = 0
victoryPoints.playArea = 0
victoryPoints.playArea = playAreaApi.countVP()
-- count cards in victory display
for _, v in ipairs(searchOnObj(self)) do
@ -102,29 +127,16 @@ function updateCountNow()
end
end
-- count locations in playArea
local playArea = getObjectFromGUID("721ba2")
for _, v in ipairs(searchOnObj(playArea)) do
local obj = v.hit_object
local cardVP = 0
if obj.hasTag("Location") then
cardVP = getCardVP(obj.is_face_down, JSON.decode(obj.getGMNotes())) or 0
if cardVP ~= 0 and not cardHasClues(obj) then
victoryPoints.playArea = victoryPoints.playArea + cardVP
end
end
end
pendingCall = false
updateVP()
end
function updateVP()
-- update the buttons that are used as labels
self.editButton({ index = 0, label = victoryPoints.display })
self.editButton({ index = 1, label = victoryPoints.playArea })
self.editButton({ index = 2, label = victoryPoints.display + victoryPoints.playArea })
-- allow new update calls
pendingCall = false
end
-- sends a message for cards in the victory display that don't have VP
function addOrSendMessage(addition, name)
if tonumber(addition) ~= nil then
return tonumber(addition)
@ -135,17 +147,6 @@ function addOrSendMessage(addition, name)
return 0
end
-- checks if a card has clues on it
function cardHasClues(card)
for _, v in ipairs(searchOnObj(card)) do
local obj = v.hit_object
if isClue(obj) then
return true
end
end
return false
end
-- gets the VP count from the notes
function getCardVP(faceDown, notes)
local cardVP
@ -155,6 +156,7 @@ function getCardVP(faceDown, notes)
-- location
if not cardVP then
-- check the correct side of the location
if not faceDown and notes.locationFront ~= nil then
cardVP = tonumber(notes.locationFront.victory)
elseif notes.locationBack ~= nil then
@ -165,6 +167,11 @@ function getCardVP(faceDown, notes)
return cardVP
end
---------------------------------------------------------
-- utility functions
---------------------------------------------------------
-- searches on an object
function searchOnObj(obj)
return Physics.cast({
direction = { 0, 1, 0 },