Extract config file saving code to a function; Do not write the NUL character to...
[kugel-rb.git] / apps / plugins / blackjack.c
blob3a43a12bb2fb7394fe46c2bb97959e0dd1ceb1ae
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"
31 /* save files */
32 #define SCORE_FILE PLUGIN_GAMES_DIR "/blackjack.score"
33 #define SAVE_FILE PLUGIN_GAMES_DIR "/blackjack.save"
34 #define NUM_SCORES 5
36 /* final game return status */
37 enum {
38 BJ_LOSE,
39 BJ_QUIT_WITHOUT_SAVING,
40 BJ_QUIT,
41 BJ_USB,
42 BJ_END,
45 #if CONFIG_KEYPAD == RECORDER_PAD
46 #define BJACK_SELECT_NAME "PLAY"
47 #define BJACK_STAY_NAME "F1"
48 #define BJACK_QUIT_NAME "OFF"
49 #define BJACK_DOUBLE_NAME "F2"
50 #define BJACK_SELECT BUTTON_PLAY
51 #define BJACK_QUIT BUTTON_OFF
52 #define BJACK_MAX (BUTTON_ON|BUTTON_UP)
53 #define BJACK_MIN (BUTTON_ON|BUTTON_DOWN)
54 #define BJACK_STAY BUTTON_F1
55 #define BJACK_DOUBLEDOWN BUTTON_F2
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_QUIT_NAME "OFF"
65 #define BJACK_DOUBLE_NAME "UP"
66 #define BJACK_SELECT BUTTON_MENU
67 #define BJACK_QUIT BUTTON_OFF
68 #define BJACK_STAY BUTTON_RIGHT
69 #define BJACK_DOUBLEDOWN BUTTON_UP
70 #define BJACK_UP BUTTON_UP
71 #define BJACK_DOWN BUTTON_DOWN
72 #define BJACK_RIGHT BUTTON_RIGHT
73 #define BJACK_LEFT BUTTON_LEFT
75 #elif CONFIG_KEYPAD == IRIVER_H10_PAD
76 #define BJACK_SELECT_NAME "PLAY"
77 #define BJACK_STAY_NAME ">>|"
78 #define BJACK_QUIT_NAME "POWER"
79 #define BJACK_DOUBLE_NAME "|<<"
80 #define BJACK_SELECT BUTTON_PLAY
81 #define BJACK_QUIT BUTTON_POWER
82 #define BJACK_STAY BUTTON_FF
83 #define BJACK_DOUBLEDOWN BUTTON_REW
84 #define BJACK_UP BUTTON_SCROLL_UP
85 #define BJACK_DOWN BUTTON_SCROLL_DOWN
86 #define BJACK_RIGHT BUTTON_RIGHT
87 #define BJACK_LEFT BUTTON_LEFT
89 #elif (CONFIG_KEYPAD == IRIVER_H100_PAD) || \
90 (CONFIG_KEYPAD == IRIVER_H300_PAD)
91 #define BJACK_SELECT_NAME "ON"
92 #define BJACK_STAY_NAME "REC"
93 #define BJACK_QUIT_NAME "OFF"
94 #define BJACK_DOUBLE_NAME "SELECT"
95 #define BJACK_SELECT BUTTON_ON
96 #define BJACK_QUIT BUTTON_OFF
97 #define BJACK_STAY BUTTON_REC
98 #define BJACK_DOUBLEDOWN BUTTON_SELECT
99 #define BJACK_UP BUTTON_UP
100 #define BJACK_DOWN BUTTON_DOWN
101 #define BJACK_RIGHT BUTTON_RIGHT
102 #define BJACK_LEFT BUTTON_LEFT
104 #elif (CONFIG_KEYPAD == IPOD_4G_PAD) || \
105 (CONFIG_KEYPAD == IPOD_3G_PAD) || \
106 (CONFIG_KEYPAD == IPOD_1G2G_PAD)
107 #define BJACK_SELECT_NAME "SELECT"
108 #define BJACK_STAY_NAME "RIGHT"
109 #define BJACK_RESUME_NAME "PLAY"
110 #define BJACK_QUIT_NAME "MENU"
111 #define BJACK_DOUBLE_NAME "LEFT"
112 #define BJACK_SELECT BUTTON_SELECT
113 #define BJACK_QUIT BUTTON_MENU
114 #define BJACK_STAY BUTTON_RIGHT
115 #define BJACK_DOUBLEDOWN BUTTON_LEFT
116 #define BJACK_UP BUTTON_SCROLL_FWD
117 #define BJACK_DOWN BUTTON_SCROLL_BACK
118 #define BJACK_RIGHT BUTTON_RIGHT
119 #define BJACK_LEFT BUTTON_LEFT
121 #elif CONFIG_KEYPAD == IAUDIO_X5M5_PAD
122 #define BJACK_SELECT_NAME "SELECT"
123 #define BJACK_STAY_NAME "REC"
124 #define BJACK_QUIT_NAME "POWER"
125 #define BJACK_DOUBLE_NAME "PLAY"
126 #define BJACK_SELECT BUTTON_SELECT
127 #define BJACK_QUIT BUTTON_POWER
128 #define BJACK_MAX (BUTTON_PLAY|BUTTON_UP)
129 #define BJACK_MIN (BUTTON_PLAY|BUTTON_DOWN)
130 #define BJACK_STAY BUTTON_REC
131 #define BJACK_DOUBLEDOWN BUTTON_PLAY
132 #define BJACK_UP BUTTON_UP
133 #define BJACK_DOWN BUTTON_DOWN
134 #define BJACK_RIGHT BUTTON_RIGHT
135 #define BJACK_LEFT BUTTON_LEFT
137 #elif CONFIG_KEYPAD == IRIVER_IFP7XX_PAD
138 #define BJACK_SELECT_NAME "MODE"
139 #define BJACK_STAY_NAME "MODE"
140 #define BJACK_QUIT_NAME "PLAY"
141 #define BJACK_DOUBLE_NAME "SELECT"
142 #define BJACK_SELECT BUTTON_MODE
143 #define BJACK_QUIT BUTTON_PLAY
144 #define BJACK_MAX (BUTTON_EQ|BUTTON_UP)
145 #define BJACK_MIN (BUTTON_EQ|BUTTON_DOWN)
146 #define BJACK_STAY BUTTON_MODE
147 #define BJACK_DOUBLEDOWN BUTTON_SELECT
148 #define BJACK_UP BUTTON_UP
149 #define BJACK_DOWN BUTTON_DOWN
150 #define BJACK_RIGHT BUTTON_RIGHT
151 #define BJACK_LEFT BUTTON_LEFT
153 #elif CONFIG_KEYPAD == GIGABEAT_PAD
154 #define BJACK_SELECT_NAME "SELECT"
155 #define BJACK_STAY_NAME "VOL-"
156 #define BJACK_QUIT_NAME "POWER"
157 #define BJACK_DOUBLE_NAME "A"
158 #define BJACK_SELECT BUTTON_SELECT
159 #define BJACK_QUIT BUTTON_POWER
160 #define BJACK_MAX BUTTON_VOL_UP
161 #define BJACK_MIN BUTTON_VOL_DOWN
162 #define BJACK_STAY BUTTON_VOL_DOWN
163 #define BJACK_DOUBLEDOWN BUTTON_A
164 #define BJACK_UP BUTTON_UP
165 #define BJACK_DOWN BUTTON_DOWN
166 #define BJACK_RIGHT BUTTON_RIGHT
167 #define BJACK_LEFT BUTTON_LEFT
169 #elif CONFIG_KEYPAD == SANSA_E200_PAD
170 #define BJACK_SELECT_NAME "SELECT"
171 #define BJACK_STAY_NAME "RIGHT"
172 #define BJACK_QUIT_NAME "POWER"
173 #define BJACK_DOUBLE_NAME "LEFT"
174 #define BJACK_SELECT BUTTON_SELECT
175 #define BJACK_QUIT BUTTON_POWER
176 #define BJACK_MAX BUTTON_UP
177 #define BJACK_MIN BUTTON_DOWN
178 #define BJACK_STAY BUTTON_RIGHT
179 #define BJACK_DOUBLEDOWN BUTTON_LEFT
180 #define BJACK_UP BUTTON_SCROLL_FWD
181 #define BJACK_DOWN BUTTON_SCROLL_BACK
182 #define BJACK_RIGHT BUTTON_RIGHT
183 #define BJACK_LEFT BUTTON_LEFT
185 #elif CONFIG_KEYPAD == SANSA_FUZE_PAD
186 #define BJACK_SELECT_NAME "SELECT"
187 #define BJACK_STAY_NAME "RIGHT"
188 #define BJACK_QUIT_NAME "HOME"
189 #define BJACK_DOUBLE_NAME "LEFT"
190 #define BJACK_SELECT BUTTON_SELECT
191 #define BJACK_QUIT (BUTTON_HOME|BUTTON_REPEAT)
192 #define BJACK_MAX BUTTON_UP
193 #define BJACK_MIN BUTTON_DOWN
194 #define BJACK_STAY BUTTON_RIGHT
195 #define BJACK_DOUBLEDOWN BUTTON_LEFT
196 #define BJACK_UP BUTTON_SCROLL_FWD
197 #define BJACK_DOWN BUTTON_SCROLL_BACK
198 #define BJACK_RIGHT BUTTON_RIGHT
199 #define BJACK_LEFT BUTTON_LEFT
201 #elif CONFIG_KEYPAD == SANSA_C200_PAD
202 #define BJACK_SELECT_NAME "SELECT"
203 #define BJACK_STAY_NAME "RIGHT"
204 #define BJACK_QUIT_NAME "POWER"
205 #define BJACK_DOUBLE_NAME "LEFT"
206 #define BJACK_SELECT BUTTON_SELECT
207 #define BJACK_QUIT BUTTON_POWER
208 #define BJACK_MAX BUTTON_VOL_UP
209 #define BJACK_MIN BUTTON_VOL_DOWN
210 #define BJACK_STAY BUTTON_RIGHT
211 #define BJACK_DOUBLEDOWN BUTTON_LEFT
212 #define BJACK_UP BUTTON_UP
213 #define BJACK_DOWN BUTTON_DOWN
214 #define BJACK_RIGHT BUTTON_RIGHT
215 #define BJACK_LEFT BUTTON_LEFT
217 #elif CONFIG_KEYPAD == SANSA_CLIP_PAD
218 #define BJACK_SELECT_NAME "SELECT"
219 #define BJACK_STAY_NAME "RIGHT"
220 #define BJACK_QUIT_NAME "POWER"
221 #define BJACK_DOUBLE_NAME "LEFT"
222 #define BJACK_SELECT BUTTON_SELECT
223 #define BJACK_QUIT BUTTON_POWER
224 #define BJACK_MAX BUTTON_VOL_UP
225 #define BJACK_MIN BUTTON_VOL_DOWN
226 #define BJACK_STAY BUTTON_RIGHT
227 #define BJACK_DOUBLEDOWN BUTTON_LEFT
228 #define BJACK_UP BUTTON_UP
229 #define BJACK_DOWN BUTTON_DOWN
230 #define BJACK_RIGHT BUTTON_RIGHT
231 #define BJACK_LEFT BUTTON_LEFT
233 #elif CONFIG_KEYPAD == SANSA_M200_PAD
234 #define BJACK_SELECT_NAME "SELECT"
235 #define BJACK_STAY_NAME "RIGHT"
236 #define BJACK_QUIT_NAME "POWER"
237 #define BJACK_DOUBLE_NAME "LEFT"
238 #define BJACK_SELECT (BUTTON_SELECT | BUTTON_REL)
239 #define BJACK_QUIT BUTTON_POWER
240 #define BJACK_MAX BUTTON_VOL_UP
241 #define BJACK_MIN BUTTON_VOL_DOWN
242 #define BJACK_STAY BUTTON_RIGHT
243 #define BJACK_DOUBLEDOWN BUTTON_LEFT
244 #define BJACK_UP BUTTON_UP
245 #define BJACK_DOWN BUTTON_DOWN
246 #define BJACK_RIGHT BUTTON_RIGHT
247 #define BJACK_LEFT BUTTON_LEFT
249 #elif CONFIG_KEYPAD == TATUNG_TPJ1022_PAD
250 #define BJACK_SELECT_NAME "MAIN"
251 #define BJACK_STAY_NAME "MENU"
252 #define BJACK_QUIT_NAME "POWER"
253 #define BJACK_DOUBLE_NAME "DOWN"
254 #define BJACK_SELECT BUTTON_MAIN
255 #define BJACK_QUIT BUTTON_POWER
256 #define BJACK_MAX (BUTTON_REC|BUTTON_UP)
257 #define BJACK_MIN (BUTTON_REC|BUTTON_DOWN)
258 #define BJACK_STAY BUTTON_MENU
259 #define BJACK_DOUBLEDOWN BUTTON_DOWN
260 #define BJACK_UP BUTTON_UP
261 #define BJACK_DOWN BUTTON_DOWN
262 #define BJACK_RIGHT BUTTON_RIGHT
263 #define BJACK_LEFT BUTTON_LEFT
265 #elif CONFIG_KEYPAD == GIGABEAT_S_PAD
266 #define BJACK_SELECT_NAME "PLAY"
267 #define BJACK_STAY_NAME "VOL-"
268 #define BJACK_QUIT_NAME "BACK"
269 #define BJACK_DOUBLE_NAME "SELECT"
270 #define BJACK_SELECT BUTTON_PLAY
271 #define BJACK_QUIT BUTTON_BACK
272 #define BJACK_MAX BUTTON_VOL_UP
273 #define BJACK_MIN BUTTON_VOL_DOWN
274 #define BJACK_STAY BUTTON_VOL_DOWN
275 #define BJACK_DOUBLEDOWN BUTTON_SELECT
276 #define BJACK_UP BUTTON_UP
277 #define BJACK_DOWN BUTTON_DOWN
278 #define BJACK_RIGHT BUTTON_RIGHT
279 #define BJACK_LEFT BUTTON_LEFT
281 #elif CONFIG_KEYPAD == MROBE100_PAD
282 #define BJACK_SELECT_NAME "SELECT"
283 #define BJACK_STAY_NAME "DISPLAY"
284 #define BJACK_QUIT_NAME "POWER"
285 #define BJACK_DOUBLE_NAME "DOWN"
286 #define BJACK_SELECT BUTTON_SELECT
287 #define BJACK_QUIT BUTTON_POWER
288 #define BJACK_MAX BUTTON_MENU
289 #define BJACK_MIN BUTTON_DISPLAY
290 #define BJACK_STAY BUTTON_DISPLAY
291 #define BJACK_DOUBLEDOWN BUTTON_DOWN
292 #define BJACK_UP BUTTON_UP
293 #define BJACK_DOWN BUTTON_DOWN
294 #define BJACK_RIGHT BUTTON_RIGHT
295 #define BJACK_LEFT BUTTON_LEFT
297 #elif CONFIG_KEYPAD == IAUDIO_M3_PAD
298 #define BJACK_SELECT_NAME "RC","PLAY"
299 #define BJACK_STAY_NAME "RC", ">>|"
300 #define BJACK_QUIT_NAME "RC_REC"
301 #define BJACK_DOUBLE_NAME "RC_REW"
302 #define BJACK_SELECT BUTTON_RC_PLAY
303 #define BJACK_QUIT BUTTON_RC_REC
304 #define BJACK_STAY BUTTON_RC_FF
305 #define BJACK_DOUBLEDOWN BUTTON_RC_REW
306 #define BJACK_UP BUTTON_RC_VOL_UP
307 #define BJACK_DOWN BUTTON_RC_VOL_DOWN
308 #define BJACK_RIGHT BUTTON_RC_FF
309 #define BJACK_LEFT BUTTON_RC_REW
311 #elif CONFIG_KEYPAD == COWON_D2_PAD
312 #define BJACK_QUIT_NAME "POWER"
313 #define BJACK_DOUBLE_NAME "-"
314 #define BJACK_QUIT BUTTON_POWER
315 #define BJACK_DOUBLEDOWN BUTTON_MINUS
317 #elif CONFIG_KEYPAD == CREATIVEZVM_PAD
318 #define BJACK_SELECT_NAME "SELECT"
319 #define BJACK_STAY_NAME "PLAY"
320 #define BJACK_QUIT_NAME "POWER"
321 #define BJACK_DOUBLE_NAME "CUSTOM"
322 #define BJACK_SELECT BUTTON_SELECT
323 #define BJACK_QUIT BUTTON_POWER
324 #define BJACK_STAY BUTTON_PLAY
325 #define BJACK_MAX (BUTTON_CUSTOM|BUTTON_UP)
326 #define BJACK_MIN (BUTTON_CUSTOM|BUTTON_DOWN)
327 #define BJACK_DOUBLEDOWN BUTTON_CUSTOM
328 #define BJACK_UP BUTTON_UP
329 #define BJACK_DOWN BUTTON_DOWN
330 #define BJACK_RIGHT BUTTON_RIGHT
331 #define BJACK_LEFT BUTTON_LEFT
333 #elif CONFIG_KEYPAD == PHILIPS_HDD1630_PAD
334 #define BJACK_SELECT_NAME "SELECT"
335 #define BJACK_STAY_NAME "VOL-"
336 #define BJACK_QUIT_NAME "POWER"
337 #define BJACK_DOUBLE_NAME "MENU"
338 #define BJACK_SELECT BUTTON_SELECT
339 #define BJACK_QUIT BUTTON_POWER
340 #define BJACK_MAX BUTTON_VOL_UP
341 #define BJACK_MIN BUTTON_VOL_DOWN
342 #define BJACK_STAY BUTTON_VOL_DOWN
343 #define BJACK_DOUBLEDOWN BUTTON_MENU
344 #define BJACK_UP BUTTON_UP
345 #define BJACK_DOWN BUTTON_DOWN
346 #define BJACK_RIGHT BUTTON_RIGHT
347 #define BJACK_LEFT BUTTON_LEFT
349 #elif CONFIG_KEYPAD == PHILIPS_HDD6330_PAD
350 #define BJACK_SELECT_NAME "PLAY"
351 #define BJACK_STAY_NAME "VOL-"
352 #define BJACK_QUIT_NAME "POWER"
353 #define BJACK_DOUBLE_NAME "MENU"
354 #define BJACK_SELECT BUTTON_PLAY
355 #define BJACK_QUIT BUTTON_POWER
356 #define BJACK_MAX BUTTON_VOL_UP
357 #define BJACK_MIN BUTTON_VOL_DOWN
358 #define BJACK_STAY BUTTON_VOL_DOWN
359 #define BJACK_DOUBLEDOWN BUTTON_MENU
360 #define BJACK_UP BUTTON_UP
361 #define BJACK_DOWN BUTTON_DOWN
362 #define BJACK_RIGHT BUTTON_RIGHT
363 #define BJACK_LEFT BUTTON_LEFT
365 #elif CONFIG_KEYPAD == PHILIPS_SA9200_PAD
366 #define BJACK_SELECT_NAME "MENU"
367 #define BJACK_STAY_NAME "VOL-"
368 #define BJACK_QUIT_NAME "POWER"
369 #define BJACK_DOUBLE_NAME "PLAY"
370 #define BJACK_SELECT BUTTON_MENU
371 #define BJACK_QUIT BUTTON_POWER
372 #define BJACK_MAX BUTTON_VOL_UP
373 #define BJACK_MIN BUTTON_VOL_DOWN
374 #define BJACK_STAY BUTTON_VOL_DOWN
375 #define BJACK_DOUBLEDOWN BUTTON_PLAY
376 #define BJACK_UP BUTTON_UP
377 #define BJACK_DOWN BUTTON_DOWN
378 #define BJACK_RIGHT BUTTON_NEXT
379 #define BJACK_LEFT BUTTON_PREV
381 #elif CONFIG_KEYPAD == ONDAVX747_PAD
382 #define BJACK_QUIT_NAME "POWER"
383 #define BJACK_DOUBLE_NAME "Vol-"
384 #define BJACK_QUIT BUTTON_POWER
385 #define BJACK_DOUBLEDOWN BUTTON_VOL_DOWN
387 #elif CONFIG_KEYPAD == ONDAVX777_PAD
388 #define BJACK_QUIT_NAME "POWER"
389 #define BJACK_QUIT BUTTON_POWER
391 #elif CONFIG_KEYPAD == MROBE500_PAD
392 #define BJACK_QUIT_NAME "POWER"
393 #define BJACK_QUIT BUTTON_POWER
395 #elif CONFIG_KEYPAD == SAMSUNG_YH_PAD
396 #define BJACK_SELECT_NAME "PLAY"
397 #define BJACK_STAY_NAME "RECORD"
398 #define BJACK_QUIT_NAME "REW"
399 #define BJACK_DOUBLE_NAME "FFWD"
400 #define BJACK_SELECT BUTTON_PLAY
401 #define BJACK_QUIT BUTTON_REW
402 #define BJACK_STAY BUTTON_REC
403 #define BJACK_DOUBLEDOWN BUTTON_FFWD
404 #define BJACK_UP BUTTON_UP
405 #define BJACK_DOWN BUTTON_DOWN
406 #define BJACK_RIGHT BUTTON_RIGHT
407 #define BJACK_LEFT BUTTON_LEFT
409 #elif CONFIG_KEYPAD == PBELL_VIBE500_PAD
410 #define BJACK_SELECT_NAME "OK"
411 #define BJACK_STAY_NAME "CANCEL"
412 #define BJACK_QUIT_NAME "REC"
413 #define BJACK_DOUBLE_NAME "MENU"
414 #define BJACK_SELECT BUTTON_OK
415 #define BJACK_QUIT BUTTON_REC
416 #define BJACK_STAY BUTTON_CANCEL
417 #define BJACK_DOUBLEDOWN BUTTON_MENU
418 #define BJACK_UP BUTTON_UP
419 #define BJACK_DOWN BUTTON_DOWN
420 #define BJACK_RIGHT BUTTON_NEXT
421 #define BJACK_LEFT BUTTON_PREV
423 #elif CONFIG_KEYPAD == MPIO_HD200_PAD
424 #define BJACK_SELECT_NAME "FUNC"
425 #define BJACK_STAY_NAME "VOL +"
426 #define BJACK_RESUME_NAME "PLAY"
427 #define BJACK_QUIT_NAME "REC+PLAY"
428 #define BJACK_DOUBLE_NAME "VOL -"
429 #define BJACK_SELECT BUTTON_FUNC
430 #define BJACK_QUIT (BUTTON_REC|BUTTON_PLAY)
431 #define BJACK_STAY BUTTON_VOL_UP
432 #define BJACK_DOUBLEDOWN BUTTON_VOL_DOWN
433 #define BJACK_UP BUTTON_REW
434 #define BJACK_DOWN BUTTON_FF
435 #define BJACK_RIGHT BUTTON_VOL_UP
436 #define BJACK_LEFT BUTTON_VOL_DOWN
438 #elif CONFIG_KEYPAD == MPIO_HD300_PAD
439 #define BJACK_SELECT_NAME "FUNC"
440 #define BJACK_STAY_NAME "VOL +"
441 #define BJACK_RESUME_NAME "PLAY"
442 #define BJACK_QUIT_NAME "REC+PLAY"
443 #define BJACK_DOUBLE_NAME "VOL -"
444 #define BJACK_SELECT BUTTON_ENTER
445 #define BJACK_QUIT (BUTTON_REC|BUTTON_REPEAT)
446 #define BJACK_STAY BUTTON_PLAY
447 #define BJACK_DOUBLEDOWN BUTTON_REC
448 #define BJACK_UP BUTTON_UP
449 #define BJACK_DOWN BUTTON_DOWN
450 #define BJACK_RIGHT BUTTON_FF
451 #define BJACK_LEFT BUTTON_REW
453 #else
454 #error No keymap defined!
455 #endif
457 #ifdef HAVE_TOUCHSCREEN
458 #ifndef BJACK_DOUBLEDOWN
459 #define BJACK_DOUBLEDOWN BUTTON_MIDLEFT
460 #define BJACK_DOUBLE_NAME "BUTTON_MIDLEFT"
461 #endif
462 #ifndef BJACK_SELECT
463 #define BJACK_SELECT BUTTON_CENTER
464 #define BJACK_SELECT_NAME "BUTTON_CENTER"
465 #endif
466 #ifndef BJACK_MAX
467 #define BJACK_MAX BUTTON_TOPRIGHT
468 #endif
469 #ifndef BJACK_MIN
470 #define BJACK_MIN BUTTON_TOPLEFT
471 #endif
472 #ifndef BJACK_STAY
473 #define BJACK_STAY BUTTON_BOTTOMLEFT
474 #define BJACK_STAY_NAME "BUTTON_BOTTOMLEFT"
475 #endif
476 #ifndef BJACK_UP
477 #define BJACK_UP BUTTON_TOPMIDDLE
478 #endif
479 #ifndef BJACK_DOWN
480 #define BJACK_DOWN BUTTON_BOTTOMMIDDLE
481 #endif
482 #ifndef BJACK_RIGHT
483 #define BJACK_RIGHT BUTTON_MIDRIGHT
484 #endif
485 #ifndef BJACK_LEFT
486 #define BJACK_LEFT BUTTON_MIDLEFT
487 #endif
489 #endif
491 #ifdef HAVE_LCD_COLOR
492 #define BG_COLOR LCD_RGBPACK(0,157,0)
493 #define FG_COLOR LCD_WHITE
494 #elif LCD_DEPTH > 1
495 #define BG_COLOR LCD_WHITE
496 #define FG_COLOR LCD_BLACK
497 #endif
499 #define CARD_WIDTH BMPWIDTH_card_back
500 #define CARD_HEIGHT BMPHEIGHT_card_back
502 /* This is the max amount of cards onscreen before condensing */
503 #define MAX_CARDS LCD_WIDTH/(CARD_WIDTH+4)
505 extern const fb_data card_deck[];
506 extern const fb_data card_back[];
508 #define NEXT_CARD bj->player_cards[done][bj->num_player_cards[done]]
510 /* dealer and player card positions */
511 unsigned int dealer_x, dealer_y, player_x, player_y;
513 typedef struct card {
514 unsigned int value; /* Card's value in Blackjack */
515 unsigned int num; /* Value on card face 0-12 (0=Ace, 1=2, 11=Q) */
516 unsigned int suit; /* 0:Spades, 1:Hearts, 2: Clubs; 3: Diamonds */
517 bool is_soft_ace;
518 } card;
520 typedef struct game_context {
521 struct card player_cards[2][22]; /* 22 Cards means the deal was all aces */
522 struct card dealer_cards[22]; /* That is the worst-case scenario */
523 unsigned int player_total;
524 unsigned int dealer_total;
525 signed int player_money;
526 unsigned int num_player_cards[2];
527 unsigned int num_dealer_cards;
528 unsigned int current_bet;
529 unsigned int split_status; /* 0 = split hasn't been asked, *
530 * 1 = split did not occur *
531 * 2 = split occurred *
532 * 3 = split occurred and 1st hand done */
533 bool is_blackjack;
534 bool end_hand;
535 bool asked_insurance;
536 } game_context;
538 static bool resume = false;
539 static bool resume_file = false;
540 static struct highscore highscores[NUM_SCORES];
542 /*****************************************************************************
543 * blackjack_init() initializes blackjack data structures.
544 ******************************************************************************/
545 static void blackjack_init(struct game_context* bj) {
546 /* seed the rand generator */
547 rb->srand(*rb->current_tick);
549 /* reset card positions */
550 dealer_x = 4;
551 dealer_y = LCD_HEIGHT/4 - CARD_HEIGHT/2;
552 player_x = 4;
553 player_y = LCD_HEIGHT - LCD_HEIGHT/4 - CARD_HEIGHT/2;
555 /* check for resumed game */
556 if(resume) return;
558 /* reset scoring */
559 bj->player_total = 0;
560 bj->dealer_total = 0;
561 bj->num_player_cards[0] = 2;
562 bj->num_player_cards[1] = 0;
563 bj->num_dealer_cards = 2;
564 bj->end_hand = false;
565 bj->split_status = 0;
566 bj->is_blackjack = false;
567 bj->asked_insurance = false;
570 /*****************************************************************************
571 * blackjack_drawtable() draws the table and some text.
572 ******************************************************************************/
573 static void blackjack_drawtable(struct game_context* bj) {
574 unsigned int w, h, y_loc;
575 char str[10];
577 #if LCD_HEIGHT <= 64
578 rb->lcd_getstringsize("Bet", &w, &h);
579 rb->lcd_putsxy(LCD_WIDTH - w, 2*h + 1, "Bet");
580 rb->snprintf(str, 9, "$%d", bj->current_bet);
581 rb->lcd_getstringsize(str, &w, &h);
582 rb->lcd_putsxy(LCD_WIDTH - w, 3*h + 1, str);
583 y_loc = LCD_HEIGHT/2;
584 #else
585 rb->lcd_getstringsize("Bet", &w, &h);
586 rb->lcd_putsxy(LCD_WIDTH - w, 5*h / 2, "Bet");
587 rb->snprintf(str, 9, "$%d", bj->current_bet);
588 rb->lcd_getstringsize(str, &w, &h);
589 rb->lcd_putsxy(LCD_WIDTH - w, 7*h / 2, str);
590 rb->lcd_hline(0, LCD_WIDTH, LCD_HEIGHT/2);
591 y_loc = LCD_HEIGHT/2 + h;
592 #endif
594 rb->lcd_putsxy(0,0, "Dealer");
595 rb->lcd_getstringsize("Player", &w, &h);
596 rb->lcd_putsxy(0, y_loc, "Player");
597 rb->lcd_getstringsize("Total", &w, &h);
598 rb->lcd_putsxy(LCD_WIDTH - w, y_loc, "Total");
599 rb->lcd_getstringsize("Money", &w, &h);
600 rb->lcd_putsxy(LCD_WIDTH - w, 0, "Money");
601 rb->snprintf(str, 9, "$%d", bj->player_money - bj->current_bet);
602 rb->lcd_getstringsize(str, &w, &h);
603 rb->lcd_putsxy(LCD_WIDTH - w, h + 1, str);
604 rb->snprintf(str, 3, "%d", bj->player_total);
605 rb->lcd_getstringsize(str, &w, &h);
606 rb->lcd_putsxy(LCD_WIDTH - w, y_loc + h, str);
609 /*****************************************************************************
610 * find_value() is passed a card and returns its blackjack value.
611 ******************************************************************************/
612 static unsigned int find_value(unsigned int number) {
613 unsigned int thisValue;
614 if (number == 0)
615 thisValue = 11; /* Aces get a value of 11 at first */
616 else if (number < 10)
617 thisValue = number + 1;
618 else
619 thisValue = 10; /* Anything 10 or higher gets a value of 10 */
621 return thisValue;
624 /*****************************************************************************
625 * draw_card() draws a card to the screen.
626 ******************************************************************************/
627 static void draw_card(struct card temp_card, bool shown,
628 unsigned int x, unsigned int y) {
629 if(shown)
630 rb->lcd_bitmap_part(card_deck, CARD_WIDTH*temp_card.num,
631 CARD_HEIGHT*temp_card.suit,
632 STRIDE( SCREEN_MAIN, BMPWIDTH_card_deck,
633 BMPHEIGHT_card_deck),
634 x+1, y+1, CARD_WIDTH, CARD_HEIGHT);
635 else
636 rb->lcd_bitmap(card_back, x+1, y+1,CARD_WIDTH, CARD_HEIGHT);
637 #if LCD_DEPTH > 1
638 rb->lcd_set_foreground(LCD_BLACK);
639 #endif
641 /* Print outlines */
642 #if CARD_WIDTH >= 26
643 rb->lcd_hline(x+2, x+CARD_WIDTH-1, y);
644 rb->lcd_hline(x+2, x+CARD_WIDTH-1, y+CARD_HEIGHT+1);
645 rb->lcd_vline(x, y+2, y+CARD_HEIGHT-3);
646 rb->lcd_vline(x+CARD_WIDTH+1, y+2, y+CARD_HEIGHT-1);
647 rb->lcd_drawpixel(x+1, y+1);
648 rb->lcd_drawpixel(x+1, y+CARD_HEIGHT);
649 rb->lcd_drawpixel(x+CARD_WIDTH, y+1);
650 rb->lcd_drawpixel(x+CARD_WIDTH, y+CARD_HEIGHT);
651 #else
652 rb->lcd_hline(x+1, x+CARD_WIDTH, y);
653 rb->lcd_hline(x+1, x+CARD_WIDTH, y+CARD_HEIGHT+1);
654 rb->lcd_vline(x, y+1, y+CARD_HEIGHT);
655 rb->lcd_vline(x+CARD_WIDTH+1, y+1, y+CARD_HEIGHT);
656 #endif
658 #if LCD_DEPTH > 1
659 rb->lcd_set_foreground(FG_COLOR);
660 #endif
663 /*****************************************************************************
664 * new_card() initializes a new card and gives it values.
665 ******************************************************************************/
666 static struct card new_card(void) {
667 struct card new_card;
668 new_card.suit = rb->rand()%4; /* Random number 0-3 */
669 new_card.num = rb->rand()%13; /* Random number 0-12 */
670 new_card.value = find_value(new_card.num);
671 new_card.is_soft_ace = (new_card.num == 0);
672 return new_card;
675 /*****************************************************************************
676 * deal_init_card() deals and draws to the screen the player's and dealer's
677 * initial cards.
678 ******************************************************************************/
679 static void deal_init_cards(struct game_context* bj) {
680 bj->dealer_cards[0] = new_card();
681 bj->dealer_total += bj->dealer_cards[0].value;
683 draw_card(bj->dealer_cards[0], false, dealer_x, dealer_y);
685 bj->dealer_cards[1] = new_card();
686 bj->dealer_total += bj->dealer_cards[1].value;
687 draw_card(bj->dealer_cards[1], true, dealer_x + CARD_WIDTH + 4, dealer_y);
689 bj->player_cards[0][0] = new_card();
690 bj->player_total += bj->player_cards[0][0].value;
691 draw_card(bj->player_cards[0][0], true, player_x, player_y);
692 player_x += CARD_WIDTH + 4;
694 bj->player_cards[0][1] = new_card();
695 bj->player_total += bj->player_cards[0][1].value;
696 draw_card(bj->player_cards[0][1], true, player_x, player_y);
697 player_x += CARD_WIDTH + 4;
700 /*****************************************************************************
701 * redraw_board() redraws all the cards and the board
702 ******************************************************************************/
703 static void redraw_board(struct game_context* bj) {
704 unsigned int i, n, upper_bound;
705 rb->lcd_clear_display();
707 blackjack_drawtable(bj);
708 player_x = 4;
709 dealer_x = 4;
710 upper_bound = bj->split_status > 1 ? 2 : 1;
712 for (i = 0; i < bj->num_dealer_cards; i++) {
713 if (!bj->end_hand) {
714 draw_card(bj->dealer_cards[0], false, dealer_x, dealer_y);
716 /* increment i so the dealer's first card isn't displayed */
717 i++;
718 dealer_x += CARD_WIDTH + 4;
720 draw_card(bj->dealer_cards[i], true, dealer_x, dealer_y);
722 if (bj->num_dealer_cards > MAX_CARDS-1)
723 dealer_x += 10;
724 else
725 dealer_x += CARD_WIDTH + 4;
728 for (n = 0; n < upper_bound; n++) {
729 for (i = 0; i < bj->num_player_cards[n]; i++) {
730 draw_card(bj->player_cards[n][i], true, player_x, player_y);
731 if (bj->split_status>1 || bj->num_player_cards[n]>MAX_CARDS)
732 player_x += 10;
733 else
734 player_x += CARD_WIDTH + 4;
736 if (bj->split_status > 1)
737 player_x = LCD_WIDTH/2 + 4;
741 /*****************************************************************************
742 * update_total updates the player's total
743 ******************************************************************************/
744 static void update_total(struct game_context* bj) {
745 char total[3];
746 unsigned int w, h;
747 rb->snprintf(total, 3, "%d", bj->player_total);
748 rb->lcd_getstringsize(total, &w, &h);
749 #if LCD_HEIGHT > 64
750 h *= 2;
751 #endif
752 rb->lcd_putsxy(LCD_WIDTH - w, LCD_HEIGHT/2 + h, total);
753 rb->lcd_update_rect(LCD_WIDTH - w, LCD_HEIGHT/2 + h, w, h);
757 /*****************************************************************************
758 * check_for_aces() is passed an array of cards and returns where an ace is
759 * located. Otherwise, returns -1.
760 ******************************************************************************/
761 static signed int check_for_aces(struct card temp_cards[], unsigned int size) {
762 unsigned int i;
763 for(i = 0; i < size; i++) {
764 if (temp_cards[i].is_soft_ace)
765 return i;
767 return -1;
770 /*****************************************************************************
771 * check_totals() compares player and dealer totals.
772 * 0: bust 1: loss, 2: push, 3: win, 4: blackjack, 5: something's not right...
773 ******************************************************************************/
774 static unsigned int check_totals(struct game_context* bj) {
775 unsigned int temp;
776 if (bj->player_total > 21)
777 temp = 0;
778 else if (bj->player_total == 21 && bj->is_blackjack) {
779 if (bj->dealer_total == 21 && bj->num_dealer_cards == 2)
780 temp = 2;
781 else
782 temp = 4;
784 else if (bj->player_total == bj->dealer_total)
785 temp = 2;
786 else if (bj->dealer_total > 21 && bj->player_total < 22)
787 temp = 3;
788 else if (bj->dealer_total > bj->player_total)
789 temp = 1;
790 else if (bj->player_total > bj->dealer_total)
791 temp = 3;
792 else
793 temp = 5;
795 return temp;
798 /*****************************************************************************
799 * finish_dealer() draws cards for the dealer until he has 17 or more.
800 ******************************************************************************/
801 static void finish_dealer(struct game_context* bj) {
802 signed int temp = 0;
804 if (bj->dealer_total > 16 && bj->dealer_total < 22)
805 return;
807 while (bj->dealer_total < 17) {
808 bj->dealer_cards[bj->num_dealer_cards] = new_card();
809 bj->dealer_total += bj->dealer_cards[bj->num_dealer_cards].value;
810 bj->num_dealer_cards++;
813 while (bj->dealer_total > 21) {
814 temp = check_for_aces(bj->dealer_cards, bj->num_dealer_cards);
815 if(temp != -1) {
816 bj->dealer_cards[temp].is_soft_ace = false;
817 bj->dealer_total -= 10;
819 else
820 return;
824 /*****************************************************************************
825 * finish_game() completes the game once player's turn is over.
826 ******************************************************************************/
827 static void finish_game(struct game_context* bj) {
828 unsigned int rValue, w, h;
829 char str[19];
831 do {
832 finish_dealer(bj);
833 } while (bj->dealer_total < 17);
835 redraw_board(bj);
836 rValue = check_totals(bj);
838 if (rValue == 0) {
839 rb->snprintf(str, sizeof(str), " Bust! ");
840 bj->player_money -= bj->current_bet;
842 else if (rValue == 1) {
843 rb->snprintf(str, sizeof(str), " Sorry, you lost. ");
844 bj->player_money -= bj->current_bet;
846 else if (rValue == 2) {
847 rb->snprintf(str, sizeof(str), " Push ");
849 else if (rValue == 3) {
850 rb->snprintf(str, sizeof(str), " You won! ");
851 bj->player_money+= bj->current_bet;
853 else {
854 rb->snprintf(str, sizeof(str), " Blackjack! ");
855 bj->player_money += bj->current_bet * 3 / 2;
857 rb->lcd_getstringsize(str, &w, &h);
859 #if LCD_HEIGHT <= 64
860 rb->lcd_set_drawmode(DRMODE_BG+DRMODE_INVERSEVID);
861 rb->lcd_fillrect(0, LCD_HEIGHT/2, LCD_WIDTH, LCD_HEIGHT/2);
862 rb->lcd_set_drawmode(DRMODE_SOLID);
863 rb->lcd_putsxy(LCD_WIDTH/2 - w/2, LCD_HEIGHT/2 + h, str);
864 rb->snprintf(str, 12, "You have %d", bj->player_total);
865 rb->lcd_getstringsize(str, &w, &h);
866 rb->lcd_putsxy(LCD_WIDTH/2 - w/2, LCD_HEIGHT/2, str);
867 #else
868 rb->lcd_putsxy(LCD_WIDTH/2 - w/2, LCD_HEIGHT/2 - h/2, str);
869 #endif
870 rb->lcd_update();
873 /*****************************************************************************
874 * blackjack_loadgame() loads the saved game and returns load success.
875 ******************************************************************************/
876 static bool blackjack_loadgame(struct game_context* bj) {
877 signed int fd;
878 bool loaded = false;
880 /* open game file */
881 fd = rb->open(SAVE_FILE, O_RDONLY);
882 if(fd < 0) return false;
884 /* read in saved game */
885 if(rb->read(fd, bj, sizeof(struct game_context))
886 == (long)sizeof(struct game_context))
888 loaded = true;
891 rb->close(fd);
893 return loaded;
896 /*****************************************************************************
897 * blackjack_savegame() saves the current game state.
898 ******************************************************************************/
899 static void blackjack_savegame(struct game_context* bj) {
900 int fd;
902 if(!resume)
903 return;
904 /* write out the game state to the save file */
905 fd = rb->open(SAVE_FILE, O_WRONLY|O_CREAT, 0666);
906 if(fd < 0)
907 return;
908 rb->write(fd, bj, sizeof(struct game_context));
909 rb->close(fd);
912 /*****************************************************************************
913 * blackjack_get_yes_no() gets a yes/no answer from the user
914 ******************************************************************************/
915 static unsigned int blackjack_get_yes_no(char message[20]) {
916 int button;
917 unsigned int w, h, b, choice = 0;
918 bool breakout = false;
919 char message_yes[24], message_no[24];
921 rb->strcpy(message_yes, message);
922 rb->strcpy(message_no, message);
923 rb->strcat(message_yes, " Yes");
924 rb->strcat(message_no, " No");
925 rb->lcd_getstringsize(message_yes, &w, &h);
926 const char *stg[] = {message_yes, message_no};
928 #if LCD_HEIGHT <= 64
929 b = 2*h+1;
930 #else
931 b = h-1;
932 #endif
934 #ifdef HAVE_LCD_COLOR
935 rb->lcd_fillrect(LCD_WIDTH/2 - w/2, LCD_HEIGHT/2 + b, w+1, h+3);
936 rb->lcd_set_foreground(LCD_BLACK);
937 rb->lcd_set_background(LCD_WHITE);
938 #else
939 rb->lcd_set_drawmode(DRMODE_BG+DRMODE_INVERSEVID);
940 rb->lcd_fillrect(LCD_WIDTH/2 - w/2, LCD_HEIGHT/2 + b, w+1, h+3);
941 rb->lcd_set_drawmode(DRMODE_SOLID);
942 #endif
943 rb->lcd_drawrect(LCD_WIDTH/2 - w/2 - 1, LCD_HEIGHT/2 + b - 1, w+3, h+4);
945 while(!breakout) {
946 rb->lcd_putsxy(LCD_WIDTH/2 - w/2, LCD_HEIGHT/2 + b +1, stg[choice]);
947 rb->lcd_update_rect(LCD_WIDTH/2 - w/2 - 1, LCD_HEIGHT/2 + b -1,
948 w+3, h+4);
949 button = rb->button_get(true);
951 switch(button) {
952 case BJACK_LEFT:
953 case (BJACK_LEFT|BUTTON_REPEAT):
954 case BJACK_RIGHT:
955 case (BJACK_RIGHT|BUTTON_REPEAT):
956 choice ^= 1;
957 break;
958 case BJACK_SELECT: breakout = true;
959 break;
960 case BJACK_QUIT: breakout = true;
961 choice = 1;
962 break;
966 #if LCD_DEPTH > 1
967 rb->lcd_set_foreground(FG_COLOR);
968 rb->lcd_set_background(BG_COLOR);
969 #endif
970 return choice;
973 /*****************************************************************************
974 * blackjack_get_amount() gets an amount from the player to be used
975 ******************************************************************************/
976 static signed int blackjack_get_amount(char message[20], signed int lower_limit,
977 signed int upper_limit,
978 signed int start) {
979 int button;
980 bool breakout = false, changed = false;
981 unsigned int w, h;
982 signed int amount;
984 rb->lcd_getstringsize("A", &w, &h); /* find the size of one character */
986 if (start > upper_limit)
987 amount = upper_limit;
988 else if (start < lower_limit)
989 amount = lower_limit;
990 else
991 amount = start;
993 #if LCD_DEPTH > 1
994 rb->lcd_set_background(LCD_WHITE);
995 rb->lcd_set_foreground(LCD_BLACK);
996 #endif
998 #if LCD_HEIGHT <= 64
999 rb->lcd_clear_display();
1000 rb->lcd_puts(0, 1, message);
1001 rb->lcd_putsf(0, 2, "$%d", amount);
1002 rb->lcd_puts(0, 3, "RIGHT: +1");
1003 rb->lcd_puts(0, 4, "LEFT: -1");
1004 rb->lcd_puts(0, 5, "UP: +10");
1005 rb->lcd_puts(0, 6, "DOWN: -10");
1006 rb->lcd_update();
1007 #else
1008 rb->lcd_set_drawmode(DRMODE_BG+DRMODE_INVERSEVID);
1009 rb->lcd_fillrect(LCD_WIDTH/2 - 9*w - 1, LCD_HEIGHT/2 - 4*h - 3,
1010 37*w / 2, 8*h -3);
1011 rb->lcd_set_drawmode(DRMODE_SOLID);
1012 rb->lcd_drawrect(LCD_WIDTH/2 - 9*w - 1, LCD_HEIGHT/2 - 4*h - 3,
1013 37*w / 2, 8*h -3);
1014 rb->lcd_putsxy(LCD_WIDTH/2 - 9*w, LCD_HEIGHT/2 - 4*h - 1, message);
1015 rb->lcd_putsxyf(LCD_WIDTH/2 - 9*w, LCD_HEIGHT/2 - 3*h, "$%d", amount);
1016 #if (CONFIG_KEYPAD == IPOD_4G_PAD) || \
1017 (CONFIG_KEYPAD == IPOD_3G_PAD) || \
1018 (CONFIG_KEYPAD == IPOD_1G2G_PAD) || \
1019 (CONFIG_KEYPAD == SANSA_E200_PAD) || \
1020 (CONFIG_KEYPAD == SANSA_FUZE_PAD)
1021 rb->lcd_putsxy(LCD_WIDTH/2 - 9*w, LCD_HEIGHT/2 - h-2, " >>|: +1");
1022 rb->lcd_putsxy(LCD_WIDTH/2 - 9*w, LCD_HEIGHT/2 - 1, " |<<: -1");
1023 rb->lcd_putsxy(LCD_WIDTH/2 - 9*w, LCD_HEIGHT/2 + h, "SCROLL+: +10");
1024 rb->lcd_putsxy(LCD_WIDTH/2 - 9*w, LCD_HEIGHT/2 + 2*h + 1, "SCROLL-: -10");
1025 #elif CONFIG_KEYPAD == IRIVER_H10_PAD
1026 rb->lcd_putsxy(LCD_WIDTH/2 - 9*w, LCD_HEIGHT/2 - h-2, "RIGHT: +1");
1027 rb->lcd_putsxy(LCD_WIDTH/2 - 9*w, LCD_HEIGHT/2 - 1, "LEFT: -1");
1028 rb->lcd_putsxy(LCD_WIDTH/2 - 9*w, LCD_HEIGHT/2 + h, "SCROLL+: +10");
1029 rb->lcd_putsxy(LCD_WIDTH/2 - 9*w, LCD_HEIGHT/2 + 2*h + 1, "SCROLL-: -10");
1030 #else
1031 rb->lcd_putsxy(LCD_WIDTH/2 - 9*w, LCD_HEIGHT/2 - h-2, "RIGHT: +1");
1032 rb->lcd_putsxy(LCD_WIDTH/2 - 9*w, LCD_HEIGHT/2 - 1, "LEFT: -1");
1033 rb->lcd_putsxy(LCD_WIDTH/2 - 9*w, LCD_HEIGHT/2 + h, "UP: +10");
1034 rb->lcd_putsxy(LCD_WIDTH/2 - 9*w, LCD_HEIGHT/2 + 2*h + 1, "DOWN: -10");
1035 #endif
1036 rb->lcd_update_rect(LCD_WIDTH/2 - 9*w - 1, LCD_HEIGHT/2 - 4*h - 3,
1037 37*w / 2, 8*h -3);
1038 #endif
1040 while(!breakout) {
1041 button = rb->button_get(true);
1043 switch(button) {
1044 case BJACK_UP:
1045 case (BJACK_UP|BUTTON_REPEAT):
1046 if (amount + 10 < upper_limit + 1) {
1047 amount += 10;
1048 changed = true;
1050 break;
1051 case BJACK_DOWN:
1052 case (BJACK_DOWN|BUTTON_REPEAT):
1053 if (amount - 10 > lower_limit - 1) {
1054 amount -= 10;
1055 changed = true;
1057 break;
1058 case BJACK_RIGHT:
1059 case (BJACK_RIGHT|BUTTON_REPEAT):
1060 if (amount + 1 < upper_limit + 1) {
1061 amount++;
1062 changed = true;
1064 break;
1065 case BJACK_LEFT:
1066 case (BJACK_LEFT|BUTTON_REPEAT):
1067 if (amount - 1 > lower_limit - 1) {
1068 amount--;
1069 changed = true;
1071 break;
1072 #ifdef BJACK_MAX
1073 case BJACK_MAX :
1074 amount = upper_limit;
1075 changed = true;
1076 break;
1077 #endif
1078 #ifdef BJACK_MIN
1079 case BJACK_MIN :
1080 amount = lower_limit;
1081 changed = true;
1082 break;
1083 #endif
1084 case BJACK_QUIT:
1085 breakout = true;
1086 amount = 0;
1087 break;
1088 case BJACK_SELECT:
1089 breakout = true;
1090 break;
1093 if(changed) {
1094 #if LCD_HEIGHT <= 64
1095 rb->lcd_putsf(0, 2, "$%d", amount);
1096 rb->lcd_update();
1097 #else
1098 rb->lcd_set_drawmode(DRMODE_BG+DRMODE_INVERSEVID);
1099 rb->lcd_fillrect(LCD_WIDTH/2 - 9*w, LCD_HEIGHT/2 - 3*h, 5*w, h);
1100 rb->lcd_set_drawmode(DRMODE_SOLID);
1101 rb->lcd_putsxyf(LCD_WIDTH/2 - 9*w, LCD_HEIGHT/2 - 3*h, "$%d", amount);
1102 rb->lcd_update_rect(LCD_WIDTH/2 - 9*w, LCD_HEIGHT/2 - 3*h, 5*w, h);
1103 #endif
1104 changed = false;
1108 #if LCD_DEPTH > 1
1109 rb->lcd_set_foreground(FG_COLOR);
1110 rb->lcd_set_background(BG_COLOR);
1111 #endif
1112 rb->lcd_clear_display();
1113 return amount;
1116 /*****************************************************************************
1117 * blackjack_get_bet() gets the player's bet.
1118 ******************************************************************************/
1119 static void blackjack_get_bet(struct game_context* bj) {
1120 bj->current_bet = blackjack_get_amount("Please enter a bet", 10,
1121 bj->player_money, bj->current_bet);
1124 /*****************************************************************************
1125 * double_down() returns one final card then finishes the game
1126 ******************************************************************************/
1127 static void double_down(struct game_context* bj) {
1128 bj->current_bet *= 2;
1129 bj->player_cards[0][bj->num_player_cards[0]] = new_card();
1130 bj->player_total += bj->player_cards[0][bj->num_player_cards[0]].value;
1131 bj->num_player_cards[0]++;
1134 /*****************************************************************************
1135 * split() checks if the player wants to split and acts accordingly.
1136 * When bj->split_status is 1, no split occurred. 2 means the player split and 3
1137 * means a split has already occurred and the first hand is done.
1138 ******************************************************************************/
1139 static void split(struct game_context* bj) {
1140 if (blackjack_get_yes_no("Split?") != 0)
1141 bj->split_status = 1;
1142 else {
1143 bj->split_status = 2;
1144 bj->current_bet *= 2;
1145 bj->num_player_cards[0] = 1;
1146 bj->num_player_cards[1] = 1;
1147 bj->player_cards[1][0] = bj->player_cards[0][1];
1148 bj->player_total = bj->player_cards[0][0].value;
1152 /*****************************************************************************
1153 * insurance() see if the player wants to buy insurance and how much.
1154 ******************************************************************************/
1155 static unsigned int insurance(struct game_context* bj) {
1156 unsigned int insurance, max_amount;
1158 insurance = blackjack_get_yes_no("Buy Insurance?");
1159 bj->asked_insurance = true;
1160 max_amount = bj->current_bet < (unsigned int)bj->player_money ?
1161 bj->current_bet/2 : (unsigned int)bj->player_money;
1162 if (insurance != 0) return 0;
1164 insurance = blackjack_get_amount("How much?", 0, max_amount, 0);
1165 redraw_board(bj);
1166 return insurance;
1169 /*****************************************************************************
1170 * play_again() checks to see if the player wants to keep playing.
1171 ******************************************************************************/
1172 static unsigned int play_again(void) {
1173 return blackjack_get_yes_no("Play Again?");
1176 /*****************************************************************************
1177 * blackjack_help() displays help text.
1178 ******************************************************************************/
1179 static bool blackjack_help(void) {
1180 static char *help_text[] = {
1181 "Blackjack", "", "Aim", "",
1182 "Try", "to", "get", "as", "close", "to", "21", "without", "going",
1183 "over", "or", "simply", "beat", "out", "the", "dealer", "for", "the",
1184 "best", "hand.", "", "",
1185 "Controls", "",
1186 BJACK_SELECT_NAME, ":", "hit", "/", "select", "",
1187 BJACK_STAY_NAME, ":", "stay", "",
1188 BJACK_DOUBLE_NAME, ":", "double", "down", "",
1189 BJACK_QUIT_NAME, ":", "go", "to", "menu", "",
1191 static struct style_text formation[]={
1192 { 0, TEXT_CENTER|TEXT_UNDERLINE },
1193 { 2, C_RED },
1194 { 26, C_RED },
1195 LAST_STYLE_ITEM
1198 rb->lcd_setfont(FONT_UI);
1199 #ifdef HAVE_LCD_COLOR
1200 rb->lcd_set_background(LCD_BLACK);
1201 rb->lcd_set_foreground(LCD_WHITE);
1202 #endif
1203 if (display_text(ARRAYLEN(help_text), help_text, formation, NULL, true))
1204 return true;
1205 rb->lcd_setfont(FONT_SYSFIXED);
1207 return false;
1210 static int blackjack_menu_cb(int action, const struct menu_item_ex *this_item)
1212 int i = ((intptr_t)this_item);
1213 if(action == ACTION_REQUEST_MENUITEM
1214 && !resume && (i==0 || i==5))
1215 return ACTION_EXIT_MENUITEM;
1216 return action;
1219 /*****************************************************************************
1220 * blackjack_menu() is the initial menu at the start of the game.
1221 ******************************************************************************/
1222 static unsigned int blackjack_menu(void) {
1223 int selection = 0;
1224 bool breakout = false;
1226 MENUITEM_STRINGLIST(menu, "BlackJack Menu", blackjack_menu_cb,
1227 "Resume Game", "Start New Game",
1228 "High Scores", "Help",
1229 "Playback Control",
1230 "Quit without Saving", "Quit");
1232 while(!breakout) {
1233 switch(rb->do_menu(&menu, &selection, NULL, false)) {
1234 case 0:
1235 breakout = true;
1236 if(resume_file)
1237 rb->remove(SAVE_FILE);
1238 resume_file = false;
1239 break;
1240 case 1:
1241 breakout = true;
1242 resume = false;
1243 break;
1244 case 2:
1245 highscore_show(-1, highscores, NUM_SCORES, false);
1246 break;
1247 case 3:
1248 if(blackjack_help())
1249 return BJ_USB;
1250 break;
1251 case 4:
1252 if (playback_control(NULL))
1253 return BJ_USB;
1254 break;
1255 case 5:
1256 return BJ_QUIT_WITHOUT_SAVING;
1257 case 6:
1258 if (resume)
1259 return BJ_QUIT;
1260 else
1261 return BJ_QUIT_WITHOUT_SAVING;
1263 case MENU_ATTACHED_USB:
1264 return BJ_USB;
1266 default:
1267 break;
1271 return 0;
1274 /*****************************************************************************
1275 * blackjack() is the main game subroutine, it returns the final game status.
1276 ******************************************************************************/
1277 static int blackjack(struct game_context* bj) {
1278 int button;
1279 unsigned int w, h, temp_var, done = 0, todo = 1;
1280 signed int temp;
1281 bool breakout = false;
1282 bool dbl_down = false;
1284 /********************
1285 * menu *
1286 ********************/
1287 temp_var = blackjack_menu();
1288 if (temp_var != 0)
1289 return temp_var;
1291 #if LCD_DEPTH > 1
1292 rb->lcd_set_background(BG_COLOR);
1293 rb->lcd_set_foreground(FG_COLOR);
1294 #endif
1296 /********************
1297 * init *
1298 ********************/
1299 blackjack_init(bj);
1301 /********************
1302 * play *
1303 ********************/
1305 resume_file = false;
1306 /* check for resumed game */
1307 if(resume) {
1308 resume = false;
1309 redraw_board(bj);
1310 if (bj->split_status == 2) {
1311 todo=2;
1312 player_x = bj->num_player_cards[0] * 10 + 4;
1314 else if (bj->split_status == 3) {
1315 player_x = bj->num_player_cards[1] * 10 + LCD_WIDTH/2 + 4;
1316 todo=2;
1317 done=1;
1320 else {
1321 bj->player_money = 1000;
1322 bj->current_bet = 10;
1323 blackjack_get_bet(bj);
1324 if (bj->current_bet == 0)
1325 return -1;
1326 rb->lcd_clear_display();
1327 deal_init_cards(bj);
1328 blackjack_drawtable(bj);
1331 rb->lcd_update();
1333 breakout = false;
1335 while(true){
1336 if(bj->player_total == 21 && bj->num_player_cards[0] == 2) {
1337 bj->is_blackjack = true;
1338 bj->end_hand = true;
1339 finish_game(bj);
1341 else if(bj->dealer_cards[1].is_soft_ace && !breakout &&
1342 !bj->asked_insurance) {
1343 temp_var = insurance(bj);
1344 if (bj->dealer_total == 21) {
1345 rb->splash(HZ, "Dealer has blackjack");
1346 bj->player_money += temp_var;
1347 bj->end_hand = true;
1348 breakout = true;
1349 redraw_board(bj);
1350 finish_game(bj);
1352 else {
1353 rb->splash(HZ, "Dealer does not have blackjack");
1354 bj->player_money -= temp_var;
1355 breakout = true;
1356 redraw_board(bj);
1357 rb->lcd_update();
1360 if(!bj->end_hand && bj->split_status == 0 &&
1361 bj->player_cards[0][0].num == bj->player_cards[0][1].num) {
1362 split(bj);
1363 redraw_board(bj);
1364 rb->lcd_update_rect(0, LCD_HEIGHT/2, LCD_WIDTH, LCD_HEIGHT/2);
1365 if (bj->split_status == 2) {
1366 todo++;
1367 player_x = bj->num_player_cards[0] * 10 + 4;
1371 while(!bj->end_hand && done < todo) {
1372 button = rb->button_get(true);
1374 switch(button) {
1375 case BJACK_SELECT:
1376 NEXT_CARD = new_card();
1377 bj->player_total += NEXT_CARD.value;
1378 draw_card(NEXT_CARD, true, player_x, player_y);
1379 bj->num_player_cards[done]++;
1380 if (bj->num_player_cards[done] == MAX_CARDS + 1) {
1381 redraw_board(bj);
1382 rb->lcd_update_rect(0, LCD_HEIGHT/2, LCD_WIDTH,
1383 LCD_HEIGHT/2);
1385 else if (bj->num_player_cards[done]>MAX_CARDS || todo > 1) {
1386 rb->lcd_update_rect(player_x, player_y, CARD_WIDTH+2,
1387 CARD_HEIGHT+2);
1388 player_x += 10;
1390 else {
1391 rb->lcd_update_rect(player_x, player_y, CARD_WIDTH+2,
1392 CARD_HEIGHT+2);
1393 player_x += CARD_WIDTH + 4;
1395 update_total(bj);
1397 break;
1398 case BJACK_STAY:
1399 bj->end_hand = true;
1400 break;
1401 case BJACK_DOUBLEDOWN:
1402 if ((signed int)bj->current_bet * 2 <
1403 bj->player_money + 1 &&
1404 bj->num_player_cards[0]==2 && todo==1) {
1405 double_down(bj);
1406 dbl_down = true;
1407 if (bj->player_total < 22) {
1408 bj->end_hand = true;
1409 finish_game(bj);
1412 else if((signed int)bj->current_bet * 2 >
1413 bj->player_money){
1414 rb->splash(HZ, "Not enough money to double down.");
1415 redraw_board(bj);
1416 rb->lcd_update();
1418 break;
1420 case BJACK_QUIT:
1421 resume = true;
1422 return BJ_END;
1425 while (bj->player_total > 21 && !bj->end_hand) {
1426 temp = check_for_aces(bj->player_cards[done],
1427 bj->num_player_cards[done]);
1428 if(temp != -1) {
1429 bj->player_cards[done][temp].is_soft_ace = false;
1430 bj->player_total -= 10;
1431 update_total(bj);
1432 if (dbl_down) {
1433 bj->end_hand = true;
1434 finish_game(bj);
1437 else
1438 bj->end_hand = true;
1441 if (bj->end_hand) {
1442 done++;
1443 if(todo > 1) {
1444 if (done == 2) {
1445 temp = bj->player_total;
1446 bj->player_total = temp_var;
1447 temp_var = temp;
1448 finish_game(bj);
1449 rb->lcd_getstringsize(" Split 1 ", &w, &h);
1450 rb->lcd_putsxy(LCD_WIDTH/2-w/2, LCD_HEIGHT/2-3*h/2,
1451 " Split 1 ");
1452 rb->lcd_update_rect(LCD_WIDTH/2-w/2, LCD_HEIGHT/2-3*h/2,
1453 w,h);
1454 bj->current_bet /= 2;
1455 rb->lcd_update_rect(LCD_WIDTH/2-w/2, LCD_HEIGHT/2-3*h/2,
1456 w,h);
1457 rb->sleep(HZ*2);
1458 bj->player_total = temp_var;
1459 finish_game(bj);
1460 rb->lcd_getstringsize(" Split 2 ", &w, &h);
1461 rb->lcd_putsxy(LCD_WIDTH/2-w/2, LCD_HEIGHT/2-3*h/2,
1462 " Split 2 ");
1463 rb->lcd_update_rect(LCD_WIDTH/2-w/2, LCD_HEIGHT/2-3*h/2,
1464 w,h);
1465 rb->sleep(HZ*2);
1467 else {
1468 bj->end_hand = false;
1469 bj->split_status = 3;
1470 temp_var = bj->player_total;
1471 bj->player_total = bj->player_cards[1][0].value;
1472 update_total(bj);
1473 redraw_board(bj);
1474 player_x += 10;
1475 rb->lcd_update();
1478 else
1479 finish_game(bj);
1483 if (bj->player_money < 10) {
1484 rb->sleep(HZ);
1485 return BJ_LOSE;
1488 if (bj->end_hand) { /* If hand is over */
1489 if (play_again() != 0) /* User wants to quit */
1490 return BJ_END;
1491 else { /* User keeps playing */
1492 breakout = false;
1493 temp = bj->current_bet;
1494 bj->current_bet = 0;
1495 redraw_board(bj);
1496 rb->lcd_update();
1497 bj->current_bet = temp;
1498 if(dbl_down) {
1499 bj->current_bet /= 2;
1500 dbl_down = false;
1502 done = 0;
1503 todo = 1;
1504 blackjack_init(bj);
1505 blackjack_get_bet(bj);
1506 if (bj->current_bet == 0)
1507 return BJ_END;
1508 deal_init_cards(bj);
1509 blackjack_drawtable(bj);
1510 rb->lcd_update();
1514 /* Never reached */
1515 return PLUGIN_OK;
1518 /*****************************************************************************
1519 * plugin entry point.
1520 ******************************************************************************/
1521 enum plugin_status plugin_start(const void* parameter)
1523 struct game_context bj;
1524 bool exit = false;
1526 (void)parameter;
1528 #if LCD_DEPTH > 1
1529 rb->lcd_set_backdrop(NULL);
1530 #endif
1532 /* load high scores */
1533 highscore_load(SCORE_FILE, highscores, NUM_SCORES);
1534 resume = blackjack_loadgame(&bj);
1535 resume_file = resume;
1537 rb->lcd_setfont(FONT_SYSFIXED);
1539 while(!exit) {
1540 switch(blackjack(&bj)){
1541 case BJ_LOSE:
1542 rb->splash(HZ, "Not enough money to continue");
1543 /* fall through to BJ_END */
1545 case BJ_END:
1546 if(!resume && bj.player_money > 10) {
1547 /* There is no level, so store -1 to blank column */
1548 int position = highscore_update(bj.player_money, -1, "",
1549 highscores, NUM_SCORES);
1550 if (position != -1)
1552 if (position==0)
1553 rb->splash(HZ*2, "New High Score");
1554 highscore_show(position, highscores, NUM_SCORES, false);
1557 break;
1559 case BJ_USB:
1560 highscore_save(SCORE_FILE, highscores, NUM_SCORES);
1561 return PLUGIN_USB_CONNECTED;
1563 case BJ_QUIT:
1564 rb->splash(HZ*1, "Saving game...");
1565 blackjack_savegame(&bj);
1566 /* fall through */
1568 case BJ_QUIT_WITHOUT_SAVING:
1569 exit = true;
1570 break;
1572 default:
1573 break;
1576 highscore_save(SCORE_FILE, highscores, NUM_SCORES);
1577 return PLUGIN_OK;