diff --git a/config.json b/config.json index 790e3a11..f92d80ce 100644 --- a/config.json +++ b/config.json @@ -103,10 +103,6 @@ "LegacyAssets.7165a9", "PlayArea.721ba2", "BarkhamHorror.308439", - "ScriptingTrigger.fb28e1", - "ScriptingTrigger.7af2cf", - "ScriptingTrigger.b047f8", - "ScriptingTrigger.18538f", "ChaosBagStatTracker.766620", "Blesstokens.afa06b", "Cursetokens.bd0253", diff --git a/objects/Playermat1White.8b081b.luascriptstate b/objects/Playermat1White.8b081b.luascriptstate index f6e1f7ad..e25057b1 100644 --- a/objects/Playermat1White.8b081b.luascriptstate +++ b/objects/Playermat1White.8b081b.luascriptstate @@ -1 +1 @@ -{"activeInvestigatorId":"00000","isDrawButtonVisible":false,"playerColor":"White","zoneID":"7af2cf"} +{"activeInvestigatorId":"00000","isDrawButtonVisible":false,"playerColor":"White"} diff --git a/objects/Playermat2Orange.bd0ff4.luascriptstate b/objects/Playermat2Orange.bd0ff4.luascriptstate index 5a62485b..b4311e09 100644 --- a/objects/Playermat2Orange.bd0ff4.luascriptstate +++ b/objects/Playermat2Orange.bd0ff4.luascriptstate @@ -1 +1 @@ -{"activeInvestigatorId":"00000","isDrawButtonVisible":false,"playerColor":"Orange","zoneID":"b047f8"} +{"activeInvestigatorId":"00000","isDrawButtonVisible":false,"playerColor":"Orange"} diff --git a/objects/Playermat3Green.383d8b.luascriptstate b/objects/Playermat3Green.383d8b.luascriptstate index 142f5f9e..f71b33c5 100644 --- a/objects/Playermat3Green.383d8b.luascriptstate +++ b/objects/Playermat3Green.383d8b.luascriptstate @@ -1 +1 @@ -{"activeInvestigatorId":"00000","isDrawButtonVisible":false,"playerColor":"Green","zoneID":"fb28e1"} +{"activeInvestigatorId":"00000","isDrawButtonVisible":false,"playerColor":"Green"} diff --git a/objects/Playermat4Red.0840d5.luascriptstate b/objects/Playermat4Red.0840d5.luascriptstate index 0c461d35..5e369679 100644 --- a/objects/Playermat4Red.0840d5.luascriptstate +++ b/objects/Playermat4Red.0840d5.luascriptstate @@ -1 +1 @@ -{"activeInvestigatorId":"00000","isDrawButtonVisible":false,"playerColor":"Red","zoneID":"18538f"} +{"activeInvestigatorId":"00000","isDrawButtonVisible":false,"playerColor":"Red"} diff --git a/objects/ScriptingTrigger.18538f.json b/objects/ScriptingTrigger.18538f.json deleted file mode 100644 index 8733e093..00000000 --- a/objects/ScriptingTrigger.18538f.json +++ /dev/null @@ -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": "" -} diff --git a/objects/ScriptingTrigger.7af2cf.json b/objects/ScriptingTrigger.7af2cf.json deleted file mode 100644 index cce12e37..00000000 --- a/objects/ScriptingTrigger.7af2cf.json +++ /dev/null @@ -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": "" -} diff --git a/objects/ScriptingTrigger.b047f8.json b/objects/ScriptingTrigger.b047f8.json deleted file mode 100644 index fb645665..00000000 --- a/objects/ScriptingTrigger.b047f8.json +++ /dev/null @@ -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": "" -} diff --git a/objects/ScriptingTrigger.fb28e1.json b/objects/ScriptingTrigger.fb28e1.json deleted file mode 100644 index 24cb97b9..00000000 --- a/objects/ScriptingTrigger.fb28e1.json +++ /dev/null @@ -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": "" -} diff --git a/src/playermat/Playmat.ttslua b/src/playermat/Playmat.ttslua index 959970a7..d92e0caf 100644 --- a/src/playermat/Playmat.ttslua +++ b/src/playermat/Playmat.ttslua @@ -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