diff --git a/.gitignore b/.gitignore index e69de29..80b7041 100644 --- a/.gitignore +++ b/.gitignore @@ -0,0 +1,3 @@ +bin/* +love/* +game.love \ No newline at end of file diff --git a/ai-anime/index.yml b/ai-anime/index.yml deleted file mode 100644 index 2bf52ee..0000000 --- a/ai-anime/index.yml +++ /dev/null @@ -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" diff --git a/ai-anime/openings.yml b/ai-anime/openings.yml deleted file mode 100644 index 70eb532..0000000 --- a/ai-anime/openings.yml +++ /dev/null @@ -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" diff --git a/ai-anime/plot-twists.yml b/ai-anime/plot-twists.yml deleted file mode 100644 index cc9acc1..0000000 --- a/ai-anime/plot-twists.yml +++ /dev/null @@ -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" diff --git a/ai-anime/quiz.zip b/ai-anime/quiz.zip deleted file mode 100644 index f6119e5..0000000 Binary files a/ai-anime/quiz.zip and /dev/null differ diff --git a/ai-anime/shounen.yml b/ai-anime/shounen.yml deleted file mode 100644 index f61e541..0000000 --- a/ai-anime/shounen.yml +++ /dev/null @@ -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" diff --git a/ai-anime/studios.yml b/ai-anime/studios.yml deleted file mode 100644 index d3e3c85..0000000 --- a/ai-anime/studios.yml +++ /dev/null @@ -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" diff --git a/anime/assets/14018-3193093789.gif b/anime/assets/14018-3193093789.gif deleted file mode 100644 index 57bfe16..0000000 Binary files a/anime/assets/14018-3193093789.gif and /dev/null differ diff --git a/anime/assets/beer.jpg b/anime/assets/beer.jpg deleted file mode 100644 index bc24dc0..0000000 Binary files a/anime/assets/beer.jpg and /dev/null differ diff --git a/anime/assets/bunny.ogv b/anime/assets/bunny.ogv deleted file mode 100644 index e5bf380..0000000 Binary files a/anime/assets/bunny.ogv and /dev/null differ diff --git a/anime/assets/gate.jpg b/anime/assets/gate.jpg deleted file mode 100644 index 3a0edba..0000000 Binary files a/anime/assets/gate.jpg and /dev/null differ diff --git a/anime/assets/shounen_name_characters.png b/anime/assets/shounen_name_characters.png deleted file mode 100644 index e88f330..0000000 Binary files a/anime/assets/shounen_name_characters.png and /dev/null differ diff --git a/anime/assets/zanarkand.mp3 b/anime/assets/zanarkand.mp3 deleted file mode 100644 index c4bb2d1..0000000 Binary files a/anime/assets/zanarkand.mp3 and /dev/null differ diff --git a/anime/index.yml b/anime/index.yml deleted file mode 100644 index 1e36b94..0000000 --- a/anime/index.yml +++ /dev/null @@ -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 diff --git a/anime/shounen.yml b/anime/shounen.yml deleted file mode 100644 index c3e3809..0000000 --- a/anime/shounen.yml +++ /dev/null @@ -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 diff --git a/assets/images/background.png b/assets/images/background.png new file mode 100644 index 0000000..c2b777d Binary files /dev/null and b/assets/images/background.png differ diff --git a/assets/images/chao_bg.png b/assets/images/chao_bg.png new file mode 100644 index 0000000..af97da2 Binary files /dev/null and b/assets/images/chao_bg.png differ diff --git a/board.lua b/board.lua deleted file mode 100644 index e6286d0..0000000 --- a/board.lua +++ /dev/null @@ -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 -} \ No newline at end of file diff --git a/conf.lua b/conf.lua index 3c4c566..c1a6f2c 100644 --- a/conf.lua +++ b/conf.lua @@ -1,9 +1,9 @@ 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.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.width = 1920 -- The window width (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.fullscreen = false -- Enable fullscreen (boolean) 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.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) @@ -29,7 +29,7 @@ function love.conf(t) t.modules.keyboard = true -- Enable the keyboard module (boolean) t.modules.math = true -- Enable the math 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.system = true -- Enable the system module (boolean) t.modules.timer = true -- Enable the timer module (boolean) diff --git a/gui b/gui index 3e100d6..fa06733 160000 --- a/gui +++ b/gui @@ -1 +1 @@ -Subproject commit 3e100d6fdf50fe121344a8f87217c662534de0b9 +Subproject commit fa0673374761b2602c9bc6dd053d943a76fd9f31 diff --git a/loader.lua b/loader.lua index 7f347dd..4ab0eae 100644 --- a/loader.lua +++ b/loader.lua @@ -18,6 +18,8 @@ function loader:new(path_or_file) else local category = yaml.parse(link) 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 return c diff --git a/main.lua b/main.lua index 897cf8d..4355413 100644 --- a/main.lua +++ b/main.lua @@ -1,40 +1,48 @@ -local gui, color, theme, utils, board, yaml, loader, scoreUpdater - 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 GLOBAL, THREAD = require("multi.integration.loveManager"):init() -gui = require("gui") -color = require("gui.core.color") -theme = require("gui.core.theme") -utils = require("utils") -board = require("board") -yaml = require("yaml") -loader = require("loader") +local gui = require("gui") +local color = require("gui.core.color") +local title = require("menus.title") +local menu = require("gui.core.menus") + +color.indexColor("bg","#2b348b") +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") -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() + love.filesystem.setIdentity("jeopardy") + success = love.filesystem.createDirectory("") gui:cacheImage({"assets/images/checked.png","assets/images/unchecked.png","assets/images/speaker.png"}) gui:setAspectSize(1920, 1080) gui.aspect_ratio = true - local bg = gui:newFrame() + local bg = gui:newImageLabel("assets/images/background.png") bg:fullFrame() - bg.color = color.new("#242f9b") - require("menus.menus").init(bg) + menu.init(bg) 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 function love.update(dt) diff --git a/menus/board.lua b/menus/board.lua index bc28b33..37e0515 100644 --- a/menus/board.lua +++ b/menus/board.lua @@ -5,13 +5,14 @@ local theme = require("gui.core.theme") local fmt = require("fmt") local timer = require("utils") 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 double = love.audio.newSource("assets/sounds/double.mp3", "static") 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 playerList = {} @@ -50,14 +51,6 @@ 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") @@ -98,22 +91,32 @@ function applyDD() 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 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 + if love.filesystem.getInfo(path .."/templates/" .. name .. ".lua") then 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 local template, err = loadstring(data) @@ -163,22 +166,96 @@ function LoadTemplate(name, path) return isoTemplate() 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) - local qframe = frame:newFrame(0, 0, 0, 0, .2, .05, .75, .9) - qframe.color = color.new("#060ee9") - local scoreboard = ScoreBoard(frame, 0, 0, 0, 0, .015, .05, .170, .9) + if path:match(".zip") then + -- local basename = path:match("([^/\\]+)$") + 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) board, question, dailydouble = qframe:newFrame(), qframe:newFrame(), qframe:newImageLabel("assets/images/double.jpg") index = data.index + local cosmetics = index.cosmetics or {} + manageCosmetics(frame, cosmetics) + board:fullFrame() question:fullFrame() dailydouble:fullFrame() dailydouble.visible = false question.visible = false - question.color = color.new("#060ce9") + question.color = color.question_bg local tiers = index.settings.tiers or 5 local start = index.settings.start or 100 @@ -190,6 +267,29 @@ function Menu(frame, path) min_questions = dd.minQuestions dd_count = dd.count 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 local c if v.image then @@ -197,26 +297,30 @@ function Menu(frame, path) 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") + c.textColor = color.header_font + c.color = color.header_tile end c.UUID = multi.generate_uuid7() -- Each otpion gets a unique UUID - img = c:newImageButton("assets/images/placeholder.jpg") - img.visibility = 0 + if not autoreveal then + img = c:newImageButton("assets/images/placeholder.jpg") + img.visibility = 0 - img:OnReleased(function(self) - self.visible = false - end) + img:OnReleased(function(self) + self.visible = false + end) + + img:fullFrame() + 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.textColor = color.tile_font t.align = gui.ALIGN_CENTER - t.color = color.new("#060ce9") + t.color = color.tile_bg t.category = v.name t.index = tier t.price = start + inc*(tier-1) @@ -226,8 +330,22 @@ function Menu(frame, path) 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 globals = index.categories[cat].global + if not globals then + globals = {} + end 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.cosmetics then + manageCosmetics(frame, q.cosmetics) + end self.textVisibility = 0 local template = LoadTemplate(q.template, path) question.visible = true @@ -255,7 +373,8 @@ function Menu(frame, path) end) end 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 player = GetActivePlayer() if tm then @@ -263,17 +382,17 @@ function Menu(frame, path) end stop = true if ans then - player:Add(self.price*mul) + player:Add((self.price*mul)*m) finished = true question.visible = false - question:cleanup() + reset:Fire() elseif ans == false then player:Add(-self.price*mul) player = GetNextPlayer() else finished = true question.visible = false - question:cleanup() + reset:Fire() end -- nil is a valid option where you weren't right or wrong, you just skipped self.text = "" end) @@ -296,8 +415,7 @@ function Menu(frame, path) return background end -scoreUpdater = gui:getProcessor():newProcessor("score-updater") -scoreUpdater.Start() + function GetActivePlayer() 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) local player = { Name = name, - Score = score, + Score = score or 0, Icon = icon, UUID = multi.generate_uuid7(), Add = function(self, amt) diff --git a/menus/menus.lua b/menus/menus.lua deleted file mode 100644 index 1969dcf..0000000 --- a/menus/menus.lua +++ /dev/null @@ -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 \ No newline at end of file diff --git a/menus/settings.lua b/menus/settings.lua index a9d2b74..ab36e44 100644 --- a/menus/settings.lua +++ b/menus/settings.lua @@ -1,6 +1,6 @@ local gui = require("gui") local color = require("gui.core.color") -local menu = require("menus.menus") +local menu = require("gui.core.menus") -- local proc = gui:getProcessor():newProcessor("settings") function Menu(frame) diff --git a/menus/title.lua b/menus/title.lua index 26cc84b..7e2df5a 100644 --- a/menus/title.lua +++ b/menus/title.lua @@ -1,14 +1,16 @@ local gui = require("gui") 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 APP_VERSION = love.filesystem.read("version.txt") + local board = require("menus.board") function Menu(frame) local background = frame:newImageLabel("assets/images/background.jpg") 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:setShader(gui.SHADERS.vignette,{ @@ -18,7 +20,7 @@ function Menu(frame) title.align = gui.ALIGN_CENTER title.visibility = 0 - title.textColor = color.new("#b16d24") + title.textColor = color.title_font title.drawBorder = false proc:newThread(function() @@ -62,10 +64,44 @@ function Menu(frame) },play,settings,quit) play:OnReleased(function() - background.visible = false - menu.getMenu("board"):visible(true,"anime") + if love.filesystem.getInfo("quiz") then + 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) + 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 end diff --git a/multi b/multi index ee5e3bd..0796788 160000 --- a/multi +++ b/multi @@ -1 +1 @@ -Subproject commit ee5e3bde7f9ea255ebcacb52e8e5333b6d3ac62a +Subproject commit 0796788fcb75b3622aa4f25e47efc1725ecfd9a4 diff --git a/package.bat b/package.bat new file mode 100644 index 0000000..3eed7c4 --- /dev/null +++ b/package.bat @@ -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" \ No newline at end of file diff --git a/rainbow.jpg b/rainbow.jpg deleted file mode 100644 index 75d4668..0000000 Binary files a/rainbow.jpg and /dev/null differ diff --git a/templates/imageword.lua b/templates/imageword.lua index 31fe3ae..04f0916 100644 --- a/templates/imageword.lua +++ b/templates/imageword.lua @@ -9,8 +9,8 @@ local function index(window, q, callback) label = window:newTextLabel(" " ..q.title.. " ",0,0,0,0,0,0,1,.2) label.align = ALIGN_CENTER label.textColor = color.white - label.color = color.new("#060ce9") - label.borderColor = color.new("#060ce9") + label.color = color.new("#363ac8") + label.borderColor = color.new("#363ac8") if not q.imageA or q.imageA == "" then error("Missing 'imageA' field for question!") diff --git a/templates/multiplechoice.lua b/templates/multiplechoice.lua index 427f540..f7ab96d 100644 --- a/templates/multiplechoice.lua +++ b/templates/multiplechoice.lua @@ -21,10 +21,10 @@ local function index(window, q, callback) label = window:newTextLabel(" " ..q.title.. " ",noOf(0,0,1,.3)) label.align = ALIGN_CENTER label.textColor = color.white - label.color = color.new("#060ce9") + label.color = color.new("#363ac8") label:setFont(50) choices = window:newFrame(noOf(0,.3,1,.7)) - choices.color = color.new("#060ce9") + choices.color = color.new("#363ac8") function choices:newChoice(choice, i) local c = choices:newFrame(noOf(.25,(i-1)/#q.choices,.5,1/#q.choices)) diff --git a/templates/one-image.lua b/templates/one-image.lua index 9964fb1..015fa8a 100644 --- a/templates/one-image.lua +++ b/templates/one-image.lua @@ -15,7 +15,7 @@ local function index(window, q, callback) label = window:newTextLabel(" " ..q.title.. " ",0,0,0,0,0,0,1,.2) label.align = ALIGN_CENTER label.textColor = color.white - label.color = color.new("#060ce9") + label.color = color.new("#363ac8") if not q.image or q.image == "" then error("Missing 'image' field for question!") end diff --git a/templates/whatis.lua b/templates/whatis.lua index 837e32e..5107de6 100644 --- a/templates/whatis.lua +++ b/templates/whatis.lua @@ -13,7 +13,7 @@ local function index(window, q, callback) label.align = ALIGN_CENTER label:fullFrame() 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) correct.color = color.new("#52b11b") local wrong = window:newTextButton("Wrong",0,-200,0,100,.5,1,.5) diff --git a/templates/whatsound.lua b/templates/whatsound.lua index d69f7e6..de7ad26 100644 --- a/templates/whatsound.lua +++ b/templates/whatsound.lua @@ -20,7 +20,7 @@ local function index(window, q, callback) label = window:newTextLabel(" " ..q.title.. " ",0,0,0,0,0,0,1,.2) label.align = ALIGN_CENTER 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:setAspectSize(imageHolder.imageWidth,imageHolder.imageHeight) imageHolder:centerX(true) diff --git a/templates/whatvideo.lua b/templates/whatvideo.lua index 1c353a7..89e1f90 100644 --- a/templates/whatvideo.lua +++ b/templates/whatvideo.lua @@ -20,7 +20,7 @@ local function index(window, q, callback) label = window:newTextLabel(" " ..q.title.. " ",0,0,0,0,0,0,1,.2) label.align = ALIGN_CENTER label.textColor = color.white - label.color = color.new("#060ce9") + label.color = color.new("#363ac8") local holder = frame:newFrame(-300, -200, 600, 400, .5, .5) holder:centerX(true) holder:centerY(true) diff --git a/version.txt b/version.txt new file mode 100644 index 0000000..7f20734 --- /dev/null +++ b/version.txt @@ -0,0 +1 @@ +1.0.1 \ No newline at end of file