summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNathan Korth <nkorth@nkorth.com>2012-02-25 10:34:26 -0500
committerWilliam Wilgus <wilgus.william@gmail.com>2024-04-28 00:21:16 -0400
commit2c7e47fc121014c1218d58248cd7c49cf2f38f0a (patch)
tree1900db6cb35b94dcda6b93f0d2d0ba096979e796
parent3ae48284c1dcca3515785d15444d3dd4000cbfe5 (diff)
downloadrockbox-2c7e47fc121014c1218d58248cd7c49cf2f38f0a.tar.gz
rockbox-2c7e47fc121014c1218d58248cd7c49cf2f38f0a.zip
New plugin: Picross
Picross is a puzzle game also known as Picture Crossword, Nonograms, or Paint By Numbers. See http://en.wikipedia.org/wiki/Nonogram for information on how to play. Update 1: nicer graphics with less images, fixed directory listing, changed how the board works to make a lot of math more sane Update 2: added missing rb.yield to viewPicture loop Update 3: you can now save a game in progress Update 4: fixed a file pointer leak, improved the numbers font Update 5: no images, use vector num draw library add zoom, freedraw -- Bilgus Change-Id: Idc476b46b6eaa10818400fa789701d5bac83467f
-rw-r--r--apps/plugins/CATEGORIES1
-rw-r--r--apps/plugins/SOURCES1
-rw-r--r--apps/plugins/SUBDIRS1
-rw-r--r--apps/plugins/picross.lua820
-rw-r--r--apps/plugins/picross/picross.make24
-rwxr-xr-xapps/plugins/picross/picross_default.picross7
-rw-r--r--apps/plugins/picross/rb.picross7
-rwxr-xr-xtools/buildzip.pl11
8 files changed, 872 insertions, 0 deletions
diff --git a/apps/plugins/CATEGORIES b/apps/plugins/CATEGORIES
index 28b8b67c68..db0eb70fc4 100644
--- a/apps/plugins/CATEGORIES
+++ b/apps/plugins/CATEGORIES
@@ -82,6 +82,7 @@ pacbox,games
82pdbox,viewers 82pdbox,viewers
83pegbox,games 83pegbox,games
84periodic_table,apps 84periodic_table,apps
85picross,games
85pictureflow,demos 86pictureflow,demos
86pitch_detector,apps 87pitch_detector,apps
87pitch_screen,viewers 88pitch_screen,viewers
diff --git a/apps/plugins/SOURCES b/apps/plugins/SOURCES
index edc801362f..ff08074f82 100644
--- a/apps/plugins/SOURCES
+++ b/apps/plugins/SOURCES
@@ -116,6 +116,7 @@ metronome.c
116/* Lua needs at least 160 KB to work in */ 116/* Lua needs at least 160 KB to work in */
117#if PLUGIN_BUFFER_SIZE >= 0x80000 117#if PLUGIN_BUFFER_SIZE >= 0x80000
118boomshine.lua 118boomshine.lua
119picross.lua
119lua_scripts.lua 120lua_scripts.lua
120#ifdef HAVE_LCD_COLOR 121#ifdef HAVE_LCD_COLOR
121pixel-painter.lua 122pixel-painter.lua
diff --git a/apps/plugins/SUBDIRS b/apps/plugins/SUBDIRS
index b9c18b5fd9..7884989d1c 100644
--- a/apps/plugins/SUBDIRS
+++ b/apps/plugins/SUBDIRS
@@ -87,4 +87,5 @@ mpegplayer
87#if PLUGIN_BUFFER_SIZE >= 0x80000 87#if PLUGIN_BUFFER_SIZE >= 0x80000
88lua 88lua
89lua_scripts 89lua_scripts
90picross
90#endif 91#endif
diff --git a/apps/plugins/picross.lua b/apps/plugins/picross.lua
new file mode 100644
index 0000000000..26ad57ee74
--- /dev/null
+++ b/apps/plugins/picross.lua
@@ -0,0 +1,820 @@
1--[[
2 __________ __ ___.
3 Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 \/ \/ \/ \/ \/
8
9Port of Picross (aka. Picture Crossword, Nonograms, Paint By Numbers)
10Copyright (c) 2012 by Nathan Korth
11
12See http://en.wikipedia.org/wiki/Nonogram for details on how to play, and
13http://nkorth.com/picross for more puzzles.
14
15]]--
16
17require "actions"
18require "luadir"
19require("rbsettings")
20require("settings")
21
22local _nums = require("draw_num")
23local _clr = require("color") -- clrset, clrinc provides device independent colors
24local _lcd = require("lcd") -- lcd helper functions
25
26local plugindir = rb.PLUGIN_GAMES_DATA_DIR
27local userdir = plugindir .. "/picross"
28
29local wrap = rb.settings.read('global_settings', rb.system.global_settings.list_wraparound)
30wrap = (wrap or 1) == 1
31
32do -- free up some ram by removing items we don't need
33 local function strip_functions(t, ...)
34 local t_keep = {...}
35 local keep
36 for key, val in pairs(t) do
37 keep = false
38 for _, v in ipairs(t_keep) do
39 if string.find (key, v) then
40 keep = true; break
41 end
42 end
43 if keep ~= true then
44 t[key] = nil
45 end
46 end
47 end
48
49 strip_functions(rb.actions, "PLA_", "TOUCHSCREEN", "_NONE")
50 rb.contexts = nil
51
52 _clr.inc = nil
53 rb.metadata = nil -- remove metadata settings
54 rb.system = nil -- remove system settings
55 rb.settings = nil --remove setting read/write fns
56end
57
58--colors for fg/bg ------------------------
59local WHITE = _clr.set(-1, 255, 255, 255)
60local BLACK = _clr.set(0, 0, 0, 0)
61-------------------------------------------
62
63-- set colors on color targets
64if rb.lcd_rgbpack ~= nil then
65 rb.lcd_set_background(rb.lcd_rgbpack(255, 255, 255))
66 rb.lcd_set_foreground(rb.lcd_rgbpack(0, 0, 0))
67end
68
69local TEXT_COLOR = BLACK
70
71if rb.LCD_DEPTH == 2 then TEXT_COLOR = bit.bnot(TEXT_COLOR) end
72
73--[[
74-- load images
75local img_numbers = rb.read_bmp_file(rb.current_path().."picross_numbers.bmp")
76
77-- image helper function
78function draw_image(img, x, y, w, h, tilenum)
79
80 local func = rb.lcd_bitmap_transparent_part
81 or rb.lcd_bitmap_part -- Fallback version for grayscale targets
82 or rb.lcd_mono_bitmap_part -- Fallback version for mono targets
83
84 func(img, 0, (tilenum * h), w, x, y, w, h)
85end
86]]
87
88function draw_number(x, y, w, tilenum, scale)
89 scale = scale or 1
90 _nums.print(_LCD, tilenum, x, y, w, TEXT_COLOR, nil, nil, true, scale, scale)
91end
92
93function showComplete(self)
94 if self:isComplete() then
95 rb.splash(rb.HZ * 2, "Puzzle complete!")
96 self:saveGame()
97 self.puzzleh = 50
98 self.puzzlew = 50
99 local old_boardh, old_boardw = self.boardh, self.boardw
100 local old_numbersw, old_numbersh = self.numbersw, self.numbersh
101 while self.numbersh > 0 do -- remove the number rows
102 table.remove (self.board, 1)
103 self.numbersh = self.numbersh - 1
104 end
105 self.numbersh = 0
106 self.numbersw = 0
107 self.solution = nil
108 self.boardh = self.puzzleh
109 self.boardw = self.puzzlew
110 self.freedraw = 0
111 -- find a free number
112 while rb.file_exists(string.format("%s/user_freedraw_%d.picross",
113 userdir, self.freedraw)) do
114 self.freedraw = self.freedraw + 1
115 end
116
117 for r = 1, self.boardh do
118 local old_row = self.board[r] or {}
119
120 self.board[r] = {}
121 -- copy over the last drawing
122 for c = 1, self.boardw do
123 local ch = old_row[c + old_numbersw]
124 if not ch or ch ~= '*' then
125 self.board[r][c] = '.'
126 else
127 self.board[r][c] = '*'
128 end
129 end
130 end
131 rb.splash(rb.HZ * 3, "Free Draw!")
132 self.cursor.x = 1
133 self.cursor.y = 1
134 self.showComplete = function() end --show once, then remove the reference
135 end
136end
137
138local State = {
139 puzzlew = 0,
140 puzzleh = 0,
141 numbersw = 0,
142 numbersh = 0,
143 boardw = 0,
144 boardh = 0,
145 board = {},
146 solution = {},
147 filename = '',
148 cursor = {x = 0, y = 0},
149 scale = 1,
150 freedraw = false
151}
152
153--[[
154
155Notes on how puzzles work in the code:
156
157The "board" array is bigger than the actual puzzle, so the numbers
158above and to the left of it can be stored and do not need to be recalculated
159for every draw. (The "solution" array is the same size as the puzzle, however.)
160The various width/height variables help keep track of where everything is.
161(they should be fairly self-explanatory)
162
163The width/height of the numbers section is always half the width/height of the
164puzzle. For odd-number-sized puzzles, the value must be rounded up. This is
165because strings of squares must have at least one blank space in between. For
166example, on a board 5 wide, the maximum set of row numbers is "1 1 1".
167
168Here are the values used in the "board" array:
169 ' ': empty space
170 '.': unfilled square
171 '*': filled square
172 [number]: number (not a string)
173
174The .picross puzzle files are text files which look pretty much the same as the
175"board" array, with two differences:
176
177 - puzzle files should not contain numbers, because they will be generated
178 based on the puzzle at runtime
179 - blank lines and lines starting with '#' are ignored
180
181]]--
182
183function State:initBoard()
184 if self.freedraw then
185 -- clear board (set the puzzle area to '.' and everything else to ' ')
186 self.board = {}
187 for r = 1,self.boardh do
188 self.board[r] = {}
189 for c = 1,self.boardw do
190 if r > self.numbersh and c > self.numbersw then
191 self.board[r][c] = '.'
192 else
193 self.board[r][c] = ' '
194 end
195 end
196 end
197
198 -- reset cursor
199 self.cursor.x = 1
200 self.cursor.y = 1
201 return
202 end --freedraw
203
204 -- metrics
205 self.puzzleh = #self.solution
206 self.puzzlew = #self.solution[1]
207 self.numbersh = math.floor(self.puzzleh / 2) + 1
208 self.numbersw = math.floor(self.puzzlew / 2) + 1
209 self.boardh = self.puzzleh + self.numbersh
210 self.boardw = self.puzzlew + self.numbersw
211 self.showComplete = showComplete
212
213 -- clear board (set the puzzle area to '.' and everything else to ' ')
214 self.board = {}
215 for r = 1,self.boardh do
216 self.board[r] = {}
217 for c = 1,self.boardw do
218 if r > self.numbersh and c > self.numbersw then
219 self.board[r][c] = '.'
220 else
221 self.board[r][c] = ' '
222 end
223 end
224 end
225
226 -- reset cursor
227 self.cursor.x = self.numbersw + 1
228 self.cursor.y = self.numbersh + 1
229
230 -- calculate row numbers
231 local rownums = {}
232 for r = 1,self.puzzleh do
233 rownums[r] = {}
234 local count = 0
235 for c = 1,self.puzzlew do
236 if self.solution[r][c] == '*' then
237 -- filled square
238 count = count + 1
239 else
240 -- empty square
241 if count > 0 then
242 table.insert(rownums[r], count)
243 count = 0
244 end
245 end
246 end
247 -- if there were no empty squares
248 if count > 0 then
249 table.insert(rownums[r], count)
250 count = 0
251 end
252 end
253
254 -- calculate column numbers
255 local columnnums = {}
256 for c = 1,self.puzzlew do
257 columnnums[c] = {}
258 local count = 0
259 for r = 1,self.puzzleh do
260 if self.solution[r][c] == '*' then
261 -- filled square
262 count = count + 1
263 else
264 -- empty square
265 if count > 0 then
266 table.insert(columnnums[c], count)
267 count = 0
268 end
269 end
270 end
271 -- if there were no empty squares
272 if count > 0 then
273 table.insert(columnnums[c], count)
274 count = 0
275 end
276 end
277
278 -- add row numbers to board
279 for r = 1,self.puzzleh do
280 for i,num in ipairs(rownums[r]) do
281 self.board[self.numbersh + r][self.numbersw - #rownums[r] + i] = num
282 end
283 end
284
285 -- add column numbers to board
286 for c = 1,self.puzzlew do
287 for i,num in ipairs(columnnums[c]) do
288 self.board[self.numbersh - #columnnums[c] + i][self.numbersw + c] = num
289 end
290 end
291end
292
293function State:saveGame()
294 local file
295 local boardw, boardh = self.boardw, self.boardh
296
297 if self.freedraw then
298 self.filename = string.format("%s/user_freedraw_%d.picross", userdir, self.freedraw)
299
300
301 --remove blank lines from the end
302 while boardh > 1 and not string.find(table.concat(self.board[boardh]), "\*") do
303 boardh = boardh - 1
304 end
305 --remove blank lines from right
306 local max_w = 0
307 for r = self.numbersh + 1, boardh do
308 for c = max_w + 1, boardw do
309 if self.board[r][c] == '*' then
310 max_w = c
311 end
312 end
313 end
314 boardw = max_w
315 if max_w == 0 then return end--nothing to save
316
317 file = io.open(self.filename, 'w')
318 else
319 file = io.open(plugindir .. '/picross.sav', 'w')
320 end
321
322 if file then
323 file:write("#"..self.filename.."\n")
324 for r = self.numbersh + 1, boardh do
325 for c = self.numbersw + 1, boardw do
326 file:write(self.board[r][c])
327 end
328 file:write("\n")
329 end
330 file:close()
331 if self.freedraw then
332 rb.splash(rb.HZ, "Freedraw saved.")
333 else
334 rb.splash(rb.HZ, "Game saved.")
335 end
336 return true
337 else
338 rb.splash(rb.HZ * 2, "Failed to open save file")
339 return false
340 end
341end
342
343function State:loadSave()
344 local file = io.open(plugindir .. '/picross.sav')
345 if file then
346 -- first line is commented path of original puzzle
347 path = file:read('*l')
348 path = path:sub(2,-1)
349 -- prepare original puzzle
350 if self:loadFile(path) then
351 -- load saved board
352 contents = file:read('*all')
353 file:close()
354 local r = 1
355 for line in contents:gmatch("[^\r\n]+") do
356 local c = 1
357 for char in line:gmatch('.') do
358 self.board[self.numbersh + r][self.numbersw + c] = char
359 c = c + 1
360 end
361 r = r + 1
362 end
363
364 return true
365 else
366 return false
367 end
368 else
369 return false
370 end
371end
372
373function State:loadDefault()
374 self:loadFile(userdir .. '/picross_default.picross')
375end
376
377function State:loadFile(path)
378 local file = io.open(path)
379 if file then
380 self.freedraw = false
381 local board = {}
382 local boardwidth = 0
383 local count = 0
384 contents = file:read('*all')
385
386 for line in contents:gmatch("[^\r\n]+") do
387 count = count + 1
388 -- ignore blank lines and comments
389 if line ~= '' and line:sub(1, 1) ~= '#' then
390 table.insert(board, {}) -- add a new row
391
392 -- ensure all lines are the same width
393 if boardwidth == 0 then
394 boardwidth = #line
395 elseif #line ~= boardwidth then
396 -- a line was the wrong width
397 local err = "Invalid puzzle file!"
398 local msg =
399 string.format("%s (wrong line width ln: %d w: %d)", err, count, #line)
400 rb.splash(rb.HZ * 2, msg)
401 return false
402 end
403 local pos = 0
404 for char in line:gmatch('.') do
405 pos = pos + 1
406 if char == '*' or char == '.' then
407 table.insert(board[#board], char)
408 else
409 local err = "Invalid puzzle file!"
410 local msg = string.format("%s (invalid character ln: %d '%s' @ %d)",
411 err, count, char, pos)
412 -- invalid character in puzzle area
413 rb.splash(rb.HZ * 2, msg)
414 return false
415 end
416 end
417 else
418 -- display puzzle comments
419 --rb.splash(rb.HZ, line:sub(2,#line))
420 end
421 end
422
423 if #board == 0 then
424 -- empty file
425 rb.splash(rb.HZ * 2, "Invalid puzzle file! (empty)")
426 return false
427 end
428
429 file:close()
430
431 self.solution = board
432 self.filename = path
433 if self.puzzleh < 100 and self.puzzlew < 100 then
434 self:initBoard()
435 return true
436 else
437 -- puzzle too big
438 rb.splash(rb.HZ * 2, "Invalid puzzle file! (too big)")
439 return false
440 end
441 else
442 -- file open failed
443 rb.splash(rb.HZ * 2, "Failed to open file!")
444 return false
445 end
446end
447
448function State:drawBoard()
449 local tw, th = 10 * self.scale, 10 * self.scale -- tile width and height (including bottom+right padding)
450
451 local ofsx = rb.LCD_WIDTH/2 - 4 - (self.cursor.x * tw)
452 local ofsy = rb.LCD_HEIGHT/2 - 4 - (self.cursor.y * th)
453
454 rb.lcd_clear_display()
455
456 -- guide lines
457 for r = 0, self.puzzleh do
458 local x1, x2, y =
459 ofsx + tw - 1,
460 ofsx + ((self.boardw + 1) * tw) - 1,
461 ofsy + ((self.numbersh + 1 + r) * th) - 1
462 if r % 5 == 0 or r == self.puzzleh then
463 rb.lcd_hline(x1, x2, y)
464 else
465 for x = x1, x2, 2 do
466 rb.lcd_drawpixel(x, y)
467 end
468 end
469 end
470 for c = 0, self.puzzlew do
471 local x, y1, y2 =
472 ofsx + ((self.numbersw + 1 + c) * tw) - 1,
473 ofsy + th - 1,
474 ofsy + ((self.boardh + 1) * th) - 1
475 if c % 5 == 0 or c == self.puzzlew then
476 rb.lcd_vline(x, y1, y2)
477 else
478 for y = y1,y2, 2 do
479 rb.lcd_drawpixel(x, y)
480 end
481 end
482 end
483
484 -- cursor
485 local cx, cy = ofsx + (self.cursor.x * tw) - 1, ofsy + (self.cursor.y * th) - 1
486 rb.lcd_drawrect(cx, cy, tw + 1, th + 1)
487 local n_width = tw / self.scale / 2 - 1
488 local xc = (tw - 5 * self.scale) / 2
489 -- tiles
490 for r = 1, self.boardh do
491 for c = 1, self.boardw do
492 local x, y = ofsx + (c * tw) + 1, ofsy + (r * th) + 1
493
494 if self.board[r][c] == '.' then
495 -- unfilled square
496 elseif self.board[r][c] == '*' then
497 -- filled square
498 rb.lcd_fillrect(x, y, tw - 3, th - 3)
499 elseif self.board[r][c] == 'x' then
500 -- eliminated square
501 rb.lcd_drawline(x + 1, y + 1, x + tw - 5, y + th - 5)
502 rb.lcd_drawline(x + tw - 5, y + 1, x + 1, y + th - 5)
503 elseif self.board[r][c] == ' ' then
504 -- empty space
505 elseif self.board[r][c] > 0 and self.board[r][c] < 100 then
506 -- number
507 local num = self.board[r][c]
508 if num < 10 then
509 draw_number(x + xc, y, n_width, num, self.scale)
510 draw_number(x + xc + 1, y, n_width, num, self.scale)
511 else
512 draw_number(x, y, n_width, num, self.scale)
513 draw_number(x + 1, y, n_width, num, self.scale)
514 end
515 end
516 end
517 end
518
519 rb.lcd_update()
520end
521
522function State:isComplete()
523 for r = 1,self.puzzleh do
524 for c = 1,self.puzzlew do
525 if self.solution[r][c] == '*' and
526 self.board[self.numbersh + r][self.numbersw + c] ~= '*' then
527 return false
528 end
529 end
530 end
531
532 return true
533end
534
535function State:moveCursor(dir)
536 -- The cursor isn't allowed to move in the top-left quadrant of the board.
537 -- This has to be checked in up and left moves.
538 local in_board_area = (self.cursor.y > (self.numbersh + 1)
539 and self.cursor.x > self.numbersw + 1)
540
541 if dir == 'left' then
542 if (self.cursor.x > (self.numbersw + 1) or self.cursor.y > self.numbersh)
543 and self.cursor.x > 1 then
544 self.cursor.x = self.cursor.x - 1
545 elseif wrap == true then
546 if in_board_area then
547 self.cursor.x = 1
548 else
549 self.cursor.x = self.boardw
550 end
551 dir = 'up'
552 end
553 elseif dir == 'right' then
554 if self.cursor.x < self.boardw then
555 self.cursor.x = self.cursor.x + 1
556 elseif wrap == true then
557 if in_board_area then
558 self.cursor.x = 1
559 else
560 self.cursor.x = self.numbersw + 1
561 end
562 dir = 'down'
563 end
564 end
565
566 if dir == 'up' then
567 if (self.cursor.y > (self.numbersh + 1) or self.cursor.x > self.numbersw)
568 and self.cursor.y > 1 then
569 self.cursor.y = self.cursor.y - 1
570 elseif wrap == true then
571 if in_board_area then
572 self.cursor.y = 1
573 else
574 self.cursor.y = self.boardh
575 end
576 end
577 elseif dir == 'down' then
578 if self.cursor.y < self.boardh then
579 self.cursor.y = self.cursor.y + 1
580 elseif wrap == true then
581 if in_board_area then
582 self.cursor.y = 1
583 else
584 self.cursor.y = self.numbersh + 1
585 end
586 end
587 end
588end
589
590function State:fillSquare(mode)
591 mode = mode or 0
592 if self.cursor.x > self.numbersw and self.cursor.y > self.numbersh then
593 if self.board[self.cursor.y][self.cursor.x] == '*' and mode ~= 2 then
594 -- clear square
595 self.board[self.cursor.y][self.cursor.x] = '.'
596 elseif mode ~= 1 then -- '.' or 'x'
597 -- fill square
598 local x, y = self.cursor.x - self.numbersw, self.cursor.y - self.numbersh
599 if not self.solution or self.solution[y][x] == '*' then
600 self.board[self.cursor.y][self.cursor.x] = '*'
601 else
602 rb.splash(rb.HZ * 2, "Invalid move!")
603 -- "x" square for convenience
604 self.board[self.cursor.y][self.cursor.x] = 'x'
605 end
606 end
607 end
608
609 self:showComplete()
610end
611
612function State:eliminateSquare()
613 if not self.freedraw
614 and self.cursor.x > self.numbersw
615 and self.cursor.y > self.numbersh then
616 if self.board[self.cursor.y][self.cursor.x] == 'x' then
617 -- clear square
618 self.board[self.cursor.y][self.cursor.x] = '.'
619 else-- '.' or '*'
620 -- "x" square
621 self.board[self.cursor.y][self.cursor.x] = 'x'
622 end
623 else
624 self.board[self.cursor.y][self.cursor.x] = '.'
625 end
626end
627
628-- main code ------------------------------------------------------------------
629
630local function mainMenu()
631 local menu = {
632 "Resume",
633 "View picture",
634 "Restart puzzle",
635 "Load puzzle",
636 "Zoom " .. State.scale - 1,
637 "Save progress",
638 "Save and quit",
639 "Quit without saving"
640 }
641 local start
642
643 if State.freedraw then
644 menu[6] = "Save freedraw " .. State.freedraw --Save Progress
645 end
646 while true do
647 local s = rb.do_menu("Picross", menu, start, false)
648 start = s
649 if s == 0 then
650 -- resume
651 return
652 elseif s == 1 then
653 -- view picture
654 viewPicture()
655 start = 0 --resume
656 elseif s == 2 then
657 -- restart
658 State:initBoard()
659 return
660 elseif s == 3 then
661 -- choose puzzle
662 if puzzleList() then
663 return
664 end
665 elseif s == 4 then
666 -- zoom
667 State.scale = State.scale + 1
668 if State.scale > 4 then
669 State.scale = 1
670 end
671 menu[5] = "Zoom " .. State.scale - 1
672 elseif s == 5 then
673 -- save
674 if State:saveGame() then
675 return
676 end
677 elseif s == 6 then
678 -- save and quit
679 if State:saveGame() then
680 os.exit()
681 end
682 elseif s == 7 then
683 -- quit
684 os.exit()
685 elseif s == -2 then
686 -- back button pressed
687 return
688 else
689 -- something strange happened
690 rb.splash(rb.HZ * 2, "Invalid menu index: "..s)
691 end
692 end
693end
694
695function puzzleList()
696 if rb.dir_exists(userdir) then
697 local files = {}
698 for file in luadir.dir(userdir) do
699 if file ~= '.' and file ~= '..' then
700 table.insert(files, file)
701 end
702 end
703
704 table.sort(files)
705 local udir = userdir .. "/"
706 if #files > 0 then
707 local s = rb.do_menu("Puzzles", files, nil, false)
708 if s >= 0 and s < #files then
709 if State:loadFile(udir..files[s+1]) then
710 return true -- return to puzzle screen
711 else
712 -- puzzle failed to load, return to main menu
713 return false
714 end
715 elseif s == -2 then
716 -- back button pressed, return to main menu
717 return false
718 else
719 -- something strange happened
720 rb.splash(rb.HZ * 2, "Invalid menu index: "..s)
721 return false
722 end
723 else
724 rb.splash(rb.HZ * 2, "No puzzles found! Put .picross files in " .. userdir)
725 return false
726 end
727 else
728 rb.splash(rb.HZ * 2, "Put .picross files in " .. userdir)
729 return false
730 end
731end
732
733function viewPicture()
734 rb.lcd_clear_display()
735
736 -- draw filled squares as pixels (scaled 2x)
737 for r = State.numbersh + 1, State.boardh do
738 for c = State.numbersw + 1, State.boardw do
739 if State.board[r][c] == '*' then
740 --rb.lcd_drawpixel(c - State.numbersw, r - State.numbersh)
741 local px = (c - State.numbersw) * State.scale - State.scale + 1
742 local py = (r - State.numbersh) * State.scale - State.scale + 1
743
744 rb.lcd_fillrect(px, py, State.scale, State.scale)
745 end
746 end
747 end
748
749 rb.lcd_update()
750
751 -- exit on button press
752 while true do
753 local action = rb.get_plugin_action(0)
754
755 if action == rb.actions.PLA_EXIT
756 or action == rb.actions.PLA_CANCEL
757 or action == rb.actions.PLA_SELECT then
758 return
759 end
760
761 rb.yield()
762 end
763end
764
765if not State:loadSave() then
766 State:loadDefault()
767end
768
769local act = rb.actions
770local action = act.ACTION_NONE
771local lockdraw = false
772
773while true do
774 action = rb.get_plugin_action(0)
775 if action == rb.actions.PLA_EXIT then
776 lockdraw = false
777 mainMenu()
778 elseif action == act.PLA_UP or action == act.PLA_UP_REPEAT then
779 State:moveCursor('up')
780 elseif action == act.PLA_DOWN or action == act.PLA_DOWN_REPEAT then
781 State:moveCursor('down')
782 elseif action == act.PLA_LEFT or action == act.PLA_LEFT_REPEAT then
783 State:moveCursor('left')
784 elseif action == act.PLA_RIGHT or action == act.PLA_RIGHT_REPEAT then
785 State:moveCursor('right')
786 elseif action == act.PLA_SELECT then
787 if lockdraw then
788 lockdraw = lockdraw - 1
789 if lockdraw < 0 then
790 lockdraw = false
791 elseif lockdraw == 1 then
792 rb.splash(50, "clear")
793 else
794 rb.splash(50, "invert")
795 end
796 else
797 State:fillSquare()
798 end
799 action = act.ACTION_NONE
800 elseif action == act.PLA_SELECT_REPEAT then
801 if State.freedraw and not lockdraw then
802 lockdraw = 2
803 rb.splash(50, "draw")
804 action = act.ACTION_NONE
805 end
806 elseif action == act.PLA_CANCEL then
807 State:eliminateSquare()
808 action = act.ACTION_NONE
809 else
810 action = act.ACTION_NONE
811 end
812
813 if lockdraw and action ~= act.ACTION_NONE then
814 State:fillSquare(lockdraw)
815 end
816
817 State:drawBoard()
818
819 rb.yield()
820end
diff --git a/apps/plugins/picross/picross.make b/apps/plugins/picross/picross.make
new file mode 100644
index 0000000000..7e78c0fb1c
--- /dev/null
+++ b/apps/plugins/picross/picross.make
@@ -0,0 +1,24 @@
1# __________ __ ___.
2# Open \______ \ ____ ____ | | _\_ |__ _______ ___
3# Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
4# Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
5# Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
6# \/ \/ \/ \/ \/
7# $Id$
8#
9
10LUASCR_SRCDIR := $(APPSDIR)/plugins/picross
11LUASCR_BUILDDIR := $(BUILDDIR)/apps/plugins/picross
12LUASCRS := $(wildcard $(LUASCR_SRCDIR)/*.picross)
13
14#DUMMY := $(info [${LUASCRS}])
15
16DUMMY : all
17
18all: $(subst $(LUASCR_SRCDIR)/,$(LUASCR_BUILDDIR)/,$(LUASCRS))
19
20$(LUASCR_BUILDDIR)/%.picross: $(LUASCR_SRCDIR)/%.picross | $(LUASCR_BUILDDIR)
21 $(call PRINTS,CP $(subst $(LUASCR_SRCDIR)/,,$<))cp $< $@
22
23$(LUASCR_BUILDDIR):
24 $(call PRINTS,MKDIR $@)mkdir -p $(LUASCR_BUILDDIR)/
diff --git a/apps/plugins/picross/picross_default.picross b/apps/plugins/picross/picross_default.picross
new file mode 100755
index 0000000000..ad7643b79e
--- /dev/null
+++ b/apps/plugins/picross/picross_default.picross
@@ -0,0 +1,7 @@
1# simple default puzzle
2
3****..*...*..
4*...*.*...*..
5****..*.*****
6*.....*...*..
7*.....*...*..
diff --git a/apps/plugins/picross/rb.picross b/apps/plugins/picross/rb.picross
new file mode 100644
index 0000000000..bb63b506f5
--- /dev/null
+++ b/apps/plugins/picross/rb.picross
@@ -0,0 +1,7 @@
1#open source jukebox firmware
2
3****...**...***.*..*..............
4*...*.*..*.*....*.*.*.............
5****..*..*.*....**..***...**..*..*
6*..**.*..*.*....*.*.*..*.*..*..**.
7*...*..**...***.*..****...**..*..*
diff --git a/tools/buildzip.pl b/tools/buildzip.pl
index 43c304ff12..2956b49492 100755
--- a/tools/buildzip.pl
+++ b/tools/buildzip.pl
@@ -182,6 +182,13 @@ sub make_install {
182 #glob_mkdir("$temp_dir/rocks/demos/lua_scripts"); 182 #glob_mkdir("$temp_dir/rocks/demos/lua_scripts");
183 #glob_copy("$ROOT/apps/plugins/lua_scripts/*.lua", "$temp_dir/rocks/demos/lua_scripts/"); 183 #glob_copy("$ROOT/apps/plugins/lua_scripts/*.lua", "$temp_dir/rocks/demos/lua_scripts/");
184 } 184 }
185 #lua picross puzzles
186 if(-e "$ROOT/apps/plugins/picross") {
187 unless (glob_mkdir("$libdir/rocks/games/picross")) {
188 return 0;
189 }
190 glob_install("$ROOT/apps/plugins/picross/*.picross", "$libdir/rocks/games/picross");
191 }
185 192
186 # all the rest directories 193 # all the rest directories
187 foreach my $t (@userstuff) { 194 foreach my $t (@userstuff) {
@@ -533,6 +540,10 @@ sub buildzip {
533 copy("$ROOT/apps/plugins/sokoban.levels", "$temp_dir/rocks/games/sokoban.levels"); # sokoban levels 540 copy("$ROOT/apps/plugins/sokoban.levels", "$temp_dir/rocks/games/sokoban.levels"); # sokoban levels
534 copy("$ROOT/apps/plugins/snake2.levels", "$temp_dir/rocks/games/snake2.levels"); # snake2 levels 541 copy("$ROOT/apps/plugins/snake2.levels", "$temp_dir/rocks/games/snake2.levels"); # snake2 levels
535 copy("$ROOT/apps/plugins/rockbox-fonts.config", "$temp_dir/rocks/viewers/"); 542 copy("$ROOT/apps/plugins/rockbox-fonts.config", "$temp_dir/rocks/viewers/");
543 # picross files
544 copy("$ROOT/apps/plugins/picross_default.picross", "$temp_dir/rocks/games/picross_default.picross");
545 copy("$ROOT/apps/plugins/bitmaps/native/picross_numbers.bmp",
546 "$temp_dir/rocks/games/picross_numbers.bmp");
536 } 547 }
537 548
538 if(-e "$temp_dir/rocks/demos/pictureflow.rock") { 549 if(-e "$temp_dir/rocks/demos/pictureflow.rock") {