Prepare new maemo release
[maemo-rb.git] / apps / plugins / blackjack.c
blobd65011c4b278664ca5989196d08d40d088c557e7
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_DATA_DIR "/blackjack.score"
33 #define SAVE_FILE PLUGIN_GAMES_DATA_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 (CONFIG_KEYPAD == SANSA_CONNECT_PAD)
171 #define BJACK_SELECT_NAME "SELECT"
172 #define BJACK_STAY_NAME "RIGHT"
173 #define BJACK_QUIT_NAME "POWER"
174 #define BJACK_DOUBLE_NAME "LEFT"
175 #define BJACK_SELECT BUTTON_SELECT
176 #define BJACK_QUIT BUTTON_POWER
177 #define BJACK_MAX BUTTON_UP
178 #define BJACK_MIN BUTTON_DOWN
179 #define BJACK_STAY BUTTON_RIGHT
180 #define BJACK_DOUBLEDOWN BUTTON_LEFT
181 #define BJACK_UP BUTTON_SCROLL_FWD
182 #define BJACK_DOWN BUTTON_SCROLL_BACK
183 #define BJACK_RIGHT BUTTON_RIGHT
184 #define BJACK_LEFT BUTTON_LEFT
186 #elif CONFIG_KEYPAD == SANSA_FUZE_PAD
187 #define BJACK_SELECT_NAME "SELECT"
188 #define BJACK_STAY_NAME "RIGHT"
189 #define BJACK_QUIT_NAME "HOME"
190 #define BJACK_DOUBLE_NAME "LEFT"
191 #define BJACK_SELECT BUTTON_SELECT
192 #define BJACK_QUIT (BUTTON_HOME|BUTTON_REPEAT)
193 #define BJACK_MAX BUTTON_UP
194 #define BJACK_MIN BUTTON_DOWN
195 #define BJACK_STAY BUTTON_RIGHT
196 #define BJACK_DOUBLEDOWN BUTTON_LEFT
197 #define BJACK_UP BUTTON_SCROLL_FWD
198 #define BJACK_DOWN BUTTON_SCROLL_BACK
199 #define BJACK_RIGHT BUTTON_RIGHT
200 #define BJACK_LEFT BUTTON_LEFT
202 #elif CONFIG_KEYPAD == SANSA_C200_PAD || CONFIG_KEYPAD == SANSA_CLIP_PAD
203 #define BJACK_SELECT_NAME "SELECT"
204 #define BJACK_STAY_NAME "RIGHT"
205 #define BJACK_QUIT_NAME "POWER"
206 #define BJACK_DOUBLE_NAME "LEFT"
207 #define BJACK_SELECT BUTTON_SELECT
208 #define BJACK_QUIT BUTTON_POWER
209 #define BJACK_MAX BUTTON_VOL_UP
210 #define BJACK_MIN BUTTON_VOL_DOWN
211 #define BJACK_STAY BUTTON_RIGHT
212 #define BJACK_DOUBLEDOWN BUTTON_LEFT
213 #define BJACK_UP BUTTON_UP
214 #define BJACK_DOWN BUTTON_DOWN
215 #define BJACK_RIGHT BUTTON_RIGHT
216 #define BJACK_LEFT BUTTON_LEFT
218 #elif CONFIG_KEYPAD == SANSA_M200_PAD
219 #define BJACK_SELECT_NAME "SELECT"
220 #define BJACK_STAY_NAME "RIGHT"
221 #define BJACK_QUIT_NAME "POWER"
222 #define BJACK_DOUBLE_NAME "LEFT"
223 #define BJACK_SELECT (BUTTON_SELECT | BUTTON_REL)
224 #define BJACK_QUIT BUTTON_POWER
225 #define BJACK_MAX BUTTON_VOL_UP
226 #define BJACK_MIN BUTTON_VOL_DOWN
227 #define BJACK_STAY BUTTON_RIGHT
228 #define BJACK_DOUBLEDOWN BUTTON_LEFT
229 #define BJACK_UP BUTTON_UP
230 #define BJACK_DOWN BUTTON_DOWN
231 #define BJACK_RIGHT BUTTON_RIGHT
232 #define BJACK_LEFT BUTTON_LEFT
234 #elif CONFIG_KEYPAD == TATUNG_TPJ1022_PAD
235 #define BJACK_SELECT_NAME "MAIN"
236 #define BJACK_STAY_NAME "MENU"
237 #define BJACK_QUIT_NAME "POWER"
238 #define BJACK_DOUBLE_NAME "DOWN"
239 #define BJACK_SELECT BUTTON_MAIN
240 #define BJACK_QUIT BUTTON_POWER
241 #define BJACK_MAX (BUTTON_REC|BUTTON_UP)
242 #define BJACK_MIN (BUTTON_REC|BUTTON_DOWN)
243 #define BJACK_STAY BUTTON_MENU
244 #define BJACK_DOUBLEDOWN BUTTON_DOWN
245 #define BJACK_UP BUTTON_UP
246 #define BJACK_DOWN BUTTON_DOWN
247 #define BJACK_RIGHT BUTTON_RIGHT
248 #define BJACK_LEFT BUTTON_LEFT
250 #elif CONFIG_KEYPAD == GIGABEAT_S_PAD
251 #define BJACK_SELECT_NAME "PLAY"
252 #define BJACK_STAY_NAME "VOL-"
253 #define BJACK_QUIT_NAME "BACK"
254 #define BJACK_DOUBLE_NAME "SELECT"
255 #define BJACK_SELECT BUTTON_PLAY
256 #define BJACK_QUIT BUTTON_BACK
257 #define BJACK_MAX BUTTON_VOL_UP
258 #define BJACK_MIN BUTTON_VOL_DOWN
259 #define BJACK_STAY BUTTON_VOL_DOWN
260 #define BJACK_DOUBLEDOWN BUTTON_SELECT
261 #define BJACK_UP BUTTON_UP
262 #define BJACK_DOWN BUTTON_DOWN
263 #define BJACK_RIGHT BUTTON_RIGHT
264 #define BJACK_LEFT BUTTON_LEFT
266 #elif CONFIG_KEYPAD == MROBE100_PAD
267 #define BJACK_SELECT_NAME "SELECT"
268 #define BJACK_STAY_NAME "DISPLAY"
269 #define BJACK_QUIT_NAME "POWER"
270 #define BJACK_DOUBLE_NAME "DOWN"
271 #define BJACK_SELECT BUTTON_SELECT
272 #define BJACK_QUIT BUTTON_POWER
273 #define BJACK_MAX BUTTON_MENU
274 #define BJACK_MIN BUTTON_DISPLAY
275 #define BJACK_STAY BUTTON_DISPLAY
276 #define BJACK_DOUBLEDOWN BUTTON_DOWN
277 #define BJACK_UP BUTTON_UP
278 #define BJACK_DOWN BUTTON_DOWN
279 #define BJACK_RIGHT BUTTON_RIGHT
280 #define BJACK_LEFT BUTTON_LEFT
282 #elif CONFIG_KEYPAD == IAUDIO_M3_PAD
283 #define BJACK_SELECT_NAME "RC","PLAY"
284 #define BJACK_STAY_NAME "RC", ">>|"
285 #define BJACK_QUIT_NAME "RC_REC"
286 #define BJACK_DOUBLE_NAME "RC_REW"
287 #define BJACK_SELECT BUTTON_RC_PLAY
288 #define BJACK_QUIT BUTTON_RC_REC
289 #define BJACK_STAY BUTTON_RC_FF
290 #define BJACK_DOUBLEDOWN BUTTON_RC_REW
291 #define BJACK_UP BUTTON_RC_VOL_UP
292 #define BJACK_DOWN BUTTON_RC_VOL_DOWN
293 #define BJACK_RIGHT BUTTON_RC_FF
294 #define BJACK_LEFT BUTTON_RC_REW
296 #elif CONFIG_KEYPAD == COWON_D2_PAD
297 #define BJACK_QUIT_NAME "POWER"
298 #define BJACK_DOUBLE_NAME "-"
299 #define BJACK_QUIT BUTTON_POWER
300 #define BJACK_DOUBLEDOWN BUTTON_MINUS
302 #elif CONFIG_KEYPAD == CREATIVEZVM_PAD
303 #define BJACK_SELECT_NAME "SELECT"
304 #define BJACK_STAY_NAME "PLAY"
305 #define BJACK_QUIT_NAME "POWER"
306 #define BJACK_DOUBLE_NAME "CUSTOM"
307 #define BJACK_SELECT BUTTON_SELECT
308 #define BJACK_QUIT BUTTON_POWER
309 #define BJACK_STAY BUTTON_PLAY
310 #define BJACK_MAX (BUTTON_CUSTOM|BUTTON_UP)
311 #define BJACK_MIN (BUTTON_CUSTOM|BUTTON_DOWN)
312 #define BJACK_DOUBLEDOWN BUTTON_CUSTOM
313 #define BJACK_UP BUTTON_UP
314 #define BJACK_DOWN BUTTON_DOWN
315 #define BJACK_RIGHT BUTTON_RIGHT
316 #define BJACK_LEFT BUTTON_LEFT
318 #elif CONFIG_KEYPAD == PHILIPS_HDD1630_PAD
319 #define BJACK_SELECT_NAME "SELECT"
320 #define BJACK_STAY_NAME "VOL-"
321 #define BJACK_QUIT_NAME "POWER"
322 #define BJACK_DOUBLE_NAME "MENU"
323 #define BJACK_SELECT BUTTON_SELECT
324 #define BJACK_QUIT BUTTON_POWER
325 #define BJACK_MAX BUTTON_VOL_UP
326 #define BJACK_MIN BUTTON_VOL_DOWN
327 #define BJACK_STAY BUTTON_VOL_DOWN
328 #define BJACK_DOUBLEDOWN BUTTON_MENU
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 == PHILIPS_HDD6330_PAD
335 #define BJACK_SELECT_NAME "PLAY"
336 #define BJACK_STAY_NAME "VOL-"
337 #define BJACK_QUIT_NAME "POWER"
338 #define BJACK_DOUBLE_NAME "MENU"
339 #define BJACK_SELECT BUTTON_PLAY
340 #define BJACK_QUIT BUTTON_POWER
341 #define BJACK_MAX BUTTON_VOL_UP
342 #define BJACK_MIN BUTTON_VOL_DOWN
343 #define BJACK_STAY BUTTON_VOL_DOWN
344 #define BJACK_DOUBLEDOWN BUTTON_MENU
345 #define BJACK_UP BUTTON_UP
346 #define BJACK_DOWN BUTTON_DOWN
347 #define BJACK_RIGHT BUTTON_RIGHT
348 #define BJACK_LEFT BUTTON_LEFT
350 #elif CONFIG_KEYPAD == PHILIPS_SA9200_PAD
351 #define BJACK_SELECT_NAME "MENU"
352 #define BJACK_STAY_NAME "VOL-"
353 #define BJACK_QUIT_NAME "POWER"
354 #define BJACK_DOUBLE_NAME "PLAY"
355 #define BJACK_SELECT BUTTON_MENU
356 #define BJACK_QUIT BUTTON_POWER
357 #define BJACK_MAX BUTTON_VOL_UP
358 #define BJACK_MIN BUTTON_VOL_DOWN
359 #define BJACK_STAY BUTTON_VOL_DOWN
360 #define BJACK_DOUBLEDOWN BUTTON_PLAY
361 #define BJACK_UP BUTTON_UP
362 #define BJACK_DOWN BUTTON_DOWN
363 #define BJACK_RIGHT BUTTON_NEXT
364 #define BJACK_LEFT BUTTON_PREV
366 #elif CONFIG_KEYPAD == ONDAVX747_PAD
367 #define BJACK_QUIT_NAME "POWER"
368 #define BJACK_DOUBLE_NAME "Vol-"
369 #define BJACK_QUIT BUTTON_POWER
370 #define BJACK_DOUBLEDOWN BUTTON_VOL_DOWN
372 #elif CONFIG_KEYPAD == ONDAVX777_PAD
373 #define BJACK_QUIT_NAME "POWER"
374 #define BJACK_QUIT BUTTON_POWER
376 #elif CONFIG_KEYPAD == MROBE500_PAD
377 #define BJACK_QUIT_NAME "POWER"
378 #define BJACK_QUIT BUTTON_POWER
380 #elif CONFIG_KEYPAD == SAMSUNG_YH_PAD
381 #define BJACK_SELECT_NAME "PLAY"
382 #define BJACK_STAY_NAME "RECORD"
383 #define BJACK_QUIT_NAME "REW"
384 #define BJACK_DOUBLE_NAME "FFWD"
385 #define BJACK_SELECT BUTTON_PLAY
386 #define BJACK_QUIT BUTTON_REW
387 #define BJACK_STAY BUTTON_REC
388 #define BJACK_DOUBLEDOWN BUTTON_FFWD
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 == PBELL_VIBE500_PAD
395 #define BJACK_SELECT_NAME "OK"
396 #define BJACK_STAY_NAME "CANCEL"
397 #define BJACK_QUIT_NAME "REC"
398 #define BJACK_DOUBLE_NAME "MENU"
399 #define BJACK_SELECT BUTTON_OK
400 #define BJACK_QUIT BUTTON_REC
401 #define BJACK_STAY BUTTON_CANCEL
402 #define BJACK_DOUBLEDOWN BUTTON_MENU
403 #define BJACK_UP BUTTON_UP
404 #define BJACK_DOWN BUTTON_DOWN
405 #define BJACK_RIGHT BUTTON_NEXT
406 #define BJACK_LEFT BUTTON_PREV
408 #elif CONFIG_KEYPAD == MPIO_HD200_PAD
409 #define BJACK_SELECT_NAME "FUNC"
410 #define BJACK_STAY_NAME "VOL +"
411 #define BJACK_RESUME_NAME "PLAY"
412 #define BJACK_QUIT_NAME "REC+PLAY"
413 #define BJACK_DOUBLE_NAME "VOL -"
414 #define BJACK_SELECT BUTTON_FUNC
415 #define BJACK_QUIT (BUTTON_REC|BUTTON_PLAY)
416 #define BJACK_STAY BUTTON_VOL_UP
417 #define BJACK_DOUBLEDOWN BUTTON_VOL_DOWN
418 #define BJACK_UP BUTTON_REW
419 #define BJACK_DOWN BUTTON_FF
420 #define BJACK_RIGHT BUTTON_VOL_UP
421 #define BJACK_LEFT BUTTON_VOL_DOWN
423 #elif CONFIG_KEYPAD == MPIO_HD300_PAD
424 #define BJACK_SELECT_NAME "ENTER"
425 #define BJACK_STAY_NAME "PLAY"
426 #define BJACK_RESUME_NAME ""
427 #define BJACK_QUIT_NAME "Long MENU"
428 #define BJACK_DOUBLE_NAME "REC"
429 #define BJACK_SELECT BUTTON_ENTER
430 #define BJACK_QUIT (BUTTON_MENU|BUTTON_REPEAT)
431 #define BJACK_STAY BUTTON_PLAY
432 #define BJACK_DOUBLEDOWN BUTTON_REC
433 #define BJACK_UP BUTTON_UP
434 #define BJACK_DOWN BUTTON_DOWN
435 #define BJACK_RIGHT BUTTON_FF
436 #define BJACK_LEFT BUTTON_REW
438 #elif CONFIG_KEYPAD == SANSA_FUZEPLUS_PAD
439 #define BJACK_SELECT_NAME "SELECT"
440 #define BJACK_STAY_NAME "PLAYPAUSE"
441 #define BJACK_RESUME_NAME ""
442 #define BJACK_QUIT_NAME "POWER"
443 #define BJACK_DOUBLE_NAME "BACK"
444 #define BJACK_SELECT BUTTON_SELECT
445 #define BJACK_QUIT BUTTON_POWER
446 #define BJACK_MAX BUTTON_BOTTOMRIGHT
447 #define BJACK_MIN BUTTON_BOTTOMLEFT
448 #define BJACK_STAY BUTTON_BACK
449 #define BJACK_DOUBLEDOWN BUTTON_PLAYPAUSE
450 #define BJACK_UP BUTTON_UP
451 #define BJACK_DOWN BUTTON_DOWN
452 #define BJACK_RIGHT BUTTON_RIGHT
453 #define BJACK_LEFT BUTTON_LEFT
455 #elif CONFIG_KEYPAD == SAMSUNG_YPR0_PAD
456 #define BJACK_SELECT_NAME "SELECT"
457 #define BJACK_STAY_NAME "MENU"
458 #define BJACK_QUIT_NAME "BACK"
459 #define BJACK_DOUBLE_NAME "USER"
460 #define BJACK_SELECT BUTTON_SELECT
461 #define BJACK_QUIT BUTTON_BACK
462 #define BJACK_MAX (BUTTON_LEFT|BUTTON_UP)
463 #define BJACK_MIN (BUTTON_RIGHT|BUTTON_DOWN)
464 #define BJACK_STAY BUTTON_MENU
465 #define BJACK_DOUBLEDOWN BUTTON_USER
466 #define BJACK_UP BUTTON_UP
467 #define BJACK_DOWN BUTTON_DOWN
468 #define BJACK_RIGHT BUTTON_RIGHT
469 #define BJACK_LEFT BUTTON_LEFT
471 #elif CONFIG_KEYPAD == HM60X_PAD
472 #define BJACK_SELECT_NAME "SELECT"
473 #define BJACK_STAY_NAME "UP+POWER"
474 #define BJACK_QUIT_NAME "POWER"
475 #define BJACK_DOUBLE_NAME "DOWN+POWER"
476 #define BJACK_SELECT BUTTON_SELECT
477 #define BJACK_QUIT BUTTON_POWER
478 #define BJACK_STAY (BUTTON_UP|BUTTON_POWER)
479 #define BJACK_DOUBLEDOWN (BUTTON_DOWN|BUTTON_POWER)
480 #define BJACK_UP BUTTON_UP
481 #define BJACK_DOWN BUTTON_DOWN
482 #define BJACK_RIGHT BUTTON_RIGHT
483 #define BJACK_LEFT BUTTON_LEFT
485 #elif CONFIG_KEYPAD == HM801_PAD
486 #define BJACK_SELECT_NAME "SELECT"
487 #define BJACK_STAY_NAME "PLAY"
488 #define BJACK_QUIT_NAME "POWER"
489 #define BJACK_DOUBLE_NAME "PREV"
490 #define BJACK_SELECT BUTTON_SELECT
491 #define BJACK_QUIT BUTTON_POWER
492 #define BJACK_STAY BUTTON_PLAY
493 #define BJACK_DOUBLEDOWN BUTTON_PREV
494 #define BJACK_UP BUTTON_UP
495 #define BJACK_DOWN BUTTON_DOWN
496 #define BJACK_RIGHT BUTTON_RIGHT
497 #define BJACK_LEFT BUTTON_LEFT
499 #else
500 #error No keymap defined!
501 #endif
503 #ifdef HAVE_TOUCHSCREEN
504 #ifndef BJACK_DOUBLEDOWN
505 #define BJACK_DOUBLEDOWN BUTTON_MIDLEFT
506 #define BJACK_DOUBLE_NAME "BUTTON_MIDLEFT"
507 #endif
508 #ifndef BJACK_SELECT
509 #define BJACK_SELECT BUTTON_CENTER
510 #define BJACK_SELECT_NAME "BUTTON_CENTER"
511 #endif
512 #ifndef BJACK_MAX
513 #define BJACK_MAX BUTTON_TOPRIGHT
514 #endif
515 #ifndef BJACK_MIN
516 #define BJACK_MIN BUTTON_TOPLEFT
517 #endif
518 #ifndef BJACK_STAY
519 #define BJACK_STAY BUTTON_BOTTOMLEFT
520 #define BJACK_STAY_NAME "BUTTON_BOTTOMLEFT"
521 #endif
522 #ifndef BJACK_UP
523 #define BJACK_UP BUTTON_TOPMIDDLE
524 #endif
525 #ifndef BJACK_DOWN
526 #define BJACK_DOWN BUTTON_BOTTOMMIDDLE
527 #endif
528 #ifndef BJACK_RIGHT
529 #define BJACK_RIGHT BUTTON_MIDRIGHT
530 #endif
531 #ifndef BJACK_LEFT
532 #define BJACK_LEFT BUTTON_MIDLEFT
533 #endif
535 #endif
537 #ifdef HAVE_LCD_COLOR
538 #define BG_COLOR LCD_RGBPACK(0,157,0)
539 #define FG_COLOR LCD_WHITE
540 #elif LCD_DEPTH > 1
541 #define BG_COLOR LCD_WHITE
542 #define FG_COLOR LCD_BLACK
543 #endif
545 #define CARD_WIDTH BMPWIDTH_card_back
546 #define CARD_HEIGHT BMPHEIGHT_card_back
548 /* This is the max amount of cards onscreen before condensing */
549 #define MAX_CARDS LCD_WIDTH/(CARD_WIDTH+4)
551 extern const fb_data card_deck[];
552 extern const fb_data card_back[];
554 #define NEXT_CARD bj->player_cards[done][bj->num_player_cards[done]]
556 /* dealer and player card positions */
557 unsigned int dealer_x, dealer_y, player_x, player_y;
559 typedef struct card {
560 unsigned int value; /* Card's value in Blackjack */
561 unsigned int num; /* Value on card face 0-12 (0=Ace, 1=2, 11=Q) */
562 unsigned int suit; /* 0:Spades, 1:Hearts, 2: Clubs; 3: Diamonds */
563 bool is_soft_ace;
564 } card;
566 typedef struct game_context {
567 struct card player_cards[2][22]; /* 22 Cards means the deal was all aces */
568 struct card dealer_cards[22]; /* That is the worst-case scenario */
569 unsigned int player_total;
570 unsigned int dealer_total;
571 signed int player_money;
572 unsigned int num_player_cards[2];
573 unsigned int num_dealer_cards;
574 unsigned int current_bet;
575 unsigned int split_status; /* 0 = split hasn't been asked, *
576 * 1 = split did not occur *
577 * 2 = split occurred *
578 * 3 = split occurred and 1st hand done */
579 bool is_blackjack;
580 bool end_hand;
581 bool asked_insurance;
582 } game_context;
584 static bool resume = false;
585 static bool resume_file = false;
586 static struct highscore highscores[NUM_SCORES];
588 /*****************************************************************************
589 * blackjack_init() initializes blackjack data structures.
590 ******************************************************************************/
591 static void blackjack_init(struct game_context* bj) {
592 /* seed the rand generator */
593 rb->srand(*rb->current_tick);
595 /* reset card positions */
596 dealer_x = 4;
597 dealer_y = LCD_HEIGHT/4 - CARD_HEIGHT/2;
598 player_x = 4;
599 player_y = LCD_HEIGHT - LCD_HEIGHT/4 - CARD_HEIGHT/2;
601 /* check for resumed game */
602 if(resume) return;
604 /* reset scoring */
605 bj->player_total = 0;
606 bj->dealer_total = 0;
607 bj->num_player_cards[0] = 2;
608 bj->num_player_cards[1] = 0;
609 bj->num_dealer_cards = 2;
610 bj->end_hand = false;
611 bj->split_status = 0;
612 bj->is_blackjack = false;
613 bj->asked_insurance = false;
616 /*****************************************************************************
617 * blackjack_drawtable() draws the table and some text.
618 ******************************************************************************/
619 static void blackjack_drawtable(struct game_context* bj) {
620 unsigned int w, h, y_loc;
621 char str[10];
623 #if LCD_HEIGHT <= 64 || LCD_WIDTH <= 96
624 rb->lcd_getstringsize("Bet", &w, &h);
625 rb->lcd_putsxy(LCD_WIDTH - w, 2*h + 1, "Bet");
626 rb->snprintf(str, 9, "$%d", bj->current_bet);
627 rb->lcd_getstringsize(str, &w, &h);
628 rb->lcd_putsxy(LCD_WIDTH - w, 3*h + 1, str);
629 y_loc = LCD_HEIGHT/2;
630 #else
631 rb->lcd_getstringsize("Bet", &w, &h);
632 rb->lcd_putsxy(LCD_WIDTH - w, 5*h / 2, "Bet");
633 rb->snprintf(str, 9, "$%d", bj->current_bet);
634 rb->lcd_getstringsize(str, &w, &h);
635 rb->lcd_putsxy(LCD_WIDTH - w, 7*h / 2, str);
636 rb->lcd_hline(0, LCD_WIDTH, LCD_HEIGHT/2);
637 y_loc = LCD_HEIGHT/2 + h;
638 #endif
640 rb->lcd_putsxy(0,0, "Dealer");
641 rb->lcd_getstringsize("Player", &w, &h);
642 rb->lcd_putsxy(0, y_loc, "Player");
643 rb->lcd_getstringsize("Total", &w, &h);
644 rb->lcd_putsxy(LCD_WIDTH - w, y_loc, "Total");
645 rb->lcd_getstringsize("Money", &w, &h);
646 rb->lcd_putsxy(LCD_WIDTH - w, 0, "Money");
647 rb->snprintf(str, 9, "$%d", bj->player_money - bj->current_bet);
648 rb->lcd_getstringsize(str, &w, &h);
649 rb->lcd_putsxy(LCD_WIDTH - w, h + 1, str);
650 rb->snprintf(str, 3, "%d", bj->player_total);
651 rb->lcd_getstringsize(str, &w, &h);
652 rb->lcd_putsxy(LCD_WIDTH - w, y_loc + h, str);
655 /*****************************************************************************
656 * find_value() is passed a card and returns its blackjack value.
657 ******************************************************************************/
658 static unsigned int find_value(unsigned int number) {
659 unsigned int thisValue;
660 if (number == 0)
661 thisValue = 11; /* Aces get a value of 11 at first */
662 else if (number < 10)
663 thisValue = number + 1;
664 else
665 thisValue = 10; /* Anything 10 or higher gets a value of 10 */
667 return thisValue;
670 /*****************************************************************************
671 * draw_card() draws a card to the screen.
672 ******************************************************************************/
673 static void draw_card(struct card temp_card, bool shown,
674 unsigned int x, unsigned int y) {
675 if(shown)
676 rb->lcd_bitmap_part(card_deck, CARD_WIDTH*temp_card.num,
677 CARD_HEIGHT*temp_card.suit,
678 STRIDE( SCREEN_MAIN, BMPWIDTH_card_deck,
679 BMPHEIGHT_card_deck),
680 x+1, y+1, CARD_WIDTH, CARD_HEIGHT);
681 else
682 rb->lcd_bitmap(card_back, x+1, y+1,CARD_WIDTH, CARD_HEIGHT);
683 #if LCD_DEPTH > 1
684 rb->lcd_set_foreground(LCD_BLACK);
685 #endif
687 /* Print outlines */
688 #if CARD_WIDTH >= 26
689 rb->lcd_hline(x+2, x+CARD_WIDTH-1, y);
690 rb->lcd_hline(x+2, x+CARD_WIDTH-1, y+CARD_HEIGHT+1);
691 rb->lcd_vline(x, y+2, y+CARD_HEIGHT-3);
692 rb->lcd_vline(x+CARD_WIDTH+1, y+2, y+CARD_HEIGHT-1);
693 rb->lcd_drawpixel(x+1, y+1);
694 rb->lcd_drawpixel(x+1, y+CARD_HEIGHT);
695 rb->lcd_drawpixel(x+CARD_WIDTH, y+1);
696 rb->lcd_drawpixel(x+CARD_WIDTH, y+CARD_HEIGHT);
697 #else
698 rb->lcd_hline(x+1, x+CARD_WIDTH, y);
699 rb->lcd_hline(x+1, x+CARD_WIDTH, y+CARD_HEIGHT+1);
700 rb->lcd_vline(x, y+1, y+CARD_HEIGHT);
701 rb->lcd_vline(x+CARD_WIDTH+1, y+1, y+CARD_HEIGHT);
702 #endif
704 #if LCD_DEPTH > 1
705 rb->lcd_set_foreground(FG_COLOR);
706 #endif
709 /*****************************************************************************
710 * new_card() initializes a new card and gives it values.
711 ******************************************************************************/
712 static struct card new_card(void) {
713 struct card new_card;
714 new_card.suit = rb->rand()%4; /* Random number 0-3 */
715 new_card.num = rb->rand()%13; /* Random number 0-12 */
716 new_card.value = find_value(new_card.num);
717 new_card.is_soft_ace = (new_card.num == 0);
718 return new_card;
721 /*****************************************************************************
722 * deal_init_card() deals and draws to the screen the player's and dealer's
723 * initial cards.
724 ******************************************************************************/
725 static void deal_init_cards(struct game_context* bj) {
726 bj->dealer_cards[0] = new_card();
727 bj->dealer_total += bj->dealer_cards[0].value;
729 draw_card(bj->dealer_cards[0], false, dealer_x, dealer_y);
731 bj->dealer_cards[1] = new_card();
732 bj->dealer_total += bj->dealer_cards[1].value;
733 draw_card(bj->dealer_cards[1], true, dealer_x + CARD_WIDTH + 4, dealer_y);
735 bj->player_cards[0][0] = new_card();
736 bj->player_total += bj->player_cards[0][0].value;
737 draw_card(bj->player_cards[0][0], true, player_x, player_y);
738 player_x += CARD_WIDTH + 4;
740 bj->player_cards[0][1] = new_card();
741 bj->player_total += bj->player_cards[0][1].value;
742 draw_card(bj->player_cards[0][1], true, player_x, player_y);
743 player_x += CARD_WIDTH + 4;
746 /*****************************************************************************
747 * redraw_board() redraws all the cards and the board
748 ******************************************************************************/
749 static void redraw_board(struct game_context* bj) {
750 unsigned int i, n, upper_bound;
751 rb->lcd_clear_display();
753 blackjack_drawtable(bj);
754 player_x = 4;
755 dealer_x = 4;
756 upper_bound = bj->split_status > 1 ? 2 : 1;
758 for (i = 0; i < bj->num_dealer_cards; i++) {
759 if (!bj->end_hand) {
760 draw_card(bj->dealer_cards[0], false, dealer_x, dealer_y);
762 /* increment i so the dealer's first card isn't displayed */
763 i++;
764 dealer_x += CARD_WIDTH + 4;
766 draw_card(bj->dealer_cards[i], true, dealer_x, dealer_y);
768 if (bj->num_dealer_cards > MAX_CARDS-1)
769 dealer_x += 10;
770 else
771 dealer_x += CARD_WIDTH + 4;
774 for (n = 0; n < upper_bound; n++) {
775 for (i = 0; i < bj->num_player_cards[n]; i++) {
776 draw_card(bj->player_cards[n][i], true, player_x, player_y);
777 if (bj->split_status>1 || bj->num_player_cards[n]>MAX_CARDS)
778 player_x += 10;
779 else
780 player_x += CARD_WIDTH + 4;
782 if (bj->split_status > 1)
783 player_x = LCD_WIDTH/2 + 4;
787 /*****************************************************************************
788 * update_total updates the player's total
789 ******************************************************************************/
790 static void update_total(struct game_context* bj) {
791 char total[3];
792 unsigned int w, h;
793 rb->snprintf(total, 3, "%d", bj->player_total);
794 rb->lcd_getstringsize(total, &w, &h);
795 #if LCD_HEIGHT > 64 && LCD_WIDTH > 96
796 h *= 2;
797 #endif
798 rb->lcd_putsxy(LCD_WIDTH - w, LCD_HEIGHT/2 + h, total);
799 rb->lcd_update_rect(LCD_WIDTH - w, LCD_HEIGHT/2 + h, w, h);
803 /*****************************************************************************
804 * check_for_aces() is passed an array of cards and returns where an ace is
805 * located. Otherwise, returns -1.
806 ******************************************************************************/
807 static signed int check_for_aces(struct card temp_cards[], unsigned int size) {
808 unsigned int i;
809 for(i = 0; i < size; i++) {
810 if (temp_cards[i].is_soft_ace)
811 return i;
813 return -1;
816 /*****************************************************************************
817 * check_totals() compares player and dealer totals.
818 * 0: bust 1: loss, 2: push, 3: win, 4: blackjack, 5: something's not right...
819 ******************************************************************************/
820 static unsigned int check_totals(struct game_context* bj) {
821 unsigned int temp;
822 if (bj->player_total > 21)
823 temp = 0;
824 else if (bj->player_total == 21 && bj->is_blackjack) {
825 if (bj->dealer_total == 21 && bj->num_dealer_cards == 2)
826 temp = 2;
827 else
828 temp = 4;
830 else if (bj->player_total == bj->dealer_total)
831 temp = 2;
832 else if (bj->dealer_total > 21 && bj->player_total < 22)
833 temp = 3;
834 else if (bj->dealer_total > bj->player_total)
835 temp = 1;
836 else if (bj->player_total > bj->dealer_total)
837 temp = 3;
838 else
839 temp = 5;
841 return temp;
844 /*****************************************************************************
845 * finish_dealer() draws cards for the dealer until he has 17 or more.
846 ******************************************************************************/
847 static void finish_dealer(struct game_context* bj) {
848 signed int temp = 0;
850 if (bj->dealer_total > 16 && bj->dealer_total < 22)
851 return;
853 while (bj->dealer_total < 17) {
854 bj->dealer_cards[bj->num_dealer_cards] = new_card();
855 bj->dealer_total += bj->dealer_cards[bj->num_dealer_cards].value;
856 bj->num_dealer_cards++;
859 while (bj->dealer_total > 21) {
860 temp = check_for_aces(bj->dealer_cards, bj->num_dealer_cards);
861 if(temp != -1) {
862 bj->dealer_cards[temp].is_soft_ace = false;
863 bj->dealer_total -= 10;
865 else
866 return;
870 /*****************************************************************************
871 * finish_game() completes the game once player's turn is over.
872 ******************************************************************************/
873 static void finish_game(struct game_context* bj) {
874 unsigned int rValue, w, h;
875 char str[19];
877 do {
878 finish_dealer(bj);
879 } while (bj->dealer_total < 17);
881 redraw_board(bj);
882 rValue = check_totals(bj);
884 if (rValue == 0) {
885 rb->snprintf(str, sizeof(str), " Bust! ");
886 bj->player_money -= bj->current_bet;
888 else if (rValue == 1) {
889 rb->snprintf(str, sizeof(str), " Sorry, you lost. ");
890 bj->player_money -= bj->current_bet;
892 else if (rValue == 2) {
893 rb->snprintf(str, sizeof(str), " Push ");
895 else if (rValue == 3) {
896 rb->snprintf(str, sizeof(str), " You won! ");
897 bj->player_money+= bj->current_bet;
899 else {
900 rb->snprintf(str, sizeof(str), " Blackjack! ");
901 bj->player_money += bj->current_bet * 3 / 2;
903 rb->lcd_getstringsize(str, &w, &h);
905 #if LCD_HEIGHT <= 64 || LCD_WIDTH <= 96
906 rb->lcd_set_drawmode(DRMODE_BG+DRMODE_INVERSEVID);
907 rb->lcd_fillrect(0, LCD_HEIGHT/2, LCD_WIDTH, LCD_HEIGHT/2);
908 rb->lcd_set_drawmode(DRMODE_SOLID);
909 rb->lcd_putsxy(LCD_WIDTH/2 - w/2, LCD_HEIGHT/2 + h, str);
910 rb->snprintf(str, 12, "You have %d", bj->player_total);
911 rb->lcd_getstringsize(str, &w, &h);
912 rb->lcd_putsxy(LCD_WIDTH/2 - w/2, LCD_HEIGHT/2, str);
913 #else
914 rb->lcd_putsxy(LCD_WIDTH/2 - w/2, LCD_HEIGHT/2 - h/2, str);
915 #endif
916 rb->lcd_update();
919 /*****************************************************************************
920 * blackjack_loadgame() loads the saved game and returns load success.
921 ******************************************************************************/
922 static bool blackjack_loadgame(struct game_context* bj) {
923 signed int fd;
924 bool loaded = false;
926 /* open game file */
927 fd = rb->open(SAVE_FILE, O_RDONLY);
928 if(fd < 0) return false;
930 /* read in saved game */
931 if(rb->read(fd, bj, sizeof(struct game_context))
932 == (long)sizeof(struct game_context))
934 loaded = true;
937 rb->close(fd);
939 return loaded;
942 /*****************************************************************************
943 * blackjack_savegame() saves the current game state.
944 ******************************************************************************/
945 static void blackjack_savegame(struct game_context* bj) {
946 int fd;
948 if(!resume)
949 return;
950 /* write out the game state to the save file */
951 fd = rb->open(SAVE_FILE, O_WRONLY|O_CREAT, 0666);
952 if(fd < 0)
953 return;
954 rb->write(fd, bj, sizeof(struct game_context));
955 rb->close(fd);
958 /*****************************************************************************
959 * blackjack_get_yes_no() gets a yes/no answer from the user
960 ******************************************************************************/
961 static unsigned int blackjack_get_yes_no(char message[20]) {
962 int button;
963 unsigned int w, h, b, choice = 0;
964 bool breakout = false;
965 char message_yes[24], message_no[24];
967 rb->strcpy(message_yes, message);
968 rb->strcpy(message_no, message);
969 rb->strcat(message_yes, " Yes");
970 rb->strcat(message_no, " No");
971 rb->lcd_getstringsize(message_yes, &w, &h);
972 const char *stg[] = {message_yes, message_no};
974 #if LCD_HEIGHT <= 64 || LCD_WIDTH <= 96
975 b = 2*h+1;
976 #else
977 b = h-1;
978 #endif
980 #ifdef HAVE_LCD_COLOR
981 rb->lcd_fillrect(LCD_WIDTH/2 - w/2, LCD_HEIGHT/2 + b, w+1, h+3);
982 rb->lcd_set_foreground(LCD_BLACK);
983 rb->lcd_set_background(LCD_WHITE);
984 #else
985 rb->lcd_set_drawmode(DRMODE_BG+DRMODE_INVERSEVID);
986 rb->lcd_fillrect(LCD_WIDTH/2 - w/2, LCD_HEIGHT/2 + b, w+1, h+3);
987 rb->lcd_set_drawmode(DRMODE_SOLID);
988 #endif
989 rb->lcd_drawrect(LCD_WIDTH/2 - w/2 - 1, LCD_HEIGHT/2 + b - 1, w+3, h+4);
991 while(!breakout) {
992 rb->lcd_putsxy(LCD_WIDTH/2 - w/2, LCD_HEIGHT/2 + b +1, stg[choice]);
993 rb->lcd_update_rect(LCD_WIDTH/2 - w/2 - 1, LCD_HEIGHT/2 + b -1,
994 w+3, h+4);
995 button = rb->button_get(true);
997 switch(button) {
998 case BJACK_LEFT:
999 case (BJACK_LEFT|BUTTON_REPEAT):
1000 case BJACK_RIGHT:
1001 case (BJACK_RIGHT|BUTTON_REPEAT):
1002 choice ^= 1;
1003 break;
1004 case BJACK_SELECT: breakout = true;
1005 break;
1006 case BJACK_QUIT: breakout = true;
1007 choice = 1;
1008 break;
1012 #if LCD_DEPTH > 1
1013 rb->lcd_set_foreground(FG_COLOR);
1014 rb->lcd_set_background(BG_COLOR);
1015 #endif
1016 return choice;
1019 /*****************************************************************************
1020 * blackjack_get_amount() gets an amount from the player to be used
1021 ******************************************************************************/
1022 static signed int blackjack_get_amount(const char message[20],
1023 signed int lower_limit,
1024 signed int upper_limit,
1025 signed int start) {
1026 int button;
1027 bool breakout = false, changed = false;
1028 unsigned int w, h;
1029 signed int amount;
1031 rb->lcd_getstringsize("A", &w, &h); /* find the size of one character */
1033 if (start > upper_limit)
1034 amount = upper_limit;
1035 else if (start < lower_limit)
1036 amount = lower_limit;
1037 else
1038 amount = start;
1040 #if LCD_DEPTH > 1
1041 rb->lcd_set_background(LCD_WHITE);
1042 rb->lcd_set_foreground(LCD_BLACK);
1043 #endif
1045 #if LCD_HEIGHT <= 64 || LCD_WIDTH <= 96
1046 rb->lcd_clear_display();
1047 rb->lcd_puts(0, 1, message);
1048 rb->lcd_putsf(0, 2, "$%d", amount);
1049 rb->lcd_puts(0, 3, "RIGHT: +1");
1050 rb->lcd_puts(0, 4, "LEFT: -1");
1051 rb->lcd_puts(0, 5, "UP: +10");
1052 rb->lcd_puts(0, 6, "DOWN: -10");
1053 rb->lcd_update();
1054 #else
1055 rb->lcd_set_drawmode(DRMODE_BG+DRMODE_INVERSEVID);
1056 rb->lcd_fillrect(LCD_WIDTH/2 - 9*w - 1, LCD_HEIGHT/2 - 4*h - 3,
1057 37*w / 2, 8*h -3);
1058 rb->lcd_set_drawmode(DRMODE_SOLID);
1059 rb->lcd_drawrect(LCD_WIDTH/2 - 9*w - 1, LCD_HEIGHT/2 - 4*h - 3,
1060 37*w / 2, 8*h -3);
1061 rb->lcd_putsxy(LCD_WIDTH/2 - 9*w, LCD_HEIGHT/2 - 4*h - 1, message);
1062 rb->lcd_putsxyf(LCD_WIDTH/2 - 9*w, LCD_HEIGHT/2 - 3*h, "$%d", amount);
1063 #if (CONFIG_KEYPAD == IPOD_4G_PAD) || \
1064 (CONFIG_KEYPAD == IPOD_3G_PAD) || \
1065 (CONFIG_KEYPAD == IPOD_1G2G_PAD) || \
1066 (CONFIG_KEYPAD == SANSA_E200_PAD) || \
1067 (CONFIG_KEYPAD == SANSA_FUZE_PAD) || \
1068 (CONFIG_KEYPAD == SANSA_CONNECT_PAD) || \
1069 (CONFIG_KEYPAD == MPIO_HD300_PAD)
1070 rb->lcd_putsxy(LCD_WIDTH/2 - 9*w, LCD_HEIGHT/2 - h-2, " >>|: +1");
1071 rb->lcd_putsxy(LCD_WIDTH/2 - 9*w, LCD_HEIGHT/2 - 1, " |<<: -1");
1072 rb->lcd_putsxy(LCD_WIDTH/2 - 9*w, LCD_HEIGHT/2 + h, "SCROLL+: +10");
1073 rb->lcd_putsxy(LCD_WIDTH/2 - 9*w, LCD_HEIGHT/2 + 2*h + 1, "SCROLL-: -10");
1074 #elif CONFIG_KEYPAD == IRIVER_H10_PAD
1075 rb->lcd_putsxy(LCD_WIDTH/2 - 9*w, LCD_HEIGHT/2 - h-2, "RIGHT: +1");
1076 rb->lcd_putsxy(LCD_WIDTH/2 - 9*w, LCD_HEIGHT/2 - 1, "LEFT: -1");
1077 rb->lcd_putsxy(LCD_WIDTH/2 - 9*w, LCD_HEIGHT/2 + h, "SCROLL+: +10");
1078 rb->lcd_putsxy(LCD_WIDTH/2 - 9*w, LCD_HEIGHT/2 + 2*h + 1, "SCROLL-: -10");
1079 #else
1080 rb->lcd_putsxy(LCD_WIDTH/2 - 9*w, LCD_HEIGHT/2 - h-2, "RIGHT: +1");
1081 rb->lcd_putsxy(LCD_WIDTH/2 - 9*w, LCD_HEIGHT/2 - 1, "LEFT: -1");
1082 rb->lcd_putsxy(LCD_WIDTH/2 - 9*w, LCD_HEIGHT/2 + h, "UP: +10");
1083 rb->lcd_putsxy(LCD_WIDTH/2 - 9*w, LCD_HEIGHT/2 + 2*h + 1, "DOWN: -10");
1084 #endif
1085 rb->lcd_update_rect(LCD_WIDTH/2 - 9*w - 1, LCD_HEIGHT/2 - 4*h - 3,
1086 37*w / 2, 8*h -3);
1087 #endif
1089 while(!breakout) {
1090 button = rb->button_get(true);
1092 switch(button) {
1093 case BJACK_UP:
1094 case (BJACK_UP|BUTTON_REPEAT):
1095 if (amount + 10 < upper_limit + 1) {
1096 amount += 10;
1097 changed = true;
1099 break;
1100 case BJACK_DOWN:
1101 case (BJACK_DOWN|BUTTON_REPEAT):
1102 if (amount - 10 > lower_limit - 1) {
1103 amount -= 10;
1104 changed = true;
1106 break;
1107 case BJACK_RIGHT:
1108 case (BJACK_RIGHT|BUTTON_REPEAT):
1109 if (amount + 1 < upper_limit + 1) {
1110 amount++;
1111 changed = true;
1113 break;
1114 case BJACK_LEFT:
1115 case (BJACK_LEFT|BUTTON_REPEAT):
1116 if (amount - 1 > lower_limit - 1) {
1117 amount--;
1118 changed = true;
1120 break;
1121 #ifdef BJACK_MAX
1122 case BJACK_MAX :
1123 amount = upper_limit;
1124 changed = true;
1125 break;
1126 #endif
1127 #ifdef BJACK_MIN
1128 case BJACK_MIN :
1129 amount = lower_limit;
1130 changed = true;
1131 break;
1132 #endif
1133 case BJACK_QUIT:
1134 breakout = true;
1135 amount = 0;
1136 break;
1137 case BJACK_SELECT:
1138 breakout = true;
1139 break;
1142 if(changed) {
1143 #if LCD_HEIGHT <= 64 || LCD_WIDTH <= 96
1144 rb->lcd_putsf(0, 2, "$%d", amount);
1145 rb->lcd_update();
1146 #else
1147 rb->lcd_set_drawmode(DRMODE_BG+DRMODE_INVERSEVID);
1148 rb->lcd_fillrect(LCD_WIDTH/2 - 9*w, LCD_HEIGHT/2 - 3*h, 5*w, h);
1149 rb->lcd_set_drawmode(DRMODE_SOLID);
1150 rb->lcd_putsxyf(LCD_WIDTH/2 - 9*w, LCD_HEIGHT/2 - 3*h, "$%d", amount);
1151 rb->lcd_update_rect(LCD_WIDTH/2 - 9*w, LCD_HEIGHT/2 - 3*h, 5*w, h);
1152 #endif
1153 changed = false;
1157 #if LCD_DEPTH > 1
1158 rb->lcd_set_foreground(FG_COLOR);
1159 rb->lcd_set_background(BG_COLOR);
1160 #endif
1161 rb->lcd_clear_display();
1162 return amount;
1165 /*****************************************************************************
1166 * blackjack_get_bet() gets the player's bet.
1167 ******************************************************************************/
1168 static void blackjack_get_bet(struct game_context* bj) {
1169 #if LCD_WIDTH <= 96
1170 static const char msg[] = "Enter a bet";
1171 #else
1172 static const char msg[] = "Please enter a bet";
1173 #endif
1174 bj->current_bet = blackjack_get_amount(msg, 10,
1175 bj->player_money, bj->current_bet);
1178 /*****************************************************************************
1179 * double_down() returns one final card then finishes the game
1180 ******************************************************************************/
1181 static void double_down(struct game_context* bj) {
1182 bj->current_bet *= 2;
1183 bj->player_cards[0][bj->num_player_cards[0]] = new_card();
1184 bj->player_total += bj->player_cards[0][bj->num_player_cards[0]].value;
1185 bj->num_player_cards[0]++;
1188 /*****************************************************************************
1189 * split() checks if the player wants to split and acts accordingly.
1190 * When bj->split_status is 1, no split occurred. 2 means the player split and 3
1191 * means a split has already occurred and the first hand is done.
1192 ******************************************************************************/
1193 static void split(struct game_context* bj) {
1194 if (blackjack_get_yes_no("Split?") != 0)
1195 bj->split_status = 1;
1196 else {
1197 bj->split_status = 2;
1198 bj->current_bet *= 2;
1199 bj->num_player_cards[0] = 1;
1200 bj->num_player_cards[1] = 1;
1201 bj->player_cards[1][0] = bj->player_cards[0][1];
1202 bj->player_total = bj->player_cards[0][0].value;
1206 /*****************************************************************************
1207 * insurance() see if the player wants to buy insurance and how much.
1208 ******************************************************************************/
1209 static unsigned int insurance(struct game_context* bj) {
1210 unsigned int insurance, max_amount;
1212 insurance = blackjack_get_yes_no("Buy Insurance?");
1213 bj->asked_insurance = true;
1214 max_amount = bj->current_bet < (unsigned int)bj->player_money ?
1215 bj->current_bet/2 : (unsigned int)bj->player_money;
1216 if (insurance != 0) return 0;
1218 insurance = blackjack_get_amount("How much?", 0, max_amount, 0);
1219 redraw_board(bj);
1220 return insurance;
1223 /*****************************************************************************
1224 * play_again() checks to see if the player wants to keep playing.
1225 ******************************************************************************/
1226 static unsigned int play_again(void) {
1227 return blackjack_get_yes_no("Play Again?");
1230 /*****************************************************************************
1231 * blackjack_help() displays help text.
1232 ******************************************************************************/
1233 static bool blackjack_help(void) {
1234 static char *help_text[] = {
1235 "Blackjack", "", "Aim", "",
1236 "Try", "to", "get", "as", "close", "to", "21", "without", "going",
1237 "over", "or", "simply", "beat", "out", "the", "dealer", "for", "the",
1238 "best", "hand.", "", "",
1239 "Controls", "",
1240 BJACK_SELECT_NAME, ":", "hit", "/", "select", "",
1241 BJACK_STAY_NAME, ":", "stay", "",
1242 BJACK_DOUBLE_NAME, ":", "double", "down", "",
1243 BJACK_QUIT_NAME, ":", "go", "to", "menu", "",
1245 static struct style_text formation[]={
1246 { 0, TEXT_CENTER|TEXT_UNDERLINE },
1247 { 2, C_RED },
1248 { 26, C_RED },
1249 LAST_STYLE_ITEM
1252 rb->lcd_setfont(FONT_UI);
1253 #ifdef HAVE_LCD_COLOR
1254 rb->lcd_set_background(LCD_BLACK);
1255 rb->lcd_set_foreground(LCD_WHITE);
1256 #endif
1257 if (display_text(ARRAYLEN(help_text), help_text, formation, NULL, true))
1258 return true;
1259 rb->lcd_setfont(FONT_SYSFIXED);
1261 return false;
1264 static int blackjack_menu_cb(int action, const struct menu_item_ex *this_item)
1266 int i = ((intptr_t)this_item);
1267 if(action == ACTION_REQUEST_MENUITEM
1268 && !resume && (i==0 || i==5))
1269 return ACTION_EXIT_MENUITEM;
1270 return action;
1273 /*****************************************************************************
1274 * blackjack_menu() is the initial menu at the start of the game.
1275 ******************************************************************************/
1276 static unsigned int blackjack_menu(void) {
1277 int selection = 0;
1278 bool breakout = false;
1280 MENUITEM_STRINGLIST(menu, "BlackJack Menu", blackjack_menu_cb,
1281 "Resume Game", "Start New Game",
1282 "High Scores", "Help",
1283 "Playback Control",
1284 "Quit without Saving", "Quit");
1286 while(!breakout) {
1287 switch(rb->do_menu(&menu, &selection, NULL, false)) {
1288 case 0:
1289 breakout = true;
1290 if(resume_file)
1291 rb->remove(SAVE_FILE);
1292 resume_file = false;
1293 break;
1294 case 1:
1295 breakout = true;
1296 resume = false;
1297 break;
1298 case 2:
1299 highscore_show(-1, highscores, NUM_SCORES, false);
1300 break;
1301 case 3:
1302 if(blackjack_help())
1303 return BJ_USB;
1304 break;
1305 case 4:
1306 if (playback_control(NULL))
1307 return BJ_USB;
1308 break;
1309 case 5:
1310 return BJ_QUIT_WITHOUT_SAVING;
1311 case 6:
1312 if (resume)
1313 return BJ_QUIT;
1314 else
1315 return BJ_QUIT_WITHOUT_SAVING;
1317 case MENU_ATTACHED_USB:
1318 return BJ_USB;
1320 default:
1321 break;
1325 return 0;
1328 /*****************************************************************************
1329 * blackjack() is the main game subroutine, it returns the final game status.
1330 ******************************************************************************/
1331 static int blackjack(struct game_context* bj) {
1332 int button;
1333 unsigned int w, h, temp_var, done = 0, todo = 1;
1334 signed int temp;
1335 bool breakout = false;
1336 bool dbl_down = false;
1338 /********************
1339 * menu *
1340 ********************/
1341 temp_var = blackjack_menu();
1342 if (temp_var != 0)
1343 return temp_var;
1345 #if LCD_DEPTH > 1
1346 rb->lcd_set_background(BG_COLOR);
1347 rb->lcd_set_foreground(FG_COLOR);
1348 #endif
1350 /********************
1351 * init *
1352 ********************/
1353 blackjack_init(bj);
1355 /********************
1356 * play *
1357 ********************/
1359 resume_file = false;
1360 /* check for resumed game */
1361 if(resume) {
1362 resume = false;
1363 redraw_board(bj);
1364 if (bj->split_status == 2) {
1365 todo=2;
1366 player_x = bj->num_player_cards[0] * 10 + 4;
1368 else if (bj->split_status == 3) {
1369 player_x = bj->num_player_cards[1] * 10 + LCD_WIDTH/2 + 4;
1370 todo=2;
1371 done=1;
1374 else {
1375 bj->player_money = 1000;
1376 bj->current_bet = 10;
1377 blackjack_get_bet(bj);
1378 if (bj->current_bet == 0)
1379 return -1;
1380 rb->lcd_clear_display();
1381 deal_init_cards(bj);
1382 blackjack_drawtable(bj);
1385 rb->lcd_update();
1387 breakout = false;
1389 while(true){
1390 if(bj->player_total == 21 && bj->num_player_cards[0] == 2) {
1391 bj->is_blackjack = true;
1392 bj->end_hand = true;
1393 finish_game(bj);
1395 else if(bj->dealer_cards[1].is_soft_ace && !breakout &&
1396 !bj->asked_insurance) {
1397 temp_var = insurance(bj);
1398 if (bj->dealer_total == 21) {
1399 rb->splash(HZ, "Dealer has blackjack");
1400 bj->player_money += temp_var;
1401 bj->end_hand = true;
1402 breakout = true;
1403 redraw_board(bj);
1404 finish_game(bj);
1406 else {
1407 rb->splash(HZ, "Dealer does not have blackjack");
1408 bj->player_money -= temp_var;
1409 breakout = true;
1410 redraw_board(bj);
1411 rb->lcd_update();
1414 if(!bj->end_hand && bj->split_status == 0 &&
1415 bj->player_cards[0][0].num == bj->player_cards[0][1].num) {
1416 split(bj);
1417 redraw_board(bj);
1418 rb->lcd_update_rect(0, LCD_HEIGHT/2, LCD_WIDTH, LCD_HEIGHT/2);
1419 if (bj->split_status == 2) {
1420 todo++;
1421 player_x = bj->num_player_cards[0] * 10 + 4;
1425 while(!bj->end_hand && done < todo) {
1426 button = rb->button_get(true);
1428 switch(button) {
1429 case BJACK_SELECT:
1430 NEXT_CARD = new_card();
1431 bj->player_total += NEXT_CARD.value;
1432 draw_card(NEXT_CARD, true, player_x, player_y);
1433 bj->num_player_cards[done]++;
1434 if (bj->num_player_cards[done] == MAX_CARDS + 1) {
1435 redraw_board(bj);
1436 rb->lcd_update_rect(0, LCD_HEIGHT/2, LCD_WIDTH,
1437 LCD_HEIGHT/2);
1439 else if (bj->num_player_cards[done]>MAX_CARDS || todo > 1) {
1440 rb->lcd_update_rect(player_x, player_y, CARD_WIDTH+2,
1441 CARD_HEIGHT+2);
1442 player_x += 10;
1444 else {
1445 rb->lcd_update_rect(player_x, player_y, CARD_WIDTH+2,
1446 CARD_HEIGHT+2);
1447 player_x += CARD_WIDTH + 4;
1449 update_total(bj);
1451 break;
1452 case BJACK_STAY:
1453 bj->end_hand = true;
1454 break;
1455 case BJACK_DOUBLEDOWN:
1456 if ((signed int)bj->current_bet * 2 <
1457 bj->player_money + 1 &&
1458 bj->num_player_cards[0]==2 && todo==1) {
1459 double_down(bj);
1460 dbl_down = true;
1461 if (bj->player_total < 22) {
1462 bj->end_hand = true;
1463 finish_game(bj);
1466 else if((signed int)bj->current_bet * 2 >
1467 bj->player_money){
1468 rb->splash(HZ, "Not enough money to double down.");
1469 redraw_board(bj);
1470 rb->lcd_update();
1472 break;
1474 case BJACK_QUIT:
1475 resume = true;
1476 return BJ_END;
1479 while (bj->player_total > 21 && !bj->end_hand) {
1480 temp = check_for_aces(bj->player_cards[done],
1481 bj->num_player_cards[done]);
1482 if(temp != -1) {
1483 bj->player_cards[done][temp].is_soft_ace = false;
1484 bj->player_total -= 10;
1485 update_total(bj);
1486 if (dbl_down) {
1487 bj->end_hand = true;
1488 finish_game(bj);
1491 else
1492 bj->end_hand = true;
1495 if (bj->end_hand) {
1496 done++;
1497 if(todo > 1) {
1498 if (done == 2) {
1499 temp = bj->player_total;
1500 bj->player_total = temp_var;
1501 temp_var = temp;
1502 finish_game(bj);
1503 rb->lcd_getstringsize(" Split 1 ", &w, &h);
1504 rb->lcd_putsxy(LCD_WIDTH/2-w/2, LCD_HEIGHT/2-3*h/2,
1505 " Split 1 ");
1506 rb->lcd_update_rect(LCD_WIDTH/2-w/2, LCD_HEIGHT/2-3*h/2,
1507 w,h);
1508 bj->current_bet /= 2;
1509 rb->lcd_update_rect(LCD_WIDTH/2-w/2, LCD_HEIGHT/2-3*h/2,
1510 w,h);
1511 rb->sleep(HZ*2);
1512 bj->player_total = temp_var;
1513 finish_game(bj);
1514 rb->lcd_getstringsize(" Split 2 ", &w, &h);
1515 rb->lcd_putsxy(LCD_WIDTH/2-w/2, LCD_HEIGHT/2-3*h/2,
1516 " Split 2 ");
1517 rb->lcd_update_rect(LCD_WIDTH/2-w/2, LCD_HEIGHT/2-3*h/2,
1518 w,h);
1519 rb->sleep(HZ*2);
1521 else {
1522 bj->end_hand = false;
1523 bj->split_status = 3;
1524 temp_var = bj->player_total;
1525 bj->player_total = bj->player_cards[1][0].value;
1526 update_total(bj);
1527 redraw_board(bj);
1528 player_x += 10;
1529 rb->lcd_update();
1532 else
1533 finish_game(bj);
1537 if (bj->player_money < 10) {
1538 rb->sleep(HZ);
1539 return BJ_LOSE;
1542 if (bj->end_hand) { /* If hand is over */
1543 if (play_again() != 0) /* User wants to quit */
1544 return BJ_END;
1545 else { /* User keeps playing */
1546 breakout = false;
1547 temp = bj->current_bet;
1548 bj->current_bet = 0;
1549 redraw_board(bj);
1550 rb->lcd_update();
1551 bj->current_bet = temp;
1552 if(dbl_down) {
1553 bj->current_bet /= 2;
1554 dbl_down = false;
1556 done = 0;
1557 todo = 1;
1558 blackjack_init(bj);
1559 blackjack_get_bet(bj);
1560 if (bj->current_bet == 0)
1561 return BJ_END;
1562 deal_init_cards(bj);
1563 blackjack_drawtable(bj);
1564 rb->lcd_update();
1568 /* Never reached */
1569 return PLUGIN_OK;
1572 /*****************************************************************************
1573 * plugin entry point.
1574 ******************************************************************************/
1575 enum plugin_status plugin_start(const void* parameter)
1577 struct game_context bj;
1578 bool exit = false;
1580 (void)parameter;
1582 #if LCD_DEPTH > 1
1583 rb->lcd_set_backdrop(NULL);
1584 #endif
1586 /* load high scores */
1587 highscore_load(SCORE_FILE, highscores, NUM_SCORES);
1588 resume = blackjack_loadgame(&bj);
1589 resume_file = resume;
1591 rb->lcd_setfont(FONT_SYSFIXED);
1593 while(!exit) {
1594 switch(blackjack(&bj)){
1595 case BJ_LOSE:
1596 rb->splash(HZ, "Not enough money to continue");
1597 /* fall through to BJ_END */
1599 case BJ_END:
1600 if(!resume && bj.player_money > 10) {
1601 /* There is no level, so store -1 to blank column */
1602 int position = highscore_update(bj.player_money, -1, "",
1603 highscores, NUM_SCORES);
1604 if (position != -1)
1606 if (position==0)
1607 rb->splash(HZ*2, "New High Score");
1608 highscore_show(position, highscores, NUM_SCORES, false);
1611 break;
1613 case BJ_USB:
1614 highscore_save(SCORE_FILE, highscores, NUM_SCORES);
1615 return PLUGIN_USB_CONNECTED;
1617 case BJ_QUIT:
1618 rb->splash(HZ*1, "Saving game...");
1619 blackjack_savegame(&bj);
1620 /* fall through */
1622 case BJ_QUIT_WITHOUT_SAVING:
1623 exit = true;
1624 break;
1626 default:
1627 break;
1630 highscore_save(SCORE_FILE, highscores, NUM_SCORES);
1631 return PLUGIN_OK;