Merge pull request #81 from argonui/doom-and-clue-counters

Doom Counter Option UI // Clue Counter clean up
This commit is contained in:
Chr1Z 2022-12-12 10:17:10 +01:00 committed by GitHub
commit 6d11bf56fb
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
11 changed files with 307 additions and 405 deletions

View File

@ -56,7 +56,7 @@
"BlockRectangle.612072",
"Cluetokens.11e0cf",
"Doomtokens.b015d8",
"AgendaDeck.85c4c6",
"DoomCounter.85c4c6",
"Custom_Tile.2eca7c",
"Custom_Tile.fb09d4",
"3DText.65eb7e",
@ -208,7 +208,7 @@
"ReturntoTheCircleUndone.757324",
"Playermat4Red.0840d5",
"Playermat3Green.383d8b",
"MiscDoominplay.652ff3",
"OtherDoominPlay.652ff3",
"Playermat1White.8b081b",
"Playermat2Orange.bd0ff4",
"CustomDataHelper.2547b3",

View File

@ -20,8 +20,8 @@
},
{
"Position": {
"x": -5.316,
"y": 1.588,
"x": -5.3,
"y": 1.583,
"z": 0.378
}
},
@ -522,8 +522,8 @@
},
{
"Position": {
"x": -5.369,
"y": 1.587,
"x": -5.3,
"y": 1.583,
"z": -5.1
}
},
@ -4204,4 +4204,4 @@
"z": 14.5
}
}
]
]

View File

@ -33,17 +33,17 @@
"IgnoreFoW": false,
"LayoutGroupSortIndex": 0,
"Locked": true,
"LuaScript": "require(\"core/AgendaDeck\")",
"LuaScriptState": "0",
"LuaScript": "require(\"core/DoomCounter\")",
"LuaScriptState": "[0,{\"Agenda\":true,\"Playarea\":true,\"Playermats\":true}]",
"MeasureMovement": false,
"Name": "Custom_Token",
"Nickname": "Agenda Deck",
"Nickname": "Doom Counter",
"Snap": true,
"Sticky": true,
"Tooltip": false,
"Tooltip": true,
"Transform": {
"posX": -5.316,
"posY": 1.639,
"posX": -5.3,
"posY": 1.633,
"posZ": 0.378,
"rotX": 0,
"rotY": 270,
@ -53,5 +53,5 @@
"scaleZ": 0.42
},
"Value": 0,
"XmlUI": ""
}
"XmlUI_path": "DoomCounter.85c4c6.xml"
}

View File

@ -0,0 +1,25 @@
<Defaults>
<Panel rotation="0 0 180"></Panel>
<ToggleButton class="optionButton" colors="#50e610|#f2d82e|#f2d82e" fontSize="45" isOn="0" textAlignment="MiddleLeft" padding="30 30 0 0"></ToggleButton>
</Defaults>
<Panel id="Buttons" offsetXY="0 285">
<TableLayout height="150" width="500" cellSpacing="10">
<Row>
<Cell columnSpan="3">
<Button onClick="startReset" fontSize="80">Reset</Button>
</Cell>
<Cell>
<ToggleButton onClick="toggleOptions" fontSize="55"></ToggleButton>
</Cell>
</Row>
</TableLayout>
</Panel>
<Panel id="Options" offsetXY="0 535" active="false" showAnimation="Grow" hideAnimation="Shrink">
<VerticalLayout height="300" width="500" spacing="10" childAlignment="MiddleCenter">
<ToggleButton class="optionButton" id="optionAgenda" onClick="optionClick(Agenda)">Doom on Agenda</ToggleButton>
<ToggleButton class="optionButton" id="optionPlayarea" onClick="optionClick(Playarea)">Doom in Playarea</ToggleButton>
<ToggleButton class="optionButton" id="optionPlayermats" onClick="optionClick(Playermats)">Doom on Playermats</ToggleButton>
</VerticalLayout>
</Panel>

View File

@ -34,16 +34,16 @@
"LayoutGroupSortIndex": 0,
"Locked": true,
"LuaScript": "require(\"core/MasterClueCounter\")",
"LuaScriptState": "[true,0]",
"LuaScriptState": "",
"MeasureMovement": false,
"Name": "Custom_Token",
"Nickname": "Master Clue Counter\n",
"Snap": true,
"Sticky": true,
"Tooltip": false,
"Tooltip": true,
"Transform": {
"posX": -5.369,
"posY": 1.557,
"posX": -5.3,
"posY": 1.633,
"posZ": -5.1,
"rotX": 0,
"rotY": 270,
@ -54,4 +54,4 @@
},
"Value": 0,
"XmlUI": ""
}
}

View File

@ -34,10 +34,10 @@
"LayoutGroupSortIndex": 0,
"Locked": true,
"LuaScript": "require(\"core/DoomInPlayCounter\")",
"LuaScriptState": "[true,0]",
"LuaScriptState": "",
"MeasureMovement": false,
"Name": "Custom_Token",
"Nickname": "Misc. Doom in play",
"Nickname": "Other Doom in Play",
"Snap": true,
"Sticky": true,
"Tags": [
@ -45,16 +45,16 @@
],
"Tooltip": true,
"Transform": {
"posX": -6.185,
"posY": 1.56,
"posZ": 1.396,
"posX": -5.3,
"posY": 1.633,
"posZ": 1.8,
"rotX": 0,
"rotY": 270,
"rotZ": 0,
"scaleX": 0.23,
"scaleX": 0.25,
"scaleY": 1,
"scaleZ": 0.23
"scaleZ": 0.25
},
"Value": 0,
"XmlUI": ""
}
}

View File

@ -1,60 +0,0 @@
-- Doom Counter with Print
-- original by: -
-- changed by: Chr1Z
-- description: Clickable counter for doom on the agenda, changing the value prints the new value, reset button added
information = {
version = "1.4",
last_updated = "12.11.2022"
}
function onSave() return JSON.encode(val) end
function onLoad(saved_data)
if saved_data ~= "" then
val = JSON.decode(saved_data)
else
val = 0
end
self.createButton({
label = tostring(val),
click_function = "addOrSubtract",
function_owner = self,
position = { 0, 0.06, 0 },
height = 800,
width = 800,
font_size = 650,
scale = { 1.5, 1.5, 1.5 },
font_color = { 1, 1, 1, 95 },
color = { 0, 0, 0, 0 }
})
self.createButton({
label = "Reset",
click_function = "setToZero",
function_owner = self,
position = { 0, -0.04, 2.7 },
height = 600,
width = 1250,
font_size = 425
})
self.addContextMenuItem("More Information", function()
printToAll("------------------------------", "White")
printToAll("Doom Counter v" .. information["version"] .. " by Chr1Z", "Orange")
printToAll("last updated: " .. information["last_updated"], "White")
end)
end
function setToZero() updateVal(0) end
function addOrSubtract(_, _, alt_click)
local new_value = math.min(math.max(val + (alt_click and -1 or 1), 0), 99)
if val ~= new_value then updateVal(new_value) end
end
function updateVal(number)
val = number or 0
self.editButton({ index = 0, label = tostring(val) })
printToAll("Doom on agenda set to: " .. val)
end

View File

@ -0,0 +1,79 @@
local optionsVisible = false
local options = {
Agenda = true,
Playarea = true,
Playermats = true
}
val = 0
-- save current value and options
function onSave() return JSON.encode({ val, options }) end
function onLoad(savedData)
if savedData ~= "" then
local loadedData = JSON.decode(savedData)
val = loadedData[1]
options = loadedData[2]
-- restore state for option panel
for key, bool in pairs(options) do
self.UI.setAttribute("option" .. key, "isOn", not bool)
end
end
self.createButton({
label = tostring(val),
click_function = "addOrSubtract",
function_owner = self,
position = { 0, 0.06, 0 },
height = 800,
width = 800,
font_size = 650,
scale = { 1.5, 1.5, 1.5 },
font_color = { 1, 1, 1, 95 },
color = { 0, 0, 0, 0 }
})
end
-- called by the invisible button to change displayed value
function addOrSubtract(_, _, isRightClick)
local newVal = math.min(math.max(val + (isRightClick and -1 or 1), 0), 99)
if val ~= newVal then
updateVal(newVal)
end
end
function updateVal(number)
val = number or 0
self.editButton({ index = 0, label = tostring(val) })
printToAll("Doom on agenda set to: " .. val)
end
-- called by "Reset" button to remove doom
function startReset()
if options.Agenda then
updateVal(0)
end
-- call the "Doom-in-Play"-counter
local DoomInPlayCounter = getObjectFromGUID("652ff3")
if DoomInPlayCounter then
DoomInPlayCounter.call("removeDoom", options)
end
end
-- XML UI functions
function optionClick(_, optionName)
options[optionName] = not options[optionName]
printToAll("Doom removal of " .. optionName .. (options[optionName] and " enabled" or " disabled"))
end
function toggleOptions()
optionsVisible = not optionsVisible
if optionsVisible then
self.UI.show("Options")
else
self.UI.hide("Options")
end
end

View File

@ -1,104 +1,106 @@
-- Doom-in-Play Counter
-- made by: Chr1Z
-- description: counts the doom tokens in play periodically (excluding the agenda), ignores objects with specified tag
information = {
version = "1.1",
last_updated = "12.11.2022"
}
-- common parameters
local castParameters = {}
castParameters.direction = { 0, 1, 0 }
castParameters.type = 3
castParameters.max_distance = 0
local zone = getObjectFromGUID("a2f932")
local doom_url = "https://i.imgur.com/EoL7yaZ.png"
local zone
local doomURL = "https://i.imgur.com/EoL7yaZ.png"
local IGNORE_TAG = "DoomCounter_ignore"
-- playermats 1 to 4
local originAndSize = {
{ origin = { -55, 1.6, 16.5 }, size = { 12, 1, 25 } },
{ origin = { -55, 1.6, -16.5 }, size = { 12, 1, 25 } },
{ origin = { -25, 1.6, 27 }, size = { 25, 1, 12 } },
{ origin = { -25, 1.6, -27 }, size = { 25, 1, 12 } }
{ origin = { -55, 1.6, 16.5 }, size = { 12, 1, 25 } },
{ origin = { -55, 1.6, -16.5 }, size = { 12, 1, 25 } },
{ origin = { -25, 1.6, 27 }, size = { 25, 1, 12 } },
{ origin = { -25, 1.6, -27 }, size = { 25, 1, 12 } }
}
-- create button, context menu and start loop
function onLoad()
self.createButton({
label = tostring(0),
click_function = "moreInformation",
function_owner = self,
position = { 0, 0.06, 0 },
height = 600,
width = 1000,
scale = { 1.5, 1.5, 1.5 },
font_size = 600,
font_color = { 1, 1, 1, 100 },
color = { 0, 0, 0, 0 }
})
self.createButton({
label = tostring(0),
click_function = "none",
function_owner = self,
position = { 0, 0.06, 0 },
height = 0,
width = 0,
scale = { 1.5, 1.5, 1.5 },
font_size = 600,
font_color = { 1, 1, 1, 100 },
color = { 0, 0, 0, 0 }
})
-- context menu
self.addContextMenuItem("More Information", moreInformation)
self.addContextMenuItem("Remove Doom", function()
Wait.stop(loopID)
removeDoom = true
countDoom()
Wait.time(function()
removeDoom = false
loopID = Wait.time(countDoom, 2, -1)
end, 2)
end)
loopID = Wait.time(countDoom, 2, -1)
end
function moreInformation()
printToAll("------------------------------", "White")
printToAll("Doom-in-Play Counter v" .. information["version"] .. " by Chr1Z", "Orange")
printToAll("last updated: " .. information["last_updated"], "White")
printToAll("Automatically counts the doom in play (exluding the agenda and objects with the ignore tag).", "Green")
printToAll("ignore tag: " .. IGNORE_TAG, "White")
zone = getObjectFromGUID("a2f932")
loopID = Wait.time(countDoom, 2, -1)
end
-- main function
function countDoom()
local doom = 0
for i = 1, 5 do doom = doom + search(i) end
self.editButton({ index = 0, label = tostring(doom) })
local doom = 0
for i = 1, 5 do doom = doom + search(i) end
self.editButton({ index = 0, label = tostring(doom) })
end
-- searches playermats (num = 1-4) or the scripting zone (num = 5)
function search(num)
local val = 0
if num == 5 then
for _, obj in ipairs(zone.getObjects()) do
val = val + isDoom(obj)
end
else
castParameters.origin = originAndSize[num].origin
castParameters.size = originAndSize[num].size
for _, obj in ipairs(Physics.cast(castParameters)) do
val = val + isDoom(obj.hit_object)
end
local val = 0
if num == 5 then
for _, obj in ipairs(zone.getObjects()) do
val = val + isDoom(obj)
end
return val
else
castParameters.origin = originAndSize[num].origin
castParameters.size = originAndSize[num].size
for _, obj in ipairs(Physics.cast(castParameters)) do
val = val + isDoom(obj.hit_object)
end
end
return val
end
-- checks an object for the doom image and gets quantity (for stacks)
function isDoom(obj)
if (obj.is_face_down and obj.getCustomObject().image_bottom == doom_url) or
(obj.name == "Custom_Token" and obj.getCustomObject().image == doom_url) then
if not obj.hasTag(IGNORE_TAG) then
if removeDoom then
obj.destruct()
return 0
else
return math.abs(obj.getQuantity())
end
end
if (obj.is_face_down and obj.getCustomObject().image_bottom == doomURL) or
(obj.name == "Custom_Token" and obj.getCustomObject().image == doomURL) then
if not obj.hasTag(IGNORE_TAG) then
return math.abs(obj.getQuantity())
end
return 0
end
return 0
end
-- removes doom from playermats / playarea
function removeDoom(options)
local trashCan = getObjectFromGUID("70b9f6")
local count = 0
if options.Playermats then
for i = 1, 4 do
castParameters.origin = originAndSize[i].origin
castParameters.size = originAndSize[i].size
for _, obj in ipairs(Physics.cast(castParameters)) do
local obj = obj.hit_object
local amount = isDoom(obj)
if amount > 0 then
trashCan.putObject(obj)
count = count + amount
end
end
end
broadcastToAll(count .. " doom removed from Playermats.", "White")
end
local count = 0
if options.Playarea then
for _, obj in ipairs(zone.getObjects()) do
local amount = isDoom(obj)
if amount > 0 then
trashCan.putObject(obj)
count = count + amount
end
end
broadcastToAll(count .. " doom removed from Playarea.", "White")
end
end

View File

@ -1,161 +1,46 @@
MIN_VALUE = -99
MAX_VALUE = 999
local clueCounters = {}
local clueCounterGUIDS = {
"37be78",
"1769ed",
"032300",
"d86b7c"
}
function onload(saved_data)
light_mode = false
val = 0
function onLoad()
self.createButton({
label = "0",
click_function = "removeAllPlayerClues",
tooltip = "Click here to remove all Clues from playermats",
function_owner = self,
position = { 0, 0.06, 0 },
height = 900,
width = 900,
scale = { 1.5, 1.5, 1.5 },
font_size = 600,
font_color = { 1, 1, 1, 100 },
color = { 0, 0, 0, 0 }
})
if saved_data ~= "" then
local loaded_data = JSON.decode(saved_data)
light_mode = loaded_data[1]
val = loaded_data[2]
end
p1ClueCounter = getObjectFromGUID("37be78")
p2ClueCounter = getObjectFromGUID("1769ed")
p3ClueCounter = getObjectFromGUID("032300")
p4ClueCounter = getObjectFromGUID("d86b7c")
-- loading object references to the counting bowls via GUID
for i = 1, 4 do
clueCounters[i] = getObjectFromGUID(clueCounterGUIDS[i])
end
timerID = self.getGUID()..math.random(9999999999999)
Timer.create({
identifier=timerID,
function_name="totalCounters", function_owner=self,
repetitions=0, delay=1
})
createAll()
end
function loadPlayerCounters()
p1ClueCounter = getObjectFromGUID("37be78")
p2ClueCounter = getObjectFromGUID("1769ed")
p3ClueCounter = getObjectFromGUID("032300")
p4ClueCounter = getObjectFromGUID("d86b7c")
end
function totalCounters()
if p1ClueCounter == nil or p2ClueCounter == nil or p3ClueCounter == nil or p4ClueCounter == nil then
loadPlayerCounters()
end
local p1ClueCount = p1ClueCounter.getVar("exposedValue")
local p2ClueCount = p2ClueCounter.getVar("exposedValue")
local p3ClueCount = p3ClueCounter.getVar("exposedValue")
local p4ClueCount = p4ClueCounter.getVar("exposedValue")
val = tonumber(p1ClueCount) + tonumber(p2ClueCount) + tonumber(p3ClueCount) + tonumber(p4ClueCount)
updateVal()
updateSave()
end
function updateSave()
local data_to_save = {light_mode, val}
saved_data = JSON.encode(data_to_save)
self.script_state = saved_data
end
function createAll()
s_color = {0.5, 0.5, 0.5, 95}
if light_mode then
f_color = {1,1,1,95}
else
f_color = {0,0,0,100}
end
self.createButton({
label=tostring(val),
click_function="removeAllPlayerClues",
function_owner=self,
position={0,0.05,0},
height=600,
width=1000,
alignment = 3,
tooltip = "Click button to remove all clues from all investigators",
scale={x=1.5, y=1.5, z=1.5},
font_size=600,
font_color=f_color,
color={0,0,0,0}
})
if light_mode then
lightButtonText = "[ Set dark ]"
else
lightButtonText = "[ Set light ]"
end
end
function removeAll()
self.removeInput(0)
self.removeInput(1)
self.removeButton(0)
self.removeButton(1)
self.removeButton(2)
loopID = Wait.time(sumClues, 2, -1)
end
-- removes all player clues by calling the respective function from the counting bowls
function removeAllPlayerClues()
p1ClueCounter.call("removeAllClues")
p2ClueCounter.call("removeAllClues")
p3ClueCounter.call("removeAllClues")
p4ClueCounter.call("removeAllClues")
end
function reloadAll()
removeAll()
createAll()
updateSave()
end
function swap_fcolor(_obj, _color, alt_click)
light_mode = not light_mode
reloadAll()
end
function swap_align(_obj, _color, alt_click)
center_mode = not center_mode
reloadAll()
end
function editName(_obj, _string, value)
self.setName(value)
setTooltips()
end
function updateVal()
self.editButton({
index = 0,
label = tostring(val),
})
end
function reset_val()
val = 0
updateVal()
updateSave()
end
function setTooltips()
self.editInput({
index = 0,
value = self.getName(),
tooltip = "Click button to remove all clues from all investigators"
})
self.editButton({
index = 0,
value = tostring(val),
})
end
function null()
end
function keepSample(_obj, _string, value)
reloadAll()
end
function onDestroy()
if timerID and type(timerID) == 'object' then
Timer.destroy(timerID)
for i = 1, 4 do
clueCounters[i].call("removeAllClues")
end
end
-- gets the counted values from the counting bowls and sums them up
function sumClues()
local count = 0
for i = 1, 4 do
count = count + tonumber(clueCounters[i].getVar("exposedValue"))
end
self.editButton({ index = 0, label = tostring(count) })
end

View File

@ -1,91 +1,69 @@
--Counting Bowl by MrStump
--Table of items which can be counted in this Bowl
--Each entry has 2 things to enter
--a name (what is in the name field of that object)
--a value (how much it is worth)
--A number in the items description will override the number entry in this table
validCountItemList = {
["Clue"] = 1,
[""] = 1,
--["Name3"] = 2,
--["Name4"] = 31,
--Add more entries as needed
--Remove the -- from before a line for the script to use it
-- Table of items which can be counted in this Bowl
-- Each entry has 2 things to enter
-- a name (what is in the name field of that object)
-- a value (how much it is worth)
-- a number in the items description will override the number entry in this table
local validCountItemList = {
["Clue"] = 1,
[""] = 1
}
--END OF CODE TO EDIT
local trashGUID = "70b9f6"
exposedValue = 0
function onLoad()
timerID = self.getGUID()..math.random(9999999999999)
--Sets position/color for the button, spawns it
self.createButton({
label="", click_function="removeAllClues", function_owner=self,
position={0,0,0}, rotation={0,8,0}, height=0, width=0,
font_color={0,0,0}, font_size=2000
})
--Start timer which repeats forever, running countItems() every second
Timer.create({
identifier=timerID,
function_name="countItems", function_owner=self,
repetitions=0, delay=1
})
exposedValue = 0
trashCan = getObjectFromGUID("147e80")
self.createButton({
label = "",
click_function = "removeAllClues",
function_owner = self,
height = 0,
width = 0,
font_color = { 0, 0, 0 },
font_size = 2000
})
loopID = Wait.time(countItems, 1, -1)
end
-- Activated once per second, counts items in bowls
function countItems()
local totalValue = -1
local countableItems = findValidItemsInSphere()
for _, entry in ipairs(countableItems) do
local descValue = tonumber(entry.hit_object.getDescription())
local stackMult = math.abs(entry.hit_object.getQuantity())
-- Use value in description if available
if descValue ~= nil then
totalValue = totalValue + descValue * stackMult
else
-- Otherwise use the value in validCountItemList
totalValue = totalValue + validCountItemList[entry.hit_object.getName()] * stackMult
end
end
exposedValue = totalValue
self.editButton({ index = 0, label = totalValue })
end
function findValidItemsInSphere()
return filterByValidity(findItemsInSphere())
end
local items = Physics.cast({
origin = self.getPosition(),
direction = { 0, 1, 0 },
type = 2,
max_distance = 0,
size = { 2, 2, 2 },
--debug=true
})
--Activated once per second, counts items in bowls
function countItems()
local totalValue = -1
local countableItems = findValidItemsInSphere()
for ind, entry in ipairs(countableItems) do
local descValue = tonumber(entry.hit_object.getDescription())
local stackMult = math.abs(entry.hit_object.getQuantity())
--Use value in description if available
if descValue ~= nil then
totalValue = totalValue + descValue * stackMult
else
--Otherwise use the value in validCountItemList
totalValue = totalValue + validCountItemList[entry.hit_object.getName()] * stackMult
end
retval = {}
for _, entry in ipairs(items) do
--Ignore the bowl
if entry.hit_object ~= self then
--Ignore if not in validCountItemList
local tableEntry = validCountItemList[entry.hit_object.getName()]
if tableEntry ~= nil then
table.insert(retval, entry)
end
end
exposedValue = totalValue
--Updates the number display
self.editButton({index=0, label=totalValue})
end
function filterByValidity(items)
retval = {}
for _, entry in ipairs(items) do
--Ignore the bowl
if entry.hit_object ~= self then
--Ignore if not in validCountItemList
local tableEntry = validCountItemList[entry.hit_object.getName()]
if tableEntry ~= nil then
table.insert(retval, entry)
end
end
end
return retval
end
--Gets the items in the bowl for countItems to count
function findItemsInSphere()
--Find scaling factor
local scale = self.getScale()
--Set position for the sphere
local pos = self.getPosition()
pos.y=pos.y+(1.25*scale.y)
--Ray trace to get all objects
return Physics.cast({
origin=pos, direction={0,1,0}, type=2, max_distance=0,
size={6*scale.x,6*scale.y,6*scale.z}, --debug=true
})
end
return retval
end
function removeAllClues()
@ -96,19 +74,12 @@ function clueRemovalCoroutine()
for _, entry in ipairs(findValidItemsInSphere()) do
-- Do not put the table in the garbage
if entry.hit_object.getGUID() ~= "4ee1f2" then
--delay for animation purposes
for k=1,10 do
-- delay for animation purposes
for k = 1, 10 do
coroutine.yield(0)
end
trashCan.putObject(entry.hit_object)
getObjectFromGUID(trashGUID).putObject(entry.hit_object)
end
end
--coroutines must return a value
return 1
end
function onDestroy()
if timerID and type(timerID) == 'object' then
Timer.destroy(timerID)
end
end