mirror of
https://github.com/Rockbox/rockbox.git
synced 2026-01-22 09:40:35 -05:00
Purge "Menu" or "Rockbox" from plugin menu titles and match application names from manual. Exception: "Main Menu" is left unchanged as the title for the Main Menu Configuration plugin, since it appears in Rockbox's Settings menu and therefore should match the name of the setting. E.g.: "Rockbox Goban" => "Goban" "Image Viewer Menu" => "Image Viewer" "Viewer Menu" => "Text Viewer" "Menu" => "Chess Clock" "Do What?" => "Text Editor" "Mpegplayer Menu" => "MPEG Player" "Multiboot Settings" => "Multiboot" "Disktidy" => "Disk Tidy" ... Change-Id: Ie6d3be7557f31a36309489037ad8b2b27b06706e
701 lines
25 KiB
Lua
701 lines
25 KiB
Lua
--[[
|
|
__________ __ ___.
|
|
Open \______ \ ____ ____ | | _\_ |__ _______ ___
|
|
Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
|
|
Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
|
|
Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
|
|
\/ \/ \/ \/ \/
|
|
$Id$
|
|
|
|
Port and extension of Pixel Painter by Pavel Bakhilau
|
|
(http://js1k.com/2010-first/demo/453) to Rockbox Lua.
|
|
|
|
Copyright (C) 2011 by Stefan Schneider-Kennedy
|
|
|
|
This program is free software; you can redistribute it and/or
|
|
modify it under the terms of the GNU General Public License
|
|
as published by the Free Software Foundation; either version 2
|
|
of the License, or (at your option) any later version.
|
|
|
|
This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
|
|
KIND, either express or implied.
|
|
|
|
]]--
|
|
|
|
--Number of colours used in the game
|
|
--Hard coded here, in the COLOURS and PIP_COLOURS definitions and in
|
|
--get_colours_count's count_table
|
|
NUM_COLOURS = 6
|
|
|
|
--Utility function makes a copy of the passed table
|
|
function deepcopy(object)
|
|
local lookup_table = {}
|
|
local function _copy(object)
|
|
if type(object) ~= "table" then
|
|
return object
|
|
elseif lookup_table[object] then
|
|
return lookup_table[object]
|
|
end
|
|
local new_table = {}
|
|
lookup_table[object] = new_table
|
|
for index, value in pairs(object) do
|
|
new_table[_copy(index)] = _copy(value)
|
|
end
|
|
return setmetatable(new_table, getmetatable(object))
|
|
end
|
|
return _copy(object)
|
|
end
|
|
|
|
--Returns the maximum value of the passed table and its index
|
|
function table_maximum(a)
|
|
local mi = 1
|
|
local m = a[mi]
|
|
for i, val in ipairs(a) do
|
|
if val > m then
|
|
mi = i
|
|
m = val
|
|
end
|
|
end
|
|
return m, mi
|
|
end
|
|
|
|
--Solves the board using a simple algorithm and returns the number of
|
|
--moves required. Each turn, the function picks the move which fills in
|
|
--the greatest area of board. The number of moves required to complete
|
|
--it is returned.
|
|
function calculate_par(board)
|
|
local board_dimension = table.getn(board)
|
|
local test_game_copy = deepcopy(board)
|
|
local moves = 0
|
|
|
|
repeat
|
|
local non_matching = {}
|
|
fill_board(test_game_copy, 0, 1, 1, test_game_copy[1][1], non_matching)
|
|
|
|
if table.getn(non_matching) > 0 then
|
|
local count_table = get_colours_count(test_game_copy, non_matching)
|
|
local max_value, colour = table_maximum(count_table)
|
|
|
|
--Corrects the invalid colour values set by
|
|
--get_colours_count, this also acts as a move
|
|
for x=1,board_dimension do
|
|
for y=1,board_dimension do
|
|
if test_game_copy[x][y] < 0 then
|
|
test_game_copy[x][y] = test_game_copy[x][y] * -1
|
|
elseif test_game_copy[x][y] == 0 then
|
|
test_game_copy[x][y] = colour
|
|
end
|
|
end
|
|
end
|
|
else
|
|
return moves
|
|
end
|
|
--Manual garbage collection is needed so it doesn't eat into the
|
|
--audio buffer, see http://forums.rockbox.org/index.php/topic,27120.msg177434.html
|
|
collectgarbage("collect")
|
|
moves = moves + 1
|
|
until false
|
|
end
|
|
|
|
--Calculates the number of blocks of each colour adjacent to the filled
|
|
--region identified by the passed parameters. A colour indexed table
|
|
--containing the counts is returned. Relies on the board having been
|
|
--flood filled with 0s prior to executing this function.
|
|
--
|
|
--The 'board' table is also adjusted as follows: The filled region's
|
|
--colour index is set to zero and each of the adjacent areas' colour
|
|
--indexes are multiplied by -1. These invalid colour values are later
|
|
--corrected in the calculate_par function.
|
|
function get_colours_count(board, non_matching)
|
|
local count_table = {0, 0, 0, 0, 0, 0}
|
|
repeat
|
|
--Pop the array
|
|
local current = non_matching[table.getn(non_matching)]
|
|
table.remove(non_matching)
|
|
--Check this square hasn't already been filled
|
|
local curr_colour = board[current[1]][current[2]]
|
|
if curr_colour > 0 then
|
|
count_table[curr_colour] = count_table[curr_colour] +
|
|
fill_board(board, curr_colour * -1, current[1], current[2], curr_colour)
|
|
end
|
|
until table.getn(non_matching) == 0
|
|
|
|
return count_table
|
|
end
|
|
|
|
--Returns a randomly coloured board of the indicated dimensions
|
|
function generate_board(board_dimension, seed)
|
|
math.randomseed(seed)
|
|
|
|
local board = {}
|
|
for x=1,board_dimension do
|
|
board[x] = {}
|
|
for y=1,board_dimension do
|
|
board[x][y] = math.random(1,NUM_COLOURS)
|
|
end
|
|
end
|
|
|
|
return board
|
|
end
|
|
|
|
--Flood fills the board from the top left using selected_colour
|
|
--Returns the number of boxes filled
|
|
function fill_board(board, fill_colour, x, y, original_colour, non_matching)
|
|
local board_dimension = table.getn(board)
|
|
if x > 0 and y > 0 and x <= board_dimension and y <= board_dimension then
|
|
if board[x][y] == original_colour then
|
|
board[x][y] = fill_colour
|
|
return fill_board(board, fill_colour, x - 1, y, original_colour, non_matching) +
|
|
fill_board(board, fill_colour, x, y - 1, original_colour, non_matching) +
|
|
fill_board(board, fill_colour, x + 1, y, original_colour, non_matching) +
|
|
fill_board(board, fill_colour, x, y + 1, original_colour, non_matching) + 1
|
|
elseif(non_matching ~= nil and board[x][y] ~= fill_colour) then
|
|
table.insert(non_matching, {x,y})
|
|
end
|
|
end
|
|
|
|
return 0
|
|
end
|
|
|
|
--Checks whether the given board is a single colour
|
|
function check_win(board)
|
|
for x,col in pairs(board) do
|
|
for y,value in pairs(col) do
|
|
if value ~= board[1][1] then
|
|
return false
|
|
end
|
|
end
|
|
end
|
|
|
|
return true
|
|
end
|
|
|
|
--Attempt to load the game variables stored in the indicated save file.
|
|
--Returns a table containing game variables if the file can be opened,
|
|
--false otherwise.
|
|
--Table keys are: difficulty, par, move_number, selected_colour, board
|
|
function load_game(filename)
|
|
local f = io.open(filename, "r")
|
|
if f ~= nil then
|
|
local rtn = {}
|
|
rtn["difficulty"] = tonumber(f:read())
|
|
rtn["par"] = tonumber(f:read())
|
|
rtn["move_number"] = tonumber(f:read())
|
|
rtn["selected_colour"] = tonumber(f:read())
|
|
|
|
local board={}
|
|
local dimension = diff_to_dimension(rtn["difficulty"])
|
|
for x=1,dimension do
|
|
board[x] = {}
|
|
local line = f:read()
|
|
local bits = {line:match(("([^ ]*) "):rep(dimension))}
|
|
for y=1,dimension do
|
|
board[x][y] = tonumber(bits[y])
|
|
end
|
|
end
|
|
rtn["board"] = board
|
|
|
|
f:close()
|
|
return rtn
|
|
else
|
|
return false
|
|
end
|
|
end
|
|
|
|
--Saves the game state to file
|
|
function save_game(state, filename)
|
|
local f = io.open(filename, "w")
|
|
if f ~= nil then
|
|
f:write(state["difficulty"],"\n")
|
|
f:write(state["par"],"\n")
|
|
f:write(state["move_number"],"\n")
|
|
f:write(state["selected_colour"],"\n")
|
|
local board = state["board"]
|
|
local dimension = diff_to_dimension(state["difficulty"])
|
|
for x=1,dimension do
|
|
for y=1,dimension do
|
|
f:write(board[x][y]," ")
|
|
end
|
|
f:write("\n")
|
|
end
|
|
f:close()
|
|
return true
|
|
else
|
|
return false
|
|
end
|
|
end
|
|
|
|
--Loads the high scores from file
|
|
--Returns true on success, false otherwise
|
|
function load_scores(filename)
|
|
local f = io.open(filename, "r")
|
|
if f ~= nil then
|
|
local highscores = {}
|
|
for i=1,3 do
|
|
local line = f:read() or ""
|
|
local value = false
|
|
if line ~= "" then
|
|
value = tonumber(line)
|
|
end
|
|
|
|
highscores[i] = value
|
|
end
|
|
f:close()
|
|
return highscores
|
|
else
|
|
return false
|
|
end
|
|
end
|
|
|
|
--Saves the high scores to file
|
|
function save_scores(highscores, filename)
|
|
local f = io.open(filename, "w")
|
|
if f ~= nil then
|
|
for i=1,3 do
|
|
local value = highscores[i]
|
|
if value == false then
|
|
value = ""
|
|
end
|
|
f:write(value,"\n")
|
|
end
|
|
f:close()
|
|
return true
|
|
else
|
|
return false
|
|
end
|
|
end
|
|
|
|
function diff_to_dimension(difficulty)
|
|
if difficulty == 1 then
|
|
return 8
|
|
elseif difficulty == 2 then
|
|
return 16
|
|
else
|
|
return 22
|
|
end
|
|
end
|
|
|
|
--Don't run the RB stuff if we're not running under RB
|
|
if rb ~= nil then
|
|
|
|
if rb.lcd_rgbpack == nil then
|
|
rb.splash(2*rb.HZ, "Non RGB targets not currently supported")
|
|
os.exit()
|
|
end
|
|
|
|
---------------------
|
|
--RB Game variables--
|
|
---------------------
|
|
|
|
--The colours used by the game
|
|
COLOURS = {
|
|
rb.lcd_rgbpack(255, 119, 34),
|
|
rb.lcd_rgbpack(255, 255, 102),
|
|
rb.lcd_rgbpack(119, 204, 51),
|
|
rb.lcd_rgbpack(102, 170, 255),
|
|
rb.lcd_rgbpack(51, 68, 255),
|
|
rb.lcd_rgbpack(51, 51, 51),
|
|
}
|
|
--The colour of the selection pip
|
|
PIP_COLOURS = {
|
|
rb.lcd_rgbpack(0, 0, 0),
|
|
rb.lcd_rgbpack(0, 0, 0),
|
|
rb.lcd_rgbpack(0, 0, 0),
|
|
rb.lcd_rgbpack(0, 0, 0),
|
|
rb.lcd_rgbpack(0, 0, 0),
|
|
rb.lcd_rgbpack(255, 255, 255),
|
|
}
|
|
DEFAULT_DIFFICULTY = 2 --1: Easy, 2: Normal, 3: Hard
|
|
|
|
FILES_ROOT = rb.PLUGIN_GAMES_DATA_DIR
|
|
SCORES_FILE = FILES_ROOT.."/pixel-painter.score"
|
|
SAVE_FILE = FILES_ROOT.."/pixel-painter.save"
|
|
r,w,TEXT_LINE_HEIGHT = rb.font_getstringsize(" ", rb.FONT_UI) --Get font height
|
|
--Determine which layout to use by considering the screen dimensions
|
|
--the +9 is so we have space for the chooser
|
|
if rb.LCD_WIDTH > (rb.LCD_HEIGHT + 9) then
|
|
LAYOUT = 1 --Wider than high, status and chooser on right
|
|
elseif rb.LCD_HEIGHT > (rb.LCD_WIDTH + 9) then
|
|
LAYOUT = 2 --Higher than wide, status and chooser below
|
|
else
|
|
LAYOUT = 3 --Treat like a square screen, chooser on right, status below
|
|
end
|
|
|
|
--Display variables
|
|
chooser_pip_dimension = 6 --pixel dimension of the selected colour pip
|
|
block_width = 0 --pixel dimension of each game square
|
|
chooser_start_pos = 0 --x or y position of the first block (depending on LAYOUT)
|
|
|
|
--Populated by load_scores()
|
|
highscores = {false, false, false}
|
|
|
|
--A table containing the game state, initialised by init_game() or
|
|
--load_game(), see
|
|
game_state = {}
|
|
|
|
-----------------------------------
|
|
--Display and interface functions--
|
|
-----------------------------------
|
|
|
|
--Sets up a new game and display variables for the indicated
|
|
--difficulty
|
|
function init_game(difficulty)
|
|
init_display_variables(difficulty)
|
|
local state = {}
|
|
local board_dimension = diff_to_dimension(difficulty)
|
|
state["selected_colour"] = 1
|
|
state["move_number"] = 0
|
|
state["difficulty"] = difficulty
|
|
state["board"] = generate_board(board_dimension, rb.current_tick()+os.time())
|
|
rb.splash(1, "Calculating par...") --Will stay on screen until it's done
|
|
state["par"] = calculate_par(state["board"])
|
|
|
|
return state
|
|
end
|
|
|
|
--Initialises the display variables for the screen LAYOUT
|
|
function init_display_variables(difficulty)
|
|
local board_dimension = diff_to_dimension(difficulty)
|
|
|
|
if LAYOUT == 1 then
|
|
block_width = rb.LCD_HEIGHT / board_dimension
|
|
chooser_start_pos = (board_dimension)*block_width + 2
|
|
chooser_width = rb.LCD_WIDTH - chooser_start_pos
|
|
chooser_height = (rb.LCD_HEIGHT - 3*TEXT_LINE_HEIGHT) / NUM_COLOURS
|
|
elseif LAYOUT == 2 then
|
|
block_width = rb.LCD_WIDTH / board_dimension
|
|
chooser_start_pos = board_dimension*block_width + 2 + TEXT_LINE_HEIGHT
|
|
chooser_width = rb.LCD_WIDTH / NUM_COLOURS
|
|
chooser_height = rb.LCD_HEIGHT - chooser_start_pos
|
|
else
|
|
if TEXT_LINE_HEIGHT > 9 then
|
|
block_width = (rb.LCD_HEIGHT - TEXT_LINE_HEIGHT) / board_dimension
|
|
else
|
|
block_width = (rb.LCD_HEIGHT - 9) / board_dimension
|
|
end
|
|
chooser_start_pos = (board_dimension)*block_width + 1
|
|
chooser_width = rb.LCD_WIDTH - chooser_start_pos
|
|
chooser_height = (rb.LCD_HEIGHT - TEXT_LINE_HEIGHT) / NUM_COLOURS
|
|
end
|
|
end
|
|
|
|
--Draws the game board to screen
|
|
function draw_board(board)
|
|
for x,col in pairs(board) do
|
|
for y,value in pairs(col) do
|
|
rb.lcd_set_foreground(COLOURS[value])
|
|
rb.lcd_fillrect((x-1)*block_width, (y-1)*block_width, block_width, block_width)
|
|
end
|
|
end
|
|
end
|
|
|
|
--Draw the colour chooser along with selected pip at the appropriate
|
|
--position
|
|
function draw_chooser(selected_colour)
|
|
for i=1,NUM_COLOURS do
|
|
rb.lcd_set_foreground(COLOURS[i])
|
|
if LAYOUT == 1 or LAYOUT == 3 then
|
|
rb.lcd_fillrect(chooser_start_pos, (i - 1)*(chooser_height), chooser_width, chooser_height)
|
|
elseif LAYOUT == 2 then
|
|
rb.lcd_fillrect((i - 1)*(chooser_width), chooser_start_pos, chooser_width, chooser_height)
|
|
end
|
|
end
|
|
|
|
rb.lcd_set_foreground(PIP_COLOURS[selected_colour])
|
|
local xpos = 0
|
|
local ypos = 0
|
|
if LAYOUT == 1 or LAYOUT == 3 then
|
|
xpos = chooser_start_pos + (chooser_width - chooser_pip_dimension)/2
|
|
ypos = (selected_colour-1)*(chooser_height) + (chooser_height - chooser_pip_dimension)/2
|
|
elseif LAYOUT == 2 then
|
|
xpos = (selected_colour-1)*(chooser_width) + (chooser_width - chooser_pip_dimension)/2
|
|
ypos = chooser_start_pos + (chooser_height - chooser_pip_dimension)/2
|
|
end
|
|
rb.lcd_fillrect(xpos, ypos, chooser_pip_dimension, chooser_pip_dimension)
|
|
end
|
|
|
|
--Draws the current moves, par and high score
|
|
function draw_status(move_number, par, highscore)
|
|
local strings = {"Move", move_number, "Par", par}
|
|
if highscore then
|
|
table.insert(strings, "Best")
|
|
table.insert(strings, highscore)
|
|
end
|
|
|
|
if LAYOUT == 1 then
|
|
local function calc_string(var_len_str, static_str)
|
|
local avail_width = chooser_width - rb.font_getstringsize(static_str, rb.FONT_UI)
|
|
local rtn_str = ""
|
|
|
|
for i=1,string.len(var_len_str) do
|
|
local c = string.sub(var_len_str, i, i)
|
|
local curr_width = rb.font_getstringsize(rtn_str, rb.FONT_UI)
|
|
local width = rb.font_getstringsize(c, rb.FONT_UI)
|
|
|
|
if curr_width + width <= avail_width then
|
|
rtn_str = rtn_str .. c
|
|
else
|
|
break
|
|
end
|
|
end
|
|
|
|
return rtn_str, rb.font_getstringsize(rtn_str, rb.FONT_UI)
|
|
end
|
|
|
|
local height = NUM_COLOURS*chooser_height
|
|
colon_width = rb.font_getstringsize(": ", rb.FONT_UI)
|
|
for i = 1,table.getn(strings),2 do
|
|
local label, label_width = calc_string(strings[i], ": "..strings[i+1])
|
|
|
|
rb.lcd_set_foreground(rb.lcd_rgbpack(255,0,0))
|
|
rb.lcd_putsxy(chooser_start_pos, height, label..": ")
|
|
rb.lcd_set_foreground(rb.lcd_rgbpack(255,255,255))
|
|
rb.lcd_putsxy(chooser_start_pos + label_width + colon_width, height, strings[i+1])
|
|
height = height + TEXT_LINE_HEIGHT
|
|
end
|
|
else
|
|
local text_ypos = 0
|
|
if LAYOUT == 2 then
|
|
text_ypos = chooser_start_pos - TEXT_LINE_HEIGHT - 1
|
|
else
|
|
text_ypos = rb.LCD_HEIGHT - TEXT_LINE_HEIGHT
|
|
end
|
|
space_width = rb.font_getstringsize(" ", rb.FONT_UI)
|
|
local xpos = 0
|
|
for i = 1,table.getn(strings),2 do
|
|
rb.lcd_set_foreground(rb.lcd_rgbpack(255,0,0))
|
|
rb.lcd_putsxy(xpos, text_ypos, strings[i]..": ")
|
|
xpos = xpos + rb.font_getstringsize(strings[i]..": ", rb.FONT_UI)
|
|
rb.lcd_set_foreground(rb.lcd_rgbpack(255,255,255))
|
|
rb.lcd_putsxy(xpos, text_ypos, strings[i+1])
|
|
xpos = xpos + rb.font_getstringsize(strings[i+1], rb.FONT_UI) + space_width
|
|
end
|
|
end
|
|
end
|
|
|
|
--Convenience function to redraw the whole board to screen
|
|
function redraw_game(game_state, highscores)
|
|
rb.lcd_clear_display()
|
|
draw_board(game_state["board"])
|
|
draw_chooser(game_state["selected_colour"])
|
|
draw_status(game_state["move_number"], game_state["par"],
|
|
highscores[game_state["difficulty"]])
|
|
rb.lcd_update()
|
|
end
|
|
|
|
|
|
--Draws help to screen, waits for a keypress to exit
|
|
function app_help()
|
|
rb.lcd_clear_display()
|
|
|
|
local title = "Pixel painter help"
|
|
local rtn, title_width, h = rb.font_getstringsize(title, rb.FONT_UI)
|
|
local title_xpos = (rb.LCD_WIDTH - title_width) / 2
|
|
local space_width = rb.font_getstringsize(" ", rb.FONT_UI)
|
|
|
|
--Draw title
|
|
function draw_text(y_offset)
|
|
rb.lcd_set_foreground(rb.lcd_rgbpack(255,0,0))
|
|
rb.lcd_putsxy(title_xpos, y_offset, title)
|
|
rb.lcd_hline(title_xpos, title_xpos + title_width, TEXT_LINE_HEIGHT + y_offset)
|
|
rb.lcd_set_foreground(rb.lcd_rgbpack(255,255,255))
|
|
|
|
local body_text = [[
|
|
The aim is to fill the screen with a single colour. Each move you select a new colour which is then filled in from the top left corner.
|
|
|
|
The bottom right displays the number of moves taken, the number of moves used by the computer and your best score relative to the computer's.
|
|
]]
|
|
local body_len = string.len(body_text)
|
|
|
|
--Draw body text
|
|
local word_buffer = ""
|
|
local xpos = 0
|
|
local ypos = TEXT_LINE_HEIGHT * 2
|
|
for i=1,body_len do
|
|
local c = string.sub(body_text, i, i)
|
|
if c == " " or c == "\n" then
|
|
local word_length = rb.font_getstringsize(word_buffer, rb.FONT_UI)
|
|
if (xpos + word_length) > rb.LCD_WIDTH then
|
|
xpos = 0
|
|
ypos = ypos + TEXT_LINE_HEIGHT
|
|
end
|
|
rb.lcd_putsxy(xpos, ypos + y_offset, word_buffer)
|
|
|
|
word_buffer = ""
|
|
if c == "\n" then
|
|
xpos = 0
|
|
ypos = ypos + TEXT_LINE_HEIGHT
|
|
else
|
|
xpos = xpos + word_length + space_width
|
|
end
|
|
else
|
|
word_buffer = word_buffer .. c
|
|
end
|
|
end
|
|
|
|
rb.lcd_update()
|
|
|
|
return ypos
|
|
end
|
|
|
|
--Deal with scrolling the help
|
|
local y_offset = 0
|
|
local max_y_offset = math.max(draw_text(y_offset) - rb.LCD_HEIGHT, 0)
|
|
local exit = false
|
|
repeat
|
|
local action = rb.get_plugin_action(0)
|
|
if action == rb.actions.PLA_DOWN then
|
|
y_offset = math.max(-max_y_offset, y_offset - TEXT_LINE_HEIGHT)
|
|
elseif action == rb.actions.PLA_UP then
|
|
y_offset = math.min(0, y_offset + TEXT_LINE_HEIGHT)
|
|
elseif action == rb.actions.PLA_LEFT or
|
|
action == rb.actions.PLA_RIGHT or
|
|
action == rb.actions.PLA_SELECT or
|
|
action == rb.actions.PLA_EXIT or
|
|
action == rb.actions.PLA_CANCEL then
|
|
--This explicit enumeration is needed for targets like
|
|
--the iriver which send more than one action when
|
|
--scrolling
|
|
|
|
exit = true
|
|
end
|
|
rb.lcd_clear_display()
|
|
draw_text(y_offset)
|
|
until exit == true
|
|
end
|
|
|
|
--Draws the application menu and handles its logic
|
|
function app_menu()
|
|
local options = {"Resume game", "Start new game", "Change difficulty",
|
|
"Help", "Quit without saving", "Quit"}
|
|
local item = rb.do_menu("Pixel Painter", options, nil, false)
|
|
|
|
if item == 0 then
|
|
redraw_game(game_state, highscores)
|
|
elseif item == 1 then
|
|
os.remove(SAVE_FILE)
|
|
game_state = init_game(game_state["difficulty"])
|
|
redraw_game(game_state, highscores)
|
|
elseif item == 2 then
|
|
local diff = rb.do_menu("Difficulty", {"Easy", "Medium", "Hard"}, game_state["difficulty"] - 1, false)
|
|
if diff < 0 then
|
|
app_menu()
|
|
else
|
|
local difficulty = diff + 1 --lua is 1 indexed
|
|
os.remove(SAVE_FILE)
|
|
game_state = init_game(difficulty)
|
|
redraw_game(game_state, highscores)
|
|
end
|
|
elseif item == 3 then
|
|
app_help()
|
|
redraw_game(game_state, highscores)
|
|
elseif item == 4 then
|
|
os.remove(SAVE_FILE)
|
|
os.exit()
|
|
elseif item == 5 then
|
|
rb.splash(1, "Saving game...") --Will stay on screen till the app exits
|
|
save_game(game_state,SAVE_FILE)
|
|
os.exit()
|
|
end
|
|
end
|
|
|
|
--Determine what victory text to show depending on the relation of the
|
|
--score to the calculated par value
|
|
function win_text(delta)
|
|
if delta < 0 then
|
|
return "You were "..(-1*delta).." under par"
|
|
elseif delta > 0 then
|
|
return "You were "..delta.." over par"
|
|
else
|
|
return "You attained par"
|
|
end
|
|
end
|
|
|
|
------------------
|
|
--Game main loop--
|
|
------------------
|
|
|
|
--Gives the option of testing things without running the game, use:
|
|
--as_library=true
|
|
--dofile('pixel-painter.lua')
|
|
if not as_library then
|
|
game_state = load_game(SAVE_FILE)
|
|
if game_state then
|
|
init_display_variables(game_state["difficulty"])
|
|
else
|
|
game_state = init_game(DEFAULT_DIFFICULTY)
|
|
end
|
|
loaded_scores = load_scores(SCORES_FILE)
|
|
if loaded_scores then
|
|
highscores = loaded_scores
|
|
end
|
|
redraw_game(game_state, highscores)
|
|
|
|
require("actions")
|
|
--Set the keys to use for scrolling the chooser
|
|
if LAYOUT == 1 or LAYOUT == 3 then -- landscape and square screens
|
|
prev_action = rb.actions.PLA_UP
|
|
prev_action_repeat = rb.actions.PLA_UP_REPEAT
|
|
next_action = rb.actions.PLA_DOWN
|
|
next_action_repeat = rb.actions.PLA_DOWN_REPEAT
|
|
else -- portrait screens
|
|
prev_action = rb.actions.PLA_LEFT
|
|
prev_action_repeat = rb.actions.PLA_LEFT_REPEAT
|
|
next_action = rb.actions.PLA_RIGHT
|
|
next_action_repeat = rb.actions.PLA_RIGHT_REPEAT
|
|
end
|
|
|
|
repeat
|
|
local action = rb.get_plugin_action(-1) -- TIMEOUT_BLOCK
|
|
|
|
if action == rb.actions.PLA_SELECT then
|
|
--Ensure the user has changed the colour before allowing move
|
|
--TODO: Check that the move would change the board
|
|
|
|
if game_state["selected_colour"] ~= game_state["board"][1][1] then
|
|
fill_board(game_state["board"], game_state["selected_colour"],
|
|
1, 1, game_state["board"][1][1])
|
|
game_state["move_number"] = game_state["move_number"] + 1
|
|
redraw_game(game_state, highscores)
|
|
|
|
if check_win(game_state["board"]) then
|
|
local par_diff = game_state["move_number"] - game_state["par"]
|
|
if not highscores[game_state["difficulty"]] or
|
|
par_diff < highscores[game_state["difficulty"]] then
|
|
--
|
|
rb.splash(3*rb.HZ, win_text(par_diff)..", a new high score!")
|
|
highscores[game_state["difficulty"]] = par_diff
|
|
save_scores(highscores, SCORES_FILE)
|
|
else
|
|
rb.splash(3*rb.HZ, win_text(par_diff)..".")
|
|
end
|
|
os.remove(SAVE_FILE)
|
|
os.exit()
|
|
end
|
|
else
|
|
--Will stay on screen until they move
|
|
rb.splash(1, "Invalid move (wouldn't change board). Change colour to continue.")
|
|
end
|
|
elseif action == next_action or action == next_action_repeat then
|
|
if game_state["selected_colour"] < NUM_COLOURS then
|
|
game_state["selected_colour"] = game_state["selected_colour"] + 1
|
|
else
|
|
game_state["selected_colour"] = 1
|
|
end
|
|
redraw_game(game_state, highscores)
|
|
elseif action == prev_action or action == prev_action_repeat then
|
|
if game_state["selected_colour"] > 1 then
|
|
game_state["selected_colour"] = game_state["selected_colour"] - 1
|
|
else
|
|
game_state["selected_colour"] = NUM_COLOURS
|
|
end
|
|
redraw_game(game_state, highscores)
|
|
elseif action == rb.actions.PLA_CANCEL then
|
|
app_menu()
|
|
end
|
|
until action == rb.actions.PLA_EXIT
|
|
--This is executed if the user presses PLA_EXIT
|
|
rb.splash(1, "Saving game...") --Will stay on screen till the app exits
|
|
save_game(game_state,SAVE_FILE)
|
|
end
|
|
end
|