267 lines
17 KiB
YAML
267 lines
17 KiB
YAML
AltLookAngle:
|
|
x: 0
|
|
y: 0
|
|
z: 0
|
|
Autoraise: true
|
|
ColorDiffuse:
|
|
b: 1
|
|
g: 0.37256
|
|
r: 0.30589
|
|
ContainedObjects:
|
|
- AltLookAngle:
|
|
x: 0
|
|
y: 0
|
|
z: 0
|
|
Autoraise: true
|
|
Bag:
|
|
Order: 0
|
|
ColorDiffuse:
|
|
b: 1
|
|
g: 1
|
|
r: 1
|
|
CustomMesh:
|
|
CastShadows: true
|
|
ColliderURL: http://cloud-3.steamusercontent.com/ugc/1754695414379239413/0B8E68F3B7311DCF2138FB701F78D1D93FBA4CAB/
|
|
Convex: true
|
|
DiffuseURL: http://cloud-3.steamusercontent.com/ugc/1750192233783143973/D526236AAE16BDBB98D3F30E27BAFC1D3E21F4AC/
|
|
MaterialIndex: 1
|
|
MeshURL: http://cloud-3.steamusercontent.com/ugc/1754695414379239413/0B8E68F3B7311DCF2138FB701F78D1D93FBA4CAB/
|
|
NormalURL: ''
|
|
TypeIndex: 6
|
|
Description: 'Drop cards here to display name, cost and skill icons.
|
|
|
|
|
|
See context menu for options.
|
|
|
|
|
|
Drop this on another card to load the respective background if available.'
|
|
DragSelectable: true
|
|
GMNotes: ''
|
|
GUID: d45664
|
|
Grid: true
|
|
GridProjection: false
|
|
Hands: false
|
|
HideWhenFaceDown: false
|
|
IgnoreFoW: false
|
|
LayoutGroupSortIndex: 0
|
|
Locked: false
|
|
LuaScript: "-- Bundled by luabundle {\"version\":\"1.6.0\"}\nlocal __bundle_require,
|
|
__bundle_loaded, __bundle_register, __bundle_modules = (function(superRequire)\n\tlocal
|
|
loadingPlaceholder = {[{}] = true}\n\n\tlocal register\n\tlocal modules = {}\n\n\tlocal
|
|
require\n\tlocal loaded = {}\n\n\tregister = function(name, body)\n\t\tif not
|
|
modules[name] then\n\t\t\tmodules[name] = body\n\t\tend\n\tend\n\n\trequire =
|
|
function(name)\n\t\tlocal loadedModule = loaded[name]\n\n\t\tif loadedModule then\n\t\t\tif
|
|
loadedModule == loadingPlaceholder then\n\t\t\t\treturn nil\n\t\t\tend\n\t\telse\n\t\t\tif
|
|
not modules[name] then\n\t\t\t\tif not superRequire then\n\t\t\t\t\tlocal identifier
|
|
= type(name) == 'string' and '\\\"' .. name .. '\\\"' or tostring(name)\n\t\t\t\t\terror('Tried
|
|
to require ' .. identifier .. ', but no such module has been registered')\n\t\t\t\telse\n\t\t\t\t\treturn
|
|
superRequire(name)\n\t\t\t\tend\n\t\t\tend\n\n\t\t\tloaded[name] = loadingPlaceholder\n\t\t\tloadedModule
|
|
= modules[name](require, loaded, register, modules)\n\t\t\tloaded[name] = loadedModule\n\t\tend\n\n\t\treturn
|
|
loadedModule\n\tend\n\n\treturn require, loaded, register, modules\nend)(nil)\n__bundle_register(\"__root\",
|
|
function(require, _LOADED, __bundle_register, __bundle_modules)\nrequire(\"accessories/AttachmentHelper\")\nend)\n__bundle_register(\"accessories/AttachmentHelper\",
|
|
function(require, _LOADED, __bundle_register, __bundle_modules)\nlocal searchLib
|
|
= require(\"util/SearchLib\")\nlocal fontColor, lastRejectedName\nlocal BACKGROUNDS
|
|
= {\n {\n title = \"Ancestral Knowledge\",\n url = \"http://cloud-3.steamusercontent.com/ugc/1915746489207287888/2F9F6F211ED0F98E66C9D35D93221E4C7FB6DD3C/\",\n
|
|
\ fontcolor = { 1, 1, 1 },\n icons = true\n },\n {\n title =
|
|
\"Astronomical Atlas\",\n url = \"http://cloud-3.steamusercontent.com/ugc/1754695853007989004/9153BC204FC707AE564ECFAC063A11CB8C2B5D1E/\",\n
|
|
\ fontcolor = { 1, 1, 1 },\n icons = true\n },\n {\n title =
|
|
\"Backpack\",\n url = \"http://cloud-3.steamusercontent.com/ugc/2018212896278691928/F55BEFFC2540109C6333179532F583B367FF2EBC/\",\n
|
|
\ fontcolor = { 0, 0, 0 },\n icons = false\n },\n {\n title =
|
|
\"Bewitching\",\n url = \"http://cloud-3.steamusercontent.com/ugc/2342503480966345423/F2070B5479C814F35780373966D77D91767A97CC/\",\n
|
|
\ fontcolor = { 1, 1, 1 },\n icons = false\n },\n {\n title =
|
|
\"Binder's Jar\",\n url = \"http://cloud-3.steamusercontent.com/ugc/2021606446228642191/4C149527851C1DBB3015F93DE91667937A3F91DD/\",\n
|
|
\ fontcolor = { 1, 1, 1 },\n icons = false\n },\n {\n title =
|
|
\"Crystallizer of Dreams\",\n url = \"http://cloud-3.steamusercontent.com/ugc/1915746489207280958/100F16441939E5E23818651D1EB5C209BF3125B9/\",\n
|
|
\ fontcolor = { 1, 1, 1 },\n icons = true\n },\n {\n title =
|
|
\"Diana Stanley\",\n url = \"http://cloud-3.steamusercontent.com/ugc/1754695635919071208/1AB7222850201630826BFFBA8F2BD0065E2D572F/\",\n
|
|
\ fontcolor = { 1, 1, 1 },\n icons = false\n },\n {\n title =
|
|
\"Gloria Goldberg\",\n url = \"http://cloud-3.steamusercontent.com/ugc/1754695635919102502/453D4426118C8A6DE2EA281184716E26CA924C84/\",\n
|
|
\ fontcolor = { 1, 1, 1 },\n icons = false\n },\n {\n title =
|
|
\"Ikiaq\",\n url = \"http://cloud-3.steamusercontent.com/ugc/2021606446228198966/5A408D8D760221DEA164E986B9BE1F79C4803071/\",\n
|
|
\ fontcolor = { 1, 1, 1 },\n icons = false\n },\n {\n title =
|
|
\"Katja Eastbank\",\n url = \"http://cloud-3.steamusercontent.com/ugc/2021606446228203475/62EEE12F4DB1EB80D79B087677459B954380215F/\",\n
|
|
\ fontcolor = { 1, 1, 1 },\n icons = false\n },\n {\n title =
|
|
\"Ravenous\",\n url = \"http://cloud-3.steamusercontent.com/ugc/2021606446228208075/EAC598A450BEE504A7FE179288F1FBBF7ABFA3E0/\",\n
|
|
\ fontcolor = { 0, 0, 0 },\n icons = false\n },\n {\n title =
|
|
\"Sefina Rousseau\",\n url = \"http://cloud-3.steamusercontent.com/ugc/1754695635919099826/3C3CBFFAADB2ACA9957C736491F470AE906CC953/\",\n
|
|
\ fontcolor = { 0, 0, 0 },\n icons = false\n },\n {\n title =
|
|
\"Stick to the Plan\",\n url = \"http://cloud-3.steamusercontent.com/ugc/2018214163838897493/8E38B96C5A8D703A59009A932432CBE21ABE63A2/\",\n
|
|
\ fontcolor = { 1, 1, 1 },\n icons = false\n },\n {\n title =
|
|
\"Subject 5U-21\",\n url = \"http://cloud-3.steamusercontent.com/ugc/2021606446228199363/CE43D58F37C9F48BDD6E6E145FE29BADEFF4DBC5/\",\n
|
|
\ fontcolor = { 1, 1, 1 },\n icons = false\n },\n {\n title =
|
|
\"Wooden Sledge\",\n url = \"http://cloud-3.steamusercontent.com/ugc/1750192233783143973/D526236AAE16BDBB98D3F30E27BAFC1D3E21F4AC/\",\n
|
|
\ fontcolor = { 0, 0, 0 },\n icons = false\n }\n}\n\n-- save state and
|
|
options to restore onLoad\nfunction onSave() return JSON.encode({ cardsInBag,
|
|
showIcons }) end\n\n-- load variables and create context menu\nfunction onLoad(savedData)\n
|
|
\ local loadedData = JSON.decode(savedData)\n cardsInBag = loadedData[1]\n
|
|
\ showIcons = loadedData[2]\n fontColor = getFontColor()\n recreateButtons()\n\n
|
|
\ self.addContextMenuItem(\"Select image\", selectImage)\n self.addContextMenuItem(\"Toggle
|
|
skill icons\", function(color)\n showIcons = not showIcons\n printToColor(\"Show
|
|
skill icons of cards: \" .. tostring(showIcons), color, \"White\")\n refresh()\n
|
|
\ end)\nend\n\n-- gets the font color based on background url\nfunction getFontColor()\n
|
|
\ local customInfo = self.getCustomObject()\n for i = 1, #BACKGROUNDS do\n if
|
|
BACKGROUNDS[i].url == customInfo.diffuse then\n return BACKGROUNDS[i].fontcolor\n
|
|
\ end\n end\n return { 1, 1, 1 }\nend\n\n-- attempt to load image from below
|
|
card when dropped\nfunction onDrop(playerColor)\n local pos = self.getPosition():setAt(\"y\",
|
|
2)\n local searchResult = searchLib.belowPosition(pos, \"isCard\")\n if #searchResult
|
|
== 0 then return end\n local syncName = searchResult[1].getName()\n\n -- remove
|
|
level information from syncName\n syncName = syncName:gsub(\"%s%(%d%)\", \"\")\n\n
|
|
\ -- loop through background table\n for _, bgInfo in ipairs(BACKGROUNDS) do\n
|
|
\ if bgInfo.title == syncName then\n printToColor(\"Background for '\"
|
|
.. syncName .. \"' loaded!\", playerColor, \"Green\")\n showIcons = bgInfo.icons\n
|
|
\ updateImage(bgInfo.url)\n return\n end\n end\n printToColor(\"Didn't
|
|
find background for '\" .. syncName .. \"'!\", playerColor, \"Orange\")\nend\n\n--
|
|
called by context menu to change background image\nfunction selectImage(color)\n
|
|
\ -- generate list of options\n local options = {}\n for i = 1, #BACKGROUNDS
|
|
do\n options[i] = BACKGROUNDS[i].title\n end\n\n -- prompt user to select
|
|
option\n Player[color].showOptionsDialog(\"Select image:\", options, 1, function(_,
|
|
optionIndex)\n showIcons = BACKGROUNDS[optionIndex].icons\n updateImage(BACKGROUNDS[optionIndex].url)\n
|
|
\ end)\nend\n\n-- sets background to the provided URL\nfunction updateImage(url)\n
|
|
\ self.script_state = JSON.encode({ cardsInBag, showIcons })\n local customInfo
|
|
= self.getCustomObject()\n customInfo.diffuse = url\n self.setCustomObject(customInfo)\n
|
|
\ self.reload()\nend\n\n-- only allow cards to enter, split decks and reject other
|
|
objects\nfunction tryObjectEnter(object)\n -- block repeated collisions\n if
|
|
object.getName() == lastRejectedName then return end\n\n if object.type == \"Deck\"
|
|
then\n local pos = self.getPosition()\n for i = 1, #object.getObjects()
|
|
do\n local card = object.takeObject({ position = pos + Vector(0, 0.1 * i,
|
|
0), smooth = false })\n findCard(card.getGUID(), card.getName(), card.getGMNotes())\n
|
|
\ self.putObject(card)\n end\n recreateButtons()\n return false\n
|
|
\ elseif object.type ~= \"Card\" then\n broadcastToAll(\"The 'Attachment Helper'
|
|
only supports cards.\", \"Orange\")\n lastRejectedName = object.getName()\n
|
|
\ Wait.time(function() lastRejectedName = nil end, 1)\n return false\n else\n
|
|
\ findCard(object.getGUID(), object.getName(), object.getGMNotes())\n recreateButtons()\n
|
|
\ return true\n end\nend\n\n-- removes leaving cards from the \"cardInBag\"
|
|
table\nfunction onObjectLeaveContainer(container, object)\n if container == self
|
|
then\n local guid = object.getGUID()\n local found = false\n for i, card
|
|
in ipairs(cardsInBag) do\n if card.guid == guid then\n table.remove(cardsInBag,
|
|
i)\n found = true\n break\n end\n end\n\n if found ~=
|
|
true then\n local name = object.getName()\n for i, card in ipairs(cardsInBag)
|
|
do\n if card.name == name then\n table.remove(cardsInBag, i)\n
|
|
\ break\n end\n end\n end\n recreateButtons()\n end\nend\n\n--
|
|
refreshes displayed buttons based on contained cards\nfunction refresh()\n cardsInBag
|
|
= {}\n for _, object in ipairs(self.getObjects()) do\n findCard(object.guid,
|
|
object.name, object.gm_notes)\n end\n recreateButtons()\nend\n\n-- gets cost
|
|
and icons for a card\nfunction findCard(guid, name, GMNotes)\n local icons =
|
|
{}\n local metadata = JSON.decode(GMNotes) or {}\n local buttonLabel = name
|
|
or \"unnamed\"\n\n if metadata.cost then\n buttonLabel = \"[\" .. metadata.cost
|
|
.. \"] \" .. buttonLabel\n end\n\n if showIcons then\n if metadata ~= {}
|
|
then\n icons[1] = metadata.wildIcons\n icons[2] = metadata.willpowerIcons\n
|
|
\ icons[3] = metadata.intellectIcons\n icons[4] = metadata.combatIcons\n
|
|
\ icons[5] = metadata.agilityIcons\n end\n\n local IconTypes = { \"Wild\",
|
|
\"Willpower\", \"Intellect\", \"Combat\", \"Agility\" }\n local found = false\n
|
|
\ for i = 1, 5 do\n if icons[i] ~= nil and icons[i] ~= \"\" then\n if
|
|
found == false then\n buttonLabel = buttonLabel .. \"\\n\"\n found
|
|
= true\n else\n buttonLabel = buttonLabel .. \" \"\n end\n
|
|
\ buttonLabel = buttonLabel .. IconTypes[i] .. \": \" .. icons[i]\n end\n
|
|
\ end\n end\n table.insert(cardsInBag, { buttonLabel = buttonLabel, hasIcons
|
|
= (#icons > 0), name = name, guid = guid })\nend\n\n-- recreates buttons with
|
|
up-to-date labels\nfunction recreateButtons()\n self.clearButtons()\n local
|
|
verticalPosition = 1.65\n\n -- create buttons for the last 7 cards that entered\n
|
|
\ for i = #cardsInBag, 1, -1 do\n if (i + 7) == #cardsInBag then\n printToAll(\"Only
|
|
displaying buttons for the last 7 cards.\", \"Orange\")\n break\n end\n\n
|
|
\ local card = cardsInBag[i]\n\n -- click function\n local funcName =
|
|
\"removeCard\" .. card.guid\n self.setVar(funcName, function() removeCard(card.guid)
|
|
end)\n\n -- font size\n local fontSize = 100\n if card.hasIcons or string.len(card.buttonLabel)
|
|
> 20 then\n fontSize = 75\n end\n\n -- button creation\n self.createButton({\n
|
|
\ label = card.buttonLabel,\n click_function = funcName,\n function_owner
|
|
= self,\n position = { 0, -0.1, verticalPosition },\n height =
|
|
200,\n width = 1200,\n font_size = fontSize\n })\n
|
|
\ verticalPosition = verticalPosition - 0.485\n end\n\n local countLabel =
|
|
#cardsInBag\n local fontSize = 250\n if #cardsInBag == 0 then\n countLabel
|
|
= \"Attachment Helper\"\n fontSize = 150\n end\n\n self.createButton({\n
|
|
\ label = tostring(countLabel),\n click_function = \"none\",\n function_owner
|
|
= self,\n position = { 0, -0.1, -1.7 },\n height = 0,\n width
|
|
\ = 0,\n font_size = fontSize,\n font_color = fontColor\n
|
|
\ })\nend\n\n-- click-function for buttons to take a card out of the bag\nfunction
|
|
removeCard(cardGUID)\n self.takeObject({\n guid = cardGUID,\n rotation
|
|
= self.getRotation(),\n position = self.getPosition() + Vector(0, 0.25, 0),\n
|
|
\ callback_function = function(obj) obj.resting = true end\n })\nend\nend)\n__bundle_register(\"util/SearchLib\",
|
|
function(require, _LOADED, __bundle_register, __bundle_modules)\ndo\n local SearchLib
|
|
= {}\n local filterFunctions = {\n isActionToken = function(x) return x.getDescription()
|
|
== \"Action Token\" end,\n isCard = function(x) return x.type == \"Card\" end,\n
|
|
\ isDeck = function(x) return x.type == \"Deck\" end,\n isCardOrDeck = function(x)
|
|
return x.type == \"Card\" or x.type == \"Deck\" end,\n isClue = function(x)
|
|
return x.memo == \"clueDoom\" and x.is_face_down == false end,\n isTileOrToken
|
|
= function(x) return x.type == \"Tile\" end\n }\n\n -- performs the actual search
|
|
and returns a filtered list of object references\n ---@param pos tts__Vector
|
|
Global position\n ---@param rot? tts__Vector Global rotation\n ---@param size
|
|
table Size\n ---@param filter? string Name of the filter function\n ---@param
|
|
direction? table Direction (positive is up)\n ---@param maxDistance? number Distance
|
|
for the cast\n local function returnSearchResult(pos, rot, size, filter, direction,
|
|
maxDistance)\n local filterFunc\n if filter then\n filterFunc = filterFunctions[filter]\n
|
|
\ end\n local searchResult = Physics.cast({\n origin = pos,\n
|
|
\ direction = direction or { 0, 1, 0 },\n orientation = rot or {
|
|
0, 0, 0 },\n type = 3,\n size = size,\n max_distance
|
|
= maxDistance or 0\n })\n\n -- filtering the result\n local objList =
|
|
{}\n for _, v in ipairs(searchResult) do\n if not filter or filterFunc(v.hit_object)
|
|
then\n table.insert(objList, v.hit_object)\n end\n end\n return
|
|
objList\n end\n\n -- searches the specified area\n SearchLib.inArea = function(pos,
|
|
rot, size, filter)\n return returnSearchResult(pos, rot, size, filter)\n end\n\n
|
|
\ -- searches the area on an object\n SearchLib.onObject = function(obj, filter)\n
|
|
\ pos = obj.getPosition()\n size = obj.getBounds().size:setAt(\"y\", 1)\n
|
|
\ return returnSearchResult(pos, _, size, filter)\n end\n\n -- searches the
|
|
specified position (a single point)\n SearchLib.atPosition = function(pos, filter)\n
|
|
\ size = { 0.1, 2, 0.1 }\n return returnSearchResult(pos, _, size, filter)\n
|
|
\ end\n\n -- searches below the specified position (downwards until y = 0)\n
|
|
\ SearchLib.belowPosition = function(pos, filter)\n direction = { 0, -1, 0
|
|
}\n maxDistance = pos.y\n return returnSearchResult(pos, _, size, filter,
|
|
direction, maxDistance)\n end\n\n return SearchLib\nend\nend)\nreturn __bundle_require(\"__root\")"
|
|
LuaScriptState: '[[],true]'
|
|
MaterialIndex: -1
|
|
MeasureMovement: false
|
|
MeshIndex: -1
|
|
Name: Custom_Model_Bag
|
|
Nickname: Attachment Helper
|
|
Number: 0
|
|
Snap: true
|
|
Sticky: true
|
|
Tags:
|
|
- Asset
|
|
Tooltip: true
|
|
Transform:
|
|
posX: 19.228
|
|
posY: 3.822
|
|
posZ: -19.636
|
|
rotX: 0
|
|
rotY: 270
|
|
rotZ: 0
|
|
scaleX: 0.8
|
|
scaleY: 1
|
|
scaleZ: 0.8
|
|
Value: 0
|
|
XmlUI: ''
|
|
Description: Provides card-sized bags that are useful for cards that are attached
|
|
facedown (e.g. Backpack).
|
|
DragSelectable: true
|
|
GMNotes: ''
|
|
GUID: 7f4976
|
|
Grid: true
|
|
GridProjection: false
|
|
Hands: false
|
|
HideWhenFaceDown: false
|
|
IgnoreFoW: false
|
|
LayoutGroupSortIndex: 0
|
|
Locked: false
|
|
LuaScript: ''
|
|
LuaScriptState: ''
|
|
MaterialIndex: -1
|
|
MeasureMovement: false
|
|
MeshIndex: -1
|
|
Name: Infinite_Bag
|
|
Nickname: Attachment Helper
|
|
Snap: true
|
|
Sticky: true
|
|
Tooltip: true
|
|
Transform:
|
|
posX: 27.68
|
|
posY: 4.47
|
|
posZ: -31.03
|
|
rotX: 0
|
|
rotY: 0
|
|
rotZ: 0
|
|
scaleX: 1
|
|
scaleY: 1
|
|
scaleZ: 1
|
|
Value: 0
|
|
XmlUI: ''
|