fixed package so it contains templates, updated config for more control

This commit is contained in:
2026-06-08 19:29:03 -07:00
parent 4d0fb606af
commit 0c90ab885e
36 changed files with 267 additions and 635 deletions
+3
View File
@@ -0,0 +1,3 @@
bin/*
love/*
game.love
-20
View File
@@ -1,20 +0,0 @@
settings:
increment: 100
start: 100
tiers: 5
dailyDouble:
enabled: true
minQuestions: 7
count: 2
categories:
- name: shounen
displayName: "Shounen"
- name: villains
displayName: "Villains"
- name: openings
displayName: "Openings"
- name: studios
displayName: "Studios & Staff"
- name: plot-twists
displayName: "Plot Twists"
-33
View File
@@ -1,33 +0,0 @@
questions:
- title: "The iconic opening 'Guren no Yumiya' by Linked Horizon belongs to this anime."
time-limit: 15
answer: "Attack on Titan"
template: "whatis"
- title: "Which anime features the opening 'Unravel' by TK from Ling Tosite Sigure?"
answer: 2
choices:
- "Parasyte"
- "Tokyo Ghoul"
- "Deadman Wonderland"
- "Elfen Lied"
template: "multiplechoice"
- title: "'Cruel Angel's Thesis' is the legendary opening theme of this 1995 mecha anime."
time-limit: 20
answer: "Neon Genesis Evangelion"
template: "whatis"
- title: "Which of these bands performed 'Again', the first opening of Fullmetal Alchemist: Brotherhood?"
answer: 4
choices:
- "Asian Kung-Fu Generation"
- "Flow"
- "Scandal"
- "YUI"
template: "multiplechoice"
- title: "This artist performed 'Gurenge', the first opening of Demon Slayer: Kimetsu no Yaiba, which became a massive hit in Japan."
time-limit: 25
answer: "LiSA"
template: "whatis"
-33
View File
@@ -1,33 +0,0 @@
questions:
- title: "In Code Geass, Lelouch's Geass ability compels anyone who makes direct eye contact with him to do this."
time-limit: 20
answer: "Obey any one order he gives them"
template: "whatis"
- title: "At the end of Madoka Magica, Madoka's wish rewrites the laws of the universe to do what?"
answer: 2
choices:
- "Destroy all witches that have ever existed and will ever exist"
- "Erase all witches before they are born, taking herself out of existence"
- "Turn every magical girl back into a normal human"
- "Destroy Kyubey and the incubator race"
template: "multiplechoice"
- title: "In Fullmetal Alchemist: Brotherhood, Edward and Alphonse discover their mother was not actually revived — what they created during their human transmutation was this."
time-limit: 30
answer: "A soulless body / failed homunculus (not their mother)"
template: "whatis"
- title: "Which of these correctly describes the twist at the end of Assassination Classroom?"
answer: 3
choices:
- "Koro-sensei was always a government weapon and willingly lets himself be killed"
- "The students refuse to kill Koro-sensei and he escapes to space"
- "Koro-sensei asks his students to be the ones to kill him as his final wish"
- "Nagisa kills the minister of defense and Koro-sensei is freed"
template: "multiplechoice"
- title: "In Gurren Lagann, Simon discovers that the key to piloting Lagann is not a special device but actually this."
time-limit: 25
answer: "His own drill / fighting spirit (spiral power)"
template: "whatis"
BIN
View File
Binary file not shown.
-33
View File
@@ -1,33 +0,0 @@
questions:
- title: "This is the name of the signature technique Naruto Uzumaki uses to create physical copies of himself."
time-limit: 15
answer: "Shadow Clone Jutsu"
template: "whatis"
- title: "In Dragon Ball Z, Goku achieved this transformation for the first time during his battle against Frieza on Namek."
time-limit: 20
answer: "Super Saiyan"
template: "whatis"
- title: "Which of these is the name of Ichigo Kurosaki's Zanpakuto in Bleach?"
answer: 3
choices:
- "Zangetsu"
- "Senbonzakura"
- "Tensa Zangetsu"
- "Ryujin Jakka"
template: "multiplechoice"
- title: "In Hunter x Hunter, this is the name of the system of power that allows users to manipulate their life energy."
time-limit: 25
answer: "Nen"
template: "whatis"
- title: "Which of these Devil Fruits did Monkey D. Luffy eat, giving him his rubber powers?"
answer: 2
choices:
- "Mera Mera no Mi"
- "Gomu Gomu no Mi"
- "Hana Hana no Mi"
- "Bara Bara no Mi"
template: "multiplechoice"
-33
View File
@@ -1,33 +0,0 @@
questions:
- title: "This animation studio, co-founded by Hayao Miyazaki, produced Spirited Away, My Neighbor Totoro, and Princess Mononoke."
time-limit: 15
answer: "Studio Ghibli"
template: "whatis"
- title: "Which studio produced Fullmetal Alchemist: Brotherhood, Sword of the Stranger, and Mob Psycho 100?"
answer: 1
choices:
- "Bones"
- "Madhouse"
- "White Fox"
- "A-1 Pictures"
template: "multiplechoice"
- title: "This director is known for helming Cowboy Bebop, Samurai Champloo, and Space Dandy."
time-limit: 25
answer: "Shinichiro Watanabe"
template: "whatis"
- title: "Which studio is responsible for the long-running adaptations of One Piece and Dragon Ball Super?"
answer: 3
choices:
- "Pierrot"
- "Sunrise"
- "Toei Animation"
- "TMS Entertainment"
template: "multiplechoice"
- title: "This legendary animator, known as 'the god of manga', created Astro Boy and is considered the father of modern anime and manga."
time-limit: 20
answer: "Osamu Tezuka"
template: "whatis"
Binary file not shown.

Before

Width:  |  Height:  |  Size: 961 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.1 MiB

Binary file not shown.
Binary file not shown.

Before

Width:  |  Height:  |  Size: 256 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.8 MiB

Binary file not shown.
-24
View File
@@ -1,24 +0,0 @@
settings:
increment: 100 # how much each tier increases by
start: 100 # starting amount see tier's comment
tiers: 5 # 5 tiers 100, 200, 300, 400, 500 based on above settings
dailyDouble:
enabled: true # should daily double be enabled?
minQuestions: 7 # how many questions need to be answered before a daily double can appear?
count: 2 # how many daily doubles should there be?
categories: # the name of each category should correspond to a yaml file with the same name
- name: shounen # name must be alphanumeric, cannot start with a number or contain special characters "-" and "." are ok if they are not at the beginning
displayName: "Shounen" # if blank will use name
image: "anime/assets/14018-3193093789.gif" # if set will display image instead of name, categories are referenced by name which is required
- name: openings
displayName: "Openings" # if blank will use name
- name: sadness
displayName: "Sadness" # if blank will use name
- name: random
displayName: Random # if blank will use name
- name: you-would-have-though
displayName: "You would have\nthought" # if blank will use name
- name: wtf-is-that
displayName: "Wtf is that!?" # if blank will use name
- name: owo
displayName: "owo" # if blank will use name
-35
View File
@@ -1,35 +0,0 @@
questions: # expects a list equal to the tier
- title: "Name at least 10 of the characters here"
time-limit: 60 # If omitted there is no time limit
answer: 10
image: "anime/assets/shounen_name_characters.png"
template: "one-image" # template to use
display-answer: true # displays the correct answer before returning to the main screen
- title: "What anime is this?"
time-limit: 30 # If omitted there is no time limit
answer: "steins;gate"
imageA: "anime/assets/beer.jpg"
imageB: "anime/assets/gate.jpg"
display-answer: true # displays the correct answer before returning to the main screen
template: "imageword" # template to use
- title: "What is 2+2"
answer: 2 # positon of correct answer
choices:
- "22"
- "4" # this is 2
- "9000"
- "-4"
- "wack"
template: "multiplechoice"
- title: "Who directed the groundbreaking film 'Akira',\nwhich helped introduce anime to Western audiences?"
time-limit: 10 # If omitted there is no time limit
answer: "Katsuhiro Otomo"
template: "whatis" # template to use
display-answer: true # displays the correct answer before returning to the main screen
- title: "What is this?"
answer: "Bunny shit"
video: "anime/assets/bunny.ogv"
start: 4
playFor: 3
template: "whatvideo" # template to use
display-answer: true # displays the correct answer before returning to the main screen
Binary file not shown.

After

Width:  |  Height:  |  Size: 613 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.0 MiB

-290
View File
@@ -1,290 +0,0 @@
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
}
+4 -4
View File
@@ -1,9 +1,9 @@
function love.conf(t) function love.conf(t)
t.identity = nil -- The name of the save directory (string) t.identity = "Jeopardy"
t.version = "11.5" -- The LOVE version this game was made for (string) t.version = "11.5" -- The LOVE version this game was made for (string)
t.console = true -- Attach a console (boolean, Windows only) t.console = true -- Attach a console (boolean, Windows only)
t.window.title = "GuiManagerTest" -- The window title (string) t.window.title = "Jeopardy" -- The window title (string)
t.window.icon = nil -- Filepath to an image to use as the window's icon (string) t.window.icon = nil -- Filepath to an image to use as the window's icon (string)
t.window.width = 1920 -- The window width (number) t.window.width = 1920 -- The window width (number)
t.window.height = 1080 -- The window height (number) t.window.height = 1080 -- The window height (number)
@@ -13,7 +13,7 @@ function love.conf(t)
t.window.minheight = 1 -- Minimum window height if the window is resizable (number) t.window.minheight = 1 -- Minimum window height if the window is resizable (number)
t.window.fullscreen = false -- Enable fullscreen (boolean) t.window.fullscreen = false -- Enable fullscreen (boolean)
t.window.fullscreentype = "desktop" -- Standard fullscreen or desktop fullscreen mode (string) t.window.fullscreentype = "desktop" -- Standard fullscreen or desktop fullscreen mode (string)
t.window.vsync = false -- Enable vertical sync (boolean) t.window.vsync = true -- Enable vertical sync (boolean)
t.window.fsaa = 4 -- The number of samples to use with multi-sampled antialiasing (number) t.window.fsaa = 4 -- The number of samples to use with multi-sampled antialiasing (number)
t.window.display = 1 -- Index of the monitor to show the window in (number) t.window.display = 1 -- Index of the monitor to show the window in (number)
t.window.highdpi = true -- Enable high-dpi mode for the window on a Retina display (boolean) t.window.highdpi = true -- Enable high-dpi mode for the window on a Retina display (boolean)
@@ -29,7 +29,7 @@ function love.conf(t)
t.modules.keyboard = true -- Enable the keyboard module (boolean) t.modules.keyboard = true -- Enable the keyboard module (boolean)
t.modules.math = true -- Enable the math module (boolean) t.modules.math = true -- Enable the math module (boolean)
t.modules.mouse = true -- Enable the mouse module (boolean) t.modules.mouse = true -- Enable the mouse module (boolean)
t.modules.physics = true -- Enable the physics module (boolean) t.modules.physics = false -- Enable the physics module (boolean)
t.modules.sound = true -- Enable the sound module (boolean) t.modules.sound = true -- Enable the sound module (boolean)
t.modules.system = true -- Enable the system module (boolean) t.modules.system = true -- Enable the system module (boolean)
t.modules.timer = true -- Enable the timer module (boolean) t.modules.timer = true -- Enable the timer module (boolean)
+1 -1
Submodule gui updated: 3e100d6fdf...fa06733747
+2
View File
@@ -18,6 +18,8 @@ function loader:new(path_or_file)
else else
local category = yaml.parse(link) local category = yaml.parse(link)
c.index.categories[i].questions = category.questions c.index.categories[i].questions = category.questions
c.index.categories[i].global = category.global or {}
c.index.categories[i].cosmetics = category.cosmetics or {}
end end
end end
return c return c
+29 -21
View File
@@ -1,40 +1,48 @@
local gui, color, theme, utils, board, yaml, loader, scoreUpdater
multi, thread = require("multi"):init({priority=true}) multi, thread = require("multi"):init({priority=true})
multi.setClock(require("socket").gettime) -- When on linux os.clock doesn't reture actual seconds the program has elapsed for multi.setClock(require("socket").gettime) -- When on linux os.clock doesn't reture actual seconds the program has elapsed for
GLOBAL, THREAD = require("multi.integration.loveManager"):init() GLOBAL, THREAD = require("multi.integration.loveManager"):init()
gui = require("gui") local gui = require("gui")
color = require("gui.core.color") local color = require("gui.core.color")
theme = require("gui.core.theme") local title = require("menus.title")
utils = require("utils") local menu = require("gui.core.menus")
board = require("board")
yaml = require("yaml") color.indexColor("bg","#2b348b")
loader = require("loader") color.indexColor("tile_bg","#5459e4")
color.indexColor("header_tile","#2a2e91")
color.indexColor("status_font", "#e4b82a")
color.indexColor("title_font","#b16d24")
color.indexColor("question_bg","#363ac8")
color.indexColor("tile_font","#ffffff")
color.indexColor("header_font","#fef6eeda")
require("gui.addons") require("gui.addons")
title = require("menus.title") gui:setHotKey({"f11"})(function()
fullscreen, fstype = love.window.getFullscreen()
love.window.setFullscreen(not fullscreen, "desktop")
end)
local old = multi.error
multi.error = function(...)
old(...)
os.exit()
end
function love.load() function love.load()
love.filesystem.setIdentity("jeopardy")
success = love.filesystem.createDirectory("")
gui:cacheImage({"assets/images/checked.png","assets/images/unchecked.png","assets/images/speaker.png"}) gui:cacheImage({"assets/images/checked.png","assets/images/unchecked.png","assets/images/speaker.png"})
gui:setAspectSize(1920, 1080) gui:setAspectSize(1920, 1080)
gui.aspect_ratio = true gui.aspect_ratio = true
local bg = gui:newFrame() local bg = gui:newImageLabel("assets/images/background.png")
bg:fullFrame() bg:fullFrame()
bg.color = color.new("#242f9b")
require("menus.menus").init(bg) menu.init(bg)
title:visible(true) title:visible(true)
bg:OnUpdate(function(self, dt)
if self.__blur then
-- pulse the blur between 2 and 12
local t = love.timer.getTime()
self:setBlurRadius(7 + 5 * math.sin(t * 2))
end
end)
end end
function love.update(dt) function love.update(dt)
+157 -39
View File
@@ -5,13 +5,14 @@ local theme = require("gui.core.theme")
local fmt = require("fmt") local fmt = require("fmt")
local timer = require("utils") local timer = require("utils")
local multi, thread = require("multi"):init() local multi, thread = require("multi"):init()
local menu = require("menus.menus") local menu = require("gui.core.menus")
local timesup = love.audio.newSource("assets/sounds/timesup.mp3", "static") local timesup = love.audio.newSource("assets/sounds/timesup.mp3", "static")
local double = love.audio.newSource("assets/sounds/double.mp3", "static") local double = love.audio.newSource("assets/sounds/double.mp3", "static")
local boardUpdater = gui:getProcessor():newProcessor("board-updater") local boardUpdater = gui:getProcessor():newProcessor("board-updater")
boardUpdater.Start() local scoreUpdater = gui:getProcessor():newProcessor("score-updater")
local qUpdater = gui:getProcessor():newProcessor("question-updater")
local activePlayer local activePlayer
local playerList = {} local playerList = {}
@@ -50,14 +51,6 @@ local dd_enabled = false
local applied_dd = false local applied_dd = false
local board, question 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) local function pickUniqueIndices(t, count)
assert(#t >= count, "Not enough elements to pick " .. count .. " unique items") assert(#t >= count, "Not enough elements to pick " .. count .. " unique items")
@@ -98,22 +91,32 @@ function applyDD()
local dd_list = {} local dd_list = {}
local dds = {pickFiltered(board.children, dd_count)} local dds = {pickFiltered(board.children, dd_count)}
for i,v in pairs(dds) do for i,v in pairs(dds) do
print(i,v)
v.isDouble = true v.isDouble = true
end end
applied_dd = true applied_dd = true
end end
end end
local qUpdater = gui:getProcessor():newProcessor("question-updater")
qUpdater.Start()
function LoadTemplate(name, path) function LoadTemplate(name, path)
if love.filesystem.getInfo(path .."/templates/" .. name .. ".lua") then
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") data = love.filesystem.read(path .."/templates/" .. name .. ".lua")
elseif love.filesystem.getInfo("templates/" .. name .. ".lua") then
data = love.filesystem.read("templates/" .. name .. ".lua")
else
print("Error Loading Template: " .. name, path)
gui:newMessageBox({
title = "Error!",
message = "Unable to load template: " .. name,
buttons = { "Yes", "No" },
onChoice = function(label, idx)
if label == "Yes" then
doCallback(selected)
pickerWindow.visible = false
pickerWindow:setTag("visual")
end
end,
})
return
end end
local template, err = loadstring(data) local template, err = loadstring(data)
@@ -163,22 +166,96 @@ function LoadTemplate(name, path)
return isoTemplate() return isoTemplate()
end end
local function manageCosmetics(frame, cosmetics)
if cosmetics["bg-img"] then
frame:setImage(cosmetics["bg-img"])
else
frame:setImage("assets/images/background.png")
end
if type(cosmetics.colors) == "table" then
for i,v in pairs(cosmetics.colors) do
color.reindexColor((i:gsub("-","_")),v)
end
end
end
function gui:cleanup()
for i = #self.children, 1, -1 do
self.children[i]:destroy()
end
self.children = {}
completed_questions = completed_questions + 1
end
local reset = boardUpdater:newConnection()
local default_text = "Pick a Category"
function Menu(frame, path) function Menu(frame, path)
local qframe = frame:newFrame(0, 0, 0, 0, .2, .05, .75, .9) if path:match(".zip") then
qframe.color = color.new("#060ee9") -- local basename = path:match("([^/\\]+)$")
local scoreboard = ScoreBoard(frame, 0, 0, 0, 0, .015, .05, .170, .9) print(path)
local success = love.filesystem.mount(path, "quiz", true)
if not success then
gui:newMessageBox({
title = "Return to the main menu?",
message = "Couldn't load file: " .. path,
buttons = { "Return", "Quit" },
onChoice = function(label, idx)
if label == "Return" then
return menu.getMenu("title"):visible(true)
else
os.exit()
end
end,
})
return
end
path = "quiz"
end
-- Start the processors now
boardUpdater.Start()
qUpdater.Start()
scoreUpdater.Start()
local scoreboard = ScoreBoard(frame, 0, 0, 0, 0, .06, .1, .170, .8)
local qframe = frame:newFrame(0, 0, 0, 0, .24, .1, .70, .8)
local label = frame:newTextLabel(default_text, 0, 10, 0, -20, .29, 0, .6, .1)
label.visibility = .85
label.drawBorder = false
label.align = gui.ALIGN_CENTER
label.color = color.bg
label.textColor = color.status_font
label:setRoundness(20,20,60)
boardUpdater:newThread(function()
local test = function()
return label.text ~= ""
end
while true do
thread.hold(test)
label:centerFont()
label:fitFont(nil, nil, {scale = 2/3})
end
end)
local data = loader:new(path) local data = loader:new(path)
board, question, dailydouble = qframe:newFrame(), qframe:newFrame(), qframe:newImageLabel("assets/images/double.jpg") board, question, dailydouble = qframe:newFrame(), qframe:newFrame(), qframe:newImageLabel("assets/images/double.jpg")
index = data.index index = data.index
local cosmetics = index.cosmetics or {}
manageCosmetics(frame, cosmetics)
board:fullFrame() board:fullFrame()
question:fullFrame() question:fullFrame()
dailydouble:fullFrame() dailydouble:fullFrame()
dailydouble.visible = false dailydouble.visible = false
question.visible = false question.visible = false
question.color = color.new("#060ce9") question.color = color.question_bg
local tiers = index.settings.tiers or 5 local tiers = index.settings.tiers or 5
local start = index.settings.start or 100 local start = index.settings.start or 100
@@ -190,6 +267,29 @@ function Menu(frame, path)
min_questions = dd.minQuestions min_questions = dd.minQuestions
dd_count = dd.count dd_count = dd.count
end end
local autoreveal = false
if index.dev and index.dev.enabled then
if index.dev["auto-reveal"] then
autoreveal = true
end
if type(index.dev.players) == "table" then
for i,v in ipairs(index.dev.players) do
if type(v) == "string" then
scoreboard:AddPlayer(v, 0)
elseif type(v) == "table" then
scoreboard:AddPlayer(v.name, v.score, v.icon)
end
end
end
end
reset(function()
question:cleanup()
manageCosmetics(frame, cosmetics, true)
label.text = default_text
end)
for cat,v in pairs(index.categories) do for cat,v in pairs(index.categories) do
local c local c
if v.image then if v.image then
@@ -197,26 +297,30 @@ function Menu(frame, path)
else 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 = 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.align = gui.ALIGN_CENTER
c.textColor = color.new("#ffffff") c.textColor = color.header_font
c.color = color.new("#060ce9") c.color = color.header_tile
end end
c.UUID = multi.generate_uuid7() -- Each otpion gets a unique UUID c.UUID = multi.generate_uuid7() -- Each otpion gets a unique UUID
img = c:newImageButton("assets/images/placeholder.jpg") if not autoreveal then
img.visibility = 0 img = c:newImageButton("assets/images/placeholder.jpg")
img.visibility = 0
img:OnReleased(function(self) img:OnReleased(function(self)
self.visible = false self.visible = false
end) end)
img:fullFrame()
end
img:fullFrame()
table.insert(manage,c) table.insert(manage,c)
for tier = 1,tiers do 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)) 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.textColor = color.tile_font
t.align = gui.ALIGN_CENTER t.align = gui.ALIGN_CENTER
t.color = color.new("#060ce9") t.color = color.tile_bg
t.category = v.name t.category = v.name
t.index = tier t.index = tier
t.price = start + inc*(tier-1) t.price = start + inc*(tier-1)
@@ -226,8 +330,22 @@ function Menu(frame, path)
applyDD() -- check and run DD if conditions meet applyDD() -- check and run DD if conditions meet
end 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 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 globals = index.categories[cat].global
if not globals then
globals = {}
end
local q = index.categories[cat].questions[self.index] local q = index.categories[cat].questions[self.index]
if not q then return end
label.text = t.category .. ": " .. t.price
local mt = debug.getmetatable(q)
if mt then
mt.__metatable = nil
end
setmetatable(q, {__index = globals})
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 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
if q.cosmetics then
manageCosmetics(frame, q.cosmetics)
end
self.textVisibility = 0 self.textVisibility = 0
local template = LoadTemplate(q.template, path) local template = LoadTemplate(q.template, path)
question.visible = true question.visible = true
@@ -255,7 +373,8 @@ function Menu(frame, path)
end) end)
end end
local finished = false local finished = false
template.index(question, q, function(ans) template.index(question, q, function(ans, m)
local m = m or 1
if finished then return end if finished then return end
player = GetActivePlayer() player = GetActivePlayer()
if tm then if tm then
@@ -263,17 +382,17 @@ function Menu(frame, path)
end end
stop = true stop = true
if ans then if ans then
player:Add(self.price*mul) player:Add((self.price*mul)*m)
finished = true finished = true
question.visible = false question.visible = false
question:cleanup() reset:Fire()
elseif ans == false then elseif ans == false then
player:Add(-self.price*mul) player:Add(-self.price*mul)
player = GetNextPlayer() player = GetNextPlayer()
else else
finished = true finished = true
question.visible = false question.visible = false
question:cleanup() reset:Fire()
end -- nil is a valid option where you weren't right or wrong, you just skipped end -- nil is a valid option where you weren't right or wrong, you just skipped
self.text = "" self.text = ""
end) end)
@@ -296,8 +415,7 @@ function Menu(frame, path)
return background return background
end end
scoreUpdater = gui:getProcessor():newProcessor("score-updater")
scoreUpdater.Start()
function GetActivePlayer() function GetActivePlayer()
if not activePlayer then return end if not activePlayer then return end
@@ -407,7 +525,7 @@ function ScoreBoard(frame, x, y, w, h, sx, sy, sw, sh)
function scoreboard:AddPlayer(name, score, icon) function scoreboard:AddPlayer(name, score, icon)
local player = { local player = {
Name = name, Name = name,
Score = score, Score = score or 0,
Icon = icon, Icon = icon,
UUID = multi.generate_uuid7(), UUID = multi.generate_uuid7(),
Add = function(self, amt) Add = function(self, amt)
-54
View File
@@ -1,54 +0,0 @@
local gui = require("gui")
local menu = {}
local menus = {}
local frame
local menuRef = {}
local mt = {
__index = menuRef
}
function menu.registerMenu(name, menu, delete)
local c = {}
c.MenuFunc = menu
c.Delete = delete
setmetatable(c, mt)
menus[name] = c
return c
end
function menu.getMenu(name)
return menus[name] or nil, "Menu ".. name .. " not found."
end
function menu.init(f)
frame = f
end
function menu.hideMenus()
for k,v in pairs(menus) do
if v.frame then
if v.Delete then
v.frame:destroy()
menus[k] = nil
else
v.frame.visible = false
v.frame.active = false
v.frame:setParent(gui.virtual)
end
end
end
end
function menuRef:visible(value, ...)
menu.hideMenus()
if self.__menuConfigured and self.frame then
self.frame.visible = true
self.frame.active = true
self.frame:setParent(frame)
else
self.__menuConfigured = true
self.frame = self.MenuFunc(frame, ...)
end
end
return menu
+1 -1
View File
@@ -1,6 +1,6 @@
local gui = require("gui") local gui = require("gui")
local color = require("gui.core.color") local color = require("gui.core.color")
local menu = require("menus.menus") local menu = require("gui.core.menus")
-- local proc = gui:getProcessor():newProcessor("settings") -- local proc = gui:getProcessor():newProcessor("settings")
function Menu(frame) function Menu(frame)
+41 -5
View File
@@ -1,14 +1,16 @@
local gui = require("gui") local gui = require("gui")
local color = require("gui.core.color") local color = require("gui.core.color")
local menu = require("menus.menus") local menu = require("gui.core.menus")
local proc = gui:getProcessor():newProcessor("main-title") local proc = gui:getProcessor():newProcessor("main-title")
local APP_VERSION = love.filesystem.read("version.txt")
local board = require("menus.board") local board = require("menus.board")
function Menu(frame) function Menu(frame)
local background = frame:newImageLabel("assets/images/background.jpg") local background = frame:newImageLabel("assets/images/background.jpg")
background:fullFrame() background:fullFrame()
local title = frame:newTextLabel("Jeopardy",0,0,0,0,0,.1,1,.25) local title = background:newTextLabel("Jeopardy",0,0,0,0,0,.1,1,.25)
title:setFont("assets/fonts/gyparody.ttf",300) title:setFont("assets/fonts/gyparody.ttf",300)
title:setShader(gui.SHADERS.vignette,{ title:setShader(gui.SHADERS.vignette,{
@@ -18,7 +20,7 @@ function Menu(frame)
title.align = gui.ALIGN_CENTER title.align = gui.ALIGN_CENTER
title.visibility = 0 title.visibility = 0
title.textColor = color.new("#b16d24") title.textColor = color.title_font
title.drawBorder = false title.drawBorder = false
proc:newThread(function() proc:newThread(function()
@@ -62,10 +64,44 @@ function Menu(frame)
},play,settings,quit) },play,settings,quit)
play:OnReleased(function() play:OnReleased(function()
background.visible = false if love.filesystem.getInfo("quiz") then
menu.getMenu("board"):visible(true,"anime") menu.getMenu("board"):visible(true, "quiz")
return
else
gui:newFilePicker("File picker test",nil, {".zip"}, function(file)
menu.getMenu("board"):visible(true, file:gsub("\\","/"):gsub(love.filesystem.getSaveDirectory(),""):sub(2,-1))
end)
end
end) end)
quit:OnReleased(function()
local f = frame:newFrame()
f:fullFrame()
f.visibility = .8
f.color = color.black
local cm = menu.getCurrentMenu()
cm:setTag("visual")
quit:setShader()
gui:newMessageBox({
title = "Confirm",
message = "Are you sure you want to exit the game?",
buttons = { "Yes", "No" },
onChoice = function(label, idx)
if label == "Yes" then os.exit() end
cm:removeTag("visual")
f:destroy()
end,
})
end)
local version = frame:newTextLabel("Version: " .. APP_VERSION, -150,-30, 150, 30, 1, 1)
thread:newThread(function()
thread.skip(2)
version:fitFont()
end)
version.textColor = color.new("#b16d24")
version.visibility = 0
return background return background
end end
+1 -1
Submodule multi updated: ee5e3bde7f...0796788fcb
+19
View File
@@ -0,0 +1,19 @@
:: Read the first line of version.txt and assign it to the MY_VERSION variable
for /f "usebackq delims=" %%i in ("version.txt") do (
set "userInput=%%i"
goto :done
)
:done
"C:\Program Files\7-Zip\7z.exe" a -tzip game.love templates version.txt assets multi\integration\loveManager multi\integration\sharedExtensions multi\init.lua gui menus conf.lua fmt.lua loader.lua main.lua utils.lua yaml.lua
rd /s /q "bin\%userInput%"
if not exist "bin\%userInput%" mkdir "bin\%userInput%"
copy /b love\love.exe + game.love "bin\%userInput%\Jeopardy.exe"
copy /b love\love.dll "bin\%userInput%\love.dll"
copy /b lovel\lua51.dll "bin\%userInput%\lua51.dll"
copy /b love\mpg123.dll "bin\%userInput%\mpg123.dll"
copy /b love\msvcp120.dll "bin\%userInput%\msvcp120.dll"
copy /b love\msvcr120.dll "bin\%userInput%\msvcr120.dll"
copy /b love\OpenAL32.dll "bin\%userInput%\OpenAL32.dll"
copy /b love\SDL2.dll "bin\%userInput%\SDL2.dll"
copy /b love\license.txt "bin\%userInput%\license.txt"
BIN
View File
Binary file not shown.

Before

Width:  |  Height:  |  Size: 29 KiB

+2 -2
View File
@@ -9,8 +9,8 @@ local function index(window, q, callback)
label = window:newTextLabel(" " ..q.title.. " ",0,0,0,0,0,0,1,.2) label = window:newTextLabel(" " ..q.title.. " ",0,0,0,0,0,0,1,.2)
label.align = ALIGN_CENTER label.align = ALIGN_CENTER
label.textColor = color.white label.textColor = color.white
label.color = color.new("#060ce9") label.color = color.new("#363ac8")
label.borderColor = color.new("#060ce9") label.borderColor = color.new("#363ac8")
if not q.imageA or q.imageA == "" then if not q.imageA or q.imageA == "" then
error("Missing 'imageA' field for question!") error("Missing 'imageA' field for question!")
+2 -2
View File
@@ -21,10 +21,10 @@ local function index(window, q, callback)
label = window:newTextLabel(" " ..q.title.. " ",noOf(0,0,1,.3)) label = window:newTextLabel(" " ..q.title.. " ",noOf(0,0,1,.3))
label.align = ALIGN_CENTER label.align = ALIGN_CENTER
label.textColor = color.white label.textColor = color.white
label.color = color.new("#060ce9") label.color = color.new("#363ac8")
label:setFont(50) label:setFont(50)
choices = window:newFrame(noOf(0,.3,1,.7)) choices = window:newFrame(noOf(0,.3,1,.7))
choices.color = color.new("#060ce9") choices.color = color.new("#363ac8")
function choices:newChoice(choice, i) function choices:newChoice(choice, i)
local c = choices:newFrame(noOf(.25,(i-1)/#q.choices,.5,1/#q.choices)) local c = choices:newFrame(noOf(.25,(i-1)/#q.choices,.5,1/#q.choices))
+1 -1
View File
@@ -15,7 +15,7 @@ local function index(window, q, callback)
label = window:newTextLabel(" " ..q.title.. " ",0,0,0,0,0,0,1,.2) label = window:newTextLabel(" " ..q.title.. " ",0,0,0,0,0,0,1,.2)
label.align = ALIGN_CENTER label.align = ALIGN_CENTER
label.textColor = color.white label.textColor = color.white
label.color = color.new("#060ce9") label.color = color.new("#363ac8")
if not q.image or q.image == "" then if not q.image or q.image == "" then
error("Missing 'image' field for question!") error("Missing 'image' field for question!")
end end
+1 -1
View File
@@ -13,7 +13,7 @@ local function index(window, q, callback)
label.align = ALIGN_CENTER label.align = ALIGN_CENTER
label:fullFrame() label:fullFrame()
label.textColor = color.white label.textColor = color.white
label.color = color.new("#060ce9") label.color = color.new("#363ac8")
local correct = window:newTextButton("Correct",0,-200,0,100,0,1,.5) local correct = window:newTextButton("Correct",0,-200,0,100,0,1,.5)
correct.color = color.new("#52b11b") correct.color = color.new("#52b11b")
local wrong = window:newTextButton("Wrong",0,-200,0,100,.5,1,.5) local wrong = window:newTextButton("Wrong",0,-200,0,100,.5,1,.5)
+1 -1
View File
@@ -20,7 +20,7 @@ local function index(window, q, callback)
label = window:newTextLabel(" " ..q.title.. " ",0,0,0,0,0,0,1,.2) label = window:newTextLabel(" " ..q.title.. " ",0,0,0,0,0,0,1,.2)
label.align = ALIGN_CENTER label.align = ALIGN_CENTER
label.textColor = color.white label.textColor = color.white
label.color = color.new("#060ce9") label.color = color.new("#363ac8")
imageHolder = frame:newImageButton("assets/images/speaker.png",0,0,0,0,0,0,.3,.4) imageHolder = frame:newImageButton("assets/images/speaker.png",0,0,0,0,0,0,.3,.4)
imageHolder:setAspectSize(imageHolder.imageWidth,imageHolder.imageHeight) imageHolder:setAspectSize(imageHolder.imageWidth,imageHolder.imageHeight)
imageHolder:centerX(true) imageHolder:centerX(true)
+1 -1
View File
@@ -20,7 +20,7 @@ local function index(window, q, callback)
label = window:newTextLabel(" " ..q.title.. " ",0,0,0,0,0,0,1,.2) label = window:newTextLabel(" " ..q.title.. " ",0,0,0,0,0,0,1,.2)
label.align = ALIGN_CENTER label.align = ALIGN_CENTER
label.textColor = color.white label.textColor = color.white
label.color = color.new("#060ce9") label.color = color.new("#363ac8")
local holder = frame:newFrame(-300, -200, 600, 400, .5, .5) local holder = frame:newFrame(-300, -200, 600, 400, .5, .5)
holder:centerX(true) holder:centerX(true)
holder:centerY(true) holder:centerY(true)
+1
View File
@@ -0,0 +1 @@
1.0.1