Merge branch 'main' into playermat-xml
This commit is contained in:
commit
a452043483
@ -3,7 +3,6 @@
|
||||
"ComponentTags_path": "ComponentTags.json",
|
||||
"CustomUIAssets_path": "CustomUIAssets.json",
|
||||
"DecalPallet_path": "DecalPallet.json",
|
||||
"Decals": [],
|
||||
"GameComplexity": "",
|
||||
"GameMode": "Arkham Horror LCG - Super Complete Edition",
|
||||
"GameType": "",
|
||||
@ -84,6 +83,7 @@
|
||||
"Trash.5f896a",
|
||||
"Trash.147e80",
|
||||
"Trash.f7b6c8",
|
||||
"PatchNotes.f47225",
|
||||
"RulesReference.d99993",
|
||||
"LatestFAQ.faqfaq",
|
||||
"Doomtokens.16724b",
|
||||
@ -207,7 +207,6 @@
|
||||
"Tokencache_Curse.16a9a7",
|
||||
"Tokencache_Frost.b2b7be",
|
||||
"PhysicsDetector.b300d8",
|
||||
"ArkhamSCE390-06302024-Page1.bd6b3e",
|
||||
"Neutral.834ad5",
|
||||
"Neutral.a84ae4",
|
||||
"Neutral.762df8",
|
||||
|
@ -33,7 +33,7 @@
|
||||
"IgnoreFoW": false,
|
||||
"LayoutGroupSortIndex": 0,
|
||||
"Locked": false,
|
||||
"LuaScript": "",
|
||||
"LuaScript": "require(\"playercards/cards/Analysis\")",
|
||||
"LuaScriptState": "",
|
||||
"MeasureMovement": false,
|
||||
"Name": "Card",
|
||||
|
@ -58,5 +58,5 @@
|
||||
"scaleZ": 1
|
||||
},
|
||||
"Value": 0,
|
||||
"XmlUI": ""
|
||||
"XmlUI": "\u003cInclude src=\"playercards/FamilyInheritance.xml\"/\u003e"
|
||||
}
|
||||
|
@ -33,7 +33,7 @@
|
||||
"IgnoreFoW": false,
|
||||
"LayoutGroupSortIndex": 0,
|
||||
"Locked": false,
|
||||
"LuaScript": "",
|
||||
"LuaScript": "require(\"playercards/cards/Strong-Armed\")",
|
||||
"LuaScriptState": "",
|
||||
"MeasureMovement": false,
|
||||
"Name": "Card",
|
||||
|
@ -33,7 +33,7 @@
|
||||
"IgnoreFoW": false,
|
||||
"LayoutGroupSortIndex": 0,
|
||||
"Locked": false,
|
||||
"LuaScript": "",
|
||||
"LuaScript": "require(\"playercards/cards/ThirdTimesaCharm\")",
|
||||
"LuaScriptState": "",
|
||||
"MeasureMovement": false,
|
||||
"Name": "Card",
|
||||
|
@ -1,137 +0,0 @@
|
||||
{
|
||||
"AltLookAngle": {
|
||||
"x": 0,
|
||||
"y": 0,
|
||||
"z": 0
|
||||
},
|
||||
"Autoraise": true,
|
||||
"ColorDiffuse": {
|
||||
"b": 1,
|
||||
"g": 1,
|
||||
"r": 1
|
||||
},
|
||||
"Description": "Thanks for downloading Arkham SCE 3.9.0!\n\n- Added confirmation dialog for discard hotkey (e.g. for locations)\r\n- Added new action / ability tokens\r\n- Added automated discarding for Patrice\r\n- Added new option to enable all card helpers\r\n- Added new option to load class-specific playermats\r",
|
||||
"DragSelectable": true,
|
||||
"GMNotes": "",
|
||||
"GUID": "bd6b3e",
|
||||
"Grid": true,
|
||||
"GridProjection": false,
|
||||
"Hands": false,
|
||||
"HideWhenFaceDown": false,
|
||||
"IgnoreFoW": false,
|
||||
"LayoutGroupSortIndex": 0,
|
||||
"Locked": false,
|
||||
"LuaScript": "",
|
||||
"LuaScriptState": "",
|
||||
"MeasureMovement": false,
|
||||
"Name": "Notecard",
|
||||
"Nickname": "Arkham SCE 3.9.0 - 06/30/2024 - Page 1",
|
||||
"Snap": true,
|
||||
"States": {
|
||||
"2": {
|
||||
"AltLookAngle": {
|
||||
"x": 0,
|
||||
"y": 0,
|
||||
"z": 0
|
||||
},
|
||||
"Autoraise": true,
|
||||
"ColorDiffuse": {
|
||||
"b": 1,
|
||||
"g": 1,
|
||||
"r": 1
|
||||
},
|
||||
"Description": "\n- Performed a small clean up of the bottom corners of the table\r\n- Updated 'Additional Cards Bag' / 'Player Card Panel' with better handling for fan-made cards\r\n- Updated Clean Up Helper, Drawing Tool, Hand Helper and Search Assistant\r\n- Updated Token Arranger",
|
||||
"DragSelectable": true,
|
||||
"GMNotes": "",
|
||||
"GUID": "522604",
|
||||
"Grid": true,
|
||||
"GridProjection": false,
|
||||
"Hands": false,
|
||||
"HideWhenFaceDown": false,
|
||||
"IgnoreFoW": false,
|
||||
"LayoutGroupSortIndex": 0,
|
||||
"Locked": false,
|
||||
"LuaScript": "",
|
||||
"LuaScriptState": "",
|
||||
"MeasureMovement": false,
|
||||
"Name": "Notecard",
|
||||
"Nickname": "Arkham SCE 3.9.0 - 06/30/2024 - Page 2",
|
||||
"Snap": true,
|
||||
"Sticky": true,
|
||||
"Tooltip": true,
|
||||
"Transform": {
|
||||
"posX": -27,
|
||||
"posY": 1.551,
|
||||
"posZ": -56.165,
|
||||
"rotX": 0,
|
||||
"rotY": 90,
|
||||
"rotZ": 0,
|
||||
"scaleX": 3,
|
||||
"scaleY": 1,
|
||||
"scaleZ": 3
|
||||
},
|
||||
"Value": 0,
|
||||
"XmlUI": ""
|
||||
},
|
||||
"3": {
|
||||
"AltLookAngle": {
|
||||
"x": 0,
|
||||
"y": 0,
|
||||
"z": 0
|
||||
},
|
||||
"Autoraise": true,
|
||||
"ColorDiffuse": {
|
||||
"b": 1,
|
||||
"g": 1,
|
||||
"r": 1
|
||||
},
|
||||
"Description": "\n- Implemented menu to redraw tokens for specific cards like Heavy Furs and Wendy Adams\r\n- Bugfix for attempting to draw an encounter card while there is no deck\r\n- Bugfix for Navigation Overlay: now checks if playmat is occupied\r\n- Bugfix for Phase Tracker broadcasting\r\n- Performance improvements",
|
||||
"DragSelectable": true,
|
||||
"GMNotes": "",
|
||||
"GUID": "522877",
|
||||
"Grid": true,
|
||||
"GridProjection": false,
|
||||
"Hands": false,
|
||||
"HideWhenFaceDown": false,
|
||||
"IgnoreFoW": false,
|
||||
"LayoutGroupSortIndex": 0,
|
||||
"Locked": false,
|
||||
"LuaScript": "",
|
||||
"LuaScriptState": "",
|
||||
"MeasureMovement": false,
|
||||
"Name": "Notecard",
|
||||
"Nickname": "Arkham SCE 3.9.0 - 06/30/2024 - Page 3",
|
||||
"Snap": true,
|
||||
"Sticky": true,
|
||||
"Tooltip": true,
|
||||
"Transform": {
|
||||
"posX": -27,
|
||||
"posY": 1.551,
|
||||
"posZ": -56.165,
|
||||
"rotX": 0,
|
||||
"rotY": 90,
|
||||
"rotZ": 0,
|
||||
"scaleX": 3,
|
||||
"scaleY": 1,
|
||||
"scaleZ": 3
|
||||
},
|
||||
"Value": 0,
|
||||
"XmlUI": ""
|
||||
}
|
||||
},
|
||||
"Sticky": true,
|
||||
"Tooltip": true,
|
||||
"Transform": {
|
||||
"posX": -27,
|
||||
"posY": 1.551,
|
||||
"posZ": -56.165,
|
||||
"rotX": 0,
|
||||
"rotY": 90,
|
||||
"rotZ": 0,
|
||||
"scaleX": 3,
|
||||
"scaleY": 1,
|
||||
"scaleZ": 3
|
||||
},
|
||||
"Value": 0,
|
||||
"XmlUI": ""
|
||||
}
|
@ -1 +1 @@
|
||||
{"acknowledgedUpgradeVersions":[],"chaosTokensGUID":[],"optionPanel":{"cardLanguage":"en","changePlayAreaImage":false,"enableCardHelpers":false,"playAreaConnectionColor":{"a":1,"b":0.4,"g":0.4,"r":0.4},"playAreaConnections":true,"playAreaSnapTags":true,"showAttachmentHelper":false,"showCleanUpHelper":false,"showCYOA":false,"showDisplacementTool":false,"showDrawButton":false,"showHandHelper":false,"showSearchAssistant":false,"showTitleSplash":true,"useClassTexture":true,"useClueClickers":false,"useResourceCounters":"disabled","useSnapTags":true}}
|
||||
{"acknowledgedUpgradeVersions":[],"chaosTokensGUID":[],"optionPanel":{"cardLanguage":"en","changePlayAreaImage":false,"enableCardHelpers":true,"playAreaConnectionColor":{"a":1,"b":0.4,"g":0.4,"r":0.4},"playAreaConnections":true,"playAreaSnapTags":true,"showAttachmentHelper":false,"showCleanUpHelper":false,"showCYOA":false,"showDisplacementTool":false,"showDrawButton":false,"showHandHelper":false,"showSearchAssistant":false,"showTitleSplash":true,"useClassTexture":true,"useClueClickers":false,"useResourceCounters":"disabled","useSnapTags":true}}
|
||||
|
113
objects/PatchNotes.f47225.json
Normal file
113
objects/PatchNotes.f47225.json
Normal file
@ -0,0 +1,113 @@
|
||||
{
|
||||
"AltLookAngle": {
|
||||
"x": 0,
|
||||
"y": 0,
|
||||
"z": 0
|
||||
},
|
||||
"AttachedDecals": [
|
||||
{
|
||||
"CustomDecal": {
|
||||
"ImageURL": "http://cloud-3.steamusercontent.com/ugc/2501268517218943111/803E57A7B3E9765DF342050EE6C71D69473A7388/",
|
||||
"Name": "Image #1",
|
||||
"Size": 1
|
||||
},
|
||||
"Transform": {
|
||||
"posX": -0.93,
|
||||
"posY": 0.105,
|
||||
"posZ": 0.66,
|
||||
"rotX": 90,
|
||||
"rotY": 180,
|
||||
"rotZ": 0,
|
||||
"scaleX": 0.6,
|
||||
"scaleY": 0.6,
|
||||
"scaleZ": 1
|
||||
}
|
||||
},
|
||||
{
|
||||
"CustomDecal": {
|
||||
"ImageURL": "http://cloud-3.steamusercontent.com/ugc/2037357792052848566/5DA900C430E97D3DFF2C9B8A3DB1CB2271791FC7/",
|
||||
"Name": "Image #2",
|
||||
"Size": 1
|
||||
},
|
||||
"Transform": {
|
||||
"posX": -1.05,
|
||||
"posY": 0.105,
|
||||
"posZ": -0.567,
|
||||
"rotX": 90,
|
||||
"rotY": 205,
|
||||
"rotZ": 0,
|
||||
"scaleX": 0.3,
|
||||
"scaleY": 0.3,
|
||||
"scaleZ": 1
|
||||
}
|
||||
},
|
||||
{
|
||||
"CustomDecal": {
|
||||
"ImageURL": "http://cloud-3.steamusercontent.com/ugc/2501268517219098388/0936FEE03B410319658B5E05DB5D486CEDDE98F5/",
|
||||
"Name": "Image #3",
|
||||
"Size": 1
|
||||
},
|
||||
"Transform": {
|
||||
"posX": 0,
|
||||
"posY": 0.105,
|
||||
"posZ": -0.81,
|
||||
"rotX": 90,
|
||||
"rotY": 180,
|
||||
"rotZ": 0,
|
||||
"scaleX": 2.4,
|
||||
"scaleY": 0.009,
|
||||
"scaleZ": 1
|
||||
}
|
||||
}
|
||||
],
|
||||
"Autoraise": true,
|
||||
"ColorDiffuse": {
|
||||
"b": 1,
|
||||
"g": 1,
|
||||
"r": 1
|
||||
},
|
||||
"CustomImage": {
|
||||
"CustomTile": {
|
||||
"Stackable": false,
|
||||
"Stretch": true,
|
||||
"Thickness": 0.1,
|
||||
"Type": 0
|
||||
},
|
||||
"ImageScalar": 1,
|
||||
"ImageSecondaryURL": "http://sfwallpaper.com/images/parchment-paper-wallpaper-10.jpg",
|
||||
"ImageURL": "http://sfwallpaper.com/images/parchment-paper-wallpaper-10.jpg",
|
||||
"WidthScale": 0
|
||||
},
|
||||
"Description": "",
|
||||
"DragSelectable": true,
|
||||
"GMNotes": "",
|
||||
"GUID": "f47225",
|
||||
"Grid": true,
|
||||
"GridProjection": false,
|
||||
"Hands": false,
|
||||
"HideWhenFaceDown": false,
|
||||
"IgnoreFoW": false,
|
||||
"LayoutGroupSortIndex": 0,
|
||||
"Locked": false,
|
||||
"LuaScriptState_path": "PatchNotes.f47225.luascriptstate",
|
||||
"LuaScript_path": "PatchNotes.f47225.ttslua",
|
||||
"MeasureMovement": false,
|
||||
"Name": "Custom_Tile",
|
||||
"Nickname": "Patch Notes",
|
||||
"Snap": true,
|
||||
"Sticky": true,
|
||||
"Tooltip": true,
|
||||
"Transform": {
|
||||
"posX": -27,
|
||||
"posY": 1.481,
|
||||
"posZ": -56.165,
|
||||
"rotX": 0,
|
||||
"rotY": 270,
|
||||
"rotZ": 0,
|
||||
"scaleX": 7.5,
|
||||
"scaleY": 1,
|
||||
"scaleZ": 7.5
|
||||
},
|
||||
"Value": 0,
|
||||
"XmlUI": ""
|
||||
}
|
1
objects/PatchNotes.f47225.luascriptstate
Normal file
1
objects/PatchNotes.f47225.luascriptstate
Normal file
@ -0,0 +1 @@
|
||||
{"checks":[],"decals":[{"locked":false,"name":"Arkham SCE logo","pos":{"x":3.1,"y":2.2},"rotation":0,"scale":{"x":"2","y":"2"},"tooltip":"None","url":"http://cloud-3.steamusercontent.com/ugc/2501268517218943111/803E57A7B3E9765DF342050EE6C71D69473A7388/"},{"locked":false,"name":"Bootlegger Finn","pos":{"x":3.5,"y":-1.89},"rotation":"25","scale":{"x":"1","y":"1"},"tooltip":"None","url":"http://cloud-3.steamusercontent.com/ugc/2037357792052848566/5DA900C430E97D3DFF2C9B8A3DB1CB2271791FC7/"},{"locked":false,"name":"black bar","pos":{"x":0,"y":-2.7},"rotation":0,"scale":{"x":"8","y":"0.03"},"tooltip":"None","url":"http://cloud-3.steamusercontent.com/ugc/2501268517219098388/0936FEE03B410319658B5E05DB5D486CEDDE98F5/"}],"fields":[{"align":3,"array":{"x":"1","y":"1"},"counter":"False","distance":{"x":"1","y":"1"},"fieldColor":{"a":0,"b":1,"g":1,"r":1},"font":"200","locked":false,"name":"Patch Notes","pos":{"x":"0","y":-2.9},"role":"Normal Field","size":{"x":"3750","y":"250"},"textColor":{"a":1,"b":0,"g":0,"r":0},"tooltip":"None","value":["Arkham Horror LCG SCE 3.9.0 - 07/08/2024"]},{"align":2,"array":{"x":"1","y":1},"distance":{"x":"1","y":"1"},"fieldColor":{"a":0,"b":1,"g":1,"r":1},"font":"89","locked":false,"name":"Details","pos":{"x":"0","y":0.4},"role":"Nothing","size":{"x":"3750","y":"2750"},"textColor":{"a":1,"b":0,"g":0,"r":0},"tooltip":"None","value":["Thanks for downloading! We're happy to present you a rather big update this time :-)\n\nNew things\n- updated note card for patch notes (bless Marum for his awesome tool!)\n- automated discarding for Patrice\n- confirmation dialog for discard hotkey (e.g. for locations)\n- helpers for cards that redraw tokens and Kohaku\n- displaying of token count for cards that seal tokens\r\n- new action / ability tokens (replacing the old ones)\r\n- option to enable all card helpers (e.g. Heavy Furs)\r\n- option to load class-colored playermat backgrounds\n- coloring for player names in broadcasts\n- right-click option for RBW button on Player Card Panel to specify trait(s)\n\nUpdates\r\n- performed a small clean up of the bottom corners of the table\n- \"Numpad 9\" to rearranges present tokens (on top of adding a resource)\n- Scroll of Secrets context menu helper now displays player names instead of colors\r\n- Player Card Panel can display fan-made cards with a new \"custom\" cycle button)\n- updated Family Inheritance helper to a proper UI\n- \"Discard object\" gamekey works for selected objects\r\n- updated a bunch of tools like Clean Up Helper, Drawing Tool,\nHand Helper, Token Arranger and Search Assistant\n\nFixes\r\r\n- Bugfix for attempting to draw an encounter card while there is no deck\r\n- Bugfix for Navigation Overlay: now checks if playmat is occupied\r\n- Bugfix for Phase Tracker broadcasting\r\n- Performance and file size improvements (e.g. by adding download\nfunctions for CYOA campaign guides and Arkham Fantasy standees)"]}],"flip":"False","height":"0.1","locks":{"checks":false,"decals":false,"fields":false},"nudgeDistance":0.1,"scale":{"x":"0.3","y":"0.3"},"sheetLocked":true}
|
3513
objects/PatchNotes.f47225.ttslua
Normal file
3513
objects/PatchNotes.f47225.ttslua
Normal file
File diff suppressed because it is too large
Load Diff
@ -284,7 +284,6 @@ end
|
||||
-- maybe ignore cards / decks on the tekelili helper
|
||||
function maybeIgnoreTekeliliCards()
|
||||
local tekeliliHelper = getTekeliliHelper()
|
||||
|
||||
if tekeliliHelper then
|
||||
removeIgnoreLater = searchLib.onObject(tekeliliHelper, "isCardOrDeck")
|
||||
for _, obj in ipairs(removeIgnoreLater) do
|
||||
@ -295,10 +294,7 @@ end
|
||||
|
||||
-- clean up for play area
|
||||
function tidyPlayareaCoroutine()
|
||||
-- small wait to allow other operations to finish
|
||||
for k = 1, 10 do
|
||||
coroutine.yield(0)
|
||||
end
|
||||
coWaitFrames(10)
|
||||
|
||||
local trash = guidReferenceApi.getObjectByOwnerAndType("Mythos", "Trash")
|
||||
local playAreaZone = guidReferenceApi.getObjectByOwnerAndType("Mythos", "PlayAreaZone")
|
||||
@ -333,43 +329,46 @@ function tidyPlayerMatCoroutine()
|
||||
|
||||
if getOptionValue() then
|
||||
for _, color in ipairs(COLORS) do
|
||||
-- delay for animation purpose
|
||||
for k = 1, 20 do
|
||||
coroutine.yield(0)
|
||||
end
|
||||
|
||||
-- get respective trash
|
||||
local trash = guidReferenceApi.getObjectByOwnerAndType(color, "Trash")
|
||||
if trash == nil then
|
||||
printToAll("Trashcan for " .. color .. " playermat could not be found! Skipping this playermat.", "Yellow")
|
||||
goto continue
|
||||
end
|
||||
else
|
||||
coWaitFrames(20)
|
||||
|
||||
-- maybe store tekelili cards
|
||||
if tekeliliHelper then
|
||||
tekeliliHelper.call("storeTekelili", color)
|
||||
end
|
||||
-- maybe store tekelili cards
|
||||
if tekeliliHelper then
|
||||
tekeliliHelper.call("storeTekelili", color)
|
||||
end
|
||||
|
||||
-- remove objects (with exceptions)
|
||||
for _, obj in ipairs(playermatApi.searchAroundPlayermat(color)) do
|
||||
maybeTrashObject(obj, trash)
|
||||
end
|
||||
-- parse playermat objects
|
||||
for _, obj in ipairs(playermatApi.searchAroundPlayermat(color)) do
|
||||
-- reset action tokens
|
||||
if obj.hasTag("UniversalToken") and obj.is_face_down then
|
||||
obj.flip()
|
||||
end
|
||||
|
||||
-- reset "activeInvestigatorId" and "...class"
|
||||
local mat = guidReferenceApi.getObjectByOwnerAndType(color, "Playermat")
|
||||
mat.setVar("activeInvestigatorId", "00000")
|
||||
mat.setVar("activeInvestigatorClass", "Neutral")
|
||||
mat.call("updateTexture")
|
||||
-- get rid of temporary tokens
|
||||
if obj.hasTag("Temporary") then
|
||||
trash.putObject(obj)
|
||||
end
|
||||
|
||||
for k = 1, 5 do
|
||||
coroutine.yield(0)
|
||||
end
|
||||
-- remove objects (with exceptions)
|
||||
maybeTrashObject(obj, trash)
|
||||
end
|
||||
|
||||
-- maybe respawn tekelili cards
|
||||
if tekeliliHelper then
|
||||
tekeliliHelper.call("spawnStoredTekelili", color)
|
||||
-- reset "activeInvestigatorId" and "...class"
|
||||
local mat = guidReferenceApi.getObjectByOwnerAndType(color, "Playermat")
|
||||
mat.setVar("activeInvestigatorId", "00000")
|
||||
mat.setVar("activeInvestigatorClass", "Neutral")
|
||||
mat.call("updateTexture")
|
||||
|
||||
coWaitFrames(5)
|
||||
|
||||
-- maybe respawn tekelili cards
|
||||
if tekeliliHelper then
|
||||
tekeliliHelper.call("spawnStoredTekelili", color)
|
||||
end
|
||||
end
|
||||
::continue::
|
||||
end
|
||||
end
|
||||
|
||||
@ -431,3 +430,10 @@ function getOptionValue()
|
||||
return options["tidyPlayermats"]
|
||||
end
|
||||
end
|
||||
|
||||
-- pauses the current coroutine for 'frameCount' frames
|
||||
function coWaitFrames(frameCount)
|
||||
for k = 1, frameCount do
|
||||
coroutine.yield(0)
|
||||
end
|
||||
end
|
||||
|
@ -9,6 +9,7 @@ function onLoad()
|
||||
|
||||
-- index 0: button as hand size label
|
||||
buttonParamaters.hover_color = "White"
|
||||
buttonParamaters.label = 0
|
||||
buttonParamaters.click_function = "none"
|
||||
buttonParamaters.position = Vector(0, 0.11, -0.4)
|
||||
buttonParamaters.height = 0
|
||||
@ -33,11 +34,14 @@ function onLoad()
|
||||
buttonParamaters.font_color = "Black"
|
||||
self.createButton(buttonParamaters)
|
||||
|
||||
updateColors()
|
||||
-- make sure this part executes after the playermats are loaded
|
||||
Wait.time(function()
|
||||
updateColors()
|
||||
|
||||
-- start loop to update card count
|
||||
playermatApi.checkForDES(matColor)
|
||||
Wait.time(updateValue, 1, -1)
|
||||
-- start loop to update card count
|
||||
playermatApi.checkForDES(matColor)
|
||||
Wait.time(updateValue, 1, -1)
|
||||
end, 1)
|
||||
end
|
||||
|
||||
-- updates colors when object is dropped somewhere
|
||||
@ -70,6 +74,9 @@ function updateValue()
|
||||
updateColors()
|
||||
end
|
||||
|
||||
-- if one of the colors is undefined, then end here
|
||||
if matColor == nil or handColor == nil then return end
|
||||
|
||||
-- if there is still no handzone, then end here
|
||||
if Player[handColor].getHandCount() == 0 then return end
|
||||
|
||||
|
@ -4,6 +4,7 @@ local searchLib = require("util/SearchLib")
|
||||
|
||||
-- forward declaration of variables that are used across functions
|
||||
local matColor, handColor, setAsidePosition, setAsideRotation, drawDeckPosition, topCardDetected
|
||||
local addedVectorLines, addedSnapPoint
|
||||
|
||||
local quickParameters = {}
|
||||
quickParameters.function_owner = self
|
||||
@ -34,6 +35,7 @@ inputParameters.validation = 2
|
||||
|
||||
function onLoad()
|
||||
normalView()
|
||||
self.max_typed_number = 9999
|
||||
end
|
||||
|
||||
-- regular view with search box
|
||||
@ -89,6 +91,10 @@ function updateSearchNumber(_, _, input)
|
||||
inputParameters.value = tonumber(input)
|
||||
end
|
||||
|
||||
function onNumberTyped(playerColor, number)
|
||||
startSearch(playerColor, number)
|
||||
end
|
||||
|
||||
-- starts the search with the number from the input field
|
||||
function searchCustom(_, messageColor)
|
||||
local number = inputParameters.value
|
||||
@ -115,7 +121,7 @@ function startSearch(messageColor, number)
|
||||
-- get bounds to know the height of the deck
|
||||
local bounds = deckAreaObjects.draw.getBounds()
|
||||
drawDeckPosition = bounds.center + Vector(0, bounds.size.y / 2 + 0.2, 0)
|
||||
printToColor("Place target(s) of search on set aside hand.", messageColor, "Green")
|
||||
printToColor("Place target(s) of search on set aside spot.", messageColor, "Green")
|
||||
|
||||
-- get playermat orientation
|
||||
local offset = -15
|
||||
@ -127,10 +133,28 @@ function startSearch(messageColor, number)
|
||||
local handData = Player[handColor].getHandTransform()
|
||||
local handCards = Player[handColor].getHandObjects()
|
||||
setAsidePosition = (handData.position + offset * handData.right):setAt("y", 1.5)
|
||||
setAsideRotation = { handData.rotation.x, handData.rotation.y + 180, 180 }
|
||||
setAsideRotation = Vector(handData.rotation.x, handData.rotation.y + 180, 180)
|
||||
|
||||
-- place hand cards set aside
|
||||
deckLib.placeOrMergeIntoDeck(handCards, setAsidePosition, setAsideRotation)
|
||||
if #handCards > 0 then
|
||||
deckLib.placeOrMergeIntoDeck(handCards, setAsidePosition, setAsideRotation)
|
||||
end
|
||||
|
||||
-- add a temporary snap point for the set aside spot
|
||||
addedSnapPoint = { position = setAsidePosition, rotation = setAsideRotation }
|
||||
local snapPoints = Global.getSnapPoints() or {}
|
||||
table.insert(snapPoints, addedSnapPoint)
|
||||
Global.setSnapPoints(snapPoints)
|
||||
|
||||
-- add a temporary box for the set aside spot
|
||||
local vectorLines = Global.getVectorLines() or {}
|
||||
local boxSize = Vector(2.5, 0, 3.5)
|
||||
addedVectorLines = generateBoxData(setAsidePosition, boxSize, setAsideRotation.y, handColor)
|
||||
|
||||
for _, line in ipairs(addedVectorLines) do
|
||||
table.insert(vectorLines, line)
|
||||
end
|
||||
Global.setVectorLines(vectorLines)
|
||||
|
||||
-- handling for Norman Withers
|
||||
if deckAreaObjects.topCard then
|
||||
@ -182,4 +206,77 @@ function drawSetAsideCards()
|
||||
end
|
||||
obj.deal(count, handColor)
|
||||
end
|
||||
removeAddedSnapAndLines()
|
||||
end
|
||||
|
||||
function removeAddedSnapAndLines()
|
||||
local vectorLines = Global.getVectorLines() or {}
|
||||
local snapPoints = Global.getSnapPoints() or {}
|
||||
|
||||
-- look for previously added data and remove it (iterate in reverse because we're removing entries)
|
||||
for i = #vectorLines, 1, -1 do
|
||||
for _, boxLine in ipairs(addedVectorLines) do
|
||||
if vectorLines[i].points[1] == boxLine.points[1] and vectorLines[i].points[2] == boxLine.points[2] then
|
||||
table.remove(vectorLines, i)
|
||||
break
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
for i = #snapPoints, 1, -1 do
|
||||
if snapPoints[i].position == addedSnapPoint.position then
|
||||
table.remove(snapPoints, i)
|
||||
break
|
||||
end
|
||||
end
|
||||
|
||||
Global.setVectorLines(vectorLines)
|
||||
Global.setSnapPoints(snapPoints)
|
||||
end
|
||||
|
||||
-- generates the lines data for a rectangular box
|
||||
---@param center tts__Vector Center of the box
|
||||
---@param size tts__Vector X and Z dimension of the box
|
||||
---@param rotation number Rotation around the Y-axis for the box
|
||||
---@param boxColor string Color for the box
|
||||
---@return table lines Vector line data for the box
|
||||
function generateBoxData(center, size, rotation, boxColor)
|
||||
local halfWidth = size.x / 2
|
||||
local halfDepth = size.z / 2
|
||||
|
||||
-- corners of the box in local coordinates
|
||||
local corners = {
|
||||
Vector(-halfWidth, 0, -halfDepth),
|
||||
Vector(halfWidth, 0, -halfDepth),
|
||||
Vector(halfWidth, 0, halfDepth),
|
||||
Vector(-halfWidth, 0, halfDepth)
|
||||
}
|
||||
|
||||
-- translate corners to global coordinates
|
||||
for i, cornerVec in ipairs(corners) do
|
||||
local rotatedCornerVec = cornerVec:rotateOver('y', rotation)
|
||||
corners[i] = rotatedCornerVec + center
|
||||
end
|
||||
|
||||
-- generate the lines data
|
||||
local lines = {
|
||||
{
|
||||
points = { corners[1], corners[2] },
|
||||
color = boxColor
|
||||
},
|
||||
{
|
||||
points = { corners[2], corners[3] },
|
||||
color = boxColor
|
||||
},
|
||||
{
|
||||
points = { corners[3], corners[4] },
|
||||
color = boxColor
|
||||
},
|
||||
{
|
||||
points = { corners[4], corners[1] },
|
||||
color = boxColor
|
||||
}
|
||||
}
|
||||
|
||||
return lines
|
||||
end
|
||||
|
@ -4,7 +4,7 @@ do
|
||||
-- respawns the chaos bag with a new state of tokens
|
||||
---@param tokenList table List of chaos token ids
|
||||
ChaosBagApi.setChaosBagState = function(tokenList)
|
||||
return Global.call("setChaosBagState", tokenList)
|
||||
Global.call("setChaosBagState", tokenList)
|
||||
end
|
||||
|
||||
-- returns a Table List of chaos token ids in the current chaos bag
|
||||
@ -31,30 +31,31 @@ do
|
||||
-- returns all sealed tokens on cards to the chaos bag
|
||||
---@param playerColor string Color of the player to show the broadcast to
|
||||
ChaosBagApi.releaseAllSealedTokens = function(playerColor)
|
||||
return Global.call("releaseAllSealedTokens", playerColor)
|
||||
Global.call("releaseAllSealedTokens", playerColor)
|
||||
end
|
||||
|
||||
-- returns all drawn tokens to the chaos bag
|
||||
ChaosBagApi.returnChaosTokens = function()
|
||||
return Global.call("returnChaosTokens")
|
||||
Global.call("returnChaosTokens")
|
||||
end
|
||||
|
||||
-- removes the specified chaos token from the chaos bag
|
||||
---@param id string ID of the chaos token
|
||||
ChaosBagApi.removeChaosToken = function(id)
|
||||
return Global.call("removeChaosToken", id)
|
||||
Global.call("removeChaosToken", id)
|
||||
end
|
||||
|
||||
-- returns a chaos token to the bag and calls all relevant functions
|
||||
---@param token tts__Object Chaos token to return
|
||||
ChaosBagApi.returnChaosTokenToBag = function(token)
|
||||
return Global.call("returnChaosTokenToBag", token)
|
||||
---@param fromBag boolean whether or not the token to return was in the middle of being drawn (true) or elsewhere (false)
|
||||
ChaosBagApi.returnChaosTokenToBag = function(token, fromBag)
|
||||
Global.call("returnChaosTokenToBag", { token = token, fromBag = fromBag })
|
||||
end
|
||||
|
||||
-- spawns the specified chaos token and puts it into the chaos bag
|
||||
---@param id string ID of the chaos token
|
||||
ChaosBagApi.spawnChaosToken = function(id)
|
||||
return Global.call("spawnChaosToken", id)
|
||||
Global.call("spawnChaosToken", id)
|
||||
end
|
||||
|
||||
-- Checks to see if the chaos bag can be manipulated. If a player is searching the bag when tokens
|
||||
|
@ -176,6 +176,17 @@ function getOwnerOfObject(object)
|
||||
end
|
||||
end
|
||||
|
||||
-- check if the object is in a handzone
|
||||
for owner, subtable in pairs(GuidReferences) do
|
||||
for type, guid in pairs(subtable) do
|
||||
for _, zone in ipairs(object.getZones()) do
|
||||
if guid == zone.getGUID() then
|
||||
return owner
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
-- check if it is on an owned object
|
||||
local result = searchLib.belowPosition(object.getPosition())
|
||||
|
||||
|
@ -1,11 +1,12 @@
|
||||
local blessCurseManagerApi = require("chaosbag/BlessCurseManagerApi")
|
||||
local guidReferenceApi = require("core/GUIDReferenceApi")
|
||||
local mythosAreaApi = require("core/MythosAreaApi")
|
||||
local guidReferenceApi = require("core/GUIDReferenceApi")
|
||||
local mythosAreaApi = require("core/MythosAreaApi")
|
||||
local navigationOverlayApi = require("core/NavigationOverlayApi")
|
||||
local optionPanelApi = require("core/OptionPanelApi")
|
||||
local playermatApi = require("playermat/PlayermatApi")
|
||||
local searchLib = require("util/SearchLib")
|
||||
local victoryDisplayApi = require("core/VictoryDisplayApi")
|
||||
local optionPanelApi = require("core/OptionPanelApi")
|
||||
local playermatApi = require("playermat/PlayermatApi")
|
||||
local searchLib = require("util/SearchLib")
|
||||
local tokenChecker = require("core/token/TokenChecker")
|
||||
local victoryDisplayApi = require("core/VictoryDisplayApi")
|
||||
|
||||
function onLoad()
|
||||
addHotkey("Add doom to agenda", addDoomToAgenda)
|
||||
@ -75,15 +76,19 @@ function takeCardIntoThreatArea(playerColor, hoveredObject)
|
||||
local mat = guidReferenceApi.getObjectByOwnerAndType(matColor, "Playermat")
|
||||
|
||||
-- do not continue if the threat area is already full
|
||||
if playermatApi.getEncounterCardDrawPosition(matColor, false) == playermatApi.getEncounterCardDrawPosition(matColor, true) then
|
||||
local threatAreaPos = playermatApi.getEncounterCardDrawPosition(matColor, false)
|
||||
if threatAreaPos == playermatApi.getEncounterCardDrawPosition(matColor, true) then
|
||||
broadcastToColor("Threat area is full.", playerColor, "Yellow")
|
||||
return
|
||||
end
|
||||
|
||||
-- initialize list of objects to move
|
||||
local moveTheseObjects = {}
|
||||
-- initialize list of objects to move (and store local positions)
|
||||
local additionalObjects = {}
|
||||
for _, obj in ipairs(searchLib.onObject(hoveredObject, "isTileOrToken")) do
|
||||
table.insert(moveTheseObjects, obj)
|
||||
local data = {}
|
||||
data.object = obj
|
||||
data.localPos = hoveredObject.positionToLocal(obj.getPosition())
|
||||
table.insert(additionalObjects, data)
|
||||
end
|
||||
|
||||
-- find out if the original card is on the green or red playermats
|
||||
@ -97,29 +102,25 @@ function takeCardIntoThreatArea(playerColor, hoveredObject)
|
||||
modifierY = -90
|
||||
end
|
||||
|
||||
-- store local positions of objects
|
||||
local localPositions = {}
|
||||
for i, obj in ipairs(moveTheseObjects) do
|
||||
local localPos = hoveredObject.positionToLocal(obj.getPosition())
|
||||
localPositions[i] = localPos
|
||||
end
|
||||
|
||||
-- move the main card
|
||||
local pos = playermatApi.getEncounterCardDrawPosition(matColor, false)
|
||||
hoveredObject.setPosition(pos)
|
||||
hoveredObject.setRotation(hoveredObject.getRotation() - Vector(0, 270 - mat.getRotation().y - modifierY, 0))
|
||||
|
||||
local cardName = hoveredObject.getName()
|
||||
if cardName == nil or cardName == "" then
|
||||
cardName = "card(s)"
|
||||
end
|
||||
broadcastToAll("Placed " .. cardName .. " into threat area.", "White")
|
||||
if cardName == "" then cardName = "card" end
|
||||
broadcastToAll("Moved " .. cardName .. " to " .. getColoredName(playerColor) .. "'s threat area.", "White")
|
||||
|
||||
for i, obj in ipairs(moveTheseObjects) do
|
||||
if not obj.locked then
|
||||
local globalPos = hoveredObject.positionToWorld(localPositions[i])
|
||||
obj.setPosition(globalPos)
|
||||
obj.setRotation(obj.getRotation() - Vector(0, 270 - mat.getRotation().y - modifierY, 0))
|
||||
-- get new rotation (rounded)
|
||||
local cardRot = hoveredObject.getRotation()
|
||||
local roundedRotY = roundToMultiple(cardRot.y, 45)
|
||||
local deltaRotY = 270 - mat.getRotation().y - modifierY
|
||||
local newCardRot = cardRot:setAt("y", roundedRotY - deltaRotY)
|
||||
|
||||
-- move the main card to threat area
|
||||
hoveredObject.setRotation(newCardRot)
|
||||
hoveredObject.setPosition(threatAreaPos)
|
||||
|
||||
-- move tokens/tiles (to new global position)
|
||||
for _, data in ipairs(additionalObjects) do
|
||||
if not data.object.locked then
|
||||
data.object.setPosition(hoveredObject.positionToWorld(data.localPos))
|
||||
data.object.setRotation(data.object.getRotation() - Vector(0, deltaRotY, 0))
|
||||
end
|
||||
end
|
||||
end
|
||||
@ -131,7 +132,7 @@ function discardObject(playerColor, hoveredObject)
|
||||
if #selectedObjects > 0 then
|
||||
discardGroup(playerColor, selectedObjects)
|
||||
return
|
||||
-- only continue if an unlocked card, deck or tile was hovered
|
||||
-- only continue if an unlocked card, deck or tile was hovered
|
||||
elseif hoveredObject == nil
|
||||
or (hoveredObject.type ~= "Card" and hoveredObject.type ~= "Deck" and hoveredObject.type ~= "Tile")
|
||||
or hoveredObject.locked then
|
||||
@ -174,11 +175,11 @@ function discardGroup(playerColor, selectedObjects)
|
||||
local count = #selectedObjects
|
||||
-- discarding one at a time avoids an error with cards in the discard pile losing the 'hands' toggle and uses multiple mats
|
||||
for i = count, 1, -1 do
|
||||
Wait.time(function()
|
||||
Wait.time(function()
|
||||
if (selectedObjects[i].type == "Card" or selectedObjects[i].type ~= "Deck" or selectedObjects[i].type == "Tile") then
|
||||
performDiscard(playerColor, selectedObjects[i])
|
||||
performDiscard(playerColor, selectedObjects[i])
|
||||
end
|
||||
end, (count - i + 1) * 0.1)
|
||||
end, (count - i + 1) * 0.1)
|
||||
end
|
||||
end
|
||||
|
||||
@ -265,7 +266,7 @@ function removeOneUse(playerColor, hoveredObject)
|
||||
for _, obj in ipairs(searchLib.onObject(hoveredObject, "isTileOrToken")) do
|
||||
if not obj.locked and obj.memo ~= "resourceCounter" then
|
||||
-- check for matching object, otherwise use the first hit
|
||||
if obj.memo == searchForType then
|
||||
if obj.memo and obj.memo == searchForType then
|
||||
targetObject = obj
|
||||
break
|
||||
elseif not targetObject then
|
||||
@ -275,6 +276,15 @@ function removeOneUse(playerColor, hoveredObject)
|
||||
end
|
||||
end
|
||||
|
||||
-- release sealed token if card has one and no uses
|
||||
if tokenChecker.isChaosToken(targetObject) and hoveredObject.hasTag("CardThatSeals") then
|
||||
local func = hoveredObject.getVar("releaseOneToken") -- check if function exists
|
||||
if func ~= nil then
|
||||
hoveredObject.call("releaseOneToken", playerColor)
|
||||
return
|
||||
end
|
||||
end
|
||||
|
||||
-- error handling
|
||||
if not targetObject then
|
||||
broadcastToColor("No tokens found!", playerColor, "Yellow")
|
||||
@ -503,3 +513,7 @@ function getColoredName(playerColor)
|
||||
-- add bb-code
|
||||
return "[" .. Color.fromString(playerColor):toHex() .. "]" .. displayName .. "[-]"
|
||||
end
|
||||
|
||||
function roundToMultiple(num, mult)
|
||||
return math.floor((num + mult / 2) / mult) * mult
|
||||
end
|
||||
|
@ -160,8 +160,8 @@ function getRandomSeed()
|
||||
return math.random(999)
|
||||
end
|
||||
|
||||
-- Event hook for any object search. When chaos tokens are manipulated while the chaos bag
|
||||
-- container is being searched, a TTS bug can cause tokens to duplicate or vanish. We lock the
|
||||
-- Event hook for any object search. When chaos tokens are manipulated while the chaos bag
|
||||
-- container is being searched, a TTS bug can cause tokens to duplicate or vanish. We lock the
|
||||
-- chaos bag during search operations to avoid this.
|
||||
function onObjectSearchStart(object, playerColor)
|
||||
local chaosBag = findChaosBag()
|
||||
@ -170,14 +170,15 @@ function onObjectSearchStart(object, playerColor)
|
||||
end
|
||||
end
|
||||
|
||||
-- Event hook for any object search. When chaos tokens are manipulated while the chaos bag
|
||||
-- container is being searched, a TTS bug can cause tokens to duplicate or vanish. We lock the
|
||||
-- Event hook for any object search. When chaos tokens are manipulated while the chaos bag
|
||||
-- container is being searched, a TTS bug can cause tokens to duplicate or vanish. We lock the
|
||||
-- chaos bag during search operations to avoid this.
|
||||
function onObjectSearchEnd(object, playerColor)
|
||||
local chaosBag = findChaosBag()
|
||||
if object == chaosBag then
|
||||
bagSearchers[playerColor] = nil
|
||||
end
|
||||
Player[playerColor].clearSelectedObjects()
|
||||
end
|
||||
|
||||
-- Pass object enter container events to the PlayArea to clear vector lines from dragged cards.
|
||||
@ -207,15 +208,25 @@ function onObjectEnterZone(zone, object)
|
||||
object.clearContextMenu()
|
||||
object.call("shutOff")
|
||||
end
|
||||
if object.hasTag("CardThatSeals") then
|
||||
local func = object.getVar("resetSealedTokens") -- check if function exists (it won't for older custom content)
|
||||
if func ~= nil then
|
||||
object.call("resetSealedTokens")
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
-- TTS event for objects that leave zones
|
||||
function onObjectLeaveZone(zone, object)
|
||||
if zone.isDestroyed() or object.isDestroyed() then return end
|
||||
if zone.type == "Hand" and object.hasTag("CardWithHelper") then
|
||||
object.call("updateDisplay")
|
||||
end
|
||||
-- 1 frame delay to avoid error messages when exiting the game
|
||||
Wait.frames(
|
||||
function()
|
||||
if zone.isDestroyed() or object.isDestroyed() then return end
|
||||
if zone.type == "Hand" and object.hasTag("CardWithHelper") then
|
||||
object.call("updateDisplay")
|
||||
end
|
||||
end, 1)
|
||||
end
|
||||
|
||||
-- handle card drawing via number typing for multihanded gameplay
|
||||
@ -224,15 +235,6 @@ function onObjectNumberTyped(hoveredObject, playerColor, number)
|
||||
-- only continue for decks or cards
|
||||
if hoveredObject.type ~= "Deck" and hoveredObject.type ~= "Card" then return end
|
||||
|
||||
-- check whether the hovered object is part of a players draw objects
|
||||
for _, color in ipairs(playermatApi.getUsedMatColors()) do
|
||||
local deckAreaObjects = playermatApi.getDeckAreaObjects(color)
|
||||
if deckAreaObjects.topCard == hoveredObject or deckAreaObjects.draw == hoveredObject then
|
||||
playermatApi.drawCardsWithReshuffle(color, number)
|
||||
return true
|
||||
end
|
||||
end
|
||||
|
||||
-- check if this is a card with states (and then change state instead of drawing it)
|
||||
local states = hoveredObject.getStates()
|
||||
if states ~= nil and #states > 0 then
|
||||
@ -242,6 +244,15 @@ function onObjectNumberTyped(hoveredObject, playerColor, number)
|
||||
return true
|
||||
end
|
||||
end
|
||||
|
||||
-- check whether the hovered object is part of a players draw objects
|
||||
for _, color in ipairs(playermatApi.getUsedMatColors()) do
|
||||
local deckAreaObjects = playermatApi.getDeckAreaObjects(color)
|
||||
if deckAreaObjects.topCard == hoveredObject or deckAreaObjects.draw == hoveredObject then
|
||||
playermatApi.drawCardsWithReshuffle(color, number)
|
||||
return true
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
-- TTS event, used to redraw the playermat slot symbols after a small delay to account for the custom font loading
|
||||
@ -249,8 +260,9 @@ function onPlayerConnect()
|
||||
Wait.time(function() playermatApi.redrawSlotSymbols("All") end, 0.2)
|
||||
end
|
||||
|
||||
-- disable delete action (only applies to promoted players) and discard objects instead
|
||||
function onPlayerAction(player, action, targets)
|
||||
if action == Player.Action.Delete and player.admin == false then
|
||||
if action == Player.Action.Delete and not player.admin then
|
||||
for _, target in ipairs(targets) do
|
||||
local matColor = playermatApi.getMatColorByPosition(target.getPosition())
|
||||
local trash = guidReferenceApi.getObjectByOwnerAndType(matColor, "Trash")
|
||||
@ -296,13 +308,13 @@ function returnChaosTokens()
|
||||
end
|
||||
|
||||
-- returns a single chaos token to the bag and calls respective functions
|
||||
function returnChaosTokenToBag(token)
|
||||
local name = token.getName()
|
||||
function returnChaosTokenToBag(params)
|
||||
local name = params.token.getName()
|
||||
local chaosBag = findChaosBag()
|
||||
chaosBag.putObject(token)
|
||||
chaosBag.putObject(params.token)
|
||||
tokenArrangerApi.layout()
|
||||
if name == "Bless" or name == "Curse" then
|
||||
blessCurseManagerApi.releasedToken(name, token.getGUID(), true)
|
||||
blessCurseManagerApi.releasedToken(name, params.token.getGUID(), params.fromBag)
|
||||
end
|
||||
end
|
||||
|
||||
@ -413,7 +425,8 @@ function returnAndRedraw(_, tokenGUID)
|
||||
|
||||
-- perform the actual token replacing
|
||||
trackChaosToken(tokenName, mat.getGUID(), true)
|
||||
returnChaosTokenToBag(returnedToken)
|
||||
local params = {token = returnedToken, fromBag = true}
|
||||
returnChaosTokenToBag(params)
|
||||
|
||||
chaosTokens[indexOfReturnedToken] = drawChaosToken({
|
||||
mat = mat,
|
||||
@ -440,10 +453,13 @@ function returnAndRedraw(_, tokenGUID)
|
||||
end
|
||||
|
||||
redrawData = {}
|
||||
|
||||
-- return a reference to the freshly drawn token
|
||||
return chaosTokens[indexOfReturnedToken]
|
||||
end
|
||||
|
||||
-- Checks to see if the chaos bag can be manipulated. If a player is searching the bag when tokens
|
||||
-- are drawn or replaced a TTS bug can cause those tokens to vanish. Any functions which change the
|
||||
-- Checks to see if the chaos bag can be manipulated. If a player is searching the bag when tokens
|
||||
-- are drawn or replaced a TTS bug can cause those tokens to vanish. Any functions which change the
|
||||
-- contents of the bag should check this method before doing so.
|
||||
-- This method will broadcast a message to all players if the bag is being searched.
|
||||
---@return boolean: True if the bag is manipulated, false if it should be blocked.
|
||||
@ -543,9 +559,9 @@ end
|
||||
-- token spawning
|
||||
---------------------------------------------------------
|
||||
|
||||
-- DEPRECATED. Use TokenManager instead.
|
||||
-- DEPRECATED. Use TokenManager instead.
|
||||
-- Spawns a single token.
|
||||
---@param params table Array with arguments to the method. 1 = position, 2 = type, 3 = rotation
|
||||
---@param params table Array with arguments to the method. 1 = position, 2 = type, 3 = rotation
|
||||
function spawnToken(params)
|
||||
return tokenManager.spawnToken(params[1], params[2], params[3])
|
||||
end
|
||||
@ -1364,7 +1380,8 @@ function contentDownloadCallback(request, params)
|
||||
if pos then
|
||||
spawnTable.position = pos
|
||||
else
|
||||
broadcastToAll("Please make space in the area below the tentacle stand in the upper middle of the table and try again.", "Red")
|
||||
broadcastToAll(
|
||||
"Please make space in the area below the tentacle stand in the upper middle of the table and try again.", "Red")
|
||||
return
|
||||
end
|
||||
end
|
||||
@ -1515,10 +1532,11 @@ function playermatRemovalSelected(player, selectedIndex, id)
|
||||
if mat then
|
||||
-- confirmation dialog about deletion
|
||||
player.pingTable(mat.getPosition())
|
||||
player.showConfirmDialog("Do you really want to remove " .. matColor .. "'s playermat and related objects? This can't be reversed.",
|
||||
function()
|
||||
removePlayermat(matColor)
|
||||
end)
|
||||
player.showConfirmDialog(
|
||||
"Do you really want to remove " .. matColor .. "'s playermat and related objects? This can't be reversed.",
|
||||
function()
|
||||
removePlayermat(matColor)
|
||||
end)
|
||||
else
|
||||
-- info dialog that it is already deleted
|
||||
player.showInfoDialog(matColor .. "'s playermat has already been removed.")
|
||||
@ -1593,6 +1611,7 @@ function applyOptionPanelChange(id, state)
|
||||
local counter = guidReferenceApi.getObjectByOwnerAndType("Mythos", "MasterClueCounter")
|
||||
counter.setVar("useClickableCounters", state)
|
||||
|
||||
-- option: Enable card helpers
|
||||
elseif id == "enableCardHelpers" then
|
||||
toggleCardHelpers(state)
|
||||
|
||||
@ -1720,7 +1739,7 @@ function onClick_defaultSettings()
|
||||
optionPanel = {
|
||||
cardLanguage = "en",
|
||||
changePlayAreaImage = false,
|
||||
enableCardHelpers = false,
|
||||
enableCardHelpers = true,
|
||||
playAreaConnectionColor = { a = 1, b = 0.4, g = 0.4, r = 0.4 },
|
||||
playAreaConnections = true,
|
||||
playAreaSnapTags = true,
|
||||
|
@ -8,12 +8,12 @@ local tokenChecker = require("core/token/TokenChecker")
|
||||
local tokenSpawnTrackerApi = require("core/token/TokenSpawnTrackerApi")
|
||||
|
||||
local ENCOUNTER_DECK_AREA = {
|
||||
upperLeft = { x = 0.9, z = 0.42 },
|
||||
lowerRight = { x = 0.86, z = 0.38 }
|
||||
upperLeft = { x = 1.05, z = 0.15 },
|
||||
lowerRight = { x = 0.70, z = 0.59 }
|
||||
}
|
||||
local ENCOUNTER_DISCARD_AREA = {
|
||||
upperLeft = { x = 1.62, z = 0.42 },
|
||||
lowerRight = { x = 1.58, z = 0.38 }
|
||||
upperLeft = { x = 1.77, z = 0.15 },
|
||||
lowerRight = { x = 1.42, z = 0.59 }
|
||||
}
|
||||
|
||||
-- global position of encounter deck and discard pile
|
||||
@ -45,7 +45,7 @@ end
|
||||
-- collison and container event handling
|
||||
---------------------------------------------------------
|
||||
|
||||
-- TTS event handler. Handles scenario name event triggering and encounter card token resets.
|
||||
-- TTS event handler. Handles scenario name event triggering and encounter card token resets.
|
||||
function onCollisionEnter(collisionInfo)
|
||||
if not collisionEnabled then return end
|
||||
|
||||
@ -240,18 +240,16 @@ end
|
||||
function inArea(point, bounds)
|
||||
return (point.x < bounds.upperLeft.x
|
||||
and point.x > bounds.lowerRight.x
|
||||
and point.z < bounds.upperLeft.z
|
||||
and point.z > bounds.lowerRight.z)
|
||||
and point.z > bounds.upperLeft.z
|
||||
and point.z < bounds.lowerRight.z)
|
||||
end
|
||||
|
||||
-- removes tokens from the provided card/deck
|
||||
function removeTokensFromObject(object)
|
||||
local TRASH = guidReferenceApi.getObjectByOwnerAndType("Mythos", "Trash")
|
||||
for _, obj in ipairs(searchLib.onObject(object)) do
|
||||
for _, obj in ipairs(searchLib.onObject(object, "isTileOrToken")) do
|
||||
if obj.getGUID() ~= "4ee1f2" and -- table
|
||||
obj ~= self and
|
||||
obj.type ~= "Deck" and
|
||||
obj.type ~= "Card" and
|
||||
obj.memo ~= nil and
|
||||
obj.getLock() == false and
|
||||
not tokenChecker.isChaosToken(obj) then
|
||||
|
@ -51,20 +51,21 @@ As a nice reminder the XML button takes on the Frost color and icon with the tex
|
||||
> require...
|
||||
----------------------------------------------------------]]
|
||||
|
||||
local isHelperEnabled = false
|
||||
-- intentionally global
|
||||
hasXML = true
|
||||
isHelperEnabled = false
|
||||
|
||||
function updateSave()
|
||||
self.script_state = JSON.encode({ isHelperEnabled = isHelperEnabled })
|
||||
end
|
||||
|
||||
function onLoad(savedData)
|
||||
self.addTag("CardWithHelper")
|
||||
if savedData and savedData ~= "" then
|
||||
local loadedData = JSON.decode(savedData)
|
||||
isHelperEnabled = loadedData.isHelperEnabled
|
||||
end
|
||||
createHelperXML()
|
||||
checkOptionPanel()
|
||||
syncDisplayWithOptionPanel()
|
||||
end
|
||||
|
||||
function createHelperXML()
|
||||
@ -95,14 +96,6 @@ function createHelperXML()
|
||||
self.UI.setXmlTable(xmlTable)
|
||||
end
|
||||
|
||||
function shutOff()
|
||||
self.UI.hide("Helper")
|
||||
end
|
||||
|
||||
function initialize()
|
||||
self.UI.show("Helper")
|
||||
end
|
||||
|
||||
function triggerXMLTokenLabelCreation()
|
||||
Global.call("activeRedrawEffect", {
|
||||
VALID_TOKENS = VALID_TOKENS,
|
||||
|
@ -1,7 +1,16 @@
|
||||
--[[ Library for cards that seal tokens
|
||||
This file is used to add sealing option to cards' context menu.
|
||||
NOTE: all cards are allowed to release a single token to enable Hallow and A Watchful Peace,
|
||||
and to release all sealed tokens to allow for cards that might leave play with sealed tokens on them.
|
||||
Valid options (set before requiring this file):
|
||||
|
||||
MAX_SEALED --@type: number (maximum number of tokens allowable by the card to be sealed)
|
||||
- required for all cards
|
||||
- if MAX_SEALED is more than 1, then an XML label is created for the topmost token indicating the number of sealed tokens
|
||||
- gives an error if user tries to seal additional tokens on the card
|
||||
- example usage: "The Chthonian Stone"
|
||||
> MAX_SEALED = 1
|
||||
|
||||
UPDATE_ON_HOVER --@type: boolean
|
||||
- automatically updates the context menu options when the card is hovered
|
||||
- the "Read Bag" function reads the content of the chaos bag to update the context menu
|
||||
@ -12,19 +21,16 @@ KEEP_OPEN --@type: boolean
|
||||
- makes the context menu stay open after selecting an option
|
||||
- example usage: "Unrelenting"
|
||||
|
||||
SHOW_SINGLE_RELEASE --@type: boolean
|
||||
SHOW_MULTI_RELEASE --@type: number (maximum amount of tokens to release at once)
|
||||
- enables an entry in the context menu
|
||||
- this entry allows releasing a single token
|
||||
- example usage: "Holy Spear" (to keep the other tokens and just release one)
|
||||
|
||||
SHOW_MULTI_RELEASE --@type: number (amount of tokens to release at once)
|
||||
- enables an entry in the context menu
|
||||
- this entry allows releasing of multiple tokens at once
|
||||
- example usage: "Nephthys" (to release 3 bless tokens at once)
|
||||
- this entry allows releasing of multiple tokens at once, to the maximum number
|
||||
- does not fail if there are fewer than the maximum sealed
|
||||
- example usage: "Nephthys" (to release up to 3 bless tokens at once)
|
||||
|
||||
SHOW_MULTI_RETURN --@type: number (amount of tokens to return to pool at once)
|
||||
- enables an entry in the context menu
|
||||
- this entry allows returning tokens to the token pool
|
||||
- fails if not enough tokens are sealed
|
||||
- example usage: "Nephthys" (to return 3 bless tokens at once)
|
||||
|
||||
SHOW_MULTI_SEAL --@type: number (amount of tokens to seal at once)
|
||||
@ -58,6 +64,7 @@ Thus it should be implemented like this:
|
||||
> ["+1"] = true,
|
||||
> ["Elder Sign"] = true
|
||||
> }
|
||||
> MAX_SEALED = 1
|
||||
> require...
|
||||
----------------------------------------------------------
|
||||
Example 2: Holy Spear
|
||||
@ -68,8 +75,8 @@ Thus it should be implemented like this:
|
||||
> VALID_TOKENS = {
|
||||
> ["Bless"] = true
|
||||
> }
|
||||
> SHOW_SINGLE_RELEASE = true
|
||||
> SHOW_MULTI_SEAL = 2
|
||||
> MAX_SEALED = 10
|
||||
> require...
|
||||
----------------------------------------------------------]]
|
||||
|
||||
@ -83,6 +90,20 @@ local sealedTokens = {}
|
||||
local ID_URL_MAP = {}
|
||||
local tokensInBag = {}
|
||||
|
||||
-- XML background color for each token for label when stacked
|
||||
local tokenColor = {
|
||||
["Skull"] = "#4A0400E6",
|
||||
["Cultist"] = "#173B0BE6",
|
||||
["Tablet"] = "#1D2238E6",
|
||||
["Elder Thing"] = "#4D2331E6",
|
||||
["Auto-fail"] = "#9B0004E6",
|
||||
["Bless"] = "#9D702CE6",
|
||||
["Curse"] = "#633A84E6",
|
||||
["Frost"] = "#404450E6",
|
||||
["Elder Sign"] = "#50A8CEE6",
|
||||
[""] = "#77674DE6"
|
||||
}
|
||||
|
||||
function onSave() return JSON.encode(sealedTokens) end
|
||||
|
||||
function onLoad(savedData)
|
||||
@ -94,13 +115,15 @@ end
|
||||
|
||||
-- builds the context menu
|
||||
function generateContextMenu()
|
||||
-- conditional single or multi release options
|
||||
if SHOW_SINGLE_RELEASE then
|
||||
self.addContextMenuItem("Release token", releaseOneToken)
|
||||
elseif SHOW_MULTI_RELEASE then
|
||||
self.addContextMenuItem("Release one token", releaseOneToken)
|
||||
|
||||
-- conditional release options
|
||||
if MAX_SEALED > 1 then
|
||||
self.addContextMenuItem("Release all tokens", releaseAllTokens)
|
||||
end
|
||||
|
||||
if SHOW_MULTI_RELEASE then
|
||||
self.addContextMenuItem("Release " .. SHOW_MULTI_RELEASE .. " token(s)", releaseMultipleTokens)
|
||||
else
|
||||
self.addContextMenuItem("Release token(s)", releaseAllTokens)
|
||||
end
|
||||
|
||||
if RESOLVE_TOKEN then
|
||||
@ -138,7 +161,7 @@ function generateContextMenu()
|
||||
end
|
||||
|
||||
if allowed then
|
||||
for i = 1, SHOW_MULTI_SEAL do
|
||||
for i = SHOW_MULTI_SEAL, 1, -1 do
|
||||
sealToken(map.name, playerColor)
|
||||
end
|
||||
else
|
||||
@ -175,6 +198,10 @@ end
|
||||
|
||||
-- seals the named token on this card
|
||||
function sealToken(name, playerColor)
|
||||
if #sealedTokens >= MAX_SEALED then
|
||||
printToColor("Cannot seal any more tokens on this card", playerColor, "Red")
|
||||
return
|
||||
end
|
||||
if not chaosBagApi.canTouchChaosTokens() then return end
|
||||
local chaosbag = chaosBagApi.findChaosBag()
|
||||
for i, obj in ipairs(chaosbag.getObjects()) do
|
||||
@ -191,6 +218,16 @@ function sealToken(name, playerColor)
|
||||
if name == "Bless" or name == "Curse" then
|
||||
blessCurseManagerApi.sealedToken(name, guid)
|
||||
end
|
||||
-- destroy XML on just covered token
|
||||
if #sealedTokens > 1 then
|
||||
local coveredToken = getObjectFromGUID(sealedTokens[#sealedTokens - 1])
|
||||
if coveredToken ~= nil then
|
||||
coveredToken.UI.setXml("")
|
||||
else
|
||||
table.remove(sealedTokens, #sealedTokens - 1)
|
||||
end
|
||||
end
|
||||
updateStackSize()
|
||||
end
|
||||
})
|
||||
return
|
||||
@ -210,16 +247,22 @@ function releaseOneToken(playerColor)
|
||||
end
|
||||
end
|
||||
|
||||
-- release multiple tokens at once
|
||||
-- release up to multiple tokens at once with no minimum
|
||||
function releaseMultipleTokens(playerColor)
|
||||
if SHOW_MULTI_RELEASE <= #sealedTokens then
|
||||
for i = 1, SHOW_MULTI_RELEASE do
|
||||
putTokenAway(table.remove(sealedTokens))
|
||||
end
|
||||
printToColor("Releasing " .. SHOW_MULTI_RELEASE .. " tokens", playerColor)
|
||||
else
|
||||
if #sealedTokens == 0 then
|
||||
printToColor("Not enough tokens sealed.", playerColor)
|
||||
return
|
||||
end
|
||||
|
||||
local numRemoved = SHOW_MULTI_RELEASE
|
||||
if #sealedTokens < SHOW_MULTI_RELEASE then
|
||||
numRemoved = #sealedTokens
|
||||
end
|
||||
|
||||
for i = 1, numRemoved do
|
||||
putTokenAway(table.remove(sealedTokens))
|
||||
end
|
||||
printToColor("Releasing " .. numRemoved .. " tokens", playerColor)
|
||||
end
|
||||
|
||||
-- releases all sealed tokens
|
||||
@ -260,6 +303,7 @@ function putTokenAway(guid)
|
||||
if name == "Bless" or name == "Curse" then
|
||||
blessCurseManagerApi.releasedToken(name, guid)
|
||||
end
|
||||
updateStackSize()
|
||||
end
|
||||
|
||||
-- returns the token to the pool (== removes it)
|
||||
@ -272,6 +316,7 @@ function returnToken(guid)
|
||||
if name == "Bless" or name == "Curse" then
|
||||
blessCurseManagerApi.returnedToken(name, guid)
|
||||
end
|
||||
updateStackSize()
|
||||
end
|
||||
|
||||
-- resolves sealed token as if it came from the chaos bag
|
||||
@ -283,5 +328,41 @@ function resolveSealed()
|
||||
local closestMatColor = playermatApi.getMatColorByPosition(self.getPosition())
|
||||
local mat = guidReferenceApi.getObjectByOwnerAndType(closestMatColor, "Playermat")
|
||||
local guidToBeResolved = table.remove(sealedTokens)
|
||||
local resolvedToken = getObjectFromGUID(guidToBeResolved)
|
||||
resolvedToken.UI.setXml("")
|
||||
updateStackSize()
|
||||
chaosBagApi.drawChaosToken(mat, true, _, guidToBeResolved)
|
||||
end
|
||||
|
||||
function updateStackSize()
|
||||
if MAX_SEALED == 1 then return end
|
||||
if #sealedTokens == 0 then return end
|
||||
-- get topmost sealed token
|
||||
local topToken = getObjectFromGUID(sealedTokens[#sealedTokens])
|
||||
local name = topToken.getName()
|
||||
|
||||
topToken.UI.setXmlTable({
|
||||
{
|
||||
tag = "Panel",
|
||||
attributes = {
|
||||
height = 380,
|
||||
width = 380,
|
||||
rotation = "0 0 180",
|
||||
scale = "0.2 0.2 1",
|
||||
position = "0 0 -12",
|
||||
color = tokenColor[name] or "#77674DE6"
|
||||
},
|
||||
children = {
|
||||
tag = "Text",
|
||||
attributes = {
|
||||
fontSize = "380",
|
||||
font = "font_teutonic-arkham",
|
||||
color = "#ffffff",
|
||||
outline = "#000000",
|
||||
outlineSize = "8 -8",
|
||||
text = "x" .. #sealedTokens
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
end
|
||||
|
@ -1,7 +1,23 @@
|
||||
--[[ Library for cards that have helpers
|
||||
This file is used to share code between cards with helpers.
|
||||
It syncs the visibility of the helper with the option panel and
|
||||
makes sure the card has the respective tag.
|
||||
Additionally, it will call 'initiliaze()' and 'shutOff()'
|
||||
in the parent file if they are present.
|
||||
|
||||
Instructions:
|
||||
1) Define the global variables before requiring this file:
|
||||
hasXML = true (whether the card has an XML display)
|
||||
isHelperEnabled = false (default state of the helper, should be 'false')
|
||||
|
||||
2) In 'onLoad()'', call 'syncDisplayWithOptionPanel()'
|
||||
----------------------------------------------------------]]
|
||||
|
||||
local optionPanelApi = require("core/OptionPanelApi")
|
||||
|
||||
-- if the respective option is enabled in onLoad(), enable the helper
|
||||
function checkOptionPanel()
|
||||
function syncDisplayWithOptionPanel()
|
||||
self.addTag("CardWithHelper")
|
||||
local options = optionPanelApi.getOptions()
|
||||
if options.enableCardHelpers then
|
||||
setHelperState(true)
|
||||
@ -33,10 +49,12 @@ function actualDisplayUpdate()
|
||||
if isHelperEnabled then
|
||||
self.clearContextMenu()
|
||||
self.addContextMenuItem("Disable Helper", toggleHelper)
|
||||
if hasXML then self.UI.show("Helper") end
|
||||
if initialize then initialize() end
|
||||
else
|
||||
self.clearContextMenu()
|
||||
self.addContextMenuItem("Enable Helper", toggleHelper)
|
||||
if hasXML then self.UI.hide("Helper") end
|
||||
if shutOff then shutOff() end
|
||||
end
|
||||
end
|
||||
|
2
src/playercards/cards/Analysis.ttslua
Normal file
2
src/playercards/cards/Analysis.ttslua
Normal file
@ -0,0 +1,2 @@
|
||||
require("playercards/CardsWithHelper")
|
||||
require("playercards/CardsThatRedrawTokens")
|
@ -1,38 +1,40 @@
|
||||
require("playercards/CardsWithHelper")
|
||||
local blessCurseManagerApi = require("chaosbag/BlessCurseManagerApi")
|
||||
local chaosBagApi = require("chaosbag/ChaosBagApi")
|
||||
local guidReferenceApi = require("core/GUIDReferenceApi")
|
||||
local playermatApi = require("playermat/PlayermatApi")
|
||||
local blessCurseManagerApi = require("chaosbag/BlessCurseManagerApi")
|
||||
local chaosBagApi = require("chaosbag/ChaosBagApi")
|
||||
local guidReferenceApi = require("core/GUIDReferenceApi")
|
||||
local playermatApi = require("playermat/PlayermatApi")
|
||||
|
||||
local isHelperEnabled = false
|
||||
local updated
|
||||
-- intentionally global
|
||||
hasXML = true
|
||||
isHelperEnabled = false
|
||||
local updated, loopId
|
||||
|
||||
function updateSave()
|
||||
self.script_state = JSON.encode({ isHelperEnabled = isHelperEnabled })
|
||||
self.script_state = JSON.encode({
|
||||
isHelperEnabled = isHelperEnabled,
|
||||
loopId = loopId
|
||||
})
|
||||
end
|
||||
|
||||
function onLoad(savedData)
|
||||
self.addTag("CardWithHelper")
|
||||
if savedData and savedData ~= "" then
|
||||
local loadedData = JSON.decode(savedData)
|
||||
isHelperEnabled = loadedData.isHelperEnabled
|
||||
loopId = loadedData.loopId
|
||||
end
|
||||
checkOptionPanel()
|
||||
syncDisplayWithOptionPanel()
|
||||
end
|
||||
|
||||
-- hide buttons and stop monitoring
|
||||
function shutOff()
|
||||
self.UI.hide("Helper")
|
||||
Wait.stopAll()
|
||||
updateSave()
|
||||
if loopId then
|
||||
Wait.stop(loopId)
|
||||
loopId = nil
|
||||
end
|
||||
end
|
||||
|
||||
-- show buttons and begin monitoring chaos bag for curse and bless tokens
|
||||
function initialize()
|
||||
self.UI.show("Helper")
|
||||
maybeUpdateButtonState()
|
||||
Wait.time(maybeUpdateButtonState, 1, -1)
|
||||
updateSave()
|
||||
loopId = Wait.time(maybeUpdateButtonState, 1, -1)
|
||||
end
|
||||
|
||||
function resolveToken(player, _, tokenType)
|
||||
|
@ -2,5 +2,6 @@ VALID_TOKENS = {
|
||||
["+1"] = true,
|
||||
["Elder Sign"] = true
|
||||
}
|
||||
MAX_SEALED = 1
|
||||
|
||||
require("playercards/CardsThatSealTokens")
|
||||
|
@ -3,5 +3,6 @@ VALID_TOKENS = {
|
||||
}
|
||||
|
||||
KEEP_OPEN = true
|
||||
MAX_SEALED = 5
|
||||
|
||||
require("playercards/CardsThatSealTokens")
|
||||
|
@ -2,4 +2,6 @@ VALID_TOKENS = {
|
||||
["Elder Sign"] = true
|
||||
}
|
||||
|
||||
MAX_SEALED = 1
|
||||
|
||||
require("playercards/CardsThatSealTokens")
|
||||
|
@ -1,5 +1,9 @@
|
||||
require("playercards/CardsWithHelper")
|
||||
local playermatApi = require("playermat/PlayermatApi")
|
||||
local playermatApi = require("playermat/PlayermatApi")
|
||||
|
||||
-- intentionally global
|
||||
hasXML = false
|
||||
isHelperEnabled = false
|
||||
|
||||
-- common button parameters
|
||||
local buttonParameters = {}
|
||||
@ -28,7 +32,6 @@ local customizableList = {
|
||||
|
||||
-- index of the currently selected button (0-indexed from the top)
|
||||
local activeButtonIndex = -1
|
||||
local isHelperEnabled = false
|
||||
local hypothesisList = {}
|
||||
|
||||
function updateSave()
|
||||
@ -39,17 +42,17 @@ function updateSave()
|
||||
end
|
||||
|
||||
function onLoad(savedData)
|
||||
self.addTag("CardWithHelper")
|
||||
if savedData and savedData ~= "" then
|
||||
local loadedData = JSON.decode(savedData)
|
||||
isHelperEnabled = loadedData.isHelperEnabled
|
||||
activeButtonIndex = loadedData.activeButtonIndex
|
||||
end
|
||||
checkOptionPanel()
|
||||
|
||||
if activeButtonIndex > 0 then
|
||||
selectButton(activeButtonIndex)
|
||||
end
|
||||
|
||||
syncDisplayWithOptionPanel()
|
||||
end
|
||||
|
||||
function initialize()
|
||||
@ -74,7 +77,7 @@ function selectButton(index)
|
||||
end
|
||||
end
|
||||
|
||||
-- Create buttons based on the button parameters
|
||||
-- create buttons based on the button parameters
|
||||
function createButtons()
|
||||
self.clearButtons()
|
||||
|
||||
@ -88,7 +91,6 @@ function createButtons()
|
||||
local upgradeSheet = findUpgradeSheet()
|
||||
if upgradeSheet then
|
||||
for i = 1, 4 do
|
||||
log(4)
|
||||
if upgradeSheet.call("isUpgradeActive", i) then
|
||||
table.insert(hypothesisList, customizableList[i])
|
||||
end
|
||||
|
@ -1,26 +1,24 @@
|
||||
local playermatApi = require("playermat/PlayermatApi")
|
||||
local searchLib = require("util/SearchLib")
|
||||
local tokenManager = require("core/token/TokenManager")
|
||||
require("playercards/CardsWithHelper")
|
||||
local playermatApi = require("playermat/PlayermatApi")
|
||||
local searchLib = require("util/SearchLib")
|
||||
local tokenManager = require("core/token/TokenManager")
|
||||
|
||||
-- intentionally global
|
||||
hasXML = true
|
||||
isHelperEnabled = false
|
||||
local clickableResourceCounter = nil
|
||||
local foundTokens = 0
|
||||
local foundTokens = 0
|
||||
|
||||
function onLoad()
|
||||
self.addContextMenuItem("Add 4 resources",
|
||||
function(playerColor)
|
||||
Player[playerColor].clearSelectedObjects()
|
||||
add4(playerColor)
|
||||
end)
|
||||
self.addContextMenuItem("Take all resources",
|
||||
function(playerColor)
|
||||
Player[playerColor].clearSelectedObjects()
|
||||
takeAll(playerColor)
|
||||
end)
|
||||
self.addContextMenuItem("Discard all resources",
|
||||
function(playerColor)
|
||||
Player[playerColor].clearSelectedObjects()
|
||||
loseAll(playerColor)
|
||||
end)
|
||||
function updateSave()
|
||||
self.script_state = JSON.encode({ isHelperEnabled = isHelperEnabled })
|
||||
end
|
||||
|
||||
function onLoad(savedData)
|
||||
if savedData and savedData ~= "" then
|
||||
local loadedData = JSON.decode(savedData)
|
||||
isHelperEnabled = loadedData.isHelperEnabled
|
||||
end
|
||||
syncDisplayWithOptionPanel()
|
||||
end
|
||||
|
||||
function searchSelf()
|
||||
@ -40,7 +38,7 @@ function searchSelf()
|
||||
end
|
||||
end
|
||||
|
||||
function add4(playerColor)
|
||||
function add4()
|
||||
searchSelf()
|
||||
|
||||
local newCount = foundTokens + 4
|
||||
@ -51,7 +49,7 @@ function add4(playerColor)
|
||||
end
|
||||
end
|
||||
|
||||
function takeAll(playerColor)
|
||||
function takeAll(player)
|
||||
searchSelf()
|
||||
local matColor = playermatApi.getMatColorByPosition(self.getPosition())
|
||||
playermatApi.updateCounter(matColor, "ResourceCounter", _, foundTokens)
|
||||
@ -59,14 +57,13 @@ function takeAll(playerColor)
|
||||
if clickableResourceCounter then
|
||||
clickableResourceCounter.call("updateVal", 0)
|
||||
end
|
||||
printToColor("Moved " .. foundTokens .. " resource(s) to " .. matColor .. "'s resource pool.", playerColor)
|
||||
printToColor("Moved " .. foundTokens .. " resource(s) to " .. matColor .. "'s resource pool.", player.color)
|
||||
end
|
||||
|
||||
function loseAll(playerColor)
|
||||
function loseAll(player)
|
||||
searchSelf()
|
||||
|
||||
if clickableResourceCounter then
|
||||
clickableResourceCounter.call("updateVal", 0)
|
||||
end
|
||||
printToColor("Discarded " .. foundTokens .. " resource(s).", playerColor)
|
||||
printToColor("Discarded " .. foundTokens .. " resource(s).", player.color)
|
||||
end
|
||||
|
@ -2,8 +2,8 @@ VALID_TOKENS = {
|
||||
["Curse"] = true
|
||||
}
|
||||
|
||||
SHOW_SINGLE_RELEASE = true
|
||||
KEEP_OPEN = true
|
||||
MAX_SEALED = 3
|
||||
RESOLVE_TOKEN = true
|
||||
|
||||
require("playercards/CardsThatSealTokens")
|
||||
|
@ -2,8 +2,8 @@ VALID_TOKENS = {
|
||||
["Bless"] = true
|
||||
}
|
||||
|
||||
SHOW_SINGLE_RELEASE = true
|
||||
KEEP_OPEN = true
|
||||
MAX_SEALED = 3
|
||||
RESOLVE_TOKEN = true
|
||||
|
||||
require("playercards/CardsThatSealTokens")
|
||||
|
@ -2,7 +2,7 @@ VALID_TOKENS = {
|
||||
["Curse"] = true
|
||||
}
|
||||
|
||||
SHOW_SINGLE_RELEASE = true
|
||||
MAX_SEALED = 10
|
||||
KEEP_OPEN = true
|
||||
|
||||
require("playercards/CardsThatSealTokens")
|
||||
|
@ -2,7 +2,7 @@ VALID_TOKENS = {
|
||||
["Bless"] = true
|
||||
}
|
||||
|
||||
SHOW_SINGLE_RELEASE = true
|
||||
SHOW_MULTI_SEAL = 2
|
||||
MAX_SEALED = 10
|
||||
|
||||
require("playercards/CardsThatSealTokens")
|
||||
|
@ -5,8 +5,10 @@ local playermatApi = require("playermat/PlayermatApi")
|
||||
local searchLib = require("util/SearchLib")
|
||||
local tokenManager = require("core/token/TokenManager")
|
||||
|
||||
local isHelperEnabled = false
|
||||
local updated
|
||||
-- intentionally global
|
||||
hasXML = true
|
||||
isHelperEnabled = false
|
||||
local updated, loopId
|
||||
|
||||
local xmlData = {
|
||||
Action = { color = "#6D202CE6", onClick = "removeAndExtraAction" },
|
||||
@ -16,31 +18,31 @@ local xmlData = {
|
||||
}
|
||||
|
||||
function updateSave()
|
||||
self.script_state = JSON.encode({ isHelperEnabled = isHelperEnabled })
|
||||
self.script_state = JSON.encode({
|
||||
isHelperEnabled = isHelperEnabled,
|
||||
loopId = loopId
|
||||
})
|
||||
end
|
||||
|
||||
function onLoad(savedData)
|
||||
self.addTag("CardWithHelper")
|
||||
if savedData and savedData ~= "" then
|
||||
local loadedData = JSON.decode(savedData)
|
||||
isHelperEnabled = loadedData.isHelperEnabled
|
||||
loopId = loadedData.loopId
|
||||
end
|
||||
checkOptionPanel()
|
||||
syncDisplayWithOptionPanel()
|
||||
end
|
||||
|
||||
-- hide buttons and stop monitoring
|
||||
function shutOff()
|
||||
self.UI.hide("Helper")
|
||||
Wait.stopAll()
|
||||
updateSave()
|
||||
end
|
||||
|
||||
-- show buttons and begin monitoring chaos bag for curse and bless tokens
|
||||
function initialize()
|
||||
self.UI.show("Helper")
|
||||
maybeUpdateButtonState()
|
||||
Wait.time(maybeUpdateButtonState, 1, -1)
|
||||
updateSave()
|
||||
loopId = Wait.time(maybeUpdateButtonState, 1, -1)
|
||||
end
|
||||
|
||||
function shutOff()
|
||||
if loopId then
|
||||
Wait.stop(loopId)
|
||||
loopId = nil
|
||||
end
|
||||
end
|
||||
|
||||
function addTokenToBag(_, _, tokenType)
|
||||
|
@ -2,8 +2,9 @@ VALID_TOKENS = {
|
||||
["Bless"] = true
|
||||
}
|
||||
|
||||
SHOW_SINGLE_RELEASE = true
|
||||
KEEP_OPEN = true
|
||||
SHOW_MULTI_RELEASE = 3
|
||||
SHOW_MULTI_RETURN = 3
|
||||
MAX_SEALED = 10
|
||||
|
||||
require("playercards/CardsThatSealTokens")
|
||||
|
@ -5,5 +5,6 @@ INVALID_TOKENS = {
|
||||
}
|
||||
|
||||
UPDATE_ON_HOVER = true
|
||||
MAX_SEALED = 1
|
||||
|
||||
require("playercards/CardsThatSealTokens")
|
||||
|
@ -3,5 +3,6 @@ VALID_TOKENS = {
|
||||
}
|
||||
|
||||
KEEP_OPEN = true
|
||||
MAX_SEALED = 3
|
||||
|
||||
require("playercards/CardsThatSealTokens")
|
||||
|
@ -3,6 +3,6 @@ VALID_TOKENS = {
|
||||
}
|
||||
|
||||
KEEP_OPEN = true
|
||||
SHOW_SINGLE_RELEASE = true
|
||||
MAX_SEALED = 5
|
||||
|
||||
require("playercards/CardsThatSealTokens")
|
||||
|
@ -2,4 +2,6 @@ VALID_TOKENS = {
|
||||
["Auto-fail"] = true
|
||||
}
|
||||
|
||||
MAX_SEALED = 1
|
||||
|
||||
require("playercards/CardsThatSealTokens")
|
||||
|
@ -2,4 +2,6 @@ VALID_TOKENS = {
|
||||
["Elder Sign"] = true
|
||||
}
|
||||
|
||||
MAX_SEALED = 1
|
||||
|
||||
require("playercards/CardsThatSealTokens")
|
||||
|
@ -2,6 +2,6 @@ VALID_TOKENS = {
|
||||
["0"] = true
|
||||
}
|
||||
|
||||
SHOW_SINGLE_RELEASE = true
|
||||
MAX_SEALED = 4 -- Core Set is component-limited to 4 '0' tokens
|
||||
|
||||
require("playercards/CardsThatSealTokens")
|
||||
|
@ -3,6 +3,6 @@ VALID_TOKENS = {
|
||||
}
|
||||
|
||||
KEEP_OPEN = true
|
||||
SHOW_SINGLE_RELEASE = true
|
||||
MAX_SEALED = 5
|
||||
|
||||
require("playercards/CardsThatSealTokens")
|
||||
|
2
src/playercards/cards/Strong-Armed.ttslua
Normal file
2
src/playercards/cards/Strong-Armed.ttslua
Normal file
@ -0,0 +1,2 @@
|
||||
require("playercards/CardsWithHelper")
|
||||
require("playercards/CardsThatRedrawTokens")
|
@ -5,4 +5,6 @@ VALID_TOKENS = {
|
||||
["Elder Thing"] = true,
|
||||
}
|
||||
|
||||
MAX_SEALED = 1
|
||||
|
||||
require("playercards/CardsThatSealTokens")
|
||||
|
@ -3,5 +3,6 @@ VALID_TOKENS = {
|
||||
}
|
||||
|
||||
RESOLVE_TOKEN = true
|
||||
MAX_SEALED = 1
|
||||
|
||||
require("playercards/CardsThatSealTokens")
|
||||
|
2
src/playercards/cards/ThirdTimesaCharm.ttslua
Normal file
2
src/playercards/cards/ThirdTimesaCharm.ttslua
Normal file
@ -0,0 +1,2 @@
|
||||
require("playercards/CardsWithHelper")
|
||||
require("playercards/CardsThatRedrawTokens")
|
@ -5,5 +5,6 @@ INVALID_TOKENS = {
|
||||
|
||||
UPDATE_ON_HOVER = true
|
||||
KEEP_OPEN = true
|
||||
MAX_SEALED = 3
|
||||
|
||||
require("playercards/CardsThatSealTokens")
|
||||
|
@ -1,5 +1,11 @@
|
||||
require("playercards/CardsWithHelper")
|
||||
local playermatApi = require("playermat/PlayermatApi")
|
||||
local playermatApi = require("playermat/PlayermatApi")
|
||||
|
||||
-- intentionally global
|
||||
hasXML = false
|
||||
isHelperEnabled = false
|
||||
|
||||
local modValue, loopId
|
||||
|
||||
local buttonParameters = {
|
||||
click_function = "shutOff",
|
||||
@ -10,13 +16,20 @@ local buttonParameters = {
|
||||
height = 175
|
||||
}
|
||||
|
||||
local modValue
|
||||
|
||||
function updateSave()
|
||||
self.script_state = JSON.encode({ isHelperEnabled = isHelperEnabled })
|
||||
self.script_state = JSON.encode({
|
||||
isHelperEnabled = isHelperEnabled,
|
||||
loopId = loopId
|
||||
})
|
||||
end
|
||||
|
||||
function onLoad(savedData)
|
||||
if savedData and savedData ~= "" then
|
||||
local loadedData = JSON.decode(savedData)
|
||||
isHelperEnabled = loadedData.isHelperEnabled
|
||||
loopId = loadedData.loopId
|
||||
end
|
||||
|
||||
-- use metadata to detect level and adjust modValue accordingly
|
||||
if JSON.decode(self.getGMNotes()).level == 0 then
|
||||
modValue = 5
|
||||
@ -24,25 +37,22 @@ function onLoad(savedData)
|
||||
modValue = 4
|
||||
end
|
||||
|
||||
self.addTag("CardWithHelper")
|
||||
if savedData and savedData ~= "" then
|
||||
local loadedData = JSON.decode(savedData)
|
||||
isHelperEnabled = loadedData.isHelperEnabled
|
||||
end
|
||||
checkOptionPanel()
|
||||
updateDisplay()
|
||||
syncDisplayWithOptionPanel()
|
||||
end
|
||||
|
||||
function initialize()
|
||||
self.clearButtons()
|
||||
self.createButton(buttonParameters)
|
||||
updateButton()
|
||||
Wait.time(updateButton, 2, -1)
|
||||
loopId = Wait.time(updateButton, 2, -1)
|
||||
end
|
||||
|
||||
function shutOff()
|
||||
self.clearButtons()
|
||||
Wait.stopAll()
|
||||
if loopId then
|
||||
Wait.stop(loopId)
|
||||
loopId = nil
|
||||
end
|
||||
end
|
||||
|
||||
function updateButton()
|
||||
|
@ -76,12 +76,12 @@ local buttonParameters = {
|
||||
|
||||
-- table of texture URLs
|
||||
local nameToTexture = {
|
||||
Guardian = "http://cloud-3.steamusercontent.com/ugc/2501268517203536128/853B9CD08FC14A8B2A08C73D8ED77E0FE235CCCB/",
|
||||
Mystic = "http://cloud-3.steamusercontent.com/ugc/2501268517203536470/11C99488B9CA9236059A5F02E4A852A7C77B42A6/",
|
||||
Guardian = "http://cloud-3.steamusercontent.com/ugc/2501268517241599869/179119CA88170D9F5C87CD00D267E6F9F397D2F7/",
|
||||
Mystic = "http://cloud-3.steamusercontent.com/ugc/2501268517241600113/F6473F92B3435C32A685BB4DC2A88C2504DDAC4F/",
|
||||
Neutral = "http://cloud-3.steamusercontent.com/ugc/2462982115659543571/5D778EA4BC682DAE97E8F59A991BCF8CB3979B04/",
|
||||
Rogue = "http://cloud-3.steamusercontent.com/ugc/2501268517203536767/587791B327255DB8F953B27BB9E4DE602FA32B64/",
|
||||
Seeker = "http://cloud-3.steamusercontent.com/ugc/2501268517203537098/EFD9FC4CCDB105EFFDFF7A57C915CD984865760D/",
|
||||
Survivor = "http://cloud-3.steamusercontent.com/ugc/2501268517203537426/14EF780606D9A449F31A007226CB48D05AA820FF/"
|
||||
Rogue = "http://cloud-3.steamusercontent.com/ugc/2501268517241600395/00CFAFC13D7B6EACC147D22A40AF9FBBFFAF3136/",
|
||||
Seeker = "http://cloud-3.steamusercontent.com/ugc/2501268517241600579/92DEB412D8D3A9C26D1795CEA0335480409C3E4B/",
|
||||
Survivor = "http://cloud-3.steamusercontent.com/ugc/2501268517241600848/CEB685E9C8A4A3C18A4B677A519B49423B54E886/"
|
||||
}
|
||||
|
||||
-- translation table for slot names to characters for special font
|
||||
@ -141,6 +141,8 @@ function onLoad(savedData)
|
||||
slotData = loadedData.slotData
|
||||
end
|
||||
|
||||
updateMessageColor(playerColor)
|
||||
|
||||
self.interactable = false
|
||||
|
||||
-- get object references to owned objects
|
||||
@ -271,7 +273,7 @@ function discardListOfObjects(objList)
|
||||
end
|
||||
elseif tokenChecker.isChaosToken(obj) then
|
||||
-- put chaos tokens back into bag (e.g. Unrelenting)
|
||||
chaosBagApi.returnChaosTokenToBag(obj)
|
||||
chaosBagApi.returnChaosTokenToBag(obj, false)
|
||||
elseif not obj.getLock() and not obj.hasTag("DontDiscard") then
|
||||
-- don't touch locked objects (like the table etc.) or specific objects (like key tokens)
|
||||
ownedObjects.Trash.putObject(obj)
|
||||
@ -404,7 +406,7 @@ function doUpkeep(_, clickedByColor, isRightClick)
|
||||
|
||||
for _, card in ipairs(handCards) do
|
||||
local md = JSON.decode(card.getGMNotes())
|
||||
if md ~= nil and (not md.weakness and not md.hidden and md.type ~= "Enemy") then
|
||||
if card.type == "Card" and md ~= nil and (not md.weakness and not md.hidden and md.id ~= "52020") then
|
||||
table.insert(cardsToDiscard, card)
|
||||
end
|
||||
end
|
||||
@ -564,23 +566,46 @@ function doDiscardOne()
|
||||
broadcastToColor("Cannot discard from empty hand!", messageColor, "Red")
|
||||
else
|
||||
local choices = {}
|
||||
for i = 1, #hand do
|
||||
local notes = JSON.decode(hand[i].getGMNotes())
|
||||
if notes ~= nil then
|
||||
if notes.hidden ~= true then
|
||||
local hiddenCards = {}
|
||||
local missingMetadataCards = {}
|
||||
for i, handObj in ipairs(hand) do
|
||||
if handObj.type == "Card" then
|
||||
-- get a name for the card or use the index if unnamed
|
||||
local name = handObj.getName()
|
||||
if name == "" then
|
||||
name = "Card " .. i
|
||||
end
|
||||
|
||||
-- check card for metadata
|
||||
local md = JSON.decode(handObj.getGMNotes())
|
||||
if md == nil then
|
||||
table.insert(missingMetadataCards, name)
|
||||
elseif md.hidden or md.id == "52020" then
|
||||
table.insert(hiddenCards, name)
|
||||
else
|
||||
table.insert(choices, i)
|
||||
end
|
||||
else
|
||||
table.insert(choices, i)
|
||||
end
|
||||
end
|
||||
|
||||
-- print message with hidden cards
|
||||
if #hiddenCards > 0 then
|
||||
local cardList = concatenateListOfStrings(hiddenCards)
|
||||
printToColor("Excluded (hidden): " .. cardList, messageColor)
|
||||
end
|
||||
|
||||
-- print message with missing metadata cards
|
||||
if #missingMetadataCards > 0 then
|
||||
local cardList = concatenateListOfStrings(missingMetadataCards)
|
||||
printToColor("Excluded (missing data): " .. cardList, messageColor)
|
||||
end
|
||||
|
||||
if #choices == 0 then
|
||||
broadcastToColor("Hidden cards can't be randomly discarded.", messageColor, "Orange")
|
||||
broadcastToColor("Didn't find any eligible cards for random discarding.", messageColor, "Orange")
|
||||
return
|
||||
end
|
||||
|
||||
-- get a random non-hidden card (from the "choices" table)
|
||||
-- get a random eligible card (from the "choices" table)
|
||||
local num = math.random(1, #choices)
|
||||
deckLib.placeOrMergeIntoDeck(hand[choices[num]], returnGlobalDiscardPosition(), self.getRotation())
|
||||
broadcastToAll(getColoredName(playerColor) .. " randomly discarded card "
|
||||
@ -588,6 +613,19 @@ function doDiscardOne()
|
||||
end
|
||||
end
|
||||
|
||||
function concatenateListOfStrings(list)
|
||||
local cardList
|
||||
for _, cardName in ipairs(list) do
|
||||
if not cardList then
|
||||
cardList = ""
|
||||
else
|
||||
cardList = cardList .. ", "
|
||||
end
|
||||
cardList = cardList .. cardName
|
||||
end
|
||||
return cardList
|
||||
end
|
||||
|
||||
-- checks if DES is present
|
||||
function checkForDES()
|
||||
hasDES = false
|
||||
@ -1031,7 +1069,7 @@ function removeTokensFromObject(object)
|
||||
|
||||
for _, obj in ipairs(searchLib.onObject(object)) do
|
||||
if tokenChecker.isChaosToken(obj) then
|
||||
chaosBagApi.returnChaosTokenToBag(obj)
|
||||
chaosBagApi.returnChaosTokenToBag(obj, false)
|
||||
elseif obj.getGUID() ~= "4ee1f2" and -- table
|
||||
obj ~= self and
|
||||
obj.type ~= "Deck" and
|
||||
|
@ -30,7 +30,7 @@ do
|
||||
max_distance = maxDistance or 0
|
||||
})
|
||||
|
||||
-- filtering the result
|
||||
-- filter the result for matching objects
|
||||
local objList = {}
|
||||
for _, v in ipairs(searchResult) do
|
||||
if not filter or filterFunc(v.hit_object) then
|
||||
@ -47,22 +47,22 @@ do
|
||||
|
||||
-- searches the area on an object
|
||||
SearchLib.onObject = function(obj, filter)
|
||||
pos = obj.getPosition()
|
||||
size = obj.getBounds().size:setAt("y", 1)
|
||||
local pos = obj.getPosition()
|
||||
local size = obj.getBounds().size:setAt("y", 1)
|
||||
return returnSearchResult(pos, _, size, filter)
|
||||
end
|
||||
|
||||
-- searches the specified position (a single point)
|
||||
SearchLib.atPosition = function(pos, filter)
|
||||
size = { 0.1, 2, 0.1 }
|
||||
local size = { 0.1, 2, 0.1 }
|
||||
return returnSearchResult(pos, _, size, filter)
|
||||
end
|
||||
|
||||
-- searches below the specified position (downwards until y = 0)
|
||||
SearchLib.belowPosition = function(pos, filter)
|
||||
size = { 0.1, 2, 0.1 }
|
||||
direction = { 0, -1, 0 }
|
||||
maxDistance = pos.y
|
||||
local size = { 0.1, 2, 0.1 }
|
||||
local direction = { 0, -1, 0 }
|
||||
local maxDistance = pos.y
|
||||
return returnSearchResult(pos, _, size, filter, direction, maxDistance)
|
||||
end
|
||||
|
||||
|
37
xml/playercards/FamilyInheritance.xml
Normal file
37
xml/playercards/FamilyInheritance.xml
Normal file
@ -0,0 +1,37 @@
|
||||
<Defaults>
|
||||
<Button padding="30 30 30 30"
|
||||
font="font_teutonic-arkham"
|
||||
textColor="white"
|
||||
fontSize="235"
|
||||
shadow="#405041B3"
|
||||
shadowDistance="-15 15"/>
|
||||
<TableLayout position="130 0 -22"
|
||||
rotation="0 0 270"
|
||||
height="460"
|
||||
width="2600"
|
||||
scale="0.1 0.1 1"
|
||||
cellSpacing="80"
|
||||
cellBackgroundColor="rgba(1,1,1,0)"/>
|
||||
</Defaults>
|
||||
|
||||
<TableLayout id="Helper"
|
||||
active="false">
|
||||
<Row>
|
||||
<Cell>
|
||||
<Button onClick="loseAll"
|
||||
color="#6D202C"
|
||||
fontSize="195"
|
||||
text="Discard all"/>
|
||||
</Cell>
|
||||
<Cell>
|
||||
<Button onClick="takeAll"
|
||||
color="#173B0B"
|
||||
text="Move all"/>
|
||||
</Cell>
|
||||
<Cell>
|
||||
<Button onClick="add4"
|
||||
color="#77674D"
|
||||
text="Place 4"/>
|
||||
</Cell>
|
||||
</Row>
|
||||
</TableLayout>
|
Loading…
x
Reference in New Issue
Block a user