Merge branch 'playmat-zone' into playermats

This commit is contained in:
Chr1Z93 2023-09-29 22:54:57 +02:00
commit 2fd7656ab1
10 changed files with 81 additions and 302 deletions

View File

@ -103,10 +103,6 @@
"LegacyAssets.7165a9", "LegacyAssets.7165a9",
"PlayArea.721ba2", "PlayArea.721ba2",
"BarkhamHorror.308439", "BarkhamHorror.308439",
"ScriptingTrigger.fb28e1",
"ScriptingTrigger.7af2cf",
"ScriptingTrigger.b047f8",
"ScriptingTrigger.18538f",
"ChaosBagStatTracker.766620", "ChaosBagStatTracker.766620",
"Blesstokens.afa06b", "Blesstokens.afa06b",
"Cursetokens.bd0253", "Cursetokens.bd0253",

View File

@ -1 +1 @@
{"activeInvestigatorId":"00000","isDrawButtonVisible":false,"playerColor":"White","zoneID":"7af2cf"} {"activeInvestigatorId":"00000","isDrawButtonVisible":false,"playerColor":"White"}

View File

@ -1 +1 @@
{"activeInvestigatorId":"00000","isDrawButtonVisible":false,"playerColor":"Orange","zoneID":"b047f8"} {"activeInvestigatorId":"00000","isDrawButtonVisible":false,"playerColor":"Orange"}

View File

@ -1 +1 @@
{"activeInvestigatorId":"00000","isDrawButtonVisible":false,"playerColor":"Green","zoneID":"fb28e1"} {"activeInvestigatorId":"00000","isDrawButtonVisible":false,"playerColor":"Green"}

View File

@ -1 +1 @@
{"activeInvestigatorId":"00000","isDrawButtonVisible":false,"playerColor":"Red","zoneID":"18538f"} {"activeInvestigatorId":"00000","isDrawButtonVisible":false,"playerColor":"Red"}

View File

@ -1,46 +0,0 @@
{
"AltLookAngle": {
"x": 0,
"y": 0,
"z": 0
},
"Autoraise": true,
"ColorDiffuse": {
"a": 0.5098,
"b": 1,
"g": 1,
"r": 1
},
"Description": "",
"DragSelectable": true,
"GMNotes": "",
"GUID": "18538f",
"Grid": true,
"GridProjection": false,
"Hands": false,
"HideWhenFaceDown": false,
"IgnoreFoW": false,
"LayoutGroupSortIndex": 0,
"Locked": true,
"LuaScript": "",
"LuaScriptState": "",
"MeasureMovement": false,
"Name": "ScriptingTrigger",
"Nickname": "",
"Snap": true,
"Sticky": true,
"Tooltip": true,
"Transform": {
"posX": -18.8,
"posY": 1.481,
"posZ": -28.6,
"rotX": 0,
"rotY": 180,
"rotZ": 0,
"scaleX": 3,
"scaleY": 5,
"scaleZ": 8
},
"Value": 0,
"XmlUI": ""
}

View File

@ -1,46 +0,0 @@
{
"AltLookAngle": {
"x": 0,
"y": 0,
"z": 0
},
"Autoraise": true,
"ColorDiffuse": {
"a": 0.5098,
"b": 1,
"g": 1,
"r": 1
},
"Description": "",
"DragSelectable": true,
"GMNotes": "",
"GUID": "7af2cf",
"Grid": true,
"GridProjection": false,
"Hands": false,
"HideWhenFaceDown": false,
"IgnoreFoW": false,
"LayoutGroupSortIndex": 0,
"Locked": true,
"LuaScript": "",
"LuaScriptState": "",
"MeasureMovement": false,
"Name": "ScriptingTrigger",
"Nickname": "",
"Snap": true,
"Sticky": true,
"Tooltip": true,
"Transform": {
"posX": -57,
"posY": 1.544,
"posZ": 4.545,
"rotX": 0,
"rotY": 270,
"rotZ": 0,
"scaleX": 3,
"scaleY": 5,
"scaleZ": 8
},
"Value": 0,
"XmlUI": ""
}

View File

@ -1,46 +0,0 @@
{
"AltLookAngle": {
"x": 0,
"y": 0,
"z": 0
},
"Autoraise": true,
"ColorDiffuse": {
"a": 0.5098,
"b": 1,
"g": 1,
"r": 1
},
"Description": "",
"DragSelectable": true,
"GMNotes": "",
"GUID": "b047f8",
"Grid": true,
"GridProjection": false,
"Hands": false,
"HideWhenFaceDown": false,
"IgnoreFoW": false,
"LayoutGroupSortIndex": 0,
"Locked": true,
"LuaScript": "",
"LuaScriptState": "",
"MeasureMovement": false,
"Name": "ScriptingTrigger",
"Nickname": "",
"Snap": true,
"Sticky": true,
"Tooltip": true,
"Transform": {
"posX": -57,
"posY": 1.539,
"posZ": -27.65,
"rotX": 0,
"rotY": 270,
"rotZ": 0,
"scaleX": 3,
"scaleY": 5,
"scaleZ": 8
},
"Value": 0,
"XmlUI": ""
}

View File

@ -1,46 +0,0 @@
{
"AltLookAngle": {
"x": 0,
"y": 0,
"z": 0
},
"Autoraise": true,
"ColorDiffuse": {
"a": 0.5098,
"b": 1,
"g": 1,
"r": 1
},
"Description": "",
"DragSelectable": true,
"GMNotes": "",
"GUID": "fb28e1",
"Grid": true,
"GridProjection": false,
"Hands": false,
"HideWhenFaceDown": false,
"IgnoreFoW": false,
"LayoutGroupSortIndex": 0,
"Locked": true,
"LuaScript": "",
"LuaScriptState": "",
"MeasureMovement": false,
"Name": "ScriptingTrigger",
"Nickname": "",
"Snap": true,
"Sticky": true,
"Tooltip": true,
"Transform": {
"posX": -41.9,
"posY": 1.468,
"posZ": 28.6,
"rotX": 0,
"rotY": 0,
"rotZ": 0,
"scaleX": 3,
"scaleY": 5,
"scaleZ": 8
},
"Value": 0,
"XmlUI": ""
}

View File

@ -19,15 +19,15 @@ local DISCARD_BUTTON_OFFSETS = {-1.365, -0.91, -0.455, 0, 0.455, 0.91}
local SEARCH_AROUND_SELF_X_BUFFER = 8 local SEARCH_AROUND_SELF_X_BUFFER = 8
-- defined areas for the function "inArea()"" -- defined areas for "inArea()" and "Physics.cast()"
local MAIN_PLAY_AREA = { local MAIN_PLAY_AREA = {
upperLeft = { upperLeft = {
x = 1.98, x = 1.98,
z = 0.736, z = 0.736
}, },
lowerRight = { lowerRight = {
x = -0.79, x = -0.79,
z = -0.39, z = -0.39
} }
} }
local INVESTIGATOR_AREA = { local INVESTIGATOR_AREA = {
@ -37,7 +37,7 @@ local INVESTIGATOR_AREA = {
}, },
lowerRight = { lowerRight = {
x = -1.258, x = -1.258,
z = -0.0805, z = -0.0805
} }
} }
local THREAT_AREA = { local THREAT_AREA = {
@ -47,7 +47,27 @@ local THREAT_AREA = {
}, },
lowerRight = { lowerRight = {
x = -1.13, x = -1.13,
z = -0.92, z = -0.92
}
}
local DECK_DISCARD_AREA = {
upperLeft = {
x = -1.62,
z = 0.855
},
lowerRight = {
x = -2.02,
z = -0.245
},
center = {
x = -1.82,
y = 0.1,
z = 0.305
},
size = {
x = 0.4,
y = 0.1,
z = 1.1
} }
} }
@ -73,14 +93,13 @@ isDES = false
function onSave() function onSave()
return JSON.encode({ return JSON.encode({
zoneID = zoneID,
playerColor = playerColor, playerColor = playerColor,
activeInvestigatorId = activeInvestigatorId, activeInvestigatorId = activeInvestigatorId,
isDrawButtonVisible = isDrawButtonVisible isDrawButtonVisible = isDrawButtonVisible
}) })
end end
function onLoad(save_state) function onLoad(saveState)
self.interactable = DEBUG self.interactable = DEBUG
-- get object references to owned objects -- get object references to owned objects
@ -121,9 +140,8 @@ function onLoad(save_state)
}) })
-- save state loading -- save state loading
local state = JSON.decode(save_state) local state = JSON.decode(saveState)
if state ~= nil then if state ~= nil then
zoneID = state.zoneID
playerColor = state.playerColor playerColor = state.playerColor
activeInvestigatorId = state.activeInvestigatorId activeInvestigatorId = state.activeInvestigatorId
isDrawButtonVisible = state.isDrawButtonVisible isDrawButtonVisible = state.isDrawButtonVisible
@ -131,7 +149,6 @@ function onLoad(save_state)
showDrawButton(isDrawButtonVisible) showDrawButton(isDrawButtonVisible)
if getObjectFromGUID(zoneID) == nil then spawnDeckZone() end
collisionEnabled = true collisionEnabled = true
math.randomseed(os.time()) math.randomseed(os.time())
@ -141,20 +158,9 @@ end
-- utility functions -- utility functions
--------------------------------------------------------- ---------------------------------------------------------
function spawnDeckZone()
spawnObject({
position = self.positionToWorld({-1.4, 0, 0.3 }),
scale = {3, 5, 8 },
type = 'ScriptingTrigger',
callback = function (zone) zoneID = zone.getGUID() end,
callback_owner = self,
rotation = self.getRotation()
})
end
-- searches an area and optionally filters the result -- searches an area and optionally filters the result
function searchArea(origin, size, filter) function searchArea(origin, size, filter)
local objList = Physics.cast({ local searchResult = Physics.cast({
origin = origin, origin = origin,
direction = { 0, 1, 0 }, direction = { 0, 1, 0 },
orientation = self.getRotation(), orientation = self.getRotation(),
@ -163,26 +169,22 @@ function searchArea(origin, size, filter)
max_distance = 1 max_distance = 1
}) })
if filter then local objList = {}
local filteredList = {} for _, v in ipairs(searchResult) do
for _, obj in ipairs(objList) do if not filter or (filter and filter(v.hit_object)) then
if filter(obj.hit_object) then table.insert(objList, v.hit_object)
table.insert(filteredList, obj)
end
end end
return filteredList
else
return objList
end end
return objList
end end
-- filter functions for searchArea -- filter functions for searchArea()
function isDeck(x) return x.tag == 'Deck' end function isCard(x) return x.type == 'Card' end
function isDeck(x) return x.type == 'Deck' end
function isCardOrDeck(x) return x.tag == 'Card' or x.tag == 'Deck' end function isCardOrDeck(x) return x.type == 'Card' or x.type == 'Deck' end
-- Finds all objects on the playmat and associated set aside zone. -- Finds all objects on the playmat and associated set aside zone.
function searchAroundSelf() function searchAroundSelf(filter)
local bounds = self.getBoundsNormalized() local bounds = self.getBoundsNormalized()
-- Increase the width to cover the set aside zone -- Increase the width to cover the set aside zone
bounds.size.x = bounds.size.x + SEARCH_AROUND_SELF_X_BUFFER bounds.size.x = bounds.size.x + SEARCH_AROUND_SELF_X_BUFFER
@ -193,19 +195,19 @@ function searchAroundSelf()
local setAsideDirection = bounds.center.z > 0 and 1 or -1 local setAsideDirection = bounds.center.z > 0 and 1 or -1
local localCenter = self.positionToLocal(bounds.center) local localCenter = self.positionToLocal(bounds.center)
localCenter.x = localCenter.x + setAsideDirection * SEARCH_AROUND_SELF_X_BUFFER / 2 / self.getScale().x localCenter.x = localCenter.x + setAsideDirection * SEARCH_AROUND_SELF_X_BUFFER / 2 / self.getScale().x
return searchArea(self.positionToWorld(localCenter), bounds.size) return searchArea(self.positionToWorld(localCenter), bounds.size, filter)
end end
function findCardsAroundSelf() -- searches the area around the draw deck and discard pile
local cards = { } function searchDeckAndDiscardArea(filter)
for _, collision in ipairs(searchAroundSelf()) do local pos = self.positionToWorld(DECK_DISCARD_AREA.center)
local obj = collision.hit_object local scale = self.getScale()
if obj.name == "Card" or obj.name == "CardCustom" then local size = {
table.insert(cards, obj) x = DECK_DISCARD_AREA.size.x * scale.x,
end y = DECK_DISCARD_AREA.size.y,
end z = DECK_DISCARD_AREA.size.z * scale.z
}
return cards return searchArea(pos, size, filter)
end end
function doNotReady(card) function doNotReady(card)
@ -226,11 +228,11 @@ end
-- builds a function that discards things in searchPosition -- builds a function that discards things in searchPosition
-- stuff on the card/deck will be put into the local trashcan -- stuff on the card/deck will be put into the local trashcan
function makeDiscardHandlerFor(searchPosition, ) function makeDiscardHandlerFor(searchPosition)
return function () return function ()
for _, hitObj in ipairs(findObjectsAtPosition(searchPosition)) do local origin = self.positionToWorld(searchPosition)
local obj = hitObj.hit_object for _, obj in ipairs(searchArea(origin, {2, 1, 3.2})) do
if obj.tag == "Deck" or obj.tag == "Card" then if isCardOrDeck(obj) then
if obj.hasTag("PlayerCard") then if obj.hasTag("PlayerCard") then
placeOrMergeIntoDeck(obj, returnGlobalDiscardPosition(), self.getRotation()) placeOrMergeIntoDeck(obj, returnGlobalDiscardPosition(), self.getRotation())
else else
@ -259,7 +261,7 @@ function placeOrMergeIntoDeck(obj, pos, rot)
-- search the new position for existing card/deck -- search the new position for existing card/deck
local searchResult = searchArea(pos, { 1, 1, 1 }, isCardOrDeck) local searchResult = searchArea(pos, { 1, 1, 1 }, isCardOrDeck)
if #searchResult == 1 then if #searchResult == 1 then
local match = searchResult[1].hit_object local match = searchResult[1]
if match.type == 'Card' then if match.type == 'Card' then
card = match card = match
elseif match.type == 'Deck' then elseif match.type == 'Deck' then
@ -269,7 +271,7 @@ function placeOrMergeIntoDeck(obj, pos, rot)
-- update vertical component of new position -- update vertical component of new position
if card or deck then if card or deck then
local bounds = searchResult[1].hit_object.getBounds() local bounds = searchResult[1].getBounds()
newPos = Vector(pos):setAt("y", bounds.center.y + bounds.size.y / 2 + offset) newPos = Vector(pos):setAt("y", bounds.center.y + bounds.size.y / 2 + offset)
else else
newPos = Vector(pos) + Vector(0, offset, 0) newPos = Vector(pos) + Vector(0, offset, 0)
@ -308,18 +310,6 @@ function makeDiscardButton(xValue, number)
}) })
end end
function findObjectsAtPosition(localPos)
return Physics.cast({
origin = self.positionToWorld(localPos),
direction = {0, 1, 0},
orientation = {0, self.getRotation().y + 90, 0},
type = 3,
size = {3.2, 1, 2},
max_distance = 0,
debug = DEBUG
})
end
--------------------------------------------------------- ---------------------------------------------------------
-- Upkeep button -- Upkeep button
--------------------------------------------------------- ---------------------------------------------------------
@ -342,11 +332,10 @@ function doUpkeep(_, clickedByColor, isRightClick)
-- unexhaust cards in play zone, flip action tokens and find forcedLearning -- unexhaust cards in play zone, flip action tokens and find forcedLearning
local forcedLearning = false local forcedLearning = false
local rot = self.getRotation() local rot = self.getRotation()
for _, v in ipairs(searchAroundSelf()) do for _, obj in ipairs(searchAroundSelf()) do
local obj = v.hit_object
if obj.getDescription() == "Action Token" and obj.is_face_down then if obj.getDescription() == "Action Token" and obj.is_face_down then
obj.flip() obj.flip()
elseif obj.tag == "Card" and not inArea(self.positionToLocal(obj.getPosition()), INVESTIGATOR_AREA) then elseif obj.type == "Card" and not inArea(self.positionToLocal(obj.getPosition()), INVESTIGATOR_AREA) then
local cardMetadata = JSON.decode(obj.getGMNotes()) or {} local cardMetadata = JSON.decode(obj.getGMNotes()) or {}
if not doNotReady(obj) then if not doNotReady(obj) then
local cardRotation = round(obj.getRotation().y, 0) - rot.y local cardRotation = round(obj.getRotation().y, 0) - rot.y
@ -381,7 +370,7 @@ function doUpkeep(_, clickedByColor, isRightClick)
if activeInvestigatorId ~= nil then if activeInvestigatorId ~= nil then
local miniId = string.match(activeInvestigatorId, ".....") .. "-m" local miniId = string.match(activeInvestigatorId, ".....") .. "-m"
for _, obj in ipairs(getObjects()) do for _, obj in ipairs(getObjects()) do
if obj.tag == "Card" and obj.is_face_down then if obj.type == "Card" and obj.is_face_down then
local notes = JSON.decode(obj.getGMNotes()) local notes = JSON.decode(obj.getGMNotes())
if notes ~= nil and notes.type == "Minicard" and (notes.id == miniId or notes.id == "09080-m") then if notes ~= nil and notes.type == "Minicard" and (notes.id == miniId or notes.id == "09080-m") then
obj.flip() obj.flip()
@ -479,19 +468,14 @@ function getDrawDiscardDecks()
discardPile = nil discardPile = nil
topCard = nil topCard = nil
local zone = getObjectFromGUID(zoneID) for _, object in ipairs(searchDeckAndDiscardArea(isCardOrDeck)) do
if zone == nil then return end if self.positionToLocal(object.getPosition()).z > 0.5 then
discardPile = object
for _, object in ipairs(zone.getObjects()) do -- Norman Withers handling
if object.tag == "Deck" or object.tag == "Card" then elseif string.match(activeInvestigatorId, "%d%d%d%d%d") == "08004" and not object.is_face_down then
if self.positionToLocal(object.getPosition()).z > 0.5 then topCard = object
discardPile = object else
-- Norman Withers handling drawDeck = object
elseif string.match(activeInvestigatorId, "%d%d%d%d%d") == "08004" and object.tag == "Card" and not object.is_face_down then
topCard = object
else
drawDeck = object
end
end end
end end
end end
@ -594,7 +578,7 @@ end
-- called when a checkbox is added or removed in-game (which should be rare), and is bounded by the -- called when a checkbox is added or removed in-game (which should be rare), and is bounded by the
-- number of customizable cards in play. -- number of customizable cards in play.
function syncAllCustomizableCards() function syncAllCustomizableCards()
for _, card in ipairs(findCardsAroundSelf()) do for _, card in ipairs(searchAroundSelf(isCard)) do
syncCustomizableMetadata(card) syncCustomizableMetadata(card)
end end
end end
@ -604,7 +588,7 @@ function syncCustomizableMetadata(card)
if cardMetadata == nil or cardMetadata.customizations == nil then if cardMetadata == nil or cardMetadata.customizations == nil then
return return
end end
for _, upgradeSheet in ipairs(findCardsAroundSelf()) do for _, upgradeSheet in ipairs(searchAroundSelf(isCard)) do
local upgradeSheetMetadata = JSON.decode(upgradeSheet.getGMNotes()) or { } local upgradeSheetMetadata = JSON.decode(upgradeSheet.getGMNotes()) or { }
if upgradeSheetMetadata.id == (cardMetadata.id .. "-c") then if upgradeSheetMetadata.id == (cardMetadata.id .. "-c") then
for i, customization in ipairs(cardMetadata.customizations) do for i, customization in ipairs(cardMetadata.customizations) do
@ -644,12 +628,13 @@ function onCollisionEnter(collision_info)
if not collisionEnabled then return end if not collisionEnabled then return end
-- only continue for cards -- only continue for cards
if object.name ~= "Card" and object.name ~= "CardCustom" then return end if object.type ~= "Card" then return end
maybeUpdateActiveInvestigator(object) maybeUpdateActiveInvestigator(object)
syncCustomizableMetadata(object) syncCustomizableMetadata(object)
if isInDeckZone(object) then local localCardPos = self.positionToLocal(object.getPosition())
if inArea(localCardPos, DECK_DISCARD_AREA) then
tokenManager.resetTokensSpawned(object) tokenManager.resetTokensSpawned(object)
removeTokensFromObject(object) removeTokensFromObject(object)
elseif shouldSpawnTokens(object) then elseif shouldSpawnTokens(object) then
@ -699,33 +684,16 @@ function onObjectEnterContainer(container, object)
end end
function resetTokensIfInDeckZone(container, object) function resetTokensIfInDeckZone(container, object)
if isInDeckZone(container) then local pos = self.positionToLocal(container.getPosition())
if inArea(pos, DECK_DISCARD_AREA) then
tokenManager.resetTokensSpawned(object) tokenManager.resetTokensSpawned(object)
removeTokensFromObject(container) removeTokensFromObject(container)
end end
end end
-- checks if an object is in this mats deckzone
function isInDeckZone(checkObject)
local deckZone = getObjectFromGUID(zoneID)
if deckZone == nil then
return false
end
for _, obj in ipairs(deckZone.getObjects()) do
if obj == checkObject then
return true
end
end
return false
end
-- removes tokens from the provided card/deck -- removes tokens from the provided card/deck
function removeTokensFromObject(object) function removeTokensFromObject(object)
for _, v in ipairs(searchArea(object.getPosition(), { 3, 1, 4 })) do for _, obj in ipairs(searchArea(object.getPosition(), { 3, 1, 4 })) do
local obj = v.hit_object
if obj.getGUID() ~= "4ee1f2" and -- table if obj.getGUID() ~= "4ee1f2" and -- table
obj ~= self and obj ~= self and
obj.type ~= "Deck" and obj.type ~= "Deck" and
@ -780,7 +748,6 @@ function maybeUpdateActiveInvestigator(card)
} }
for _, obj in ipairs(search) do for _, obj in ipairs(search) do
local obj = obj.hit_object
if obj.getDescription() == "Action Token" and obj.getStateId() > 0 then if obj.getDescription() == "Action Token" and obj.getStateId() > 0 then
if obj.getScale().x < 0.4 then if obj.getScale().x < 0.4 then
smallToken = obj smallToken = obj
@ -984,10 +951,10 @@ function setLimitSnapsByType(matchTypes)
end end
-- Simple method to check if the given point is in a specified area. Local use only, -- Simple method to check if the given point is in a specified area. Local use only,
---@param point Vector. Point to check, only x and z values are relevant ---@param point Vector Point to check, only x and z values are relevant
---@param bounds Table. Defined area to see if the point is within. See MAIN_PLAY_AREA for sample ---@param bounds Table Defined area to see if the point is within. See MAIN_PLAY_AREA for sample
-- bounds definition. -- bounds definition.
---@return Boolean. True if the point is in the area defined by bounds ---@return Boolean True if the point is in the area defined by bounds
function inArea(point, bounds) function inArea(point, bounds)
return (point.x < bounds.upperLeft.x return (point.x < bounds.upperLeft.x
and point.x > bounds.lowerRight.x and point.x > bounds.lowerRight.x