diff options
author | Johannes Schwarz <ubuntuxer@rockbox.org> | 2009-07-08 17:42:37 +0000 |
---|---|---|
committer | Johannes Schwarz <ubuntuxer@rockbox.org> | 2009-07-08 17:42:37 +0000 |
commit | 4dd33aed66e7f8a58900f8c04ae495caa8827042 (patch) | |
tree | 2d5bc0bf25052dadd2eb4c6839e962fe29f6cfe8 | |
parent | 851b0e3234e696ce538414d2b074da023a9e9fc3 (diff) | |
download | rockbox-4dd33aed66e7f8a58900f8c04ae495caa8827042.tar.gz rockbox-4dd33aed66e7f8a58900f8c04ae495caa8827042.zip |
new game plugin for colored players named clix (by Rene Peinthor)
git-svn-id: svn://svn.rockbox.org/rockbox/trunk@21720 a1c6a512-1295-4272-9138-f99709370657
-rw-r--r-- | apps/plugins/CATEGORIES | 1 | ||||
-rw-r--r-- | apps/plugins/SOURCES | 1 | ||||
-rw-r--r-- | apps/plugins/clix.c | 855 | ||||
-rw-r--r-- | manual/plugins/clix.tex | 29 | ||||
-rw-r--r-- | manual/plugins/main.tex | 2 |
5 files changed, 888 insertions, 0 deletions
diff --git a/apps/plugins/CATEGORIES b/apps/plugins/CATEGORIES index 8e4bb7d7c4..a7a8e75b61 100644 --- a/apps/plugins/CATEGORIES +++ b/apps/plugins/CATEGORIES | |||
@@ -12,6 +12,7 @@ chessbox,games | |||
12 | chessclock,apps | 12 | chessclock,apps |
13 | chip8,viewers | 13 | chip8,viewers |
14 | chopper,games | 14 | chopper,games |
15 | clix,games | ||
15 | clock,apps | 16 | clock,apps |
16 | credits,viewers | 17 | credits,viewers |
17 | cube,demos | 18 | cube,demos |
diff --git a/apps/plugins/SOURCES b/apps/plugins/SOURCES index 5fb62a9117..92d1ae6ef6 100644 --- a/apps/plugins/SOURCES +++ b/apps/plugins/SOURCES | |||
@@ -56,6 +56,7 @@ wavview.c | |||
56 | robotfindskitten.c | 56 | robotfindskitten.c |
57 | 57 | ||
58 | #ifdef HAVE_LCD_COLOR | 58 | #ifdef HAVE_LCD_COLOR |
59 | clix.c | ||
59 | ppmviewer.c | 60 | ppmviewer.c |
60 | #endif | 61 | #endif |
61 | 62 | ||
diff --git a/apps/plugins/clix.c b/apps/plugins/clix.c new file mode 100644 index 0000000000..4768859762 --- /dev/null +++ b/apps/plugins/clix.c | |||
@@ -0,0 +1,855 @@ | |||
1 | /*************************************************************************** | ||
2 | * __________ __ ___. | ||
3 | * Open \______ \ ____ ____ | | _\_ |__ _______ ___ | ||
4 | * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / | ||
5 | * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < | ||
6 | * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ | ||
7 | * \/ \/ \/ \/ \/ | ||
8 | * $Id$ | ||
9 | * | ||
10 | * Copyright (C) 2008-2009 Rene Peinthor | ||
11 | * Contribution from Johannes Schwarz (new menu system, use of highscore lib) | ||
12 | * | ||
13 | * All files in this archive are subject to the GNU General Public License. | ||
14 | * See the file COPYING in the source tree root for full license agreement. | ||
15 | * | ||
16 | * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY | ||
17 | * KIND, either express or implied. | ||
18 | * | ||
19 | ****************************************************************************/ | ||
20 | #include "plugin.h" | ||
21 | #include "lib/highscore.h" | ||
22 | #include "lib/playback_control.h" | ||
23 | #include "lib/display_text.h" | ||
24 | |||
25 | PLUGIN_HEADER | ||
26 | |||
27 | #if (CONFIG_KEYPAD == SANSA_E200_PAD) | ||
28 | #define CLIX_BUTTON_QUIT BUTTON_POWER | ||
29 | #define CLIX_BUTTON_UP BUTTON_UP | ||
30 | #define CLIX_BUTTON_DOWN BUTTON_DOWN | ||
31 | #define CLIX_BUTTON_SCROLL_FWD BUTTON_SCROLL_FWD | ||
32 | #define CLIX_BUTTON_SCROLL_BACK BUTTON_SCROLL_BACK | ||
33 | #define CLIX_BUTTON_LEFT BUTTON_LEFT | ||
34 | #define CLIX_BUTTON_RIGHT BUTTON_RIGHT | ||
35 | #define CLIX_BUTTON_CLICK BUTTON_SELECT | ||
36 | |||
37 | #elif (CONFIG_KEYPAD == SANSA_CLIP_PAD) | ||
38 | #define CLIX_BUTTON_QUIT BUTTON_POWER | ||
39 | #define CLIX_BUTTON_UP BUTTON_UP | ||
40 | #define CLIX_BUTTON_DOWN BUTTON_DOWN | ||
41 | #define CLIX_BUTTON_LEFT BUTTON_LEFT | ||
42 | #define CLIX_BUTTON_RIGHT BUTTON_RIGHT | ||
43 | #define CLIX_BUTTON_CLICK BUTTON_SELECT | ||
44 | |||
45 | #elif (CONFIG_KEYPAD == SANSA_FUZE_PAD) | ||
46 | #define CLIX_BUTTON_QUIT BUTTON_HOME | ||
47 | #define CLIX_BUTTON_UP BUTTON_UP | ||
48 | #define CLIX_BUTTON_DOWN BUTTON_DOWN | ||
49 | #define CLIX_BUTTON_SCROLL_FWD BUTTON_SCROLL_FWD | ||
50 | #define CLIX_BUTTON_SCROLL_BACK BUTTON_SCROLL_BACK | ||
51 | #define CLIX_BUTTON_LEFT BUTTON_LEFT | ||
52 | #define CLIX_BUTTON_RIGHT BUTTON_RIGHT | ||
53 | #define CLIX_BUTTON_CLICK BUTTON_SELECT | ||
54 | |||
55 | #elif (CONFIG_KEYPAD == SANSA_C200_PAD) | ||
56 | #define CLIX_BUTTON_QUIT BUTTON_POWER | ||
57 | #define CLIX_BUTTON_UP BUTTON_UP | ||
58 | #define CLIX_BUTTON_DOWN BUTTON_DOWN | ||
59 | #define CLIX_BUTTON_SCROLL_FWD BUTTON_VOL_UP | ||
60 | #define CLIX_BUTTON_SCROLL_BACK BUTTON_VOL_DOWN | ||
61 | #define CLIX_BUTTON_LEFT BUTTON_LEFT | ||
62 | #define CLIX_BUTTON_RIGHT BUTTON_RIGHT | ||
63 | #define CLIX_BUTTON_CLICK BUTTON_SELECT | ||
64 | |||
65 | #elif (CONFIG_KEYPAD == IPOD_4G_PAD) || \ | ||
66 | (CONFIG_KEYPAD == IPOD_3G_PAD) || \ | ||
67 | (CONFIG_KEYPAD == IPOD_1G2G_PAD) | ||
68 | #define CLIX_BUTTON_QUIT BUTTON_MENU | ||
69 | #define CLIX_BUTTON_UP BUTTON_SCROLL_BACK | ||
70 | #define CLIX_BUTTON_DOWN BUTTON_SCROLL_FWD | ||
71 | #define CLIX_BUTTON_CLICK BUTTON_SELECT | ||
72 | #define CLIX_BUTTON_RIGHT BUTTON_RIGHT | ||
73 | #define CLIX_BUTTON_LEFT BUTTON_LEFT | ||
74 | |||
75 | #elif (CONFIG_KEYPAD == GIGABEAT_PAD) | ||
76 | #define CLIX_BUTTON_QUIT BUTTON_POWER | ||
77 | #define CLIX_BUTTON_LEFT BUTTON_LEFT | ||
78 | #define CLIX_BUTTON_RIGHT BUTTON_RIGHT | ||
79 | #define CLIX_BUTTON_CLICK BUTTON_SELECT | ||
80 | #define CLIX_BUTTON_UP BUTTON_UP | ||
81 | #define CLIX_BUTTON_DOWN BUTTON_DOWN | ||
82 | |||
83 | #elif (CONFIG_KEYPAD == GIGABEAT_S_PAD) | ||
84 | #define CLIX_BUTTON_QUIT BUTTON_BACK | ||
85 | #define CLIX_BUTTON_LEFT BUTTON_LEFT | ||
86 | #define CLIX_BUTTON_RIGHT BUTTON_RIGHT | ||
87 | #define CLIX_BUTTON_CLICK BUTTON_SELECT | ||
88 | #define CLIX_BUTTON_UP BUTTON_UP | ||
89 | #define CLIX_BUTTON_DOWN BUTTON_DOWN | ||
90 | |||
91 | #elif (CONFIG_KEYPAD == IRIVER_H10_PAD) | ||
92 | #define CLIX_BUTTON_QUIT BUTTON_POWER | ||
93 | #define CLIX_BUTTON_LEFT BUTTON_LEFT | ||
94 | #define CLIX_BUTTON_RIGHT BUTTON_RIGHT | ||
95 | #define CLIX_BUTTON_CLICK BUTTON_PLAY | ||
96 | #define CLIX_BUTTON_UP BUTTON_SCROLL_UP | ||
97 | #define CLIX_BUTTON_DOWN BUTTON_SCROLL_DOWN | ||
98 | |||
99 | #elif CONFIG_KEYPAD == IAUDIO67_PAD | ||
100 | #define CLIX_BUTTON_QUIT BUTTON_POWER | ||
101 | #define CLIX_BUTTON_LEFT BUTTON_LEFT | ||
102 | #define CLIX_BUTTON_RIGHT BUTTON_RIGHT | ||
103 | #define CLIX_BUTTON_CLICK BUTTON_PLAY | ||
104 | #define CLIX_BUTTON_UP BUTTON_STOP | ||
105 | #define CLIX_BUTTON_DOWN BUTTON_PLAY | ||
106 | |||
107 | #elif CONFIG_KEYPAD == IAUDIO_X5M5_PAD | ||
108 | #define CLIX_BUTTON_QUIT BUTTON_POWER | ||
109 | #define CLIX_BUTTON_LEFT BUTTON_LEFT | ||
110 | #define CLIX_BUTTON_RIGHT BUTTON_RIGHT | ||
111 | #define CLIX_BUTTON_CLICK BUTTON_SELECT | ||
112 | #define CLIX_BUTTON_UP BUTTON_UP | ||
113 | #define CLIX_BUTTON_DOWN BUTTON_DOWN | ||
114 | |||
115 | #elif CONFIG_KEYPAD == CREATIVEZVM_PAD | ||
116 | #define CLIX_BUTTON_QUIT BUTTON_BACK | ||
117 | #define CLIX_BUTTON_LEFT BUTTON_LEFT | ||
118 | #define CLIX_BUTTON_RIGHT BUTTON_RIGHT | ||
119 | #define CLIX_BUTTON_CLICK BUTTON_SELECT | ||
120 | #define CLIX_BUTTON_UP BUTTON_UP | ||
121 | #define CLIX_BUTTON_DOWN BUTTON_DOWN | ||
122 | |||
123 | #elif (CONFIG_KEYPAD == PHILIPS_HDD1630_PAD) | ||
124 | #define CLIX_BUTTON_QUIT BUTTON_POWER | ||
125 | #define CLIX_BUTTON_LEFT BUTTON_LEFT | ||
126 | #define CLIX_BUTTON_RIGHT BUTTON_RIGHT | ||
127 | #define CLIX_BUTTON_CLICK BUTTON_SELECT | ||
128 | #define CLIX_BUTTON_UP BUTTON_UP | ||
129 | #define CLIX_BUTTON_DOWN BUTTON_DOWN | ||
130 | |||
131 | #elif CONFIG_KEYPAD == COWOND2_PAD | ||
132 | #define CLIX_BUTTON_QUIT BUTTON_POWER | ||
133 | |||
134 | #elif (CONFIG_KEYPAD == ONDAVX747_PAD) || \ | ||
135 | (CONFIG_KEYPAD == MROBE500_PAD) | ||
136 | #define CLIX_BUTTON_QUIT BUTTON_POWER | ||
137 | |||
138 | #else | ||
139 | #error "no keymap" | ||
140 | #endif | ||
141 | |||
142 | #ifdef HAVE_TOUCHSCREEN | ||
143 | #ifndef CLIX_BUTTON_LEFT | ||
144 | #define CLIX_BUTTON_LEFT BUTTON_MIDLEFT | ||
145 | #endif | ||
146 | #ifndef CLIX_BUTTON_RIGHT | ||
147 | #define CLIX_BUTTON_RIGHT BUTTON_MIDRIGHT | ||
148 | #endif | ||
149 | #ifndef CLIX_BUTTON_CLICK | ||
150 | #define CLIX_BUTTON_CLICK BUTTON_CENTER | ||
151 | #endif | ||
152 | #ifndef CLIX_BUTTON_UP | ||
153 | #define CLIX_BUTTON_UP BUTTON_TOPMIDDLE | ||
154 | #endif | ||
155 | #ifndef CLIX_BUTTON_DOWN | ||
156 | #define CLIX_BUTTON_DOWN BUTTON_BOTTOMMIDDLE | ||
157 | #endif | ||
158 | #endif | ||
159 | |||
160 | #define HIGHSCORE_FILE PLUGIN_GAMES_DIR "/clix.score" | ||
161 | #define NUM_SCORES 5 | ||
162 | struct highscore highest[NUM_SCORES]; | ||
163 | |||
164 | #define NUM_LEVELS 9 | ||
165 | #define BLINK_TICKCOUNT 25 | ||
166 | #define MARGIN 5 | ||
167 | |||
168 | #if (LCD_WIDTH >= LCD_HEIGHT) | ||
169 | #define BOARD_WIDTH 18 | ||
170 | #define BOARD_HEIGHT 12 | ||
171 | #else | ||
172 | #define BOARD_WIDTH 12 | ||
173 | #define BOARD_HEIGHT 18 | ||
174 | #endif | ||
175 | |||
176 | #if (LCD_WIDTH >= 306 && LCD_HEIGHT>= 204) | ||
177 | #define CELL_SIZE 16 | ||
178 | |||
179 | #elif (LCD_WIDTH >= 270 && LCD_HEIGHT>= 180) | ||
180 | #define CELL_SIZE 14 | ||
181 | |||
182 | #elif (LCD_WIDTH >= 234 && LCD_HEIGHT>= 156) | ||
183 | #define CELL_SIZE 12 | ||
184 | |||
185 | #elif (LCD_WIDTH >= 198 && LCD_HEIGHT>= 132) | ||
186 | #define CELL_SIZE 10 | ||
187 | |||
188 | #elif (LCD_WIDTH >= 162 && LCD_HEIGHT>= 108) | ||
189 | #define CELL_SIZE 8 | ||
190 | |||
191 | #elif (LCD_WIDTH >= 126 && LCD_HEIGHT>= 84) | ||
192 | #define CELL_SIZE 6 | ||
193 | |||
194 | #elif (LCD_WIDTH >= 60) | ||
195 | #define CELL_SIZE 4 | ||
196 | #endif | ||
197 | |||
198 | #define XYPOS(x,y) ((y) * BOARD_WIDTH + x) | ||
199 | #define XOFS LCD_WIDTH/2-(BOARD_WIDTH * (CELL_SIZE + 1)/2) | ||
200 | #define YOFS (LCD_HEIGHT+10)/2-(BOARD_HEIGHT * (CELL_SIZE + 1)/2) | ||
201 | |||
202 | |||
203 | struct clix_game_state_t { | ||
204 | unsigned char level; /* current level */ | ||
205 | char x,y; /* current positions of the cursor */ | ||
206 | char board[BOARD_WIDTH * BOARD_HEIGHT]; /* play board*/ | ||
207 | /* state of selected fields,maybe we can store this in the play board too */ | ||
208 | bool board_selected[ BOARD_WIDTH * BOARD_HEIGHT]; | ||
209 | char selected_count; | ||
210 | unsigned short score; /* current game score */ | ||
211 | char status; | ||
212 | bool blink; /* true if selected CELLS are currently white */ | ||
213 | }; | ||
214 | |||
215 | /* game state enum */ | ||
216 | enum { | ||
217 | CLIX_GAMEOVER = -1, | ||
218 | CLIX_CONTINUE, | ||
219 | CLIX_CLEARED | ||
220 | }; | ||
221 | |||
222 | /* cell color enum */ | ||
223 | enum { | ||
224 | CC_BLACK = -1, | ||
225 | CC_BLUE, | ||
226 | CC_GREEN, | ||
227 | CC_RED, | ||
228 | CC_YELLOW, | ||
229 | CC_ORANGE, | ||
230 | CC_CYAN, | ||
231 | CC_BROWN, | ||
232 | CC_PINK, | ||
233 | CC_DARK_BLUE, | ||
234 | CC_DARK_GREEN | ||
235 | }; | ||
236 | |||
237 | /* display the highscore list and highlight the last one */ | ||
238 | static void clix_show_highscores(int position) | ||
239 | { | ||
240 | int i, w, h; | ||
241 | char str[30]; | ||
242 | |||
243 | #ifdef HAVE_LCD_COLOR | ||
244 | rb->lcd_set_background(LCD_BLACK); | ||
245 | rb->lcd_set_foreground(LCD_WHITE); | ||
246 | #endif | ||
247 | rb->button_clear_queue(); | ||
248 | rb->lcd_clear_display(); | ||
249 | |||
250 | rb->lcd_setfont(FONT_UI); | ||
251 | rb->lcd_getstringsize("High Scores", &w, &h); | ||
252 | /* check wether it fits on screen */ | ||
253 | if ((4*h + h*(NUM_SCORES-1) + MARGIN) > LCD_HEIGHT) { | ||
254 | rb->lcd_setfont(FONT_SYSFIXED); | ||
255 | rb->lcd_getstringsize("High Scores", &w, &h); | ||
256 | } | ||
257 | rb->lcd_putsxy(LCD_WIDTH/2-w/2, MARGIN, "High Scores"); | ||
258 | rb->lcd_putsxy(LCD_WIDTH/4-w/4,2*h, "Score"); | ||
259 | rb->lcd_putsxy(LCD_WIDTH*3/4-w/4,2*h, "Level"); | ||
260 | |||
261 | for (i = 0; i<NUM_SCORES; i++) | ||
262 | { | ||
263 | #ifdef HAVE_LCD_COLOR | ||
264 | if (i == position) { | ||
265 | rb->lcd_set_foreground(LCD_RGBPACK(245,0,0)); | ||
266 | } | ||
267 | #endif | ||
268 | rb->snprintf (str, sizeof (str), "%d)", i+1); | ||
269 | rb->lcd_putsxy (MARGIN,3*h + h*i, str); | ||
270 | rb->snprintf (str, sizeof (str), "%d", highest[i].score); | ||
271 | rb->lcd_putsxy (LCD_WIDTH/4-w/4,3*h + h*i, str); | ||
272 | rb->snprintf (str, sizeof (str), "%d", highest[i].level); | ||
273 | rb->lcd_putsxy (LCD_WIDTH*3/4-w/4,3*h + h*i, str); | ||
274 | if(i == position) { | ||
275 | #ifdef HAVE_LCD_COLOR | ||
276 | rb->lcd_set_foreground(LCD_WHITE); | ||
277 | #else | ||
278 | rb->lcd_hline(MARGIN, LCD_WIDTH-MARGIN, 3*h + h*(i+1)); | ||
279 | #endif | ||
280 | } | ||
281 | } | ||
282 | rb->lcd_update(); | ||
283 | rb->button_get(true); | ||
284 | rb->lcd_setfont(FONT_SYSFIXED); | ||
285 | } | ||
286 | |||
287 | /* recursiv function to check if a neighbour cell is of the same color | ||
288 | if so call the function with the neighbours position | ||
289 | */ | ||
290 | static void clix_set_selected(struct clix_game_state_t* state, | ||
291 | const int x, const int y) | ||
292 | { | ||
293 | state->selected_count++; | ||
294 | state->board_selected[ XYPOS( x, y)] = true; | ||
295 | int current_color = state->board[ XYPOS( x, y)]; | ||
296 | |||
297 | if( (x - 1) >= 0 && | ||
298 | state->board[ XYPOS( x - 1, y)] == current_color && | ||
299 | state->board_selected[ XYPOS(x - 1, y)] == false) | ||
300 | clix_set_selected( state, x - 1, y); | ||
301 | |||
302 | if( (y + 1) < BOARD_HEIGHT && | ||
303 | state->board[ XYPOS( x, y + 1)] == current_color && | ||
304 | state->board_selected[ XYPOS(x, y + 1)] == false) | ||
305 | clix_set_selected( state, x, y + 1); | ||
306 | |||
307 | if( (x + 1) < BOARD_WIDTH && | ||
308 | state->board[ XYPOS( x + 1, y)] == current_color && | ||
309 | state->board_selected[ XYPOS(x + 1, y)] == false) | ||
310 | clix_set_selected( state, x + 1, y); | ||
311 | |||
312 | if( (y - 1) >= 0 && | ||
313 | state->board[ XYPOS( x, y - 1)] == current_color && | ||
314 | state->board_selected[ XYPOS(x, y - 1)] == false) | ||
315 | clix_set_selected( state, x, y - 1); | ||
316 | } | ||
317 | |||
318 | /* updates "blinking" cells by finding out which one is a valid neighbours */ | ||
319 | static void clix_update_selected(struct clix_game_state_t* state) | ||
320 | { | ||
321 | int i; | ||
322 | |||
323 | for( i = 0; i < BOARD_WIDTH * BOARD_HEIGHT; ++i) | ||
324 | { | ||
325 | state->board_selected[i] = false; | ||
326 | } | ||
327 | state->selected_count = 0; | ||
328 | |||
329 | /* recursion starts here */ | ||
330 | clix_set_selected( state, state->x, state->y); | ||
331 | } | ||
332 | |||
333 | /* inits the board with new random colors according to the level */ | ||
334 | static void clix_init_new_level(struct clix_game_state_t* state) | ||
335 | { | ||
336 | int i; | ||
337 | int r; | ||
338 | |||
339 | state->y = BOARD_HEIGHT / 2; | ||
340 | state->x = BOARD_WIDTH / 2; | ||
341 | |||
342 | rb->srand( *rb->current_tick); | ||
343 | /* create a random colored board, according to the current level */ | ||
344 | for(i = 0; i < BOARD_HEIGHT * BOARD_WIDTH; ++i) | ||
345 | { | ||
346 | r = rb->rand() % (state->level + 1); | ||
347 | state->board[i] = r; | ||
348 | } | ||
349 | } | ||
350 | |||
351 | /* this inits the game state structure */ | ||
352 | static void clix_init(struct clix_game_state_t* state) | ||
353 | { | ||
354 | state->level = 1; | ||
355 | state->score = 0; | ||
356 | state->blink = false; | ||
357 | state->status = CLIX_CONTINUE; | ||
358 | |||
359 | clix_init_new_level(state); | ||
360 | |||
361 | clix_update_selected(state); | ||
362 | } | ||
363 | |||
364 | /* Function for drawing a cell */ | ||
365 | static void clix_draw_cell(struct clix_game_state_t* state, const int x, const int y) | ||
366 | { | ||
367 | int realx = XOFS; | ||
368 | int realy = YOFS; | ||
369 | |||
370 | realx += x * (CELL_SIZE + 1); | ||
371 | realy += y * (CELL_SIZE + 1); | ||
372 | |||
373 | if (state->blink && state->board_selected[ XYPOS( x, y)]) { | ||
374 | rb->lcd_set_foreground(LCD_WHITE); | ||
375 | } else { | ||
376 | switch (state->board[ XYPOS( x, y)]) | ||
377 | { | ||
378 | case CC_BLUE: | ||
379 | rb->lcd_set_foreground( LCD_RGBPACK( 25, 25, 255)); | ||
380 | break; | ||
381 | case CC_GREEN: | ||
382 | rb->lcd_set_foreground( LCD_RGBPACK( 25, 255, 25)); | ||
383 | break; | ||
384 | case CC_RED: | ||
385 | rb->lcd_set_foreground( LCD_RGBPACK( 255, 25, 25)); | ||
386 | break; | ||
387 | case CC_YELLOW: | ||
388 | rb->lcd_set_foreground( LCD_RGBPACK( 225, 225, 25)); | ||
389 | break; | ||
390 | case CC_ORANGE: | ||
391 | rb->lcd_set_foreground( LCD_RGBPACK( 230, 140, 15)); | ||
392 | break; | ||
393 | case CC_CYAN: | ||
394 | rb->lcd_set_foreground( LCD_RGBPACK( 25, 245, 230)); | ||
395 | break; | ||
396 | case CC_BROWN: | ||
397 | rb->lcd_set_foreground( LCD_RGBPACK(139, 69, 19)); | ||
398 | break; | ||
399 | case CC_PINK: | ||
400 | rb->lcd_set_foreground( LCD_RGBPACK(255, 105, 180)); | ||
401 | break; | ||
402 | case CC_DARK_GREEN: | ||
403 | rb->lcd_set_foreground( LCD_RGBPACK( 0, 100, 0)); | ||
404 | break; | ||
405 | case CC_DARK_BLUE: | ||
406 | rb->lcd_set_foreground( LCD_RGBPACK( 280, 32, 144)); | ||
407 | break; | ||
408 | default: | ||
409 | rb->lcd_set_foreground( LCD_BLACK); | ||
410 | break; | ||
411 | } | ||
412 | } | ||
413 | |||
414 | rb->lcd_fillrect( realx, realy, CELL_SIZE, CELL_SIZE); | ||
415 | |||
416 | /* draw cursor */ | ||
417 | if ( x == state->x && y == state->y) { | ||
418 | rb->lcd_set_foreground( LCD_WHITE); | ||
419 | rb->lcd_drawrect( realx - 1, realy - 1, CELL_SIZE + 2, CELL_SIZE + 2); | ||
420 | } | ||
421 | } | ||
422 | |||
423 | /* main function of drawing the whole board and score... */ | ||
424 | static void clix_draw(struct clix_game_state_t* state) | ||
425 | { | ||
426 | int i,j; | ||
427 | char str[30]; | ||
428 | |||
429 | /* Clear screen */ | ||
430 | rb->lcd_clear_display(); | ||
431 | rb->lcd_set_foreground( LCD_WHITE); | ||
432 | |||
433 | rb->lcd_putsxy( MARGIN, MARGIN, "Score:"); | ||
434 | rb->snprintf( str, sizeof(str), "%d", state->score); | ||
435 | rb->lcd_putsxy( 43, MARGIN, str); | ||
436 | #if LCD_WIDTH <= 100 | ||
437 | rb->lcd_putsxy( 75, MARGIN, "L:"); | ||
438 | rb->snprintf( str, sizeof(str), "%d", state->level); | ||
439 | rb->lcd_putsxy( 90, MARGIN, str); | ||
440 | #else | ||
441 | rb->lcd_putsxy( 75, MARGIN, "Level:"); | ||
442 | rb->snprintf( str, sizeof(str), "%d", state->level); | ||
443 | rb->lcd_putsxy( 113, MARGIN, str); | ||
444 | #endif | ||
445 | for( i = 0; i < BOARD_WIDTH; ++i) | ||
446 | { | ||
447 | for( j = 0; j < BOARD_HEIGHT; ++j) | ||
448 | { | ||
449 | clix_draw_cell( state, i, j); | ||
450 | } | ||
451 | } | ||
452 | |||
453 | rb->lcd_update(); | ||
454 | } | ||
455 | |||
456 | static void clix_move_cursor(struct clix_game_state_t* state, const bool left) | ||
457 | { | ||
458 | signed char x, y; | ||
459 | |||
460 | x = state->x; | ||
461 | do | ||
462 | { | ||
463 | y = state->y; | ||
464 | while(state->board[ XYPOS( x, y)] == CC_BLACK && y < BOARD_HEIGHT) y++; | ||
465 | if (y < BOARD_HEIGHT) { | ||
466 | state->y = y; | ||
467 | state->x = x; | ||
468 | } | ||
469 | else | ||
470 | { | ||
471 | if (left) { | ||
472 | if( x >= 0) | ||
473 | x--; | ||
474 | else | ||
475 | y = state->y; | ||
476 | } | ||
477 | else | ||
478 | { | ||
479 | if( x < BOARD_WIDTH - 1) | ||
480 | x++; | ||
481 | else | ||
482 | x = 0; | ||
483 | } | ||
484 | } | ||
485 | } while ( y != state->y); | ||
486 | |||
487 | } | ||
488 | |||
489 | /* returns the color of the given position, if out of bounds return CC_BLACK */ | ||
490 | static int clix_get_color(struct clix_game_state_t* state, const int x, const int y) | ||
491 | { | ||
492 | if( x >= 0 && x < BOARD_WIDTH && y >= 0 && y < BOARD_HEIGHT) | ||
493 | return state->board[XYPOS( x, y)]; | ||
494 | else | ||
495 | return CC_BLACK; | ||
496 | } | ||
497 | |||
498 | static int clix_clear_selected(struct clix_game_state_t* state) | ||
499 | { | ||
500 | int i, j, x, y; | ||
501 | |||
502 | state->status = CLIX_CLEARED; | ||
503 | |||
504 | /* clear the selected blocks */ | ||
505 | for( i = 0; i < BOARD_WIDTH; ++i) | ||
506 | { | ||
507 | for( j = 0; j < BOARD_HEIGHT; ++j) | ||
508 | { | ||
509 | if( state->board_selected[ XYPOS( i, j)] ) | ||
510 | { | ||
511 | state->board_selected[ XYPOS( i, j)] = false; | ||
512 | state->board[ XYPOS( i, j)] = CC_BLACK; | ||
513 | } | ||
514 | } | ||
515 | } | ||
516 | |||
517 | /* let blocks falling down */ | ||
518 | for( i = BOARD_WIDTH - 1; i >= 0; --i) | ||
519 | { | ||
520 | for( j = BOARD_HEIGHT - 1; j >= 0; --j) | ||
521 | { | ||
522 | y = j; | ||
523 | while( state->board[ XYPOS( i, y + 1)] == CC_BLACK && | ||
524 | y < BOARD_HEIGHT | ||
525 | ) | ||
526 | y++; | ||
527 | |||
528 | if (y != j) { | ||
529 | state->board[ XYPOS(i, y)] = state->board[ XYPOS( i, j)]; | ||
530 | state->board[ XYPOS( i, j)] = CC_BLACK; | ||
531 | } | ||
532 | } | ||
533 | } | ||
534 | |||
535 | /* count score */ | ||
536 | state->score += state->selected_count * state->level; | ||
537 | |||
538 | /* check every column (from right to left) if its empty, | ||
539 | if so copy the contents from the right side */ | ||
540 | for( i = BOARD_WIDTH - 1; i >= 0; --i) | ||
541 | { | ||
542 | if (state->board[ XYPOS( i, BOARD_HEIGHT - 1)] == CC_BLACK) { | ||
543 | if( (i + 1) < BOARD_WIDTH && | ||
544 | state->board[ XYPOS( i + 1, BOARD_HEIGHT - 1)] != CC_BLACK) | ||
545 | { | ||
546 | for( x = (i + 1); x < BOARD_WIDTH; ++x) | ||
547 | { | ||
548 | for( j = 0; j < BOARD_HEIGHT; ++j) | ||
549 | { | ||
550 | state->board[ XYPOS( x - 1, j)] = | ||
551 | state->board[ XYPOS( x, j)]; | ||
552 | |||
553 | state->board[ XYPOS( x, j)] = CC_BLACK; | ||
554 | } | ||
555 | } | ||
556 | } | ||
557 | } | ||
558 | else | ||
559 | state->status = CLIX_CONTINUE; | ||
560 | } | ||
561 | |||
562 | if (state->status != CLIX_CLEARED) { | ||
563 | /* check if a move is still possible, otherwise the game is over. | ||
564 | tart from the left bottom, because there are the last fields | ||
565 | at the end of the game. | ||
566 | */ | ||
567 | for( i = 0; i < BOARD_WIDTH; ++i) | ||
568 | { | ||
569 | for( j = BOARD_HEIGHT - 1; j >= 0; --j) | ||
570 | { | ||
571 | if (state->board[ XYPOS( i, j)] != CC_BLACK) { | ||
572 | if ( state->board[ XYPOS( i, j)] == | ||
573 | clix_get_color( state, i - 1, j) || | ||
574 | state->board[ XYPOS( i, j)] == | ||
575 | clix_get_color( state, i + 1, j) || | ||
576 | state->board[ XYPOS( i, j)] == | ||
577 | clix_get_color( state, i, j - 1) || | ||
578 | state->board[ XYPOS( i, j)] == | ||
579 | clix_get_color( state, i, j + 1) | ||
580 | ) | ||
581 | { | ||
582 | /* and the loop, but in a diffrent way than usually*/ | ||
583 | i = BOARD_WIDTH + 1; | ||
584 | j = -2; | ||
585 | } | ||
586 | } | ||
587 | } | ||
588 | } | ||
589 | /* if the loops ended without a possible move, the game is over */ | ||
590 | if( i == BOARD_WIDTH && j == -1) | ||
591 | state->status = CLIX_GAMEOVER; | ||
592 | |||
593 | /* set cursor to the right position */ | ||
594 | if (state->status == CLIX_CONTINUE) { | ||
595 | clix_move_cursor( state, true); | ||
596 | clix_update_selected( state); | ||
597 | } | ||
598 | } | ||
599 | |||
600 | return state->status; | ||
601 | } | ||
602 | |||
603 | static int clix_help(void) | ||
604 | { | ||
605 | rb->lcd_setfont(FONT_UI); | ||
606 | rb->lcd_set_foreground(LCD_WHITE); | ||
607 | #define WORDS (sizeof help_text / sizeof (char*)) | ||
608 | char *help_text[] = { | ||
609 | "Clix", "", "Aim", "", "Remove", "all", "blocks", "from", "the", | ||
610 | "board", "to", "achieve", "the", "next", "level.", "You", "can", | ||
611 | "only", "remove", "blocks,", "if", "at", "least", "two", "blocks", | ||
612 | "with", "the", "same", "color", "have", "a", "direct", "connection.", | ||
613 | "The", "more", "blocks", "you", "remove", "per", "turn,", "the", | ||
614 | "more", "points", "you", "get." | ||
615 | }; | ||
616 | static struct style_text formation[]={ | ||
617 | { 0, TEXT_CENTER|TEXT_UNDERLINE }, | ||
618 | { 2, C_RED } | ||
619 | }; | ||
620 | |||
621 | if (display_text(WORDS, help_text, formation, NULL)==PLUGIN_USB_CONNECTED) | ||
622 | return PLUGIN_USB_CONNECTED; | ||
623 | int button; | ||
624 | do { | ||
625 | button = rb->button_get(true); | ||
626 | if (button == SYS_USB_CONNECTED) { | ||
627 | return PLUGIN_USB_CONNECTED; | ||
628 | } | ||
629 | } while( ( button == BUTTON_NONE ) | ||
630 | || ( button & (BUTTON_REL|BUTTON_REPEAT) ) ); | ||
631 | rb->lcd_setfont(FONT_SYSFIXED); | ||
632 | return 0; | ||
633 | } | ||
634 | |||
635 | static bool _ingame; | ||
636 | static int clix_menu_cb(int action, const struct menu_item_ex *this_item) | ||
637 | { | ||
638 | if(action == ACTION_REQUEST_MENUITEM | ||
639 | && !_ingame && ((intptr_t)this_item)==0) | ||
640 | return ACTION_EXIT_MENUITEM; | ||
641 | return action; | ||
642 | } | ||
643 | |||
644 | static int clix_menu(struct clix_game_state_t* state, bool ingame) | ||
645 | { | ||
646 | rb->button_clear_queue(); | ||
647 | int choice = 0; | ||
648 | |||
649 | _ingame = ingame; | ||
650 | |||
651 | MENUITEM_STRINGLIST (main_menu, "Clix Menu", clix_menu_cb, | ||
652 | "Resume Game", | ||
653 | "Start New Game", | ||
654 | "Help", | ||
655 | "High Score", | ||
656 | "Playback Control", | ||
657 | "Quit"); | ||
658 | |||
659 | while (true) { | ||
660 | choice = rb->do_menu(&main_menu, &choice, NULL, false); | ||
661 | switch (choice) { | ||
662 | case 0: | ||
663 | return 0; | ||
664 | case 1: | ||
665 | clix_init(state); | ||
666 | return 0; | ||
667 | case 2: | ||
668 | if (clix_help()==PLUGIN_USB_CONNECTED) | ||
669 | return 1; | ||
670 | break; | ||
671 | case 3: | ||
672 | clix_show_highscores(NUM_SCORES); | ||
673 | break; | ||
674 | case 4: | ||
675 | playback_control(NULL); | ||
676 | break; | ||
677 | case 5: | ||
678 | case MENU_ATTACHED_USB: | ||
679 | return 1; | ||
680 | default: | ||
681 | break; | ||
682 | } | ||
683 | } | ||
684 | } | ||
685 | |||
686 | static int clix_handle_game(struct clix_game_state_t* state) | ||
687 | { | ||
688 | if (clix_menu(state, 0)) | ||
689 | return 1; | ||
690 | |||
691 | int button; | ||
692 | int blink_tick = *rb->current_tick + BLINK_TICKCOUNT; | ||
693 | int position; | ||
694 | |||
695 | int time; | ||
696 | int start; | ||
697 | int end; | ||
698 | int oldx, oldy; | ||
699 | |||
700 | while(true) | ||
701 | { | ||
702 | if (blink_tick < *rb->current_tick) { | ||
703 | state->blink = state->blink ? false : true; | ||
704 | blink_tick = *rb->current_tick + BLINK_TICKCOUNT; | ||
705 | } | ||
706 | |||
707 | time = 6; /* number of ticks this function will loop reading keys */ | ||
708 | start = *rb->current_tick; | ||
709 | end = start + time; | ||
710 | while(end > *rb->current_tick) | ||
711 | { | ||
712 | oldx = state->x; | ||
713 | oldy = state->y; | ||
714 | |||
715 | rb->button_get_w_tmo(end - *rb->current_tick); | ||
716 | button = rb->button_status(); | ||
717 | rb->button_clear_queue(); | ||
718 | switch( button) | ||
719 | { | ||
720 | #ifdef CLIX_BUTTON_SCROLL_BACK | ||
721 | case CLIX_BUTTON_SCROLL_BACK: | ||
722 | #endif | ||
723 | case CLIX_BUTTON_UP: | ||
724 | if( state->y == 0 || | ||
725 | state->board[ XYPOS( state->x, state->y - 1)] == | ||
726 | CC_BLACK | ||
727 | ) | ||
728 | state->y = BOARD_HEIGHT - 1; | ||
729 | else | ||
730 | state->y--; | ||
731 | |||
732 | clix_move_cursor(state, true); | ||
733 | break; | ||
734 | case CLIX_BUTTON_RIGHT: | ||
735 | if( state->x == (BOARD_WIDTH - 1)) | ||
736 | state->x = 0; | ||
737 | else | ||
738 | state->x++; | ||
739 | |||
740 | clix_move_cursor(state, false); | ||
741 | break; | ||
742 | #ifdef CLIX_BUTTON_SCROLL_FWD | ||
743 | case CLIX_BUTTON_SCROLL_FWD: | ||
744 | #endif | ||
745 | case CLIX_BUTTON_DOWN: | ||
746 | if( state->y == (BOARD_HEIGHT - 1)) | ||
747 | state->y = 0; | ||
748 | else | ||
749 | state->y++; | ||
750 | |||
751 | clix_move_cursor( state, true); | ||
752 | break; | ||
753 | case CLIX_BUTTON_LEFT: | ||
754 | if( state->x == 0) | ||
755 | state->x = BOARD_WIDTH - 1; | ||
756 | else | ||
757 | state->x--; | ||
758 | |||
759 | clix_move_cursor(state, true); | ||
760 | |||
761 | break; | ||
762 | case CLIX_BUTTON_CLICK: | ||
763 | { | ||
764 | if (state->selected_count > 1) { | ||
765 | switch( clix_clear_selected( state)) | ||
766 | { | ||
767 | case CLIX_CLEARED: | ||
768 | clix_draw( state); | ||
769 | if (state->level < NUM_LEVELS) { | ||
770 | rb->splash(HZ*2, "Great! Next Level!"); | ||
771 | state->score += state->level * 100; | ||
772 | state->level++; | ||
773 | clix_init_new_level( state); | ||
774 | clix_update_selected( state); | ||
775 | } | ||
776 | else { | ||
777 | rb->splash(HZ*2, "Congratulation!!!"); | ||
778 | rb->lcd_clear_display(); | ||
779 | rb->splash(HZ*2, "You have finished the game."); | ||
780 | if (clix_menu(state, 0)) | ||
781 | return 1; | ||
782 | } | ||
783 | break; | ||
784 | case CLIX_GAMEOVER: | ||
785 | clix_draw( state); | ||
786 | rb->splash(HZ*2, "Game Over!"); | ||
787 | rb->lcd_clear_display(); | ||
788 | if (highscore_would_update(state->score, | ||
789 | highest, NUM_SCORES)) { | ||
790 | position=highscore_update(state->score, | ||
791 | state->level, "", | ||
792 | highest,NUM_SCORES); | ||
793 | if (position == 0) { | ||
794 | rb->splash(HZ*2, "New High Score"); | ||
795 | } | ||
796 | clix_show_highscores(position); | ||
797 | } | ||
798 | if (clix_menu(state, 0)) | ||
799 | return 1; | ||
800 | break; | ||
801 | default: | ||
802 | rb->sleep(10); /* prevent repeating clicks */ | ||
803 | break; | ||
804 | } | ||
805 | } | ||
806 | } | ||
807 | break; | ||
808 | case CLIX_BUTTON_QUIT: | ||
809 | if (clix_menu(state, 1) != 0) { | ||
810 | rb->button_clear_queue(); | ||
811 | return 1; | ||
812 | } | ||
813 | break; | ||
814 | default: | ||
815 | |||
816 | break; | ||
817 | } | ||
818 | |||
819 | if( (oldx != state->x || oldy != state->y) && | ||
820 | state->board_selected[ XYPOS( oldx, oldy)] != | ||
821 | state->board_selected[ XYPOS( state->x, state->y)] | ||
822 | ) | ||
823 | { | ||
824 | clix_update_selected(state); | ||
825 | } | ||
826 | clix_draw(state); | ||
827 | rb->sleep(time); | ||
828 | } | ||
829 | } | ||
830 | } | ||
831 | |||
832 | /* this is the plugin entry point */ | ||
833 | enum plugin_status plugin_start(const void* parameter) | ||
834 | { | ||
835 | (void)parameter; | ||
836 | |||
837 | #ifdef HAVE_LCD_COLOR | ||
838 | rb->lcd_set_backdrop(NULL); | ||
839 | rb->lcd_set_foreground(LCD_WHITE); | ||
840 | rb->lcd_set_background(LCD_BLACK); | ||
841 | rb->lcd_setfont(FONT_SYSFIXED); | ||
842 | |||
843 | highscore_load(HIGHSCORE_FILE, highest, NUM_SCORES); | ||
844 | |||
845 | struct clix_game_state_t state; | ||
846 | clix_handle_game( &state); | ||
847 | |||
848 | highscore_save(HIGHSCORE_FILE, highest, NUM_SCORES); | ||
849 | |||
850 | rb->lcd_set_foreground(LCD_WHITE); | ||
851 | rb->lcd_setfont(FONT_UI); | ||
852 | #endif | ||
853 | |||
854 | return PLUGIN_OK; | ||
855 | } | ||
diff --git a/manual/plugins/clix.tex b/manual/plugins/clix.tex new file mode 100644 index 0000000000..33b535a9b7 --- /dev/null +++ b/manual/plugins/clix.tex | |||
@@ -0,0 +1,29 @@ | |||
1 | \subsection{Clix} | ||
2 | \screenshot{plugins/images/ss-clix}{Clix}{img:clix} | ||
3 | |||
4 | The aim is to remove all blocks from the board. You can only | ||
5 | remove blocks, if at least two blocks with the same color have a direct connection. | ||
6 | The more blocks you remove per turn, the more points you get. | ||
7 | |||
8 | \begin{table} | ||
9 | \begin{btnmap}{}{} | ||
10 | \ButtonLeft/\ButtonRight/\\ | ||
11 | \opt{RECORDER_PAD,ONDIO_PAD,IRIVER_H100_PAD,IRIVER_H300_PAD,SANSA_E200_PAD% | ||
12 | ,SANSA_C200_PAD,GIGABEAT_PAD,MROBE100_PAD,IAUDIO_X5_PAD,GIGABEAT_S_PAD} | ||
13 | {\ButtonUp/\ButtonDown} | ||
14 | \opt{IPOD_4G_PAD,IPOD_3G_PAD}{\ButtonMenu/\ButtonPlay} | ||
15 | \opt{IRIVER_H10_PAD}{\ButtonScrollUp/\ButtonScrollDown} | ||
16 | & Move the cursor around the blocks \\ | ||
17 | \opt{RECORDER_PAD,IRIVER_H10_PAD}{\ButtonPlay} | ||
18 | \opt{ONDIO_PAD}{\ButtonMenu} | ||
19 | \opt{IRIVER_H100_PAD,IRIVER_H300_PAD,IPOD_4G_PAD,IPOD_3G_PAD,SANSA_E200_PAD% | ||
20 | ,SANSA_C200_PAD,GIGABEAT_PAD,MROBE100_PAD,IAUDIO_X5_PAD,GIGABEAT_S_PAD} | ||
21 | {\ButtonSelect} | ||
22 | & Remove a block \\ | ||
23 | \opt{RECORDER_PAD,ONDIO_PAD,IRIVER_H100_PAD,IRIVER_H300_PAD} | ||
24 | {\ButtonOff & Exit \\}% | ||
25 | \opt{IRIVER_H10_PAD,SANSA_E200_PAD,SANSA_C200_PAD,GIGABEAT_PAD,MROBE100_PAD% | ||
26 | ,IAUDIO_X5_PAD}{\ButtonPower & Exit \\}% | ||
27 | \opt{GIGABEAT_S_PAD}{\ButtonBack & Exit \\}% | ||
28 | \end{btnmap} | ||
29 | \end{table} | ||
diff --git a/manual/plugins/main.tex b/manual/plugins/main.tex index 70f5cbd527..f500d8084e 100644 --- a/manual/plugins/main.tex +++ b/manual/plugins/main.tex | |||
@@ -27,6 +27,8 @@ text files% | |||
27 | 27 | ||
28 | \opt{lcd_bitmap}{\input{plugins/chessbox.tex}} | 28 | \opt{lcd_bitmap}{\input{plugins/chessbox.tex}} |
29 | 29 | ||
30 | \opt{lcd_bitmap}{\input{plugins/clix.tex}} | ||
31 | |||
30 | \opt{lcd_bitmap}{\input{plugins/chopper.tex}} | 32 | \opt{lcd_bitmap}{\input{plugins/chopper.tex}} |
31 | 33 | ||
32 | {\input{plugins/dice.tex}} | 34 | {\input{plugins/dice.tex}} |