root/modules/games/gui_sokoban.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. sokoban_undo_add
  2. sokoban_undo
  3. sokoban_redo
  4. sokoban_undo_reset
  5. sokoban_set_level
  6. sokoban_finished
  7. sokoban_next_level
  8. sokoban_move
  9. sokoban_draw_box
  10. gui_sokoban_init
  11. gui_sokoban_kbd_process
  12. gui_sokoban_draw
  13. gui_module_menu_kbd_process
  14. _run
  15. _module_loader
  16. _module_unloader
  17. _module_can_unload
  18. _module_exit_alt

   1 #include "camera_info.h"
   2 #include "keyboard.h"
   3 #include "modes.h"
   4 #include "lang.h"
   5 #include "conf.h"
   6 #include "gui.h"
   7 #include "gui_draw.h"
   8 #include "gui_lang.h"
   9 #include "gui_batt.h"
  10 #include "gui_mbox.h"
  11 
  12 #include "module_def.h"
  13 #include "simple_module.h"
  14 
  15 //-------------------------------------------------------------------
  16 
  17 typedef struct
  18 {
  19     int sokoban_level;
  20 } SokobanConf;
  21 
  22 SokobanConf sconf;
  23 
  24 static ConfInfo conf_info[] = {
  25     CONF_INFO( 1, sconf.sokoban_level,          CONF_DEF_VALUE, i:0),
  26     {0}
  27 };
  28 
  29 void gui_module_menu_kbd_process();
  30 int gui_sokoban_kbd_process();
  31 void gui_sokoban_draw();
  32 
  33 gui_handler GUI_MODE_SOKOBAN = 
  34     /*GUI_MODE_SOKOBAN*/    { GUI_MODE_MODULE, gui_sokoban_draw, gui_sokoban_kbd_process, gui_module_menu_kbd_process, 0, GUI_MODE_FLAG_NODRAWRESTORE };
  35 
  36 //-------------------------------------------------------------------
  37 #define FIELD_WIDTH             15
  38 #define FIELD_HEIGHT            15
  39 
  40 #define WALL_COLOR_1            COLOR_GREY
  41 #define WALL_COLOR_2            COLOR_BLACK
  42 #define BOX_COLOR_1             COLOR_RED
  43 #define BOX_COLOR_2             COLOR_BLACK
  44 #define BOX_COLOR_3             COLOR_YELLOW
  45 #define PLACE_COLOR_1           COLOR_BLUE
  46 #define PLACE_COLOR_2           COLOR_BLACK
  47 #define PLAYER_COLOR_1          COLOR_GREEN
  48 #define PLAYER_COLOR_2          COLOR_BLACK
  49 
  50 #define MARKER_WALL             '#'
  51 #define MARKER_BOX              '$'
  52 #define MARKER_PLACE            '.'
  53 #define MARKER_BOX_PLACE        '*'
  54 #define MARKER_PLAYER           '@'
  55 #define MARKER_PLAYER_PLACE     '+'
  56 #define MARKER_EMPTY            '_' // was space
  57 #define MARKER_LINE_END        '\n' // was |
  58 #define MARKER_LEVEL_END        '!'
  59 
  60 #define LEVEL_CHARS "#$.*@+_"
  61 
  62 #define UNDO_SIZE               1000
  63 
  64 //-------------------------------------------------------------------
  65 static const char *level_file_name="A/CHDK/GAMES/SOKOBAN.LEV";
  66 #define MAX_LEVELS 200
  67 static unsigned short level_start_list[MAX_LEVELS];
  68 static unsigned char level_length_list[MAX_LEVELS];
  69 static int num_levels;
  70 
  71 static int need_redraw;
  72 static int need_redraw_all;
  73 static int  moves;
  74 static char field[FIELD_HEIGHT][FIELD_WIDTH];
  75 
  76 static int cell_size;
  77 static int xPl, yPl;
  78 
  79 static int undo[UNDO_SIZE/10];
  80 static int undo_begin, undo_end, undo_curr;
  81 
  82 //-------------------------------------------------------------------
  83 static void sokoban_undo_add(int dx, int dy, int box) {
  84     int offs, bits, value;
  85 
  86     value = ((box)?1:0)<<2;
  87     if (dx) {
  88         value |= ((dx<0)?1:0)<<1;
  89     } else {
  90         value |= (((dy<0)?1:0)<<1)|1;
  91     }
  92     
  93     offs = undo_curr/10;
  94     bits = (undo_curr%10)*3;
  95     undo[offs] &= ~(7<<bits);
  96     undo[offs] |= (value&7)<<bits;
  97 
  98     if (++undo_curr==UNDO_SIZE) undo_curr=0;
  99     if (undo_curr==undo_begin) {
 100         if (++undo_begin==UNDO_SIZE) undo_begin=0;
 101     }
 102     undo_end=undo_curr;
 103 } 
 104 
 105 //-------------------------------------------------------------------
 106 static void sokoban_undo() {
 107     int dx=0, dy=0, value;
 108     
 109     if (undo_curr!=undo_begin) {
 110         if (undo_curr==0) undo_curr=UNDO_SIZE;
 111         --undo_curr;
 112         
 113         value = (undo[undo_curr/10]>>((undo_curr%10)*3))&7;
 114         if (value&1) dy=1; else dx=1;
 115         if (value&2) {dy=-dy; dx=-dx;}
 116 
 117         field[yPl][xPl]=(field[yPl][xPl]==MARKER_PLAYER_PLACE)?MARKER_PLACE:MARKER_EMPTY;
 118         if (value&4) {
 119             field[yPl+dy][xPl+dx]=(field[yPl+dy][xPl+dx]==MARKER_BOX_PLACE)?MARKER_PLACE:MARKER_EMPTY;
 120             field[yPl][xPl]=(field[yPl][xPl]==MARKER_PLACE)?MARKER_BOX_PLACE:MARKER_BOX;
 121         }
 122         xPl-=dx; yPl-=dy;
 123         field[yPl][xPl]=(field[yPl][xPl]==MARKER_PLACE)?MARKER_PLAYER_PLACE:MARKER_PLAYER;
 124         --moves;
 125     }
 126 }
 127 
 128 //-------------------------------------------------------------------
 129 static void sokoban_redo() {
 130     int dx=0, dy=0, value;
 131     
 132     if (undo_curr!=undo_end) {
 133         value = (undo[undo_curr/10]>>((undo_curr%10)*3))&7;
 134         if (value&1) dy=1; else dx=1;
 135         if (value&2) {dy=-dy; dx=-dx;}
 136 
 137         field[yPl][xPl]=(field[yPl][xPl]==MARKER_PLAYER_PLACE)?MARKER_PLACE:MARKER_EMPTY;
 138         xPl+=dx; yPl+=dy;
 139         if (value&4) {
 140             field[yPl][xPl]=(field[yPl][xPl]==MARKER_BOX_PLACE)?MARKER_PLACE:MARKER_EMPTY;
 141             field[yPl+dy][xPl+dx]=(field[yPl+dy][xPl+dx]==MARKER_PLACE)?MARKER_BOX_PLACE:MARKER_BOX;
 142         }
 143         field[yPl][xPl]=(field[yPl][xPl]==MARKER_PLACE)?MARKER_PLAYER_PLACE:MARKER_PLAYER;
 144         ++moves;
 145 
 146         ++undo_curr;
 147         if (undo_curr==UNDO_SIZE) undo_curr=0;
 148     }
 149 }
 150 
 151 //-------------------------------------------------------------------
 152 static void sokoban_undo_reset() {
 153     undo_begin=undo_end=undo_curr=0;
 154 }
 155 
 156 //-------------------------------------------------------------------
 157 static void sokoban_set_level(int lvl) {
 158     int x=0, y, w=0, h=0;
 159     const char *p;
 160     char *buf;
 161     FILE *fd;    
 162     int start,len;
 163 
 164     len=level_length_list[lvl];
 165     start=level_start_list[lvl];
 166     fd=fopen(level_file_name,"rb");
 167     if(!fd) {
 168         num_levels=0;
 169         return;
 170     }
 171 
 172     buf=malloc(len+1);
 173     if(!buf) {
 174         fclose(fd);
 175         return;
 176     }
 177 
 178     if(fseek(fd,start,SEEK_SET) != 0) {
 179         fclose(fd);
 180         free(buf);
 181         return;
 182     }
 183     fread(buf,1,len,fd);
 184     buf[len]=0;
 185     fclose(fd);
 186 
 187     p=buf;
 188 
 189     // determine dimensions
 190     while (*p) {
 191       if (*p==MARKER_LINE_END) {
 192           ++h;
 193           if (x>w) w=x;
 194           x=0;
 195       } else {
 196           ++x;
 197       }
 198       ++p;
 199     }
 200     if (x>w) w=x;
 201     h-=1; //the last line didn't previously have an end marker
 202 
 203     // clear field
 204     for (y=0; y<FIELD_HEIGHT; ++y)
 205         for (x=0; x<FIELD_WIDTH; ++x)
 206             field[y][x]=MARKER_EMPTY;
 207     
 208     // place maze at the center
 209     p=buf;
 210     for (y=(FIELD_HEIGHT-h)/2; y<FIELD_HEIGHT; ++y, ++p) {
 211         for (x=(FIELD_WIDTH-w)/2; x<FIELD_WIDTH && *p && *p!=MARKER_LINE_END; ++x, ++p) {
 212             field[y][x]=*p;
 213             if (field[y][x] == MARKER_PLAYER || field[y][x] == MARKER_PLAYER_PLACE) {
 214               xPl = x; yPl = y;
 215             }
 216         }
 217         if (!*p || (*p == MARKER_LINE_END && !*(p+1))) break;
 218     }
 219     
 220     free(buf);
 221     sconf.sokoban_level = lvl;
 222     moves = 0;
 223     sokoban_undo_reset();
 224 }
 225 
 226 //-------------------------------------------------------------------
 227 static int sokoban_finished() {
 228     int x, y;
 229 
 230     for (y=0; y<FIELD_HEIGHT; ++y)
 231         for (x=0; x<FIELD_WIDTH; ++x)
 232             if (field[y][x]==MARKER_BOX) 
 233                 return 0;
 234     return 1;
 235 }
 236 
 237 //-------------------------------------------------------------------
 238 static void sokoban_next_level() {
 239     if (++sconf.sokoban_level >= num_levels) sconf.sokoban_level = 0;
 240     sokoban_set_level(sconf.sokoban_level);
 241     need_redraw_all = 1;
 242 }
 243 
 244 //-------------------------------------------------------------------
 245 static int sokoban_move(int dx, int dy) {
 246     switch (field[yPl+dy][xPl+dx]) {
 247         case MARKER_WALL:
 248             return 0;
 249             break;
 250         case MARKER_BOX:
 251         case MARKER_BOX_PLACE:
 252             if (field[yPl+dy*2][xPl+dx*2]==MARKER_WALL || field[yPl+dy*2][xPl+dx*2]==MARKER_BOX || field[yPl+dy*2][xPl+dx*2]==MARKER_BOX_PLACE)
 253                 return 0;
 254             break;
 255         case MARKER_PLACE:
 256         case MARKER_EMPTY:
 257             break;
 258     }
 259     field[yPl][xPl]=(field[yPl][xPl]==MARKER_PLAYER_PLACE)?MARKER_PLACE:MARKER_EMPTY;
 260     xPl+=dx; yPl+=dy;
 261     if (field[yPl][xPl]==MARKER_BOX || field[yPl][xPl]==MARKER_BOX_PLACE) {
 262         field[yPl][xPl]=(field[yPl][xPl]==MARKER_BOX_PLACE)?MARKER_PLACE:MARKER_EMPTY;
 263         field[yPl+dy][xPl+dx]=(field[yPl+dy][xPl+dx]==MARKER_PLACE)?MARKER_BOX_PLACE:MARKER_BOX;
 264         sokoban_undo_add(dx, dy, 1);
 265     } else {
 266         sokoban_undo_add(dx, dy, 0);
 267     }
 268     field[yPl][xPl]=(field[yPl][xPl]==MARKER_PLACE)?MARKER_PLAYER_PLACE:MARKER_PLAYER;
 269     return 1;
 270 }
 271 
 272 //-------------------------------------------------------------------
 273 static void sokoban_draw_box(int x, int y, twoColors cl) {
 274     draw_rectangle(camera_screen.disp_left+x*cell_size, y*cell_size, camera_screen.disp_left+x*cell_size+cell_size-1, y*cell_size+cell_size-1, cl, RECT_BORDER1|DRAW_FILLED);
 275     draw_line(camera_screen.disp_left+x*cell_size+2, y*cell_size, camera_screen.disp_left+x*cell_size+2, y*cell_size+cell_size-1, FG_COLOR(cl));
 276     draw_line(camera_screen.disp_left+x*cell_size+cell_size-1-2, y*cell_size, camera_screen.disp_left+x*cell_size+cell_size-1-2, y*cell_size+cell_size-1, FG_COLOR(cl));
 277     draw_line(camera_screen.disp_left+x*cell_size+2, y*cell_size+2, camera_screen.disp_left+x*cell_size+cell_size-1-2, y*cell_size+2, FG_COLOR(cl));
 278     draw_line(camera_screen.disp_left+x*cell_size+2, y*cell_size+cell_size-1-2, camera_screen.disp_left+x*cell_size+cell_size-1-2, y*cell_size+cell_size-1-2, FG_COLOR(cl));
 279 }
 280 
 281 //-------------------------------------------------------------------
 282 int gui_sokoban_init() {
 283     /* first time through, load the file and make an index
 284      if would could tell when the user left sokoban, 
 285      we could avoid this and malloc all the data structures
 286      unfortunately, gui_mode gets set all over the place */
 287     if(!num_levels) {
 288         char *buf,*p;
 289         FILE *fd;    
 290         struct stat st;
 291 
 292         if (stat((char *)level_file_name,&st) != 0 || st.st_size==0) 
 293             return 0;
 294 
 295         fd=fopen(level_file_name,"rb");
 296         if(!fd) 
 297             return 0;
 298 
 299         buf=malloc(st.st_size+1);
 300         if(!buf) {
 301             fclose(fd);
 302             return 0;
 303         }
 304 
 305         fread(buf,1,st.st_size,fd);
 306         buf[st.st_size]=0;
 307         fclose(fd);
 308         p = buf;
 309         do {
 310             // skip to the first level char
 311             p = strpbrk(p,LEVEL_CHARS);
 312             // found a level char, store the start
 313             if (p) {
 314                 unsigned pos = p - buf;
 315                 if ( pos > 65535 ) {
 316                     break;
 317                 }
 318                 level_start_list[num_levels] = (unsigned short)pos;
 319                 p=strchr(p,MARKER_LEVEL_END);
 320                 // found the end char, store the end
 321                 if(p) {
 322                     unsigned len = p - (buf + level_start_list[num_levels]);
 323                     // bail on invalid level
 324                     if ( len > 255 ) {
 325                         break;
 326                     }
 327                     level_length_list[num_levels] = (unsigned char)len;
 328                     ++num_levels;
 329                 }
 330             }
 331         } while(p && num_levels < MAX_LEVELS);
 332         free(buf);
 333     }
 334     if(!num_levels) {
 335         return 0;
 336     }
 337     else if(sconf.sokoban_level >= num_levels) {
 338         sconf.sokoban_level = 0;
 339     }
 340     if (camera_screen.height*3 > camera_screen.width*2) {
 341         // worst case scenario (640x480)
 342         cell_size = 8*camera_screen.height/(9*FIELD_HEIGHT);
 343     }
 344     else {
 345         cell_size = camera_screen.height/FIELD_HEIGHT;
 346     }
 347     sokoban_set_level(sconf.sokoban_level);
 348         // if the file is no longer readable, set_level will set this
 349     if(!num_levels) {
 350         return 0;
 351     }
 352     need_redraw_all = 1;
 353 
 354     gui_set_mode(&GUI_MODE_SOKOBAN);
 355     return 1;
 356 }
 357 
 358 //-------------------------------------------------------------------
 359 int gui_sokoban_kbd_process() {
 360     switch (kbd_get_autoclicked_key()) {
 361         case KEY_UP:
 362             moves+=sokoban_move(0, -1);
 363             need_redraw = 1;
 364             break;
 365         case KEY_DOWN:
 366             moves+=sokoban_move(0, +1);
 367             need_redraw = 1;
 368             break;
 369         case KEY_LEFT:
 370             moves+=sokoban_move(-1, 0);
 371             need_redraw = 1;
 372             break;
 373         case KEY_RIGHT:
 374             moves+=sokoban_move(+1, 0);
 375             need_redraw = 1;
 376             break;
 377         case KEY_SET:
 378             if (moves == 0) {
 379                 sokoban_next_level();
 380             }
 381             break;
 382         case KEY_ZOOM_OUT:
 383             sokoban_undo();
 384             need_redraw = 1;
 385             break;
 386         case KEY_ZOOM_IN:
 387             sokoban_redo();
 388             need_redraw = 1;
 389             break;
 390         case KEY_ERASE:
 391         case KEY_DISPLAY:
 392             sokoban_set_level(sconf.sokoban_level);
 393             need_redraw_all = 1;
 394             break;
 395     }
 396     return 0;
 397 }
 398 
 399 //-------------------------------------------------------------------
 400 void gui_sokoban_draw() {
 401     int y, x;
 402     static char str[16];
 403 
 404     if (need_redraw_all) {
 405         draw_rectangle(camera_screen.disp_left, 0, camera_screen.disp_right, camera_screen.height-1, MAKE_COLOR(COLOR_BLACK, COLOR_BLACK), RECT_BORDER0|DRAW_FILLED);
 406         need_redraw_all = 0;
 407         need_redraw = 1;
 408     }
 409 
 410     if (need_redraw) {
 411         need_redraw = 0;
 412         for (y=0; y<FIELD_HEIGHT; ++y) {
 413             for (x=0; x<FIELD_WIDTH; ++x) {
 414                 switch (field[y][x]) {
 415                     case MARKER_WALL:
 416                         draw_rectangle(camera_screen.disp_left+x*cell_size, y*cell_size, camera_screen.disp_left+x*cell_size+cell_size-1, y*cell_size+cell_size-1, MAKE_COLOR(WALL_COLOR_1, WALL_COLOR_2), RECT_BORDER1|DRAW_FILLED);
 417                         break;
 418                     case MARKER_BOX:
 419                         sokoban_draw_box(x, y, MAKE_COLOR(BOX_COLOR_1, BOX_COLOR_2));
 420                         break;
 421                     case MARKER_PLACE:
 422                         draw_rectangle(camera_screen.disp_left+x*cell_size, y*cell_size, camera_screen.disp_left+x*cell_size+cell_size-1, y*cell_size+cell_size-1, MAKE_COLOR(COLOR_BLACK, COLOR_BLACK), RECT_BORDER0|DRAW_FILLED);
 423                         draw_rectangle(camera_screen.disp_left+x*cell_size+4, y*cell_size+4, camera_screen.disp_left+x*cell_size+cell_size-1-4, y*cell_size+cell_size-1-4, MAKE_COLOR(PLACE_COLOR_1, PLACE_COLOR_2), RECT_BORDER1|DRAW_FILLED);
 424                         break;
 425                     case MARKER_BOX_PLACE:
 426                         sokoban_draw_box(x, y, MAKE_COLOR(BOX_COLOR_3, BOX_COLOR_2));
 427                         break;
 428                     case MARKER_PLAYER:
 429                     case MARKER_PLAYER_PLACE:
 430                         draw_rectangle(camera_screen.disp_left+x*cell_size, y*cell_size, camera_screen.disp_left+x*cell_size+cell_size-1, y*cell_size+cell_size-1, MAKE_COLOR(COLOR_BLACK, COLOR_BLACK), RECT_BORDER0|DRAW_FILLED);
 431                         draw_ellipse(camera_screen.disp_left+x*cell_size+(cell_size>>1)-1, y*cell_size+(cell_size>>1)-1, (cell_size>>1)-3, (cell_size>>1)-3, PLAYER_COLOR_1, DRAW_FILLED);
 432                         break;
 433                     case MARKER_EMPTY:
 434                     default:
 435                         draw_rectangle(camera_screen.disp_left+x*cell_size, y*cell_size, camera_screen.disp_left+x*cell_size+cell_size-1, y*cell_size+cell_size-1, MAKE_COLOR(COLOR_BLACK, COLOR_BLACK), RECT_BORDER0|DRAW_FILLED);
 436                         break;
 437                 }
 438             }
 439         }
 440 
 441         draw_line(camera_screen.disp_left+cell_size*FIELD_WIDTH, 0, camera_screen.disp_left+cell_size*FIELD_WIDTH, camera_screen.height-1, COLOR_WHITE);
 442         draw_line(camera_screen.disp_left+cell_size*FIELD_WIDTH+1, 0, camera_screen.disp_left+cell_size*FIELD_WIDTH+1, camera_screen.height-1, COLOR_BLACK);
 443 
 444         sprintf(str, "%s: %-6d", lang_str(LANG_SOKOBAN_TEXT_LEVEL), sconf.sokoban_level+1);
 445         draw_string(camera_screen.disp_left+cell_size*FIELD_WIDTH+2, 8, str, MAKE_COLOR(COLOR_BLACK, COLOR_WHITE));
 446         sprintf(str, "%s: %-6d", lang_str(LANG_SOKOBAN_TEXT_MOVES), moves);
 447         draw_string(camera_screen.disp_left+cell_size*FIELD_WIDTH+2, 8+FONT_HEIGHT, str, MAKE_COLOR(COLOR_BLACK, COLOR_WHITE));
 448 
 449         if (sokoban_finished()) {
 450             gui_mbox_init(LANG_SOKOBAN_MSG_FINISH_TITLE, LANG_SOKOBAN_MSG_FINISH_TEXT, MBOX_TEXT_CENTER, NULL);
 451             sokoban_next_level();
 452         }
 453     }
 454 
 455     sprintf(str, "Batt:%3d%%", get_batt_perc());
 456     draw_string_justified(camera_screen.disp_left, camera_screen.height-FONT_HEIGHT,
 457                           str, MAKE_COLOR(COLOR_BLACK, COLOR_WHITE), 0, camera_screen.disp_width-FONT_WIDTH, TEXT_RIGHT);
 458 }
 459 
 460 
 461 static int running = 0;
 462 
 463 void gui_module_menu_kbd_process()
 464 {
 465     running = 0;
 466         gui_default_kbd_process_menu_btn();
 467 }
 468 
 469 // =========  MODULE INIT =================
 470 
 471 /***************** BEGIN OF AUXILARY PART *********************
 472   ATTENTION: DO NOT REMOVE OR CHANGE SIGNATURES IN THIS SECTION
 473  **************************************************************/
 474 
 475 int _run()
 476 {
 477     if (!camera_info.state.mode_play)
 478     {
 479         gui_mbox_init(LANG_MSG_INFO_TITLE, LANG_MSG_SWITCH_TO_PLAY_MODE, MBOX_FUNC_RESTORE|MBOX_TEXT_CENTER, 0);
 480     }
 481     else
 482     {
 483         running = 1;
 484         gui_sokoban_init();
 485     }
 486 
 487     return 0;
 488 }
 489 
 490 //---------------------------------------------------------
 491 // PURPOSE:   Perform on-load initialisation
 492 // RETURN VALUE: 1 error, 0 ok
 493 //---------------------------------------------------------
 494 int _module_loader( __attribute__ ((unused))unsigned int* chdk_export_list )
 495 {
 496     sconf.sokoban_level = 0;
 497     config_restore(&conf_info[0], "A/CHDK/MODULES/CFG/sokoban.cfg", 0);
 498     return 0;
 499 }
 500 
 501 //---------------------------------------------------------
 502 // PURPOSE: Finalize module operations (close allocs, etc)
 503 // RETURN VALUE: 0-ok, 1-fail
 504 //---------------------------------------------------------
 505 int _module_unloader()
 506 {
 507     config_save(&conf_info[0], "A/CHDK/MODULES/CFG/sokoban.cfg", 99000);
 508     return 0;
 509 }
 510 
 511 int _module_can_unload()
 512 {
 513     return running == 0;
 514 }
 515 
 516 int _module_exit_alt()
 517 {
 518     running = 0;
 519     return 0;
 520 }
 521 
 522 /******************** Module Information structure ******************/
 523 
 524 libsimple_sym _librun =
 525 {
 526     {
 527          0, _module_unloader, _module_can_unload, _module_exit_alt, _run
 528     }
 529 };
 530 
 531 ModuleInfo _module_info =
 532 {
 533     MODULEINFO_V1_MAGICNUM,
 534     sizeof(ModuleInfo),
 535     SIMPLE_MODULE_VERSION,              // Module version
 536 
 537     ANY_CHDK_BRANCH, 0, OPT_ARCHITECTURE,                       // Requirements of CHDK version
 538     ANY_PLATFORM_ALLOWED,               // Specify platform dependency
 539 
 540     -LANG_MENU_GAMES_SOKOBAN,   // Module name
 541     MTYPE_GAME,
 542 
 543     &_librun.base,
 544 
 545     ANY_VERSION,                // CONF version
 546     CAM_SCREEN_VERSION,         // CAM SCREEN version
 547     ANY_VERSION,                // CAM SENSOR version
 548     ANY_VERSION,                // CAM INFO version
 549 
 550     0,
 551 };
 552 
 553 /*************** END OF AUXILARY PART *******************/

/* [<][>][^][v][top][bottom][index][help] */