290 lines
10 KiB
Lua
290 lines
10 KiB
Lua
local gui = require("gui")
|
|
local color = require("gui.core.color")
|
|
local loader = require("loader")
|
|
local theme = require("gui.core.theme")
|
|
local fmt = require("fmt")
|
|
local timer = require("utils")
|
|
local multi, thread = require("multi"):init()
|
|
|
|
local timesup = love.audio.newSource("assets/sounds/timesup.mp3", "static")
|
|
local double = love.audio.newSource("assets/sounds/double.mp3", "static")
|
|
|
|
local boardUpdater = gui:getProcessor():newProcessor("board-updater")
|
|
boardUpdater.Start()
|
|
|
|
local activePlayer
|
|
local playerList = {}
|
|
local playerStaticList = {}
|
|
local scoreboard = {}
|
|
|
|
-- Create a table to manage GUI elements
|
|
local manage = {}
|
|
|
|
-- Function to resize fonts for all managed elements
|
|
local function resizeFonts()
|
|
-- Use multi-threading to improve performance
|
|
multi:newThread(function()
|
|
-- Introduce a small delay to avoid too many iterations at once
|
|
thread.skip(2)
|
|
-- Iterate over each element in the 'manage' table
|
|
for i = 1, #manage do
|
|
local elem = manage[i]
|
|
|
|
-- Check if the current element has a centerFont property
|
|
if elem.centerFont then
|
|
-- Adjust font size and re-center the text
|
|
elem:fitFont(nil, nil, {scale = 2/3})
|
|
elem:centerFont()
|
|
end
|
|
end
|
|
end)
|
|
end
|
|
|
|
gui.Events.OnResized(resizeFonts)
|
|
|
|
local completed_questions = 0
|
|
local min_questions = 0
|
|
local dd_count = 0
|
|
local dd_enabled = false
|
|
local applied_dd = false
|
|
local board, question
|
|
|
|
function gui:cleanup()
|
|
for i = #self.children, 1, -1 do
|
|
self.children[i]:destroy()
|
|
end
|
|
self.children = {}
|
|
completed_questions = completed_questions + 1
|
|
end
|
|
|
|
local function pickUniqueIndices(t, count)
|
|
assert(#t >= count, "Not enough elements to pick " .. count .. " unique items")
|
|
|
|
local indices = {}
|
|
for i = 1, #t do indices[i] = i end
|
|
|
|
-- partial Fisher-Yates shuffle
|
|
for i = 1, count do
|
|
local j = math.random(i, #indices)
|
|
indices[i], indices[j] = indices[j], indices[i]
|
|
end
|
|
|
|
return unpack(indices, 1, count)
|
|
end
|
|
|
|
local function pickFiltered(items, count)
|
|
-- Filter to only elements whose text contains "$"
|
|
local filtered = {}
|
|
for _, item in ipairs(items) do
|
|
if item.text:find("%$") then
|
|
filtered[#filtered + 1] = item
|
|
end
|
|
end
|
|
|
|
-- Use pickUniqueIndices to select from filtered results
|
|
local picks = { pickUniqueIndices(filtered, count) }
|
|
local results = {}
|
|
for _, idx in ipairs(picks) do
|
|
results[#results + 1] = filtered[idx]
|
|
end
|
|
|
|
return unpack(results)
|
|
end
|
|
|
|
function applyDD()
|
|
if not applied_dd and completed_questions > min_questions then
|
|
local dd = 0
|
|
local dd_list = {}
|
|
local dds = {pickFiltered(board.children, dd_count)}
|
|
for i,v in pairs(dds) do
|
|
print(i,v)
|
|
v.isDouble = true
|
|
end
|
|
applied_dd = true
|
|
end
|
|
end
|
|
|
|
local function buildBoard(frame, path)
|
|
local data = loader:new(path)
|
|
board, question, dailydouble = frame:newFrame(), frame:newFrame(), frame:newImageLabel("assets/images/double.jpg")
|
|
index = data.index
|
|
board:fullFrame()
|
|
question:fullFrame()
|
|
dailydouble:fullFrame()
|
|
dailydouble.visible = false
|
|
question.visible = false
|
|
question.color = color.new("#060ce9")
|
|
local tiers = index.settings.tiers or 5
|
|
local start = index.settings.start or 100
|
|
local inc = index.settings.increment or 100
|
|
|
|
if index.settings.dailyDouble and index.settings.dailyDouble.enabled then
|
|
local dd = index.settings.dailyDouble
|
|
dd_enabled = dd.enabled
|
|
min_questions = dd.minQuestions
|
|
dd_count = dd.count
|
|
end
|
|
for cat,v in pairs(index.categories) do
|
|
local c
|
|
if v.image then
|
|
c = board:newImageLabel(v.image, 0, 0, 0, 0,(1/#index.categories)*(cat-1),0,1/#index.categories,1/(tiers+1))
|
|
else
|
|
c = board:newTextLabel(v.displayName or v.name,0,0,0,0,(1/#index.categories)*(cat-1),0,1/#index.categories,1/(tiers+1))
|
|
c.align = gui.ALIGN_CENTER
|
|
c.textColor = color.new("#ffffff")
|
|
c.color = color.new("#060ce9")
|
|
end
|
|
|
|
c.UUID = multi.generate_uuid7() -- Each otpion gets a unique UUID
|
|
|
|
img = c:newImageButton("assets/images/placeholder.jpg")
|
|
img.visibility = 0
|
|
|
|
img:OnReleased(function(self)
|
|
self.visible = false
|
|
end)
|
|
|
|
img:fullFrame()
|
|
table.insert(manage,c)
|
|
for tier = 1,tiers do
|
|
local t = board:newTextButton("$" .. start + inc*(tier-1),0,0,0,0,(1/#index.categories)*(cat-1),1/(tiers+1)*tier,(1/#index.categories),1/(tiers+1))
|
|
t.textColor = color.new("#9b9024")
|
|
t.align = gui.ALIGN_CENTER
|
|
t.color = color.new("#060ce9")
|
|
t.category = v.name
|
|
t.index = tier
|
|
t.price = start + inc*(tier-1)
|
|
t:OnReleased(boardUpdater:newFunction(function(self)
|
|
if self.text == "" or GetActivePlayer() == nil then return end
|
|
if dd_enabled then
|
|
applyDD() -- check and run DD if conditions meet
|
|
end
|
|
if index.categories[cat].questions == nil then fmt.Printf("Question not defined: File: %v Category: %v - %v\n",path,index.categories[cat].name,start + inc*(tier-1)) return end
|
|
local q = index.categories[cat].questions[self.index]
|
|
if q == nil then fmt.Printf("Question contains no data: File: %v Category: %v Tier: %v\n",path,index.categories[cat].name,start + inc*(tier-1)) return end
|
|
self.textVisibility = 0
|
|
local template = LoadTemplate(q.template, path)
|
|
question.visible = true
|
|
local player = GetActivePlayer()
|
|
local tm
|
|
local stop
|
|
fmt.Printf("--------------------\nQuestion: %v \nAnswer: %v\n--------------------\n",q["title"],q["answer"])
|
|
local mul = 1
|
|
boardUpdater:newThread(function()
|
|
if self.isDouble then
|
|
mul = 2
|
|
double:play()
|
|
dailydouble.visible = true
|
|
thread.hold(function()
|
|
return not double:isPlaying()
|
|
end)
|
|
dailydouble.visible = false
|
|
end
|
|
if q["time-limit"] then
|
|
tm = timer.startTimer({duration = q["time-limit"]})
|
|
tm.OnStop(function()
|
|
-- Make sound? Subtract if daily double
|
|
if stop then return end
|
|
timesup:play()
|
|
end)
|
|
end
|
|
local finished = false
|
|
template.index(question, q, function(ans)
|
|
if finished then return end
|
|
player = GetActivePlayer()
|
|
if tm then
|
|
tm:Cleanup()
|
|
end
|
|
stop = true
|
|
if ans then
|
|
player:Add(self.price*mul)
|
|
finished = true
|
|
question.visible = false
|
|
question:cleanup()
|
|
elseif ans == false then
|
|
player:Add(-self.price*mul)
|
|
player = GetNextPlayer()
|
|
else
|
|
finished = true
|
|
question.visible = false
|
|
question:cleanup()
|
|
end -- nil is a valid option where you weren't right or wrong, you just skipped
|
|
self.text = ""
|
|
end)
|
|
boardUpdater:newThread("QuestionUpdater",function()
|
|
while true do
|
|
template.update(dt)
|
|
thread.yield()
|
|
if self.text == "" then return end
|
|
end
|
|
end)
|
|
end)
|
|
end))
|
|
table.insert(manage,t)
|
|
end
|
|
end
|
|
resizeFonts()
|
|
resizeFonts()
|
|
end
|
|
|
|
local qUpdater = gui:getProcessor():newProcessor("question-updater")
|
|
qUpdater.Start()
|
|
|
|
function LoadTemplate(name, path)
|
|
|
|
if love.filesystem.getInfo("templates/" .. name .. ".lua") then
|
|
data = love.filesystem.read("templates/" .. name .. ".lua")
|
|
elseif love.filesystem.getInfo(path .."/templates/" .. name .. ".lua") then
|
|
data = love.filesystem.read(path .."/templates/" .. name .. ".lua")
|
|
end
|
|
|
|
local template, err = loadstring(data)
|
|
|
|
if err ~= nil then
|
|
error(err)
|
|
end
|
|
|
|
local timer = function(wait, callback)
|
|
multi:newAlarm(wait):OnRing(callback)
|
|
end
|
|
|
|
local env = { -- lua built-ins except io/os code execution
|
|
pairs=pairs,
|
|
print=print,
|
|
tostring=tostring,
|
|
tonumber=tonumber,
|
|
type=type,
|
|
assert=assert,
|
|
ipairs=ipairs,
|
|
table=table,
|
|
math=math,
|
|
string=string,
|
|
next=next,
|
|
pcall=pcall,
|
|
select=select,
|
|
xpcall=xpcall,
|
|
utf8=utf8,
|
|
clock = require("socket").gettime,
|
|
ALIGN_CENTER = gui.ALIGN_CENTER,
|
|
ALIGN_LEFT = gui.ALIGN_LEFT,
|
|
ALIGN_RIGHT = gui.ALIGN_RIGHT,
|
|
ALIGN_JUSTIFY = gui.ALIGN_JUSTIFY,
|
|
-- Global vars
|
|
color = color,
|
|
error = multi.error,
|
|
theme = theme,
|
|
gui = gui,
|
|
timer = timer,
|
|
-- love stuff
|
|
newSource = love.audio.newSource
|
|
}
|
|
|
|
env._G = env
|
|
local isoTemplate = multi.isolateFunction(template, env)
|
|
|
|
return isoTemplate()
|
|
end
|
|
|
|
return {
|
|
buildBoard = buildBoard
|
|
} |