Skip to content

Instantly share code, notes, and snippets.

@wjkennedy
Created July 8, 2024 15:13
Show Gist options
  • Save wjkennedy/3c193a0d3268d5e14701749bf158975e to your computer and use it in GitHub Desktop.
Save wjkennedy/3c193a0d3268d5e14701749bf158975e to your computer and use it in GitHub Desktop.
-- PICO-8 Game: Jira Sprint Manager
-- Constants
local SPRINT_CAPACITY = 20
local MAX_TASKS = 15
local BUCKET_SPEED = 2
local FALL_SPEED = 1
local BUG_PAUSE_TIME = 60 -- Time to pause when a bug is found
local GAME_OVER_TIME = 120 -- Time to show "Game Over" screen (2 seconds at 30 fps)
local DROP_INTERVAL = 30 -- Frames between drops
-- Colors
local JIRA_BLUE = 12
local WHITE = 7
local RED = 8
local HIGH_PRIORITY = 9 -- Yellow
local MEDIUM_PRIORITY = 10 -- Orange
local LOW_PRIORITY = 11 -- Green
-- Game State
backlog = {}
falling_tasks = {}
bucket = {x = 64, y = 120, width = 16, height = 8, sprite_index = 0}
burndown = 0
capacity = SPRINT_CAPACITY
game_over = false
sprint_number = 1
bug_found = false
bug_timer = 0
game_over_timer = 0
drop_timer = 0
wip_admonished = false
-- Splash Screen State
show_splash = true
splash_timer = 0
-- Task Generation
function generate_task()
local priority = flr(rnd(3)) + 1 -- Random priority between 1 and 3
local priority_color
if priority == 1 then
priority_color = LOW_PRIORITY
elseif priority == 2 then
priority_color = MEDIUM_PRIORITY
else
priority_color = HIGH_PRIORITY
end
local task = {
title = "Task "..tostr(#backlog+1),
story_points = flr(rnd(8)) + 1, -- Random story points between 1 and 8
bug_probability = 0.5, -- 50% bug probability
x = rnd(120), -- Random x position
y = -8, -- Start above the screen
priority = priority,
priority_color = priority_color
}
return task
end
-- Initialize Backlog
function init_backlog()
for i=1,MAX_TASKS do
add(backlog, generate_task())
end
end
-- Add falling task
function add_falling_task()
if #backlog > 0 then
local task = deli(backlog, 1)
add(falling_tasks, task)
end
end
-- Move bucket
function move_bucket()
if btn(0) then
bucket.x -= BUCKET_SPEED
end
if btn(1) then
bucket.x += BUCKET_SPEED
end
-- Keep bucket within screen bounds
bucket.x = mid(0, bucket.x, 128 - bucket.width)
end
-- Find index of a task in a list
function indexof(list, item)
for i=1,#list do
if list[i] == item then
return i
end
end
return nil
end
-- Update falling tasks
function update_falling_tasks()
drop_timer += 1
if drop_timer > DROP_INTERVAL then
add_falling_task()
drop_timer = 0
end
for task in all(falling_tasks) do
task.y += FALL_SPEED
-- Check if task is caught by the bucket
if task.y >= bucket.y and task.y <= bucket.y + bucket.height and task.x >= bucket.x and task.x <= bucket.x + bucket.width then
-- Calculate actual story points (considering bugs)
local actual_points = task.story_points
if rnd(1) < task.bug_probability then
actual_points *= 2 -- Double points if it has bugs
bug_found = true
bug_timer = BUG_PAUSE_TIME
sfx(2) -- Buzzer sound
else
sfx(0) -- Happy fanfare for catching a card
end
burndown += actual_points
capacity -= task.story_points
deli(falling_tasks, indexof(falling_tasks, task))
elseif task.y > 128 then
-- Remove task if it falls off the screen
deli(falling_tasks, indexof(falling_tasks, task))
end
end
end
-- Draw Splash Screen
function draw_splash()
cls()
local base_y = 64
local t = splash_timer / 30
local text = "SCRUMASTER"
local text_length = #text * 8
local start_x = (128 - text_length) / 2
for i = 1, #text do
local char = sub(text, i, i)
local y = base_y + 10 * sin(t + i / 6.5)
print(char, start_x + (i - 1) * 8, y, JIRA_BLUE)
end
print("Press X to Start", 30, 90, WHITE)
end
-- Draw UI
function draw_ui()
cls()
-- Draw backlog
print("Backlog", 2, 2, JIRA_BLUE)
for i=1,#backlog do
local task = backlog[i]
print(task.title.." ("..task.story_points.." SP)", 2, 10+i*8, JIRA_BLUE)
end
-- Draw burndown and capacity
print("Burndown: "..burndown, 2, 100, WHITE)
print("Capacity: "..capacity, 2, 110, WHITE)
print("Sprint: "..sprint_number, 2, 120, WHITE)
-- Draw bucket
spr(bucket.sprite_index, bucket.x, bucket.y)
-- Draw falling tasks
for task in all(falling_tasks) do
rectfill(task.x, task.y, task.x + 8, task.y + 8, JIRA_BLUE)
print(task.story_points.." SP", task.x, task.y + 2, WHITE)
pset(task.x + 4, task.y + 4, task.priority_color) -- Draw priority indicator
end
-- Draw bug message if a bug is found
if bug_found then
print("Bug Found!", 50, 30, RED)
end
end
-- Draw Game Over Message
function draw_game_over()
print("Game Over!", 50, 64, WHITE)
if wip_admonished then
print("Limit your WIP!", 40, 80, RED)
end
end
-- Main Update Loop
function _update()
if show_splash then
splash_timer += 1
if splash_timer == 1 then
music(0) -- Start the intro music
end
if btnp(5) then -- 'X' to start the game
music(-1) -- Stop the intro music
show_splash = false
init_backlog()
end
else
if game_over then
game_over_timer += 1
if game_over_timer > GAME_OVER_TIME then
show_splash = true
game_over = false
game_over_timer = 0
wip_admonished = false
sprint_number = 1
burndown = 0
capacity = SPRINT_CAPACITY
backlog = {}
falling_tasks = {}
end
else
if bug_found then
bug_timer -= 1
if bug_timer <= 0 then
bug_found = false
end
else
move_bucket()
update_falling_tasks()
if #falling_tasks < 3 and #backlog > 0 then
add_falling_task()
end
if capacity <= 0 then
game_over = true
elseif #backlog == 0 and #falling_tasks == 0 then
if sprint_number == 1 and burndown < SPRINT_CAPACITY then
wip_admonished = true
end
sprint_number += 1
capacity = SPRINT_CAPACITY
for task in all(falling_tasks) do
add(backlog, task)
end
falling_tasks = {}
init_backlog()
burndown = 0
sfx(1) -- Happy fanfare for completing a sprint
end
end
end
end
end
-- Main Draw Loop
function _draw()
if show_splash then
draw_splash()
else
draw_ui()
if game_over then
draw_game_over()
end
end
end
-- Sound Effects
-- SFX 0: Happy fanfare for catching a card
-- SFX 1: Happy fanfare for completing a sprint
-- SFX 2: Buzzer sound for finding a bug
-- Music
-- Music 0: Intro music
-- Initialize Game
init_backlog()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment