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.' DragSelectable: true GMNotes: '' GUID: d45664 Grid: true GridProjection: false Hands: false HideWhenFaceDown: false IgnoreFoW: false LayoutGroupSortIndex: 0 Locked: false LuaScript: "local OPTION_TEXT = {\n \"Ancestral Knowledge\",\n \"Astronomical\ \ Atlas\",\n \"Crystallizer of Dreams\",\n \"Diana Stanley\",\n \"Gloria Goldberg\"\ ,\n \"Sefina Rousseau\",\n \"Wooden Sledge\"\n}\n\nlocal IMAGE_LIST = {\n --\ \ Ancestral Knowledge\n \"http://cloud-3.steamusercontent.com/ugc/1915746489207287888/2F9F6F211ED0F98E66C9D35D93221E4C7FB6DD3C/\"\ ,\n -- Astronomical Atlas\n \"http://cloud-3.steamusercontent.com/ugc/1754695853007989004/9153BC204FC707AE564ECFAC063A11CB8C2B5D1E/\"\ ,\n -- Crystallizer of Dreams\n \"http://cloud-3.steamusercontent.com/ugc/1915746489207280958/100F16441939E5E23818651D1EB5C209BF3125B9/\"\ ,\n -- Diana Stanley\n \"http://cloud-3.steamusercontent.com/ugc/1754695635919071208/1AB7222850201630826BFFBA8F2BD0065E2D572F/\"\ ,\n -- Gloria Goldberg\n \"http://cloud-3.steamusercontent.com/ugc/1754695635919102502/453D4426118C8A6DE2EA281184716E26CA924C84/\"\ ,\n -- Sefina Rousseau\n \"http://cloud-3.steamusercontent.com/ugc/1754695635919099826/3C3CBFFAADB2ACA9957C736491F470AE906CC953/\"\ ,\n -- Wooden Sledge\n \"http://cloud-3.steamusercontent.com/ugc/1750192233783143973/D526236AAE16BDBB98D3F30E27BAFC1D3E21F4AC/\"\ \n}\n\n-- save state and options to restore onLoad\nfunction onSave() return JSON.encode({\ \ cardsInBag, showCost, showIcons }) end\n\n-- load variables and create context\ \ menu\nfunction onLoad(savedData)\n local loadedData = JSON.decode(savedData)\n\ \ cardsInBag = loadedData[1] or {}\n showCost = loadedData[2]\ \ or true\n showIcons = loadedData[3] or true\n\n recreateButtons()\n\ \n self.addContextMenuItem(\"Select image\", selectImage)\n self.addContextMenuItem(\"\ Toggle cost\", function(color)\n showCost = not showCost\n printToColor(\"\ Show cost of cards: \" .. tostring(showCost), color, \"White\")\n refresh()\n\ \ end)\n\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)\n\n self.addContextMenuItem(\"\ More Information\", function()\n printToAll(\"------------------------------\"\ , \"White\")\n printToAll(\"Attachment Helper by Chr1Z\", \"Orange\")\n \ \ printToAll(\"original by bankey\", \"White\")\n end)\nend\n\nfunction selectImage(color)\n\ \ Player[color].showOptionsDialog(\"Select image:\", OPTION_TEXT, 1, function(_,\ \ option_index)\n local customInfo = self.getCustomObject()\n customInfo.diffuse\ \ = IMAGE_LIST[option_index]\n self.setCustomObject(customInfo)\n self.reload()\n\ \ end)\nend\n\n-- called for every card that enters\nfunction onObjectEnterContainer(container,\ \ object)\n if container == self then\n if object.tag ~= \"Card\" then\n \ \ broadcastToAll(\"The 'Attachment Helper' is meant to be used for single\ \ cards.\", \"White\")\n else\n findCard(object.getGUID(), object.getName(),\ \ object.getGMNotes())\n end\n -- TODO: implement splitting of decks that\ \ get thrown in here\n recreateButtons()\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.id\ \ == 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 cost =\ \ \"\"\n local icons = {}\n local metadata = {}\n local displayName = name\n\ \n if displayName == nil or displayName == \"\" then displayName = \"unnamed\"\ \ end\n if showCost or showIcons then metadata = JSON.decode(GMNotes) end\n\n\ \ if showCost then\n if GMNotes ~= \"\" then cost = metadata.cost end\n \ \ if cost == nil or cost == \"\" then cost = \"\u2013\" end\n displayName\ \ = \"[\" .. cost .. \"] \" .. displayName\n end\n\n if showIcons then\n \ \ if GMNotes ~= \"\" 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 displayName\ \ = displayName .. \"\\n\" .. IconTypes[i] .. \": \" .. icons[i]\n found\ \ = true\n else\n displayName = displayName .. \" \" .. IconTypes[i]\ \ .. \": \" .. icons[i]\n end\n end\n end\n end\n table.insert(cardsInBag,\ \ { name = name, displayName = displayName, id = guid })\nend\n\n-- recreates\ \ buttons with up-to-date labels\nfunction recreateButtons()\n self.clearButtons()\n\ \ local verticalPosition = 1.65\n\n for _, card in ipairs(cardsInBag) do\n \ \ local id = card.id\n local funcName = \"removeCard\" .. id\n self.setVar(funcName,\ \ function() removeCard(id) end)\n self.createButton({\n label \ \ = card.displayName,\n click_function = funcName,\n function_owner\ \ = self,\n position = { 0, 0, verticalPosition },\n height \ \ = 200,\n width = 1200,\n font_size = string.len(card.displayName)\ \ > 20 and 75 or 100\n })\n verticalPosition = verticalPosition - 0.5\n\ \ end\n\n local countLabel = \"Attachment\\nHelper\"\n if #cardsInBag ~= 0\ \ then countLabel = #cardsInBag end\n\n self.createButton({\n label \ \ = countLabel,\n click_function = \"none\",\n function_owner = self,\n\ \ position = { 0, 0, -1.35 },\n height = 0,\n width \ \ = 0,\n font_size = 225,\n font_color = { 1, 1, 1 }\n })\n\ end\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" LuaScriptState: '[[],true,true]' MaterialIndex: -1 MeasureMovement: false MeshIndex: -1 Name: Custom_Model_Bag Nickname: Attachment Helper Number: 0 Snap: true Sticky: true Tags: - Asset - scesetup_memory_object Tooltip: true Transform: posX: 19.228 posY: 3.822 posZ: -19.636 rotX: 0 rotY: 270 rotZ: 359 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: ''