A modern Music Player Daemon based on Rockbox open source high quality audio player
libadwaita audio rust zig deno mpris rockbox mpd
at master 2575 lines 77 kB view raw
1/*************************************************************************** 2 * __________ __ ___. 3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___ 4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / 5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < 6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ 7 * \/ \/ \/ \/ \/ 8 * $Id$ 9 * 10 * Copyright (C) 2006 Will Robertson 11 * 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. 16 * 17 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY 18 * KIND, either express or implied. 19 * 20 ****************************************************************************/ 21/* TODO list: 22 - improve AI 23 - buy/use nukes - DONE 24 - build farms/factories 25*/ 26 27 28#include "plugin.h" 29#include "lib/display_text.h" 30#include "lib/playback_control.h" 31#include "lib/pluginlib_actions.h" 32#include "pluginbitmaps/superdom_boarditems.h" 33 34char buf[255]; 35 36/* key mappings */ 37 38#define SUPERDOM_OK PLA_SELECT 39#define SUPERDOM_CANCEL PLA_CANCEL 40#define SUPERDOM_RIGHT PLA_RIGHT 41#define SUPERDOM_LEFT PLA_LEFT 42#define SUPERDOM_UP PLA_UP 43#define SUPERDOM_DOWN PLA_DOWN 44 45#define SUPERDOM_RIGHT_REPEAT PLA_RIGHT_REPEAT 46#define SUPERDOM_LEFT_REPEAT PLA_LEFT_REPEAT 47#define SUPERDOM_UP_REPEAT PLA_UP_REPEAT 48#define SUPERDOM_DOWN_REPEAT PLA_DOWN_REPEAT 49 50/***** game settings *****/ 51 52/* Some defines for the prices */ 53#define PRICE_MEN 1 54#define PRICE_MOVE 100 55#define PRICE_TANK 300 56#define PRICE_PLANE 600 57#define PRICE_FARM 1150 58#define PRICE_FACTORY 1300 59#define PRICE_NUKE 2000 60 61#define STRINGIZE_2(X) #X 62#define STRINGIZE(X) STRINGIZE_2(X) 63 64#define PRICE_MEN_STR STRINGIZE(PRICE_MEN) 65#define PRICE_MOVE_STR STRINGIZE(PRICE_MOVE) 66#define PRICE_TANK_STR STRINGIZE(PRICE_TANK) 67#define PRICE_PLANE_STR STRINGIZE(PRICE_PLANE) 68#define PRICE_FARM_STR STRINGIZE(PRICE_FARM) 69#define PRICE_FACTORY_STR STRINGIZE(PRICE_FACTORY) 70#define PRICE_NUKE_STR STRINGIZE(PRICE_NUKE) 71 72/* surrender thresholds */ 73#define HUMAN_SURRENDER_THRESHOLD 15 74#define COMPUTER_SURRENDER_THRESHOLD 15 75#define COMPUTER_HARD_SURRENDER_THRESHOLD 25 76 77/* AI settings */ 78#define AI_INVESTING_LEVEL 2 79#define AI_BUILD_NUKES_LEVEL 3 80#define AI_BUILD_INDS_FARMS_LEVEL 2 81 82/* board size */ 83#define BOARD_SIZE 10 84#define NUM_SPACES (BOARD_SIZE*BOARD_SIZE) 85#define COLOUR_DARK 0 86#define COLOUR_LIGHT 1 87 88/* drawing presets */ 89 90#define MARGIN 5 91 92#if (LCD_DEPTH >= 16) 93#define MY_BITMAP_PART rb->lcd_bitmap_transparent_part 94#else 95#define MY_BITMAP_PART rb->lcd_mono_bitmap_part 96#endif 97 98#if LCD_WIDTH > LCD_HEIGHT 99#define BOX_WIDTH ((LCD_WIDTH-(MARGIN*2))/BOARD_SIZE) 100#define BOX_HEIGHT ((BOX_WIDTH*2)/3) 101 102#else 103#define BOX_HEIGHT ((LCD_HEIGHT-(MARGIN*2)-15)/BOARD_SIZE) 104#define BOX_WIDTH ((BOX_HEIGHT*2)/3) 105 106#endif 107 108/* NUM_BOX HEIGHT and WIDTH are used for the number pad in the game. The height 109 * calculation includes spacing for the text placed above and below the number 110 * pad (it divides by 6 instead of just 4). The width calculation gives extra 111 * spacing on the sides of the pad too (divides by 5 instead of 3). 112 */ 113#define NUM_BOX_HEIGHT (LCD_HEIGHT/6) 114#define NUM_BOX_WIDTH (LCD_WIDTH/5) 115 116#define NUM_MARGIN_X (LCD_WIDTH-3*NUM_BOX_WIDTH)/2 117#define NUM_MARGIN_Y (LCD_HEIGHT-4*NUM_BOX_HEIGHT)/2 118 119/* These parameters define the piece image dimensions, Stride is the total width 120 * of the bitmap. 121 */ 122#define ICON_STRIDE STRIDE(SCREEN_MAIN, BMPWIDTH_superdom_boarditems, BMPHEIGHT_superdom_boarditems) 123#define ICON_HEIGHT (BMPHEIGHT_superdom_boarditems/6) 124#define ICON_WIDTH (BMPWIDTH_superdom_boarditems/2) 125 126enum { 127 RET_VAL_OK, 128 RET_VAL_USB, 129 RET_VAL_QUIT_ERR, /* quit or error */ 130}; 131 132static void gen_interest(void); 133static void init_resources(void); 134static int select_square(void); 135static void update_score(void); 136static void gen_resources(void); 137static void draw_cursor(void); 138static void draw_board(void); 139 140struct tile { 141 signed int colour; /* -1 = Unset */ 142 bool tank; 143 bool plane; 144 bool nuke; 145 bool ind; 146 bool farm; 147 int men; 148}; 149 150struct resources { 151 int cash; 152 int food; 153 int farms; 154 int inds; 155 int men; 156 int tanks; 157 int planes; 158 int nukes; 159 int bank; 160 int moves; 161}; 162 163static struct settings { 164 int compstartfarms; 165 int compstartinds; 166 int humanstartfarms; 167 int humanstartinds; 168 int startcash; 169 int startfood; 170 int movesperturn; 171 /* 1=easy 2=medium 3=hard */ 172 /* AI difficulty works like this: 173 easy: 174 - no movement 175 - no investing 176 - will build factories if it has none 177 medium: 178 - movement 179 - investing 180 - can build factories/farms if it has money 181 hard: 182 - can buy/use nukes 183 - will hold out longer (surrender threshold 25) 184 */ 185 int compdiff; 186 bool spoil_enabled; 187 bool persistent_units; 188} superdom_settings; 189 190static struct resources humanres; 191static struct resources compres; 192enum { GS_PROD, GS_MOVE, GS_WAR }; 193static int gamestate; 194 195static struct cursor { 196 int x; 197 int y; 198} cursor; 199 200static struct tile board[BOARD_SIZE+2][BOARD_SIZE+2]; 201 202static const struct button_mapping *plugin_contexts[] = { pla_main_ctx }; 203 204static void init_board(void) 205{ 206 int i,j; 207 rb->srand(*rb->current_tick); 208 for(i=0;i<12;i++) 209 { /* Hopefully about 50% each colour */ 210 for(j=0;j<BOARD_SIZE+2;j++) 211 { 212 if((i<1)||(j<1)||(i>BOARD_SIZE)||(j>BOARD_SIZE)) 213 board[i][j].colour = -1; /* Unset */ 214 else 215 board[i][j].colour = rb->rand()%2; 216 board[i][j].tank = false; 217 board[i][j].plane = false; 218 board[i][j].nuke = false; 219 board[i][j].ind = false; 220 board[i][j].farm = false; 221 board[i][j].men = 0; 222 } 223 } 224 225 while(compres.farms < superdom_settings.compstartfarms) 226 { 227 i = rb->rand()%BOARD_SIZE + 1; 228 j = rb->rand()%BOARD_SIZE + 1; 229 if((board[i][j].colour == COLOUR_DARK) && (board[i][j].farm == false)) 230 { 231 board[i][j].farm = true; 232 compres.farms++; 233 } 234 } 235 while(compres.inds < superdom_settings.compstartinds) 236 { 237 i = rb->rand()%BOARD_SIZE + 1; 238 j = rb->rand()%BOARD_SIZE + 1; 239 if((board[i][j].colour == COLOUR_DARK) && (board[i][j].ind == false)) 240 { 241 board[i][j].ind = true; 242 compres.inds++; 243 } 244 } 245 while(humanres.farms < superdom_settings.humanstartfarms) 246 { 247 i = rb->rand()%BOARD_SIZE + 1; 248 j = rb->rand()%BOARD_SIZE + 1; 249 if((board[i][j].colour == COLOUR_LIGHT)&&(board[i][j].farm == false)) 250 { 251 board[i][j].farm = true; 252 humanres.farms++; 253 } 254 } 255 while(humanres.inds < superdom_settings.humanstartinds) 256 { 257 i = rb->rand()%BOARD_SIZE + 1; 258 j = rb->rand()%BOARD_SIZE + 1; 259 if((board[i][j].colour == COLOUR_LIGHT) && (board[i][j].ind == false)) 260 { 261 board[i][j].ind = true; 262 humanres.inds++; 263 } 264 } 265} 266 267void draw_board(void) 268{ 269 int i,j; 270 rb->lcd_clear_display(); 271 for(i=1;i<=BOARD_SIZE;i++) 272 { 273 for(j=1;j<=BOARD_SIZE;j++) 274 { 275 if(board[i][j].colour == COLOUR_DARK) 276 { 277 rb->lcd_set_foreground(LCD_DARKGRAY); 278 } 279 else 280 { 281 rb->lcd_set_foreground(LCD_LIGHTGRAY); 282 } 283 rb->lcd_fillrect(MARGIN+(BOX_WIDTH*(i-1)), 284 MARGIN+(BOX_HEIGHT*(j-1)), BOX_WIDTH, 285 BOX_HEIGHT); 286#if LCD_DEPTH != 16 287 rb->lcd_set_drawmode(DRMODE_BG | DRMODE_INVERSEVID); 288#endif 289 if(board[i][j].ind) 290 { 291 MY_BITMAP_PART(superdom_boarditems, 292 board[i][j].colour?ICON_WIDTH:0, 0, ICON_STRIDE, 293#if LCD_WIDTH > LCD_HEIGHT 294 MARGIN+(BOX_WIDTH*(i-1))+1, 295 MARGIN+(BOX_HEIGHT*(j-1))+ICON_HEIGHT+1, 296#else 297 MARGIN+(BOX_WIDTH*(i-1))+1+ICON_WIDTH, 298 MARGIN+(BOX_HEIGHT*(j-1))+1, 299#endif 300 ICON_WIDTH, ICON_HEIGHT); 301 } 302 if(board[i][j].farm) 303 { 304 MY_BITMAP_PART(superdom_boarditems, 305 board[i][j].colour?ICON_WIDTH:0, ICON_HEIGHT, 306 ICON_STRIDE, MARGIN+(BOX_WIDTH*(i-1))+1, 307 MARGIN+(BOX_HEIGHT*(j-1))+1, 308 ICON_WIDTH, ICON_HEIGHT); 309 } 310 if(board[i][j].tank) 311 { 312 MY_BITMAP_PART(superdom_boarditems, 313 board[i][j].colour?ICON_WIDTH:0, ICON_HEIGHT*2, 314 ICON_STRIDE, MARGIN+(BOX_WIDTH*(i-1))+ICON_WIDTH+1, 315 MARGIN+(BOX_HEIGHT*(j-1))+ICON_HEIGHT+1, 316 ICON_WIDTH, ICON_HEIGHT); 317 } 318 if(board[i][j].men) 319 { 320 MY_BITMAP_PART(superdom_boarditems, 321 board[i][j].colour?ICON_WIDTH:0, ICON_HEIGHT*3, 322#if LCD_WIDTH > LCD_HEIGHT 323 ICON_STRIDE, MARGIN+(BOX_WIDTH*(i-1))+ICON_WIDTH+1, 324 MARGIN+(BOX_HEIGHT*(j-1))+1, 325#else 326 ICON_STRIDE, MARGIN+(BOX_WIDTH*(i-1))+1, 327 MARGIN+(BOX_HEIGHT*(j-1))+1+ICON_HEIGHT, 328#endif 329 ICON_WIDTH, ICON_HEIGHT); 330 } 331 if(board[i][j].plane) 332 { 333 MY_BITMAP_PART(superdom_boarditems, 334 board[i][j].colour?ICON_WIDTH:0, ICON_HEIGHT*4, 335#if LCD_WIDTH > LCD_HEIGHT 336 ICON_STRIDE,MARGIN+(BOX_WIDTH*(i-1))+ICON_WIDTH*2+1, 337 MARGIN+(BOX_HEIGHT*(j-1))+ICON_HEIGHT+1, 338#else 339 ICON_STRIDE,MARGIN+(BOX_WIDTH*(i-1))+ICON_WIDTH+1, 340 MARGIN+(BOX_HEIGHT*(j-1))+ICON_HEIGHT*2+1, 341#endif 342 ICON_WIDTH, ICON_HEIGHT); 343 } 344 if(board[i][j].nuke) 345 { 346 MY_BITMAP_PART(superdom_boarditems, 347 board[i][j].colour?ICON_WIDTH:0, ICON_HEIGHT*5, 348#if LCD_WIDTH > LCD_HEIGHT 349 ICON_STRIDE,MARGIN+(BOX_WIDTH*(i-1))+ICON_WIDTH*2+1, 350 MARGIN+(BOX_HEIGHT*(j-1))+1, 351#else 352 ICON_STRIDE,MARGIN+(BOX_WIDTH*(i-1))+1, 353 MARGIN+(BOX_HEIGHT*(j-1))+ICON_HEIGHT*2+1, 354#endif 355 ICON_WIDTH, ICON_HEIGHT); 356 } 357#if LCD_DEPTH != 16 358 rb->lcd_set_drawmode(DRMODE_SOLID); 359#endif 360 } 361 } 362 rb->lcd_set_foreground(LCD_BLACK); 363 /* Draw Horizontal lines */ 364 for(i=0;i<=BOARD_SIZE;i++) 365 { 366 rb->lcd_hline(MARGIN, MARGIN+(BOX_WIDTH*BOARD_SIZE), MARGIN+(BOX_HEIGHT*i)); 367 } 368 /* Draw Vertical lines */ 369 for(i=0;i<=BOARD_SIZE;i++) 370 { 371 rb->lcd_vline(MARGIN+(BOX_WIDTH*i), MARGIN, MARGIN+(BOX_HEIGHT*BOARD_SIZE)); 372 } 373 rb->lcd_update(); 374} 375 376static int calc_strength(int colour, int x, int y) 377{ 378 int a, b, score=0; 379 for (a = -1; a < 2; a++) 380 { 381 for (b = -1; b < 2; b++) 382 { 383 if(board[x+a][y+b].colour==colour) 384 { 385 if(a && b) /* diagonally adjacent, give less influence */ 386 { 387 score += 5; 388 if(board[x + a][y + b].tank) 389 score += 15; 390 if(board[x + a][y + b].farm) 391 score += 15; 392 if(board[x + a][y + b].plane) 393 score += 20; 394 if (board[x + a][y + b].ind) 395 score += 20; 396 if(board[x + a][y + b].nuke) 397 score += 10; 398 if(board[x + a][y + b].men) 399 score += (board[x + a][y + b].men*133/1000); 400 } 401 else 402 { 403 score += 10; 404 if(board[x + a][y + b].tank) 405 score += 30; 406 if(board[x + a][y + b].farm) 407 score += 30; 408 if(board[x + a][y + b].plane) 409 score += 20; 410 if(board[x + a][y + b].ind) 411 score += 20; 412 if(board[x + a][y + b].nuke) 413 score += 20; 414 if(board[x + a][y + b].men) 415 score += (board[x + a][y + b].men*133/1000); 416 } 417 } 418 } 419 } 420 return score; 421} 422 423void gen_interest(void) 424{ 425 /* Interest should be around 10% */ 426 int interest = 7+rb->rand()%6; 427 humanres.bank = humanres.bank+(interest*humanres.bank/100); 428 /* Different interest for AI player */ 429 interest = 7+rb->rand()%6; 430 compres.bank = compres.bank+(interest*compres.bank/100); 431} 432 433void draw_cursor(void) 434{ 435 rb->lcd_set_drawmode(DRMODE_COMPLEMENT); 436 rb->lcd_fillrect(MARGIN+((cursor.x-1)*BOX_WIDTH), 437 MARGIN+((cursor.y-1)*BOX_HEIGHT), BOX_WIDTH+1, BOX_HEIGHT+1); 438 rb->lcd_set_drawmode(DRMODE_SOLID); 439 rb->lcd_update(); 440} 441 442void gen_resources(void) 443{ 444 int inccash = 0; 445 int incfood = 0; 446 int ratecash = 0; 447 int ratefood = 0; 448 int i; 449 gen_interest(); 450 /* Generate Human's resources */ 451 for(i=0;i<humanres.inds;i++) 452 { 453 inccash += (300+rb->rand()%200); 454 } 455 for(i=0;i<humanres.farms;i++) 456 { 457 incfood += (200+rb->rand()%200); 458 } 459 if(humanres.inds) 460 ratecash = inccash/humanres.inds; 461 if(humanres.farms) 462 ratefood = incfood/humanres.farms; 463 if(ratecash > 450) 464 { 465 if(ratefood > 350) 466 { 467 rb->splash(HZ*2, "Patriotism sweeps the land, all production" 468 " is up this year!"); 469 } 470 else 471 { 472 rb->splash(HZ*2, "Factories working at maximum efficiency," 473 " cash production up this year!"); 474 } 475 } 476 else if(ratecash > 350) 477 { 478 if(ratefood > 350) 479 { 480 rb->splash(HZ*2, "Record crop harvest this year!"); 481 } 482 else if(ratefood > 250) 483 { 484 rb->splash(HZ*2, "Production continues as normal"); 485 } 486 else 487 { 488 rb->splash(HZ*2, "Spoilage of crops leads to reduced farm" 489 " output this year"); 490 } 491 } 492 else 493 { 494 if(ratefood > 350) 495 { 496 rb->splash(HZ*2, "Record crop harvest this year!"); 497 } 498 else if(ratefood > 250) 499 { 500 rb->splash(HZ*2, "Factory unions introduced. Industrial" 501 " production is down this year."); 502 } 503 else 504 { 505 rb->splash(HZ*2, "Internet created. All production is down" 506 " due to time wasted."); 507 } 508 } 509 humanres.cash += inccash; 510 humanres.food += incfood; 511 512 /* Generate Computer's resources */ 513 inccash = 0; 514 incfood = 0; 515 for(i=0;i<compres.inds;i++) 516 { 517 inccash += (300+rb->rand()%200); 518 } 519 for(i=0;i<compres.farms;i++) 520 { 521 incfood += (200+rb->rand()%200); 522 } 523 compres.cash += inccash; 524 compres.food += incfood; 525} 526 527static void update_score(void) 528{ 529 int strength; 530 531 rb->lcd_setfont(FONT_SYSFIXED); 532 rb->lcd_set_drawmode(DRMODE_BG|DRMODE_INVERSEVID); 533 rb->lcd_fillrect(5,LCD_HEIGHT-20,105,20); 534 rb->lcd_set_drawmode(DRMODE_SOLID); 535 strength = calc_strength(COLOUR_LIGHT, cursor.x, cursor.y); 536 rb->lcd_putsxyf(5,LCD_HEIGHT-20,"Your power: %d.%d",strength/10,strength%10); 537 strength = calc_strength(COLOUR_DARK, cursor.x, cursor.y); 538 rb->lcd_putsxyf(5,LCD_HEIGHT-10,"Comp power: %d.%d",strength/10,strength%10); 539 rb->lcd_setfont(FONT_UI); 540} 541 542static int settings_menu(void) 543{ 544 int selection = 0; 545 546 MENUITEM_STRINGLIST(menu, "Super Domination Settings", NULL, 547 "Computer starting farms", "Computer starting factories", 548 "Human starting farms", "Human starting factories", 549 "Starting cash", "Starting food", "Computer difficulty","Food spoilage", "Persistent units", "Moves per turn"); 550 551 while(1) 552 { 553 switch(rb->do_menu(&menu, &selection, NULL, false)) 554 { 555 case 0: 556 rb->set_int("Computer starting farms", "", UNIT_INT, 557 &superdom_settings.compstartfarms, NULL, 558 1, 0, 5, NULL); 559 break; 560 case 1: 561 rb->set_int("Computer starting factories", "", UNIT_INT, 562 &superdom_settings.compstartinds, NULL, 563 1, 0, 5, NULL); 564 break; 565 case 2: 566 rb->set_int("Human starting farms", "", UNIT_INT, 567 &superdom_settings.humanstartfarms, NULL, 568 1, 0, 5, NULL); 569 break; 570 case 3: 571 rb->set_int("Human starting factories", "", UNIT_INT, 572 &superdom_settings.humanstartinds, NULL, 573 1, 0, 5, NULL); 574 break; 575 case 4: 576 rb->set_int("Starting cash", "", UNIT_INT, 577 &superdom_settings.startcash, NULL, 578 250, 0, 5000, NULL); 579 break; 580 case 5: 581 rb->set_int("Starting food", "", UNIT_INT, 582 &superdom_settings.startfood, NULL, 583 250, 0, 5000, NULL); 584 break; 585 case 6: 586 { 587 static const struct opt_items difficulty_options[3]={ 588 {"Easy", -1}, 589 {"Intermediate", -1}, 590 {"Hard", -1} 591 }; 592 static int sel=1; 593 rb->set_option("Computer difficulty", &sel, 594 RB_INT, difficulty_options, 3, NULL); 595 superdom_settings.compdiff=sel+1; 596 break; 597 } 598 case 7: 599 rb->set_bool_options("Food spoilage", &superdom_settings.spoil_enabled, "Enabled", 600 0, "Disabled", 0, NULL); 601 break; 602 case 8: 603 rb->set_bool_options("Persistent units", &superdom_settings.persistent_units, "Enabled", 0, 604 "Disabled", 0, NULL); 605 break; 606 case 9: 607 rb->set_int("Moves per turn", "", UNIT_INT, 608 &superdom_settings.movesperturn, NULL, 609 1, 1, 5, NULL); 610 break; 611 case MENU_ATTACHED_USB: 612 return RET_VAL_USB; 613 break; 614 case GO_TO_PREVIOUS: 615 return RET_VAL_OK; 616 break; 617 } 618 } 619 return RET_VAL_OK; 620} 621 622static int superdom_help(void) 623{ 624 static char* help_text[] = {"Super Domination","", 625 "Aim", "", 626 "Super", "Domination", "is", "a", "turn-based", 627 "strategy", "game", "where", "the", "aim", "is", 628 "to", "overpower", "the", "computer.", "", "", 629 "How", "to", "Play", "", 630 "Each", "year", "you", "are", "allocated", "an", "amount", "of", "cash", 631 "and", "food,", "depending", "on", "how", "many", "farms", "and", 632 "factories", "you", "control.", "", 633 "Use", "this", "cash", "and", "food", "to", "build", "and", "feed", "your", 634 "army.", "Each", "tile", "has", "a", "strength,", "calculated", "by", 635 "the", "ownership", "of", "surrounding", "tiles,", "and", "the", "type", 636 "and", "number", "of", "troops", "on", "them."}; 637 static struct style_text style[]={ 638 {0, TEXT_CENTER|TEXT_UNDERLINE}, 639 {2, C_RED}, 640 {21, C_RED}, 641 {22, C_RED}, 642 {23, C_RED}, 643 LAST_STYLE_ITEM 644 }; 645#ifdef HAVE_LCD_COLOR 646 rb->lcd_set_foreground(LCD_WHITE); 647 rb->lcd_set_background(LCD_BLACK); 648#endif 649 int ret=display_text(ARRAYLEN(help_text), help_text, style, NULL, true); 650#ifdef HAVE_LCD_COLOR 651 rb->lcd_set_foreground(LCD_BLACK); 652 rb->lcd_set_background(LCD_WHITE); 653#endif 654 if(ret) 655 return RET_VAL_USB; 656 return RET_VAL_OK; 657} 658 659static int start_menu(void) 660{ 661 int selection = 0; 662 663 MENUITEM_STRINGLIST(menu, "Super Domination Menu", NULL, 664 "Play Super Domination", "Settings", 665 "Help", "Playback Control", "Quit"); 666 667 while(1) 668 { 669 switch(rb->do_menu(&menu, &selection, NULL, false)) 670 { 671 case 0: 672 return RET_VAL_OK; /* start playing */ 673 break; 674 case 1: 675 if(settings_menu()==RET_VAL_USB) 676 return RET_VAL_USB; 677 break; 678 case 2: 679 if(superdom_help()==RET_VAL_USB) 680 return RET_VAL_USB; 681 break; 682 case 3: 683 if(playback_control(NULL)) 684 return RET_VAL_USB; 685 break; 686 case 4: 687 return RET_VAL_QUIT_ERR; 688 break; 689 } 690 } 691 return RET_VAL_QUIT_ERR; 692} 693 694static int save_game(void) 695{ 696 int fd; 697 char savepath[MAX_PATH]; 698 699 rb->snprintf(savepath, sizeof(savepath), "/Savegame.ssg"); 700 if(rb->kbd_input(savepath, MAX_PATH, NULL)) 701 { 702 DEBUGF("Keyboard input failed\n"); 703 return -1; 704 } 705 706 fd = rb->open(savepath, O_WRONLY|O_CREAT, 0666); 707 DEBUGF("savepath: %s\n", savepath); 708 if(fd < 0) 709 { 710 DEBUGF("Couldn't create/open file\n"); 711 return -1; 712 } 713 714 rb->write(fd, "SSGv3", 5); 715 rb->write(fd, &gamestate, sizeof(gamestate)); 716 rb->write(fd, &humanres.cash, sizeof(humanres.cash)); 717 rb->write(fd, &humanres.food, sizeof(humanres.food)); 718 rb->write(fd, &humanres.bank, sizeof(humanres.bank)); 719 rb->write(fd, &humanres.planes, sizeof(humanres.planes)); 720 rb->write(fd, &humanres.tanks, sizeof(humanres.tanks)); 721 rb->write(fd, &humanres.men, sizeof(humanres.men)); 722 rb->write(fd, &humanres.nukes, sizeof(humanres.nukes)); 723 rb->write(fd, &humanres.inds, sizeof(humanres.inds)); 724 rb->write(fd, &humanres.farms, sizeof(humanres.farms)); 725 rb->write(fd, &humanres.moves, sizeof(humanres.moves)); 726 rb->write(fd, &compres.cash, sizeof(compres.cash)); 727 rb->write(fd, &compres.food, sizeof(compres.food)); 728 rb->write(fd, &compres.bank, sizeof(compres.bank)); 729 rb->write(fd, &compres.planes, sizeof(compres.planes)); 730 rb->write(fd, &compres.tanks, sizeof(compres.tanks)); 731 rb->write(fd, &compres.men, sizeof(compres.men)); 732 rb->write(fd, &compres.nukes, sizeof(compres.nukes)); 733 rb->write(fd, &compres.inds, sizeof(compres.inds)); 734 rb->write(fd, &compres.farms, sizeof(compres.farms)); 735 rb->write(fd, &compres.moves, sizeof(compres.moves)); 736 rb->write(fd, board, sizeof(board)); 737 rb->write(fd, &superdom_settings.compstartfarms, sizeof(int)); 738 rb->write(fd, &superdom_settings.compstartinds, sizeof(int)); 739 rb->write(fd, &superdom_settings.humanstartfarms, sizeof(int)); 740 rb->write(fd, &superdom_settings.humanstartinds, sizeof(int)); 741 rb->write(fd, &superdom_settings.startcash, sizeof(int)); 742 rb->write(fd, &superdom_settings.startfood, sizeof(int)); 743 rb->write(fd, &superdom_settings.movesperturn, sizeof(int)); 744 rb->close(fd); 745 return 0; 746} 747 748static int ingame_menu(void) 749{ 750 MENUITEM_STRINGLIST(menu, "Super Domination Menu", NULL, 751 "Return to game", "Save Game", 752 "Playback Control", "Quit"); 753 754 switch(rb->do_menu(&menu, NULL, NULL, false)) 755 { 756 case 0: 757 return RET_VAL_OK; 758 break; 759 case 1: 760 if(!save_game()) 761 rb->splash(HZ, "Game saved"); 762 else 763 rb->splash(HZ, "Error in save"); 764 break; 765 case 2: 766 if(playback_control(NULL)) 767 return RET_VAL_USB; 768 break; 769 case 3: 770 return RET_VAL_QUIT_ERR; 771 break; 772 case MENU_ATTACHED_USB: 773 return RET_VAL_USB; 774 break; 775 case GO_TO_PREVIOUS: 776 return RET_VAL_OK; 777 break; 778 } 779 return RET_VAL_OK; 780} 781 782static int get_number(char* param, int* value, int max) 783{ 784 static const char *button_labels[4][3] = { 785 { "1", "2", "3" }, 786 { "4", "5", "6" }, 787 { "7", "8", "9" }, 788 { "DEL", "0", "OK" } 789 }; 790 int i,j,x=0,y=0; 791 int height, width; 792 int button = 0, ret = RET_VAL_OK; 793 bool done = false; 794 rb->lcd_clear_display(); 795 rb->lcd_getstringsize("DEL", &width, &height); 796 if(width > NUM_BOX_WIDTH || height > NUM_BOX_HEIGHT) 797 rb->lcd_setfont(FONT_SYSFIXED); 798 /* Draw a 3x4 grid */ 799 for(i=0;i<=3;i++) 800 { /* Vertical lines */ 801 rb->lcd_vline(NUM_MARGIN_X+(NUM_BOX_WIDTH*i), NUM_MARGIN_Y, 802 NUM_MARGIN_Y+(4*NUM_BOX_HEIGHT)); 803 } 804 /* Horizontal lines */ 805 for(i=0;i<=4;i++) 806 { 807 rb->lcd_hline(NUM_MARGIN_X, NUM_MARGIN_X+(3*NUM_BOX_WIDTH), 808 NUM_MARGIN_Y+(NUM_BOX_HEIGHT*i)); 809 } 810 for(i=0;i<4;i++) 811 { 812 for(j=0;j<3;j++) 813 { 814 rb->lcd_getstringsize(button_labels[i][j], &width, &height); 815 rb->lcd_putsxy(NUM_MARGIN_X+(j*NUM_BOX_WIDTH)+NUM_BOX_WIDTH/2-width/2, 816 NUM_MARGIN_Y+(i*NUM_BOX_HEIGHT)+NUM_BOX_HEIGHT/2-height/2, 817 button_labels[i][j]); 818 } 819 } 820 rb->lcd_putsxyf(NUM_MARGIN_X+10, NUM_MARGIN_Y+4*NUM_BOX_HEIGHT+10,"%d",*value); 821 rb->lcd_getstringsize(param, &width, &height); 822 if(width < LCD_WIDTH) 823 rb->lcd_putsxy((LCD_WIDTH-width)/2, (NUM_MARGIN_Y-height)/2, param); 824 else 825 rb->lcd_puts_scroll(0, (NUM_MARGIN_Y/height-1)/2, param); 826 827 rb->lcd_set_drawmode(DRMODE_COMPLEMENT); 828 rb->lcd_fillrect(NUM_MARGIN_X+(NUM_BOX_WIDTH*x), 829 NUM_MARGIN_Y+(NUM_BOX_HEIGHT*y), 830 NUM_BOX_WIDTH+1, NUM_BOX_HEIGHT+1); 831 rb->lcd_set_drawmode(DRMODE_SOLID); 832 rb->lcd_update(); 833 834 while(!done) 835 { 836 button=pluginlib_getaction(-1, plugin_contexts, ARRAYLEN(plugin_contexts)); 837 rb->lcd_set_drawmode(DRMODE_COMPLEMENT); 838 rb->lcd_fillrect(NUM_MARGIN_X+(NUM_BOX_WIDTH*x), 839 NUM_MARGIN_Y+(NUM_BOX_HEIGHT*y), 840 NUM_BOX_WIDTH+1, NUM_BOX_HEIGHT+1); 841 rb->lcd_set_drawmode(DRMODE_SOLID); 842 switch(button) 843 { 844 case SUPERDOM_OK: 845 if(y!=3) 846 { 847 *value *= 10; 848 *value += button_labels[y][x][0] - '0'; 849 } 850 else if(x==0) 851 { 852 *value /= 10; 853 } 854 else if(x==1) 855 { 856 *value *= 10; 857 } 858 else if(x==2) 859 { 860 done = true; 861 break; 862 } 863 if ((unsigned) *value > (unsigned) max) 864 *value = max; 865 rb->lcd_set_drawmode(DRMODE_BG|DRMODE_INVERSEVID); 866 rb->lcd_fillrect(0, NUM_MARGIN_Y+4*NUM_BOX_HEIGHT+10, 867 LCD_WIDTH, 30); 868 rb->lcd_set_drawmode(DRMODE_SOLID); 869 rb->lcd_putsxyf(NUM_MARGIN_X+10,NUM_MARGIN_Y+4*NUM_BOX_HEIGHT+10, 870 "%d", *value); 871 break; 872 case SUPERDOM_CANCEL: 873 *value = 0; 874 done = true; 875 ret = RET_VAL_QUIT_ERR; 876 break; 877#if CONFIG_KEYPAD != IRIVER_H10_PAD 878 case SUPERDOM_LEFT: 879 if(x==0) 880 { 881 x=2; 882 } 883 else 884 { 885 x--; 886 } 887 break; 888 case SUPERDOM_RIGHT: 889 if(x==2) 890 { 891 x=0; 892 } 893 else 894 { 895 x++; 896 } 897 break; 898#endif 899 case SUPERDOM_UP: 900 if(y==0) 901 { 902#if CONFIG_KEYPAD == IRIVER_H10_PAD 903 if(x > 0) 904 x--; 905 else 906 x=2; 907#endif 908 y=3; 909 } 910 else 911 { 912 y--; 913 } 914 break; 915 case SUPERDOM_DOWN: 916 if(y==3) 917 { 918#if CONFIG_KEYPAD == IRIVER_H10_PAD 919 if(x < 2) 920 x++; 921 else 922 x=0; 923#endif /* CONFIG_KEYPAD == IRIVER_H10_PAD */ 924 y=0; 925 } 926 else 927 { 928 y++; 929 } 930 break; 931 default: 932 if(rb->default_event_handler(button) == SYS_USB_CONNECTED) 933 { 934 done = true; 935 ret = RET_VAL_USB; 936 } 937 break; 938 } 939 rb->lcd_set_drawmode(DRMODE_COMPLEMENT); 940 rb->lcd_fillrect(NUM_MARGIN_X+(NUM_BOX_WIDTH*x), 941 NUM_MARGIN_Y+(NUM_BOX_HEIGHT*y), 942 NUM_BOX_WIDTH+1, NUM_BOX_HEIGHT+1); 943 rb->lcd_set_drawmode(DRMODE_SOLID); 944 rb->lcd_update(); 945 } 946 rb->lcd_setfont(FONT_UI); 947 rb->lcd_scroll_stop(); 948 if (ret == RET_VAL_QUIT_ERR) 949 rb->splash(HZ, "Cancelled"); 950 return ret; 951} 952 953static bool tile_has_item(int type, int x, int y) 954{ 955 switch(type) 956 { 957 case 0: 958 return (board[x][y].men > 0); 959 break; 960 case 1: 961 return board[x][y].tank; 962 break; 963 case 2: 964 return board[x][y].plane; 965 break; 966 case 3: 967 return board[x][y].farm; 968 break; 969 case 4: 970 return board[x][y].ind; 971 break; 972 case 5: 973 return board[x][y].nuke; 974 break; 975 } 976 return false; 977} 978 979static int buy_resources(int colour, int type, int x, int y, int nummen) 980{ 981 const char *itemnames[][6] = { 982 { 983 "them", 984 "the tank", 985 "the plane", 986 "the farm", 987 "the industrial plant", 988 "the nuke", 989 }, 990 { 991 "place men", 992 "place a tank", 993 "place a plane", 994 "build a farm", 995 "build an industrial plant", 996 "place a nuke", 997 }, 998 { 999 NULL, 1000 "a tank", 1001 "a plane", 1002 "a farm", 1003 "an industrial plant", 1004 "a nuke", 1005 }, 1006 }; 1007 1008 bool human = (colour == COLOUR_LIGHT); 1009 int price = 0; 1010 int temp; 1011 struct resources *res; 1012 1013 if(human) 1014 { 1015 res = &humanres; 1016 } 1017 else 1018 { 1019 res = &compres; 1020 } 1021 switch(type) 1022 { 1023 case 0: /* men */ 1024 price = PRICE_MEN*nummen; 1025 break; 1026 case 1: /* tank */ 1027 price = PRICE_TANK; 1028 break; 1029 case 2: /* plane */ 1030 price = PRICE_PLANE; 1031 break; 1032 case 3: /* Farm */ 1033 price = PRICE_FARM; 1034 break; 1035 case 4: /* Factory */ 1036 price = PRICE_FACTORY; 1037 break; 1038 case 5: /* nuke */ 1039 price = PRICE_NUKE; 1040 break; 1041 } 1042 if(res->cash < price) 1043 { 1044 if(human) 1045 rb->splash(HZ, "Not enough money!"); 1046 return RET_VAL_QUIT_ERR; 1047 } 1048 if(human) 1049 { 1050 rb->splashf(HZ, "Where do you want to place %s?", itemnames[0][type]); 1051 if((temp = select_square()) != RET_VAL_OK) 1052 return temp; 1053 x = cursor.x; 1054 y = cursor.y; 1055 } 1056 if(board[x][y].colour != colour) 1057 { 1058 if(human) 1059 rb->splashf(HZ, "Can't %s on enemy territory", itemnames[1][type]); 1060 return RET_VAL_QUIT_ERR; 1061 } 1062 if(type != 0 && tile_has_item(type, x, y)) 1063 { 1064 if(human) 1065 rb->splashf(HZ, "There is already %s there", itemnames[2][type]); 1066 return RET_VAL_QUIT_ERR; 1067 } 1068 switch(type) 1069 { 1070 case 0: 1071 board[x][y].men += nummen; 1072 res->men += nummen; 1073 break; 1074 case 1: 1075 board[x][y].tank = true; 1076 res->tanks++; 1077 break; 1078 case 2: 1079 board[x][y].plane = true; 1080 res->planes++; 1081 break; 1082 case 3: 1083 board[x][y].farm = true; 1084 res->farms++; 1085 break; 1086 case 4: 1087 board[x][y].ind = true; 1088 res->inds++; 1089 break; 1090 case 5: 1091 board[x][y].nuke = true; 1092 res->nukes++; 1093 break; 1094 } 1095 res->cash -= price; 1096 1097 draw_board(); 1098 rb->sleep(HZ); 1099 1100 return RET_VAL_OK; 1101} 1102 1103static int buy_resources_menu(void) 1104{ 1105 int selection = 0,nummen; 1106 1107 MENUITEM_STRINGLIST(menu, "Buy Resources", NULL, 1108 "Buy men ($" PRICE_MEN_STR ")", "Buy tank ($" PRICE_TANK_STR ")", "Buy plane ($" PRICE_PLANE_STR ")", 1109 "Buy Farm ($" PRICE_FARM_STR ")", "Buy Factory ($" PRICE_FACTORY_STR ")", 1110 "Buy Nuke ($" PRICE_NUKE_STR ")", 1111 "Finish buying"); 1112 1113 while(1) { 1114 switch(rb->do_menu(&menu, &selection, NULL, false)) { 1115 case 0: 1116 nummen = 0; 1117 if(get_number("How many men would you like?", &nummen, 1118 humanres.cash) == RET_VAL_USB) 1119 return RET_VAL_USB; 1120 if(!nummen) 1121 break; 1122 /* fall through */ 1123 case 1: 1124 case 2: 1125 case 3: 1126 case 4: 1127 case 5: 1128 if(buy_resources(COLOUR_LIGHT, selection, 0, 0, nummen)== RET_VAL_USB) 1129 return RET_VAL_USB; 1130 break; 1131 case 6: 1132 return RET_VAL_OK; 1133 break; 1134 case MENU_ATTACHED_USB: 1135 return RET_VAL_USB; 1136 break; 1137 case GO_TO_PREVIOUS: 1138 return RET_VAL_OK; 1139 break; 1140 } 1141 } 1142 return RET_VAL_OK; 1143} 1144 1145static int move_unit(int colour, int type, int fromx, int fromy, 1146 int tox, int toy, int nummen) 1147{ 1148 const char *itemnames[][3] = { 1149 { 1150 "troops", 1151 "the tank", 1152 "the plane", 1153 }, 1154 { 1155 "any troops", 1156 "a tank", 1157 "a plane", 1158 }, 1159 { 1160 "the troops", 1161 "the tank", 1162 "the plane", 1163 } 1164 }; 1165 bool human = (colour == COLOUR_LIGHT); 1166 int temp; 1167 1168 if(human) 1169 { 1170 rb->splashf(HZ, "Select where you want to move %s from", 1171 itemnames[0][type]); 1172 if((temp = select_square()) != RET_VAL_OK) 1173 return temp; 1174 fromx = cursor.x; 1175 fromy = cursor.y; 1176 } 1177 if(board[fromx][fromy].colour != colour) 1178 { 1179 if(human) 1180 rb->splash(HZ, "That isn't your territory"); 1181 return RET_VAL_QUIT_ERR; 1182 } 1183 if(!tile_has_item(type, fromx, fromy)) 1184 { 1185 if(human) 1186 rb->splashf(HZ, "You don't have %s there", itemnames[1][type]); 1187 return RET_VAL_QUIT_ERR; 1188 } 1189 if(type == 0) 1190 { 1191 if(human) 1192 { 1193 nummen = board[fromx][fromy].men; 1194 if((temp = get_number("How many men do you want to move?", &nummen, 1195 nummen)) != RET_VAL_OK) 1196 return temp; 1197 } 1198 if(nummen > board[fromx][fromy].men) 1199 { 1200 if(human) 1201 rb->splash(HZ, "You don't have that many troops."); 1202 return RET_VAL_QUIT_ERR; 1203 } 1204 } 1205 if(human) 1206 { 1207 rb->splashf(HZ, "Select where you want to move %s to", 1208 itemnames[2][type]); 1209 if((temp = select_square()) != RET_VAL_OK) 1210 return temp; 1211 tox = cursor.x; 1212 toy = cursor.y; 1213 } 1214 if((tox == fromx && toy == fromy) || 1215 board[tox][toy].colour != colour || 1216 (type != 2 && (abs(tox - fromx) > 1 || 1217 abs(toy - fromy) > 1))) 1218 { 1219 if(human) 1220 rb->splash(HZ, "Invalid move"); 1221 return RET_VAL_QUIT_ERR; 1222 } 1223 if(type != 0 && tile_has_item(type, tox, toy)) 1224 { 1225 if(human) 1226 rb->splashf(HZ, "There is already %s there", itemnames[1][type]); 1227 return RET_VAL_QUIT_ERR; 1228 } 1229 switch(type) 1230 { 1231 case 0: 1232 board[fromx][fromy].men -= nummen; 1233 board[tox][toy].men += nummen; 1234 break; 1235 case 1: 1236 board[fromx][fromy].tank = false; 1237 board[tox][toy].tank = true; 1238 break; 1239 case 2: 1240 board[fromx][fromy].plane = false; 1241 board[tox][toy].plane = true; 1242 break; 1243 } 1244 return RET_VAL_OK; 1245} 1246 1247static int move_unit_menu(void) 1248{ 1249 int selection = 0; 1250 1251 MENUITEM_STRINGLIST(menu, "Move unit", NULL, 1252 "Move men", "Move tank", "Move plane"); 1253 switch(rb->do_menu(&menu, &selection, NULL, false)) 1254 { 1255 case 0: 1256 case 1: 1257 case 2: 1258 switch(move_unit(COLOUR_LIGHT, selection, 0, 0, 0, 0, 0)) 1259 { 1260 case RET_VAL_OK: 1261 humanres.moves--; 1262 break; 1263 case RET_VAL_USB: 1264 return RET_VAL_USB; 1265 break; 1266 } 1267 break; 1268 case MENU_ATTACHED_USB: 1269 return RET_VAL_USB; 1270 } 1271 return RET_VAL_OK; 1272} 1273 1274static int launch_nuke(int colour, int nukex, int nukey, int targetx, int targety) 1275{ 1276 bool human = (colour == COLOUR_LIGHT); 1277 int temp; 1278 struct resources *res; 1279 1280 if(board[nukex][nukey].colour != colour) 1281 { 1282 if(human) 1283 rb->splash(HZ, "That isn't your territory"); 1284 return RET_VAL_QUIT_ERR; 1285 } 1286 if(! board[nukex][nukey].nuke) 1287 { 1288 if(human) 1289 rb->splashf(HZ, "You don't have a nuke there"); 1290 return RET_VAL_QUIT_ERR; 1291 } 1292 if(human) 1293 { 1294 rb->splash(HZ, "Select place to target with nuke"); 1295 if((temp = select_square()) != RET_VAL_OK) 1296 return temp; 1297 targetx = cursor.x; 1298 targety = cursor.y; 1299 } 1300 if(human) 1301 { 1302 humanres.nukes--; 1303 } 1304 else 1305 { 1306 compres.nukes--; 1307 } 1308 board[nukex][nukey].nuke = false; 1309 1310 if(board[targetx][targety].colour == COLOUR_LIGHT) 1311 { 1312 res = &humanres; 1313 } 1314 else 1315 { 1316 res = &compres; 1317 } 1318 res->men -= board[targetx][targety].men; 1319 res->tanks -= board[targetx][targety].tank; 1320 res->planes -= board[targetx][targety].plane; 1321 res->nukes -= board[targetx][targety].nuke; 1322 res->farms -= board[targetx][targety].farm; 1323 res->inds -= board[targetx][targety].ind; 1324 board[targetx][targety].men = 0; 1325 board[targetx][targety].tank = false; 1326 board[targetx][targety].plane = false; 1327 board[targetx][targety].ind = false; 1328 board[targetx][targety].nuke = false; 1329 board[targetx][targety].farm = false; 1330 /* TODO: Fallout carried by wind */ 1331 draw_board(); 1332 if(human) 1333 rb->sleep(HZ*2); 1334 else 1335 rb->sleep(HZ); 1336 return RET_VAL_OK; 1337} 1338 1339static int movement_menu(void) 1340{ 1341 int selection = 0, temp; 1342 1343 MENUITEM_STRINGLIST(menu, "Movement", NULL, 1344 "Move unit", "Buy additional moves ($" PRICE_MOVE_STR ")", 1345 "Launch nuclear missile", "Check map", 1346 "Finish moving", "Game menu"); 1347 1348 while(1) 1349 { 1350 switch(rb->do_menu(&menu, &selection, NULL, false)) 1351 { 1352 case 0: 1353 if(humanres.moves) 1354 { 1355 if(move_unit_menu()==RET_VAL_USB) 1356 return RET_VAL_USB; 1357 } 1358 else 1359 { 1360 rb->splash(HZ, "You have no more moves left." 1361 " You can buy more for $" PRICE_MOVE_STR " each."); 1362 } 1363 break; 1364 case 1: 1365 if(humanres.cash > PRICE_MOVE) 1366 { 1367 humanres.moves++; 1368 humanres.cash -= PRICE_MOVE; 1369 rb->snprintf(buf, sizeof(buf), "You now have %d moves", 1370 humanres.moves); 1371 rb->splash(HZ, buf); 1372 } 1373 else 1374 { 1375 rb->splash(HZ, "Not enough money!"); 1376 } 1377 break; 1378 case 2: 1379 if(humanres.nukes==0) 1380 { 1381 rb->splash(HZ, "You do not have any nukes to launch"); 1382 } 1383 else 1384 { 1385 rb->splash(HZ, "Select place to launch nuke from"); 1386 switch(select_square()) 1387 { 1388 case RET_VAL_OK: 1389 if(launch_nuke(COLOUR_LIGHT, cursor.x, cursor.y, 1390 0, 0) == RET_VAL_USB) 1391 return RET_VAL_USB; 1392 break; 1393 case RET_VAL_USB: 1394 return RET_VAL_USB; 1395 break; 1396 } 1397 } 1398 break; 1399 case 3: 1400 if(select_square() == RET_VAL_USB) 1401 return RET_VAL_USB; 1402 break; 1403 case 4: 1404 return RET_VAL_OK; 1405 break; 1406 case 5: 1407 if((temp = ingame_menu()) != RET_VAL_OK) 1408 return temp; 1409 break; 1410 case MENU_ATTACHED_USB: 1411 return RET_VAL_USB; 1412 break; 1413 } 1414 } 1415 return RET_VAL_OK; 1416} 1417 1418static const char* inventory_data(int selected_item, void * data, 1419 char * buffer, size_t buffer_len) 1420{ 1421 (void)data; 1422 switch(selected_item) 1423 { 1424 case 0: 1425 rb->snprintf(buffer,buffer_len,"Men: %d", humanres.men); 1426 break; 1427 case 1: 1428 rb->snprintf(buffer,buffer_len,"Tanks: %d", humanres.tanks); 1429 break; 1430 case 2: 1431 rb->snprintf(buffer,buffer_len,"Planes: %d", humanres.planes); 1432 break; 1433 case 3: 1434 rb->snprintf(buffer,buffer_len,"Factories: %d", humanres.inds); 1435 break; 1436 case 4: 1437 rb->snprintf(buffer,buffer_len,"Farms: %d", humanres.farms); 1438 break; 1439 case 5: 1440 rb->snprintf(buffer,buffer_len,"Nukes: %d", humanres.nukes); 1441 break; 1442 case 6: 1443 rb->snprintf(buffer,buffer_len,"Cash: %d", humanres.cash); 1444 break; 1445 case 7: 1446 rb->snprintf(buffer,buffer_len,"Food: %d", humanres.food); 1447 break; 1448 case 8: 1449 rb->snprintf(buffer,buffer_len,"Bank: %d", humanres.bank); 1450 break; 1451 default: 1452 return NULL; 1453 } 1454 return buffer; 1455} 1456 1457static int show_inventory(void) 1458{ 1459 struct simplelist_info info; 1460 rb->simplelist_info_init(&info, "Inventory", 9, NULL); 1461 info.get_name = inventory_data; 1462 if(rb->simplelist_show_list(&info)) 1463 { 1464 return RET_VAL_USB; 1465 } 1466 else 1467 { 1468 return RET_VAL_OK; 1469 } 1470} 1471 1472static int production_menu(void) 1473{ 1474 int selection = 0, temp; 1475 1476 MENUITEM_STRINGLIST(menu, "Production", NULL, 1477 "Buy resources", "Show inventory", "Check map", 1478 "Invest money", "Withdraw money", 1479 "Finish turn", "Game menu"); 1480 1481 while(1) 1482 { 1483 switch(rb->do_menu(&menu, &selection, NULL, false)) 1484 { 1485 case 0: 1486 if(buy_resources_menu() == RET_VAL_USB) 1487 return RET_VAL_USB; 1488 break; 1489 case 1: 1490 if(show_inventory() == RET_VAL_USB) 1491 return RET_VAL_USB; 1492 break; 1493 case 2: 1494 if(select_square() == RET_VAL_USB) 1495 return RET_VAL_USB; 1496 break; 1497 case 3: 1498 temp = humanres.cash; 1499 if(get_number("How much do you want to invest?", &temp, 1500 humanres.cash) == RET_VAL_USB) 1501 return RET_VAL_USB; 1502 if(temp > humanres.cash) 1503 { 1504 rb->splash(HZ, "You don't have that much cash to invest"); 1505 } 1506 else 1507 { 1508 humanres.cash -= temp; 1509 humanres.bank += temp; 1510 } 1511 break; 1512 case 4: 1513 temp = humanres.bank; 1514 if(get_number("How much do you want to withdraw?", &temp, 1515 humanres.bank) == RET_VAL_USB) 1516 return RET_VAL_USB; 1517 if(temp > humanres.bank) 1518 { 1519 rb->splash(HZ, "You don't have that much cash to withdraw"); 1520 } 1521 else 1522 { 1523 humanres.cash += temp; 1524 humanres.bank -= temp; 1525 } 1526 break; 1527 case 5: 1528 return RET_VAL_OK; 1529 break; 1530 case 6: 1531 if((temp = ingame_menu()) != RET_VAL_OK) 1532 return temp; 1533 break; 1534 case MENU_ATTACHED_USB: 1535 return RET_VAL_USB; 1536 break; 1537 } 1538 } 1539 return RET_VAL_OK; 1540} 1541 1542static void init_resources(void) 1543{ 1544 humanres.cash = superdom_settings.startcash; 1545 humanres.food = superdom_settings.startfood; 1546 humanres.tanks = 0; 1547 humanres.planes = 0; 1548 humanres.nukes = 0; 1549 humanres.inds = 0; 1550 humanres.farms = 0; 1551 humanres.men = 0; 1552 humanres.bank = 0; 1553 humanres.moves = 0; 1554 compres.cash = superdom_settings.startcash; 1555 compres.food = superdom_settings.startfood; 1556 compres.tanks = 0; 1557 compres.planes = 0; 1558 compres.nukes = 0; 1559 compres.inds = 0; 1560 compres.farms = 0; 1561 compres.men = 0; 1562 compres.bank = 0; 1563 compres.moves = 0; 1564} 1565 1566static int select_square(void) 1567{ 1568 int button = 0; 1569 draw_board(); 1570 draw_cursor(); 1571 update_score(); 1572#if LCD_WIDTH >= 220 1573 rb->lcd_setfont(FONT_SYSFIXED); 1574 rb->lcd_putsxyf(125, LCD_HEIGHT-20,"Cash: %d", humanres.cash); 1575 rb->lcd_putsxyf(125, LCD_HEIGHT-10,"Food: %d", humanres.food); 1576 rb->lcd_setfont(FONT_UI); 1577#endif 1578 rb->lcd_update(); 1579 while(1) 1580 { 1581 button=pluginlib_getaction(-1, plugin_contexts, ARRAYLEN(plugin_contexts)); 1582 switch(button) 1583 { 1584 case SUPERDOM_CANCEL: 1585 rb->splash(HZ, "Cancelled"); 1586 return RET_VAL_QUIT_ERR; 1587 break; 1588 case SUPERDOM_OK: 1589 return RET_VAL_OK; 1590 break; 1591 case SUPERDOM_LEFT: 1592 case SUPERDOM_LEFT_REPEAT: 1593 draw_cursor(); /* Deselect the current tile */ 1594 if(cursor.x>1) 1595 { 1596 cursor.x--; 1597 } 1598 else 1599 { 1600 cursor.x = BOARD_SIZE; 1601 } 1602 update_score(); 1603 draw_cursor(); 1604 break; 1605 case SUPERDOM_RIGHT: 1606 case SUPERDOM_RIGHT_REPEAT: 1607 draw_cursor(); /* Deselect the current tile */ 1608 if(cursor.x<BOARD_SIZE) 1609 { 1610 cursor.x++; 1611 } 1612 else 1613 { 1614 cursor.x = 1; 1615 } 1616 update_score(); 1617 draw_cursor(); 1618 break; 1619 case SUPERDOM_UP: 1620 case SUPERDOM_UP_REPEAT: 1621 draw_cursor(); /* Deselect the current tile */ 1622 if(cursor.y>1) 1623 { 1624 cursor.y--; 1625 } 1626 else 1627 { 1628#if CONFIG_KEYPAD == IRIVER_H10_PAD 1629 if(cursor.x > 1) 1630 cursor.x--; 1631 else 1632 cursor.x = BOARD_SIZE; 1633#endif 1634 cursor.y = BOARD_SIZE; 1635 } 1636 update_score(); 1637 draw_cursor(); 1638 break; 1639 case SUPERDOM_DOWN: 1640 case SUPERDOM_DOWN_REPEAT: 1641 draw_cursor(); /* Deselect the current tile */ 1642 if(cursor.y<BOARD_SIZE) 1643 { 1644 cursor.y++; 1645 } 1646 else 1647 { 1648#if CONFIG_KEYPAD == IRIVER_H10_PAD 1649 if(cursor.x < BOARD_SIZE) 1650 cursor.x++; 1651 else 1652 cursor.x = 1; 1653#endif 1654 cursor.y = 1; 1655 } 1656 update_score(); 1657 draw_cursor(); 1658 break; 1659 default: 1660 if (rb->default_event_handler(button) == SYS_USB_CONNECTED) 1661 { 1662 return RET_VAL_USB; 1663 } 1664 } 1665 } 1666} 1667 1668static int killmen(int colour) 1669{ 1670 bool human = (colour == COLOUR_LIGHT); 1671 int menkilled,i,j; 1672 int percent; 1673 if(human) 1674 { 1675 percent = (humanres.food*1000)/humanres.men; 1676 humanres.food = 0; 1677 } 1678 else 1679 { 1680 percent = (compres.food*1000)/compres.men; 1681 compres.food = 0; 1682 } 1683 menkilled = 0; 1684 for(i=1;i<=BOARD_SIZE;i++) 1685 { 1686 for(j=1;j<=BOARD_SIZE;j++) 1687 { 1688 if(board[i][j].colour == colour) 1689 { 1690 int nummen = ((board[i][j].men * percent)/1000); 1691 menkilled += board[i][j].men - nummen; 1692 board[i][j].men = nummen; 1693 } 1694 } 1695 } 1696 1697 if(human) 1698 humanres.men -= menkilled; 1699 else 1700 compres.men -= menkilled; 1701 return menkilled; 1702} 1703 1704/* return -1 if error, 1 if attack is succeeded, 0 otherwise */ 1705static int attack_territory(int colour, int x, int y) 1706{ 1707 bool human = (colour == COLOUR_LIGHT); 1708 int str_diff; 1709 1710 if(board[x][y].colour == colour) 1711 { 1712 if(human) 1713 rb->splash(HZ, "You can't attack your own territory"); 1714 return -1; 1715 } 1716 str_diff = calc_strength(COLOUR_DARK, x, y) - 1717 calc_strength(COLOUR_LIGHT, x, y); 1718 if(human) 1719 { 1720 str_diff = -str_diff; 1721 } 1722 if(str_diff > 0 || (str_diff == 0 && rb->rand()%2)) 1723 { 1724 struct resources *offres, *defres; 1725 if(human) 1726 { 1727 offres = &humanres; 1728 defres = &compres; 1729 } 1730 else 1731 { 1732 offres = &compres; 1733 defres = &humanres; 1734 } 1735 defres->men -= board[x][y].men; 1736 defres->tanks -= board[x][y].tank; 1737 defres->planes -= board[x][y].plane; 1738 defres->nukes -= board[x][y].nuke; 1739 defres->farms -= board[x][y].farm; 1740 defres->inds -= board[x][y].ind; 1741 offres->farms += board[x][y].farm; 1742 offres->inds += board[x][y].ind; 1743 offres->nukes += board[x][y].nuke; 1744 board[x][y].colour = colour; 1745 if(!superdom_settings.persistent_units) 1746 { 1747 board[x][y].men = 0; 1748 board[x][y].tank = false; 1749 board[x][y].plane = false; 1750 } 1751 draw_board(); 1752 if(human) 1753 rb->sleep(HZ*2); 1754 else 1755 rb->sleep(HZ); 1756 return 1; 1757 } 1758 else 1759 { 1760 if(human) 1761 rb->splash(HZ, "Your troops were unable to overcome" 1762 " the enemy troops"); 1763 else 1764 rb->splash(HZ*2, "The computer attempted to " 1765 "attack, but the invasion was" 1766 " pushed back"); 1767 return 0; 1768 } 1769 return 0; 1770} 1771 1772static void spoil_food(void) 1773{ 1774 /* spoil 0-10% of food, different amounts for computer/player */ 1775 int spoil_amount=humanres.food*(0.1*rb->rand()/RAND_MAX); 1776 if(spoil_amount) 1777 rb->splashf(2*HZ, "Spoilage claims %d units of food", spoil_amount); 1778 humanres.food-=spoil_amount; 1779 1780 /* now for computer */ 1781 spoil_amount=compres.food*(0.1*rb->rand()/RAND_MAX); 1782 compres.food-=spoil_amount; 1783} 1784 1785static int war_menu(void) 1786{ 1787 int selection = 0, temp; 1788 1789 MENUITEM_STRINGLIST(menu, "War!", NULL, 1790 "Select territory to attack", 1791 "Finish turn", "Game menu"); 1792 1793 while(humanres.moves) 1794 { 1795 switch(rb->do_menu(&menu, &selection, NULL, false)) 1796 { 1797 case 0: 1798 switch(select_square()) 1799 { 1800 case RET_VAL_OK: 1801 if(attack_territory(COLOUR_LIGHT, cursor.x, cursor.y) >= 0) 1802 humanres.moves--; 1803 break; 1804 case RET_VAL_USB: 1805 return RET_VAL_USB; 1806 break; 1807 } 1808 break; 1809 case 1: 1810 return RET_VAL_OK; 1811 break; 1812 case 2: 1813 if((temp = ingame_menu()) != RET_VAL_OK) 1814 return temp; 1815 break; 1816 } 1817 } 1818 return RET_VAL_OK; 1819} 1820 1821struct threat { 1822 int x; 1823 int y; 1824 int str_diff; 1825}; 1826 1827static bool place_adjacent(bool tank, int x, int y) 1828{ 1829 int type = (tank ? 1: 2); 1830 if(!buy_resources(COLOUR_DARK, type, x, y, 0)) 1831 { 1832 return true; 1833 } 1834 if(!buy_resources(COLOUR_DARK, type, x-1, y, 0)) 1835 { 1836 return true; 1837 } 1838 if(!buy_resources(COLOUR_DARK, type, x+1, y, 0)) 1839 { 1840 return true; 1841 } 1842 if(!buy_resources(COLOUR_DARK, type, x, y-1, 0)) 1843 { 1844 return true; 1845 } 1846 if(!buy_resources(COLOUR_DARK, type, x, y+1, 0)) 1847 { 1848 return true; 1849 } 1850 return false; 1851} 1852 1853static bool has_adjacent(int x, int y) 1854{ 1855 if ((board[x][y].colour == COLOUR_LIGHT) && 1856 ((board[x-1][y].colour == COLOUR_DARK) || 1857 (board[x+1][y].colour == COLOUR_DARK) || 1858 (board[x][y+1].colour == COLOUR_DARK) || 1859 (board[x][y-1].colour == COLOUR_DARK))) 1860 return 1; 1861 else 1862 return 0; 1863} 1864 1865static void find_adjacent(int x, int y, int* adj_x, int* adj_y) 1866{ 1867 /* Finds adjacent squares, returning squares without tanks on them 1868 * in preference to those with them */ 1869 if(board[x-1][y].colour == COLOUR_DARK) 1870 { 1871 *adj_x = x-1; 1872 *adj_y = y; 1873 return; 1874 } 1875 if(board[x+1][y].colour == COLOUR_DARK) 1876 { 1877 *adj_x = x+1; 1878 *adj_y = y; 1879 return; 1880 } 1881 if(board[x][y-1].colour == COLOUR_DARK) 1882 { 1883 *adj_x = x; 1884 *adj_y = y-1; 1885 return; 1886 } 1887 if(board[x][y+1].colour == COLOUR_DARK) 1888 { 1889 *adj_x = x; 1890 *adj_y = y+1; 1891 return; 1892 } 1893} 1894 1895static void computer_allocate(void) 1896{ 1897 /* Firstly, decide whether to go offensive or defensive. 1898 * This is primarily decided by the human player posing a threat to either 1899 * the computer's farms, factories or nukes */ 1900 int i, j, k; 1901 bool offensive = true; 1902 struct threat threats[4]; 1903 int numthreats = 0; 1904 int total_str_diff = 0; 1905 int numterritory = 0; 1906 int str_diff; 1907 int men_needed; 1908 struct threat targets[2]; 1909 int numtargets; 1910 struct cursor adj = { 0, 0 }; 1911 1912 compres.cash += compres.bank; 1913 compres.bank = 0; 1914 for(i=1;i<=BOARD_SIZE;i++) 1915 { 1916 for(j=1;j<=BOARD_SIZE;j++) 1917 { 1918 if(board[i][j].colour == COLOUR_DARK) 1919 { 1920 numterritory++; 1921 str_diff = calc_strength(COLOUR_LIGHT,i,j) - 1922 calc_strength(COLOUR_DARK,i,j); 1923 if(str_diff > 0 && (board[i][j].ind || board[i][j].farm || board[i][j].nuke)) 1924 { 1925 /* computer's farm/factory/nuke is being threatened */ 1926 if(numthreats < 3) 1927 { 1928 offensive = false; 1929 threats[numthreats].x = i; 1930 threats[numthreats].y = j; 1931 threats[numthreats].str_diff = str_diff; 1932 numthreats++; 1933 } 1934 } 1935 } 1936 rb->yield(); 1937 } 1938 } 1939 /* if the computer has no factories, build some ASAP */ 1940 if(!compres.inds) 1941 { 1942 while(compres.cash >= PRICE_FACTORY && compres.inds < numterritory) 1943 { 1944 i = rb->rand()%BOARD_SIZE + 1; 1945 j = rb->rand()%BOARD_SIZE + 1; 1946 if(board[i][j].colour == COLOUR_DARK) 1947 { 1948 buy_resources(COLOUR_DARK, 4, i, j, 0); 1949 } 1950 } 1951 } 1952 if(superdom_settings.compdiff>=AI_BUILD_INDS_FARMS_LEVEL && compres.cash>=PRICE_FACTORY+100) 1953 { 1954 int cnt = 0; 1955 do 1956 { 1957 if(compres.farms<compres.inds) 1958 { 1959 i = rb->rand()%BOARD_SIZE + 1; 1960 j = rb->rand()%BOARD_SIZE + 1; 1961 if(board[i][j].colour == COLOUR_DARK && !board[i][j].farm) 1962 { 1963 buy_resources(COLOUR_DARK, 3, i, j, 0); 1964 break; 1965 } 1966 } 1967 else 1968 { 1969 i = rb->rand()%BOARD_SIZE + 1; 1970 j = rb->rand()%BOARD_SIZE + 1; 1971 if(board[i][j].colour == COLOUR_DARK && !board[i][j].ind) 1972 { 1973 buy_resources(COLOUR_DARK, 4, i, j, 0); 1974 break; 1975 } 1976 } 1977 } while(compres.cash>=PRICE_FACTORY + 100 && cnt++ < 3); 1978 } 1979 /* AI will buy nukes first if possible */ 1980 if(compres.cash > PRICE_NUKE + PRICE_TANK && superdom_settings.compdiff>=AI_BUILD_NUKES_LEVEL) 1981 { 1982 while(compres.cash >= PRICE_NUKE && compres.nukes < numterritory) 1983 { 1984 i = rb->rand()%BOARD_SIZE + 1; 1985 j = rb->rand()%BOARD_SIZE + 1; 1986 if(board[i][j].colour == COLOUR_DARK) 1987 { 1988 buy_resources(COLOUR_DARK, 5, i, j, 0); 1989 } 1990 rb->yield(); 1991 } 1992 } 1993 if(offensive) 1994 { 1995 /* The AI is going to go straight for the throat here and attack 1996 * the player's farms, nukes, and factories. The amount of cash 1997 * the AI has to spend will determine how many targets there are */ 1998 if(compres.cash > 1200) 1999 { 2000 /* 1200 is a figure I pulled out of nowhere. Adjust as needed */ 2001 numtargets = 2; 2002 } 2003 else 2004 { 2005 numtargets = 1; 2006 } 2007 /* Work out which target(s) to attack. They must have adjacent squares 2008 * owned by the computer. If none are found just place troops in 2009 * random places around the map until we run out of money */ 2010 k = 0; 2011 for(i=1;i<=BOARD_SIZE;i++) 2012 { 2013 for(j=1;j<=BOARD_SIZE;j++) 2014 { 2015 if(has_adjacent(i,j) && 2016 (board[i][j].ind || board[i][j].farm || board[i][j].nuke)) 2017 { 2018 if(k<numtargets) 2019 { 2020 targets[k].x = i; 2021 targets[k].y = j; 2022 targets[k].str_diff = 2023 calc_strength(COLOUR_LIGHT, i, j) - 2024 calc_strength(COLOUR_DARK, i, j); 2025 k++; 2026 } 2027 } 2028 rb->yield(); 2029 } 2030 } 2031 if(k == 0) 2032 { 2033 /* randomly place tanks */ 2034 while(compres.cash >= PRICE_TANK && compres.tanks < numterritory) 2035 { 2036 i = rb->rand()%BOARD_SIZE + 1; 2037 j = rb->rand()%BOARD_SIZE + 1; 2038 if(board[i][j].colour == COLOUR_DARK) 2039 { 2040 buy_resources(COLOUR_DARK, 1, i, j, 0); 2041 } 2042 rb->yield(); 2043 } 2044 } 2045 else 2046 { 2047 for(i=0;i<k;i++) 2048 { 2049 str_diff = targets[i].str_diff; 2050 while(str_diff + 20 > 0 && compres.cash > 0) 2051 { 2052 /* While we still need them keep placing men */ 2053 if(!place_adjacent(true, targets[i].x, targets[i].y)) 2054 { 2055 find_adjacent(targets[i].x, targets[i].y, 2056 &adj.x, &adj.y); 2057 men_needed = (str_diff + 20)*1000/133; 2058 if(compres.cash < men_needed) 2059 { 2060 men_needed = compres.cash; 2061 } 2062 buy_resources(COLOUR_DARK, 0, adj.x, adj.y, 2063 men_needed); 2064 break; 2065 } 2066 str_diff = calc_strength(COLOUR_LIGHT, 2067 targets[i].x, targets[i].y) - 2068 calc_strength(COLOUR_DARK, 2069 targets[i].x, targets[i].y); 2070 } 2071 } 2072 } 2073 } 2074 else 2075 { 2076 /* Work out what to place on each square to defend it. 2077 * Tanks are preferential because they do not require food, 2078 * but if the budget is tight then we fall back onto troops. 2079 * Conversely if cash is not an issue and there are already tanks in 2080 * place planes will be deployed. We would like a margin of at least 2081 * 20 points to be safe. */ 2082 2083 for(i=0;i<numthreats;i++) 2084 { 2085 total_str_diff += threats[i].str_diff; 2086 } 2087 if((total_str_diff+20)*10 > compres.cash) 2088 { 2089 /* Not enough cash to accomodate all threats using tanks alone - 2090 * use men as a backup */ 2091 for(i=0;i<numthreats;i++) 2092 { 2093 men_needed = ((threats[i].str_diff + 20)*1000)/133; 2094 if(compres.cash < men_needed) 2095 { 2096 men_needed = compres.cash; 2097 } 2098 buy_resources(COLOUR_DARK, 0, threats[i].x, threats[i].y, 2099 men_needed); 2100 } 2101 } 2102 else 2103 { 2104 /* Tanks it is */ 2105 /* Enough money to pay their way by planes? */ 2106 bool tank = ((total_str_diff+20)*15 >= compres.cash); 2107 for(i=0;i<numthreats;i++) 2108 { 2109 str_diff = threats[i].str_diff; 2110 while(str_diff + 20 > 0) 2111 { 2112 if(!place_adjacent(tank, threats[i].x, threats[i].y)) 2113 { 2114 /* No room for any more planes or tanks, revert to 2115 * men */ 2116 find_adjacent(threats[i].x, threats[i].y, 2117 &adj.x, &adj.y); 2118 men_needed = (str_diff + 20)*1000/133; 2119 if(compres.cash < men_needed) 2120 { 2121 men_needed = compres.cash; 2122 } 2123 buy_resources(COLOUR_DARK, 0, threats[i].x, 2124 threats[i].y, men_needed); 2125 break; 2126 } 2127 str_diff = calc_strength(COLOUR_LIGHT, 2128 threats[i].x, threats[i].y) - 2129 calc_strength(COLOUR_DARK, 2130 threats[i].x, threats[i].y); 2131 } 2132 } 2133 } 2134 } 2135 /* no investing in easy mode */ 2136 if(superdom_settings.compdiff>=AI_INVESTING_LEVEL) 2137 { 2138 compres.bank += compres.cash; 2139 compres.cash = 0; 2140 } 2141} 2142 2143static int find_adj_target(int x, int y, struct cursor* adj) 2144{ 2145 /* Find a square next to a computer's farm or factory owned by the player 2146 * that is vulnerable. Return 1 on success, 0 otherwise */ 2147 if(board[x+1][y].colour == COLOUR_LIGHT && 2148 calc_strength(COLOUR_LIGHT,x+1,y)<=calc_strength(COLOUR_DARK,x+1,y)) 2149 { 2150 adj->x = x+1; 2151 adj->y = y; 2152 return 1; 2153 } 2154 if(board[x-1][y].colour == COLOUR_LIGHT && 2155 calc_strength(COLOUR_LIGHT,x-1,y)<=calc_strength(COLOUR_DARK,x-1,y)) 2156 { 2157 adj->x = x-1; 2158 adj->y = y; 2159 return 1; 2160 } 2161 if(board[x][y+1].colour == COLOUR_LIGHT && 2162 calc_strength(COLOUR_LIGHT,x,y+1)<=calc_strength(COLOUR_DARK,x,y+1)) 2163 { 2164 adj->x = x; 2165 adj->y = y+1; 2166 return 1; 2167 } 2168 if(board[x][y-1].colour == COLOUR_LIGHT && 2169 calc_strength(COLOUR_LIGHT,x,y-1)<=calc_strength(COLOUR_DARK,x,y-1)) 2170 { 2171 adj->x = x; 2172 adj->y = y-1; 2173 return 1; 2174 } 2175 return 0; 2176} 2177 2178static void computer_movement(void) 2179{ 2180 /* use nukes */ 2181 if(superdom_settings.compdiff>=3) 2182 { 2183 struct cursor nukes[10]; /* 10 for now, change as needed */ 2184 int nukes_back=0; 2185 if(compres.nukes>0) 2186 { 2187 for(int i=1;i<=BOARD_SIZE && nukes_back<compres.nukes && nukes_back<10;i++) 2188 { 2189 for(int j=1;j<BOARD_SIZE && nukes_back<compres.nukes && nukes_back<10 ;j++) 2190 { 2191 if(board[i][j].nuke) 2192 { 2193 nukes[nukes_back].x=i; 2194 nukes[nukes_back].y=j; 2195 nukes_back++; 2196 } 2197 rb->yield(); 2198 } 2199 } 2200 bool found_target=true; 2201 struct cursor adj; 2202 int next_nuke=0; 2203 /* first, use nukes for defence */ 2204 while(found_target && next_nuke<nukes_back) 2205 { 2206 found_target = false; 2207 for(int i=1;i<=BOARD_SIZE && nukes_back<compres.nukes && nukes_back<10;i++) 2208 { 2209 for(int j=1;j<=BOARD_SIZE && nukes_back<compres.nukes && nukes_back<10;j++) 2210 { 2211 if((board[i][j].colour == COLOUR_DARK) && 2212 (board[i][j].farm || board[i][j].ind || board[i][j].nuke) && 2213 find_adj_target(i, j, &adj)) 2214 { 2215 found_target = true; 2216 rb->splashf(2*HZ, "Launching nuke for defence, from (%d, %d) to (%d, %d)", nukes[next_nuke].x, nukes[next_nuke].y, adj.x, adj.y); 2217 launch_nuke(COLOUR_DARK, nukes[next_nuke].x, nukes[next_nuke].y, adj.x, adj.y); 2218 next_nuke++; 2219 } 2220 rb->yield(); 2221 } 2222 } 2223 } 2224 2225 /* if we still have any left over, use those for offence */ 2226 found_target = true; 2227 while(found_target && next_nuke<nukes_back) 2228 { 2229 found_target = false; 2230 for(int i=1;i<=BOARD_SIZE;i++) 2231 { 2232 for(int j=1;j<=BOARD_SIZE;j++) 2233 { 2234 if(board[i][j].colour == COLOUR_LIGHT && 2235 (board[i][j].ind || board[i][j].farm || board[i][j].nuke) && 2236 (calc_strength(COLOUR_DARK, i, j) >= calc_strength(COLOUR_LIGHT, i, j))) 2237 { 2238 found_target = true; 2239 rb->splashf(2*HZ, "Launching nuke for offence, nuke index %d", next_nuke); 2240 launch_nuke(COLOUR_DARK, nukes[next_nuke].x, nukes[next_nuke].y, i, j); 2241 next_nuke++; 2242 } 2243 rb->yield(); 2244 } 2245 } 2246 } 2247 2248 } 2249 } 2250 /* TODO: move other units */ 2251} 2252 2253static void computer_war(void) 2254{ 2255 /* Work out where to attack - prioritise the defence of buildings and nukes */ 2256 int i, j; 2257 bool found_target = true; 2258 struct cursor adj; 2259 2260 while(found_target) 2261 { 2262 found_target = false; 2263 for(i=1;i<=BOARD_SIZE;i++) 2264 { 2265 for(j=1;j<=BOARD_SIZE;j++) 2266 { 2267 if((board[i][j].colour == COLOUR_DARK) && 2268 (board[i][j].farm || board[i][j].ind || board[i][j].nuke) && 2269 find_adj_target(i, j, &adj)) 2270 { 2271 found_target = true; 2272 if(attack_territory(COLOUR_DARK, adj.x, adj.y) >= 0) 2273 { 2274 compres.moves--; 2275 if(!compres.moves) 2276 return; 2277 } 2278 } 2279 rb->yield(); 2280 } 2281 } 2282 } 2283 /* Defence stage done, move on to OFFENCE */ 2284 found_target = true; 2285 while(found_target) 2286 { 2287 found_target = false; 2288 for(i=1;i<=BOARD_SIZE;i++) 2289 { 2290 for(j=1;j<=BOARD_SIZE;j++) 2291 { 2292 if(board[i][j].colour == COLOUR_LIGHT && 2293 (board[i][j].ind || board[i][j].farm || board[i][j].nuke) && 2294 (calc_strength(COLOUR_DARK, i, j) >= calc_strength(COLOUR_LIGHT, i, j))) 2295 { 2296 found_target = true; 2297 if(attack_territory(COLOUR_DARK, i, j) >= 0) 2298 { 2299 compres.moves--; 2300 if(!compres.moves) 2301 return; 2302 } 2303 } 2304 rb->yield(); 2305 } 2306 } 2307 } 2308 /* Spend leftover moves wherever attacking randomly */ 2309 found_target = true; 2310 while(found_target) 2311 { 2312 found_target = false; 2313 for(i=1;i<=BOARD_SIZE;i++) 2314 { 2315 for(j=1;j<=BOARD_SIZE;j++) 2316 { 2317 if(board[i][j].colour == COLOUR_LIGHT && 2318 (calc_strength(COLOUR_DARK, i, j) >= 2319 calc_strength(COLOUR_LIGHT, i, j))) 2320 { 2321 found_target = true; 2322 if(attack_territory(COLOUR_DARK, i, j) >= 0) 2323 { 2324 compres.moves--; 2325 if(!compres.moves) 2326 return; 2327 } 2328 } 2329 rb->yield(); 2330 } 2331 } 2332 } 2333} 2334 2335static int load_game(const char* file) 2336{ 2337 int fd; 2338 2339 fd = rb->open(file, O_RDONLY); 2340 if(fd < 0) 2341 { 2342 DEBUGF("Couldn't open savegame\n"); 2343 return -1; 2344 } 2345 rb->read(fd, buf, 5); 2346 if(rb->strcmp(buf, "SSGv3")) 2347 { 2348 rb->splash(HZ, "Invalid/incompatible savegame"); 2349 return -1; 2350 } 2351 rb->read(fd, &gamestate, sizeof(gamestate)); 2352 rb->read(fd, &humanres.cash, sizeof(humanres.cash)); 2353 rb->read(fd, &humanres.food, sizeof(humanres.food)); 2354 rb->read(fd, &humanres.bank, sizeof(humanres.bank)); 2355 rb->read(fd, &humanres.planes, sizeof(humanres.planes)); 2356 rb->read(fd, &humanres.tanks, sizeof(humanres.tanks)); 2357 rb->read(fd, &humanres.men, sizeof(humanres.men)); 2358 rb->read(fd, &humanres.nukes, sizeof(humanres.nukes)); 2359 rb->read(fd, &humanres.inds, sizeof(humanres.inds)); 2360 rb->read(fd, &humanres.farms, sizeof(humanres.farms)); 2361 rb->read(fd, &humanres.moves, sizeof(humanres.moves)); 2362 rb->read(fd, &compres.cash, sizeof(humanres.cash)); 2363 rb->read(fd, &compres.food, sizeof(humanres.food)); 2364 rb->read(fd, &compres.bank, sizeof(humanres.bank)); 2365 rb->read(fd, &compres.planes, sizeof(humanres.planes)); 2366 rb->read(fd, &compres.tanks, sizeof(humanres.tanks)); 2367 rb->read(fd, &compres.men, sizeof(humanres.men)); 2368 rb->read(fd, &compres.nukes, sizeof(humanres.nukes)); 2369 rb->read(fd, &compres.inds, sizeof(humanres.inds)); 2370 rb->read(fd, &compres.farms, sizeof(humanres.farms)); 2371 rb->read(fd, &compres.moves, sizeof(humanres.moves)); 2372 rb->read(fd, board, sizeof(board)); 2373 rb->read(fd, &superdom_settings.compstartfarms, sizeof(int)); 2374 rb->read(fd, &superdom_settings.compstartinds, sizeof(int)); 2375 rb->read(fd, &superdom_settings.humanstartfarms, sizeof(int)); 2376 rb->read(fd, &superdom_settings.humanstartinds, sizeof(int)); 2377 rb->read(fd, &superdom_settings.startcash, sizeof(int)); 2378 rb->read(fd, &superdom_settings.startfood, sizeof(int)); 2379 rb->read(fd, &superdom_settings.movesperturn, sizeof(int)); 2380 rb->close(fd); 2381 return 0; 2382} 2383 2384static void default_settings(void) 2385{ 2386 superdom_settings.compstartfarms = 1; 2387 superdom_settings.compstartinds = 1; 2388 superdom_settings.humanstartfarms = 2; 2389 superdom_settings.humanstartinds = 2; 2390 superdom_settings.startcash = 0; 2391 superdom_settings.startfood = 0; 2392 superdom_settings.movesperturn = 2; 2393 superdom_settings.compdiff=2; 2394 superdom_settings.spoil_enabled=false; 2395 superdom_settings.persistent_units=false; 2396} 2397 2398static int average_strength(int colour) 2399{ 2400 /* This function calculates the average strength of the given player, 2401 * used to determine when the computer wins or loses. */ 2402 int i,j; 2403 int totalpower = 0; 2404 for(i=1;i<=BOARD_SIZE;i++) 2405 { 2406 for(j=1;j<=BOARD_SIZE;j++) 2407 { 2408 if(board[i][j].colour != -1) 2409 { 2410 totalpower += calc_strength(colour, i, j); 2411 } 2412 } 2413 } 2414 return totalpower/NUM_SPACES; 2415} 2416 2417enum plugin_status plugin_start(const void* parameter) 2418{ 2419 rb->srand(*rb->current_tick); 2420#if LCD_DEPTH > 1 2421 rb->lcd_set_backdrop(NULL); 2422 rb->lcd_set_foreground(LCD_BLACK); 2423 rb->lcd_set_background(LCD_WHITE); 2424#endif 2425 2426 cursor.x = 1; 2427 cursor.y = 1; 2428 default_settings(); 2429 if(parameter) 2430 { 2431 if(load_game(parameter) != 0) 2432 { 2433 DEBUGF("Loading failed, generating new game\n"); 2434 } 2435 else 2436 { 2437 switch(gamestate) 2438 { 2439 case GS_PROD: 2440 goto startprod; 2441 break; 2442 case GS_MOVE: 2443 goto startmove; 2444 break; 2445 case GS_WAR: 2446 goto startwar; 2447 break; 2448 default: 2449 goto startyear; 2450 break; 2451 } 2452 } 2453 } 2454 2455 switch(start_menu()) 2456 { 2457 case RET_VAL_OK: /* start playing */ 2458 break; 2459 case RET_VAL_QUIT_ERR: /* quit */ 2460 return PLUGIN_OK; 2461 break; 2462 case RET_VAL_USB: 2463 return PLUGIN_USB_CONNECTED; 2464 break; 2465 } 2466 2467 init_resources(); 2468 init_board(); 2469 gen_resources(); 2470startyear: 2471 while(1) 2472 { 2473 int avg_str_diff = (average_strength(COLOUR_LIGHT) - 2474 average_strength(COLOUR_DARK)); 2475 /* computer will hold out longer in hard mode */ 2476 if(avg_str_diff > (superdom_settings.compdiff>=3 ? 2477 COMPUTER_HARD_SURRENDER_THRESHOLD : 2478 COMPUTER_SURRENDER_THRESHOLD)) 2479 { 2480 rb->splash(HZ*4, "The computer has surrendered. You win."); 2481 return PLUGIN_OK; 2482 } 2483 if(-avg_str_diff > HUMAN_SURRENDER_THRESHOLD) 2484 { 2485 rb->splash(HZ*4, "Your army has suffered terrible morale from" 2486 " the bleak prospects of winning. You lose."); 2487 return PLUGIN_OK; 2488 } 2489 2490 /* production */ 2491 startprod: 2492 gamestate = GS_PROD; 2493 switch(production_menu()) 2494 { 2495 case RET_VAL_USB: 2496 return PLUGIN_USB_CONNECTED; 2497 break; 2498 case RET_VAL_QUIT_ERR: 2499 return PLUGIN_OK; 2500 break; 2501 } 2502 computer_allocate(); 2503 2504 /* movement */ 2505 humanres.moves = superdom_settings.movesperturn; 2506 startmove: 2507 gamestate = GS_MOVE; 2508 switch(movement_menu()) 2509 { 2510 case RET_VAL_USB: 2511 return PLUGIN_USB_CONNECTED; 2512 break; 2513 case RET_VAL_QUIT_ERR: 2514 return PLUGIN_OK; 2515 break; 2516 } 2517 /* computer movement */ 2518 computer_movement(); 2519 2520 /* spoil food */ 2521 if(superdom_settings.spoil_enabled) 2522 { 2523 spoil_food(); 2524 } 2525 2526 /* feed men */ 2527 if(humanres.men) 2528 { 2529 if(humanres.food > humanres.men) 2530 { 2531 rb->snprintf(buf, sizeof(buf), "Your men ate %d units of food", 2532 humanres.men); 2533 humanres.food -= humanres.men; 2534 } 2535 else 2536 { 2537 rb->snprintf(buf, sizeof(buf), "There was not enough food" 2538 " to feed all your men, %d men have died of starvation", 2539 killmen(COLOUR_LIGHT)); 2540 } 2541 rb->splash(HZ*2, buf); 2542 } 2543 if(compres.men) 2544 { 2545 if(compres.food > compres.men) 2546 { 2547 compres.food -= compres.men; 2548 } 2549 else 2550 { 2551 rb->snprintf(buf, sizeof(buf), "The computer does not have" 2552 " enough food to feed its men. %d have died of starvation", 2553 killmen(COLOUR_DARK)); 2554 rb->splash(HZ, buf); 2555 } 2556 } 2557 /* war */ 2558 humanres.moves = superdom_settings.movesperturn; 2559 startwar: 2560 gamestate = GS_WAR; 2561 switch(war_menu()) 2562 { 2563 case RET_VAL_USB: 2564 return PLUGIN_USB_CONNECTED; 2565 break; 2566 case RET_VAL_QUIT_ERR: 2567 return PLUGIN_OK; 2568 break; 2569 } 2570 compres.moves = superdom_settings.movesperturn; 2571 computer_war(); 2572 gen_resources(); 2573 } 2574 return PLUGIN_OK; 2575}