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",
"PlayArea.721ba2",
"BarkhamHorror.308439",
"ScriptingTrigger.fb28e1",
"ScriptingTrigger.7af2cf",
"ScriptingTrigger.b047f8",
"ScriptingTrigger.18538f",
"ChaosBagStatTracker.766620",
"Blesstokens.afa06b",
"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
-- defined areas for the function "inArea()""
-- defined areas for "inArea()" and "Physics.cast()"
local MAIN_PLAY_AREA = {
upperLeft = {
x = 1.98,
z = 0.736,
z = 0.736
},
lowerRight = {
x = -0.79,
z = -0.39,
z = -0.39
}
}
local INVESTIGATOR_AREA = {
@ -37,7 +37,7 @@ local INVESTIGATOR_AREA = {
},
lowerRight = {
x = -1.258,
z = -0.0805,
z = -0.0805
}
}
local THREAT_AREA = {
@ -47,7 +47,27 @@ local THREAT_AREA = {
},
lowerRight = {
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()
return JSON.encode({
zoneID = zoneID,
playerColor = playerColor,
activeInvestigatorId = activeInvestigatorId,
isDrawButtonVisible = isDrawButtonVisible
})
end
function onLoad(save_state)
function onLoad(saveState)
self.interactable = DEBUG
-- get object references to owned objects
@ -121,9 +140,8 @@ function onLoad(save_state)
})
-- save state loading
local state = JSON.decode(save_state)
local state = JSON.decode(saveState)
if state ~= nil then
zoneID = state.zoneID
playerColor = state.playerColor
activeInvestigatorId = state.activeInvestigatorId
isDrawButtonVisible = state.isDrawButtonVisible
@ -131,7 +149,6 @@ function onLoad(save_state)
showDrawButton(isDrawButtonVisible)
if getObjectFromGUID(zoneID) == nil then spawnDeckZone() end
collisionEnabled = true
math.randomseed(os.time())
@ -141,20 +158,9 @@ end
-- 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
function searchArea(origin, size, filter)
local objList = Physics.cast({
local searchResult = Physics.cast({
origin = origin,
direction = { 0, 1, 0 },
orientation = self.getRotation(),
@ -163,26 +169,22 @@ function searchArea(origin, size, filter)
max_distance = 1
})
if filter then
local filteredList = {}
for _, obj in ipairs(objList) do
if filter(obj.hit_object) then
table.insert(filteredList, obj)
end
local objList = {}
for _, v in ipairs(searchResult) do
if not filter or (filter and filter(v.hit_object)) then
table.insert(objList, v.hit_object)
end
return filteredList
else
return objList
end
return objList
end
-- filter functions for searchArea
function isDeck(x) return x.tag == 'Deck' end
function isCardOrDeck(x) return x.tag == 'Card' or x.tag == 'Deck' end
-- filter functions for searchArea()
function isCard(x) return x.type == 'Card' end
function isDeck(x) return x.type == '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.
function searchAroundSelf()
function searchAroundSelf(filter)
local bounds = self.getBoundsNormalized()
-- Increase the width to cover the set aside zone
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 localCenter = self.positionToLocal(bounds.center)
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
function findCardsAroundSelf()
local cards = { }
for _, collision in ipairs(searchAroundSelf()) do
local obj = collision.hit_object
if obj.name == "Card" or obj.name == "CardCustom" then
table.insert(cards, obj)
end
end
return cards
-- searches the area around the draw deck and discard pile
function searchDeckAndDiscardArea(filter)
local pos = self.positionToWorld(DECK_DISCARD_AREA.center)
local scale = self.getScale()
local size = {
x = DECK_DISCARD_AREA.size.x * scale.x,
y = DECK_DISCARD_AREA.size.y,
z = DECK_DISCARD_AREA.size.z * scale.z
}
return searchArea(pos, size, filter)
end
function doNotReady(card)
@ -226,11 +228,11 @@ end
-- builds a function that discards things in searchPosition
-- stuff on the card/deck will be put into the local trashcan
function makeDiscardHandlerFor(searchPosition, )
function makeDiscardHandlerFor(searchPosition)
return function ()
for _, hitObj in ipairs(findObjectsAtPosition(searchPosition)) do
local obj = hitObj.hit_object
if obj.tag == "Deck" or obj.tag == "Card" then
local origin = self.positionToWorld(searchPosition)
for _, obj in ipairs(searchArea(origin, {2, 1, 3.2})) do
if isCardOrDeck(obj) then
if obj.hasTag("PlayerCard") then
placeOrMergeIntoDeck(obj, returnGlobalDiscardPosition(), self.getRotation())
else
@ -259,7 +261,7 @@ function placeOrMergeIntoDeck(obj, pos, rot)
-- search the new position for existing card/deck
local searchResult = searchArea(pos, { 1, 1, 1 }, isCardOrDeck)
if #searchResult == 1 then
local match = searchResult[1].hit_object
local match = searchResult[1]
if match.type == 'Card' then
card = match
elseif match.type == 'Deck' then
@ -269,7 +271,7 @@ function placeOrMergeIntoDeck(obj, pos, rot)
-- update vertical component of new position
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)
else
newPos = Vector(pos) + Vector(0, offset, 0)
@ -308,18 +310,6 @@ function makeDiscardButton(xValue, number)
})
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
---------------------------------------------------------
@ -342,11 +332,10 @@ function doUpkeep(_, clickedByColor, isRightClick)
-- unexhaust cards in play zone, flip action tokens and find forcedLearning
local forcedLearning = false
local rot = self.getRotation()
for _, v in ipairs(searchAroundSelf()) do
local obj = v.hit_object
for _, obj in ipairs(searchAroundSelf()) do
if obj.getDescription() == "Action Token" and obj.is_face_down then
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 {}
if not doNotReady(obj) then
local cardRotation = round(obj.getRotation().y, 0) - rot.y
@ -381,7 +370,7 @@ function doUpkeep(_, clickedByColor, isRightClick)
if activeInvestigatorId ~= nil then
local miniId = string.match(activeInvestigatorId, ".....") .. "-m"
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())
if notes ~= nil and notes.type == "Minicard" and (notes.id == miniId or notes.id == "09080-m") then
obj.flip()
@ -479,19 +468,14 @@ function getDrawDiscardDecks()
discardPile = nil
topCard = nil
local zone = getObjectFromGUID(zoneID)
if zone == nil then return end
for _, object in ipairs(zone.getObjects()) do
if object.tag == "Deck" or object.tag == "Card" then
if self.positionToLocal(object.getPosition()).z > 0.5 then
discardPile = object
-- Norman Withers handling
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
for _, object in ipairs(searchDeckAndDiscardArea(isCardOrDeck)) do
if self.positionToLocal(object.getPosition()).z > 0.5 then
discardPile = object
-- Norman Withers handling
elseif string.match(activeInvestigatorId, "%d%d%d%d%d") == "08004" and not object.is_face_down then
topCard = object
else
drawDeck = object
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
-- number of customizable cards in play.
function syncAllCustomizableCards()
for _, card in ipairs(findCardsAroundSelf()) do
for _, card in ipairs(searchAroundSelf(isCard)) do
syncCustomizableMetadata(card)
end
end
@ -604,7 +588,7 @@ function syncCustomizableMetadata(card)
if cardMetadata == nil or cardMetadata.customizations == nil then
return
end
for _, upgradeSheet in ipairs(findCardsAroundSelf()) do
for _, upgradeSheet in ipairs(searchAroundSelf(isCard)) do
local upgradeSheetMetadata = JSON.decode(upgradeSheet.getGMNotes()) or { }
if upgradeSheetMetadata.id == (cardMetadata.id .. "-c") then
for i, customization in ipairs(cardMetadata.customizations) do
@ -644,12 +628,13 @@ function onCollisionEnter(collision_info)
if not collisionEnabled then return end
-- only continue for cards
if object.name ~= "Card" and object.name ~= "CardCustom" then return end
if object.type ~= "Card" then return end
maybeUpdateActiveInvestigator(object)
syncCustomizableMetadata(object)
if isInDeckZone(object) then
local localCardPos = self.positionToLocal(object.getPosition())
if inArea(localCardPos, DECK_DISCARD_AREA) then
tokenManager.resetTokensSpawned(object)
removeTokensFromObject(object)
elseif shouldSpawnTokens(object) then
@ -699,33 +684,16 @@ function onObjectEnterContainer(container, object)
end
function resetTokensIfInDeckZone(container, object)
if isInDeckZone(container) then
local pos = self.positionToLocal(container.getPosition())
if inArea(pos, DECK_DISCARD_AREA) then
tokenManager.resetTokensSpawned(object)
removeTokensFromObject(container)
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
function removeTokensFromObject(object)
for _, v in ipairs(searchArea(object.getPosition(), { 3, 1, 4 })) do
local obj = v.hit_object
for _, obj in ipairs(searchArea(object.getPosition(), { 3, 1, 4 })) do
if obj.getGUID() ~= "4ee1f2" and -- table
obj ~= self and
obj.type ~= "Deck" and
@ -780,7 +748,6 @@ function maybeUpdateActiveInvestigator(card)
}
for _, obj in ipairs(search) do
local obj = obj.hit_object
if obj.getDescription() == "Action Token" and obj.getStateId() > 0 then
if obj.getScale().x < 0.4 then
smallToken = obj
@ -984,10 +951,10 @@ function setLimitSnapsByType(matchTypes)
end
-- 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 bounds Table. Defined area to see if the point is within. See MAIN_PLAY_AREA for sample
---@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
-- 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)
return (point.x < bounds.upperLeft.x
and point.x > bounds.lowerRight.x