1 /***************************************************************************
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
10 * Copyright (C) 2006 Will Robertson
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 "lib/playback_control.h"
23 #include "lib/display_text.h"
24 #include "pluginbitmaps/superdom_boarditems.h"
27 extern const fb_data superdom_boarditems
[];
31 #define COLOUR_LIGHT 1
36 #define MY_BITMAP_PART rb->lcd_bitmap_transparent_part
38 #define MY_BITMAP_PART rb->lcd_mono_bitmap_part
41 #if LCD_WIDTH > LCD_HEIGHT
42 #define BOX_WIDTH ((LCD_WIDTH-(MARGIN*2))/10)
43 #define BOX_HEIGHT ((BOX_WIDTH*2)/3)
46 #define BOX_HEIGHT ((LCD_HEIGHT-(MARGIN*2)-15)/10)
47 #define BOX_WIDTH ((BOX_HEIGHT*2)/3)
51 /* NUM_BOX HEIGHT and WIDTH are used for the number pad in the game. The height
52 * calculation includes spacing for the text placed above and below the number
53 * pad (it divides by 6 instead of just 4). The width calculation gives extra
54 * spacing on the sides of the pad too (divides by 5 instead of 3).
56 #define NUM_BOX_HEIGHT (LCD_HEIGHT/6)
57 #define NUM_BOX_WIDTH (LCD_WIDTH/5)
59 #define NUM_MARGIN_X (LCD_WIDTH-3*NUM_BOX_WIDTH)/2
60 #define NUM_MARGIN_Y (LCD_HEIGHT-4*NUM_BOX_HEIGHT)/2
62 /* These parameters define the piece image dimensions, Stride is the total width
65 #define ICON_STRIDE STRIDE(SCREEN_MAIN, BMPWIDTH_superdom_boarditems, BMPHEIGHT_superdom_boarditems)
66 #define ICON_HEIGHT (BMPHEIGHT_superdom_boarditems/6)
67 #define ICON_WIDTH (BMPWIDTH_superdom_boarditems/2)
69 #if (CONFIG_KEYPAD == IPOD_4G_PAD) || (CONFIG_KEYPAD == IPOD_3G_PAD) || \
70 (CONFIG_KEYPAD == IPOD_1G2G_PAD)
71 #define SUPERDOM_OK BUTTON_SELECT
72 #define SUPERDOM_CANCEL BUTTON_MENU
73 #define SUPERDOM_LEFT BUTTON_LEFT
74 #define SUPERDOM_RIGHT BUTTON_RIGHT
77 #elif CONFIG_KEYPAD == IRIVER_H300_PAD || CONFIG_KEYPAD == IRIVER_H100_PAD
78 #define SUPERDOM_OK BUTTON_SELECT
79 #define SUPERDOM_LEFT BUTTON_LEFT
80 #define SUPERDOM_RIGHT BUTTON_RIGHT
81 #define SUPERDOM_UP BUTTON_UP
82 #define SUPERDOM_DOWN BUTTON_DOWN
83 #define SUPERDOM_CANCEL BUTTON_OFF
85 #elif CONFIG_KEYPAD == IAUDIO_X5M5_PAD
86 #define SUPERDOM_OK BUTTON_SELECT
87 #define SUPERDOM_LEFT BUTTON_LEFT
88 #define SUPERDOM_RIGHT BUTTON_RIGHT
89 #define SUPERDOM_UP BUTTON_UP
90 #define SUPERDOM_DOWN BUTTON_DOWN
91 #define SUPERDOM_CANCEL BUTTON_REC
93 #elif CONFIG_KEYPAD == IRIVER_H10_PAD
94 #define SUPERDOM_OK BUTTON_RIGHT
95 #define SUPERDOM_UP BUTTON_SCROLL_UP
96 #define SUPERDOM_DOWN BUTTON_SCROLL_DOWN
97 #define SUPERDOM_CANCEL BUTTON_LEFT
99 #elif CONFIG_KEYPAD == GIGABEAT_PAD
100 #define SUPERDOM_OK BUTTON_SELECT
101 #define SUPERDOM_UP BUTTON_UP
102 #define SUPERDOM_DOWN BUTTON_DOWN
103 #define SUPERDOM_LEFT BUTTON_LEFT
104 #define SUPERDOM_RIGHT BUTTON_RIGHT
105 #define SUPERDOM_CANCEL BUTTON_POWER
107 #elif CONFIG_KEYPAD == SANSA_E200_PAD
108 #define SUPERDOM_OK BUTTON_SELECT
109 #define SUPERDOM_UP BUTTON_SCROLL_BACK
110 #define SUPERDOM_DOWN BUTTON_SCROLL_FWD
111 #define SUPERDOM_LEFT BUTTON_LEFT
112 #define SUPERDOM_RIGHT BUTTON_RIGHT
113 #define SUPERDOM_CANCEL BUTTON_POWER
115 #elif CONFIG_KEYPAD == SANSA_FUZE_PAD
116 #define SUPERDOM_OK BUTTON_SELECT
117 #define SUPERDOM_UP BUTTON_SCROLL_BACK
118 #define SUPERDOM_DOWN BUTTON_SCROLL_FWD
119 #define SUPERDOM_LEFT BUTTON_LEFT
120 #define SUPERDOM_RIGHT BUTTON_RIGHT
121 #define SUPERDOM_CANCEL (BUTTON_HOME|BUTTON_REPEAT)
123 #elif CONFIG_KEYPAD == GIGABEAT_S_PAD || \
124 CONFIG_KEYPAD == SAMSUNG_YPR0_PAD
125 #define SUPERDOM_OK BUTTON_SELECT
126 #define SUPERDOM_UP BUTTON_UP
127 #define SUPERDOM_DOWN BUTTON_DOWN
128 #define SUPERDOM_LEFT BUTTON_LEFT
129 #define SUPERDOM_RIGHT BUTTON_RIGHT
130 #define SUPERDOM_CANCEL BUTTON_BACK
132 #elif CONFIG_KEYPAD == COWON_D2_PAD
133 #define SUPERDOM_CANCEL BUTTON_POWER
135 #elif CONFIG_KEYPAD == CREATIVEZVM_PAD
136 #define SUPERDOM_OK BUTTON_SELECT
137 #define SUPERDOM_UP BUTTON_UP
138 #define SUPERDOM_DOWN BUTTON_DOWN
139 #define SUPERDOM_LEFT BUTTON_LEFT
140 #define SUPERDOM_RIGHT BUTTON_RIGHT
141 #define SUPERDOM_CANCEL BUTTON_BACK
143 #elif CONFIG_KEYPAD == PHILIPS_HDD6330_PAD
144 #define SUPERDOM_OK BUTTON_PLAY
145 #define SUPERDOM_UP BUTTON_UP
146 #define SUPERDOM_DOWN BUTTON_DOWN
147 #define SUPERDOM_LEFT BUTTON_PREV
148 #define SUPERDOM_RIGHT BUTTON_NEXT
149 #define SUPERDOM_CANCEL BUTTON_LEFT
151 #elif CONFIG_KEYPAD == PHILIPS_SA9200_PAD
152 #define SUPERDOM_OK BUTTON_PLAY
153 #define SUPERDOM_UP BUTTON_UP
154 #define SUPERDOM_DOWN BUTTON_DOWN
155 #define SUPERDOM_LEFT BUTTON_PREV
156 #define SUPERDOM_RIGHT BUTTON_NEXT
157 #define SUPERDOM_CANCEL BUTTON_LEFT
159 #elif (CONFIG_KEYPAD == ONDAVX747_PAD) || (CONFIG_KEYPAD == MROBE500_PAD)
160 #define SUPERDOM_CANCEL BUTTON_POWER
162 #elif CONFIG_KEYPAD == SAMSUNG_YH_PAD
163 #define SUPERDOM_OK BUTTON_PLAY
164 #define SUPERDOM_UP BUTTON_UP
165 #define SUPERDOM_DOWN BUTTON_DOWN
166 #define SUPERDOM_LEFT BUTTON_LEFT
167 #define SUPERDOM_RIGHT BUTTON_RIGHT
168 #define SUPERDOM_CANCEL BUTTON_REW
170 #elif CONFIG_KEYPAD == PBELL_VIBE500_PAD
171 #define SUPERDOM_OK BUTTON_OK
172 #define SUPERDOM_UP BUTTON_UP
173 #define SUPERDOM_DOWN BUTTON_DOWN
174 #define SUPERDOM_LEFT BUTTON_PREV
175 #define SUPERDOM_RIGHT BUTTON_NEXT
176 #define SUPERDOM_CANCEL BUTTON_CANCEL
178 #elif CONFIG_KEYPAD == MPIO_HD300_PAD
179 #define SUPERDOM_OK BUTTON_ENTER
180 #define SUPERDOM_UP BUTTON_UP
181 #define SUPERDOM_DOWN BUTTON_DOWN
182 #define SUPERDOM_LEFT BUTTON_REW
183 #define SUPERDOM_RIGHT BUTTON_FF
184 #define SUPERDOM_CANCEL BUTTON_MENU
186 #elif CONFIG_KEYPAD == SANSA_FUZEPLUS_PAD
187 #define SUPERDOM_OK BUTTON_SELECT
188 #define SUPERDOM_UP BUTTON_UP
189 #define SUPERDOM_DOWN BUTTON_DOWN
190 #define SUPERDOM_LEFT BUTTON_LEFT
191 #define SUPERDOM_RIGHT BUTTON_RIGHT
192 #define SUPERDOM_CANCEL BUTTON_BACK
194 #elif CONFIG_KEYPAD == SANSA_CONNECT_PAD
195 #define SUPERDOM_OK BUTTON_SELECT
196 #define SUPERDOM_UP BUTTON_UP
197 #define SUPERDOM_DOWN BUTTON_DOWN
198 #define SUPERDOM_LEFT BUTTON_LEFT
199 #define SUPERDOM_RIGHT BUTTON_RIGHT
200 #define SUPERDOM_CANCEL BUTTON_POWER
202 #elif (CONFIG_KEYPAD == HM60X_PAD) || \
203 (CONFIG_KEYPAD == HM801_PAD)
204 #define SUPERDOM_OK BUTTON_SELECT
205 #define SUPERDOM_UP BUTTON_UP
206 #define SUPERDOM_DOWN BUTTON_DOWN
207 #define SUPERDOM_LEFT BUTTON_LEFT
208 #define SUPERDOM_RIGHT BUTTON_RIGHT
209 #define SUPERDOM_CANCEL BUTTON_POWER
213 #ifdef HAVE_TOUCHSCREEN
215 #define SUPERDOM_OK BUTTON_CENTER
218 #define SUPERDOM_UP BUTTON_TOPMIDDLE
220 #ifndef SUPERDOM_LEFT
221 #define SUPERDOM_LEFT BUTTON_MIDLEFT
223 #ifndef SUPERDOM_RIGHT
224 #define SUPERDOM_RIGHT BUTTON_MIDRIGHT
226 #ifndef SUPERDOM_DOWN
227 #define SUPERDOM_DOWN BUTTON_BOTTOMMIDDLE
229 #ifndef SUPERDOM_CANCEL
230 #define SUPERDOM_CANCEL BUTTON_TOPLEFT
237 RET_VAL_QUIT_ERR
, /* quit or error */
240 static void gen_interest(void);
241 static void init_resources(void);
242 static int select_square(void);
243 static void update_score(void);
244 static void gen_resources(void);
245 static void draw_cursor(void);
246 static void draw_board(void);
249 signed int colour
; /* -1 = Unset */
271 static struct settings
{
281 static struct resources humanres
;
282 static struct resources compres
;
283 enum { GS_PROD
, GS_MOVE
, GS_WAR
};
284 static int gamestate
;
286 static struct cursor
{
291 static struct tile board
[12][12];
293 static void init_board(void) {
295 rb
->srand(*rb
->current_tick
);
296 for(i
=0;i
<12;i
++) { /* Hopefully about 50% each colour */
298 if((i
<1)||(j
<1)||(i
>10)||(j
>10))
299 board
[i
][j
].colour
= -1; /* Unset */
301 board
[i
][j
].colour
= rb
->rand()%2;
302 board
[i
][j
].tank
= false;
303 board
[i
][j
].plane
= false;
304 board
[i
][j
].nuke
= false;
305 board
[i
][j
].ind
= false;
306 board
[i
][j
].farm
= false;
311 while(compres
.farms
< superdom_settings
.compstartfarms
) {
312 i
= rb
->rand()%10 + 1;
313 j
= rb
->rand()%10 + 1;
314 if((board
[i
][j
].colour
== COLOUR_DARK
) && (board
[i
][j
].farm
== false)) {
315 board
[i
][j
].farm
= true;
319 while(compres
.inds
< superdom_settings
.compstartinds
) {
320 i
= rb
->rand()%10 + 1;
321 j
= rb
->rand()%10 + 1;
322 if((board
[i
][j
].colour
== COLOUR_DARK
) && (board
[i
][j
].ind
== false)) {
323 board
[i
][j
].ind
= true;
327 while(humanres
.farms
< superdom_settings
.humanstartfarms
) {
328 i
= rb
->rand()%10 + 1;
329 j
= rb
->rand()%10 + 1;
330 if((board
[i
][j
].colour
== COLOUR_LIGHT
)&&(board
[i
][j
].farm
== false)) {
331 board
[i
][j
].farm
= true;
335 while(humanres
.inds
< superdom_settings
.humanstartinds
) {
336 i
= rb
->rand()%10 + 1;
337 j
= rb
->rand()%10 + 1;
338 if((board
[i
][j
].colour
== COLOUR_LIGHT
) && (board
[i
][j
].ind
== false)) {
339 board
[i
][j
].ind
= true;
345 void draw_board(void) {
347 rb
->lcd_clear_display();
350 if(board
[i
][j
].colour
== COLOUR_DARK
) {
351 rb
->lcd_set_foreground(LCD_DARKGRAY
);
353 rb
->lcd_set_foreground(LCD_LIGHTGRAY
);
355 rb
->lcd_fillrect(MARGIN
+(BOX_WIDTH
*(i
-1)),
356 MARGIN
+(BOX_HEIGHT
*(j
-1)), BOX_WIDTH
,
359 rb
->lcd_set_drawmode(DRMODE_BG
| DRMODE_INVERSEVID
);
361 if(board
[i
][j
].ind
) {
362 MY_BITMAP_PART(superdom_boarditems
,
363 board
[i
][j
].colour
?ICON_WIDTH
:0, 0, ICON_STRIDE
,
364 #if LCD_WIDTH > LCD_HEIGHT
365 MARGIN
+(BOX_WIDTH
*(i
-1))+1,
366 MARGIN
+(BOX_HEIGHT
*(j
-1))+ICON_HEIGHT
+1,
368 MARGIN
+(BOX_WIDTH
*(i
-1))+1+ICON_WIDTH
,
369 MARGIN
+(BOX_HEIGHT
*(j
-1))+1,
371 ICON_WIDTH
, ICON_HEIGHT
);
373 if(board
[i
][j
].farm
) {
374 MY_BITMAP_PART(superdom_boarditems
,
375 board
[i
][j
].colour
?ICON_WIDTH
:0, ICON_HEIGHT
,
376 ICON_STRIDE
, MARGIN
+(BOX_WIDTH
*(i
-1))+1,
377 MARGIN
+(BOX_HEIGHT
*(j
-1))+1,
378 ICON_WIDTH
, ICON_HEIGHT
);
380 if(board
[i
][j
].tank
) {
381 MY_BITMAP_PART(superdom_boarditems
,
382 board
[i
][j
].colour
?ICON_WIDTH
:0, ICON_HEIGHT
*2,
383 ICON_STRIDE
, MARGIN
+(BOX_WIDTH
*(i
-1))+ICON_WIDTH
+1,
384 MARGIN
+(BOX_HEIGHT
*(j
-1))+ICON_HEIGHT
+1,
385 ICON_WIDTH
, ICON_HEIGHT
);
387 if(board
[i
][j
].men
) {
388 MY_BITMAP_PART(superdom_boarditems
,
389 board
[i
][j
].colour
?ICON_WIDTH
:0, ICON_HEIGHT
*3,
390 #if LCD_WIDTH > LCD_HEIGHT
391 ICON_STRIDE
, MARGIN
+(BOX_WIDTH
*(i
-1))+ICON_WIDTH
+1,
392 MARGIN
+(BOX_HEIGHT
*(j
-1))+1,
394 ICON_STRIDE
, MARGIN
+(BOX_WIDTH
*(i
-1))+1,
395 MARGIN
+(BOX_HEIGHT
*(j
-1))+1+ICON_HEIGHT
,
397 ICON_WIDTH
, ICON_HEIGHT
);
399 if(board
[i
][j
].plane
) {
400 MY_BITMAP_PART(superdom_boarditems
,
401 board
[i
][j
].colour
?ICON_WIDTH
:0, ICON_HEIGHT
*4,
402 #if LCD_WIDTH > LCD_HEIGHT
403 ICON_STRIDE
,MARGIN
+(BOX_WIDTH
*(i
-1))+ICON_WIDTH
*2+1,
404 MARGIN
+(BOX_HEIGHT
*(j
-1))+ICON_HEIGHT
+1,
406 ICON_STRIDE
,MARGIN
+(BOX_WIDTH
*(i
-1))+ICON_WIDTH
+1,
407 MARGIN
+(BOX_HEIGHT
*(j
-1))+ICON_HEIGHT
*2+1,
409 ICON_WIDTH
, ICON_HEIGHT
);
411 if(board
[i
][j
].nuke
) {
412 MY_BITMAP_PART(superdom_boarditems
,
413 board
[i
][j
].colour
?ICON_WIDTH
:0, ICON_HEIGHT
*5,
414 #if LCD_WIDTH > LCD_HEIGHT
415 ICON_STRIDE
,MARGIN
+(BOX_WIDTH
*(i
-1))+ICON_WIDTH
*2+1,
416 MARGIN
+(BOX_HEIGHT
*(j
-1))+1,
418 ICON_STRIDE
,MARGIN
+(BOX_WIDTH
*(i
-1))+1,
419 MARGIN
+(BOX_HEIGHT
*(j
-1))+ICON_HEIGHT
*2+1,
421 ICON_WIDTH
, ICON_HEIGHT
);
424 rb
->lcd_set_drawmode(DRMODE_SOLID
);
428 rb
->lcd_set_foreground(LCD_BLACK
);
429 for(i
=0;i
<=10;i
++) { /* Draw Horizontal lines */
430 rb
->lcd_hline(MARGIN
, MARGIN
+(BOX_WIDTH
*10), MARGIN
+(BOX_HEIGHT
*i
));
432 for(i
=0;i
<=10;i
++) { /* Draw Vertical lines */
433 rb
->lcd_vline(MARGIN
+(BOX_WIDTH
*i
), MARGIN
, MARGIN
+(BOX_HEIGHT
*10));
438 static int calc_strength(int colour
, int x
, int y
) {
440 for (a
= -1; a
< 2; a
++) {
441 for (b
= -1; b
< 2; b
++) {
442 if ((b
== 0 || a
== 0) &&
443 (board
[x
+ a
][y
+ b
].colour
== colour
)) {
445 if(board
[x
+ a
][y
+ b
].tank
|| board
[x
+ a
][y
+ b
].farm
)
447 if(board
[x
+ a
][y
+ b
].plane
|| board
[x
+ a
][y
+ b
].ind
)
449 if(board
[x
+ a
][y
+ b
].nuke
)
451 if(board
[x
+ a
][y
+ b
].men
)
452 score
+= (board
[x
+ a
][y
+ b
].men
*133/1000);
459 void gen_interest(void) {
460 /* Interest should be around 10% */
461 rb
->srand(*rb
->current_tick
);
462 int interest
= 7+rb
->rand()%6;
463 humanres
.bank
= humanres
.bank
+(interest
*humanres
.bank
/100);
464 compres
.bank
= compres
.bank
+(interest
*compres
.bank
/100);
467 void draw_cursor(void) {
468 rb
->lcd_set_drawmode(DRMODE_COMPLEMENT
);
469 rb
->lcd_fillrect(MARGIN
+((cursor
.x
-1)*BOX_WIDTH
),
470 MARGIN
+((cursor
.y
-1)*BOX_HEIGHT
), BOX_WIDTH
+1, BOX_HEIGHT
+1);
471 rb
->lcd_set_drawmode(DRMODE_SOLID
);
475 void gen_resources(void) {
482 rb
->srand(*rb
->current_tick
);
483 /* Generate Human's resources */
484 for(i
=0;i
<humanres
.inds
;i
++) {
485 inccash
+= (300+rb
->rand()%200);
487 for(i
=0;i
<humanres
.farms
;i
++) {
488 incfood
+= (200+rb
->rand()%200);
491 ratecash
= inccash
/humanres
.inds
;
493 ratefood
= incfood
/humanres
.farms
;
496 rb
->splash(HZ
*2, "Patriotism sweeps the land, all production"
497 " is up this year!");
499 rb
->splash(HZ
*2, "Factories working at maximum efficiency,"
500 " cash production up this year!");
502 } else if(ratecash
> 350) {
504 rb
->splash(HZ
*2, "Record crop harvest this year!");
505 } else if(ratefood
> 250) {
506 rb
->splash(HZ
*2, "Production continues as normal");
508 rb
->splash(HZ
*2, "Spoilage of crops leads to reduced farm"
509 " output this year");
513 rb
->splash(HZ
*2, "Record crop harvest this year!");
514 } else if(ratefood
> 250) {
515 rb
->splash(HZ
*2, "Factory unions introduced. Industrial"
516 " production is down this year.");
518 rb
->splash(HZ
*2, "Internet created. All production is down"
519 " due to time wasted.");
522 humanres
.cash
+= inccash
;
523 humanres
.food
+= incfood
;
525 /* Generate Computer's resources */
528 for(i
=0;i
<compres
.inds
;i
++) {
529 inccash
+= (300+rb
->rand()%200);
531 for(i
=0;i
<compres
.farms
;i
++) {
532 incfood
+= (200+rb
->rand()%200);
534 compres
.cash
+= inccash
;
535 compres
.food
+= incfood
;
538 static void update_score(void) {
540 rb
->lcd_setfont(FONT_SYSFIXED
);
541 rb
->lcd_set_drawmode(DRMODE_BG
|DRMODE_INVERSEVID
);
542 rb
->lcd_fillrect(5,LCD_HEIGHT
-20,105,20);
543 rb
->lcd_set_drawmode(DRMODE_SOLID
);
544 strength
= calc_strength(COLOUR_LIGHT
, cursor
.x
, cursor
.y
);
545 rb
->lcd_putsxyf(5,LCD_HEIGHT
-20,"Your power: %d.%d",strength
/10,strength
%10);
546 strength
= calc_strength(COLOUR_DARK
, cursor
.x
, cursor
.y
);
547 rb
->lcd_putsxyf(5,LCD_HEIGHT
-10,"Comp power: %d.%d",strength
/10,strength
%10);
548 rb
->lcd_setfont(FONT_UI
);
551 static int settings_menu(void) {
554 MENUITEM_STRINGLIST(menu
, "Super Domination Settings", NULL
,
555 "Computer starting farms", "Computer starting factories",
556 "Human starting farms", "Human starting factories",
557 "Starting cash", "Starting food", "Moves per turn");
560 switch(rb
->do_menu(&menu
, &selection
, NULL
, false)) {
562 rb
->set_int("Computer starting farms", "", UNIT_INT
,
563 &superdom_settings
.compstartfarms
, NULL
,
567 rb
->set_int("Computer starting factories", "", UNIT_INT
,
568 &superdom_settings
.compstartinds
, NULL
,
572 rb
->set_int("Human starting farms", "", UNIT_INT
,
573 &superdom_settings
.humanstartfarms
, NULL
,
577 rb
->set_int("Human starting factories", "", UNIT_INT
,
578 &superdom_settings
.humanstartinds
, NULL
,
582 rb
->set_int("Starting cash", "", UNIT_INT
,
583 &superdom_settings
.startcash
, NULL
,
587 rb
->set_int("Starting food", "", UNIT_INT
,
588 &superdom_settings
.startfood
, NULL
,
592 rb
->set_int("Moves per turn", "", UNIT_INT
,
593 &superdom_settings
.movesperturn
, NULL
,
596 case MENU_ATTACHED_USB
:
607 static int superdom_help(void) {
608 static char* help_text
[] = {
609 "Super", "domination", "is", "a", "turn", "based", "strategy", "game,",
610 "where", "the", "aim", "is", "to", "overpower", "the", "computer",
611 "player", "by", "taking", "their", "territory.", "",
612 "Each", "year", "you", "are", "allocated", "an", "amount", "of", "cash",
613 "and", "food,", "depending", "on", "how", "many", "farms", "and",
614 "factories", "you", "control.", "",
615 "Use", "this", "cash", "and", "food", "to", "buy", "and", "feed", "your",
616 "army.", "Each", "tile", "has", "a", "strength,", "calculated", "by",
617 "the", "ownership", "of", "adjacent", "tiles,", "and", "the", "type",
618 "and", "number", "of", "troops", "on", "them.",
621 if (display_text(ARRAYLEN(help_text
), help_text
, NULL
, NULL
, true))
626 static int start_menu(void) {
629 MENUITEM_STRINGLIST(menu
, "Super Domination Menu", NULL
,
630 "Play Super Domination", "Settings",
631 "Help", "Playback Control", "Quit");
634 switch(rb
->do_menu(&menu
, &selection
, NULL
, false)) {
636 return RET_VAL_OK
; /* start playing */
639 if(settings_menu()==RET_VAL_USB
)
643 if(superdom_help()==RET_VAL_USB
)
647 if(playback_control(NULL
))
651 return RET_VAL_QUIT_ERR
;
655 return RET_VAL_QUIT_ERR
;
658 static int save_game(void) {
660 char savepath
[MAX_PATH
];
662 rb
->snprintf(savepath
, sizeof(savepath
), "/Savegame.ssg");
663 if(rb
->kbd_input(savepath
, MAX_PATH
)) {
664 DEBUGF("Keyboard input failed\n");
668 fd
= rb
->open(savepath
, O_WRONLY
|O_CREAT
, 0666);
669 DEBUGF("savepath: %s\n", savepath
);
671 DEBUGF("Couldn't create/open file\n");
675 rb
->write(fd
, "SSGv3", 5);
676 rb
->write(fd
, &gamestate
, sizeof(gamestate
));
677 rb
->write(fd
, &humanres
.cash
, sizeof(humanres
.cash
));
678 rb
->write(fd
, &humanres
.food
, sizeof(humanres
.food
));
679 rb
->write(fd
, &humanres
.bank
, sizeof(humanres
.bank
));
680 rb
->write(fd
, &humanres
.planes
, sizeof(humanres
.planes
));
681 rb
->write(fd
, &humanres
.tanks
, sizeof(humanres
.tanks
));
682 rb
->write(fd
, &humanres
.men
, sizeof(humanres
.men
));
683 rb
->write(fd
, &humanres
.nukes
, sizeof(humanres
.nukes
));
684 rb
->write(fd
, &humanres
.inds
, sizeof(humanres
.inds
));
685 rb
->write(fd
, &humanres
.farms
, sizeof(humanres
.farms
));
686 rb
->write(fd
, &humanres
.moves
, sizeof(humanres
.moves
));
687 rb
->write(fd
, &compres
.cash
, sizeof(compres
.cash
));
688 rb
->write(fd
, &compres
.food
, sizeof(compres
.food
));
689 rb
->write(fd
, &compres
.bank
, sizeof(compres
.bank
));
690 rb
->write(fd
, &compres
.planes
, sizeof(compres
.planes
));
691 rb
->write(fd
, &compres
.tanks
, sizeof(compres
.tanks
));
692 rb
->write(fd
, &compres
.men
, sizeof(compres
.men
));
693 rb
->write(fd
, &compres
.nukes
, sizeof(compres
.nukes
));
694 rb
->write(fd
, &compres
.inds
, sizeof(compres
.inds
));
695 rb
->write(fd
, &compres
.farms
, sizeof(compres
.farms
));
696 rb
->write(fd
, &compres
.moves
, sizeof(compres
.moves
));
697 rb
->write(fd
, board
, sizeof(board
));
698 rb
->write(fd
, &superdom_settings
.compstartfarms
, sizeof(int));
699 rb
->write(fd
, &superdom_settings
.compstartinds
, sizeof(int));
700 rb
->write(fd
, &superdom_settings
.humanstartfarms
, sizeof(int));
701 rb
->write(fd
, &superdom_settings
.humanstartinds
, sizeof(int));
702 rb
->write(fd
, &superdom_settings
.startcash
, sizeof(int));
703 rb
->write(fd
, &superdom_settings
.startfood
, sizeof(int));
704 rb
->write(fd
, &superdom_settings
.movesperturn
, sizeof(int));
709 static int ingame_menu(void) {
710 MENUITEM_STRINGLIST(menu
, "Super Domination Menu", NULL
,
711 "Return to game", "Save Game",
712 "Playback Control", "Quit");
714 switch(rb
->do_menu(&menu
, NULL
, NULL
, false)) {
720 rb
->splash(HZ
, "Game saved");
722 rb
->splash(HZ
, "Error in save");
725 if(playback_control(NULL
))
729 return RET_VAL_QUIT_ERR
;
731 case MENU_ATTACHED_USB
:
741 static int get_number(char* param
, int* value
, int max
) {
742 static const char *button_labels
[4][3] = {
750 int button
= 0, ret
= RET_VAL_OK
;
752 rb
->lcd_clear_display();
753 rb
->lcd_getstringsize("CLR", &width
, &height
);
754 if(width
> NUM_BOX_WIDTH
|| height
> NUM_BOX_HEIGHT
)
755 rb
->lcd_setfont(FONT_SYSFIXED
);
756 /* Draw a 3x4 grid */
757 for(i
=0;i
<=3;i
++) { /* Vertical lines */
758 rb
->lcd_vline(NUM_MARGIN_X
+(NUM_BOX_WIDTH
*i
), NUM_MARGIN_Y
,
759 NUM_MARGIN_Y
+(4*NUM_BOX_HEIGHT
));
761 for(i
=0;i
<=4;i
++) { /* Horizontal lines */
762 rb
->lcd_hline(NUM_MARGIN_X
, NUM_MARGIN_X
+(3*NUM_BOX_WIDTH
),
763 NUM_MARGIN_Y
+(NUM_BOX_HEIGHT
*i
));
767 rb
->lcd_getstringsize(button_labels
[i
][j
], &width
, &height
);
769 NUM_MARGIN_X
+(j
*NUM_BOX_WIDTH
)+NUM_BOX_WIDTH
/2-width
/2,
770 NUM_MARGIN_Y
+(i
*NUM_BOX_HEIGHT
)+NUM_BOX_HEIGHT
/2-height
/2,
771 button_labels
[i
][j
]);
774 rb
->lcd_putsxyf(NUM_MARGIN_X
+10, NUM_MARGIN_Y
+4*NUM_BOX_HEIGHT
+10,"%d",*value
);
775 rb
->lcd_getstringsize(param
, &width
, &height
);
776 if(width
< LCD_WIDTH
)
777 rb
->lcd_putsxy((LCD_WIDTH
-width
)/2, (NUM_MARGIN_Y
-height
)/2, param
);
779 rb
->lcd_puts_scroll(0, (NUM_MARGIN_Y
/height
-1)/2, param
);
780 rb
->lcd_set_drawmode(DRMODE_COMPLEMENT
);
781 rb
->lcd_fillrect(NUM_MARGIN_X
+(NUM_BOX_WIDTH
*x
),
782 NUM_MARGIN_Y
+(NUM_BOX_HEIGHT
*y
),
783 NUM_BOX_WIDTH
+1, NUM_BOX_HEIGHT
+1);
784 rb
->lcd_set_drawmode(DRMODE_SOLID
);
787 button
= rb
->button_get(true);
788 rb
->lcd_set_drawmode(DRMODE_COMPLEMENT
);
789 rb
->lcd_fillrect(NUM_MARGIN_X
+(NUM_BOX_WIDTH
*x
),
790 NUM_MARGIN_Y
+(NUM_BOX_HEIGHT
*y
),
791 NUM_BOX_WIDTH
+1, NUM_BOX_HEIGHT
+1);
792 rb
->lcd_set_drawmode(DRMODE_SOLID
);
797 *value
+= button_labels
[y
][x
][0] - '0';
806 if ((unsigned) *value
> (unsigned) max
)
808 rb
->lcd_set_drawmode(DRMODE_BG
|DRMODE_INVERSEVID
);
809 rb
->lcd_fillrect(0, NUM_MARGIN_Y
+4*NUM_BOX_HEIGHT
+10,
811 rb
->lcd_set_drawmode(DRMODE_SOLID
);
812 rb
->lcd_putsxyf(NUM_MARGIN_X
+10,NUM_MARGIN_Y
+4*NUM_BOX_HEIGHT
+10,
815 case SUPERDOM_CANCEL
:
818 ret
= RET_VAL_QUIT_ERR
;
820 #if CONFIG_KEYPAD != IRIVER_H10_PAD
851 #if CONFIG_KEYPAD == IRIVER_H10_PAD
864 #if CONFIG_KEYPAD == IRIVER_H10_PAD
877 if (rb
->default_event_handler(button
) == SYS_USB_CONNECTED
)
884 rb
->lcd_set_drawmode(DRMODE_COMPLEMENT
);
885 rb
->lcd_fillrect(NUM_MARGIN_X
+(NUM_BOX_WIDTH
*x
),
886 NUM_MARGIN_Y
+(NUM_BOX_HEIGHT
*y
),
887 NUM_BOX_WIDTH
+1, NUM_BOX_HEIGHT
+1);
888 rb
->lcd_set_drawmode(DRMODE_SOLID
);
891 rb
->lcd_setfont(FONT_UI
);
892 rb
->lcd_stop_scroll();
893 if (ret
== RET_VAL_QUIT_ERR
)
894 rb
->splash(HZ
, "Cancelled");
898 static bool tile_has_item(int type
, int x
, int y
) {
901 return (board
[x
][y
].men
> 0);
904 return board
[x
][y
].tank
;
907 return board
[x
][y
].plane
;
910 return board
[x
][y
].farm
;
913 return board
[x
][y
].ind
;
916 return board
[x
][y
].nuke
;
922 static int buy_resources(int colour
, int type
, int x
, int y
, int nummen
) {
923 const char *itemnames
[][6] = {
929 "the industrial plant",
936 "build an industrial plant",
943 "an industrial plant",
948 bool human
= (colour
== COLOUR_LIGHT
);
951 struct resources
*res
;
971 case 4: /* Factory */
978 if(res
->cash
< price
) {
980 rb
->splash(HZ
, "Not enough money!");
981 return RET_VAL_QUIT_ERR
;
984 rb
->splashf(HZ
, "Where do you want to place %s?", itemnames
[0][type
]);
985 if((temp
= select_square()) != RET_VAL_OK
)
990 if(board
[x
][y
].colour
!= colour
) {
992 rb
->splashf(HZ
, "Can't %s on enemy territory", itemnames
[1][type
]);
993 return RET_VAL_QUIT_ERR
;
995 if(type
!= 0 && tile_has_item(type
, x
, y
)) {
997 rb
->splashf(HZ
, "There is already %s there", itemnames
[2][type
]);
998 return RET_VAL_QUIT_ERR
;
1002 board
[x
][y
].men
+= nummen
;
1006 board
[x
][y
].tank
= true;
1010 board
[x
][y
].plane
= true;
1014 board
[x
][y
].farm
= true;
1018 board
[x
][y
].ind
= true;
1022 board
[x
][y
].nuke
= true;
1034 static int buy_resources_menu(void) {
1035 int selection
= 0,nummen
;
1037 MENUITEM_STRINGLIST(menu
, "Buy Resources", NULL
,
1038 "Buy men ($1)", "Buy tank ($300)", "Buy plane ($600)",
1039 "Buy Farm ($1150)", "Buy Factory ($1300)",
1044 switch(rb
->do_menu(&menu
, &selection
, NULL
, false)) {
1047 if(get_number("How many men would you like?", &nummen
,
1048 humanres
.cash
) == RET_VAL_USB
)
1058 if(buy_resources(COLOUR_LIGHT
, selection
, 0, 0, nummen
)
1065 case MENU_ATTACHED_USB
:
1068 case GO_TO_PREVIOUS
:
1076 static int move_unit(int colour
, int type
, int fromx
, int fromy
,
1077 int tox
, int toy
, int nummen
) {
1078 const char *itemnames
[][3] = {
1093 bool human
= (colour
== COLOUR_LIGHT
);
1097 rb
->splashf(HZ
, "Select where you want to move %s from",
1098 itemnames
[0][type
]);
1099 if((temp
= select_square()) != RET_VAL_OK
)
1104 if(board
[fromx
][fromy
].colour
!= colour
) {
1106 rb
->splash(HZ
, "That isn't your territory");
1107 return RET_VAL_QUIT_ERR
;
1109 if(!tile_has_item(type
, fromx
, fromy
)) {
1111 rb
->splashf(HZ
, "You don't have %s there", itemnames
[1][type
]);
1112 return RET_VAL_QUIT_ERR
;
1116 nummen
= board
[fromx
][fromy
].men
;
1117 if((temp
= get_number("How many men do you want to move?", &nummen
,
1118 nummen
)) != RET_VAL_OK
)
1121 if(nummen
> board
[fromx
][fromy
].men
) {
1123 rb
->splash(HZ
, "You don't have that many troops.");
1124 return RET_VAL_QUIT_ERR
;
1128 rb
->splashf(HZ
, "Select where you want to move %s to",
1129 itemnames
[2][type
]);
1130 if((temp
= select_square()) != RET_VAL_OK
)
1135 if((tox
== fromx
&& toy
== fromy
) ||
1136 board
[tox
][toy
].colour
!= colour
||
1137 (type
!= 2 && (abs(tox
- fromx
) > 1 || abs(toy
- fromy
) > 1))) {
1139 rb
->splash(HZ
, "Invalid move");
1140 return RET_VAL_QUIT_ERR
;
1142 if(type
!= 0 && tile_has_item(type
, tox
, toy
)) {
1144 rb
->splashf(HZ
, "There is already %s there", itemnames
[1][type
]);
1145 return RET_VAL_QUIT_ERR
;
1149 board
[fromx
][fromy
].men
-= nummen
;
1150 board
[tox
][toy
].men
+= nummen
;
1153 board
[fromx
][fromy
].tank
= false;
1154 board
[tox
][toy
].tank
= true;
1157 board
[fromx
][fromy
].plane
= false;
1158 board
[tox
][toy
].plane
= true;
1164 static int move_unit_menu(void) {
1167 MENUITEM_STRINGLIST(menu
, "Move unit", NULL
,
1168 "Move men", "Move tank", "Move plane");
1169 switch(rb
->do_menu(&menu
, &selection
, NULL
, false)) {
1173 switch(move_unit(COLOUR_LIGHT
, selection
, 0, 0, 0, 0, 0)) {
1182 case MENU_ATTACHED_USB
:
1188 static int launch_nuke(int colour
, int nukex
, int nukey
, int targetx
, int targety
) {
1189 bool human
= (colour
== COLOUR_LIGHT
);
1191 struct resources
*res
;
1193 if(board
[nukex
][nukey
].colour
!= colour
) {
1195 rb
->splash(HZ
, "That isn't your territory");
1196 return RET_VAL_QUIT_ERR
;
1198 if(! board
[nukex
][nukey
].nuke
) {
1200 rb
->splashf(HZ
, "You don't have %s there", "a nuke");
1201 return RET_VAL_QUIT_ERR
;
1204 rb
->splash(HZ
, "Select place to target with nuke");
1205 if((temp
= select_square()) != RET_VAL_OK
)
1215 board
[nukex
][nukey
].nuke
= false;
1217 if(board
[targetx
][targety
].colour
== COLOUR_LIGHT
) {
1222 res
->men
-= board
[targetx
][targety
].men
;
1223 res
->tanks
-= board
[targetx
][targety
].tank
;
1224 res
->planes
-= board
[targetx
][targety
].plane
;
1225 res
->nukes
-= board
[targetx
][targety
].nuke
;
1226 res
->farms
-= board
[targetx
][targety
].farm
;
1227 res
->inds
-= board
[targetx
][targety
].ind
;
1228 board
[targetx
][targety
].men
= 0;
1229 board
[targetx
][targety
].tank
= false;
1230 board
[targetx
][targety
].plane
= false;
1231 board
[targetx
][targety
].ind
= false;
1232 board
[targetx
][targety
].nuke
= false;
1233 board
[targetx
][targety
].farm
= false;
1234 /* TODO: Fallout carried by wind */
1239 static int movement_menu(void) {
1240 int selection
= 0, temp
;
1242 MENUITEM_STRINGLIST(menu
, "Movement", NULL
,
1243 "Move unit", "Buy additional moves ($100)",
1244 "Launch nuclear missile", "Check map",
1245 "Finish moving", "Game menu");
1248 switch(rb
->do_menu(&menu
, &selection
, NULL
, false)) {
1250 if(humanres
.moves
) {
1251 if(move_unit_menu()==RET_VAL_USB
)
1254 rb
->splash(HZ
, "You have no more moves left."
1255 " You can buy more for $100 each.");
1259 if(humanres
.cash
> 100) {
1261 humanres
.cash
-= 100;
1262 rb
->snprintf(buf
, sizeof(buf
), "You now have %d moves",
1264 rb
->splash(HZ
, buf
);
1268 if(humanres
.nukes
==0) {
1269 rb
->splash(HZ
, "You do not have any nukes to launch");
1271 rb
->splash(HZ
, "Select place to launch nuke from");
1272 switch(select_square()) {
1274 if(launch_nuke(COLOUR_LIGHT
, cursor
.x
, cursor
.y
,
1275 0, 0) == RET_VAL_USB
)
1285 if(select_square() == RET_VAL_USB
)
1292 if((temp
= ingame_menu()) != RET_VAL_OK
)
1295 case MENU_ATTACHED_USB
:
1303 static const char* inventory_data(int selected_item
, void * data
,
1304 char * buffer
, size_t buffer_len
) {
1306 switch(selected_item
) {
1308 rb
->snprintf(buffer
,buffer_len
,"Men: %d", humanres
.men
);
1311 rb
->snprintf(buffer
,buffer_len
,"Tanks: %d", humanres
.tanks
);
1314 rb
->snprintf(buffer
,buffer_len
,"Planes: %d", humanres
.planes
);
1317 rb
->snprintf(buffer
,buffer_len
,"Factories: %d", humanres
.inds
);
1320 rb
->snprintf(buffer
,buffer_len
,"Farms: %d", humanres
.farms
);
1323 rb
->snprintf(buffer
,buffer_len
,"Nukes: %d", humanres
.nukes
);
1326 rb
->snprintf(buffer
,buffer_len
,"Cash: %d", humanres
.cash
);
1329 rb
->snprintf(buffer
,buffer_len
,"Food: %d", humanres
.food
);
1332 rb
->snprintf(buffer
,buffer_len
,"Bank: %d", humanres
.bank
);
1340 static int show_inventory(void) {
1341 struct simplelist_info info
;
1342 rb
->simplelist_info_init(&info
, "Inventory", 9, NULL
);
1343 info
.hide_selection
= true;
1344 info
.get_name
= inventory_data
;
1345 if(rb
->simplelist_show_list(&info
)) {
1352 static int production_menu(void) {
1353 int selection
= 0, temp
;
1355 MENUITEM_STRINGLIST(menu
, "Production", NULL
,
1356 "Buy resources", "Show inventory", "Check map",
1357 "Invest money", "Withdraw money",
1358 "Finish turn", "Game menu");
1361 switch(rb
->do_menu(&menu
, &selection
, NULL
, false)) {
1363 if(buy_resources_menu() == RET_VAL_USB
)
1367 if(show_inventory() == RET_VAL_USB
)
1371 if(select_square() == RET_VAL_USB
)
1375 temp
= humanres
.cash
;
1376 if(get_number("How much do you want to invest?", &temp
,
1377 humanres
.cash
) == RET_VAL_USB
)
1379 if(temp
> humanres
.cash
) {
1380 rb
->splash(HZ
, "You don't have that much cash to invest");
1382 humanres
.cash
-= temp
;
1383 humanres
.bank
+= temp
;
1387 temp
= humanres
.bank
;
1388 if(get_number("How much do you want to withdraw?", &temp
,
1389 humanres
.bank
) == RET_VAL_USB
)
1391 if(temp
> humanres
.bank
) {
1392 rb
->splash(HZ
, "You don't have that much cash to withdraw");
1394 humanres
.cash
+= temp
;
1395 humanres
.bank
-= temp
;
1402 if((temp
= ingame_menu()) != RET_VAL_OK
)
1405 case MENU_ATTACHED_USB
:
1413 static void init_resources(void) {
1414 humanres
.cash
= superdom_settings
.startcash
;
1415 humanres
.food
= superdom_settings
.startfood
;
1417 humanres
.planes
= 0;
1424 compres
.cash
= superdom_settings
.startcash
;
1425 compres
.food
= superdom_settings
.startfood
;
1436 static int select_square(void) {
1441 #if LCD_WIDTH >= 220
1442 rb
->lcd_setfont(FONT_SYSFIXED
);
1443 rb
->lcd_putsxyf(125, LCD_HEIGHT
-20,"Cash: %d", humanres
.cash
);
1444 rb
->lcd_putsxyf(125, LCD_HEIGHT
-10,"Food: %d", humanres
.food
);
1445 rb
->lcd_setfont(FONT_UI
);
1449 button
= rb
->button_get(true);
1451 case SUPERDOM_CANCEL
:
1452 rb
->splash(HZ
, "Cancelled");
1453 return RET_VAL_QUIT_ERR
;
1458 #if CONFIG_KEYPAD != IRIVER_H10_PAD
1460 case (SUPERDOM_LEFT
|BUTTON_REPEAT
):
1461 draw_cursor(); /* Deselect the current tile */
1476 case SUPERDOM_RIGHT
:
1477 case (SUPERDOM_RIGHT
|BUTTON_REPEAT
):
1478 draw_cursor(); /* Deselect the current tile */
1496 case (SUPERDOM_UP
|BUTTON_REPEAT
):
1497 draw_cursor(); /* Deselect the current tile */
1501 #if CONFIG_KEYPAD == IRIVER_H10_PAD
1513 case (SUPERDOM_DOWN
|BUTTON_REPEAT
):
1514 draw_cursor(); /* Deselect the current tile */
1518 #if CONFIG_KEYPAD == IRIVER_H10_PAD
1531 if (rb
->default_event_handler(button
) == SYS_USB_CONNECTED
)
1539 static int killmen(int colour
) {
1540 bool human
= (colour
== COLOUR_LIGHT
);
1544 percent
= (humanres
.food
*1000)/humanres
.men
;
1547 percent
= (compres
.food
*1000)/compres
.men
;
1553 if(board
[i
][j
].colour
== colour
) {
1554 int nummen
= ((board
[i
][j
].men
* percent
)/1000);
1555 menkilled
+= board
[i
][j
].men
- nummen
;
1556 board
[i
][j
].men
= nummen
;
1562 humanres
.men
-= menkilled
;
1564 compres
.men
-= menkilled
;
1568 /* return -1 if error, 1 if attack is succeeded, 0 otherwise */
1569 static int attack_territory(int colour
, int x
, int y
) {
1570 bool human
= (colour
== COLOUR_LIGHT
);
1573 if(board
[x
][y
].colour
== colour
) {
1575 rb
->splash(HZ
, "You can't attack your own territory");
1578 str_diff
= calc_strength(COLOUR_DARK
, x
, y
) -
1579 calc_strength(COLOUR_LIGHT
, x
, y
);
1581 str_diff
= -str_diff
;
1583 rb
->srand(*rb
->current_tick
);
1584 if(str_diff
> 0 || (str_diff
== 0 && rb
->rand()%2)) {
1585 struct resources
*offres
, *defres
;
1593 defres
->men
-= board
[x
][y
].men
;
1594 defres
->tanks
-= board
[x
][y
].tank
;
1595 defres
->planes
-= board
[x
][y
].plane
;
1596 defres
->nukes
-= board
[x
][y
].nuke
;
1597 defres
->farms
-= board
[x
][y
].farm
;
1598 defres
->inds
-= board
[x
][y
].ind
;
1599 offres
->farms
+= board
[x
][y
].farm
;
1600 offres
->inds
+= board
[x
][y
].ind
;
1601 board
[x
][y
].colour
= colour
;
1602 board
[x
][y
].men
= 0;
1603 board
[x
][y
].tank
= false;
1604 board
[x
][y
].plane
= false;
1605 board
[x
][y
].nuke
= false;
1614 rb
->splash(HZ
, "Your troops were unable to overcome"
1615 " the enemy troops");
1617 rb
->splash(HZ
*2, "The computer attempted to "
1618 "attack, but the invasion was"
1625 static int war_menu(void) {
1626 int selection
= 0, temp
;
1628 MENUITEM_STRINGLIST(menu
, "War!", NULL
,
1629 "Select territory to attack",
1630 "Finish turn", "Game menu");
1632 while(humanres
.moves
) {
1633 switch(rb
->do_menu(&menu
, &selection
, NULL
, false)) {
1635 switch(select_square()) {
1637 if(attack_territory(COLOUR_LIGHT
, cursor
.x
, cursor
.y
)
1650 if((temp
= ingame_menu()) != RET_VAL_OK
)
1664 static bool place_adjacent(bool tank
, int x
, int y
) {
1665 int type
= (tank
? 1: 2);
1666 if(!buy_resources(COLOUR_DARK
, type
, x
, y
, 0)) {
1669 if(!buy_resources(COLOUR_DARK
, type
, x
-1, y
, 0)) {
1672 if(!buy_resources(COLOUR_DARK
, type
, x
+1, y
, 0)) {
1675 if(!buy_resources(COLOUR_DARK
, type
, x
, y
-1, 0)) {
1678 if(!buy_resources(COLOUR_DARK
, type
, x
, y
+1, 0)) {
1684 static bool has_adjacent(int x
, int y
) {
1685 if((board
[x
][y
].colour
== COLOUR_LIGHT
) &&
1686 ((board
[x
-1][y
].colour
== COLOUR_DARK
) ||
1687 (board
[x
+1][y
].colour
== COLOUR_DARK
) ||
1688 (board
[x
][y
+1].colour
== COLOUR_DARK
) ||
1689 (board
[x
][y
-1].colour
== COLOUR_DARK
)))
1695 static void find_adjacent(int x
, int y
, int* adj_x
, int* adj_y
) {
1696 /* Finds adjacent squares, returning squares without tanks on them
1697 * in preference to those with them */
1698 if(board
[x
-1][y
].colour
== COLOUR_DARK
) {
1703 if(board
[x
+1][y
].colour
== COLOUR_DARK
) {
1708 if(board
[x
][y
-1].colour
== COLOUR_DARK
) {
1713 if(board
[x
][y
+1].colour
== COLOUR_DARK
) {
1720 static void computer_allocate(void) {
1721 /* Firstly, decide whether to go offensive or defensive.
1722 * This is primarily decided by the human player posing a threat to either
1723 * the computer's farms or factories */
1725 bool offensive
= true;
1726 struct threat threats
[4];
1728 int total_str_diff
= 0;
1729 int numterritory
= 0;
1732 struct threat targets
[2];
1736 compres
.cash
+= compres
.bank
;
1740 if(board
[i
][j
].colour
== COLOUR_DARK
) {
1742 str_diff
= calc_strength(COLOUR_LIGHT
,i
,j
) -
1743 calc_strength(COLOUR_DARK
,i
,j
);
1744 if(str_diff
> 0 && (board
[i
][j
].ind
|| board
[i
][j
].farm
)) {
1745 if(numthreats
< 3) {
1747 threats
[numthreats
].x
= i
;
1748 threats
[numthreats
].y
= j
;
1749 threats
[numthreats
].str_diff
= str_diff
;
1758 /* The AI is going to go straight for the throat here and attack
1759 * the player's farms and factories. The amount of cash
1760 * the AI has to spend will determine how many targets there are */
1761 if(compres
.cash
> 1200) {
1762 /* 1200 is a figure I pulled out of nowhere. Adjust as needed */
1767 /* Work out which target(s) to attack. They must have adjacent squares
1768 * owned by the computer. If none are found just place troops in
1769 * random places around the map until we run out of money */
1773 if(has_adjacent(i
,j
) &&
1774 (board
[i
][j
].ind
|| board
[i
][j
].farm
)) {
1778 targets
[k
].str_diff
=
1779 calc_strength(COLOUR_LIGHT
, i
, j
) -
1780 calc_strength(COLOUR_DARK
, i
, j
);
1788 /* No targets found! Randomly pick squares and if they're owned
1789 * by the computer then stick a tank on it. */
1790 rb
->srand(*rb
->current_tick
);
1791 while(compres
.cash
>= 300 && compres
.tanks
< numterritory
) {
1792 i
= rb
->rand()%10 + 1;
1793 j
= rb
->rand()%10 + 1;
1794 if(board
[i
][j
].colour
== COLOUR_DARK
) {
1795 buy_resources(COLOUR_DARK
, 1, i
, j
, 0);
1801 str_diff
= targets
[i
].str_diff
;
1802 while(str_diff
+ 20 > 0 && compres
.cash
> 0) {
1803 /* While we still need them keep placing men */
1804 if(!place_adjacent(true, targets
[i
].x
, targets
[i
].y
)) {
1805 find_adjacent(targets
[i
].x
, targets
[i
].y
,
1807 men_needed
= (str_diff
+ 20)*1000/133;
1808 if(compres
.cash
< men_needed
) {
1809 men_needed
= compres
.cash
;
1811 buy_resources(COLOUR_DARK
, 0, adj
.x
, adj
.y
,
1815 str_diff
= calc_strength(COLOUR_LIGHT
,
1816 targets
[i
].x
, targets
[i
].y
) -
1817 calc_strength(COLOUR_DARK
,
1818 targets
[i
].x
, targets
[i
].y
);
1823 /* Work out what to place on each square to defend it.
1824 * Tanks are preferential because they do not require food,
1825 * but if the budget is tight then we fall back onto troops.
1826 * Conversely if cash is not an issue and there are already tanks in
1827 * place planes will be deployed. We would like a margin of at least
1828 * 20 points to be safe. */
1830 for(i
=0;i
<numthreats
;i
++) {
1831 total_str_diff
+= threats
[i
].str_diff
;
1833 if((total_str_diff
+20)*10 > compres
.cash
) {
1834 /* Not enough cash to accomodate all threats using tanks alone -
1835 * use men as a backup */
1836 for(i
=0;i
<numthreats
;i
++) {
1837 men_needed
= ((threats
[i
].str_diff
+ 20)*1000)/133;
1838 if(compres
.cash
< men_needed
) {
1839 men_needed
= compres
.cash
;
1841 buy_resources(COLOUR_DARK
, 0, threats
[i
].x
, threats
[i
].y
,
1846 /* Enough money to pay their way by planes? */
1847 bool tank
= ((total_str_diff
+20)*15 >= compres
.cash
);
1848 for(i
=0;i
<numthreats
;i
++) {
1849 str_diff
= threats
[i
].str_diff
;
1850 while(str_diff
+ 20 > 0) {
1851 if(!place_adjacent(tank
, threats
[i
].x
, threats
[i
].y
)) {
1852 /* No room for any more planes or tanks, revert to
1854 find_adjacent(threats
[i
].x
, threats
[i
].y
,
1856 men_needed
= (str_diff
+ 20)*1000/133;
1857 if(compres
.cash
< men_needed
) {
1858 men_needed
= compres
.cash
;
1860 buy_resources(COLOUR_DARK
, 0, threats
[i
].x
,
1861 threats
[i
].y
, men_needed
);
1864 str_diff
= calc_strength(COLOUR_LIGHT
,
1865 threats
[i
].x
, threats
[i
].y
) -
1866 calc_strength(COLOUR_DARK
,
1867 threats
[i
].x
, threats
[i
].y
);
1872 compres
.bank
+= compres
.cash
;
1876 static int find_adj_target(int x
, int y
, struct cursor
* adj
) {
1877 /* Find a square next to a computer's farm or factory owned by the player
1878 * that is vulnerable. Return 1 on success, 0 otherwise */
1879 if(board
[x
+1][y
].colour
== COLOUR_LIGHT
&&
1880 calc_strength(COLOUR_LIGHT
,x
+1,y
)<=calc_strength(COLOUR_DARK
,x
+1,y
)) {
1885 if(board
[x
-1][y
].colour
== COLOUR_LIGHT
&&
1886 calc_strength(COLOUR_LIGHT
,x
-1,y
)<=calc_strength(COLOUR_DARK
,x
-1,y
)) {
1891 if(board
[x
][y
+1].colour
== COLOUR_LIGHT
&&
1892 calc_strength(COLOUR_LIGHT
,x
,y
+1)<=calc_strength(COLOUR_DARK
,x
,y
+1)) {
1897 if(board
[x
][y
-1].colour
== COLOUR_LIGHT
&&
1898 calc_strength(COLOUR_LIGHT
,x
,y
-1)<=calc_strength(COLOUR_DARK
,x
,y
-1)) {
1906 static void computer_war(void) {
1907 /* Work out where to attack - prioritise the defence of buildings */
1909 bool found_target
= true;
1912 while(found_target
) {
1913 found_target
= false;
1916 if((board
[i
][j
].colour
== COLOUR_DARK
) &&
1917 (board
[i
][j
].farm
|| board
[i
][j
].ind
) &&
1918 find_adj_target(i
, j
, &adj
)) {
1919 found_target
= true;
1920 if(attack_territory(COLOUR_DARK
, adj
.x
, adj
.y
) >= 0) {
1930 /* Defence stage done, move on to OFFENCE */
1931 found_target
= true;
1932 while(found_target
) {
1933 found_target
= false;
1936 if(board
[i
][j
].colour
== COLOUR_LIGHT
&&
1937 (board
[i
][j
].ind
|| board
[i
][j
].farm
) &&
1938 (calc_strength(COLOUR_DARK
, i
, j
) >=
1939 calc_strength(COLOUR_LIGHT
, i
, j
))) {
1940 found_target
= true;
1941 if(attack_territory(COLOUR_DARK
, i
, j
) >= 0) {
1951 /* Spend leftover moves wherever attacking randomly */
1952 found_target
= true;
1953 while(found_target
) {
1954 found_target
= false;
1957 if(board
[i
][j
].colour
== COLOUR_LIGHT
&&
1958 (calc_strength(COLOUR_DARK
, i
, j
) >=
1959 calc_strength(COLOUR_LIGHT
, i
, j
))) {
1960 found_target
= true;
1961 if(attack_territory(COLOUR_DARK
, i
, j
) >= 0) {
1973 static int load_game(const char* file
) {
1976 fd
= rb
->open(file
, O_RDONLY
);
1978 DEBUGF("Couldn't open savegame\n");
1981 rb
->read(fd
, buf
, 5);
1982 if(rb
->strcmp(buf
, "SSGv3")) {
1983 rb
->splash(HZ
, "Invalid/incompatible savegame");
1986 rb
->read(fd
, &gamestate
, sizeof(gamestate
));
1987 rb
->read(fd
, &humanres
.cash
, sizeof(humanres
.cash
));
1988 rb
->read(fd
, &humanres
.food
, sizeof(humanres
.food
));
1989 rb
->read(fd
, &humanres
.bank
, sizeof(humanres
.bank
));
1990 rb
->read(fd
, &humanres
.planes
, sizeof(humanres
.planes
));
1991 rb
->read(fd
, &humanres
.tanks
, sizeof(humanres
.tanks
));
1992 rb
->read(fd
, &humanres
.men
, sizeof(humanres
.men
));
1993 rb
->read(fd
, &humanres
.nukes
, sizeof(humanres
.nukes
));
1994 rb
->read(fd
, &humanres
.inds
, sizeof(humanres
.inds
));
1995 rb
->read(fd
, &humanres
.farms
, sizeof(humanres
.farms
));
1996 rb
->read(fd
, &humanres
.moves
, sizeof(humanres
.moves
));
1997 rb
->read(fd
, &compres
.cash
, sizeof(humanres
.cash
));
1998 rb
->read(fd
, &compres
.food
, sizeof(humanres
.food
));
1999 rb
->read(fd
, &compres
.bank
, sizeof(humanres
.bank
));
2000 rb
->read(fd
, &compres
.planes
, sizeof(humanres
.planes
));
2001 rb
->read(fd
, &compres
.tanks
, sizeof(humanres
.tanks
));
2002 rb
->read(fd
, &compres
.men
, sizeof(humanres
.men
));
2003 rb
->read(fd
, &compres
.nukes
, sizeof(humanres
.nukes
));
2004 rb
->read(fd
, &compres
.inds
, sizeof(humanres
.inds
));
2005 rb
->read(fd
, &compres
.farms
, sizeof(humanres
.farms
));
2006 rb
->read(fd
, &compres
.moves
, sizeof(humanres
.moves
));
2007 rb
->read(fd
, board
, sizeof(board
));
2008 rb
->read(fd
, &superdom_settings
.compstartfarms
, sizeof(int));
2009 rb
->read(fd
, &superdom_settings
.compstartinds
, sizeof(int));
2010 rb
->read(fd
, &superdom_settings
.humanstartfarms
, sizeof(int));
2011 rb
->read(fd
, &superdom_settings
.humanstartinds
, sizeof(int));
2012 rb
->read(fd
, &superdom_settings
.startcash
, sizeof(int));
2013 rb
->read(fd
, &superdom_settings
.startfood
, sizeof(int));
2014 rb
->read(fd
, &superdom_settings
.movesperturn
, sizeof(int));
2019 static void default_settings(void) {
2020 superdom_settings
.compstartfarms
= 1;
2021 superdom_settings
.compstartinds
= 1;
2022 superdom_settings
.humanstartfarms
= 2;
2023 superdom_settings
.humanstartinds
= 2;
2024 superdom_settings
.startcash
= 0;
2025 superdom_settings
.startfood
= 0;
2026 superdom_settings
.movesperturn
= 2;
2029 static int average_strength(int colour
) {
2030 /* This function calculates the average strength of the given player,
2031 * used to determine when the computer wins or loses. */
2036 if(board
[i
][j
].colour
!= -1) {
2037 totalpower
+= calc_strength(colour
, i
, j
);
2041 return totalpower
/100;
2044 enum plugin_status
plugin_start(const void* parameter
)
2047 rb
->lcd_set_backdrop(NULL
);
2048 rb
->lcd_set_foreground(LCD_BLACK
);
2049 rb
->lcd_set_background(LCD_WHITE
);
2056 if(load_game(parameter
) != 0) {
2057 DEBUGF("Loading failed, generating new game\n");
2076 switch(start_menu()) {
2077 case RET_VAL_OK
: /* start playing */
2079 case RET_VAL_QUIT_ERR
: /* quit */
2083 return PLUGIN_USB_CONNECTED
;
2092 int avg_str_diff
= (average_strength(COLOUR_LIGHT
) -
2093 average_strength(COLOUR_DARK
));
2094 if(avg_str_diff
> 15) {
2095 rb
->splash(HZ
*4, "The computer has surrendered. You win.");
2098 if(-avg_str_diff
> 15) {
2099 rb
->splash(HZ
*4, "Your army have suffered terrible morale from"
2100 " the bleak prospects of winning. You lose.");
2106 gamestate
= GS_PROD
;
2107 switch(production_menu()) {
2109 return PLUGIN_USB_CONNECTED
;
2111 case RET_VAL_QUIT_ERR
:
2115 computer_allocate();
2118 humanres
.moves
= superdom_settings
.movesperturn
;
2120 gamestate
= GS_MOVE
;
2121 switch(movement_menu()) {
2123 return PLUGIN_USB_CONNECTED
;
2125 case RET_VAL_QUIT_ERR
:
2131 if(humanres
.food
> humanres
.men
) {
2132 rb
->snprintf(buf
, sizeof(buf
), "Your men ate %d units of food",
2134 humanres
.food
-= humanres
.men
;
2136 rb
->snprintf(buf
, sizeof(buf
), "There was not enough food"
2137 " to feed all your men, %d men have died of starvation",
2138 killmen(COLOUR_LIGHT
));
2140 rb
->splash(HZ
*2, buf
);
2143 if(compres
.food
> compres
.men
) {
2144 compres
.food
-= compres
.men
;
2146 rb
->snprintf(buf
, sizeof(buf
), "The computer does not have"
2147 " enough food to feed its men. %d have died of starvation",
2148 killmen(COLOUR_DARK
));
2149 rb
->splash(HZ
, buf
);
2153 humanres
.moves
= superdom_settings
.movesperturn
;
2156 switch(war_menu()) {
2158 return PLUGIN_USB_CONNECTED
;
2160 case RET_VAL_QUIT_ERR
:
2164 compres
.moves
= superdom_settings
.movesperturn
;