Introduce __attribute__((unused)) (#defined to UNUSED_ATTR) to mark possibly unused...
[kugel-rb.git] / apps / plugins / blackjack.c
blob6a2a6a879c6673d8f2dc0253a787cf9e42aa5090
1 /***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
10 * Copyright (C) 2006 Tom Ross
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation; either version 2
15 * of the License, or (at your option) any later version.
17 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
18 * KIND, either express or implied.
20 ****************************************************************************/
22 #include "plugin.h"
23 #include "pluginbitmaps/card_deck.h"
24 #include "pluginbitmaps/card_back.h"
25 #include "lib/display_text.h"
26 #include "lib/highscore.h"
27 #include "lib/playback_control.h"
29 PLUGIN_HEADER
31 /* save files */
32 #define HIGH_SCORE PLUGIN_GAMES_DIR "/blackjack.score"
33 #define SAVE_FILE PLUGIN_GAMES_DIR "/blackjack.save"
34 #define NUM_SCORES 5
35 struct highscore highest[NUM_SCORES];
37 /* final game return status */
38 #define BJ_END 3
39 #define BJ_USB 2
40 #define BJ_QUIT 1
41 #define BJ_LOSE 0
43 #if CONFIG_KEYPAD == RECORDER_PAD
44 #define BJACK_SELECT_NAME "PLAY"
45 #define BJACK_STAY_NAME "F1"
46 #define BJACK_RESUME_NAME "F3"
47 #define BJACK_QUIT_NAME "OFF"
48 #define BJACK_DOUBLE_NAME "F2"
49 #define BJACK_SELECT BUTTON_PLAY
50 #define BJACK_QUIT BUTTON_OFF
51 #define BJACK_MAX (BUTTON_ON|BUTTON_UP)
52 #define BJACK_MIN (BUTTON_ON|BUTTON_DOWN)
53 #define BJACK_STAY BUTTON_F1
54 #define BJACK_DOUBLEDOWN BUTTON_F2
55 #define BJACK_RESUME BUTTON_F3
56 #define BJACK_UP BUTTON_UP
57 #define BJACK_DOWN BUTTON_DOWN
58 #define BJACK_RIGHT BUTTON_RIGHT
59 #define BJACK_LEFT BUTTON_LEFT
61 #elif CONFIG_KEYPAD == ONDIO_PAD
62 #define BJACK_SELECT_NAME "MENU"
63 #define BJACK_STAY_NAME "RIGHT"
64 #define BJACK_RESUME_NAME "DOWN"
65 #define BJACK_QUIT_NAME "OFF"
66 #define BJACK_DOUBLE_NAME "UP"
67 #define BJACK_SELECT BUTTON_MENU
68 #define BJACK_QUIT BUTTON_OFF
69 #define BJACK_MAX (BUTTON_MENU|BUTTON_UP)
70 #define BJACK_MIN (BUTTON_MENU|BUTTON_DOWN)
71 #define BJACK_STAY BUTTON_RIGHT
72 #define BJACK_DOUBLEDOWN BUTTON_UP
73 #define BJACK_RESUME BUTTON_DOWN
74 #define BJACK_UP BUTTON_UP
75 #define BJACK_DOWN BUTTON_DOWN
76 #define BJACK_RIGHT BUTTON_RIGHT
77 #define BJACK_LEFT BUTTON_LEFT
79 #elif CONFIG_KEYPAD == IRIVER_H10_PAD
80 #define BJACK_SELECT_NAME "PLAY"
81 #define BJACK_STAY_NAME ">>|"
82 #define BJACK_RESUME_NAME "RIGHT"
83 #define BJACK_QUIT_NAME "POWER"
84 #define BJACK_DOUBLE_NAME "|<<"
85 #define BJACK_SELECT BUTTON_PLAY
86 #define BJACK_QUIT BUTTON_POWER
87 #define BJACK_MAX (BUTTON_PLAY|BUTTON_SCROLL_UP)
88 #define BJACK_MIN (BUTTON_PLAY|BUTTON_SCROLL_DOWN)
89 #define BJACK_STAY BUTTON_FF
90 #define BJACK_DOUBLEDOWN BUTTON_REW
91 #define BJACK_RESUME BUTTON_RIGHT
92 #define BJACK_UP BUTTON_SCROLL_UP
93 #define BJACK_DOWN BUTTON_SCROLL_DOWN
94 #define BJACK_RIGHT BUTTON_RIGHT
95 #define BJACK_LEFT BUTTON_LEFT
97 #elif (CONFIG_KEYPAD == IRIVER_H100_PAD) || \
98 (CONFIG_KEYPAD == IRIVER_H300_PAD)
99 #define BJACK_SELECT_NAME "ON"
100 #define BJACK_STAY_NAME "REC"
101 #define BJACK_RESUME_NAME "MODE"
102 #define BJACK_QUIT_NAME "OFF"
103 #define BJACK_DOUBLE_NAME "SELECT"
104 #define BJACK_SELECT BUTTON_ON
105 #define BJACK_QUIT BUTTON_OFF
106 #define BJACK_MAX (BUTTON_ON|BUTTON_UP)
107 #define BJACK_MIN (BUTTON_ON|BUTTON_DOWN)
108 #define BJACK_STAY BUTTON_REC
109 #define BJACK_DOUBLEDOWN BUTTON_SELECT
110 #define BJACK_RESUME BUTTON_MODE
111 #define BJACK_UP BUTTON_UP
112 #define BJACK_DOWN BUTTON_DOWN
113 #define BJACK_RIGHT BUTTON_RIGHT
114 #define BJACK_LEFT BUTTON_LEFT
116 #elif (CONFIG_KEYPAD == IPOD_4G_PAD) || \
117 (CONFIG_KEYPAD == IPOD_3G_PAD) || \
118 (CONFIG_KEYPAD == IPOD_1G2G_PAD)
119 #define BJACK_SELECT_NAME "SELECT"
120 #define BJACK_STAY_NAME "RIGHT"
121 #define BJACK_RESUME_NAME "PLAY"
122 #define BJACK_QUIT_NAME "MENU"
123 #define BJACK_DOUBLE_NAME "LEFT"
124 #define BJACK_SELECT BUTTON_SELECT
125 #define BJACK_QUIT BUTTON_MENU
126 #define BJACK_MAX (BUTTON_SELECT|BUTTON_SCROLL_FWD)
127 #define BJACK_MIN (BUTTON_SELECT|BUTTON_SCROLL_BACK)
128 #define BJACK_STAY BUTTON_RIGHT
129 #define BJACK_DOUBLEDOWN BUTTON_LEFT
130 #define BJACK_RESUME BUTTON_PLAY
131 #define BJACK_UP BUTTON_SCROLL_FWD
132 #define BJACK_DOWN BUTTON_SCROLL_BACK
133 #define BJACK_RIGHT BUTTON_RIGHT
134 #define BJACK_LEFT BUTTON_LEFT
136 #elif CONFIG_KEYPAD == IAUDIO_X5M5_PAD
137 #define BJACK_SELECT_NAME "PLAY"
138 #define BJACK_STAY_NAME "REC"
139 #define BJACK_RESUME_NAME "DOWN"
140 #define BJACK_QUIT_NAME "POWER"
141 #define BJACK_DOUBLE_NAME "PLAY"
142 #define BJACK_SELECT BUTTON_SELECT
143 #define BJACK_QUIT BUTTON_POWER
144 #define BJACK_MAX (BUTTON_PLAY|BUTTON_UP)
145 #define BJACK_MIN (BUTTON_PLAY|BUTTON_DOWN)
146 #define BJACK_STAY BUTTON_REC
147 #define BJACK_DOUBLEDOWN BUTTON_PLAY
148 #define BJACK_RESUME BUTTON_DOWN
149 #define BJACK_UP BUTTON_UP
150 #define BJACK_DOWN BUTTON_DOWN
151 #define BJACK_RIGHT BUTTON_RIGHT
152 #define BJACK_LEFT BUTTON_LEFT
154 #elif CONFIG_KEYPAD == IRIVER_IFP7XX_PAD
155 #define BJACK_SELECT_NAME "MODE"
156 #define BJACK_STAY_NAME "MODE"
157 #define BJACK_RESUME_NAME "EQ+MODE"
158 #define BJACK_QUIT_NAME "PLAY"
159 #define BJACK_DOUBLE_NAME "SELECT"
160 #define BJACK_SELECT BUTTON_MODE
161 #define BJACK_QUIT BUTTON_PLAY
162 #define BJACK_MAX (BUTTON_EQ|BUTTON_UP)
163 #define BJACK_MIN (BUTTON_EQ|BUTTON_DOWN)
164 #define BJACK_STAY BUTTON_MODE
165 #define BJACK_DOUBLEDOWN BUTTON_SELECT
166 #define BJACK_RESUME (BUTTON_EQ|BUTTON_MODE)
167 #define BJACK_UP BUTTON_UP
168 #define BJACK_DOWN BUTTON_DOWN
169 #define BJACK_RIGHT BUTTON_RIGHT
170 #define BJACK_LEFT BUTTON_LEFT
172 #elif CONFIG_KEYPAD == GIGABEAT_PAD
173 #define BJACK_SELECT_NAME "A"
174 #define BJACK_STAY_NAME "VOL-"
175 #define BJACK_RESUME_NAME "MENU"
176 #define BJACK_QUIT_NAME "POWER"
177 #define BJACK_DOUBLE_NAME "SELECT"
178 #define BJACK_SELECT BUTTON_A
179 #define BJACK_QUIT BUTTON_POWER
180 #define BJACK_MAX BUTTON_VOL_UP
181 #define BJACK_MIN BUTTON_VOL_DOWN
182 #define BJACK_STAY BUTTON_VOL_DOWN
183 #define BJACK_DOUBLEDOWN BUTTON_SELECT
184 #define BJACK_RESUME BUTTON_MENU
185 #define BJACK_UP BUTTON_UP
186 #define BJACK_DOWN BUTTON_DOWN
187 #define BJACK_RIGHT BUTTON_RIGHT
188 #define BJACK_LEFT BUTTON_LEFT
190 #elif CONFIG_KEYPAD == SANSA_E200_PAD
191 #define BJACK_SELECT_NAME "SELECT"
192 #define BJACK_STAY_NAME "RIGHT"
193 #define BJACK_RESUME_NAME "DOWN"
194 #define BJACK_QUIT_NAME "POWER"
195 #define BJACK_DOUBLE_NAME "LEFT"
196 #define BJACK_SELECT BUTTON_SELECT
197 #define BJACK_QUIT BUTTON_POWER
198 #define BJACK_MAX (BUTTON_REC|BUTTON_UP)
199 #define BJACK_MIN (BUTTON_REC|BUTTON_DOWN)
200 #define BJACK_STAY BUTTON_RIGHT
201 #define BJACK_DOUBLEDOWN BUTTON_LEFT
202 #define BJACK_RESUME BUTTON_DOWN
203 #define BJACK_UP BUTTON_SCROLL_FWD
204 #define BJACK_DOWN BUTTON_SCROLL_BACK
205 #define BJACK_RIGHT BUTTON_RIGHT
206 #define BJACK_LEFT BUTTON_LEFT
208 #elif CONFIG_KEYPAD == SANSA_FUZE_PAD
209 #define BJACK_SELECT_NAME "SELECT"
210 #define BJACK_STAY_NAME "RIGHT"
211 #define BJACK_RESUME_NAME "UP"
212 #define BJACK_QUIT_NAME "HOME"
213 #define BJACK_DOUBLE_NAME "LEFT"
214 #define BJACK_SELECT BUTTON_SELECT
215 #define BJACK_QUIT (BUTTON_HOME|BUTTON_REPEAT)
216 #define BJACK_MAX (BUTTON_SELECT|BUTTON_UP)
217 #define BJACK_MIN (BUTTON_SELECT|BUTTON_DOWN)
218 #define BJACK_STAY BUTTON_RIGHT
219 #define BJACK_DOUBLEDOWN BUTTON_LEFT
220 #define BJACK_RESUME BUTTON_UP
221 #define BJACK_UP BUTTON_SCROLL_FWD
222 #define BJACK_DOWN BUTTON_SCROLL_BACK
223 #define BJACK_RIGHT BUTTON_RIGHT
224 #define BJACK_LEFT BUTTON_LEFT
226 #elif CONFIG_KEYPAD == SANSA_C200_PAD
227 #define BJACK_SELECT_NAME "SELECT"
228 #define BJACK_STAY_NAME "RIGHT"
229 #define BJACK_RESUME_NAME "DOWN"
230 #define BJACK_QUIT_NAME "POWER"
231 #define BJACK_DOUBLE_NAME "LEFT"
232 #define BJACK_SELECT BUTTON_SELECT
233 #define BJACK_QUIT BUTTON_POWER
234 #define BJACK_MAX BUTTON_VOL_UP
235 #define BJACK_MIN BUTTON_VOL_DOWN
236 #define BJACK_STAY BUTTON_RIGHT
237 #define BJACK_DOUBLEDOWN BUTTON_LEFT
238 #define BJACK_RESUME BUTTON_DOWN
239 #define BJACK_UP BUTTON_UP
240 #define BJACK_DOWN BUTTON_DOWN
241 #define BJACK_RIGHT BUTTON_RIGHT
242 #define BJACK_LEFT BUTTON_LEFT
244 #elif CONFIG_KEYPAD == SANSA_CLIP_PAD
245 #define BJACK_SELECT_NAME "SELECT"
246 #define BJACK_STAY_NAME "RIGHT"
247 #define BJACK_RESUME_NAME "DOWN"
248 #define BJACK_QUIT_NAME "POWER"
249 #define BJACK_DOUBLE_NAME "LEFT"
250 #define BJACK_SELECT BUTTON_SELECT
251 #define BJACK_QUIT BUTTON_POWER
252 #define BJACK_MAX BUTTON_VOL_UP
253 #define BJACK_MIN BUTTON_VOL_DOWN
254 #define BJACK_STAY BUTTON_RIGHT
255 #define BJACK_DOUBLEDOWN BUTTON_LEFT
256 #define BJACK_RESUME BUTTON_DOWN
257 #define BJACK_UP BUTTON_UP
258 #define BJACK_DOWN BUTTON_DOWN
259 #define BJACK_RIGHT BUTTON_RIGHT
260 #define BJACK_LEFT BUTTON_LEFT
262 #elif CONFIG_KEYPAD == SANSA_M200_PAD
263 #define BJACK_SELECT_NAME "SELECT"
264 #define BJACK_STAY_NAME "RIGHT"
265 #define BJACK_RESUME_NAME "DOWN"
266 #define BJACK_QUIT_NAME "POWER"
267 #define BJACK_DOUBLE_NAME "LEFT"
268 #define BJACK_SELECT (BUTTON_SELECT | BUTTON_REL)
269 #define BJACK_QUIT BUTTON_POWER
270 #define BJACK_MAX BUTTON_VOL_UP
271 #define BJACK_MIN BUTTON_VOL_DOWN
272 #define BJACK_STAY BUTTON_RIGHT
273 #define BJACK_DOUBLEDOWN BUTTON_LEFT
274 #define BJACK_RESUME BUTTON_DOWN
275 #define BJACK_UP BUTTON_UP
276 #define BJACK_DOWN BUTTON_DOWN
277 #define BJACK_RIGHT BUTTON_RIGHT
278 #define BJACK_LEFT BUTTON_LEFT
280 #elif CONFIG_KEYPAD == ELIO_TPJ1022_PAD
281 #define BJACK_SELECT_NAME "MAIN"
282 #define BJACK_STAY_NAME "MENU"
283 #define BJACK_RESUME_NAME ">>|"
284 #define BJACK_QUIT_NAME "POWER"
285 #define BJACK_DOUBLE_NAME "DOWN"
286 #define BJACK_SELECT BUTTON_MAIN
287 #define BJACK_QUIT BUTTON_POWER
288 #define BJACK_MAX (BUTTON_REC|BUTTON_UP)
289 #define BJACK_MIN (BUTTON_REC|BUTTON_DOWN)
290 #define BJACK_STAY BUTTON_MENU
291 #define BJACK_DOUBLEDOWN BUTTON_DOWN
292 #define BJACK_RESUME BUTTON_FF
293 #define BJACK_UP BUTTON_UP
294 #define BJACK_DOWN BUTTON_DOWN
295 #define BJACK_RIGHT BUTTON_RIGHT
296 #define BJACK_LEFT BUTTON_LEFT
298 #elif CONFIG_KEYPAD == GIGABEAT_S_PAD
299 #define BJACK_SELECT_NAME "PLAY"
300 #define BJACK_STAY_NAME "VOL-"
301 #define BJACK_RESUME_NAME "MENU"
302 #define BJACK_QUIT_NAME "BACK"
303 #define BJACK_DOUBLE_NAME "SELECT"
304 #define BJACK_SELECT BUTTON_PLAY
305 #define BJACK_QUIT BUTTON_BACK
306 #define BJACK_MAX BUTTON_VOL_UP
307 #define BJACK_MIN BUTTON_VOL_DOWN
308 #define BJACK_STAY BUTTON_VOL_DOWN
309 #define BJACK_DOUBLEDOWN BUTTON_SELECT
310 #define BJACK_RESUME BUTTON_MENU
311 #define BJACK_UP BUTTON_UP
312 #define BJACK_DOWN BUTTON_DOWN
313 #define BJACK_RIGHT BUTTON_RIGHT
314 #define BJACK_LEFT BUTTON_LEFT
316 #elif CONFIG_KEYPAD == MROBE100_PAD
317 #define BJACK_SELECT_NAME "SELECT"
318 #define BJACK_STAY_NAME "DISPLAY"
319 #define BJACK_RESUME_NAME "PLAY"
320 #define BJACK_QUIT_NAME "POWER"
321 #define BJACK_DOUBLE_NAME "DOWN"
322 #define BJACK_SELECT BUTTON_SELECT
323 #define BJACK_QUIT BUTTON_POWER
324 #define BJACK_MAX BUTTON_MENU
325 #define BJACK_MIN BUTTON_DISPLAY
326 #define BJACK_STAY BUTTON_DISPLAY
327 #define BJACK_DOUBLEDOWN BUTTON_DOWN
328 #define BJACK_RESUME BUTTON_PLAY
329 #define BJACK_UP BUTTON_UP
330 #define BJACK_DOWN BUTTON_DOWN
331 #define BJACK_RIGHT BUTTON_RIGHT
332 #define BJACK_LEFT BUTTON_LEFT
334 #elif CONFIG_KEYPAD == IAUDIO_M3_PAD
335 #define BJACK_SELECT_NAME "RC","PLAY"
336 #define BJACK_STAY_NAME "RC", ">>|"
337 #define BJACK_RESUME_NAME "RC_MODE"
338 #define BJACK_QUIT_NAME "RC_REC"
339 #define BJACK_DOUBLE_NAME "RC_REW"
340 #define BJACK_SELECT BUTTON_RC_PLAY
341 #define BJACK_QUIT BUTTON_RC_REC
342 #define BJACK_MAX (BUTTON_RC_PLAY|BUTTON_RC_VOL_UP)
343 #define BJACK_MIN (BUTTON_RC_PLAY|BUTTON_RC_VOL_DOWN)
344 #define BJACK_STAY BUTTON_RC_FF
345 #define BJACK_DOUBLEDOWN BUTTON_RC_REW
346 #define BJACK_RESUME BUTTON_RC_MODE
347 #define BJACK_UP BUTTON_RC_VOL_UP
348 #define BJACK_DOWN BUTTON_RC_VOL_DOWN
349 #define BJACK_RIGHT BUTTON_RC_FF
350 #define BJACK_LEFT BUTTON_RC_REW
352 #elif CONFIG_KEYPAD == COWOND2_PAD
353 #define BJACK_QUIT_NAME "POWER"
354 #define BJACK_DOUBLE_NAME "-"
355 #define BJACK_QUIT BUTTON_POWER
356 #define BJACK_DOUBLEDOWN BUTTON_MINUS
358 #elif CONFIG_KEYPAD == CREATIVEZVM_PAD
359 #define BJACK_SELECT_NAME "SELECT"
360 #define BJACK_STAY_NAME "PLAY"
361 #define BJACK_RESUME_NAME "MENU"
362 #define BJACK_QUIT_NAME "POWER"
363 #define BJACK_DOUBLE_NAME "CUSTOM"
364 #define BJACK_SELECT BUTTON_SELECT
365 #define BJACK_QUIT BUTTON_POWER
366 #define BJACK_STAY BUTTON_PLAY
367 #define BJACK_MAX (BUTTON_CUSTOM|BUTTON_UP)
368 #define BJACK_MIN (BUTTON_CUSTOM|BUTTON_DOWN)
369 #define BJACK_DOUBLEDOWN BUTTON_CUSTOM
370 #define BJACK_RESUME BUTTON_MENU
371 #define BJACK_UP BUTTON_UP
372 #define BJACK_DOWN BUTTON_DOWN
373 #define BJACK_RIGHT BUTTON_RIGHT
374 #define BJACK_LEFT BUTTON_LEFT
376 #elif CONFIG_KEYPAD == PHILIPS_HDD1630_PAD
377 #define BJACK_SELECT_NAME "MENU"
378 #define BJACK_STAY_NAME "VOL-"
379 #define BJACK_RESUME_NAME "VIEW"
380 #define BJACK_QUIT_NAME "POWER"
381 #define BJACK_DOUBLE_NAME "SELECT"
382 #define BJACK_SELECT BUTTON_MENU
383 #define BJACK_QUIT BUTTON_POWER
384 #define BJACK_MAX BUTTON_VOL_UP
385 #define BJACK_MIN BUTTON_VOL_DOWN
386 #define BJACK_STAY BUTTON_VOL_DOWN
387 #define BJACK_DOUBLEDOWN BUTTON_SELECT
388 #define BJACK_RESUME BUTTON_VIEW
389 #define BJACK_UP BUTTON_UP
390 #define BJACK_DOWN BUTTON_DOWN
391 #define BJACK_RIGHT BUTTON_RIGHT
392 #define BJACK_LEFT BUTTON_LEFT
394 #elif CONFIG_KEYPAD == ONDAVX747_PAD
395 #define BJACK_QUIT_NAME "POWER"
396 #define BJACK_DOUBLE_NAME "Vol-"
397 #define BJACK_QUIT BUTTON_POWER
398 #define BJACK_DOUBLEDOWN BUTTON_VOL_DOWN
400 #elif CONFIG_KEYPAD == MROBE500_PAD
401 #define BJACK_QUIT_NAME "POWER"
402 #define BJACK_QUIT BUTTON_POWER
404 #elif CONFIG_KEYPAD == SAMSUNG_YH_PAD
405 #define BJACK_SELECT_NAME ""
406 #define BJACK_STAY_NAME "RECORD"
407 #define BJACK_RESUME_NAME "PREVIOUS"
408 #define BJACK_QUIT_NAME "PLAY+LEFT"
409 #define BJACK_DOUBLE_NAME "FFWD"
410 #define BJACK_SELECT BUTTON_PLAY
411 #define BJACK_QUIT (BUTTON_PLAY|BUTTON_LEFT)
412 #define BJACK_MAX (BUTTON_PLAY|BUTTON_UP)
413 #define BJACK_MIN (BUTTON_PLAY|BUTTON_DOWN)
414 #define BJACK_STAY BUTTON_REC
415 #define BJACK_DOUBLEDOWN BUTTON_FFWD
416 #define BJACK_RESUME BUTTON_REW
417 #define BJACK_UP BUTTON_UP
418 #define BJACK_DOWN BUTTON_DOWN
419 #define BJACK_RIGHT BUTTON_RIGHT
420 #define BJACK_LEFT BUTTON_LEFT
422 #else
423 #error No keymap defined!
424 #endif
426 #ifdef HAVE_TOUCHSCREEN
427 #ifndef BJACK_DOUBLEDOWN
428 #define BJACK_DOUBLEDOWN BUTTON_MIDLEFT
429 #define BJACK_DOUBLE_NAME "BUTTON_MIDLEFT"
430 #endif
431 #ifndef BJACK_SELECT
432 #define BJACK_SELECT BUTTON_CENTER
433 #define BJACK_SELECT_NAME "BUTTON_CENTER"
434 #endif
435 #ifndef BJACK_MAX
436 #define BJACK_MAX BUTTON_TOPRIGHT
437 #endif
438 #ifndef BJACK_MIN
439 #define BJACK_MIN BUTTON_TOPLEFT
440 #endif
441 #ifndef BJACK_RESUME
442 #define BJACK_RESUME BUTTON_BOTTOMRIGHT
443 #define BJACK_RESUME_NAME "BUTTON_BOTTOMRIGHT"
444 #endif
445 #ifndef BJACK_STAY
446 #define BJACK_STAY BUTTON_BOTTOMLEFT
447 #define BJACK_STAY_NAME "BUTTON_BOTTOMLEFT"
448 #endif
449 #ifndef BJACK_UP
450 #define BJACK_UP BUTTON_TOPMIDDLE
451 #endif
452 #ifndef BJACK_DOWN
453 #define BJACK_DOWN BUTTON_BOTTOMMIDDLE
454 #endif
455 #ifndef BJACK_RIGHT
456 #define BJACK_RIGHT BUTTON_MIDRIGHT
457 #endif
458 #ifndef BJACK_LEFT
459 #define BJACK_LEFT BUTTON_MIDLEFT
460 #endif
462 #endif
464 #ifdef HAVE_LCD_COLOR
465 #define BG_COLOR LCD_RGBPACK(0,157,0)
466 #define FG_COLOR LCD_WHITE
467 #elif LCD_DEPTH > 1
468 #define BG_COLOR LCD_WHITE
469 #define FG_COLOR LCD_BLACK
470 #endif
472 #define CARD_WIDTH BMPWIDTH_card_back
473 #define CARD_HEIGHT BMPHEIGHT_card_back
475 /* This is the max amount of cards onscreen before condensing */
476 #define MAX_CARDS LCD_WIDTH/(CARD_WIDTH+4)
478 extern const fb_data card_deck[];
479 extern const fb_data card_back[];
481 #define NEXT_CARD bj->player_cards[done][bj->num_player_cards[done]]
483 /* dealer and player card positions */
484 unsigned int dealer_x, dealer_y, player_x, player_y;
486 typedef struct card {
487 unsigned int value; /* Card's value in Blackjack */
488 unsigned int num; /* Value on card face 0-12 (0=Ace, 1=2, 11=Q) */
489 unsigned int suit; /* 0:Spades, 1:Hearts, 2: Clubs; 3: Diamonds */
490 bool is_soft_ace;
491 } card;
493 typedef struct game_context {
494 struct card player_cards[2][22]; /* 22 Cards means the deal was all aces */
495 struct card dealer_cards[22]; /* That is the worst-case scenario */
496 unsigned int player_total;
497 unsigned int dealer_total;
498 signed int player_money;
499 unsigned int num_player_cards[2];
500 unsigned int num_dealer_cards;
501 unsigned int current_bet;
502 unsigned int split_status; /* 0 = split hasn't been asked, *
503 * 1 = split did not occur *
504 * 2 = split occurred *
505 * 3 = split occurred and 1st hand done */
506 bool is_blackjack;
507 bool end_hand;
508 bool asked_insurance;
509 bool resume;
510 } game_context;
512 /*****************************************************************************
513 * blackjack_init() initializes blackjack data structures.
514 ******************************************************************************/
515 static void blackjack_init(struct game_context* bj) {
516 /* seed the rand generator */
517 rb->srand(*rb->current_tick);
519 /* reset card positions */
520 dealer_x = 4;
521 dealer_y = LCD_HEIGHT/4 - CARD_HEIGHT/2;
522 player_x = 4;
523 player_y = LCD_HEIGHT - LCD_HEIGHT/4 - CARD_HEIGHT/2;
525 /* check for resumed game */
526 if(bj->resume) return;
528 /* reset scoring */
529 bj->player_total = 0;
530 bj->dealer_total = 0;
531 bj->num_player_cards[0] = 2;
532 bj->num_player_cards[1] = 0;
533 bj->num_dealer_cards = 2;
534 bj->end_hand = false;
535 bj->split_status = 0;
536 bj->is_blackjack = false;
537 bj->asked_insurance = false;
540 /*****************************************************************************
541 * blackjack_drawtable() draws the table and some text.
542 ******************************************************************************/
543 static void blackjack_drawtable(struct game_context* bj) {
544 unsigned int w, h, y_loc;
545 char str[10];
547 #if LCD_HEIGHT <= 64
548 rb->lcd_getstringsize("Bet", &w, &h);
549 rb->lcd_putsxy(LCD_WIDTH - w, 2*h + 1, "Bet");
550 rb->snprintf(str, 9, "$%d", bj->current_bet);
551 rb->lcd_getstringsize(str, &w, &h);
552 rb->lcd_putsxy(LCD_WIDTH - w, 3*h + 1, str);
553 y_loc = LCD_HEIGHT/2;
554 #else
555 rb->lcd_getstringsize("Bet", &w, &h);
556 rb->lcd_putsxy(LCD_WIDTH - w, 5*h / 2, "Bet");
557 rb->snprintf(str, 9, "$%d", bj->current_bet);
558 rb->lcd_getstringsize(str, &w, &h);
559 rb->lcd_putsxy(LCD_WIDTH - w, 7*h / 2, str);
560 rb->lcd_hline(0, LCD_WIDTH, LCD_HEIGHT/2);
561 y_loc = LCD_HEIGHT/2 + h;
562 #endif
564 rb->lcd_putsxy(0,0, "Dealer");
565 rb->lcd_getstringsize("Player", &w, &h);
566 rb->lcd_putsxy(0, y_loc, "Player");
567 rb->lcd_getstringsize("Total", &w, &h);
568 rb->lcd_putsxy(LCD_WIDTH - w, y_loc, "Total");
569 rb->lcd_getstringsize("Money", &w, &h);
570 rb->lcd_putsxy(LCD_WIDTH - w, 0, "Money");
571 rb->snprintf(str, 9, "$%d", bj->player_money - bj->current_bet);
572 rb->lcd_getstringsize(str, &w, &h);
573 rb->lcd_putsxy(LCD_WIDTH - w, h + 1, str);
574 rb->snprintf(str, 3, "%d", bj->player_total);
575 rb->lcd_getstringsize(str, &w, &h);
576 rb->lcd_putsxy(LCD_WIDTH - w, y_loc + h, str);
579 /*****************************************************************************
580 * find_value() is passed a card and returns its blackjack value.
581 ******************************************************************************/
582 static unsigned int find_value(unsigned int number) {
583 unsigned int thisValue;
584 if (number == 0)
585 thisValue = 11; /* Aces get a value of 11 at first */
586 else if (number < 10)
587 thisValue = number + 1;
588 else
589 thisValue = 10; /* Anything 10 or higher gets a value of 10 */
591 return thisValue;
594 /*****************************************************************************
595 * draw_card() draws a card to the screen.
596 ******************************************************************************/
597 static void draw_card(struct card temp_card, bool shown,
598 unsigned int x, unsigned int y) {
599 if(shown)
600 rb->lcd_bitmap_part(card_deck, CARD_WIDTH*temp_card.num,
601 CARD_HEIGHT*temp_card.suit, BMPWIDTH_card_deck,
602 x+1, y+1, CARD_WIDTH, CARD_HEIGHT);
603 else
604 rb->lcd_bitmap(card_back, x+1, y+1,CARD_WIDTH, CARD_HEIGHT);
605 #if LCD_DEPTH > 1
606 rb->lcd_set_foreground(LCD_BLACK);
607 #endif
609 /* Print outlines */
610 #if CARD_WIDTH >= 26
611 rb->lcd_hline(x+2, x+CARD_WIDTH-1, y);
612 rb->lcd_hline(x+2, x+CARD_WIDTH-1, y+CARD_HEIGHT+1);
613 rb->lcd_vline(x, y+2, y+CARD_HEIGHT-3);
614 rb->lcd_vline(x+CARD_WIDTH+1, y+2, y+CARD_HEIGHT-1);
615 rb->lcd_drawpixel(x+1, y+1);
616 rb->lcd_drawpixel(x+1, y+CARD_HEIGHT);
617 rb->lcd_drawpixel(x+CARD_WIDTH, y+1);
618 rb->lcd_drawpixel(x+CARD_WIDTH, y+CARD_HEIGHT);
619 #else
620 rb->lcd_hline(x+1, x+CARD_WIDTH, y);
621 rb->lcd_hline(x+1, x+CARD_WIDTH, y+CARD_HEIGHT+1);
622 rb->lcd_vline(x, y+1, y+CARD_HEIGHT);
623 rb->lcd_vline(x+CARD_WIDTH+1, y+1, y+CARD_HEIGHT);
624 #endif
626 #if LCD_DEPTH > 1
627 rb->lcd_set_foreground(FG_COLOR);
628 #endif
631 /*****************************************************************************
632 * new_card() initializes a new card and gives it values.
633 ******************************************************************************/
634 static struct card new_card(void) {
635 struct card new_card;
636 new_card.suit = rb->rand()%4; /* Random number 0-3 */
637 new_card.num = rb->rand()%13; /* Random number 0-12 */
638 new_card.value = find_value(new_card.num);
639 new_card.is_soft_ace = new_card.num == 0 ? true : false;
640 return new_card;
643 /*****************************************************************************
644 * deal_init_card() deals and draws to the screen the player's and dealer's
645 * initial cards.
646 ******************************************************************************/
647 static void deal_init_cards(struct game_context* bj) {
648 bj->dealer_cards[0] = new_card();
649 bj->dealer_total += bj->dealer_cards[0].value;
651 draw_card(bj->dealer_cards[0], false, dealer_x, dealer_y);
653 bj->dealer_cards[1] = new_card();
654 bj->dealer_total += bj->dealer_cards[1].value;
655 draw_card(bj->dealer_cards[1], true, dealer_x + CARD_WIDTH + 4, dealer_y);
657 bj->player_cards[0][0] = new_card();
658 bj->player_total += bj->player_cards[0][0].value;
659 draw_card(bj->player_cards[0][0], true, player_x, player_y);
660 player_x += CARD_WIDTH + 4;
662 bj->player_cards[0][1] = new_card();
663 bj->player_total += bj->player_cards[0][1].value;
664 draw_card(bj->player_cards[0][1], true, player_x, player_y);
665 player_x += CARD_WIDTH + 4;
668 /*****************************************************************************
669 * redraw_board() redraws all the cards and the board
670 ******************************************************************************/
671 static void redraw_board(struct game_context* bj) {
672 unsigned int i, n, upper_bound;
673 rb->lcd_clear_display();
675 blackjack_drawtable(bj);
676 player_x = 4;
677 dealer_x = 4;
678 upper_bound = bj->split_status > 1 ? 2 : 1;
680 for (i = 0; i < bj->num_dealer_cards; i++) {
681 if (!bj->end_hand) {
682 draw_card(bj->dealer_cards[0], false, dealer_x, dealer_y);
684 /* increment i so the dealer's first card isn't displayed */
685 i++;
686 dealer_x += CARD_WIDTH + 4;
688 draw_card(bj->dealer_cards[i], true, dealer_x, dealer_y);
690 if (bj->num_dealer_cards > MAX_CARDS-1)
691 dealer_x += 10;
692 else
693 dealer_x += CARD_WIDTH + 4;
696 for (n = 0; n < upper_bound; n++) {
697 for (i = 0; i < bj->num_player_cards[n]; i++) {
698 draw_card(bj->player_cards[n][i], true, player_x, player_y);
699 if (bj->split_status>1 || bj->num_player_cards[n]>MAX_CARDS)
700 player_x += 10;
701 else
702 player_x += CARD_WIDTH + 4;
704 if (bj->split_status > 1)
705 player_x = LCD_WIDTH/2 + 4;
709 /*****************************************************************************
710 * update_total updates the player's total
711 ******************************************************************************/
712 static void update_total(struct game_context* bj) {
713 char total[3];
714 unsigned int w, h;
715 rb->snprintf(total, 3, "%d", bj->player_total);
716 rb->lcd_getstringsize(total, &w, &h);
717 #if LCD_HEIGHT > 64
718 h *= 2;
719 #endif
720 rb->lcd_putsxy(LCD_WIDTH - w, LCD_HEIGHT/2 + h, total);
721 rb->lcd_update_rect(LCD_WIDTH - w, LCD_HEIGHT/2 + h, w, h);
725 /*****************************************************************************
726 * check_for_aces() is passed an array of cards and returns where an ace is
727 * located. Otherwise, returns -1.
728 ******************************************************************************/
729 static signed int check_for_aces(struct card temp_cards[], unsigned int size) {
730 unsigned int i;
731 for(i = 0; i < size; i++) {
732 if (temp_cards[i].is_soft_ace == true)
733 return i;
735 return -1;
738 /*****************************************************************************
739 * check_totals() compares player and dealer totals.
740 * 0: bust 1: loss, 2: push, 3: win, 4: blackjack, 5: something's not right...
741 ******************************************************************************/
742 static unsigned int check_totals(struct game_context* bj) {
743 unsigned int temp;
744 if (bj->player_total > 21)
745 temp = 0;
746 else if (bj->player_total == 21 && bj->is_blackjack) {
747 if (bj->dealer_total == 21 && bj->num_dealer_cards == 2)
748 temp = 2;
749 else
750 temp = 4;
752 else if (bj->player_total == bj->dealer_total)
753 temp = 2;
754 else if (bj->dealer_total > 21 && bj->player_total < 22)
755 temp = 3;
756 else if (bj->dealer_total > bj->player_total)
757 temp = 1;
758 else if (bj->player_total > bj->dealer_total)
759 temp = 3;
760 else
761 temp = 5;
763 return temp;
766 /*****************************************************************************
767 * finish_dealer() draws cards for the dealer until he has 17 or more.
768 ******************************************************************************/
769 static void finish_dealer(struct game_context* bj) {
770 signed int temp = 0;
772 if (bj->dealer_total > 16 && bj->dealer_total < 22)
773 return;
775 while (bj->dealer_total < 17) {
776 bj->dealer_cards[bj->num_dealer_cards] = new_card();
777 bj->dealer_total += bj->dealer_cards[bj->num_dealer_cards].value;
778 bj->num_dealer_cards++;
781 while (bj->dealer_total > 21) {
782 temp = check_for_aces(bj->dealer_cards, bj->num_dealer_cards);
783 if(temp != -1) {
784 bj->dealer_cards[temp].is_soft_ace = false;
785 bj->dealer_total -= 10;
787 else
788 return;
792 /*****************************************************************************
793 * finish_game() completes the game once player's turn is over.
794 ******************************************************************************/
795 static void finish_game(struct game_context* bj) {
796 unsigned int rValue, w, h;
797 char str[19];
799 do {
800 finish_dealer(bj);
801 } while (bj->dealer_total < 17);
803 redraw_board(bj);
804 rValue = check_totals(bj);
806 if (rValue == 0) {
807 rb->snprintf(str, sizeof(str), " Bust! ");
808 bj->player_money -= bj->current_bet;
810 else if (rValue == 1) {
811 rb->snprintf(str, sizeof(str), " Sorry, you lost. ");
812 bj->player_money -= bj->current_bet;
814 else if (rValue == 2) {
815 rb->snprintf(str, sizeof(str), " Push ");
817 else if (rValue == 3) {
818 rb->snprintf(str, sizeof(str), " You won! ");
819 bj->player_money+= bj->current_bet;
821 else {
822 rb->snprintf(str, sizeof(str), " Blackjack! ");
823 bj->player_money += bj->current_bet * 3 / 2;
825 rb->lcd_getstringsize(str, &w, &h);
827 #if LCD_HEIGHT <= 64
828 rb->lcd_set_drawmode(DRMODE_BG+DRMODE_INVERSEVID);
829 rb->lcd_fillrect(0, LCD_HEIGHT/2, LCD_WIDTH, LCD_HEIGHT/2);
830 rb->lcd_set_drawmode(DRMODE_SOLID);
831 rb->lcd_putsxy(LCD_WIDTH/2 - w/2, LCD_HEIGHT/2 + h, str);
832 rb->snprintf(str, 12, "You have %d", bj->player_total);
833 rb->lcd_getstringsize(str, &w, &h);
834 rb->lcd_putsxy(LCD_WIDTH/2 - w/2, LCD_HEIGHT/2, str);
835 #else
836 rb->lcd_putsxy(LCD_WIDTH/2 - w/2, LCD_HEIGHT/2 - h/2, str);
837 #endif
838 rb->lcd_update();
841 /*****************************************************************************
842 * blackjack_loadgame() loads the saved game and returns load success.
843 ******************************************************************************/
844 static bool blackjack_loadgame(struct game_context* bj) {
845 signed int fd;
846 bool loaded = false;
848 /* open game file */
849 fd = rb->open(SAVE_FILE, O_RDONLY);
850 if(fd < 0) return loaded;
852 /* read in saved game */
853 while(true) {
854 if(rb->read(fd, &bj->player_money, sizeof(bj->player_money)) <= 0)
855 break;
856 if(rb->read(fd, &bj->player_total, sizeof(bj->player_total)) <= 0)
857 break;
858 if(rb->read(fd, &bj->dealer_total, sizeof(bj->dealer_total)) <= 0)
859 break;
860 if(rb->read(fd, &bj->num_player_cards, sizeof(bj->num_player_cards))<=0)
861 break;
862 if(rb->read(fd, &bj->num_dealer_cards, sizeof(bj->num_dealer_cards))<=0)
863 break;
864 if(rb->read(fd, &bj->current_bet, sizeof(bj->current_bet)) <= 0)
865 break;
866 if(rb->read(fd, &bj->is_blackjack, sizeof(bj->is_blackjack)) <= 0)
867 break;
868 if(rb->read(fd, &bj->split_status, sizeof(bj->split_status)) <= 0)
869 break;
870 if(rb->read(fd, &bj->asked_insurance, sizeof(bj->asked_insurance)) <= 0)
871 break;
872 if(rb->read(fd, &bj->end_hand, sizeof(bj->end_hand)) <= 0)
873 break;
874 if(rb->read(fd, &bj->player_cards, sizeof(bj->player_cards)) <= 0)
875 break;
876 if(rb->read(fd, &bj->dealer_cards, sizeof(bj->dealer_cards)) <= 0)
877 break;
878 bj->resume = true;
879 loaded = true;
880 break;
883 rb->close(fd);
885 /* delete saved file */
886 rb->remove(SAVE_FILE);
887 return loaded;
890 /*****************************************************************************
891 * blackjack_savegame() saves the current game state.
892 ******************************************************************************/
893 static void blackjack_savegame(struct game_context* bj) {
894 unsigned int fd;
896 /* write out the game state to the save file */
897 fd = rb->open(SAVE_FILE, O_WRONLY|O_CREAT);
898 rb->write(fd, &bj->player_money, sizeof(bj->player_money));
899 rb->write(fd, &bj->player_total, sizeof(bj->player_total));
900 rb->write(fd, &bj->dealer_total, sizeof(bj->dealer_total));
901 rb->write(fd, &bj->num_player_cards, sizeof(bj->num_player_cards));
902 rb->write(fd, &bj->num_dealer_cards, sizeof(bj->num_dealer_cards));
903 rb->write(fd, &bj->current_bet, sizeof(bj->current_bet));
904 rb->write(fd, &bj->is_blackjack, sizeof(bj->is_blackjack));
905 rb->write(fd, &bj->split_status, sizeof(bj->split_status));
906 rb->write(fd, &bj->asked_insurance, sizeof(bj->asked_insurance));
907 rb->write(fd, &bj->end_hand, sizeof(bj->end_hand));
908 rb->write(fd, &bj->player_cards, sizeof(bj->player_cards));
909 rb->write(fd, &bj->dealer_cards, sizeof(bj->dealer_cards));
910 rb->close(fd);
912 bj->resume = true;
915 /*****************************************************************************
916 * blackjack_get_yes_no() gets a yes/no answer from the user
917 ******************************************************************************/
918 static unsigned int blackjack_get_yes_no(char message[20]) {
919 int button;
920 unsigned int w, h, b, choice = 0;
921 bool breakout = false;
922 char message_yes[24], message_no[24];
924 rb->strcpy(message_yes, message);
925 rb->strcpy(message_no, message);
926 rb->strcat(message_yes, " Yes");
927 rb->strcat(message_no, " No");
928 rb->lcd_getstringsize(message_yes, &w, &h);
929 const char *stg[] = {message_yes, message_no};
931 #if LCD_HEIGHT <= 64
932 b = 2*h+1;
933 #else
934 b = h-1;
935 #endif
937 #ifdef HAVE_LCD_COLOR
938 rb->lcd_fillrect(LCD_WIDTH/2 - w/2, LCD_HEIGHT/2 + b, w+1, h+3);
939 rb->lcd_set_foreground(LCD_BLACK);
940 rb->lcd_set_background(LCD_WHITE);
941 #else
942 rb->lcd_set_drawmode(DRMODE_BG+DRMODE_INVERSEVID);
943 rb->lcd_fillrect(LCD_WIDTH/2 - w/2, LCD_HEIGHT/2 + b, w+1, h+3);
944 rb->lcd_set_drawmode(DRMODE_SOLID);
945 #endif
946 rb->lcd_drawrect(LCD_WIDTH/2 - w/2 - 1, LCD_HEIGHT/2 + b - 1, w+3, h+4);
948 while(!breakout) {
949 rb->lcd_putsxy(LCD_WIDTH/2 - w/2, LCD_HEIGHT/2 + b +1, stg[choice]);
950 rb->lcd_update_rect(LCD_WIDTH/2 - w/2 - 1, LCD_HEIGHT/2 + b -1,
951 w+3, h+4);
952 button = rb->button_get(true);
954 switch(button) {
955 case BJACK_LEFT:
956 case (BJACK_LEFT|BUTTON_REPEAT):
957 case BJACK_RIGHT:
958 case (BJACK_RIGHT|BUTTON_REPEAT):
959 choice ^= 1;
960 break;
961 case BJACK_SELECT: breakout = true;
962 break;
963 case BJACK_QUIT: breakout = true;
964 choice = BJ_QUIT;
965 break;
969 #if LCD_DEPTH > 1
970 rb->lcd_set_foreground(FG_COLOR);
971 rb->lcd_set_background(BG_COLOR);
972 #endif
973 return choice;
976 /*****************************************************************************
977 * blackjack_get_amount() gets an amount from the player to be used
978 ******************************************************************************/
979 static signed int blackjack_get_amount(char message[20], signed int lower_limit,
980 signed int upper_limit,
981 signed int start) {
982 int button;
983 char str[9];
984 bool changed = false;
985 unsigned int w, h;
986 signed int amount;
988 rb->lcd_getstringsize("A", &w, &h); /* find the size of one character */
990 if (start > upper_limit)
991 amount = upper_limit;
992 else if (start < lower_limit)
993 amount = lower_limit;
994 else
995 amount = start;
997 #if LCD_DEPTH > 1
998 rb->lcd_set_background(LCD_WHITE);
999 rb->lcd_set_foreground(LCD_BLACK);
1000 #endif
1002 #if LCD_HEIGHT <= 64
1003 rb->lcd_clear_display();
1004 rb->lcd_puts(0, 1, message);
1005 rb->snprintf(str, 9, "$%d", amount);
1006 rb->lcd_puts(0, 2, str);
1007 rb->lcd_puts(0, 3, "RIGHT: +1");
1008 rb->lcd_puts(0, 4, "LEFT: -1");
1009 rb->lcd_puts(0, 5, "UP: +10");
1010 rb->lcd_puts(0, 6, "DOWN: -10");
1011 rb->lcd_update();
1012 #else
1013 rb->lcd_set_drawmode(DRMODE_BG+DRMODE_INVERSEVID);
1014 rb->lcd_fillrect(LCD_WIDTH/2 - 9*w - 1, LCD_HEIGHT/2 - 4*h - 3,
1015 37*w / 2, 8*h -3);
1016 rb->lcd_set_drawmode(DRMODE_SOLID);
1017 rb->lcd_drawrect(LCD_WIDTH/2 - 9*w - 1, LCD_HEIGHT/2 - 4*h - 3,
1018 37*w / 2, 8*h -3);
1019 rb->lcd_putsxy(LCD_WIDTH/2 - 9*w, LCD_HEIGHT/2 - 4*h - 1, message);
1020 rb->snprintf(str, 9, "$%d", amount);
1021 rb->lcd_putsxy(LCD_WIDTH/2 - 9*w, LCD_HEIGHT/2 - 3*h, str);
1022 #if (CONFIG_KEYPAD == IPOD_4G_PAD) || \
1023 (CONFIG_KEYPAD == IPOD_3G_PAD) || \
1024 (CONFIG_KEYPAD == IPOD_1G2G_PAD)
1025 rb->lcd_putsxy(LCD_WIDTH/2 - 9*w, LCD_HEIGHT/2 - h-2, " >>|: +1");
1026 rb->lcd_putsxy(LCD_WIDTH/2 - 9*w, LCD_HEIGHT/2 - 1, " |<<: -1");
1027 rb->lcd_putsxy(LCD_WIDTH/2 - 9*w, LCD_HEIGHT/2 + h, "SCROLL+: +10");
1028 rb->lcd_putsxy(LCD_WIDTH/2 - 9*w, LCD_HEIGHT/2 + 2*h + 1, "SCROLL-: -10");
1029 #elif CONFIG_KEYPAD == IRIVER_H10_PAD
1030 rb->lcd_putsxy(LCD_WIDTH/2 - 9*w, LCD_HEIGHT/2 - h-2, "RIGHT: +1");
1031 rb->lcd_putsxy(LCD_WIDTH/2 - 9*w, LCD_HEIGHT/2 - 1, "LEFT: -1");
1032 rb->lcd_putsxy(LCD_WIDTH/2 - 9*w, LCD_HEIGHT/2 + h, "SCROLL+: +10");
1033 rb->lcd_putsxy(LCD_WIDTH/2 - 9*w, LCD_HEIGHT/2 + 2*h + 1, "SCROLL-: -10");
1034 #else
1035 rb->lcd_putsxy(LCD_WIDTH/2 - 9*w, LCD_HEIGHT/2 - h-2, "RIGHT: +1");
1036 rb->lcd_putsxy(LCD_WIDTH/2 - 9*w, LCD_HEIGHT/2 - 1, "LEFT: -1");
1037 rb->lcd_putsxy(LCD_WIDTH/2 - 9*w, LCD_HEIGHT/2 + h, "UP: +10");
1038 rb->lcd_putsxy(LCD_WIDTH/2 - 9*w, LCD_HEIGHT/2 + 2*h + 1, "DOWN: -10");
1039 #endif
1040 rb->lcd_update_rect(LCD_WIDTH/2 - 9*w - 1, LCD_HEIGHT/2 - 4*h - 3,
1041 37*w / 2, 8*h -3);
1042 #endif
1044 while(true) {
1045 button = rb->button_get(true);
1047 switch(button) {
1048 case BJACK_UP:
1049 case (BJACK_UP|BUTTON_REPEAT):
1050 if (amount + 10 < upper_limit + 1) {
1051 amount += 10;
1052 changed = true;
1054 break;
1055 case BJACK_DOWN:
1056 case (BJACK_DOWN|BUTTON_REPEAT):
1057 if (amount - 10 > lower_limit - 1) {
1058 amount -= 10;
1059 changed = true;
1061 break;
1062 case BJACK_RIGHT:
1063 case (BJACK_RIGHT|BUTTON_REPEAT):
1064 if (amount + 1 < upper_limit + 1) {
1065 amount++;
1066 changed = true;
1068 break;
1069 case BJACK_LEFT:
1070 case (BJACK_LEFT|BUTTON_REPEAT):
1071 if (amount - 1 > lower_limit - 1) {
1072 amount--;
1073 changed = true;
1075 break;
1076 case BJACK_MAX :
1077 amount = upper_limit;
1078 changed = true;
1079 break;
1080 case BJACK_MIN :
1081 amount = lower_limit;
1082 changed = true;
1083 break;
1084 case BJACK_QUIT:
1085 return 0;
1086 case BJACK_SELECT:
1087 #if LCD_DEPTH > 1
1088 rb->lcd_set_foreground(FG_COLOR);
1089 rb->lcd_set_background(BG_COLOR);
1090 #endif
1091 rb->lcd_clear_display();
1092 return amount;
1095 if(changed) {
1096 rb->snprintf(str, 9, "$%d", amount);
1097 #if LCD_HEIGHT <= 64
1098 rb->lcd_puts(0, 2, str);
1099 rb->lcd_update();
1100 #else
1101 rb->lcd_set_drawmode(DRMODE_BG+DRMODE_INVERSEVID);
1102 rb->lcd_fillrect(LCD_WIDTH/2 - 9*w, LCD_HEIGHT/2 - 3*h, 5*w, h);
1103 rb->lcd_set_drawmode(DRMODE_SOLID);
1104 rb->lcd_putsxy(LCD_WIDTH/2 - 9*w, LCD_HEIGHT/2 - 3*h, str);
1105 rb->lcd_update_rect(LCD_WIDTH/2 - 9*w, LCD_HEIGHT/2 - 3*h, 5*w, h);
1106 #endif
1107 changed = false;
1112 /*****************************************************************************
1113 * blackjack_get_bet() gets the player's bet.
1114 ******************************************************************************/
1115 static void blackjack_get_bet(struct game_context* bj) {
1116 bj->current_bet = blackjack_get_amount("Please enter a bet", 10,
1117 bj->player_money, bj->current_bet);
1120 /*****************************************************************************
1121 * double_down() returns one final card then finishes the game
1122 ******************************************************************************/
1123 static void double_down(struct game_context* bj) {
1124 bj->current_bet *= 2;
1125 bj->player_cards[0][bj->num_player_cards[0]] = new_card();
1126 bj->player_total += bj->player_cards[0][bj->num_player_cards[0]].value;
1127 bj->num_player_cards[0]++;
1130 /*****************************************************************************
1131 * split() checks if the player wants to split and acts accordingly.
1132 * When bj->split_status is 1, no split occurred. 2 means the player split and 3
1133 * means a split has already occurred and the first hand is done.
1134 ******************************************************************************/
1135 static void split(struct game_context* bj) {
1136 if (blackjack_get_yes_no("Split?") == 1)
1137 bj->split_status = 1;
1138 else {
1139 bj->split_status = 2;
1140 bj->current_bet *= 2;
1141 bj->num_player_cards[0] = 1;
1142 bj->num_player_cards[1] = 1;
1143 bj->player_cards[1][0] = bj->player_cards[0][1];
1144 bj->player_total = bj->player_cards[0][0].value;
1148 /*****************************************************************************
1149 * insurance() see if the player wants to buy insurance and how much.
1150 ******************************************************************************/
1151 static unsigned int insurance(struct game_context* bj) {
1152 unsigned int insurance, max_amount;
1154 insurance = blackjack_get_yes_no("Buy Insurance?");
1155 bj->asked_insurance = true;
1156 max_amount = bj->current_bet < (unsigned int)bj->player_money ?
1157 bj->current_bet/2 : (unsigned int)bj->player_money;
1158 if (insurance == 1) return 0;
1160 insurance = blackjack_get_amount("How much?", 0, max_amount, 0);
1161 redraw_board(bj);
1162 return insurance;
1165 /*****************************************************************************
1166 * play_again() checks to see if the player wants to keep playing.
1167 ******************************************************************************/
1168 static unsigned int play_again(void) {
1169 return blackjack_get_yes_no("Play Again?");
1172 /*****************************************************************************
1173 * blackjack_help() displays help text.
1174 ******************************************************************************/
1175 static bool blackjack_help(void) {
1176 #define WORDS (sizeof help_text / sizeof (char*))
1177 static char *help_text[] = {
1178 "Blackjack", "",
1179 "The", "goal", "is", "to", "get", "21.", "", "",
1180 "Controls", "",
1181 BJACK_SELECT_NAME, ":", "hit", "/", "select", "",
1182 BJACK_STAY_NAME, ":", "stay", "",
1183 BJACK_DOUBLE_NAME, ":", "double", "down", "",
1184 BJACK_QUIT_NAME, ":", "Go", "to", "menu", "without", "save", "",
1185 BJACK_RESUME_NAME, ":", "Save", "and", "go", "to", "menu", "",
1188 static struct style_text formation[]={
1189 { 0, TEXT_CENTER|TEXT_UNDERLINE },
1190 { 12, C_RED }, /* Hit/Select */
1191 { 18, C_RED }, /* Stay */
1192 { 22, C_RED }, /* Double Down */
1193 { 27, C_RED }, /* Quit */
1194 { 35, C_RED }, /* Save */
1195 { -1, 0 }
1197 int button;
1199 rb->lcd_setfont(FONT_UI);
1200 #ifdef HAVE_LCD_COLOR
1201 rb->lcd_set_background(LCD_BLACK);
1202 rb->lcd_set_foreground(LCD_WHITE);
1203 #endif
1205 if (display_text(WORDS, help_text, formation, NULL))
1206 return true;
1207 do {
1208 button = rb->button_get(true);
1209 if (rb->default_event_handler(button) == SYS_USB_CONNECTED) {
1210 return true;
1212 } while( ( button == BUTTON_NONE )
1213 || ( button & (BUTTON_REL|BUTTON_REPEAT) ) );
1214 rb->lcd_setfont(FONT_SYSFIXED);
1215 return false;
1218 /*****************************************************************************
1219 * blackjack_menu() is the initial menu at the start of the game.
1220 ******************************************************************************/
1221 static unsigned int blackjack_menu(struct game_context* bj) {
1222 int selection=0;
1223 bool breakout = false;
1225 MENUITEM_STRINGLIST(menu, "BlackJack Menu", NULL,
1226 "Start Game","Resume Game",
1227 "High Scores", "Help",
1228 "Playback Control", "Quit");
1230 while(!breakout) {
1231 switch(rb->do_menu(&menu, &selection, NULL, false)) {
1232 case 0:
1233 breakout = true;
1234 break;
1235 case 1:
1236 if(!blackjack_loadgame(bj)) {
1237 rb->splash(HZ*2, "Nothing to resume");
1238 } else {
1239 breakout = true;
1241 break;
1242 case 2:
1243 highscore_show(NUM_SCORES, highest, NUM_SCORES, false);
1244 break;
1245 case 3:
1246 if(blackjack_help())
1247 return BJ_USB;
1248 break;
1249 case 4:
1250 if (playback_control(NULL))
1251 return BJ_USB;
1252 break;
1253 case 5:
1254 return BJ_QUIT;
1256 case MENU_ATTACHED_USB:
1257 return BJ_USB;
1259 default:
1260 break;
1264 return 0;
1267 /*****************************************************************************
1268 * blackjack() is the main game subroutine, it returns the final game status.
1269 ******************************************************************************/
1270 static int blackjack(struct game_context* bj) {
1271 int button;
1272 unsigned int w, h, temp_var, done = 0, todo = 1;
1273 signed int temp;
1274 bool breakout = false;
1275 bool dbl_down = false;
1277 #if LCD_DEPTH > 1
1278 rb->lcd_set_background(BG_COLOR);
1279 rb->lcd_set_foreground(FG_COLOR);
1280 #endif
1282 /* don't resume by default */
1283 bj->resume = false;
1285 /********************
1286 * menu *
1287 ********************/
1288 temp_var = blackjack_menu(bj);
1289 if (temp_var == BJ_QUIT || temp_var == BJ_USB)
1290 return temp_var;
1293 /********************
1294 * init *
1295 ********************/
1296 blackjack_init(bj);
1298 /********************
1299 * play *
1300 ********************/
1302 /* check for resumed game */
1303 if(bj->resume) {
1304 bj->resume = false;
1305 redraw_board(bj);
1306 if (bj->split_status == 2) {
1307 todo=2;
1308 player_x = bj->num_player_cards[0] * 10 + 4;
1310 else if (bj->split_status == 3) {
1311 player_x = bj->num_player_cards[1] * 10 + LCD_WIDTH/2 + 4;
1312 todo=2;
1313 done=1;
1316 else {
1317 bj->player_money = 1000;
1318 bj->current_bet = 10;
1319 blackjack_get_bet(bj);
1320 if (bj->current_bet == 0)
1321 return -1;
1322 rb->lcd_clear_display();
1323 deal_init_cards(bj);
1324 blackjack_drawtable(bj);
1327 rb->lcd_update();
1329 breakout = false;
1331 while(true){
1332 if(bj->player_total == 21 && bj->num_player_cards[0] == 2) {
1333 bj->is_blackjack = true;
1334 bj->end_hand = true;
1335 finish_game(bj);
1337 else if(bj->dealer_cards[1].is_soft_ace && !breakout &&
1338 !bj->asked_insurance) {
1339 temp_var = insurance(bj);
1340 if (bj->dealer_total == 21) {
1341 rb->splash(HZ, "Dealer has blackjack");
1342 bj->player_money += temp_var;
1343 bj->end_hand = true;
1344 breakout = true;
1345 redraw_board(bj);
1346 finish_game(bj);
1348 else {
1349 rb->splash(HZ, "Dealer does not have blackjack");
1350 bj->player_money -= temp_var;
1351 breakout = true;
1352 redraw_board(bj);
1353 rb->lcd_update();
1356 if(!bj->end_hand && bj->split_status == 0 &&
1357 bj->player_cards[0][0].num == bj->player_cards[0][1].num) {
1358 split(bj);
1359 redraw_board(bj);
1360 rb->lcd_update_rect(0, LCD_HEIGHT/2, LCD_WIDTH, LCD_HEIGHT/2);
1361 if (bj->split_status == 2) {
1362 todo++;
1363 player_x = bj->num_player_cards[0] * 10 + 4;
1367 while(!bj->end_hand && done < todo) {
1368 button = rb->button_get(true);
1370 switch(button) {
1371 case BJACK_SELECT:
1372 NEXT_CARD = new_card();
1373 bj->player_total += NEXT_CARD.value;
1374 draw_card(NEXT_CARD, true, player_x, player_y);
1375 bj->num_player_cards[done]++;
1376 if (bj->num_player_cards[done] == MAX_CARDS + 1) {
1377 redraw_board(bj);
1378 rb->lcd_update_rect(0, LCD_HEIGHT/2, LCD_WIDTH,
1379 LCD_HEIGHT/2);
1381 else if (bj->num_player_cards[done]>MAX_CARDS || todo > 1) {
1382 rb->lcd_update_rect(player_x, player_y, CARD_WIDTH+2,
1383 CARD_HEIGHT+2);
1384 player_x += 10;
1386 else {
1387 rb->lcd_update_rect(player_x, player_y, CARD_WIDTH+2,
1388 CARD_HEIGHT+2);
1389 player_x += CARD_WIDTH + 4;
1391 update_total(bj);
1393 break;
1394 case BJACK_STAY:
1395 bj->end_hand = true;
1396 break;
1397 case BJACK_DOUBLEDOWN:
1398 if ((signed int)bj->current_bet * 2 <
1399 bj->player_money + 1 &&
1400 bj->num_player_cards[0]==2 && todo==1) {
1401 double_down(bj);
1402 dbl_down = true;
1403 if (bj->player_total < 22) {
1404 bj->end_hand = true;
1405 finish_game(bj);
1408 else if((signed int)bj->current_bet * 2 >
1409 bj->player_money){
1410 rb->splash(HZ, "Not enough money to double down.");
1411 redraw_board(bj);
1412 rb->lcd_update();
1414 break;
1415 case BJACK_RESUME: /* save and end game */
1416 rb->splash(HZ, "Saving game...");
1417 blackjack_savegame(bj);
1418 /* fall through to BJACK_QUIT */
1420 case BJACK_QUIT:
1421 return BJ_END;
1424 while (bj->player_total > 21 && !bj->end_hand) {
1425 temp = check_for_aces(bj->player_cards[done],
1426 bj->num_player_cards[done]);
1427 if(temp != -1) {
1428 bj->player_cards[done][temp].is_soft_ace = false;
1429 bj->player_total -= 10;
1430 update_total(bj);
1431 if (dbl_down) {
1432 bj->end_hand = true;
1433 finish_game(bj);
1436 else
1437 bj->end_hand = true;
1440 if (bj->end_hand) {
1441 done++;
1442 if(todo > 1) {
1443 if (done == 2) {
1444 temp = bj->player_total;
1445 bj->player_total = temp_var;
1446 temp_var = temp;
1447 finish_game(bj);
1448 rb->lcd_getstringsize(" Split 1 ", &w, &h);
1449 rb->lcd_putsxy(LCD_WIDTH/2-w/2, LCD_HEIGHT/2-3*h/2,
1450 " Split 1 ");
1451 rb->lcd_update_rect(LCD_WIDTH/2-w/2, LCD_HEIGHT/2-3*h/2,
1452 w,h);
1453 bj->current_bet /= 2;
1454 rb->lcd_update_rect(LCD_WIDTH/2-w/2, LCD_HEIGHT/2-3*h/2,
1455 w,h);
1456 rb->sleep(HZ*2);
1457 bj->player_total = temp_var;
1458 finish_game(bj);
1459 rb->lcd_getstringsize(" Split 2 ", &w, &h);
1460 rb->lcd_putsxy(LCD_WIDTH/2-w/2, LCD_HEIGHT/2-3*h/2,
1461 " Split 2 ");
1462 rb->lcd_update_rect(LCD_WIDTH/2-w/2, LCD_HEIGHT/2-3*h/2,
1463 w,h);
1464 rb->sleep(HZ*2);
1466 else {
1467 bj->end_hand = false;
1468 bj->split_status = 3;
1469 temp_var = bj->player_total;
1470 bj->player_total = bj->player_cards[1][0].value;
1471 update_total(bj);
1472 redraw_board(bj);
1473 player_x += 10;
1474 rb->lcd_update();
1477 else
1478 finish_game(bj);
1482 if (bj->player_money < 10) {
1483 rb->sleep(HZ);
1484 return BJ_LOSE;
1487 if (bj->end_hand) { /* If hand is over */
1488 if (play_again() != 0) /* User wants to quit */
1489 return BJ_END;
1490 else { /* User keeps playing */
1491 breakout = false;
1492 temp = bj->current_bet;
1493 bj->current_bet = 0;
1494 redraw_board(bj);
1495 rb->lcd_update();
1496 bj->current_bet = temp;
1497 if(dbl_down) {
1498 bj->current_bet /= 2;
1499 dbl_down = false;
1501 done = 0;
1502 todo = 1;
1503 blackjack_init(bj);
1504 blackjack_get_bet(bj);
1505 if (bj->current_bet == 0)
1506 return BJ_END;
1507 deal_init_cards(bj);
1508 blackjack_drawtable(bj);
1509 rb->lcd_update();
1513 /* Never reached */
1514 return PLUGIN_OK;
1517 /*****************************************************************************
1518 * plugin entry point.
1519 ******************************************************************************/
1520 enum plugin_status plugin_start(UNUSED_ATTR const void* parameter)
1522 struct game_context bj;
1523 bool exit = false;
1526 #if LCD_DEPTH > 1
1527 rb->lcd_set_backdrop(NULL);
1528 #endif
1530 /* load high scores */
1531 highscore_load(HIGH_SCORE,highest,NUM_SCORES);
1533 rb->lcd_setfont(FONT_SYSFIXED);
1535 while(!exit) {
1536 switch(blackjack(&bj)){
1537 case BJ_LOSE:
1538 rb->splash(HZ, "Not enough money to continue");
1539 /* fall through to BJ_END */
1541 case BJ_END:
1542 if(!bj.resume && bj.player_money > 10) {
1543 /* There is no level, so store -1 to blank column */
1544 int position = highscore_update(bj.player_money, -1, "",
1545 highest, NUM_SCORES);
1546 if (position == 0) {
1547 rb->splash(HZ*2, "New High Score");
1549 if (position != -1) {
1550 highscore_show(position, highest, NUM_SCORES, false);
1553 break;
1555 case BJ_USB:
1556 rb->lcd_setfont(FONT_UI);
1557 highscore_save(HIGH_SCORE,highest,NUM_SCORES);
1558 return PLUGIN_USB_CONNECTED;
1560 case BJ_QUIT:
1561 highscore_save(HIGH_SCORE,highest,NUM_SCORES);
1562 exit = true;
1563 break;
1565 default:
1566 break;
1570 rb->lcd_setfont(FONT_UI);
1571 return PLUGIN_OK;