diff --git a/objects/ChaosBag.fea079.json b/objects/ChaosBag.fea079.json
index c754bb79..120a732f 100644
--- a/objects/ChaosBag.fea079.json
+++ b/objects/ChaosBag.fea079.json
@@ -63,7 +63,7 @@
"IgnoreFoW": false,
"LayoutGroupSortIndex": 0,
"Locked": false,
- "LuaScript": "require(\"chaosbag/ChaosBag\")",
+ "LuaScript": "",
"LuaScriptState": "",
"MaterialIndex": -1,
"MeasureMovement": false,
diff --git a/objects/ChaosTokenReserve.106418.json b/objects/ChaosTokenReserve.106418.json
index 909ac287..fde4514a 100644
--- a/objects/ChaosTokenReserve.106418.json
+++ b/objects/ChaosTokenReserve.106418.json
@@ -18,7 +18,7 @@
"Curse.16a9a7",
"Bless.8e3aab",
"ElderSign.0b1aca",
- "Auto-Fail.e31821",
+ "Auto-fail.e31821",
"ElderThing.38609c",
"Tablet.1a1506",
"Cultist.7d6103",
diff --git a/objects/ChaosTokenReserve.106418/Auto-Fail.e31821.json b/objects/ChaosTokenReserve.106418/Auto-fail.e31821.json
similarity index 97%
rename from objects/ChaosTokenReserve.106418/Auto-Fail.e31821.json
rename to objects/ChaosTokenReserve.106418/Auto-fail.e31821.json
index c0d32e93..4825ddbe 100644
--- a/objects/ChaosTokenReserve.106418/Auto-Fail.e31821.json
+++ b/objects/ChaosTokenReserve.106418/Auto-fail.e31821.json
@@ -37,7 +37,7 @@
"LuaScriptState": "",
"MeasureMovement": false,
"Name": "Custom_Tile",
- "Nickname": "Auto-Fail",
+ "Nickname": "Auto-fail",
"Snap": true,
"Sticky": true,
"Tooltip": true,
diff --git a/objects/Fan-MadeAccessories.aa8b38.json b/objects/Fan-MadeAccessories.aa8b38.json
index 635e68be..205119ae 100644
--- a/objects/Fan-MadeAccessories.aa8b38.json
+++ b/objects/Fan-MadeAccessories.aa8b38.json
@@ -15,8 +15,7 @@
},
"ContainedObjects_order": [
"ArkhamFantasy-PixelArtMini-Cards.e17c9e",
- "DrawTokenButtonTooltipRenamer.cc77a8",
- "WhimsicalsGenericDifficultySelector.05efb4",
+ "GenericDifficultySelector.8112ff",
"LuckyPenny.2ab443",
"Double-SidedResource.bc81cb",
"DescriptivePhaseTracker.b171c8",
diff --git a/objects/Fan-MadeAccessories.aa8b38/DrawTokenButtonTooltipRenamer.cc77a8.json b/objects/Fan-MadeAccessories.aa8b38/DrawTokenButtonTooltipRenamer.cc77a8.json
deleted file mode 100644
index 20e25995..00000000
--- a/objects/Fan-MadeAccessories.aa8b38/DrawTokenButtonTooltipRenamer.cc77a8.json
+++ /dev/null
@@ -1,45 +0,0 @@
-{
- "AltLookAngle": {
- "x": 0,
- "y": 0,
- "z": 0
- },
- "Autoraise": true,
- "ColorDiffuse": {
- "b": 0,
- "g": 0,
- "r": 1
- },
- "Description": "By Pyxel",
- "DragSelectable": true,
- "GMNotes": "",
- "GUID": "cc77a8",
- "Grid": true,
- "GridProjection": false,
- "Hands": false,
- "HideWhenFaceDown": false,
- "IgnoreFoW": false,
- "LayoutGroupSortIndex": 0,
- "Locked": false,
- "LuaScriptState": "",
- "LuaScript_path": "Fan-MadeAccessories.aa8b38/DrawTokenButtonTooltipRenamer.cc77a8.ttslua",
- "MeasureMovement": false,
- "Name": "Checker_red",
- "Nickname": "Draw Token Button Tooltip Renamer",
- "Snap": true,
- "Sticky": true,
- "Tooltip": true,
- "Transform": {
- "posX": 30.498,
- "posY": 4.084,
- "posZ": -20.929,
- "rotX": 0,
- "rotY": 270,
- "rotZ": 0,
- "scaleX": 1,
- "scaleY": 1,
- "scaleZ": 1
- },
- "Value": 0,
- "XmlUI": ""
-}
diff --git a/objects/Fan-MadeAccessories.aa8b38/DrawTokenButtonTooltipRenamer.cc77a8.ttslua b/objects/Fan-MadeAccessories.aa8b38/DrawTokenButtonTooltipRenamer.cc77a8.ttslua
deleted file mode 100644
index f6c8e24d..00000000
--- a/objects/Fan-MadeAccessories.aa8b38/DrawTokenButtonTooltipRenamer.cc77a8.ttslua
+++ /dev/null
@@ -1,455 +0,0 @@
-function onLoad()
- spawnButton("symbols", "Change Tooltips",
- "Changes tooltip for 'draw chaos token' buttons.", 0, 0.5, 0, 600, 400, 70)
-end
-
-function spawnButton( func, text, tool_tip, xPosition, yPosition, zPosition, button_width, button_height, fontsize )
- scale = self.getScale()
- scale = scale[1]
- params = {
- click_function = func,
- function_owner = self,
- label = text,
- position = {scale * xPosition, yPosition, scale * zPosition},
- rotation = {0, 0, 0},
- width = button_width * scale,
- height = button_height * scale,
- font_size = fontsize * scale,
- color = {1, 1, 1},
- font_color = {0, 0, 0},
- tooltip = tool_tip
- }
- self.createButton(params)
-end
-
-function symbols()
- local tool = "no scenario selected"
- for _, scenario in ipairs(getObjectFromGUID("fe2ae4").getObjects()) do
- if scenario.getDescription() == "The Gathering" then
- if scenario.is_face_down == true then
- tool = "Hard / Expert\n\n[skull] -2. If you fail, after this skill test, search the encounter deck and discard pile for a [[Ghoul]] enemy, and draw it. Shuffle the encounter deck.\n\n[cultist] Reveal another token. If you fail, take 2 horror.\n\n[tablet] -4. If there is a [[Ghoul]] enemy at your location, take 1 damage and 1 horror."
- else
- tool = "Easy / Standard\n\n[skull] -X. X is the number of [[Ghoul]] enemies at your location.\n\n[cultist] -1. If you fail, take 1 horror.\n\n[tablet] -2. If there is a [[Ghoul]] enemy at your location, take 1 damage.\n\n"
- end
- end
- -- midnight masks
- if scenario.getDescription() == "The Midnight Masks" then
- if scenario.is_face_down == true then
- tool = "Hard / Expert\n\n[skull]: -X. X is the total number of doom in play.\n\n[cultist]: -2. Place 1 doom on each [[Cultist]] enemy in play. If there are no [[Cultist]] enemies in play, reveal another token.\n\n[tablet]: -4. If you fail, place all your clues on your location."
- else
- tool = "Easy / Standard\n\n[skull]: -X. X is the highest number of doom on a [[Cultist]] enemy in play.\n\n[cultist]: -2. Place 1 doom on the nearest [[Cultist]] enemy.\n\n[tablet]: -3. If you fail, place 1 of your clues on your location."
- end
- end
- -- devourer below
- if scenario.getDescription() == "The Devourer Below" then
- if scenario.is_face_down == true then
- tool = "Hard / Expert\n\n[skull]: -3. If you fail, after this skill test, search the encounter deck and discard pile for a [[Monster]] enemy, and draw it. Shuffle the encounter deck.\n\n[cultist]: -4. Place 2 doom on the nearest enemy.\n\n[tablet]: -5. If there is a [[Monster]] enemy at your location, take 1 damage and 1 horror.\n\n[elder_thing]: -7. If there is an [[Ancient One]] enemy in play, reveal another token."
- else
- tool = "Easy / Standard\n\n[skull]: -X. X is the number of [[Monster]] enemies in play.\n\n[cultist]: -2. Place 1 doom on the nearest enemy.\n\n[tablet]: -3. If there is a [[Monster]] enemy at your location, take 1 damage.\n\n[elder_thing]: -5. If there is an [[Ancient One]] enemy in play, reveal another token."
- end
- end
- -- extracurricular activity symbols
- if scenario.getDescription() == "Extracurricular Activity" then
- if scenario.is_face_down == true then
- tool = "Hard / Expert\n\n[skull]: -2. If you fail, discard the top 5 cards of your deck.\n\n[cultist]: -1 (-5 instead if there are 10 or more cards in your discard pile).\n\n[elder_thing]: -X. Discard the top 3 cards of your deck. X is the total printed cost of those discarded cards."
- else
- tool = "Easy / Standard\n\n[skull]: -1. If you fail, discard the top 3 cards of your deck.\n\n[cultist]: -1 (-3 instead if there are 10 or more cards in your discard pile).\n\n[elder_thing]: -X. Discard the top 2 cards of your deck. X is the total printed cost of those discarded cards."
- end
- end
- -- The house always wins symbols
- if scenario.getDescription() == "The House Always Wins" then
- if scenario.is_face_down == true then
- tool = "Hard / Expert\n\n[skull]: -3. You may spend 3 resources to treat this token as a 0, instead.\n\n[cultist]: -3. If you fail, discard 3 resources.\n\n[tablet]: -2. Discard 3 resources."
- else
- tool = "Easy / Standard\n\n[skull]: -2. You may spend 2 resources to treat this token as a 0, instead.\n\n[cultist]: -3. If you succeed, gain 3 resources.\n\n[tablet]: -2. If you fail, discard 3 resources."
- end
- end
- -- Miskatonic museum symbols
- if scenario.getDescription() == "The Miskatonic Museum" then
- if scenario.is_face_down == true then
- tool = "Hard / Expert\n\n[skull]: -2 (-4 instead if Hunting Horror is at your location.)\n\n[cultist]: -3. If you fail, search the encounter deck, discard pile, and the void for Hunting Horror and spawn it at your location, if able.\n\n[tablet]: -4. If Hunting Horror is at your location, it immediately attacks you.\n\n[elder_thing]: -5. If you fail, discard an asset you control."
- else
- tool = "Easy / Standard\n\n[skull]: -1 (-3 instead if Hunting Horror is at your location.)\n\n[cultist]: -1. If you fail, search the encounter deck, discard pile, and the void for Hunting Horror and spawn it at your location, if able.\n\n[tablet]: -2. Return 1 of your clues to your current location.\n\n[elder_thing]: -3. If you fail, discard an asset you control."
- end
- end
- -- essex county express symbols
- if scenario.getDescription() == "The Essex County Express" then
- if scenario.is_face_down == true then
- tool = "Hard / Expert\n\n[skull]: -X. X is 1 more than the current Agenda #. \n\n[cultist]: Reveal another token. If you fail and it is your turn, lose all remaining actions and end your turn immediately.\n\n[tablet]: -4. Add 1 doom token to each Cultist enemy in play.\n\n[elder_thing]: -3. If you fail, choose and discard a card from your hand for each point you failed by."
- else
- tool = "Easy / Standard\n\n[skull]: -X. X is the current Agenda #.\n\n[cultist]: -1. If you fail and it is your turn, lose all remaining actions and end your turn immediately.\n\n[tablet]: -2. Add 1 doom token to the nearest Cultist enemy.\n\n[elder_thing]: -3. If you fail, choose and discard a card from your hand."
- end
- end
- --blood on the Altar
- if scenario.getDescription() == "Blood on the Altar" then
- if scenario.is_face_down == true then
- tool = "Hard / Expert\n\n[skull]: -1 for each location in play with no encounter card underneath it.\n\n[cultist]: -4. If you fail, add 1 clue from the token pool to your location.\n\n[tablet]: -3. Reveal another token.\n\n[elder_thing]: -3. Place 1 doom on the current agenda."
- else
- tool = "Easy / Standard\n\n[skull]: -1 for each location in play with no encounter card underneath it (max -4).\n\n[cultist]: -2. If you fail, add 1 clue from the token pool to your location.\n\n[tablet]: -2. If you are in the Hidden Chamber, reveal another token.\n\n[elder_thing]: -3. If you fail, place 1 doom on the current agenda."
- end
- end
- --undimensioned and unseen
- if scenario.getDescription() == "Undimensioned and Unseen" then
- if scenario.is_face_down == true then
- tool = "Hard / Expert\n\n[skull]: -2 for each Brood of Yog-Sothoth in play.\n\n[cultist]: Reveal another token. If you fail this test, take 1 horror and 1 damage.\n\n[tablet]: 0. You must either remove all clue tokens from a Brood of Yog-Sothoth in play, or this test automatically fails.\n\n[elder_thing]: -5. If this token is revealed during an attack or evasion attempt against a Brood of Yog-Sothoth, it immediately attacks you."
- else
- tool = "Easy / Standard\n\n[skull]: -1 for each Brood of Yog-Sothoth in play.\n\n[cultist]: Reveal another token. If you fail this test, take 1 horror.\n\n[tablet]: 0. You must either remove all clue tokens from a Brood of Yog-Sothoth in play, or this token's modifier is -4 instead.\n\n[elder_thing]: -3. If this token is revealed during an attack or evasion attempt against a Brood of Yog-Sothoth, it immediately attacks you."
- end
- end
- -- where doom Awaits
- if scenario.getDescription() == "Where Doom Awaits" then
- if scenario.is_face_down == true then
- tool = "Hard / Expert\n\n[skull]: -2 (-5 instead if you are at an [[Altered]] location).\n\n[cultist]: Reveal another token. Cancel the effects and icons of each skill card committed to this test.\n\n[tablet]: -3. If it is Agenda 2, you automatically fail instead.\n\n[elder_thing]: -X. Discard the top 3 cards of your deck. X is the total printed cost of those discarded cards."
- else
- tool = "Easy / Standard\n\n[skull]: -1 (-3 instead if you are at an [[Altered]] location).\n\n[cultist]: Reveal another token. Cancel the effects and icons of each skill card committed to this test.\n\n[tablet]: -2 (-4 instead if it is Agenda 2).\n\n[elder_thing]: -X. Discard the top 2 cards of your deck. X is the total printed cost of those discarded cards."
- end
- end
- --lost in time and space
- if scenario.getDescription() == "Lost in Time and Space" then
- if scenario.is_face_down == true then
- tool = "Hard / Expert\n\n[skull]: -1 for each [[Extradimensional]] location in play.\n\n[cultist]: Reveal another token. After this skill test, discard cards from the top of the encounter deck until a location is discarded. Put that location into play and move there.\n\n[tablet]: -5. If Yog-Sothoth is in play, it attacks you after this skill test.\n\n[elder_thing]: -X. X is twice the shroud value of your location. If you fail and your location is [[Extradimensional]], discard it."
- else
- tool = "Easy / Standard\n\n[skull]: -1 for each [[Extradimensional]] location in play (max -5).\n\n[cultist]: Reveal another token. If you fail, after this skill test, discard cards from the top of the encounter deck until a location is discarded. Put that location into play and move there.\n\n[tablet]: -3. If Yog-Sothoth is in play, it attacks you after this skill test.\n\n[elder_thing]: -X. X is the shroud value of your location. If you fail and your location is [[Extradimensional]], discard it."
- end
- end
- -- curtain call
- if scenario.getDescription() == "Curtain Call" then
- if scenario.is_face_down == true then
- tool = "Hard / Expert\n\n[skull]: -X, where X is the amount of horror on you. (If you have no horror on you, X is 1.)\n\n[cultist] [tablet] [elder_thing]: -5. If your location has at least 1 horror on it, take 1 horror (from the token pool). If your location has no horror on it, place 1 horror on it instead."
- else
- tool = "Easy / Standard\n\n[skull]: -1 (-3 instead if you have 3 or more horror on you).\n\n[cultist] [tablet] [elder_thing]: -4. If your location has at least 1 horror on it, take 1 horror (from the token pool). If your location has no horror on it, place 1 horror on it instead."
- end
- end
- -- Last King
- if scenario.getDescription() == "The Last King" then
- if scenario.is_face_down == true then
- tool = "Hard / Expert\n\n[skull]: Reveal another token. If you fail, place 1 doom on the [[Lunatic]] enemy in play with the most remaining health.\n\n[cultist]: -3. Place 1 of your clues on your location.\n\n[tablet]: -4. Take 1 horror.\n\n[elder_thing]: -X. X is the shroud value of your location. If you fail, take 1 damage."
- else
- tool = "Easy / Standard\n\n[skull]: Reveal another token. If you fail, place 1 doom on a [[Lunatic]] enemy in play.\n\n[cultist]: -2. If you fail, place 1 of your clues on your location.\n\n[tablet]: -4. If you fail, take 1 horror.\n\n[elder_thing]: -X. X is the shroud value of your location."
- end
- end
- -- Echoes Past
- if scenario.getDescription() == "Echoes of the Past" then
- if scenario.is_face_down == true then
- tool = "Hard / Expert\n\n[skull]: -X. X is the total number of doom on enemies in play.\n\n[cultist]: -4. Place 1 doom on the nearest enemy.\n\n[tablet]: -4. Discard a random card from your hand.\n\n[elder_thing]: -4. If there is an enemy at your location, take 1 horror."
- else
- tool = "Easy / Standard\n\n[skull]: -X. X is the highest number of doom on an enemy in play.\n\n[cultist]: -2. If you fail, place 1 doom on the nearest enemy.\n\n[tablet]: -2. If you fail, discard a random card from your hand.\n\n[elder_thing]: -2. If you fail and there is an enemy at your location, take 1 horror."
- end
- end
- -- Unspeakable Oath
- if scenario.getDescription() == "The Unspeakable Oath" then
- if scenario.is_face_down == true then
- tool = "Hard / Expert\n\n[skull]: Reveal another token. If you fail, randomly choose an enemy from among the set-aside [[Monster]] enemies and place it beneath the act deck without looking at it. (Limit once per test.)\n\n[cultist]: -X. X is the amount of horror on you. If you fail, take 1 horror.\n\n[tablet]: -X. X is the base shroud value of your location. If you fail, take 1 horror.\n\n[elder_thing]: 0. Either randomly choose an enemy from among the set-aside [[Monster]] enemies and place it beneath the act deck without looking at it, or this test automatically fails instead."
- else
- tool = "Easy / Standard\n\n[skull]: -1. If you fail, randomly choose an enemy from among the set-aside [[Monster]] enemies and place it beneath the act deck without looking at it.\n\n[cultist]: -X. X is the amount of horror on you.\n\n[tablet]: -X. X is the base shroud value of your location.\n\n[elder_thing]: 0. Either randomly choose an enemy from among the set-aside [[Monster]] enemies and place it beneath the act deck without looking at it, or this test automatically fails instead."
- end
- end
- -- A Phantom of Truth
- if scenario.getDescription() == "A Phantom of Truth" then
- if scenario.is_face_down == true then
- tool = "Hard / Expert\n\n[skull]: -X. X is the amount of doom in play.\n\n[cultist]: -2. Move each unengaged [[Byakhee]] in play once toward the nearest investigator.\n\n[tablet]: -4. Cancel the effects and icons of each skill card committed to this test.\n\n[elder_thing]: -3. If you fail, lose 1 resource for each point you failed by."
- else
- tool = "Easy / Standard\n\n[skull]: -X. X is the amount of doom in play (max 5).\n\n[cultist]: -2. If you fail, move each unengaged [[Byakhee]] in play once toward the nearest investigator.\n\n[tablet]: -3. Cancel the effects and icons of each skill card committed to this test.\n\n[elder_thing]: -2. If you fail, lose 1 resource for each point you failed by."
- end
- end
- -- The Pallid Mask
- if scenario.getDescription() == "The Pallid Mask" then
- if scenario.is_face_down == true then
- tool = "Hard / Expert\n\n[skull]: -X. X is the number of locations away from the starting location you are.\n\n[cultist]: -3. If this token is revealed during an attack and this skill test is successful, this attack deals no damage.\n\n[tablet]: -3. If there is a [[Ghoul]] or [[Geist]] enemy at your location, it readies and attacks you (if there is more than one, choose one).\n\n[elder_thing]: -4. If you fail, search the encounter deck and discard pile for a [[Ghoul]] or [[Geist]] enemy and draw it."
- else
- tool = "Easy / Standard\n\n[skull]: -X. X is the number of locations away from the starting location you are (max 5).\n\n[cultist]: -2. If this token is revealed during an attack, and this skill test is successful, this attack deals 1 less damage.\n\n[tablet]: -2. If there is a ready [[Ghoul]] or [[Geist]] enemy at your location, it attacks you (if there is more than one, choose one).\n\n[elder_thing]: -3. If you fail, search the encounter deck and discard pile for a [[Ghoul]] or [[Geist]] enemy and draw it."
- end
- end
- -- Dim Carcosa
- if scenario.getDescription() == "Dim Carcosa" then
- if scenario.is_face_down == true then
- tool = "Hard / Expert\n\n[skull]: -X. X is the amount of horror on you.\n\n[cultist]: Reveal another token. If you fail, take 2 horror.\n\n[tablet]: -5. If you fail and Hastur is in play, place 1 clue on your location (from the token bank).\n\n[elder_thing]: -5. If this token is revealed during an attack or evasion attempt against a [[Monster]] or [[Ancient One]] enemy, lose 1 action."
- else
- tool = "Easy / Standard\n\n[skull]: -2 (-4 instead if you have no sanity remaining).\n\n[cultist]: Reveal another token. If you fail, take 1 horror.\n\n[tablet]: -3. If you fail and Hastur is in play, place 1 clue on your location (from the token bank).\n\n[elder_thing]: -3. If this token is revealed during an attack or evasion attempt against a [[Monster]] or [[Ancient One]] enemy, lose 1 action."
- end
- end
- if scenario.getDescription() == "Black Stars Rise" then
- if scenario.is_face_down == true then
- tool = "Hard / Expert\n\n[skull]: -X. X is the total amount of doom on agendas in play.\n\n[cultist]: Reveal another token. If there is an enemy with 1 or more doom on it at your location, this test automatically fails instead.\n\n[tablet]: Reveal another token. If you do not succeed by at least 1, place 1 doom on each agenda.\n\n[elder_thing]: -3. If you fail, search the encounter deck and discard pile for a [[Byakhee]] enemy and draw it."
- else
- tool = "Easy / Standard\n\n[skull]: -X. X is the highest amount of doom on an agenda in play.\n\n[cultist]: Reveal another token. If this token is revealed during an attack or evasion attempt against an enemy with doom on it, this skill test automatically fails instead.\n\n[tablet]: Reveal another token. If you fail, place 1 doom on each agenda.\n\n[elder_thing]: -2. If you fail, search the encounter deck and discard pile for a [[Byakhee]] enemy and draw it."
- end
- end
- -- untamed Wilds
- if scenario.getDescription() == "The Untamed Wilds" then
- if scenario.is_face_down == true then
- tool = "Hard / Expert\n\n[skull]: -X. X is 1 higher than the number of vengeance points in the victory display.\n\n[cultist]: -X. X is the number of locations in play.\n\n[tablet]: -X. X is the number of cards in the exploration deck (min 3).\n\n[elder_thing]: -3. If you are poisoned, this test automatically fails instead. If you are not poisoned and you fail, put a set-aside Poisoned weakness into play in your threat area."
- else
- tool = "Easy / Standard\n\n[skull]: -X. X is the number of vengeance points in the victory display.\n\n[cultist]: -X. X is the number of locations in play (max 5).\n\n[tablet]: -X. X is the number of cards in the exploration deck (max 5).\n\n[elder_thing]: -2. If you are poisoned, this test automatically fails instead."
- end
- end
- --The doom of Eztli
- if scenario.getDescription() == "The Doom of Eztli" then
- if scenario.is_face_down == true then
- tool = "Hard / Expert\n\n[skull]: -2 (-4 instead if there is doom on your location).\n\n[cultist] [tablet]: -X. X is the total amount of doom on locations in play.\n\n[elder_thing]: Reveal another chaos token. Place 1 doom on your location."
- else
- tool = "Easy / Standard\n\n[skull]: -1 (-3 instead if there is doom on your location).\n\n[cultist] [tablet]: -X. X is the number of locations with doom on them.\n\n[elder_thing]: Reveal another chaos token. If you fail, place 1 doom on your location."
- end
- end
- --Threads of Fate
- if scenario.getDescription() == "Threads of Fate" then
- if scenario.is_face_down == true then
- tool = "Hard / Expert\n\n[skull] : -X. X is the total number of doom in play.\n\n[cultist]: -2. If you do not succeed by at least 2, take 1 direct damage.\n\n[tablet]: -2. If you do not succeed by at least 2, place 1 doom on each [[cultist]] enemy.\n\n[elder_thing]: -3. If you fail, lose 1 of your clues."
- else
- tool = "Easy / Standard\n\n[skull] : -X. X is the highest number of doom on a [[cultist]] enemy.\n\n[cultist]: -2. If you do not succeed by at least 1, take 1 damage.\n\n[tablet]: -2. If you do not succeed by at least 1, place 1 doom on the nearest [[cultist]] enemy.\n\n[elder_thing]: -2. If you fail, lose 1 of your clues."
- end
- end
- --The boundary beyond
- if scenario.getDescription() == "The Boundary Beyond" then
- if scenario.is_face_down == true then
- tool = "Hard / Expert\n\n[skull]: -2 (-4 instead if you are at an [[Ancient]] location).\n\n[cultist]: Reveal another token. If you fail, place 1 doom on each [[Cultist]] enemy.\n\n[tablet]: Reveal another token. If you fail, each [[Serpent]] enemy at your location attacks you.\n\n[elder_thing]: -4. Place 1 clue (from the token pool) on the nearest [[Ancient]] location."
- else
- tool = "Easy / Standard\n\n[skull]: -1 (-3 instead if you are at an [[Ancient]] location).\n\n[cultist]: Reveal another token. If you fail, place 1 doom on a [[Cultist]] enemy.\n\n[tablet]: Reveal another token. If you fail and there is a [[Serpent]] enemy at your location, it attacks you.\n\n[elder_thing]: -4. If you fail, place 1 clue (from the token pool) on the nearest [[Ancient]] location."
- end
- end
- --Heart of the elders p1
- if scenario.getDescription() == "Heart of the Elders" then
- if scenario.is_face_down == true then
- tool = "Hard / Expert\n\n[skull]: -2 (-4 instead if you are in a [[Cave]] location).\n\n[cultist]: -3. If you fail, place 1 doom on your location.\n\n[tablet]: -3. If you are poisoned, this test automatically fails instead. If you are not poisoned and you fail, put a set-aside Poisoned weakness into play in your threat area.\n\n[elder_thing]: -4. If you fail, take 1 horror."
- else
- tool = "Easy / Standard\n\n[skull]: -1 (-3 instead if you are in a [[Cave]] location).\n\n[cultist]: -2. If you fail, place 1 doom on your location.\n\n[tablet]: -2. If you are poisoned, this test automatically fails instead.\n\n[elder_thing]: -3. If you fail, take 1 horror."
- end
- end
- -- City of Archives
- if scenario.getDescription() == "The City of Archives" then
- if scenario.is_face_down == true then
- tool = "Hard / Expert\n\n[skull]: -2 (if you have 5 or more cards in your hand, you automatically fail instead).\n\n[cultist] or [elder_thing]: -2. Place 1 of your clues on your location.\n\n[tablet]: -3. For each point you fail by, discard 1 random card from your hand."
- else
- tool = "Easy / Standard\n\n[skull]: -1 (-3 instead if you have 5 or more cards in your hand).\n\n[cultist] or [elder_thing]: -2. If you fail, place 1 of your clues on your location.\n\n[tablet]: -3. If you fail, discard 1 random card from your hand."
- end
- end
- --Depths of Yoth
- if scenario.getName() == "Scenario - Easy/Standard" then
- tool = "Easy / Standard\n\n[skull]: -X. X is the current depth level.\n\n[cultist]: Reveal another token. If you fail, each [[Serpent]] enemy at your location or a connecting location heals 2 damage.\n\n[tablet]: Reveal another token. If you fail, place 1 clue on your location (from the token pool).\n\n[elder_thing]: -2. If there are 3 or more vengeance points in the victory display, you automatically fail this test, instead."
- end
- --hard
- if scenario.getName() == "Scenario - Hard/Expert" then
- tool = "Hard / Expert\n\n[skull]: -X. X is the current depth level. If you fail, take 1 horror.\n\n[cultist]: Reveal another token. If you fail, each [[Serpent]] enemy at your location or a connecting location heals 2 damage.\n\n[tablet]: Reveal another token. If you fail, place 1 clue on your location (from the token pool).\n\n[elder_thing]: -4. If there are 3 or more vengeance points in the victory display, you automatically fail this test, instead."
- end
- --Shattered Aeons
- if scenario.getDescription() == "Shattered Aeons" then
- if scenario.is_face_down == true then
- tool = "Hard / Expert\n\n[skull]: -3 (-5 instead if the Relic of Ages is at your location).\n\n[cultist]: -3. If you do not succeed by at least 1, place 1 doom on each [[Cultist]] enemy.\n\n[tablet]: -3. If you are poisoned, this test automatically fails instead. If you are not poisoned and you fail, put a set-aside Poisoned weakness into play in your threat area.\n\n[elder_thing]: -3. Shuffle the topmost [[Hex]] treachery in the encounter discard pile into the exploration deck."
- else
- tool = "Easy / Standard\n\n[skull]: -2 (-4 instead if the Relic of Ages is at your location).\n\n[cultist]: -2. If you do not succeed by at least 1, place 1 doom on the nearest [[Cultist]] enemy.\n\n[tablet]: -2. If you are poisoned, this test automatically fails instead.\n\n[elder_thing]: -2. If you fail, shuffle the topmost [[Hex]] treachery in the encounter discard pile into the exploration deck."
- end
- end
- --secret scenario
- if scenario.getDescription() == "Turn Back Time" then
- if scenario.is_face_down == true then
- tool = "Hard / Expert\n\n[skull]: -X . X is the total amount of doom on locations.\n\n[elder_thing]: -6. Place 1 doom on your location."
- else
- tool = "Easy / Standard\n\n[skull]: -X . X is the number of locations with doom on them.\n\n[elder_thing]: -4. If you fail, place 1 doom on your location."
- end
- end
- --Dissappearance Twilight
- if scenario.getDescription() == "Disappearance at the Twilight Estate" then
- if scenario.is_face_down == true then
- tool = "Hard / Expert\n\n[skull]: -5. If you fail and this is an attack or evasion attempt, resolve each haunted ability on your location."
- else
- tool = "Easy / Standard\n\n[skull]: -3. If you fail and this is an attack or evasion attempt, resolve each haunted ability on your location."
- end
- end
- --Witching Hour
- if scenario.getDescription() == "The Witching Hour" then
- if scenario.is_face_down == true then
- tool = "Hard / Expert\n\n[skull]: -2. Discard cards from the top of the encounter deck equal to this test's difficulty.\n\n[tablet]: -2. If you fail, after this test resolves, draw the bottommost treachery in the encounter discard pile.\n\n[elder_thing]: -4. If you fail, ready each [[Witch]] enemy at your location and at each connecting location. Heal all damage from each of those enemies."
- else
- tool = "Easy / Standard\n\n[skull]: -1. For each point you fail by, discard the top card of the encounter deck.\n\n[tablet]: -1. If you fail, after this test resolves, draw the bottommost treachery in the encounter discard pile.\n\n[elder_thing]: -3. If you fail, choose an exhausted or damaged [[Witch]] enemy at your location or at a connecting location. Ready that enemy and heal all damage from it."
- end
- end
- --Death's Doorstep
- if scenario.getDescription() == "At Death's Doorstep" then
- if scenario.is_face_down == true then
- tool = "Hard / Expert\n\n[skull]: -2 (-4 instead if your location is haunted).\n\n[tablet]: -3. If this is an attack or evasion attempt, resolve each haunted ability on your location.\n\n[elder_thing]: -4. If there is a [[Spectral]] enemy at your location, take 1 damage and 1 horror."
- else
- tool = "Easy / Standard\n\n[skull]: -1 (-3 instead if your location is haunted).\n\n[tablet]: -2. If you fail and this is an attack or evasion attempt, resolve each haunted ability on your location.\n\n[elder_thing]: -2. If there is a [[Spectral]] enemy at your location, take 1 damage."
- end
- end
- --Secret Name
- if scenario.getDescription() == "The Secret Name" then
- if scenario.is_face_down == true then
- tool = "Hard / Expert\n\n[skull]: -2 (-4 instead if you are at an [[Extradimensional]] location).\n\n[cultist]: Reveal another chaos token. If you fail, discard the top 5 cards of the encounter deck.\n\n[tablet]: -3. If you fail and Nahab is in play, she attacks you (regardless of her current location).\n\n[elder_thing]: -4. Resolve the hunter keyword on each enemy in play."
- else
- tool = "Easy / Standard\n\n[skull]: -1 (-3 instead if you are at an [[Extradimensional]] location).\n\n[cultist]: Reveal another chaos token. If you fail, discard the top 3 cards of the encounter deck.\n\n[tablet]: -2. If you fail and Nahab is at your location, she attacks you.\n\n[elder_thing]: -3. If you fail, resolve the hunter keyword on each enemy in play."
- end
- end
- --Wages of Sin
- if scenario.getDescription() == "The Wages of Sin" then
- if scenario.is_face_down == true then
- tool = "Hard / Expert\n\n[skull]: -X. X is the number of copies of Unfinished Business in the victory display. Reveal another token.\n\n[cultist]: -4. Until the end of the rount, each Heretic enemy in play gets +1 fight and +1 evade.\n\n[tablet]: -4. If you fail, trigger the forced ability on a copy of Unfinished Business in your threat area as if it were the end of the round.\n\n[elder_thing]: -2. If this is an attack or evasion attempt, resolve each haunted ability on your location."
- else
- tool = "Easy / Standard\n\n[skull]: -X. X is 1 higher than the number of copies of Unfinished Business in the victory display.\n\n[cultist]: -3. Until the end of the round, each Heretic enemy in play gets +1 fight and +1 evade.\n\n[tablet]: -3. If you fail, trigger the forced ability on a copy of Unfinished Business in yout threat area as if it were the end of the round.\n\n[elder_thing]: -2. If you fail and this is an attack or evasion attempt, resolve each haunted ability on your location."
- end
- end
- -- For The Greater Good
- if scenario.getDescription() == "For the Greater Good" then
- if scenario.is_face_down == true then
- tool = "Hard / Expert\n\n[skull]: -X. X is the total number of doom among [[Cultist]] enemies in play.\n\n[cultist]: -2. Reveal another token.\n\n[tablet]: -3. If you fail, place 1 doom on each [[Cultist]] enemy in play. If there are no [[Cultist]] enemies in play, reveal another token.\n\n[elder_thing]: -3. If you fail, move all doom from the [[Cultist]] enemy with the most doom on it to the current agenda. If no [[Cultist]] enemies in play have doom on them, reveal another token."
- else
- tool = "Easy / Standard\n\n[skull]: -X. X is the highest number of doom on a [[Cultist]] enemy in play.\n\n[cultist]: -2. Reveal another token.\n\n[tablet]: -3. If you fail, place 1 doom on the nearest [[Cultist]] enemy.\n\n[elder_thing]: -3. If you fail, move 1 doom from the nearest [[Cultist]] enemy to the current agenda."
- end
- end
- --Union and Disillusion
- if scenario.getDescription() == "Union and Disillusion" then
- if scenario.is_face_down == true then
- tool = "Hard / Expert\n\n[skull]: -3. If this is a skill test during a circle action, reveal another token.\n\n[cultist]: -4. If you have no damage on you, take 1 damage. If you have no horror on you, take 1 horror.\n\n[tablet]: -4. If you fail, a [[Spectral]] enemy at your location attacks you (even if it is exhausted).\n\n[elder_thing]: -4. If this is a skill test during a circle action and you fail, resolve each haunted ability on your location."
- else
- tool = "Easy / Standard\n\n[skull]: -2. If this is a skill test during a circle action, reveal another token.\n\n[cultist]: -3. If you have no damage on you, take 1 damage. If you have no horror on you, take 1 horror.\n\n[tablet]: -3. If you fail, a [[Spectral]] enemy at your location attacks you (even if it is exhausted).\n\n[elder_thing]: -3. If this is a skill test during a circle action and you fail, resolve each haunted ability on your location."
- end
- end
- --Clutches of Chaos
- if scenario.getDescription() == "In the Clutches of Chaos" then
- if scenario.is_face_down == true then
- tool = "Hard / Expert\n\n[skull]: -X. X is 1 higher than the total amount of doom and breaches on your location.\n\n[cultist]: Reveal another token. If there are fewer than 3 breaches on your location, place 1 breach on your location.\n\n[tablet]: -3. For each point you fail by, remove 1 breach from the current act.\n\n[elder_thing]: -4. If you fail, place 1 breach on a random location."
- else
- tool = "Easy / Standard\n\n[skull]: -X. X is the total amount of doom and breaches on your location.\n\n[cultist]: Reveal another token. If there are fewer than 3 breaches on your location, place 1 breach on your location.\n\n[tablet]: -2. For each point you fail by, remove 1 breach from the current act.\n\n[elder_thing]: -3. If you fail, place 1 breach on a random location."
- end
- end
- --Before the Black Throne
- if scenario.getDescription() == "Before the Black Throne" then
- if scenario.is_face_down == true then
- tool = "Hard / Expert\n\n[skull]: -X. X is the amount of doom on Azathoth, to a minimum of 2.\n\n[cultist]: Reveal another token. If you fail, search the encounter deck and discard pile for a [[Cultist]] enemy and draw it. Shuffle the encounter deck.\n\n[tablet]: -3. If you fail, Azathoth attacks you.\n\n[elder_thing]: -6. If your modified skill value for this test is 0, place 1 doom on Azathoth."
- else
- tool = "Easy / Standard\n\n[skull]: -X. X is half of the doom on Azathoth (rounded up), to a minimum of 2.\n\n[cultist]: Reveal another token. If you fail, search the encounter deck and discard pile for a [[Cultist]] enemy and draw it. Shuffle the encounter deck.\n\n[tablet]: -2. If you fail, Azathoth attacks you.\n\n[elder_thing]: -4. If your modified skill value for this test is 0, place 1 doom on Azathoth."
- end
- end
- --Beyond the gates of sleep
- if scenario.getDescription() == "Beyond the Gates of Sleep" then
- if scenario.is_face_down == true then
- tool = "Hard / Expert\n\n[skull] : -X. X is the number of cards in your hand.\n\n[cultist]: -X. X is the number of revealed [[Woods]] locations.\n\n[tablet]: -2. If this is an attack or evasion attempt against a swarming enemy, add 1 swarm card to it."
- else
- tool = "Easy / Standard\n\n[skull] : -X. X is half the number of cards in your hand (rounded up).\n\n[cultist]: -X. X is the number of revealed Enchanted Woods locations.\n\n[tablet]: -2. If you fail and this is an attack or evasion attempt against a swarming enemy, add 1 swarm card to it."
- end
- end
- --Waking Nightmare
- if scenario.getDescription() == "Waking Nightmare" then
- if scenario.is_face_down == true then
- tool = "Hard / Expert\n\n[skull]: -2 (-4 instead if you are engaged with a [[Staff]] enemy).\n\n[cultist]: Reveal another chaos token. If it is agenda 2 or 3, make an infestation test.\n\n[elder_thing]: -X. X is 1 higher than the number of infested locations."
- else
- tool = "Easy / Standard\n\n[skull]: -1 (-3 instead if you are engaged with a [[Staff]] enemy).\n\n[cultist]: Reveal another chaos token. If you fail and it is agenda 2 or 3, make an infestation test.\n\n[elder_thing]: -X. X is the number of infested locations."
- end
- end
- --The search for kadath
- if scenario.getDescription() == "The Search for Kadath" then
- if scenario.is_face_down == true then
- tool = "Hard / Expert\n\n[skull]: -X. X is 1 more than the number of Signs of the Gods the investigators have uncovered.\n\n[cultist]: Reveal another token. If this token is revealed during an investigation and this skill test fails, increase that location's shroud by 2 for the remainder of the round.\n\n[tablet]: -3. If you fail, either take 1 damage and 1 horror, or place 1 doom on the current agenda.\n\n[elder_thing]: +1. The black cat points you in the right direction. If this token is revealed during an investigation and you succeed, discover 1 additional clue."
- else
- tool = "Easy / Standard\n\n[skull]: -X. X is the number of Signs of the Gods the investigators have uncovered.\n\n[cultist]: Reveal another token. If this token is revealed during an investigation and this skill test fails, increase that location's shroud by 1 for the remainder of the round.\n\n[tablet]: -2. If you fail, either take 1 damage and 1 horror, or place 1 doom on the current agenda.\n\n[elder_thing]: +2. The black cat points you in the right direction. If this token is revealed during an investigation and you succeed, discover 1 additional clue."
- end
- end
- --A thousand shapes of horror
- if scenario.getDescription() == "A Thousand Shapes of Horror" then
- if scenario.is_face_down == true then
- tool = "Hard / Expert\n\n[skull]: -2 (-4 instead if you are at a [[Graveyard]] location).\n\n[cultist]: Reveal another token. If you fail and The Unnamable is in play, it attacks you (regardless of its current location).\n\n[tablet]: +1. The black cat causes a distraction. If this test is successful, choose and evade an enemy at any location with a fight value of X or lower, where X is the amount you succeeded by.\n\n[elder_thing]: -3. If you fail, you must either place 1 of your clues on your location or take 1 damage."
- else
- tool = "Easy / Standard\n\n[skull]: -1 (-3 instead if you are at a [[Graveyard]] location).\n\n[cultist]: Reveal another token. If you fail and The Unnamable is in play, it attacks you (regardless of its current location).\n\n[tablet]: +2. The black cat causes a distraction. If this test is successful, choose and evade an enemy at any location with a fight value of X or lower, where X is the amount you succeeded by.\n\n[elder_thing]: -2. If you fail, you must either place 1 of your clues on your location or take 1 damage."
- end
- end
- --Dark Side of the moon
- if scenario.getDescription() == "Dark Side of the Moon" then
- if scenario.is_face_down == true then
- tool = "Hard / Expert\n\n[skull]: -X. X is your alarm level.\n\n[cultist]: Reveal another token. If you fail and your alarm level is higher than your modified skill value, after this skill test ends, draw the top card of the encounter deck.\n\n[tablet]: -2. If you fail, raise your alarm level by 1.\n\n[elder_thing]: 0. The black cat summons several other cats to help. If this token is revealed during an evasion attempt and you succeed, deal 2 damage to the evaded enemy."
- else
- tool = "Easy / Standard\n\n[skull]: -X. X is half your alarm level (rounded up).\n\n[cultist]: Reveal another token. If you fail and your alarm level is higher than your modified skill value, after this skill test ends, draw the top card of the encounter deck.\n\n[tablet]: -1. If you fail, raise your alarm level by 1.\n\n[elder_thing]: +1. The black cat summons several other cats to help. If this token is revealed during an evasion attempt and you succeed, deal 2 damage to the evaded enemy."
- end
- end
- --point of no return
- if scenario.getDescription() == "Point of No Return" then
- if scenario.is_face_down == true then
- tool = "Hard / Expert\n\n[skull]: -X. X is 1 more than the amount of damage on this card.\n\n[cultist]: Reveal another token. If you fail, after this skill test ends, draw the top card of the encounter deck.\n\n[tablet]: 0. The black cat helps you navigate through the death-fire. If this token is revealed during an investigation and you succeed, draw 1 card.\n\n[elder_thing]: -4. If you fail by 2 or more, choose a ready enemy at your location or a connecting location. That enemy moves to your location, engages you, and makes an immediate attack."
- else
- tool = "Easy / Standard\n\n[skull]: -X. X is the amount of damage on this card.\n\n[cultist]: Reveal another token. If you fail, after this skill test ends, draw the top card of the encounter deck.\n\n[tablet]: +1. The black cat helps you navigate through the death-fire. If this token is revealed during an investigation and you succeed, draw 1 card.\n\n[elder_thing]: -3. If you fail by 2 or more, choose a ready enemy at your location or a connecting location. That enemy moves to your location, engages you, and makes an immediate attack."
- end
- end
- --where the gods dwell
- if scenario.getDescription() == "Where the Gods Dwell" then
- if scenario.is_face_down == true then
- tool = "Hard / Expert\n\n[skull]: -X. X is the number of the current act plus the number of the current agenda.\n\n[cultist]: Reveal another token. If you fail, place 1 doom on the current agenda. This effect may cause the current agenda to advance.\n\n[tablet]: -6. If you fail, choose and reveal a copy of Nyarlathotep in your hand. It attacks you and is shuffled into the encounter deck.\n\n[elder_thing]: -1. The black cat reminds you that it's all a dream."
- else
- tool = "Easy / Standard\n\n[skull]: -X. X is the number of the current act.\n\n[cultist]: Reveal another token. If you fail, place 1 doom on the current agenda.\n\n[tablet]: -4. If you fail, choose and reveal a copy of Nyarlathotep in your hand. It attacks you and is shuffled into the encounter deck.\n\n[elder_thing]: 0. The black cat reminds you that it's all a dream."
- end
- end
- --weaver of the cosmos
- if scenario.getDescription() == "Weaver of the Cosmos" then
- if scenario.is_face_down == true then
- tool = "Hard / Expert\n\n[skull]: -X. X is the amount of doom on locations in play.\n\n[cultist]: Reveal another token. If you fail, and there is an [[Ancient One]] enemy at your location, it attacks you.\n\n[tablet]: -1. The black cat tears at the web with its claws. If you succeed by 2 or more, remove 1 doom from your location.\n\n[elder_thing]: -4. If this skill test fails during an attack against a [[Spider]] enemy, place 1 doom on that enemy's location."
- else
- tool = "Easy / Standard\n\n[skull]: -X. X is the highest amount of doom on a location in play.\n\n[cultist]: Reveal another token. If you fail, and there is an [[Ancient One]] enemy at your location, it attacks you.\n\n[tablet]: 0. The black cat tears at the web with its claws. If you succeed by 2 or more, remove 1 doom from your location.\n\n[elder_thing]: -3. If this skill test fails during an attack against a [[Spider]] enemy, place 1 doom on that enemy's location."
- end
- end
- --pit of despair
- if scenario.getDescription() == "The Pit of Despair" then
- if scenario.is_face_down == true then
- tool = "Hard / Expert\n\n[skull]: -2 (-3 instead if your location is partially flooded; -4 instead if your location is fully flooded).\n\n[cultist]: -2. If your location is flooded, take 1 damage.\n\n[tablet]: -2. If you control a key, take 1 horror.\n\n[elder_thing]: -3. If The Amalgam is in the depths, put it into play engaged with you."
- else
- tool = "Easy / Standard\n\n[skull]: -1 (-2 instead if your location is partially flooded; -3 instead if your location is fully flooded).\n\n[cultist]: -2. If you fail and your location is flooded, take 1 damage.\n\n[tablet]: -2. If you fail and you control a key, take 1 horror.\n\n[elder_thing]: -3. If you fail and The Amalgam is in the depths, put it into play engaged with you."
- end
- end
- --vanishing of elena harper
- if scenario.getDescription() == "The Vanishing of Elina Harper" then
- if scenario.is_face_down == true then
- tool = "Hard / Expert\n\n[skull]: -X. X is 1 more than the current agenda number.\n\n[cultist]: -2. Place 1 doom on the nearest enemy (2 doom instead if you failed).\n\n[tablet]: -3. Take 1 horror (1 horror and 1 damage instead if you failed).\n\n[elder_thing]: -4. Place 1 of your clues on your location (2 clues instead if you failed)."
- else
- tool = "Easy / Standard\n\n[skull]: -X. X is the current agenda number.\n\n[cultist]: -2. If you fail, place 1 doom on the nearest enemy.\n\n[tablet]: -3. If you fail, take 1 horror.\n\n[elder_thing]: -4. If you fail, place 1 of your clues on your location."
- end
- end
- --in too deep
- if scenario.getDescription() == "In Too Deep" then
- if scenario.is_face_down == true then
- tool = "Hard / Expert\n\n[skull]: -2 for each location to the east of your location (on the same row).\n\n[cultist]: -4. If you fail, move to the connecting location to the east, ignoring all barriers.\n\n[tablet]: -5. If you fail, choose a connecting location with no barriers between it and your location. Place 1 barrier between the two locations.\n\n[elder_thing]: -X. X is twice the number of barriers between your location and all connecting locations."
- else
- tool = "Easy / Standard\n\n[skull]: -1 for each location to the east of your location (on the same row).\n\n[cultist]: -2. If you fail, move to the connecting location to the east, ignoring all barriers.\n\n[tablet]: -3. If you fail, choose a connecting location with no barriers between it and your location. Place 1 barrier between the two locations.\n\n[elder_thing]: -X. X is the number of barriers between your location and all connecting locations."
- end
- end
- --devil reef
- if scenario.getDescription() == "Devil Reef" then
- if scenario.is_face_down == true then
- tool = "Hard / Expert\n\n[skull]: -X. X is 1 more than the number of keys the investigators control.\n\n[cultist]: -3. If this is an attack or evasion attempt against a [[Deep One]] enemy, it engages you. (If it is already engaged with you, it disengages first, then re-engages you.)\n\n[tablet]: -4. If you are not in a vehicle, take 1 damage.\n\n[elder_thing]: -5. If your location has a key on it, take 1 horror."
- else
- tool = "Easy / Standard\n\n[skull]: -X. X is the number of keys the investigators control.\n\n[cultist]: -2. If you fail and this is an attack or evasion attempt against a [[Deep One]] enemy, it engages you. (If it is already engaged with you, it disengages first, then re-engages you.)\n\n[tablet]: -3. If you fail and you are not in a vehicle, take 1 damage.\n\n[elder_thing]: -4. If you fail and your location has a key on it, take 1 horror."
- end
- end
- --horror in high gear
- if scenario.getDescription() == "Horror in High Gear" then
- if scenario.is_face_down == true then
- tool = "Hard / Expert\n\n[skull]: -2 (-4 instead if there are 6 or fewer locations remaining in the Road deck).\n\n[cultist]: -2. For each point you fail by, an investigator in your vehicle places 1 of their clues on your location.\n\n[tablet]: -3. For each point you fail by, an investigator in your vehicle loses 1 resource.\n\n[elder_thing]: -4. Resolve the hunter keyword on each enemy in play."
- else
- tool = "Easy / Standard\n\n[skull]: -1 (-3 instead if there are 6 or fewer locations remaining in the Road deck).\n\n[cultist]: -1. For each point you fail by, an investigator in your vehicle places 1 of their clues on your location.\n\n[tablet]: -2. For each point you fail by, an investigator in your vehicle loses 1 resource.\n\n[elder_thing]: -4. If you fail, resolve the hunter keyword on each enemy in play."
- end
- end
- --light in the fog
- if scenario.getDescription() == "A Light in the Fog" then
- if scenario.is_face_down == true then
- tool = "Hard / Expert\n\n[skull]: -2. If your location is flooded, reveal an additional chaos token.\n\n[cultist]: -2. If you fail, after this test ends, increase the flood level of your location (if you cannot, take 1 horror instead).\n\n[tablet]: -3. If you fail this test and your location is flooded, take 2 damage.\n\n[elder_thing]: -4. Move the nearest unengaged enemy once toward your location. It loses aloof during this movement."
- else
- tool = "Easy / Standard\n\n[skull]: -1. If your location is flooded, reveal an additional chaos token.\n\n[cultist]: -2. If you fail, after this test ends, increase the flood level of your location.\n\n[tablet]: -3. If you fail this test and your location is flooded, take 1 damage.\n\n[elder_thing]: -4. If you fail, move the nearest ready unengaged enemy once toward your location. It loses aloof during this movement."
- end
- end
- --lair of dagon
- if scenario.getDescription() == "The Lair of Dagon" then
- if scenario.is_face_down == true then
- tool = "Hard / Expert\n\n[skull]: -2 for each key on this card.\n\n[cultist]: -2. Reveal an additional chaos token. If you reveal 1 or more [curse] tokens during this test, you automatically fail.\n\n[tablet]: -3. Place each key you control on your location and take 1 damage.\n\n[elder_thing]: -4. Add 2 [curse] tokens to the chaos bag."
- else
- tool = "Easy / Standard\n\n[skull]: -1 for each key on this card.\n\n[cultist]: 0. Reveal an additional chaos token. If you reveal 1 or more [curse] tokens during this test, you automatically fail.\n\n[tablet]: -3. If you fail, place each key you control on your location.\n\n[elder_thing]: -4. If you fail, add 1 [curse] token to the chaos bag."
- end
- end
- --into the maelstrom
- if scenario.getDescription() == "Into the Maelstrom" then
- if scenario.is_face_down == true then
- tool = "Hard / Expert\n\n[skull]: -2 (-4 instead if there are 4 or more unflooded [[Y'ha-nthlei]] locations in play).\n\n[cultist]: -4. If you fail, place 1 doom on the current agenda (this may cause the current agenda to advance).\n\n[tablet]: -5. If you fail, you must either increase the flood level of your location or take 1 damage.\n\n[elder_thing]: -6. If you fail and there is a key on your location, take 1 horror."
- else
- tool = "Easy / Standard\n\n[skull]: -1 (-3 instead if there are 4 or more unflooded [[Y'ha-nthlei]] locations in play).\n\n[cultist]: -3. If you fail, place 1 doom on the current agenda (this may cause the current agenda to advance).\n\n[tablet]: -4. If you fail, you must either increase the flood level of your location or take 1 damage.\n\n[elder_thing]: -5. If you fail and there is a key on your location, take 1 horror."
- end
- end
- end
- getObjectFromGUID("8b081b").editButton({index = 6, tooltip = tool})
- getObjectFromGUID("bd0ff4").editButton({index = 6, tooltip = tool})
- getObjectFromGUID("383d8b").editButton({index = 6, tooltip = tool})
- getObjectFromGUID("0840d5").editButton({index = 6, tooltip = tool})
-end
diff --git a/objects/Fan-MadeAccessories.aa8b38/WhimsicalsGenericDifficultySelector.05efb4/GenericDifficultySelector.8112ff.json b/objects/Fan-MadeAccessories.aa8b38/GenericDifficultySelector.8112ff.json
similarity index 85%
rename from objects/Fan-MadeAccessories.aa8b38/WhimsicalsGenericDifficultySelector.05efb4/GenericDifficultySelector.8112ff.json
rename to objects/Fan-MadeAccessories.aa8b38/GenericDifficultySelector.8112ff.json
index 08d5f0b1..72f701d1 100644
--- a/objects/Fan-MadeAccessories.aa8b38/WhimsicalsGenericDifficultySelector.05efb4/GenericDifficultySelector.8112ff.json
+++ b/objects/Fan-MadeAccessories.aa8b38/GenericDifficultySelector.8112ff.json
@@ -22,7 +22,7 @@
"ImageURL": "http://cloud-3.steamusercontent.com/ugc/965354846165100486/3DC8FCEF364B30758B09EF96AF9458F2B8E64D56/",
"WidthScale": 0
},
- "Description": "click to set chaos token difficulty",
+ "Description": "Define difficulties in this object's script.",
"DragSelectable": true,
"GMNotes": "",
"GUID": "8112ff",
@@ -34,7 +34,7 @@
"LayoutGroupSortIndex": 0,
"Locked": false,
"LuaScriptState": "",
- "LuaScript_path": "Fan-MadeAccessories.aa8b38/WhimsicalsGenericDifficultySelector.05efb4/GenericDifficultySelector.8112ff.ttslua",
+ "LuaScript_path": "Fan-MadeAccessories.aa8b38/GenericDifficultySelector.8112ff.ttslua",
"MeasureMovement": false,
"Name": "Custom_Tile",
"Nickname": "Generic Difficulty Selector",
@@ -54,4 +54,4 @@
},
"Value": 0,
"XmlUI": ""
-}
+}
\ No newline at end of file
diff --git a/objects/Fan-MadeAccessories.aa8b38/GenericDifficultySelector.8112ff.ttslua b/objects/Fan-MadeAccessories.aa8b38/GenericDifficultySelector.8112ff.ttslua
new file mode 100644
index 00000000..522cac8a
--- /dev/null
+++ b/objects/Fan-MadeAccessories.aa8b38/GenericDifficultySelector.8112ff.ttslua
@@ -0,0 +1,38 @@
+-- edit the "tokenData" table to change the preset difficulties
+-- list of valid ids: 'p1', '0', 'm1', 'm2', 'm3', 'm4', 'm5', 'm6', 'm7', 'm8',
+-- 'skull', 'cultist', 'tablet', 'elder', 'red', 'blue', 'bless', 'curse', 'frost'
+
+local tokenData = {
+ Easy = { 'p1', 'p1', '0', '0', '0', 'm1', 'm1', 'm1', 'm2', 'm2', 'skull', 'skull', 'cultist', 'red', 'blue' },
+ Standard = { 'p1', '0', '0', 'm1', 'm1', 'm1', 'm2', 'm2', 'm3', 'm4', 'skull', 'skull', 'cultist', 'red', 'blue' },
+ Hard = { '0', '0', '0', 'm1', 'm1', 'm2', 'm2', 'm3', 'm3', 'm4', 'm5', 'skull', 'skull', 'cultist', 'red', 'blue' },
+ Expert = { '0', 'm1', 'm1', 'm2', 'm2', 'm3', 'm3', 'm4', 'm4', 'm5', 'm6', 'm8', 'skull', 'skull', 'cultist', 'red', 'blue' }
+}
+
+-- create buttons on startup
+function onLoad()
+ local z_offset = -0.15
+ for difficulty, _ in pairs(tokenData) do
+ local clickFunction = difficulty:lower() .. "Click"
+ self.setVar(clickFunction, function() clickFun(difficulty) end)
+
+ self.createButton({
+ label = difficulty,
+ function_owner = self,
+ click_function = clickFunction,
+ position = { 0, 0.1, z_offset },
+ rotation = { 0, 0, 0 },
+ scale = { 0.47, 1, 0.47 },
+ height = 200,
+ width = 1150,
+ font_size = 100,
+ color = { 0.87, 0.8, 0.70 },
+ font_color = { 0, 0, 0 }
+ })
+ z_offset = z_offset + 0.20
+ end
+end
+
+function clickFun(difficulty)
+ Global.call("setChaosBagState", tokenData[difficulty])
+end
diff --git a/objects/Fan-MadeAccessories.aa8b38/WhimsicalsGenericDifficultySelector.05efb4.json b/objects/Fan-MadeAccessories.aa8b38/WhimsicalsGenericDifficultySelector.05efb4.json
deleted file mode 100644
index 6c44742b..00000000
--- a/objects/Fan-MadeAccessories.aa8b38/WhimsicalsGenericDifficultySelector.05efb4.json
+++ /dev/null
@@ -1,57 +0,0 @@
-{
- "AltLookAngle": {
- "x": 0,
- "y": 0,
- "z": 0
- },
- "Autoraise": true,
- "Bag": {
- "Order": 0
- },
- "ColorDiffuse": {
- "b": 0,
- "g": 0.36652,
- "r": 0.70588
- },
- "ContainedObjects_order": [
- "GenericDifficultySelector.8112ff",
- "TokenImageProvider.162580",
- "TokenList.297f5e",
- "GenericDifficultySelectorInstructions13.c32992"
- ],
- "ContainedObjects_path": "WhimsicalsGenericDifficultySelector.05efb4",
- "Description": "",
- "DragSelectable": true,
- "GMNotes": "",
- "GUID": "05efb4",
- "Grid": true,
- "GridProjection": false,
- "Hands": false,
- "HideWhenFaceDown": false,
- "IgnoreFoW": false,
- "LayoutGroupSortIndex": 0,
- "Locked": false,
- "LuaScript": "",
- "LuaScriptState": "",
- "MaterialIndex": -1,
- "MeasureMovement": false,
- "MeshIndex": -1,
- "Name": "Bag",
- "Nickname": "Whimsical's Generic Difficulty Selector",
- "Snap": true,
- "Sticky": true,
- "Tooltip": true,
- "Transform": {
- "posX": 29.073,
- "posY": 3.901,
- "posZ": -21.285,
- "rotX": 0,
- "rotY": 0,
- "rotZ": 0,
- "scaleX": 1,
- "scaleY": 1,
- "scaleZ": 1
- },
- "Value": 0,
- "XmlUI": ""
-}
diff --git a/objects/Fan-MadeAccessories.aa8b38/WhimsicalsGenericDifficultySelector.05efb4/GenericDifficultySelector.8112ff.ttslua b/objects/Fan-MadeAccessories.aa8b38/WhimsicalsGenericDifficultySelector.05efb4/GenericDifficultySelector.8112ff.ttslua
deleted file mode 100644
index 054e3435..00000000
--- a/objects/Fan-MadeAccessories.aa8b38/WhimsicalsGenericDifficultySelector.05efb4/GenericDifficultySelector.8112ff.ttslua
+++ /dev/null
@@ -1,169 +0,0 @@
----
---- Generated by EmmyLua(https://github.com/EmmyLua)
---- Created by Whimsical.
---- DateTime: 2021-08-05 6:14 p.m.
----
-
-
-local tags = {
- bag = "chaosBag",
- provider = "token_list_provider",
- tokens = "token_image_provider"
-}
-
----@class ChaosToken
----@field name string
----@field image string
-local _ = {}
-
----@type table
-local sources
-
----@type table
-local tokens
-
----@param source TTSObject
-local LoadSource = function (source)
- tokens = source:getTable("chaos_tokens")
-end
-
----@param token ChaosToken
----@param position Vector
----@param chaosBag TTSObject
----@return number
-local SpawnToken = function(token, position, chaosBag)
- spawnObject {
- type = "Custom_Tile",
- position = position,
- scale = { 0.81, 1.0, 0.81 },
- rotation = { 0, 270, 0 },
- ---@param object TTSObject
- callback_function = function(object, _, _)
- object:setName(token.name)
- chaosBag:putObject(object)
- end
- }:setCustomObject {
- image = token.image,
- type = 2,
- thickness = 0.1
- }
-end
-
----@param chaosBag TTSObject
-local emptyBag = function(chaosBag)
- local object = chaosBag:getObjects()
- local pos = self:getPosition()
- pos.y = pos.y+1
-
- for _, object in ipairs(object) do
- chaosBag:takeObject {
- guid = object.guid,
- position = pos,
- ---@param item TTSObject
- callback_function = function (item) item:destruct() end
- }
- end
-end
-
----@param difficulty string
-local clickFun= function (difficulty)
- local chaosBag = getObjectsWithTag(tags.bag)[1]
-
- emptyBag(chaosBag)
-
- local loading = tokens[difficulty]
- local pos = self:getPosition()
-
- for _, token_id in ipairs(loading) do
- if type(token_id)=="string" then token_id = token_id:lower() end
-
- local token = sources[token_id]
-
- if (token==nil) then
- error("Could not find token \"" .. token_id .. "\".")
- return
- end
-
- SpawnToken(token, pos, chaosBag)
- end
-end
-
-
----@param difficulty string
-local MakeClickFun = function(difficulty)
- return function ()
- clickFun(difficulty)
- end
-end
-
----@param label string
----@param z_offset number|nil
-local makeButton = function(label , z_offset)
- z_offset = z_offset or -0.15
-
- _G[label:lower() .. "Click"] = MakeClickFun(label)
-
- self:createButton({
- label = label,
- function_owner = self,
- click_function = label:lower() .. "Click",
- position = {0, 0.1, z_offset},
- rotation = {0, 0, 0},
- scale = {0.47, 1, 0.47},
- height = 200,
- width = 1150,
- font_size = 100,
- color = {0.87, 0.8, 0.70},
- font_color = {0, 0, 0}
- })
- return z_offset + 0.20
-end
-
----@param source TTSObject
-local CreateButtons= function(source)
- self:clearButtons()
-
- local z_offset
- for difficulty,_ in pairs(tokens) do
- z_offset = makeButton(difficulty, z_offset)
- end
-end
-
-
-function LoadTokens()
- ---@type TTSObject[]
- local image_sources = getObjectsWithTag(tags.tokens)
-
- if (#image_sources<=0) then
- error("Cannot find images_sources")
- return
- end
-
- sources = image_sources[1]:getTable("sources")
-
- if (tokens~=nil) then CreateButtons() return end
-
- local source = getObjectsWithTag(tags.provider)
-
- if (#source<=0) then return end
-
- LoadSource(source[1])
-
- CreateButtons()
-end
-
-function onload()
- Timer.create {
- identifier = self:getGUID(),
- function_name = "LoadTokens"
- }
-end
-
----@param provider TTSObject
-function onObjectSpawn(provider)
- if (not provider:hasTag(tags.provider)) then return end
-
- LoadSource(provider)
-
- CreateButtons()
-end
diff --git a/objects/Fan-MadeAccessories.aa8b38/WhimsicalsGenericDifficultySelector.05efb4/GenericDifficultySelectorInstructions13.c32992.json b/objects/Fan-MadeAccessories.aa8b38/WhimsicalsGenericDifficultySelector.05efb4/GenericDifficultySelectorInstructions13.c32992.json
deleted file mode 100644
index a1ffa120..00000000
--- a/objects/Fan-MadeAccessories.aa8b38/WhimsicalsGenericDifficultySelector.05efb4/GenericDifficultySelectorInstructions13.c32992.json
+++ /dev/null
@@ -1,137 +0,0 @@
-{
- "AltLookAngle": {
- "x": 0,
- "y": 0,
- "z": 0
- },
- "Autoraise": true,
- "ColorDiffuse": {
- "b": 1,
- "g": 1,
- "r": 1
- },
- "Description": "Tool for create custom chaos bag configurations.\n - The actual difficulty selector: click a difficulty to fill the chaos bag.\n- Token Image Provider: edit in scripting editor to add new token types. Cut and Paste to save.\n- Token List: edit in scripting editor to customize difficulties. Cut and Paste to save.\n\nReference of Token codes on following pages:",
- "DragSelectable": true,
- "GMNotes": "",
- "GUID": "c32992",
- "Grid": true,
- "GridProjection": false,
- "Hands": false,
- "HideWhenFaceDown": false,
- "IgnoreFoW": false,
- "LayoutGroupSortIndex": 0,
- "Locked": false,
- "LuaScript": "",
- "LuaScriptState": "",
- "MeasureMovement": false,
- "Name": "Notecard",
- "Nickname": "Generic Difficulty Selector Instructions 1/3",
- "Snap": true,
- "States": {
- "2": {
- "AltLookAngle": {
- "x": 0,
- "y": 0,
- "z": 0
- },
- "Autoraise": true,
- "ColorDiffuse": {
- "b": 1,
- "g": 1,
- "r": 1
- },
- "Description": "1 — -8: Numeric tokens (Don't place quotes around these).\r\n\"S\": Skull.\r\n\"C\": Cultist.\r\n\"T\": Tablet.\r\n\"E\": Elder Thing.\r\n\"Fr\": Frost.",
- "DragSelectable": true,
- "GMNotes": "",
- "GUID": "eab766",
- "Grid": true,
- "GridProjection": false,
- "Hands": false,
- "HideWhenFaceDown": false,
- "IgnoreFoW": false,
- "LayoutGroupSortIndex": 0,
- "Locked": false,
- "LuaScript": "",
- "LuaScriptState": "",
- "MeasureMovement": false,
- "Name": "Notecard",
- "Nickname": "Generic Difficulty Selector Instructions 2/3",
- "Snap": true,
- "Sticky": true,
- "Tooltip": true,
- "Transform": {
- "posX": 3.29240441,
- "posY": 1.33262193,
- "posZ": 56.0586357,
- "rotX": 359.9792,
- "rotY": 89.99884,
- "rotZ": 359.983215,
- "scaleX": 1,
- "scaleY": 1,
- "scaleZ": 1
- },
- "Value": 0,
- "XmlUI": ""
- },
- "3": {
- "AltLookAngle": {
- "x": 0,
- "y": 0,
- "z": 0
- },
- "Autoraise": true,
- "ColorDiffuse": {
- "b": 1,
- "g": 1,
- "r": 1
- },
- "Description": "\"*\": Elder Sign.\r\n\"F\": Auto-fail.\r\n\"+\": Bless.\r\n\"-\": Curse.",
- "DragSelectable": true,
- "GMNotes": "",
- "GUID": "309295",
- "Grid": true,
- "GridProjection": false,
- "Hands": false,
- "HideWhenFaceDown": false,
- "IgnoreFoW": false,
- "LayoutGroupSortIndex": 0,
- "Locked": false,
- "LuaScript": "",
- "LuaScriptState": "",
- "MeasureMovement": false,
- "Name": "Notecard",
- "Nickname": "Generic Difficulty Selector Instructions 3/3",
- "Snap": true,
- "Sticky": true,
- "Tooltip": true,
- "Transform": {
- "posX": 3.29240441,
- "posY": 1.33262193,
- "posZ": 56.0586357,
- "rotX": 359.9792,
- "rotY": 89.9988556,
- "rotZ": 359.983215,
- "scaleX": 1,
- "scaleY": 1,
- "scaleZ": 1
- },
- "Value": 0,
- "XmlUI": ""
- }
- },
- "Sticky": true,
- "Tooltip": true,
- "Transform": {
- "posX": 13.505,
- "posY": 3.625,
- "posZ": 30.273,
- "rotX": 0,
- "rotY": 90,
- "rotZ": 0,
- "scaleX": 1,
- "scaleY": 1,
- "scaleZ": 1
- },
- "Value": 0,
- "XmlUI": ""
-}
diff --git a/objects/Fan-MadeAccessories.aa8b38/WhimsicalsGenericDifficultySelector.05efb4/TokenImageProvider.162580.json b/objects/Fan-MadeAccessories.aa8b38/WhimsicalsGenericDifficultySelector.05efb4/TokenImageProvider.162580.json
deleted file mode 100644
index 6da706bc..00000000
--- a/objects/Fan-MadeAccessories.aa8b38/WhimsicalsGenericDifficultySelector.05efb4/TokenImageProvider.162580.json
+++ /dev/null
@@ -1,48 +0,0 @@
-{
- "AltLookAngle": {
- "x": 0,
- "y": 0,
- "z": 0
- },
- "Autoraise": true,
- "ColorDiffuse": {
- "b": 1,
- "g": 1,
- "r": 1
- },
- "Description": "",
- "DragSelectable": true,
- "GMNotes": "",
- "GUID": "162580",
- "Grid": true,
- "GridProjection": false,
- "Hands": false,
- "HideWhenFaceDown": false,
- "IgnoreFoW": false,
- "LayoutGroupSortIndex": 0,
- "Locked": false,
- "LuaScriptState": "",
- "LuaScript_path": "Fan-MadeAccessories.aa8b38/WhimsicalsGenericDifficultySelector.05efb4/TokenImageProvider.162580.ttslua",
- "MeasureMovement": false,
- "Name": "Checker_white",
- "Nickname": "Token Image Provider",
- "Snap": true,
- "Sticky": true,
- "Tags": [
- "token_image_provider"
- ],
- "Tooltip": true,
- "Transform": {
- "posX": 13.194,
- "posY": 3.807,
- "posZ": 28.835,
- "rotX": 0,
- "rotY": 270,
- "rotZ": 180,
- "scaleX": 1,
- "scaleY": 1,
- "scaleZ": 1
- },
- "Value": 0,
- "XmlUI": ""
-}
diff --git a/objects/Fan-MadeAccessories.aa8b38/WhimsicalsGenericDifficultySelector.05efb4/TokenImageProvider.162580.ttslua b/objects/Fan-MadeAccessories.aa8b38/WhimsicalsGenericDifficultySelector.05efb4/TokenImageProvider.162580.ttslua
deleted file mode 100644
index 415f1183..00000000
--- a/objects/Fan-MadeAccessories.aa8b38/WhimsicalsGenericDifficultySelector.05efb4/TokenImageProvider.162580.ttslua
+++ /dev/null
@@ -1,37 +0,0 @@
----
---- Generated by EmmyLua(https://github.com/EmmyLua)
---- Created by Whimsical.
---- DateTime: 2021-08-05 6:51 p.m.
----
-
----@param name string
----@param image string
----@return ChaosToken
-local MakeToken = function (name, image)
- return {
- name = name,
- image = image
- }
-end
-
-sources = {
- [1] = MakeToken("+1", "https://i.imgur.com/uIx8jbY.png"),
- [0] = MakeToken("0", "https://i.imgur.com/btEtVfd.png"),
- [-1] = MakeToken("-1", "https://i.imgur.com/w3XbrCC.png"),
- [-2] = MakeToken("-2", "https://i.imgur.com/bfTg2hb.png"),
- [-3] = MakeToken("-3", "https://i.imgur.com/yfs8gHq.png"),
- [-4] = MakeToken("-4", "https://i.imgur.com/qrgGQRD.png"),
- [-5] = MakeToken("-5", "https://i.imgur.com/3Ym1IeG.png"),
- [-6] = MakeToken("-6", "https://i.imgur.com/c9qdSzS.png"),
- [-7] = MakeToken("-7", "https://i.imgur.com/4WRD42n.png"),
- [-8] = MakeToken("-8", "https://i.imgur.com/9t3rPTQ.png"),
- ["s"] = MakeToken("Skull", "https://i.imgur.com/stbBxtx.png"),
- ["c"] = MakeToken("Cultist", "https://i.imgur.com/VzhJJaH.png"),
- ["t"] = MakeToken("Tablet", "https://i.imgur.com/1plY463.png"),
- ["e"] = MakeToken("Elder Thing", "https://i.imgur.com/ttnspKt.png"),
- ["*"] = MakeToken("Elder Sign", "https://i.imgur.com/nEmqjmj.png"),
- ["f"] = MakeToken("Auto-fail", "https://i.imgur.com/lns4fhz.png"),
- ["+"] = MakeToken("Bless", "http://cloud-3.steamusercontent.com/ugc/1655601092778627699/339FB716CB25CA6025C338F13AFDFD9AC6FA8356/"),
- ["-"] = MakeToken("Curse", "http://cloud-3.steamusercontent.com/ugc/1655601092778636039/2A25BD38E8C44701D80DD96BF0121DA21843672E/"),
- ["fr"] = MakeToken("Frost", "http://cloud-3.steamusercontent.com/ugc/1858293462583104677/195F93C063A8881B805CE2FD4767A9718B27B6AE/"),
-}
diff --git a/objects/Fan-MadeAccessories.aa8b38/WhimsicalsGenericDifficultySelector.05efb4/TokenList.297f5e.json b/objects/Fan-MadeAccessories.aa8b38/WhimsicalsGenericDifficultySelector.05efb4/TokenList.297f5e.json
deleted file mode 100644
index 4d8224b0..00000000
--- a/objects/Fan-MadeAccessories.aa8b38/WhimsicalsGenericDifficultySelector.05efb4/TokenList.297f5e.json
+++ /dev/null
@@ -1,49 +0,0 @@
-{
- "AltLookAngle": {
- "x": 0,
- "y": 0,
- "z": 0
- },
- "Autoraise": true,
- "ColorDiffuse": {
- "b": 0,
- "g": 0,
- "r": 0
- },
- "Description": "",
- "DragSelectable": true,
- "GMNotes": "",
- "GUID": "297f5e",
- "Grid": true,
- "GridProjection": false,
- "Hands": false,
- "HideWhenFaceDown": false,
- "IgnoreFoW": false,
- "LayoutGroupSortIndex": 0,
- "Locked": false,
- "LuaScriptState": "",
- "LuaScript_path": "Fan-MadeAccessories.aa8b38/WhimsicalsGenericDifficultySelector.05efb4/TokenList.297f5e.ttslua",
- "MeasureMovement": false,
- "Name": "Checker_black",
- "Nickname": "Token List",
- "Snap": true,
- "Sticky": true,
- "Tags": [
- "mlc_memory_object",
- "token_list_provider"
- ],
- "Tooltip": true,
- "Transform": {
- "posX": 12.984,
- "posY": 4.045,
- "posZ": 29.828,
- "rotX": 0,
- "rotY": 270,
- "rotZ": 206,
- "scaleX": 1,
- "scaleY": 1,
- "scaleZ": 1
- },
- "Value": 0,
- "XmlUI": ""
-}
diff --git a/objects/Fan-MadeAccessories.aa8b38/WhimsicalsGenericDifficultySelector.05efb4/TokenList.297f5e.ttslua b/objects/Fan-MadeAccessories.aa8b38/WhimsicalsGenericDifficultySelector.05efb4/TokenList.297f5e.ttslua
deleted file mode 100644
index 4a1559f2..00000000
--- a/objects/Fan-MadeAccessories.aa8b38/WhimsicalsGenericDifficultySelector.05efb4/TokenList.297f5e.ttslua
+++ /dev/null
@@ -1,12 +0,0 @@
----
---- Generated by EmmyLua(https://github.com/EmmyLua)
---- Created by Whimsical.
---- DateTime: 2021-08-05 7:19 p.m.
----
-
-chaos_tokens = {
- Easy = {1, 1, 0, 0, -1, -1, -1, -2, -2, "S", "S", "C", "T", "F", "*"},
- Standard = {1, 0, 0, -1, -1, -1, -2, -2, -3, -4, "S", "S", "C", "T", "F", "*"},
- Hard = {0, 0, -1, -1, -2, -2, -3, -4, -4, -5, "Fr", "Fr", "S", "S", "C", "T", "F", "*"},
- Expert = {0, -1, -2, -2, -3, -4, -4, -5, -7, "Fr", "Fr", "Fr", "S", "S", "C", "T", "F", "*"}
-}
diff --git a/objects/Playermat1White.8b081b.ttslua b/objects/Playermat1White.8b081b.ttslua
index b2cd6913..7dd4c4fd 100644
--- a/objects/Playermat1White.8b081b.ttslua
+++ b/objects/Playermat1White.8b081b.ttslua
@@ -2,7 +2,6 @@
-- specific setup (different for each playmat)
---------------------------------------------------------
-PLAYER_COLOR = "White"
PLAY_ZONE_POSITION = { x = -54.5, y = 4, z = 19 }
PLAY_ZONE_SCALE = { x = 32, y = 5, z = 12 }
TRASHCAN_GUID = "147e80"
diff --git a/objects/Playermat2Orange.bd0ff4.ttslua b/objects/Playermat2Orange.bd0ff4.ttslua
index 0d86c537..c30fe5af 100644
--- a/objects/Playermat2Orange.bd0ff4.ttslua
+++ b/objects/Playermat2Orange.bd0ff4.ttslua
@@ -2,7 +2,6 @@
-- specific setup (different for each playmat)
---------------------------------------------------------
-PLAYER_COLOR = "Orange"
PLAY_ZONE_POSITION = { x = -54.5, y = 4, z = -19 }
PLAY_ZONE_SCALE = { x = 32, y = 5, z = 12 }
TRASHCAN_GUID = "f7b6c8"
diff --git a/objects/Playermat3Green.383d8b.ttslua b/objects/Playermat3Green.383d8b.ttslua
index 17c1a652..35b55b38 100644
--- a/objects/Playermat3Green.383d8b.ttslua
+++ b/objects/Playermat3Green.383d8b.ttslua
@@ -2,7 +2,6 @@
-- specific setup (different for each playmat)
---------------------------------------------------------
-PLAYER_COLOR = "Green"
PLAY_ZONE_POSITION = { x = -26.5, y = 4, z = 26.5 }
PLAY_ZONE_SCALE = { x = 32, y = 5, z = 12 }
TRASHCAN_GUID = "5f896a"
diff --git a/objects/Playermat4Red.0840d5.ttslua b/objects/Playermat4Red.0840d5.ttslua
index 024f8cdd..082fc126 100644
--- a/objects/Playermat4Red.0840d5.ttslua
+++ b/objects/Playermat4Red.0840d5.ttslua
@@ -2,7 +2,6 @@
-- specific setup (different for each playmat)
---------------------------------------------------------
-PLAYER_COLOR = "Red"
PLAY_ZONE_POSITION = { x = -26.5, y = 4, z = -26.5 }
PLAY_ZONE_SCALE = { x = 32, y = 5, z = 12 }
TRASHCAN_GUID = "4b8594"
diff --git a/src/accessories/ChaosBagManager.ttslua b/src/accessories/ChaosBagManager.ttslua
index a64b2883..96fdced9 100644
--- a/src/accessories/ChaosBagManager.ttslua
+++ b/src/accessories/ChaosBagManager.ttslua
@@ -1,30 +1,10 @@
-local TOKEN_URL = {
- ElderSign = "https://i.imgur.com/nEmqjmj.png",
- plusOne = "https://i.imgur.com/uIx8jbY.png",
- Zero = "https://i.imgur.com/btEtVfd.png",
- minusOne = "https://i.imgur.com/w3XbrCC.png",
- minusTwo = "https://i.imgur.com/bfTg2hb.png",
- minusThree = "https://i.imgur.com/yfs8gHq.png",
- minusFour = "https://i.imgur.com/qrgGQRD.png",
- minusFive = "https://i.imgur.com/3Ym1IeG.png",
- minusSix = "https://i.imgur.com/c9qdSzS.png",
- minusSeven = "https://i.imgur.com/4WRD42n.png",
- minusEight = "https://i.imgur.com/9t3rPTQ.png",
- Skull = "https://i.imgur.com/stbBxtx.png",
- Cultist = "https://i.imgur.com/VzhJJaH.png",
- Tablet = "https://i.imgur.com/1plY463.png",
- ElderThing = "https://i.imgur.com/ttnspKt.png",
- AutoFail = "https://i.imgur.com/lns4fhz.png",
- Frost = "http://cloud-3.steamusercontent.com/ugc/1858293462583104677/195F93C063A8881B805CE2FD4767A9718B27B6AE/"
-}
-
-local TOKEN_NAMES = {
+local TOKEN_IDS = {
-- first row
- "plusOne", "Zero", "minusOne", "minusTwo", "minusThree", "minusFour",
+ "p1", "0", "m1", "m2", "m3", "m4",
-- second row
- "minusFive", "minusSix", "minusSeven", "minusEight", "Frost",
+ "m5", "m6", "m7", "m8", "frost",
-- third row
- "ElderSign", "Skull", "Cultist", "Tablet", "ElderThing", "AutoFail"
+ "blue", "skull", "cultist", "tablet", "elder", "red"
}
local BUTTON_TOOLTIP = {
@@ -52,9 +32,6 @@ buttonParameters.color = { 0, 0, 0, 0 }
buttonParameters.width = 300
buttonParameters.height = 300
-local UPDATING = false
-local tokenArranger
-
local name
local tokens = {}
@@ -76,108 +53,30 @@ function onLoad()
self.createButton(buttonParameters)
end
-
- self.addContextMenuItem("More Information", function()
- printToAll("------------------------------", "White")
- printToAll("Chaos Bag Manager by Chr1Z", "Orange")
- end)
-
- tokenArranger = getObjectFromGUID("022907")
-end
-
--- get chaos bag from scripting zone and description
-function getChaosBag()
- local chaosbag = nil
- local chaosbag_zone = getObjectFromGUID("83ef06")
-
- -- error handling: scripting zone not found
- if chaosbag_zone == nil then
- printToAll("Zone for chaos bag detection couldn't be found.", "Red")
- return nil
- end
-
- for _, v in ipairs(chaosbag_zone.getObjects()) do
- if v.getDescription() == "Chaos Bag" then
- chaosbag = getObjectFromGUID(v.getGUID())
- break
- end
- end
-
- -- error handling: chaos bag not found
- if chaosbag == nil then
- printToAll("Chaos bag couldn't be found.", "Red")
- end
- return chaosbag
end
-- click function for buttons
function buttonClick(index, isRightClick)
- chaosbag = getChaosBag()
+ local tokenId = TOKEN_IDS[index]
- -- error handling: chaos bag not found
- if chaosbag == nil then return end
-
- name = BUTTON_TOOLTIP[index]
- tokens = {}
- for _, v in ipairs(chaosbag.getObjects()) do
- if v.name == name then table.insert(tokens, v.guid) end
- end
-
- token = TOKEN_NAMES[index]
if isRightClick then
- -- error handling: no matching token found
- if #tokens == 0 then
- printToAll("No " .. name .. " tokens in the chaos bag.", "Yellow")
- return
+ Global.call("removeChaosToken", tokenId)
+ else
+ local tokens = {}
+ local name = BUTTON_TOOLTIP[index]
+ local chaosbag = Global.call("findChaosBag")
+
+ for _, v in ipairs(chaosbag.getObjects()) do
+ if v.name == name then table.insert(tokens, v.guid) end
end
- -- remove token
- chaosbag.takeObject({
- guid = tokens[1],
- position = self.getPosition(),
- smooth = false,
- callback_function = removeCallback
- })
- else
-- spawn token (only 8 frost tokens allowed)
- if token == "Frost" and #tokens == 8 then
+ if tokenId == "frost" and #tokens == 8 then
printToAll("The maximum of 8 Frost tokens is already in the bag.", "Yellow")
return
end
- local obj = spawnObject({
- type = 'Custom_Tile',
- position = chaosbag.getPosition() + Vector(0, 1, 0),
- rotation = { x = 0, y = 260, z = 0 },
- callback_function = spawnCallback
- })
- obj.setCustomObject({
- type = 2,
- image = TOKEN_URL[token],
- thickness = 0.1
- })
- end
-
- updateTokenArranger()
-end
-
-function removeCallback(obj)
- printToAll("Removing " .. name .. " token (in bag: " .. #tokens - 1 .. ")", "White")
- obj.destruct()
-end
-
-function spawnCallback(obj)
- obj.scale { 0.81, 1, 0.81 }
- obj.setName(name)
- printToAll("Adding " .. name .. " token (in bag: " .. #tokens + 1 .. ")", "White")
-end
-
-function updateTokenArranger()
- if tokenArranger and not UPDATING then
- UPDATING = true
- Wait.time(function()
- UPDATING = false
- tokenArranger.call("layout")
- end, 1.5)
+ Global.call("spawnChaosToken", tokenId)
+ printToAll("Adding " .. name .. " token (in bag: " .. #tokens + 1 .. ")", "White")
end
end
diff --git a/src/accessories/CleanUpHelper.ttslua b/src/accessories/CleanUpHelper.ttslua
index d0b8f3f4..ebcd03ac 100644
--- a/src/accessories/CleanUpHelper.ttslua
+++ b/src/accessories/CleanUpHelper.ttslua
@@ -2,13 +2,10 @@
Cleans up the table for the next scenario in a campaign:
- sets counters to default values (resources and doom) or trauma values (health and sanity, if not disabled) from campaign log
- puts everything on playmats and hands into respective trashcans
-- use the IGNORE_TAG to exclude objects from tidying (default: "CleanUpHelper_Ignore")
---]]
+- use the IGNORE_TAG to exclude objects from tidying (default: "CleanUpHelper_Ignore")]]
local tokenSpawnTrackerApi = require("core/token/TokenSpawnTrackerApi")
-
--- enable this for debugging
-local SHOW_RAYS = false
+local playmatApi = require("playermat/PlaymatApi")
-- these objects will be ignored
local IGNORE_GUIDS = {
@@ -81,9 +78,7 @@ buttonParameters.function_owner = self
---------------------------------------------------------
function onSave()
- return JSON.encode({
- options = options
- })
+ return JSON.encode({ options = options })
end
function onLoad(savedData)
@@ -213,7 +208,7 @@ function resetSkillTrackers()
if obj ~= nil then
obj.call("updateStats", { 1, 1, 1, 1 })
else
- printToAll("Skill tracker number " .. i .. " could not be found.", "Yellow")
+ printToAll("Skill tracker for " .. COLORS[i] .. " playmat could not be found.", "Yellow")
end
end
end
@@ -296,7 +291,7 @@ function discardHands()
for i = 1, 4 do
local trashcan = getObjectFromGUID(TRASHCAN_GUIDS[i])
if trashcan == nil then return end
- local hand = Player[COLORS[i]].getHandObjects()
+ local hand = Player[playmatApi.getPlayerColor(COLORS[i])].getHandObjects()
for j = #hand, 1, -1 do
trashcan.putObject(hand[j])
end
@@ -339,7 +334,7 @@ function tidyPlayerMatCoroutine()
local trashcan = getObjectFromGUID(TRASHCAN_GUIDS[i])
if trashcan == nil then
printToAll("Trashcan for " .. COLORS[i] .. " playmat could not be found!", "Red")
- return
+ return 1
end
for _, entry in ipairs(findObjects(i)) do
@@ -390,7 +385,7 @@ function findObjects(num)
size = PHYSICS_SCALE[num],
origin = PHYSICS_POSITION[num],
orientation = { 0, PHYSICS_ROTATION[num], 0 },
- debug = SHOW_RAYS
+ debug = false
})
end
diff --git a/src/accessories/HandHelper.ttslua b/src/accessories/HandHelper.ttslua
index 21e2e586..b72c5ef5 100644
--- a/src/accessories/HandHelper.ttslua
+++ b/src/accessories/HandHelper.ttslua
@@ -1,4 +1,6 @@
-local playmatAPI = require("playermat/PlaymatApi")
+local playmatApi = require("playermat/PlaymatApi")
+
+-- forward declaration of variables that are used across functions
local matColor, handColor, loopId, hovering
function onLoad()
@@ -62,8 +64,8 @@ end
-- updates the matcolor and handcolor variable
function updateColors()
- matColor = playmatAPI.getMatColorByPosition(self.getPosition())
- handColor = playmatAPI.getHandColor(matColor)
+ matColor = playmatApi.getMatColorByPosition(self.getPosition())
+ handColor = playmatApi.getPlayerColor(matColor)
self.setName(handColor .. " Hand Helper")
end
@@ -78,7 +80,7 @@ function updateValue(toggle)
if Player[handColor].getHandCount() == 0 then return end
-- get state of "Dream-Enhancing Serum" from playermat and update button label
- local des = playmatAPI.isDES(matColor)
+ local des = playmatApi.isDES(matColor)
if toggle then des = not des end
self.editButton({ index = 1, label = "DES: " .. (des and "✓" or "✗") })
@@ -110,5 +112,5 @@ end
-- discards a random non-hidden card from hand
function discardRandom()
- playmatAPI.doDiscardOne(matColor)
+ playmatApi.doDiscardOne(matColor)
end
diff --git a/src/accessories/SearchAssistant.ttslua b/src/accessories/SearchAssistant.ttslua
index efba521e..e1f305c4 100644
--- a/src/accessories/SearchAssistant.ttslua
+++ b/src/accessories/SearchAssistant.ttslua
@@ -1,10 +1,7 @@
-local playmatAPI = require("playermat/PlaymatApi")
+local playmatApi = require("playermat/PlaymatApi")
-- forward declaration of variables that are used across functions
-local matColor
-local setAsidePosition
-local setAsideRotation
-local drawDeckPosition
+local matColor, handColor, setAsidePosition, setAsideRotation, drawDeckPosition
local quickParameters = {}
quickParameters.function_owner = self
@@ -102,10 +99,11 @@ end
-- start the search (change UI, set handCards aside, draw cards)
function startSearch(messageColor, number)
- matColor = playmatAPI.getMatColorByPosition(self.getPosition())
+ matColor = playmatApi.getMatColorByPosition(self.getPosition())
+ handColor = playmatApi.getPlayerColor(matColor)
-- get draw deck
- local drawDeck = playmatAPI.getDrawDeck(matColor)
+ local drawDeck = playmatApi.getDrawDeck(matColor)
if drawDeck == nil then
printToColor(matColor .. " draw deck could not be found!", messageColor, "Red")
return
@@ -121,8 +119,8 @@ function startSearch(messageColor, number)
end
-- get position and rotation for set aside cards
- local handData = Player[matColor].getHandTransform()
- local handCards = Player[matColor].getHandObjects()
+ local handData = Player[handColor].getHandTransform()
+ local handCards = Player[handColor].getHandObjects()
setAsidePosition = handData.position + offset * handData.right
setAsideRotation = { handData.rotation.x, handData.rotation.y + 180, 180 }
@@ -136,18 +134,18 @@ function startSearch(messageColor, number)
local object = v.hit_object
if object.tag == "Card" and not object.is_face_down then
object.flip()
- Wait.time(function() drawDeck = playmatAPI.getDrawDeck(matColor) end, 1)
+ Wait.time(function() drawDeck = playmatApi.getDrawDeck(matColor) end, 1)
break
end
end
- Wait.time(function() drawDeck.deal(number, matColor) end, 1)
+ Wait.time(function() drawDeck.deal(number, handColor) end, 1)
searchView()
end
-- place handCards back into deck and optionally shuffle
function endSearch(_, _, isRightClick)
- local handCards = Player[matColor].getHandObjects()
+ local handCards = Player[handColor].getHandObjects()
for i = #handCards, 1, -1 do
handCards[i].setPosition(drawDeckPosition + Vector(0, 6 - i * 0.3, 0))
@@ -156,7 +154,7 @@ function endSearch(_, _, isRightClick)
if not isRightClick then
Wait.time(function()
- local deck = playmatAPI.getDrawDeck(matColor)
+ local deck = playmatApi.getDrawDeck(matColor)
if deck ~= nil then
deck.shuffle()
end
@@ -168,11 +166,11 @@ function endSearch(_, _, isRightClick)
local obj = v.hit_object
if obj.tag == "Deck" then
Wait.time(function()
- obj.deal(#obj.getObjects(), matColor)
+ obj.deal(#obj.getObjects(), handColor)
end, 1)
break
elseif obj.tag == "Card" then
- obj.setPosition(Player[matColor].getHandTransform().position)
+ obj.setPosition(Player[handColor].getHandTransform().position)
obj.flip()
break
end
diff --git a/src/accessories/TokenArranger.ttslua b/src/accessories/TokenArranger.ttslua
index 5f5c955e..2f779006 100644
--- a/src/accessories/TokenArranger.ttslua
+++ b/src/accessories/TokenArranger.ttslua
@@ -374,7 +374,7 @@ end
function onTokenDataChanged(parameters)
local tokenData = parameters.tokenData or {}
local currentScenario = parameters.currentScenario or ""
- local useFrontData = parameters.useFrontData or true
+ local useFrontData = parameters.useFrontData
-- only update if this data is new
local info = currentScenario .. tostring(useFrontData)
diff --git a/src/accessories/TokenArrangerApi.ttslua b/src/accessories/TokenArrangerApi.ttslua
index b61aee5f..47afb77f 100644
--- a/src/accessories/TokenArrangerApi.ttslua
+++ b/src/accessories/TokenArrangerApi.ttslua
@@ -24,7 +24,7 @@ do
-- updates the laid out tokens
TokenArrangerApi.layout = function()
- callIfExistent("layout")
+ Wait.time(function() callIfExistent("layout") end, 0.1)
end
return TokenArrangerApi
diff --git a/src/arkhamdb/DeckImporterMain.ttslua b/src/arkhamdb/DeckImporterMain.ttslua
index aa8be95c..66452455 100644
--- a/src/arkhamdb/DeckImporterMain.ttslua
+++ b/src/arkhamdb/DeckImporterMain.ttslua
@@ -1,6 +1,7 @@
require("arkhamdb/DeckImporterUi")
require("playercards/PlayerCardSpawner")
+local playmatApi = require("playermat/PlaymatApi")
local playAreaApi = require("core/PlayAreaApi")
local arkhamDb = require("arkhamdb/ArkhamDb")
local zones = require("playermat/Zones")
@@ -184,7 +185,8 @@ end
---@param deck Object Callback-provided spawned deck object
---@param playerColor String Color of the player to draw the cards to
function deckSpawned(deck, playerColor)
- local handPos = Player[playerColor].getHandTransform(1).position -- Only one hand zone per player
+ local player = Player[playmatApi.getPlayerColor(playerColor)]
+ local handPos = player.getHandTransform(1).position -- Only one hand zone per player
local deckCards = deck.getData().ContainedObjects
-- Process in reverse order so taking cards out doesn't upset the indexing
for i = #deckCards, 1, -1 do
diff --git a/src/chaosbag/BlessCurseManager.ttslua b/src/chaosbag/BlessCurseManager.ttslua
index d7e64786..a11910a6 100644
--- a/src/chaosbag/BlessCurseManager.ttslua
+++ b/src/chaosbag/BlessCurseManager.ttslua
@@ -1,9 +1,4 @@
-local tokenArrangerApi = require("accessories/TokenArrangerApi")
-
-local IMAGE_URL = {
- Bless = "http://cloud-3.steamusercontent.com/ugc/1655601092778627699/339FB716CB25CA6025C338F13AFDFD9AC6FA8356/",
- Curse = "http://cloud-3.steamusercontent.com/ugc/1655601092778636039/2A25BD38E8C44701D80DD96BF0121DA21843672E/"
-}
+local tokenArrangerApi = require("accessories/TokenArrangerApi")
-- common button parameters
local buttonParamaters = {}
@@ -12,11 +7,21 @@ buttonParamaters.color = { 0, 0, 0, 0 }
buttonParamaters.width = 700
buttonParamaters.height = 700
-local altState = false
-local MODE = { [false] = "Add / Remove", [true] = "Take / Return" }
-local BUTTON_COLOR = { [false] = { 0.4, 0.4, 0.4 }, [true] = { 0.9, 0.9, 0.9 } }
-local FONT_COLOR = { [false] = { 1, 1, 1 }, [true] = { 0, 0, 0 } }
-local whitespace = " "
+local altState = false
+local MODE = {
+ [false] = "Add / Remove",
+ [true] = "Take / Return"
+}
+local BUTTON_COLOR = {
+ [false] = { 0.4, 0.4, 0.4 },
+ [true] = { 0.9, 0.9, 0.9 }
+}
+local FONT_COLOR = {
+ [false] = { 1, 1, 1 },
+ [true] = { 0, 0, 0 }
+}
+local whitespace = " "
+local updating
---------------------------------------------------------
-- creating buttons and menus + initializing tables
@@ -71,8 +76,7 @@ end
function initializeState()
-- count tokens in the bag
- local chaosbag = getChaosBag()
- if chaosbag == nil then return end
+ local chaosbag = Global.call("findChaosBag")
local tokens = {}
for _, v in ipairs(chaosbag.getObjects()) do
if v.name == "Bless" then
@@ -101,23 +105,19 @@ function initializeState()
end
function broadcastCount(token)
- local count = getTokenCount(token)
+ local count = formatTokenCount(token)
if count == "(0/0)" then return end
broadcastToAll(token .. " Tokens " .. count, "White")
end
function printStatus(color)
- broadcastToColor("Curse Tokens " .. getTokenCount("Curse"), color, "White")
- broadcastToColor("Bless Tokens " .. getTokenCount("Bless"), color, "White")
+ broadcastToColor("Curse Tokens " .. formatTokenCount("Curse"), color, "White")
+ broadcastToColor("Bless Tokens " .. formatTokenCount("Bless"), color, "White")
end
-- context menu function 1
function doRemove(color)
- local chaosbag = getChaosBag()
- if chaosbag == nil then
- broadcastToAll("Chaos bag not found!", "Red")
- return
- end
+ local chaosbag = Global.call("findChaosBag")
-- remove tokens from chaos bag
local count = { Bless = 0, Curse = 0 }
@@ -132,33 +132,16 @@ function doRemove(color)
end
end
- broadcastToColor("Removed " .. count["Bless"] .. " Bless and " ..
- count["Curse"] .. " Curse tokens from the chaos bag.", color, "White")
-
- -- removing tokens that were 'taken'
- local function removeType(type)
- local count = 0
- for _, guid in ipairs(tokensTaken[type]) do
- local token = getObjectFromGUID(guid)
- if token ~= nil then
- token.destruct()
- count = count + 1
- end
- end
- return count
- end
-
- broadcastToColor("Removed " .. removeType("Bless") .. " Bless and " ..
- removeType("Curse") .. " Curse tokens from play.", color, "White")
+ broadcastToColor("Removed " .. count.Bless .. " Bless and " ..
+ count.Curse .. " Curse tokens from the chaos bag.", color, "White")
+ broadcastToColor("Removed " .. removeTakenTokens("Bless") .. " Bless and " ..
+ removeTakenTokens("Curse") .. " Curse tokens from play.", color, "White")
doReset(color)
end
-- context menu function 2
function doReset(color)
- -- delete previously pulled out tokens by the token arranger
- tokenArrangerApi.deleteCopiedTokens()
-
playerColor = color
numInPlay = { Bless = 0, Curse = 0 }
tokensTaken = { Bless = {}, Curse = {} }
@@ -166,6 +149,19 @@ function doReset(color)
tokenArrangerApi.layout()
end
+-- removing tokens that were 'taken'
+function removeTakenTokens(type)
+ local count = 0
+ for _, guid in ipairs(tokensTaken[type]) do
+ local token = getObjectFromGUID(guid)
+ if token ~= nil then
+ token.destruct()
+ count = count + 1
+ end
+ end
+ return count
+end
+
---------------------------------------------------------
-- click functions
---------------------------------------------------------
@@ -248,25 +244,35 @@ function callFunctions(token, isRightClick)
if success ~= 0 then tokenArrangerApi.layout() end
end
-function getChaosBag()
- local zone = getObjectFromGUID("83ef06")
- if zone == nil then printToAll("Zone for chaosbag not found!", "Red") return end
+-- returns a formatted string with information about the provided token type (bless / curse)
+function formatTokenCount(type)
+ if type == nil then type = mode end
+ return "(" .. (numInPlay[type] - #tokensTaken[type]) .. "/" .. #tokensTaken[type] .. ")"
+end
- local items = zone.getObjects()
- local chaosbag = nil
- for _, v in ipairs(items) do
- if v.getDescription() == "Chaos Bag" then
- chaosbag = getObjectFromGUID(v.getGUID())
+-- called by cards that seal bless/curse tokens
+---@param param Table This contains the type and guid of the sealed token
+function sealedToken(param)
+ table.insert(tokensTaken[param.type], param.guid)
+ broadcastCount(param.type)
+end
+
+-- called by cards that seal bless/curse tokens
+---@param param Table This contains the type and guid of the released token
+function releasedToken(param)
+ for i, v in ipairs(tokensTaken[param.type]) do
+ if v == param.guid then
+ table.remove(tokensTaken[param.type], i)
break
end
end
- if chaosbag == nil then printToColor("No chaos bag found", playerColor) end
- return chaosbag
-end
-
-function getTokenCount(type)
- if type == nil then type = mode end
- return "(" .. (numInPlay[type] - #tokensTaken[type]) .. "/" .. #tokensTaken[type] .. ")"
+ if not updating then
+ updating = true
+ Wait.frames(function()
+ broadcastCount(param.type)
+ updating = false
+ end, 1)
+ end
end
---------------------------------------------------------
@@ -278,39 +284,13 @@ function addToken(type)
printToColor("10 tokens already in play, not adding any.", playerColor)
return 0
end
- return spawnToken(type)
-end
-
-function spawnToken(type)
- local chaosbag = getChaosBag()
- if chaosbag == nil then
- return 0
- end
- local pos = chaosbag.getPosition()
- local obj = spawnObject({
- type = 'Custom_Tile',
- position = { pos.x, pos.y + 1, pos.z },
- callback_function = function(obj)
- obj.setName(type)
- chaosbag.putObject(obj)
- numInPlay[type] = numInPlay[type] + 1
- printToAll("Adding " .. type .. " token " .. getTokenCount(type))
- end
- })
- obj.setCustomObject({
- type = 2,
- image = IMAGE_URL[type],
- thickness = 0.1,
- })
- obj.scale { 0.81, 1, 0.81 }
+ numInPlay[type] = numInPlay[type] + 1
+ printToAll("Adding " .. type .. " token " .. formatTokenCount(type))
+ return Global.call("spawnChaosToken", type)
end
function takeToken(type, remove)
- local chaosbag = getChaosBag()
- if chaosbag == nil then
- broadcastToAll("Chaos bag not found!", "Red")
- return 0
- end
+ local chaosbag = Global.call("findChaosBag")
if not remove and not SEAL_CARD_MESSAGE then
broadcastToColor("For sealing tokens on cards try right-clicking on the card for seal options.", playerColor)
SEAL_CARD_MESSAGE = true
@@ -334,11 +314,11 @@ function takeToken(type, remove)
callback_function = function(obj)
if remove then
numInPlay[type] = numInPlay[type] - 1
- printToAll("Removing " .. type .. " token " .. getTokenCount(type))
+ printToAll("Removing " .. type .. " token " .. formatTokenCount(type))
obj.destruct()
else
table.insert(tokensTaken[type], obj.getGUID())
- printToAll("Taking " .. type .. " token " .. getTokenCount(type))
+ printToAll("Taking " .. type .. " token " .. formatTokenCount(type))
end
end
})
@@ -355,12 +335,12 @@ function returnToken(type)
printToColor("Couldn't find token " .. guid .. ", not returning to bag", playerColor)
return 0
end
- local chaosbag = getChaosBag()
+ local chaosbag = Global.call("findChaosBag")
if chaosbag == nil then
return 0
end
chaosbag.putObject(token)
- printToAll("Returning " .. type .. " token " .. getTokenCount(type))
+ printToAll("Returning " .. type .. " token " .. formatTokenCount(type))
end
---------------------------------------------------------
@@ -400,7 +380,7 @@ function addMenuOptions(playerColor, hoveredObject)
end
function sealToken(type, playerColor, enemy)
- local chaosbag = getChaosBag()
+ local chaosbag = Global.call("findChaosBag")
if chaosbag == nil then return end
local pos = enemy.getPosition()
@@ -414,7 +394,7 @@ function sealToken(type, playerColor, enemy)
Wait.frames(function()
table.insert(sealedTokens[enemy.getGUID()], obj)
table.insert(tokensTaken[type], obj.getGUID())
- printToColor("Sealing " .. type .. " token " .. getTokenCount(type), playerColor)
+ printToColor("Sealing " .. type .. " token " .. formatTokenCount(type), playerColor)
end, 1)
end
})
@@ -425,7 +405,7 @@ function sealToken(type, playerColor, enemy)
end
function releaseToken(type, playerColor, enemy)
- local chaosbag = getChaosBag()
+ local chaosbag = Global.call("findChaosBag")
if chaosbag == nil then return end
local tokens = sealedTokens[enemy.getGUID()]
if tokens == nil or #tokens == 0 then return end
@@ -438,7 +418,7 @@ function releaseToken(type, playerColor, enemy)
if v == guid then
table.remove(tokensTaken[type], j)
table.remove(tokens, i)
- printToColor("Releasing " .. type .. " token" .. getTokenCount(type), playerColor)
+ printToColor("Releasing " .. type .. " token" .. formatTokenCount(type), playerColor)
return
end
end
diff --git a/src/chaosbag/BlessCurseManagerApi.ttslua b/src/chaosbag/BlessCurseManagerApi.ttslua
new file mode 100644
index 00000000..0e535b6d
--- /dev/null
+++ b/src/chaosbag/BlessCurseManagerApi.ttslua
@@ -0,0 +1,24 @@
+do
+ local BlessCurseManagerApi = {}
+ local MANAGER_GUID = "5933fb"
+
+ -- removes all taken tokens and resets the counts
+ BlessCurseManagerApi.removeTakenTokensAndReset = function()
+ local BlessCurseManager = getObjectFromGUID(MANAGER_GUID)
+ Wait.time(function() BlessCurseManager.call("removeType", "Bless") end, 0.05)
+ Wait.time(function() BlessCurseManager.call("removeType", "Curse") end, 0.10)
+ Wait.time(function() BlessCurseManager.call("doReset", "White") end, 0.15)
+ end
+
+ -- updates the internal count (called by cards that seal bless/curse tokens)
+ BlessCurseManagerApi.sealedToken = function(type, guid)
+ getObjectFromGUID(MANAGER_GUID).call("sealedToken", { type = type, guid = guid })
+ end
+
+ -- updates the internal count (called by cards that seal bless/curse tokens)
+ BlessCurseManagerApi.releasedToken = function(type, guid)
+ getObjectFromGUID(MANAGER_GUID).call("releasedToken", { type = type, guid = guid })
+ end
+
+ return BlessCurseManagerApi
+end
diff --git a/src/chaosbag/ChaosBag.ttslua b/src/chaosbag/ChaosBag.ttslua
deleted file mode 100644
index a9b40351..00000000
--- a/src/chaosbag/ChaosBag.ttslua
+++ /dev/null
@@ -1,9 +0,0 @@
--- automatically add correct names to tokens that enter the chaos bag
-function filterObjectEnter(obj)
- local props = obj.getCustomObject()
- if props ~= nil and props.image ~= nil then
- obj.setName(Global.call("getTokenName", { url = props.image }))
- end
- return true
-end
-
diff --git a/src/core/Global.ttslua b/src/core/Global.ttslua
index 57792a9c..24c41cf2 100644
--- a/src/core/Global.ttslua
+++ b/src/core/Global.ttslua
@@ -34,6 +34,9 @@ local hideTitleSplashWaitFunctionId = nil
local playmatApi = require("playermat/PlaymatApi")
local tokenManager = require("core/token/TokenManager")
local playAreaAPI = require("core/PlayAreaApi")
+local mythosAreaApi = require("core/MythosAreaApi")
+local tokenArrangerApi = require("accessories/TokenArrangerApi")
+local blessCurseManagerApi = require("chaosbag/BlessCurseManagerApi")
---------------------------------------------------------
-- data for tokens
@@ -47,87 +50,46 @@ TOKEN_DATA = {
clue = {image = "http://cloud-3.steamusercontent.com/ugc/1758068501357164917/1D06F1DC4D6888B6F57124BD2AFE20D0B0DA15A8/", scale = {0.15, 0.15, 0.15}}
}
-IMAGE_TOKEN_MAP = {
- ["https://i.imgur.com/nEmqjmj.png"] = "Elder Sign",
- ["https://i.imgur.com/uIx8jbY.png"] = "+1",
- ["https://i.imgur.com/btEtVfd.png"] = "0",
- ["https://i.imgur.com/w3XbrCC.png"] = "-1",
- ["https://i.imgur.com/bfTg2hb.png"] = "-2",
- ["https://i.imgur.com/yfs8gHq.png"] = "-3",
- ["https://i.imgur.com/qrgGQRD.png"] = "-4",
- ["https://i.imgur.com/3Ym1IeG.png"] = "-5",
- ["https://i.imgur.com/c9qdSzS.png"] = "-6",
- ["https://i.imgur.com/4WRD42n.png"] = "-7",
- ["https://i.imgur.com/9t3rPTQ.png"] = "-8",
- ["https://i.imgur.com/stbBxtx.png"] = "Skull",
- ["https://i.imgur.com/VzhJJaH.png"] = "Cultist",
- ["https://i.imgur.com/1plY463.png"] = "Tablet",
- ["https://i.imgur.com/ttnspKt.png"] = "Elder Thing",
- ["https://i.imgur.com/lns4fhz.png"] = "Auto-fail",
- ["http://cloud-3.steamusercontent.com/ugc/1655601092778627699/339FB716CB25CA6025C338F13AFDFD9AC6FA8356/"] = "Bless",
- ["http://cloud-3.steamusercontent.com/ugc/1655601092778636039/2A25BD38E8C44701D80DD96BF0121DA21843672E/"] = "Curse",
- ["http://cloud-3.steamusercontent.com/ugc/1858293462583104677/195F93C063A8881B805CE2FD4767A9718B27B6AE/"] = "Frost"
+ID_URL_MAP = {
+ ['blue'] = {name = "Elder Sign", url = 'https://i.imgur.com/nEmqjmj.png'},
+ ['p1'] = {name = "+1", url = 'https://i.imgur.com/uIx8jbY.png'},
+ ['0'] = {name = "0", url = 'https://i.imgur.com/btEtVfd.png'},
+ ['m1'] = {name = "-1", url = 'https://i.imgur.com/w3XbrCC.png'},
+ ['m2'] = {name = "-2", url = 'https://i.imgur.com/bfTg2hb.png'},
+ ['m3'] = {name = "-3", url = 'https://i.imgur.com/yfs8gHq.png'},
+ ['m4'] = {name = "-4", url = 'https://i.imgur.com/qrgGQRD.png'},
+ ['m5'] = {name = "-5", url = 'https://i.imgur.com/3Ym1IeG.png'},
+ ['m6'] = {name = "-6", url = 'https://i.imgur.com/c9qdSzS.png'},
+ ['m7'] = {name = "-7", url = 'https://i.imgur.com/4WRD42n.png'},
+ ['m8'] = {name = "-8", url = 'https://i.imgur.com/9t3rPTQ.png'},
+ ['skull'] = {name = "Skull", url = 'https://i.imgur.com/stbBxtx.png'},
+ ['cultist'] = {name = "Cultist", url = 'https://i.imgur.com/VzhJJaH.png'},
+ ['tablet'] = {name = "Tablet", url = 'https://i.imgur.com/1plY463.png'},
+ ['elder'] = {name = "Elder Thing", url = 'https://i.imgur.com/ttnspKt.png'},
+ ['red'] = {name = "Auto-fail", url = 'https://i.imgur.com/lns4fhz.png'},
+ ['bless'] = {name = "Bless", url = 'http://cloud-3.steamusercontent.com/ugc/1655601092778627699/339FB716CB25CA6025C338F13AFDFD9AC6FA8356/'},
+ ['curse'] = {name = "Curse", url = 'http://cloud-3.steamusercontent.com/ugc/1655601092778636039/2A25BD38E8C44701D80DD96BF0121DA21843672E/'},
+ ['frost'] = {name = "Frost", url = 'http://cloud-3.steamusercontent.com/ugc/1858293462583104677/195F93C063A8881B805CE2FD4767A9718B27B6AE/'}
}
---------------------------------------------------------
-- data for chaos token stat tracker
---------------------------------------------------------
-local maxSquid = 0
-
-MAT_GUID_TO_COLOUR = {
- ["8b081b"] = "White",
- ["bd0ff4"] = "Orange",
- ["383d8b"] = "Green",
- ["0840d5"] = "Red"
+local MAT_GUID_TO_COLOR = {
+ ["Overall"] = "Overall",
+ ["8b081b"] = "White",
+ ["bd0ff4"] = "Orange",
+ ["383d8b"] = "Green",
+ ["0840d5"] = "Red"
}
-local personalStats = {
- ["8b081b"] = {},
- ["bd0ff4"] = {},
- ["383d8b"] = {},
- ["0840d5"] = {}
-}
-
-local overallStats = {
- -- cultist
- ["https://i.imgur.com/VzhJJaH.png"] = 0,
- -- skull
- ["https://i.imgur.com/stbBxtx.png"] = 0,
- -- tablet
- ["https://i.imgur.com/1plY463.png"] = 0,
- -- curse
- ["http://cloud-3.steamusercontent.com/ugc/1655601092778636039/2A25BD38E8C44701D80DD96BF0121DA21843672E/"] = 0,
- -- tentacle
- ["https://i.imgur.com/lns4fhz.png"] = 0,
- -- minus eight
- ["https://i.imgur.com/9t3rPTQ.png"] = 0,
- -- minus seven
- ["https://i.imgur.com/4WRD42n.png"] = 0,
- -- minus six
- ["https://i.imgur.com/c9qdSzS.png"] = 0,
- -- minus five
- ["https://i.imgur.com/3Ym1IeG.png"] = 0,
- -- minus four
- ["https://i.imgur.com/qrgGQRD.png"] = 0,
- -- minus three
- ["https://i.imgur.com/yfs8gHq.png"] = 0,
- -- minus two
- ["https://i.imgur.com/bfTg2hb.png"] = 0,
- -- minus one
- ["https://i.imgur.com/w3XbrCC.png"] = 0,
- -- zero
- ["https://i.imgur.com/btEtVfd.png"] = 0,
- -- plus one
- ["https://i.imgur.com/uIx8jbY.png"] = 0,
- -- elder thing
- ["https://i.imgur.com/ttnspKt.png"] = 0,
- -- bless
- ["http://cloud-3.steamusercontent.com/ugc/1655601092778627699/339FB716CB25CA6025C338F13AFDFD9AC6FA8356/"] = 0,
- -- elder sign
- ["https://i.imgur.com/nEmqjmj.png"] = 0,
- -- frost
- ["http://cloud-3.steamusercontent.com/ugc/1858293462583104677/195F93C063A8881B805CE2FD4767A9718B27B6AE/"] = 0,
+local tokenDrawingStats = {
+ ["Overall"] = {},
+ ["8b081b"] = {},
+ ["bd0ff4"] = {},
+ ["383d8b"] = {},
+ ["0840d5"] = {}
}
---------------------------------------------------------
@@ -270,13 +232,24 @@ end
-- chaos token drawing
---------------------------------------------------------
--- checks scripting zone for chaos bag
+-- checks scripting zone for chaos bag (also called by a lot of objects!)
function findChaosBag()
- for _, item in ipairs(getObjectFromGUID("83ef06").getObjects()) do
+ local chaosbag_zone = getObjectFromGUID("83ef06")
+
+ -- error handling: scripting zone not found
+ if chaosbag_zone == nil then
+ printToAll("Zone for chaos bag detection couldn't be found.", "Red")
+ return
+ end
+
+ for _, item in ipairs(chaosbag_zone.getObjects()) do
if item.getDescription() == "Chaos Bag" then
return item
end
end
+
+ -- error handling: chaos bag not found
+ printToAll("Chaos bag couldn't be found.", "Red")
end
function returnChaosTokens()
@@ -290,22 +263,20 @@ end
-- 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.
+---@return Boolean. True if the bag is manipulated, false if it should be blocked.
function canTouchChaosTokens()
for color, searching in pairs(bagSearchers) do
if searching then
- broadcastToAll("Someone is searching the chaos bag, can't touch the tokens", "Red")
+ broadcastToAll("Someone is searching the chaos bag, can't touch the tokens.", "Red")
return false
end
end
-
return true
end
-function drawChaostoken(params)
- if not canTouchChaosTokens() then
- return
- end
+-- called by playermats (by the "Draw chaos token" button)
+function drawChaosToken(params)
+ if not canTouchChaosTokens() then return end
local mat = params[1]
local tokenOffset = params[2]
@@ -320,6 +291,7 @@ function drawChaostoken(params)
end
chaosTokensLastMat = mat
+
-- if we have left clicked and have no tokens OR if we have right clicked
if isRightClick or #chaosTokens == 0 then
if #chaosbag.getObjects() == 0 then return end
@@ -328,11 +300,18 @@ function drawChaostoken(params)
-- add the token to the list, compute new position based on list length
tokenOffset[1] = tokenOffset[1] + (0.17 * #chaosTokens)
local token = chaosbag.takeObject({
- index = 0,
position = mat.positionToWorld(tokenOffset),
- rotation = mat.getRotation(),
- callback_function = function(obj) trackChaosToken(obj, mat.getGUID()) end
+ rotation = mat.getRotation()
})
+
+ -- get data for token description
+ local name = token.getName()
+ local tokenData = mythosAreaApi.returnTokenData().tokenData or {}
+ local specificData = tokenData[name] or {}
+ token.setDescription(specificData.description or "")
+
+ -- track the chaos token (for stat tracker and future returning)
+ trackChaosToken(name, mat.getGUID())
chaosTokens[#chaosTokens + 1] = token
return
else
@@ -355,64 +334,50 @@ end
-- chaos token stat tracker
---------------------------------------------------------
-function trackChaosToken(token, matGUID)
- local image = token.getCustomObject().image
- overallStats[image] = (overallStats[image] or 0) + 1
- personalStats[matGUID][image] = (personalStats[matGUID][image] or 0) + 1
+function trackChaosToken(tokenName, matGUID)
+ tokenDrawingStats["Overall"][tokenName] = (tokenDrawingStats["Overall"][tokenName] or 0) + 1
+ tokenDrawingStats[matGUID][tokenName] = (tokenDrawingStats[matGUID][tokenName] or 0) + 1
end
+-- Left-click: print stats, Right-click: reset stats
function handleStatTrackerClick(_, _, isRightClick)
if isRightClick then
- resetChaosTokenStats()
+ for key, _ in pairs(tokenDrawingStats) do
+ tokenDrawingStats[key] = {}
+ end
else
- printChaosTokenStats()
- end
-end
+ local squidKing = "Nobody"
+ local maxSquid = 0
+ local playerColor, playerName
+
+ for key, personalStats in pairs(tokenDrawingStats) do
+ if personalStats ~= {} then
+ if key == "Overall" then
+ playerColor = "White"
+ playerName = "Overall"
+ else
+ playerColor = playmatApi.getPlayerColor(MAT_GUID_TO_COLOR[key])
+ playerName = Player[playerColor].steam_name or playerColor
-function resetChaosTokenStats()
- for key, _ in pairs(overallStats) do
- overallStats[key] = 0
- end
- for playerKey, _ in pairs(personalStats) do
- for key, value in pairs(overallStats) do
- personalStats[playerKey][key] = value
- end
- end
-end
-
-function printChaosTokenStats()
- local squidKing = "Nobody"
- printToAll("")
- printToAll("Overall Stats")
- printToAll("------------------------------")
- printNonZeroTokenPairs(overallStats)
- printToAll("")
- printToAll("Individual Stats")
- printToAll("------------------------------")
- for matGUID, _ in pairs(personalStats) do
- local playerColour = MAT_GUID_TO_COLOUR[matGUID]
- local playerSquidCount = personalStats[matGUID]["https://i.imgur.com/lns4fhz.png"] or 0
- local playerName = playerColour
- if Player[playerColour].seated then
- playerName = Player[playerColour].steam_name
- end
-
- printToAll(playerName .. " Stats", playerColour)
- printNonZeroTokenPairs(personalStats[matGUID])
-
- if playerSquidCount > maxSquid then
- squidKing = playerName
- maxSquid = playerSquidCount
- end
- end
- printToAll(squidKing .. " is an auto-fail magnet.", {255, 0, 0})
-end
-
-function printNonZeroTokenPairs(theTable)
- for key, value in pairs(theTable) do
- if value ~= 0 then
- printToAll(IMAGE_TOKEN_MAP[key] .. ': ' .. tostring(value))
+ local playerSquidCount = personalStats["Auto-fail"] or 0
+ if playerSquidCount > maxSquid then
+ squidKing = playerName
+ maxSquid = playerSquidCount
+ end
+ end
+
+ printToAll("------------------------------")
+ printToAll(playerName .. " Stats", playerColor)
+
+ for tokenName, value in pairs(personalStats) do
+ if value then
+ printToAll(tokenName .. ': ' .. tostring(value))
+ end
+ end
+ end
end
+ printToAll("------------------------------")
+ printToAll(squidKing .. " is an auto-fail magnet.", {255, 0, 0})
end
end
@@ -473,63 +438,44 @@ end
-- called for adding chaos tokens
---@param object object Usually "self"
---@param key string Name of the scenario
----@param mode string diffculty (e.g. "hard" or "expert")
+---@param mode string difficulty (e.g. "hard" or "expert")
function fillContainer(args)
- chaosbag = findChaosBag()
+ local data = getDataValue('modeData', args.key)
+ if data == nil then return end
- if chaosbag ~= nil then
- local data = getDataValue('modeData', args.key)
- if data == nil then return end
+ local value = data[args.mode]
+ if value == nil or value.token == nil then return end
- local value = data[args.mode]
- if value == nil or value.token == nil then return end
+ local tokenList = {}
- local pos = chaosbag.getPosition()
- if args.object ~= nil then
- pos = args.object.getPosition()
+ for _, tokenId in ipairs(value.token) do
+ table.insert(tokenList, tokenId)
+ end
+
+ if value.append ~= nil then
+ for _, tokenId in ipairs(value.append) do
+ table.insert(tokenList, tokenId)
end
+ end
- -- empty the chaos bag
- for _, item in ipairs(chaosbag.getObjects()) do
- destroyObject(chaosbag.takeObject({}))
- end
-
- for _, token in ipairs(value.token) do
- local obj = spawnChaosToken(token, pos)
- if obj ~= nil then
- chaosbag.putObject(obj)
+ -- randomly choose tokens for specific Carcosa scenarios in standalone
+ if value.random then
+ local n = #value.random
+ if n > 0 then
+ for _, tokenId in ipairs(value.random[math.random(1, n)]) do
+ table.insert(tokenList, tokenId)
end
end
+ end
- if value.append ~= nil then
- for _, token in ipairs(value.append) do
- local obj = spawnChaosToken(token, pos)
- if obj ~= nil then
- chaosbag.putObject(obj)
- end
- end
- end
+ setChaosBagState(tokenList)
- -- randomly choose tokens for specific Carcosa scenarios in standalone
- if value.random then
- local n = #value.random
- if n > 0 then
- for _, token in ipairs(value.random[math.random(1, n)]) do
- local obj = spawnChaosToken(token, pos)
- if obj ~= nil then
- chaosbag.putObject(obj)
- end
- end
- end
- end
+ if value.message then
+ broadcastToAll(value.message)
+ end
- if value.message then
- broadcastToAll(value.message)
- end
-
- if value.warning then
- broadcastToAll(value.warning, { 1, 0.5, 0.5 })
- end
+ if value.warning then
+ broadcastToAll(value.warning, { 1, 0.5, 0.5 })
end
end
@@ -554,52 +500,112 @@ function getDataValue(storage, key)
end
end
-function spawnChaosToken(id, pos)
- local url = getChaosTokenImageURL(id)
- if url ~= '' then
- local obj = spawnObject({
+-- respawns the chaos bag with a new state of tokens
+---@param tokenList Table List of chaos token ids
+function setChaosBagState(tokenList)
+ if not canTouchChaosTokens() then return end
+
+ local chaosbag = findChaosBag()
+ local chaosbagData = chaosbag.getData()
+ local reserveData = getObjectFromGUID("106418").getData()
+ local tokenCache = {}
+ local containedObjects = {}
+
+ -- create a temporary copy of the data for each chaos token
+ for _, objData in ipairs(reserveData.ContainedObjects) do
+ tokenCache[objData.Nickname] = objData
+ end
+
+ -- iterate over tokenlist and insert specified tokens into new table
+ for _, tokenId in ipairs(tokenList) do
+ local tokenName = ID_URL_MAP[tokenId].name
+ table.insert(containedObjects, tokenCache[tokenName])
+ end
+
+ -- overwrite chaos bag content and respawn it
+ chaosbagData.ContainedObjects = containedObjects
+ chaosbag.destruct()
+ spawnObjectData({data = chaosbagData})
+
+ -- remove tokens that are still in play
+ for _, token in pairs(chaosTokens) do
+ if token ~= nil then token.destruct() end
+ end
+ chaosTokens = {}
+ chaosTokensLastMat = nil
+
+ -- reset bless / curse manager
+ blessCurseManagerApi.removeTakenTokensAndReset()
+
+ printToAll("Chaos bag set to chosen difficulty.", "Green")
+end
+
+-- spawns the specified chaos token and puts it into the chaos bag
+---@param id String ID of the chaos token
+function spawnChaosToken(id)
+ if not canTouchChaosTokens() then return end
+
+ id = id:lower()
+ local chaosbag = findChaosBag()
+ local url = ID_URL_MAP[id].url or ""
+
+ if url ~= "" then
+ return spawnObject({
type = 'Custom_Tile',
- position = {pos.x, pos.y + 3, pos.z},
- rotation = {0, 260, 0}
- })
- obj.setCustomObject({
+ position = { 0.49, 3, 0 },
+ scale = { 0.81, 1.0, 0.81 },
+ rotation = {0, 270, 0},
+ callback_function = function(obj)
+ obj.setName(ID_URL_MAP[id].name)
+ chaosbag.putObject(obj)
+ tokenArrangerApi.layout()
+ end
+ }).setCustomObject({
type = 2,
image = url,
thickness = 0.1
})
- obj.scale {0.81, 1, 0.81}
- obj.setName(getTokenName({ url=url }))
- return obj
end
end
--- chaos bag needs this for renaming chaos tokens
-function getTokenName(params)
- local name = IMAGE_TOKEN_MAP[params.url]
- if name == nil then name = "" end
- return name
+-- removes the specified chaos token from the chaos bag
+---@param id String ID of the chaos token
+function removeChaosToken(id)
+ if not canTouchChaosTokens() then return end
+
+ local tokens = {}
+ local chaosbag = findChaosBag()
+ local name = ID_URL_MAP[id].name
+
+ for _, v in ipairs(chaosbag.getObjects()) do
+ if v.name == name then table.insert(tokens, v.guid) end
+ end
+
+ -- error handling: no matching token found
+ if #tokens == 0 then
+ printToAll("No " .. name .. " tokens in the chaos bag.", "Yellow")
+ return
+ end
+
+ chaosbag.takeObject({
+ guid = tokens[1],
+ smooth = false,
+ callback_function = function(obj)
+ obj.destruct()
+ tokenArrangerApi.layout()
+ end
+ })
+ printToAll("Removing " .. name .. " token (in bag: " .. #tokens - 1 .. ")", "White")
end
--- returns the image url for a chaos token (identified by the "id")
-function getChaosTokenImageURL(id)
- if id == 'p1' then return 'https://i.imgur.com/uIx8jbY.png' end
- if id == '0' then return 'https://i.imgur.com/btEtVfd.png' end
- if id == 'm1' then return 'https://i.imgur.com/w3XbrCC.png' end
- if id == 'm2' then return 'https://i.imgur.com/bfTg2hb.png' end
- if id == 'm3' then return 'https://i.imgur.com/yfs8gHq.png' end
- if id == 'm4' then return 'https://i.imgur.com/qrgGQRD.png' end
- if id == 'm5' then return 'https://i.imgur.com/3Ym1IeG.png' end
- if id == 'm6' then return 'https://i.imgur.com/c9qdSzS.png' end
- if id == 'm7' then return 'https://i.imgur.com/4WRD42n.png' end
- if id == 'm8' then return 'https://i.imgur.com/9t3rPTQ.png' end
- if id == 'skull' then return 'https://i.imgur.com/stbBxtx.png' end
- if id == 'cultist' then return 'https://i.imgur.com/VzhJJaH.png' end
- if id == 'tablet' then return 'https://i.imgur.com/1plY463.png' end
- if id == 'elder' then return 'https://i.imgur.com/ttnspKt.png' end
- if id == 'red' then return 'https://i.imgur.com/lns4fhz.png' end
- if id == 'blue' then return 'https://i.imgur.com/nEmqjmj.png' end
- if id == 'frost' then return 'http://cloud-3.steamusercontent.com/ugc/1858293462583104677/195F93C063A8881B805CE2FD4767A9718B27B6AE/' end
- return ''
+-- empty the chaos bag
+function emptyChaosBag()
+ if not canTouchChaosTokens() then return end
+
+ local chaosbag = findChaosBag()
+ for _, object in ipairs(chaosbag.getObjects()) do
+ chaosbag.takeObject({callback_function = function(item) item.destruct() end})
+ end
end
---------------------------------------------------------
diff --git a/src/core/MythosArea.ttslua b/src/core/MythosArea.ttslua
index 81bbd4f3..a28c42c8 100644
--- a/src/core/MythosArea.ttslua
+++ b/src/core/MythosArea.ttslua
@@ -62,7 +62,10 @@ function onCollisionEnter(collisionInfo)
-- trigger update if a change was detected and push new data
if updateNeeded then
local metadata = JSON.decode(object.getGMNotes()) or {}
- if not metadata["tokens"] then return end
+ if not metadata["tokens"] then
+ tokenData = {}
+ return
+ end
tokenData = metadata["tokens"][(useFrontData and "front" or "back")]
fireTokenDataChangedEvent()
end
diff --git a/src/playercards/CardsThatSealTokens.ttslua b/src/playercards/CardsThatSealTokens.ttslua
new file mode 100644
index 00000000..aab8aebb
--- /dev/null
+++ b/src/playercards/CardsThatSealTokens.ttslua
@@ -0,0 +1,219 @@
+--[[ Library for cards that seal tokens
+This file is used to add sealing option to cards' context menu.
+Valid options (set before requiring this file):
+
+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
+ - example usage: "Unrelenting" (to only display valid tokens)
+
+SHOW_SINGLE_RELEASE --@type: boolean
+ - 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 enty allows releasing of multiple tokens at once
+ - example usage: "Nephthys" (to release 3 bless tokens at once)
+
+SHOW_MULTI_SEAL --@type: number (amount of tokens to seal at once)
+ - enables an entry in the context menu
+ - this entry allows sealing of multiple tokens at once
+ - example usage: "Holy Spear" (to seal two bless tokens at once)
+
+VALID_TOKENS --@type: table ([tokenName] = true)
+ - this table defines which tokens should be abled to be sealed
+ - needs to be defined for each card -> even if empty
+ - example usage: "The Chthonian Stone"
+ > VALID_TOKENS = {
+ > ["Skull"] = true,
+ > ["Cultist"] = true,
+ > ["Tablet"] = true,
+ > ["Elder Thing"] = true,
+ > }
+
+INVALID_TOKENS --@type: table ([tokenName] = true)
+ - this table defines which tokens are invalid for sealing
+ - only needs to be defined if needed
+ - usually combined with empty "VALID_TOKENS" table
+ - example usage: "Protective Incantation" (not allowed to seal Auto-fail)
+
+----------------------------------------------------------
+Example 1: Crystalline Elder Sign
+This card can only seal the "+1" or "Elder Sign" token,
+it does not need specific options for multi-sealing or releasing.
+Thus it should be implemented like this:
+
+> VALID_TOKENS = {
+> ["+1"] = true,
+> ["Elder Sign"] = true
+> }
+> require ("playercards/CardsThatSealTokens") -- includes a space after "require" to not executing bundling
+----------------------------------------------------------
+Example 2: Holy Spear
+This card features the following abilities (just listing the relevant parts):
+- releasing a single bless token
+- sealing two bless tokens
+Thus it should be implemented like this:
+
+> VALID_TOKENS = {
+> ["Bless"] = true
+> }
+> SHOW_SINGLE_RELEASE = true
+> SHOW_MULTI_SEAL = 2
+> require ("playercards/CardsThatSealTokens") -- includes a space after "require" to not executing bundling
+----------------------------------------------------------]]
+
+local blessCurseManagerApi = require("chaosbag/BlessCurseManagerApi")
+local tokenArrangerApi = require("accessories/TokenArrangerApi")
+local sealedTokens = {}
+local ID_URL_MAP = {}
+local tokensInBag = {}
+
+function onSave() return JSON.encode(sealedTokens) end
+
+function onLoad(savedData)
+ sealedTokens = JSON.decode(savedData) or {}
+ ID_URL_MAP = Global.getTable("ID_URL_MAP")
+ generateContextMenu()
+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 " .. SHOW_MULTI_RELEASE .. " token(s)", releaseMultipleTokens)
+ else
+ self.addContextMenuItem("Release token(s)", releaseAllTokens)
+ end
+
+ -- main context menu options to seal tokens
+ for _, map in pairs(ID_URL_MAP) do
+ if (VALID_TOKENS[map.name] ~= nil) or (UPDATE_ON_HOVER and tokensInBag[map.name] and not INVALID_TOKENS[map.name]) then
+ if not SHOW_MULTI_SEAL then
+ self.addContextMenuItem("Seal " .. map.name, function(playerColor)
+ sealToken(map.name, playerColor)
+ end)
+ else
+ self.addContextMenuItem("Seal " .. SHOW_MULTI_SEAL .. " " .. map.name, function(playerColor)
+ readBag()
+ local allowed = true
+ local notFound
+
+ for name, _ in pairs(VALID_TOKENS) do
+ if (tokensInBag[name] or 0) < SHOW_MULTI_SEAL then
+ allowed = false
+ notFound = name
+ end
+ end
+
+ if allowed then
+ for i = 1, SHOW_MULTI_SEAL do
+ sealToken(map.name, playerColor)
+ end
+ else
+ printToColor("Not enough " .. notFound .. " tokens in the chaos bag.", playerColor)
+ end
+ end)
+ end
+ end
+ end
+end
+
+-- generates a list of chaos tokens that is in the chaos bag
+function readBag()
+ local chaosbag = Global.call("findChaosBag")
+ tokensInBag = {}
+
+ for _, token in ipairs(chaosbag.getObjects()) do
+ tokensInBag[token.name] = (tokensInBag[token.name] or 0) + 1
+ end
+end
+
+-- native event from TTS - used to update the context menu for cards like "Unrelenting"
+function onHover()
+ if UPDATE_ON_HOVER then
+ readBag()
+ self.clearContextMenu()
+ generateContextMenu()
+ end
+end
+
+-- seals the named token on this card
+function sealToken(name, playerColor)
+ if not Global.call("canTouchChaosTokens") then return end
+ local chaosbag = Global.call("findChaosBag")
+ for i, obj in ipairs(chaosbag.getObjects()) do
+ if obj.name == name then
+ chaosbag.takeObject({
+ position = self.getPosition() + Vector(0, 0.5 + 0.1 * #sealedTokens, 0),
+ rotation = self.getRotation(),
+ index = i - 1,
+ smooth = false,
+ callback_function = function(token)
+ local guid = token.getGUID()
+ table.insert(sealedTokens, guid)
+ tokenArrangerApi.layout()
+ if name == "Bless" or name == "Curse" then
+ blessCurseManagerApi.sealedToken(name, guid)
+ end
+ end
+ })
+ return
+ end
+ end
+ printToColor(name .. " token not found in chaos bag", playerColor)
+end
+
+-- release the last sealed token
+function releaseOneToken(playerColor)
+ if not Global.call("canTouchChaosTokens") then return end
+ if #sealedTokens == 0 then
+ printToColor("No sealed token(s) found", playerColor)
+ else
+ printToColor("Releasing token", playerColor)
+ putTokenAway(table.remove(sealedTokens))
+ end
+end
+
+-- release multiple tokens at once
+function releaseMultipleTokens(playerColor)
+ if SHOW_MULTI_RELEASE >= #sealedTokens then
+ for i = 1, SHOW_MULTI_RELEASE do
+ releaseOneToken(playerColor)
+ end
+ else
+ printToColor("Not enough " .. name .. " tokens sealed.", playerColor)
+ end
+end
+
+-- releases all sealed tokens
+function releaseAllTokens(playerColor)
+ if not Global.call("canTouchChaosTokens") then return end
+ if #sealedTokens == 0 then
+ printToColor("No sealed token(s) found", playerColor)
+ else
+ printToColor("Releasing token(s)", playerColor)
+ for _, guid in ipairs(sealedTokens) do
+ putTokenAway(guid)
+ end
+ sealedTokens = {}
+ end
+end
+
+-- returns the token (referenced by GUID) to the chaos bag
+function putTokenAway(guid)
+ local token = getObjectFromGUID(guid)
+ if not token then return end
+
+ local name = token.getName()
+ local chaosbag = Global.call("findChaosBag")
+ chaosbag.putObject(token)
+ tokenArrangerApi.layout()
+ if name == "Bless" or name == "Curse" then
+ blessCurseManagerApi.releasedToken(name, guid)
+ end
+end
diff --git a/src/playercards/cards/CrystallineElderSign3.ttslua b/src/playercards/cards/CrystallineElderSign3.ttslua
index ee47beff..f0652701 100644
--- a/src/playercards/cards/CrystallineElderSign3.ttslua
+++ b/src/playercards/cards/CrystallineElderSign3.ttslua
@@ -1,65 +1,6 @@
VALID_TOKENS = {
- ["+1"]=true,
- ["Elder Sign"]=true
+ ["+1"] = true,
+ ["Elder Sign"] = true
}
-function onload()
- chaosbag = getChaosBag()
- sealedTokens = { }
- IMAGE_TOKEN_MAP = { }
- for i,v in pairs(Global.getVar("IMAGE_TOKEN_MAP")) do
- IMAGE_TOKEN_MAP[i] = v
- end
-
- -- add menu items
- self.clearContextMenu()
- self.addContextMenuItem("Release Token", releaseTokens)
- for url,name in pairs(IMAGE_TOKEN_MAP) do
- if VALID_TOKENS[name] ~= nil then
- self.addContextMenuItem("Seal " .. name, function(playerColor) sealToken(url, playerColor) end)
- end
- end
-end
-
-function sealToken(url, playerColor)
- local pos = self.getPosition()
-
- local name = IMAGE_TOKEN_MAP[url]
- for i,obj in ipairs(chaosbag.getObjects()) do
- if obj.name == name then
- chaosbag.takeObject({
- position={ pos.x, pos.y + 1, pos.z },
- index=i-1,
- smooth=false,
- callback_function=_sealToken
- })
- return
- end
- end
- printToColor(name .. " token not found in bag", playerColor)
-end
-
-function _sealToken(obj)
- table.insert(sealedTokens, obj)
-end
-
-function releaseTokens(playerColor)
- printToColor("Releasing token", playerColor)
- for i,obj in ipairs(sealedTokens) do
- chaosbag.putObject(obj)
- end
- sealedTokens = { }
-end
-
-function getChaosBag()
- local items = getObjectFromGUID("83ef06").getObjects()
- local chaosbag = nil
- for i,v in ipairs(items) do
- if v.getDescription() == "Chaos Bag" then
- chaosbag = getObjectFromGUID(v.getGUID())
- break
- end
- end
- if chaosbag == nil then printToAll("No chaos bag found") end
- return chaosbag
-end
+require("playercards/CardsThatSealTokens")
diff --git a/src/playercards/cards/DarkRitual.ttslua b/src/playercards/cards/DarkRitual.ttslua
index 000cd744..540513c1 100644
--- a/src/playercards/cards/DarkRitual.ttslua
+++ b/src/playercards/cards/DarkRitual.ttslua
@@ -1,81 +1,5 @@
-function onload()
- mode = "Curse"
- chaosbag = getChaosBag()
- manager = getObjectFromGUID("5933fb")
- sealedTokens = { }
- IMAGE_TOKEN_MAP = { }
- for i,v in pairs(Global.getVar("IMAGE_TOKEN_MAP")) do
- IMAGE_TOKEN_MAP[i] = v
- end
+VALID_TOKENS = {
+ ["Curse"] = true
+}
- -- add menu items
- self.clearContextMenu()
- self.addContextMenuItem("Release Token", releaseTokens, true)
- for url,name in pairs(IMAGE_TOKEN_MAP) do
- if name == mode then
- self.addContextMenuItem("Seal " .. mode, function(playerColor) sealToken(url, playerColor) end, true)
- end
- end
-end
-
-function sealToken(url, playerColor)
- local pos = self.getPosition()
-
- local name = IMAGE_TOKEN_MAP[url]
- for i,obj in ipairs(chaosbag.getObjects()) do
- if obj.name == name then
- chaosbag.takeObject({
- position={ pos.x, pos.y + 1, pos.z },
- index=i-1,
- smooth=false,
- callback_function=_sealToken
- })
- return
- end
- end
- printToColor(name .. " token not found in bag", playerColor)
-end
-
-function _sealToken(obj)
- table.insert(sealedTokens, obj)
- local guid = obj.getGUID()
- local tokensTaken = manager.getVar("tokensTaken")
- table.insert(tokensTaken[mode], guid)
- manager.setVar("tokensTaken", tokensTaken)
- manager.setVar("mode", mode)
- printToAll("Sealing " .. mode .. " token " .. manager.call("getTokenCount"))
-end
-
-function releaseTokens(playerColor)
- if #sealedTokens == 0 then return end
- local token = sealedTokens[#sealedTokens]
- if token ~= nil then
- local guid = token.getGUID()
- chaosbag.putObject(token)
- local tokensTaken = manager.getVar("tokensTaken")
- for i,v in ipairs(tokensTaken[mode]) do
- if v == guid then
- table.remove(tokensTaken[mode], i)
- break
- end
- end
- manager.setVar("tokensTaken", tokensTaken)
- manager.setVar("mode", mode)
- printToAll("Releasing " .. mode .. " token" .. manager.call("getTokenCount"))
- end
-
- table.remove(sealedTokens)
-end
-
-function getChaosBag()
- local items = getObjectFromGUID("83ef06").getObjects()
- local chaosbag = nil
- for i,v in ipairs(items) do
- if v.getDescription() == "Chaos Bag" then
- chaosbag = getObjectFromGUID(v.getGUID())
- break
- end
- end
- if chaosbag == nil then printToAll("No chaos bag found") end
- return chaosbag
-end
+require("playercards/CardsThatSealTokens")
diff --git a/src/playercards/cards/DayofReckoning.ttslua b/src/playercards/cards/DayofReckoning.ttslua
index 447d6743..78e4493c 100644
--- a/src/playercards/cards/DayofReckoning.ttslua
+++ b/src/playercards/cards/DayofReckoning.ttslua
@@ -1,60 +1,5 @@
-function onload()
- chaosbag = getChaosBag()
- sealedTokens = { }
- IMAGE_TOKEN_MAP = { }
- for i,v in pairs(Global.getVar("IMAGE_TOKEN_MAP")) do
- IMAGE_TOKEN_MAP[i] = v
- end
+VALID_TOKENS = {
+ ["Elder Sign"] = true
+}
- -- add menu items
- self.clearContextMenu()
- self.addContextMenuItem("Release Token", releaseTokens)
- for url,name in pairs(IMAGE_TOKEN_MAP) do
- if name == "Elder Sign" then
- self.addContextMenuItem("Seal Elder Sign", function(playerColor) sealToken(url, playerColor) end)
- end
- end
-end
-
-function sealToken(url, playerColor)
- local pos = self.getPosition()
-
- local name = IMAGE_TOKEN_MAP[url]
- for i,obj in ipairs(chaosbag.getObjects()) do
- if obj.name == name then
- chaosbag.takeObject({
- position={ pos.x, pos.y + 1, pos.z },
- index=i-1,
- smooth=false,
- callback_function=_sealToken
- })
- return
- end
- end
- printToColor(name .. " token not found in bag", playerColor)
-end
-
-function _sealToken(obj)
- table.insert(sealedTokens, obj)
-end
-
-function releaseTokens(playerColor)
- printToColor("Releasing token", playerColor)
- for i,obj in ipairs(sealedTokens) do
- chaosbag.putObject(obj)
- end
- sealedTokens = { }
-end
-
-function getChaosBag()
- local items = getObjectFromGUID("83ef06").getObjects()
- local chaosbag = nil
- for i,v in ipairs(items) do
- if v.getDescription() == "Chaos Bag" then
- chaosbag = getObjectFromGUID(v.getGUID())
- break
- end
- end
- if chaosbag == nil then printToAll("No chaos bag found") end
- return chaosbag
-end
+require("playercards/CardsThatSealTokens")
diff --git a/src/playercards/cards/FavoroftheMoon1.ttslua b/src/playercards/cards/FavoroftheMoon1.ttslua
index 000cd744..a1a7782a 100644
--- a/src/playercards/cards/FavoroftheMoon1.ttslua
+++ b/src/playercards/cards/FavoroftheMoon1.ttslua
@@ -1,81 +1,7 @@
-function onload()
- mode = "Curse"
- chaosbag = getChaosBag()
- manager = getObjectFromGUID("5933fb")
- sealedTokens = { }
- IMAGE_TOKEN_MAP = { }
- for i,v in pairs(Global.getVar("IMAGE_TOKEN_MAP")) do
- IMAGE_TOKEN_MAP[i] = v
- end
+VALID_TOKENS = {
+ ["Curse"] = true
+}
- -- add menu items
- self.clearContextMenu()
- self.addContextMenuItem("Release Token", releaseTokens, true)
- for url,name in pairs(IMAGE_TOKEN_MAP) do
- if name == mode then
- self.addContextMenuItem("Seal " .. mode, function(playerColor) sealToken(url, playerColor) end, true)
- end
- end
-end
+SHOW_SINGLE_RELEASE = true
-function sealToken(url, playerColor)
- local pos = self.getPosition()
-
- local name = IMAGE_TOKEN_MAP[url]
- for i,obj in ipairs(chaosbag.getObjects()) do
- if obj.name == name then
- chaosbag.takeObject({
- position={ pos.x, pos.y + 1, pos.z },
- index=i-1,
- smooth=false,
- callback_function=_sealToken
- })
- return
- end
- end
- printToColor(name .. " token not found in bag", playerColor)
-end
-
-function _sealToken(obj)
- table.insert(sealedTokens, obj)
- local guid = obj.getGUID()
- local tokensTaken = manager.getVar("tokensTaken")
- table.insert(tokensTaken[mode], guid)
- manager.setVar("tokensTaken", tokensTaken)
- manager.setVar("mode", mode)
- printToAll("Sealing " .. mode .. " token " .. manager.call("getTokenCount"))
-end
-
-function releaseTokens(playerColor)
- if #sealedTokens == 0 then return end
- local token = sealedTokens[#sealedTokens]
- if token ~= nil then
- local guid = token.getGUID()
- chaosbag.putObject(token)
- local tokensTaken = manager.getVar("tokensTaken")
- for i,v in ipairs(tokensTaken[mode]) do
- if v == guid then
- table.remove(tokensTaken[mode], i)
- break
- end
- end
- manager.setVar("tokensTaken", tokensTaken)
- manager.setVar("mode", mode)
- printToAll("Releasing " .. mode .. " token" .. manager.call("getTokenCount"))
- end
-
- table.remove(sealedTokens)
-end
-
-function getChaosBag()
- local items = getObjectFromGUID("83ef06").getObjects()
- local chaosbag = nil
- for i,v in ipairs(items) do
- if v.getDescription() == "Chaos Bag" then
- chaosbag = getObjectFromGUID(v.getGUID())
- break
- end
- end
- if chaosbag == nil then printToAll("No chaos bag found") end
- return chaosbag
-end
+require("playercards/CardsThatSealTokens")
diff --git a/src/playercards/cards/FavoroftheSun1.ttslua b/src/playercards/cards/FavoroftheSun1.ttslua
index ab3fe3f1..fe5a27fc 100644
--- a/src/playercards/cards/FavoroftheSun1.ttslua
+++ b/src/playercards/cards/FavoroftheSun1.ttslua
@@ -1,81 +1,7 @@
-function onload()
- mode = "Bless"
- chaosbag = getChaosBag()
- manager = getObjectFromGUID("5933fb")
- sealedTokens = { }
- IMAGE_TOKEN_MAP = { }
- for i,v in pairs(Global.getVar("IMAGE_TOKEN_MAP")) do
- IMAGE_TOKEN_MAP[i] = v
- end
+VALID_TOKENS = {
+ ["Bless"] = true
+}
- -- add menu items
- self.clearContextMenu()
- self.addContextMenuItem("Release Token", releaseTokens, true)
- for url,name in pairs(IMAGE_TOKEN_MAP) do
- if name == mode then
- self.addContextMenuItem("Seal " .. mode, function(playerColor) sealToken(url, playerColor) end, true)
- end
- end
-end
+SHOW_SINGLE_RELEASE = true
-function sealToken(url, playerColor)
- local pos = self.getPosition()
-
- local name = IMAGE_TOKEN_MAP[url]
- for i,obj in ipairs(chaosbag.getObjects()) do
- if obj.name == name then
- chaosbag.takeObject({
- position={ pos.x, pos.y + 1, pos.z },
- index=i-1,
- smooth=false,
- callback_function=_sealToken
- })
- return
- end
- end
- printToColor(name .. " token not found in bag", playerColor)
-end
-
-function _sealToken(obj)
- table.insert(sealedTokens, obj)
- local guid = obj.getGUID()
- local tokensTaken = manager.getVar("tokensTaken")
- table.insert(tokensTaken[mode], guid)
- manager.setVar("tokensTaken", tokensTaken)
- manager.setVar("mode", mode)
- printToAll("Sealing " .. mode .. " token " .. manager.call("getTokenCount"))
-end
-
-function releaseTokens(playerColor)
- if #sealedTokens == 0 then return end
- local token = sealedTokens[#sealedTokens]
- if token ~= nil then
- local guid = token.getGUID()
- chaosbag.putObject(token)
- local tokensTaken = manager.getVar("tokensTaken")
- for i,v in ipairs(tokensTaken[mode]) do
- if v == guid then
- table.remove(tokensTaken[mode], i)
- break
- end
- end
- manager.setVar("tokensTaken", tokensTaken)
- manager.setVar("mode", mode)
- printToAll("Releasing " .. mode .. " token" .. manager.call("getTokenCount"))
- end
-
- table.remove(sealedTokens)
-end
-
-function getChaosBag()
- local items = getObjectFromGUID("83ef06").getObjects()
- local chaosbag = nil
- for i,v in ipairs(items) do
- if v.getDescription() == "Chaos Bag" then
- chaosbag = getObjectFromGUID(v.getGUID())
- break
- end
- end
- if chaosbag == nil then printToAll("No chaos bag found") end
- return chaosbag
-end
+require("playercards/CardsThatSealTokens")
diff --git a/src/playercards/cards/FluteoftheOuterGods4.ttslua b/src/playercards/cards/FluteoftheOuterGods4.ttslua
index 000cd744..a1a7782a 100644
--- a/src/playercards/cards/FluteoftheOuterGods4.ttslua
+++ b/src/playercards/cards/FluteoftheOuterGods4.ttslua
@@ -1,81 +1,7 @@
-function onload()
- mode = "Curse"
- chaosbag = getChaosBag()
- manager = getObjectFromGUID("5933fb")
- sealedTokens = { }
- IMAGE_TOKEN_MAP = { }
- for i,v in pairs(Global.getVar("IMAGE_TOKEN_MAP")) do
- IMAGE_TOKEN_MAP[i] = v
- end
+VALID_TOKENS = {
+ ["Curse"] = true
+}
- -- add menu items
- self.clearContextMenu()
- self.addContextMenuItem("Release Token", releaseTokens, true)
- for url,name in pairs(IMAGE_TOKEN_MAP) do
- if name == mode then
- self.addContextMenuItem("Seal " .. mode, function(playerColor) sealToken(url, playerColor) end, true)
- end
- end
-end
+SHOW_SINGLE_RELEASE = true
-function sealToken(url, playerColor)
- local pos = self.getPosition()
-
- local name = IMAGE_TOKEN_MAP[url]
- for i,obj in ipairs(chaosbag.getObjects()) do
- if obj.name == name then
- chaosbag.takeObject({
- position={ pos.x, pos.y + 1, pos.z },
- index=i-1,
- smooth=false,
- callback_function=_sealToken
- })
- return
- end
- end
- printToColor(name .. " token not found in bag", playerColor)
-end
-
-function _sealToken(obj)
- table.insert(sealedTokens, obj)
- local guid = obj.getGUID()
- local tokensTaken = manager.getVar("tokensTaken")
- table.insert(tokensTaken[mode], guid)
- manager.setVar("tokensTaken", tokensTaken)
- manager.setVar("mode", mode)
- printToAll("Sealing " .. mode .. " token " .. manager.call("getTokenCount"))
-end
-
-function releaseTokens(playerColor)
- if #sealedTokens == 0 then return end
- local token = sealedTokens[#sealedTokens]
- if token ~= nil then
- local guid = token.getGUID()
- chaosbag.putObject(token)
- local tokensTaken = manager.getVar("tokensTaken")
- for i,v in ipairs(tokensTaken[mode]) do
- if v == guid then
- table.remove(tokensTaken[mode], i)
- break
- end
- end
- manager.setVar("tokensTaken", tokensTaken)
- manager.setVar("mode", mode)
- printToAll("Releasing " .. mode .. " token" .. manager.call("getTokenCount"))
- end
-
- table.remove(sealedTokens)
-end
-
-function getChaosBag()
- local items = getObjectFromGUID("83ef06").getObjects()
- local chaosbag = nil
- for i,v in ipairs(items) do
- if v.getDescription() == "Chaos Bag" then
- chaosbag = getObjectFromGUID(v.getGUID())
- break
- end
- end
- if chaosbag == nil then printToAll("No chaos bag found") end
- return chaosbag
-end
+require("playercards/CardsThatSealTokens")
diff --git a/src/playercards/cards/HolySpear5.ttslua b/src/playercards/cards/HolySpear5.ttslua
index d34e5462..aa948b10 100644
--- a/src/playercards/cards/HolySpear5.ttslua
+++ b/src/playercards/cards/HolySpear5.ttslua
@@ -1,93 +1,8 @@
-function onload()
- mode = "Bless"
- chaosbag = getChaosBag()
- manager = getObjectFromGUID("5933fb")
- sealedTokens = { }
- IMAGE_TOKEN_MAP = { }
- for i,v in pairs(Global.getVar("IMAGE_TOKEN_MAP")) do
- IMAGE_TOKEN_MAP[i] = v
- end
+VALID_TOKENS = {
+ ["Bless"] = true
+}
- -- add menu items
- self.clearContextMenu()
- self.addContextMenuItem("Release Token", releaseTokens, true)
- for url,name in pairs(IMAGE_TOKEN_MAP) do
- if name == mode then
- self.addContextMenuItem("Seal 2 " .. mode, function(playerColor) sealToken(url, playerColor) end, true)
- end
- end
-end
+SHOW_SINGLE_RELEASE = true
+SHOW_MULTI_SEAL = 2
-function sealToken(url, playerColor)
- local pos = self.getPosition()
-
- local name = IMAGE_TOKEN_MAP[url]
- local indexes = {}
-
- for i,obj in ipairs(chaosbag.getObjects()) do
- if obj.name == name then
- table.insert(indexes, obj.index)
- end
- end
- if #indexes < 2 then
- printToColor("Fewer than 2 " .. name .. " tokens in bag", playerColor)
- return
- end
- table.sort(indexes)
- chaosbag.takeObject({
- position={ pos.x, pos.y + 1, pos.z },
- index=indexes[#indexes],
- smooth=false,
- callback_function=_sealToken
- })
- chaosbag.takeObject({
- position={ pos.x, pos.y + 2, pos.z },
- index=indexes[#indexes-1],
- smooth=false,
- callback_function=_sealToken
- })
-end
-
-function _sealToken(obj)
- table.insert(sealedTokens, obj)
- local guid = obj.getGUID()
- local tokensTaken = manager.getVar("tokensTaken")
- table.insert(tokensTaken[mode], guid)
- manager.setVar("tokensTaken", tokensTaken)
- manager.setVar("mode", mode)
- printToAll("Sealing " .. mode .. " token " .. manager.call("getTokenCount"))
-end
-
-function releaseTokens(playerColor)
- if #sealedTokens == 0 then return end
- local token = sealedTokens[#sealedTokens]
- if token ~= nil then
- local guid = token.getGUID()
- chaosbag.putObject(token)
- local tokensTaken = manager.getVar("tokensTaken")
- for i,v in ipairs(tokensTaken[mode]) do
- if v == guid then
- table.remove(tokensTaken[mode], i)
- break
- end
- end
- manager.setVar("tokensTaken", tokensTaken)
- manager.setVar("mode", mode)
- printToAll("Releasing " .. mode .. " token" .. manager.call("getTokenCount"))
- end
-
- table.remove(sealedTokens)
-end
-
-function getChaosBag()
- local items = getObjectFromGUID("83ef06").getObjects()
- local chaosbag = nil
- for i,v in ipairs(items) do
- if v.getDescription() == "Chaos Bag" then
- chaosbag = getObjectFromGUID(v.getGUID())
- break
- end
- end
- if chaosbag == nil then printToAll("No chaos bag found") end
- return chaosbag
-end
+require("playercards/CardsThatSealTokens")
diff --git a/src/playercards/cards/Nephthys4.ttslua b/src/playercards/cards/Nephthys4.ttslua
index ab3fe3f1..5d42b3f3 100644
--- a/src/playercards/cards/Nephthys4.ttslua
+++ b/src/playercards/cards/Nephthys4.ttslua
@@ -1,81 +1,7 @@
-function onload()
- mode = "Bless"
- chaosbag = getChaosBag()
- manager = getObjectFromGUID("5933fb")
- sealedTokens = { }
- IMAGE_TOKEN_MAP = { }
- for i,v in pairs(Global.getVar("IMAGE_TOKEN_MAP")) do
- IMAGE_TOKEN_MAP[i] = v
- end
+VALID_TOKENS = {
+ ["Bless"] = true
+}
- -- add menu items
- self.clearContextMenu()
- self.addContextMenuItem("Release Token", releaseTokens, true)
- for url,name in pairs(IMAGE_TOKEN_MAP) do
- if name == mode then
- self.addContextMenuItem("Seal " .. mode, function(playerColor) sealToken(url, playerColor) end, true)
- end
- end
-end
+SHOW_MULTI_RELEASE = 3
-function sealToken(url, playerColor)
- local pos = self.getPosition()
-
- local name = IMAGE_TOKEN_MAP[url]
- for i,obj in ipairs(chaosbag.getObjects()) do
- if obj.name == name then
- chaosbag.takeObject({
- position={ pos.x, pos.y + 1, pos.z },
- index=i-1,
- smooth=false,
- callback_function=_sealToken
- })
- return
- end
- end
- printToColor(name .. " token not found in bag", playerColor)
-end
-
-function _sealToken(obj)
- table.insert(sealedTokens, obj)
- local guid = obj.getGUID()
- local tokensTaken = manager.getVar("tokensTaken")
- table.insert(tokensTaken[mode], guid)
- manager.setVar("tokensTaken", tokensTaken)
- manager.setVar("mode", mode)
- printToAll("Sealing " .. mode .. " token " .. manager.call("getTokenCount"))
-end
-
-function releaseTokens(playerColor)
- if #sealedTokens == 0 then return end
- local token = sealedTokens[#sealedTokens]
- if token ~= nil then
- local guid = token.getGUID()
- chaosbag.putObject(token)
- local tokensTaken = manager.getVar("tokensTaken")
- for i,v in ipairs(tokensTaken[mode]) do
- if v == guid then
- table.remove(tokensTaken[mode], i)
- break
- end
- end
- manager.setVar("tokensTaken", tokensTaken)
- manager.setVar("mode", mode)
- printToAll("Releasing " .. mode .. " token" .. manager.call("getTokenCount"))
- end
-
- table.remove(sealedTokens)
-end
-
-function getChaosBag()
- local items = getObjectFromGUID("83ef06").getObjects()
- local chaosbag = nil
- for i,v in ipairs(items) do
- if v.getDescription() == "Chaos Bag" then
- chaosbag = getObjectFromGUID(v.getGUID())
- break
- end
- end
- if chaosbag == nil then printToAll("No chaos bag found") end
- return chaosbag
-end
+require("playercards/CardsThatSealTokens")
diff --git a/src/playercards/cards/ProtectiveIncantation1.ttslua b/src/playercards/cards/ProtectiveIncantation1.ttslua
index e30935a6..33b6970f 100644
--- a/src/playercards/cards/ProtectiveIncantation1.ttslua
+++ b/src/playercards/cards/ProtectiveIncantation1.ttslua
@@ -1,75 +1,9 @@
-function onload()
- chaosbag = getChaosBag()
- sealedTokens = { }
- IMAGE_TOKEN_MAP = { }
- for i,v in pairs(Global.getVar("IMAGE_TOKEN_MAP")) do
- IMAGE_TOKEN_MAP[i] = v
- end
- readBag()
-end
+VALID_TOKENS = {}
-function readBag(playerColor)
- if playerColor ~= nil then
- printToColor("Reading chaos bag", playerColor)
- end
+INVALID_TOKENS = {
+ ["Auto-fail"] = true
+}
- local tokensInBag = { }
- for i,token in ipairs(chaosbag.getObjects()) do
- if token.name ~= nil and token.name ~= "" then
- tokensInBag[token.name] = true
- end
- end
+UPDATE_ON_HOVER = true
- -- add menu items
- self.clearContextMenu()
- self.addContextMenuItem("Release Token", releaseTokens)
- for url,name in pairs(IMAGE_TOKEN_MAP) do
- if tokensInBag[name] and name ~= "Auto-fail" then
- self.addContextMenuItem("Seal " .. name, function(playerColor) sealToken(url, playerColor) end)
- end
- end
- self.addContextMenuItem("Read Chaos Bag", readBag)
-end
-
-function sealToken(url, playerColor)
- local pos = self.getPosition()
-
- local name = IMAGE_TOKEN_MAP[url]
- for i,obj in ipairs(chaosbag.getObjects()) do
- if obj.name == name then
- chaosbag.takeObject({
- position={ pos.x, pos.y + 1, pos.z },
- index=i-1,
- smooth=false,
- callback_function=_sealToken
- })
- return
- end
- end
- printToColor(name .. " token not found in bag", playerColor)
-end
-
-function _sealToken(obj)
- table.insert(sealedTokens, obj)
-end
-
-function releaseTokens(playerColor)
- printToColor("Releasing token", playerColor)
- for i,obj in ipairs(sealedTokens) do
- chaosbag.putObject(obj)
- end
- sealedTokens = { }
-end
-
-function getChaosBag()
- local items = getObjectFromGUID("83ef06").getObjects()
- local chaosbag = nil
- for i,v in ipairs(items) do
- if v.getDescription() == "Chaos Bag" then
- chaosbag = getObjectFromGUID(v.getGUID())
- break
- end
- end
- if chaosbag == nil then printToAll("No chaos bag found") end
- return chaosbag
-end
+require("playercards/CardsThatSealTokens")
diff --git a/src/playercards/cards/RadiantSmite1.ttslua b/src/playercards/cards/RadiantSmite1.ttslua
index ab3fe3f1..79219afc 100644
--- a/src/playercards/cards/RadiantSmite1.ttslua
+++ b/src/playercards/cards/RadiantSmite1.ttslua
@@ -1,81 +1,5 @@
-function onload()
- mode = "Bless"
- chaosbag = getChaosBag()
- manager = getObjectFromGUID("5933fb")
- sealedTokens = { }
- IMAGE_TOKEN_MAP = { }
- for i,v in pairs(Global.getVar("IMAGE_TOKEN_MAP")) do
- IMAGE_TOKEN_MAP[i] = v
- end
+VALID_TOKENS = {
+ ["Bless"] = true
+}
- -- add menu items
- self.clearContextMenu()
- self.addContextMenuItem("Release Token", releaseTokens, true)
- for url,name in pairs(IMAGE_TOKEN_MAP) do
- if name == mode then
- self.addContextMenuItem("Seal " .. mode, function(playerColor) sealToken(url, playerColor) end, true)
- end
- end
-end
-
-function sealToken(url, playerColor)
- local pos = self.getPosition()
-
- local name = IMAGE_TOKEN_MAP[url]
- for i,obj in ipairs(chaosbag.getObjects()) do
- if obj.name == name then
- chaosbag.takeObject({
- position={ pos.x, pos.y + 1, pos.z },
- index=i-1,
- smooth=false,
- callback_function=_sealToken
- })
- return
- end
- end
- printToColor(name .. " token not found in bag", playerColor)
-end
-
-function _sealToken(obj)
- table.insert(sealedTokens, obj)
- local guid = obj.getGUID()
- local tokensTaken = manager.getVar("tokensTaken")
- table.insert(tokensTaken[mode], guid)
- manager.setVar("tokensTaken", tokensTaken)
- manager.setVar("mode", mode)
- printToAll("Sealing " .. mode .. " token " .. manager.call("getTokenCount"))
-end
-
-function releaseTokens(playerColor)
- if #sealedTokens == 0 then return end
- local token = sealedTokens[#sealedTokens]
- if token ~= nil then
- local guid = token.getGUID()
- chaosbag.putObject(token)
- local tokensTaken = manager.getVar("tokensTaken")
- for i,v in ipairs(tokensTaken[mode]) do
- if v == guid then
- table.remove(tokensTaken[mode], i)
- break
- end
- end
- manager.setVar("tokensTaken", tokensTaken)
- manager.setVar("mode", mode)
- printToAll("Releasing " .. mode .. " token" .. manager.call("getTokenCount"))
- end
-
- table.remove(sealedTokens)
-end
-
-function getChaosBag()
- local items = getObjectFromGUID("83ef06").getObjects()
- local chaosbag = nil
- for i,v in ipairs(items) do
- if v.getDescription() == "Chaos Bag" then
- chaosbag = getObjectFromGUID(v.getGUID())
- break
- end
- end
- if chaosbag == nil then printToAll("No chaos bag found") end
- return chaosbag
-end
+require("playercards/CardsThatSealTokens")
diff --git a/src/playercards/cards/RiteofSanctification.ttslua b/src/playercards/cards/RiteofSanctification.ttslua
index ab3fe3f1..fe5a27fc 100644
--- a/src/playercards/cards/RiteofSanctification.ttslua
+++ b/src/playercards/cards/RiteofSanctification.ttslua
@@ -1,81 +1,7 @@
-function onload()
- mode = "Bless"
- chaosbag = getChaosBag()
- manager = getObjectFromGUID("5933fb")
- sealedTokens = { }
- IMAGE_TOKEN_MAP = { }
- for i,v in pairs(Global.getVar("IMAGE_TOKEN_MAP")) do
- IMAGE_TOKEN_MAP[i] = v
- end
+VALID_TOKENS = {
+ ["Bless"] = true
+}
- -- add menu items
- self.clearContextMenu()
- self.addContextMenuItem("Release Token", releaseTokens, true)
- for url,name in pairs(IMAGE_TOKEN_MAP) do
- if name == mode then
- self.addContextMenuItem("Seal " .. mode, function(playerColor) sealToken(url, playerColor) end, true)
- end
- end
-end
+SHOW_SINGLE_RELEASE = true
-function sealToken(url, playerColor)
- local pos = self.getPosition()
-
- local name = IMAGE_TOKEN_MAP[url]
- for i,obj in ipairs(chaosbag.getObjects()) do
- if obj.name == name then
- chaosbag.takeObject({
- position={ pos.x, pos.y + 1, pos.z },
- index=i-1,
- smooth=false,
- callback_function=_sealToken
- })
- return
- end
- end
- printToColor(name .. " token not found in bag", playerColor)
-end
-
-function _sealToken(obj)
- table.insert(sealedTokens, obj)
- local guid = obj.getGUID()
- local tokensTaken = manager.getVar("tokensTaken")
- table.insert(tokensTaken[mode], guid)
- manager.setVar("tokensTaken", tokensTaken)
- manager.setVar("mode", mode)
- printToAll("Sealing " .. mode .. " token " .. manager.call("getTokenCount"))
-end
-
-function releaseTokens(playerColor)
- if #sealedTokens == 0 then return end
- local token = sealedTokens[#sealedTokens]
- if token ~= nil then
- local guid = token.getGUID()
- chaosbag.putObject(token)
- local tokensTaken = manager.getVar("tokensTaken")
- for i,v in ipairs(tokensTaken[mode]) do
- if v == guid then
- table.remove(tokensTaken[mode], i)
- break
- end
- end
- manager.setVar("tokensTaken", tokensTaken)
- manager.setVar("mode", mode)
- printToAll("Releasing " .. mode .. " token" .. manager.call("getTokenCount"))
- end
-
- table.remove(sealedTokens)
-end
-
-function getChaosBag()
- local items = getObjectFromGUID("83ef06").getObjects()
- local chaosbag = nil
- for i,v in ipairs(items) do
- if v.getDescription() == "Chaos Bag" then
- chaosbag = getObjectFromGUID(v.getGUID())
- break
- end
- end
- if chaosbag == nil then printToAll("No chaos bag found") end
- return chaosbag
-end
+require("playercards/CardsThatSealTokens")
diff --git a/src/playercards/cards/SealoftheSeventhSign5.ttslua b/src/playercards/cards/SealoftheSeventhSign5.ttslua
index b24b7903..736b14a8 100644
--- a/src/playercards/cards/SealoftheSeventhSign5.ttslua
+++ b/src/playercards/cards/SealoftheSeventhSign5.ttslua
@@ -1,60 +1,5 @@
-function onload()
- chaosbag = getChaosBag()
- sealedTokens = { }
- IMAGE_TOKEN_MAP = { }
- for i,v in pairs(Global.getVar("IMAGE_TOKEN_MAP")) do
- IMAGE_TOKEN_MAP[i] = v
- end
+VALID_TOKENS = {
+ ["Auto-fail"] = true
+}
- -- add menu items
- self.clearContextMenu()
- self.addContextMenuItem("Release Token", releaseTokens)
- for url,name in pairs(IMAGE_TOKEN_MAP) do
- if name == "Auto-fail" then
- self.addContextMenuItem("Seal Auto-fail", function(playerColor) sealToken(url, playerColor) end)
- end
- end
-end
-
-function sealToken(url, playerColor)
- local pos = self.getPosition()
-
- local name = IMAGE_TOKEN_MAP[url]
- for i,obj in ipairs(chaosbag.getObjects()) do
- if obj.name == name then
- chaosbag.takeObject({
- position={ pos.x, pos.y + 1, pos.z },
- index=i-1,
- smooth=false,
- callback_function=_sealToken
- })
- return
- end
- end
- printToColor(name .. " token not found in bag", playerColor)
-end
-
-function _sealToken(obj)
- table.insert(sealedTokens, obj)
-end
-
-function releaseTokens(playerColor)
- printToColor("Releasing token", playerColor)
- for i,obj in ipairs(sealedTokens) do
- chaosbag.putObject(obj)
- end
- sealedTokens = { }
-end
-
-function getChaosBag()
- local items = getObjectFromGUID("83ef06").getObjects()
- local chaosbag = nil
- for i,v in ipairs(items) do
- if v.getDescription() == "Chaos Bag" then
- chaosbag = getObjectFromGUID(v.getGUID())
- break
- end
- end
- if chaosbag == nil then printToAll("No chaos bag found") end
- return chaosbag
-end
+require("playercards/CardsThatSealTokens")
diff --git a/src/playercards/cards/SerpentsofYig.ttslua b/src/playercards/cards/SerpentsofYig.ttslua
index 447d6743..78e4493c 100644
--- a/src/playercards/cards/SerpentsofYig.ttslua
+++ b/src/playercards/cards/SerpentsofYig.ttslua
@@ -1,60 +1,5 @@
-function onload()
- chaosbag = getChaosBag()
- sealedTokens = { }
- IMAGE_TOKEN_MAP = { }
- for i,v in pairs(Global.getVar("IMAGE_TOKEN_MAP")) do
- IMAGE_TOKEN_MAP[i] = v
- end
+VALID_TOKENS = {
+ ["Elder Sign"] = true
+}
- -- add menu items
- self.clearContextMenu()
- self.addContextMenuItem("Release Token", releaseTokens)
- for url,name in pairs(IMAGE_TOKEN_MAP) do
- if name == "Elder Sign" then
- self.addContextMenuItem("Seal Elder Sign", function(playerColor) sealToken(url, playerColor) end)
- end
- end
-end
-
-function sealToken(url, playerColor)
- local pos = self.getPosition()
-
- local name = IMAGE_TOKEN_MAP[url]
- for i,obj in ipairs(chaosbag.getObjects()) do
- if obj.name == name then
- chaosbag.takeObject({
- position={ pos.x, pos.y + 1, pos.z },
- index=i-1,
- smooth=false,
- callback_function=_sealToken
- })
- return
- end
- end
- printToColor(name .. " token not found in bag", playerColor)
-end
-
-function _sealToken(obj)
- table.insert(sealedTokens, obj)
-end
-
-function releaseTokens(playerColor)
- printToColor("Releasing token", playerColor)
- for i,obj in ipairs(sealedTokens) do
- chaosbag.putObject(obj)
- end
- sealedTokens = { }
-end
-
-function getChaosBag()
- local items = getObjectFromGUID("83ef06").getObjects()
- local chaosbag = nil
- for i,v in ipairs(items) do
- if v.getDescription() == "Chaos Bag" then
- chaosbag = getObjectFromGUID(v.getGUID())
- break
- end
- end
- if chaosbag == nil then printToAll("No chaos bag found") end
- return chaosbag
-end
+require("playercards/CardsThatSealTokens")
diff --git a/src/playercards/cards/ShardsoftheVoid3.ttslua b/src/playercards/cards/ShardsoftheVoid3.ttslua
index c935705c..10645275 100644
--- a/src/playercards/cards/ShardsoftheVoid3.ttslua
+++ b/src/playercards/cards/ShardsoftheVoid3.ttslua
@@ -1,45 +1,7 @@
-function onload()
- chaosbag = getChaosBag()
- IMAGE_TOKEN_MAP = { }
- for i,v in pairs(Global.getVar("IMAGE_TOKEN_MAP")) do
- IMAGE_TOKEN_MAP[i] = v
- end
+VALID_TOKENS = {
+ ["0"] = true
+}
- -- add menu items
- self.clearContextMenu()
- for url,name in pairs(IMAGE_TOKEN_MAP) do
- if name == "0" then
- self.addContextMenuItem("Seal 0", function(playerColor) sealToken(url, playerColor) end)
- end
- end
-end
+SHOW_SINGLE_RELEASE = true
-function sealToken(url, playerColor)
- local pos = self.getPosition()
-
- local name = IMAGE_TOKEN_MAP[url]
- for i,obj in ipairs(chaosbag.getObjects()) do
- if obj.name == name then
- chaosbag.takeObject({
- position={ pos.x, pos.y + 1, pos.z },
- index=i-1,
- smooth=false
- })
- return
- end
- end
- printToColor(name .. " token not found in bag", playerColor)
-end
-
-function getChaosBag()
- local items = getObjectFromGUID("83ef06").getObjects()
- local chaosbag = nil
- for i,v in ipairs(items) do
- if v.getDescription() == "Chaos Bag" then
- chaosbag = getObjectFromGUID(v.getGUID())
- break
- end
- end
- if chaosbag == nil then printToAll("No chaos bag found") end
- return chaosbag
-end
+require("playercards/CardsThatSealTokens")
diff --git a/src/playercards/cards/ShieldofFaith2.ttslua b/src/playercards/cards/ShieldofFaith2.ttslua
index ab3fe3f1..fe5a27fc 100644
--- a/src/playercards/cards/ShieldofFaith2.ttslua
+++ b/src/playercards/cards/ShieldofFaith2.ttslua
@@ -1,81 +1,7 @@
-function onload()
- mode = "Bless"
- chaosbag = getChaosBag()
- manager = getObjectFromGUID("5933fb")
- sealedTokens = { }
- IMAGE_TOKEN_MAP = { }
- for i,v in pairs(Global.getVar("IMAGE_TOKEN_MAP")) do
- IMAGE_TOKEN_MAP[i] = v
- end
+VALID_TOKENS = {
+ ["Bless"] = true
+}
- -- add menu items
- self.clearContextMenu()
- self.addContextMenuItem("Release Token", releaseTokens, true)
- for url,name in pairs(IMAGE_TOKEN_MAP) do
- if name == mode then
- self.addContextMenuItem("Seal " .. mode, function(playerColor) sealToken(url, playerColor) end, true)
- end
- end
-end
+SHOW_SINGLE_RELEASE = true
-function sealToken(url, playerColor)
- local pos = self.getPosition()
-
- local name = IMAGE_TOKEN_MAP[url]
- for i,obj in ipairs(chaosbag.getObjects()) do
- if obj.name == name then
- chaosbag.takeObject({
- position={ pos.x, pos.y + 1, pos.z },
- index=i-1,
- smooth=false,
- callback_function=_sealToken
- })
- return
- end
- end
- printToColor(name .. " token not found in bag", playerColor)
-end
-
-function _sealToken(obj)
- table.insert(sealedTokens, obj)
- local guid = obj.getGUID()
- local tokensTaken = manager.getVar("tokensTaken")
- table.insert(tokensTaken[mode], guid)
- manager.setVar("tokensTaken", tokensTaken)
- manager.setVar("mode", mode)
- printToAll("Sealing " .. mode .. " token " .. manager.call("getTokenCount"))
-end
-
-function releaseTokens(playerColor)
- if #sealedTokens == 0 then return end
- local token = sealedTokens[#sealedTokens]
- if token ~= nil then
- local guid = token.getGUID()
- chaosbag.putObject(token)
- local tokensTaken = manager.getVar("tokensTaken")
- for i,v in ipairs(tokensTaken[mode]) do
- if v == guid then
- table.remove(tokensTaken[mode], i)
- break
- end
- end
- manager.setVar("tokensTaken", tokensTaken)
- manager.setVar("mode", mode)
- printToAll("Releasing " .. mode .. " token" .. manager.call("getTokenCount"))
- end
-
- table.remove(sealedTokens)
-end
-
-function getChaosBag()
- local items = getObjectFromGUID("83ef06").getObjects()
- local chaosbag = nil
- for i,v in ipairs(items) do
- if v.getDescription() == "Chaos Bag" then
- chaosbag = getObjectFromGUID(v.getGUID())
- break
- end
- end
- if chaosbag == nil then printToAll("No chaos bag found") end
- return chaosbag
-end
+require("playercards/CardsThatSealTokens")
diff --git a/src/playercards/cards/TheChthonianStone.ttslua b/src/playercards/cards/TheChthonianStone.ttslua
index b7aabf11..050c1176 100644
--- a/src/playercards/cards/TheChthonianStone.ttslua
+++ b/src/playercards/cards/TheChthonianStone.ttslua
@@ -1,67 +1,8 @@
VALID_TOKENS = {
- Skull=true,
- Cultist=true,
- Tablet=true,
- ["Elder Thing"]=true
+ ["Skull"] = true,
+ ["Cultist"] = true,
+ ["Tablet"] = true,
+ ["Elder Thing"] = true,
}
-function onload()
- chaosbag = getChaosBag()
- sealedTokens = { }
- IMAGE_TOKEN_MAP = { }
- for i,v in pairs(Global.getVar("IMAGE_TOKEN_MAP")) do
- IMAGE_TOKEN_MAP[i] = v
- end
-
- -- add menu items
- self.clearContextMenu()
- self.addContextMenuItem("Release Token", releaseTokens)
- for url,name in pairs(IMAGE_TOKEN_MAP) do
- if VALID_TOKENS[name] ~= nil then
- self.addContextMenuItem("Seal " .. name, function(playerColor) sealToken(url, playerColor) end)
- end
- end
-end
-
-function sealToken(url, playerColor)
- local pos = self.getPosition()
-
- local name = IMAGE_TOKEN_MAP[url]
- for i,obj in ipairs(chaosbag.getObjects()) do
- if obj.name == name then
- chaosbag.takeObject({
- position={ pos.x, pos.y + 1, pos.z },
- index=i-1,
- smooth=false,
- callback_function=_sealToken
- })
- return
- end
- end
- printToColor(name .. " token not found in bag", playerColor)
-end
-
-function _sealToken(obj)
- table.insert(sealedTokens, obj)
-end
-
-function releaseTokens(playerColor)
- printToColor("Releasing token", playerColor)
- for i,obj in ipairs(sealedTokens) do
- chaosbag.putObject(obj)
- end
- sealedTokens = { }
-end
-
-function getChaosBag()
- local items = getObjectFromGUID("83ef06").getObjects()
- local chaosbag = nil
- for i,v in ipairs(items) do
- if v.getDescription() == "Chaos Bag" then
- chaosbag = getObjectFromGUID(v.getGUID())
- break
- end
- end
- if chaosbag == nil then printToAll("No chaos bag found") end
- return chaosbag
-end
+require("playercards/CardsThatSealTokens")
diff --git a/src/playercards/cards/TheChthonianStone3.ttslua b/src/playercards/cards/TheChthonianStone3.ttslua
index b7aabf11..050c1176 100644
--- a/src/playercards/cards/TheChthonianStone3.ttslua
+++ b/src/playercards/cards/TheChthonianStone3.ttslua
@@ -1,67 +1,8 @@
VALID_TOKENS = {
- Skull=true,
- Cultist=true,
- Tablet=true,
- ["Elder Thing"]=true
+ ["Skull"] = true,
+ ["Cultist"] = true,
+ ["Tablet"] = true,
+ ["Elder Thing"] = true,
}
-function onload()
- chaosbag = getChaosBag()
- sealedTokens = { }
- IMAGE_TOKEN_MAP = { }
- for i,v in pairs(Global.getVar("IMAGE_TOKEN_MAP")) do
- IMAGE_TOKEN_MAP[i] = v
- end
-
- -- add menu items
- self.clearContextMenu()
- self.addContextMenuItem("Release Token", releaseTokens)
- for url,name in pairs(IMAGE_TOKEN_MAP) do
- if VALID_TOKENS[name] ~= nil then
- self.addContextMenuItem("Seal " .. name, function(playerColor) sealToken(url, playerColor) end)
- end
- end
-end
-
-function sealToken(url, playerColor)
- local pos = self.getPosition()
-
- local name = IMAGE_TOKEN_MAP[url]
- for i,obj in ipairs(chaosbag.getObjects()) do
- if obj.name == name then
- chaosbag.takeObject({
- position={ pos.x, pos.y + 1, pos.z },
- index=i-1,
- smooth=false,
- callback_function=_sealToken
- })
- return
- end
- end
- printToColor(name .. " token not found in bag", playerColor)
-end
-
-function _sealToken(obj)
- table.insert(sealedTokens, obj)
-end
-
-function releaseTokens(playerColor)
- printToColor("Releasing token", playerColor)
- for i,obj in ipairs(sealedTokens) do
- chaosbag.putObject(obj)
- end
- sealedTokens = { }
-end
-
-function getChaosBag()
- local items = getObjectFromGUID("83ef06").getObjects()
- local chaosbag = nil
- for i,v in ipairs(items) do
- if v.getDescription() == "Chaos Bag" then
- chaosbag = getObjectFromGUID(v.getGUID())
- break
- end
- end
- if chaosbag == nil then printToAll("No chaos bag found") end
- return chaosbag
-end
+require("playercards/CardsThatSealTokens")
diff --git a/src/playercards/cards/TheCodexofAges.ttslua b/src/playercards/cards/TheCodexofAges.ttslua
index 447d6743..78e4493c 100644
--- a/src/playercards/cards/TheCodexofAges.ttslua
+++ b/src/playercards/cards/TheCodexofAges.ttslua
@@ -1,60 +1,5 @@
-function onload()
- chaosbag = getChaosBag()
- sealedTokens = { }
- IMAGE_TOKEN_MAP = { }
- for i,v in pairs(Global.getVar("IMAGE_TOKEN_MAP")) do
- IMAGE_TOKEN_MAP[i] = v
- end
+VALID_TOKENS = {
+ ["Elder Sign"] = true
+}
- -- add menu items
- self.clearContextMenu()
- self.addContextMenuItem("Release Token", releaseTokens)
- for url,name in pairs(IMAGE_TOKEN_MAP) do
- if name == "Elder Sign" then
- self.addContextMenuItem("Seal Elder Sign", function(playerColor) sealToken(url, playerColor) end)
- end
- end
-end
-
-function sealToken(url, playerColor)
- local pos = self.getPosition()
-
- local name = IMAGE_TOKEN_MAP[url]
- for i,obj in ipairs(chaosbag.getObjects()) do
- if obj.name == name then
- chaosbag.takeObject({
- position={ pos.x, pos.y + 1, pos.z },
- index=i-1,
- smooth=false,
- callback_function=_sealToken
- })
- return
- end
- end
- printToColor(name .. " token not found in bag", playerColor)
-end
-
-function _sealToken(obj)
- table.insert(sealedTokens, obj)
-end
-
-function releaseTokens(playerColor)
- printToColor("Releasing token", playerColor)
- for i,obj in ipairs(sealedTokens) do
- chaosbag.putObject(obj)
- end
- sealedTokens = { }
-end
-
-function getChaosBag()
- local items = getObjectFromGUID("83ef06").getObjects()
- local chaosbag = nil
- for i,v in ipairs(items) do
- if v.getDescription() == "Chaos Bag" then
- chaosbag = getObjectFromGUID(v.getGUID())
- break
- end
- end
- if chaosbag == nil then printToAll("No chaos bag found") end
- return chaosbag
-end
+require("playercards/CardsThatSealTokens")
diff --git a/src/playercards/cards/Unrelenting1.ttslua b/src/playercards/cards/Unrelenting1.ttslua
index 16e20d25..c57efbf4 100644
--- a/src/playercards/cards/Unrelenting1.ttslua
+++ b/src/playercards/cards/Unrelenting1.ttslua
@@ -1,97 +1,6 @@
-function onload()
- chaosbag = getChaosBag()
- manager = getObjectFromGUID("5933fb")
- sealedTokens = { }
- IMAGE_TOKEN_MAP = { }
- for i,v in pairs(Global.getVar("IMAGE_TOKEN_MAP")) do
- IMAGE_TOKEN_MAP[i] = v
- end
+VALID_TOKENS = {}
+INVALID_TOKENS = {}
- readBag()
-end
+UPDATE_ON_HOVER = true
-function sealToken(url, playerColor)
- local pos = self.getPosition()
-
- local name = IMAGE_TOKEN_MAP[url]
- for i,obj in ipairs(chaosbag.getObjects()) do
- if obj.name == name then
- chaosbag.takeObject({
- position={ pos.x, pos.y + 1, pos.z },
- index=i-1,
- smooth=false,
- callback_function=_sealToken
- })
- return
- end
- end
- printToColor(name .. " token not found in bag", playerColor)
-end
-
-function _sealToken(obj)
- table.insert(sealedTokens, obj)
- local guid = obj.getGUID()
- local name = obj.getName()
- if name == "Bless" or name == "Curse" then
- local tokensTaken = manager.getVar("tokensTaken")
- table.insert(tokensTaken[name], guid)
- manager.setVar("tokensTaken", tokensTaken)
- manager.setVar("mode", name)
- printToAll("Sealing " .. name .. " token " .. manager.call("getTokenCount"))
- end
-end
-
-function releaseTokens(playerColor)
- if #sealedTokens == 0 then return end
- for i,token in ipairs(sealedTokens) do
- local guid = token.getGUID()
- local name = token.getName()
- chaosbag.putObject(token)
- if name == "Bless" or name == "Curse" then
- local tokensTaken = manager.getVar("tokensTaken")
- for i,v in ipairs(tokensTaken[name]) do
- if v == guid then
- table.remove(tokensTaken[name], i)
- break
- end
- end
- manager.setVar("tokensTaken", tokensTaken)
- manager.setVar("mode", name)
- printToAll("Releasing " .. name .. " token" .. manager.call("getTokenCount"))
- end
- end
-
- sealedTokens = { }
-end
-
-function getChaosBag()
- local items = getObjectFromGUID("83ef06").getObjects()
- local chaosbag = nil
- for i,v in ipairs(items) do
- if v.getDescription() == "Chaos Bag" then
- chaosbag = getObjectFromGUID(v.getGUID())
- break
- end
- end
- if chaosbag == nil then printToAll("No chaos bag found") end
- return chaosbag
-end
-
-function readBag()
- -- add menu items
- self.clearContextMenu()
- self.addContextMenuItem("Release Tokens", releaseTokens)
-
- local bagTokens = { }
- local tokens = chaosbag.getObjects()
- for i,token in ipairs(tokens) do
- bagTokens[token.name] = true
- end
-
- for url,token in pairs(IMAGE_TOKEN_MAP) do
- if bagTokens[token] then
- self.addContextMenuItem("Seal " .. token, function(playerColor) sealToken(url, playerColor) end, true)
- end
- end
- self.addContextMenuItem("Refresh Seal Options", readBag)
-end
+require("playercards/CardsThatSealTokens")
diff --git a/src/playermat/Playmat.ttslua b/src/playermat/Playmat.ttslua
index 98dbb7e2..5a14b196 100644
--- a/src/playermat/Playmat.ttslua
+++ b/src/playermat/Playmat.ttslua
@@ -67,7 +67,7 @@ isDES = false
function onSave()
return JSON.encode({
zoneID = zoneID,
- playerColor = PLAYER_COLOR,
+ playerColor = playerColor,
activeInvestigatorId = activeInvestigatorId,
isDrawButtonVisible = isDrawButtonVisible
})
@@ -80,6 +80,7 @@ function onLoad(save_state)
STAT_TRACKER = getObjectFromGUID(STAT_TRACKER_GUID)
RESOURCE_COUNTER = getObjectFromGUID(RESOURCE_COUNTER_GUID)
+ -- button creation
for i = 1, 6 do
makeDiscardButton(DISCARD_BUTTON_OFFSETS[i], {-3.85, 3, 10.38}, i)
end
@@ -94,7 +95,7 @@ function onLoad(save_state)
})
self.createButton({
- click_function = "drawChaostokenButton",
+ click_function = "drawChaosTokenButton",
function_owner = self,
position = {1.85, 0, -0.74},
rotation = {0, -45, 0},
@@ -113,10 +114,11 @@ function onLoad(save_state)
font_size = 180
})
+ -- save state loading
local state = JSON.decode(save_state)
if state ~= nil then
zoneID = state.zoneID
- PLAYER_COLOR = state.playerColor
+ playerColor = state.playerColor
activeInvestigatorId = state.activeInvestigatorId
isDrawButtonVisible = state.isDrawButtonVisible
end
@@ -133,15 +135,6 @@ end
-- utility functions
---------------------------------------------------------
-function log(message)
- if DEBUG then print(message) end
-end
-
--- send messages to player who clicked button if no seated player found
-function setMessageColor(color)
- messageColor = Player[PLAYER_COLOR].seated and PLAYER_COLOR or color
-end
-
function spawnDeckZone()
spawnObject({
position = self.positionToWorld({-1.4, 0, 0.3 }),
@@ -165,7 +158,9 @@ function searchArea(origin, size)
})
end
-function doNotReady(card) return card.getVar("do_not_ready") or false end
+function doNotReady(card)
+ return card.getVar("do_not_ready") or false
+end
---------------------------------------------------------
-- Discard buttons
@@ -231,19 +226,18 @@ end
-- Upkeep button
---------------------------------------------------------
-function doUpkeep(_, color, alt_click)
- setMessageColor(color)
-
- -- right-click binds to new player color
- if alt_click then
- PLAYER_COLOR = color
- printToColor("Upkeep button bound to " .. color, color)
+function doUpkeep(_, clickedByColor, isRightClick)
+ -- right-click allow color changing
+ if isRightClick then
+ changeColor(clickedByColor)
return
end
- local forcedLearning = false
+ -- send messages to player who clicked button if no seated player found
+ messageColor = Player[playerColor].seated and playerColor or clickedByColor
-- unexhaust cards in play zone, flip action tokens and find forcedLearning
+ local forcedLearning = false
for _, v in ipairs(searchArea(PLAY_ZONE_POSITION, PLAY_ZONE_SCALE)) do
local obj = v.hit_object
if obj.getDescription() == "Action Token" and obj.is_face_down then
@@ -304,7 +298,7 @@ function doUpkeep(_, color, alt_click)
if forcedLearning then
printToColor("Wow, did you really take 'Versatile' to play Patrice with 'Forced Learning'? Choose which draw replacement effect takes priority and draw cards accordingly.", messageColor)
else
- local handSize = #Player[PLAYER_COLOR].getHandObjects()
+ local handSize = #Player[playerColor].getHandObjects()
if handSize < 5 then
local cardsToDraw = 5 - handSize
printToColor("Drawing " .. cardsToDraw .. " cards (Patrice)", messageColor)
@@ -328,7 +322,8 @@ end
-- function for "draw 1 button" (that can be added via option panel)
function doDrawOne(_, color)
- setMessageColor(color)
+ -- send messages to player who clicked button if no seated player found
+ messageColor = Player[playerColor].seated and playerColor or color
drawCardsWithReshuffle(1)
end
@@ -351,7 +346,7 @@ function drawCardsWithReshuffle(numCards)
end
if topCard ~= nil then
- topCard.deal(numCards, PLAYER_COLOR)
+ topCard.deal(numCards, playerColor)
numCards = numCards - 1
if numCards == 0 then return end
end
@@ -402,7 +397,7 @@ end
function drawCards(numCards)
if drawDeck == nil then return end
- drawDeck.deal(numCards, PLAYER_COLOR)
+ drawDeck.deal(numCards, playerColor)
end
function shuffleDiscardIntoDeck()
@@ -415,8 +410,7 @@ end
-- discard a random non-hidden card from hand
function doDiscardOne()
- local handColor = getHandColor()
- local hand = Player[handColor].getHandObjects()
+ local hand = Player[playerColor].getHandObjects()
if #hand == 0 then
broadcastToAll("Cannot discard from empty hand!", "Red")
else
@@ -444,18 +438,72 @@ function doDiscardOne()
end
end
--- gets the hand color of the closest seated player (by roughly cutting the table into quarters)
-function getHandColor()
- for _, handColor in ipairs(Player.getAvailableColors()) do
- local handPosition = Player[handColor].getHandTransform().position
+---------------------------------------------------------
+-- color related functions
+---------------------------------------------------------
- if (PLAYER_COLOR == "White" and handPosition.x < -42 and handPosition.z > 0)
- or (PLAYER_COLOR == "Orange" and handPosition.x < -42 and handPosition.z < 0)
- or (PLAYER_COLOR == "Green" and handPosition.x > -42 and handPosition.z > 0)
- or (PLAYER_COLOR == "Red" and handPosition.x > -42 and handPosition.z < 0) then
- return handColor
+-- changes the player color
+function changeColor(clickedByColor)
+ local colorList = {
+ "White",
+ "Brown",
+ "Red",
+ "Orange",
+ "Yellow",
+ "Green",
+ "Teal",
+ "Blue",
+ "Purple",
+ "Pink"
+ }
+
+ -- remove existing colors from the list of choices
+ for _, existingColor in ipairs(Player.getAvailableColors()) do
+ for i, newColor in ipairs(colorList) do
+ if existingColor == newColor then
+ table.remove(colorList, i)
+ end
end
end
+
+ -- show the option dialog for color selection to the player that triggered this
+ Player[clickedByColor].showOptionsDialog("Select a new color:", colorList, _, function(color)
+ local HAND_ZONE_GUIDS = {
+ "a70eee", -- White
+ "5fe087", -- Orange
+ "0285cc", -- Green
+ "be2f17" -- Red
+ }
+ local index
+ local startPos = self.getPosition()
+
+ -- get respective hand zone by position
+ if startPos.x < -42 then
+ if startPos.z > 0 then
+ index = 1
+ else
+ index = 2
+ end
+ else
+ if startPos.z > 0 then
+ index = 3
+ else
+ index = 4
+ end
+ end
+
+ -- update the color of the hand zone
+ local handZone = getObjectFromGUID(HAND_ZONE_GUIDS[index])
+ handZone.setValue(color)
+
+ -- if the seated player clicked this, reseat him to the new color
+ if clickedByColor == playerColor then
+ Player[playerColor].changeColor(color)
+ end
+
+ -- update the internal variable
+ playerColor = color
+ end)
end
---------------------------------------------------------
@@ -722,8 +770,8 @@ end
-- calls to 'Global' / functions for calls from outside
---------------------------------------------------------
-function drawChaostokenButton(_, _, isRightClick)
- Global.call("drawChaostoken", {self, DRAWN_CHAOS_TOKEN_OFFSET, isRightClick})
+function drawChaosTokenButton(_, _, isRightClick)
+ Global.call("drawChaosToken", {self, DRAWN_CHAOS_TOKEN_OFFSET, isRightClick})
end
function drawEncountercard(_, _, isRightClick)
diff --git a/src/playermat/PlaymatApi.ttslua b/src/playermat/PlaymatApi.ttslua
index df49ded4..d8975615 100644
--- a/src/playermat/PlaymatApi.ttslua
+++ b/src/playermat/PlaymatApi.ttslua
@@ -43,9 +43,9 @@ do
-- Returns the color of the player's hand that is seated next to the playermat
---@param matColor String Color of the playermat
- PlaymatApi.getHandColor = function(matColor)
+ PlaymatApi.getPlayerColor = function(matColor)
local mat = getObjectFromGUID(MAT_IDS[matColor])
- return mat.call("getHandColor")
+ return mat.getVar("playerColor")
end
-- Returns if there is the card "Dream-Enhancing Serum" on the requested playermat