diff options
author | Thomas Martitz <kugel@rockbox.org> | 2009-08-02 16:41:30 +0000 |
---|---|---|
committer | Thomas Martitz <kugel@rockbox.org> | 2009-08-02 16:41:30 +0000 |
commit | 322fae42992040a30416ddd1587fd96dbca0a5e7 (patch) | |
tree | f9873dd12ea04ae1c7f210a86c182f27c4d0d0a1 /apps/plugins/bubbles.c | |
parent | 1060326f027292b0760666180019359fc6e0240f (diff) | |
download | rockbox-322fae42992040a30416ddd1587fd96dbca0a5e7.tar.gz rockbox-322fae42992040a30416ddd1587fd96dbca0a5e7.zip |
A bit of rework in bubbles:
*) Change saving mechanism: always save into RAM on any exit button, and offer an additional quit item in the game menu (so that 1 item doesn't save -> no disk spinup)
*) Change loading mechanism: always load on entering the game, but delete the save file still on actually resuming (that fixes weirdnesses with the level choosing menu item)
*) Remove the highscores from the bubbles struct.
*) Swap the "Start New Game" and "Resume Game" menu items to help against accidental deletion of progress.
git-svn-id: svn://svn.rockbox.org/rockbox/trunk@22116 a1c6a512-1295-4272-9138-f99709370657
Diffstat (limited to 'apps/plugins/bubbles.c')
-rw-r--r-- | apps/plugins/bubbles.c | 189 |
1 files changed, 102 insertions, 87 deletions
diff --git a/apps/plugins/bubbles.c b/apps/plugins/bubbles.c index 4ed15bd124..1f1e3ac905 100644 --- a/apps/plugins/bubbles.c +++ b/apps/plugins/bubbles.c | |||
@@ -38,12 +38,15 @@ PLUGIN_HEADER | |||
38 | #define SAVE_FILE PLUGIN_GAMES_DIR "/bubbles.save" | 38 | #define SAVE_FILE PLUGIN_GAMES_DIR "/bubbles.save" |
39 | 39 | ||
40 | /* final game return status */ | 40 | /* final game return status */ |
41 | #define BB_NONE 5 | 41 | enum { |
42 | #define BB_WIN 4 | 42 | BB_LOSE, |
43 | #define BB_END 3 | 43 | BB_QUIT, |
44 | #define BB_USB 2 | 44 | BB_QUIT_AND_SAVE, |
45 | #define BB_QUIT 1 | 45 | BB_USB, |
46 | #define BB_LOSE 0 | 46 | BB_END, |
47 | BB_WIN, | ||
48 | BB_NONE, | ||
49 | }; | ||
47 | 50 | ||
48 | /* play board dimension */ | 51 | /* play board dimension */ |
49 | #define BB_HEIGHT 12 | 52 | #define BB_HEIGHT 12 |
@@ -1223,7 +1226,6 @@ struct tile { | |||
1223 | * score is the current score | 1226 | * score is the current score |
1224 | * level is the current level | 1227 | * level is the current level |
1225 | * highlevel is the highest level beaten | 1228 | * highlevel is the highest level beaten |
1226 | * highscores is the list of high scores | ||
1227 | * angle is the current cannon direction | 1229 | * angle is the current cannon direction |
1228 | * shots is the number of shots fired since last compression | 1230 | * shots is the number of shots fired since last compression |
1229 | * compress is the height of the compressor | 1231 | * compress is the height of the compressor |
@@ -1240,8 +1242,7 @@ struct tile { | |||
1240 | struct game_context { | 1242 | struct game_context { |
1241 | unsigned int score; | 1243 | unsigned int score; |
1242 | unsigned int level; | 1244 | unsigned int level; |
1243 | struct highscore highlevel; | 1245 | unsigned int highlevel; |
1244 | struct highscore highscores[NUM_SCORES]; | ||
1245 | int angle; | 1246 | int angle; |
1246 | int shots; | 1247 | int shots; |
1247 | int compress; | 1248 | int compress; |
@@ -1252,10 +1253,14 @@ struct game_context { | |||
1252 | long elapsedlvl; | 1253 | long elapsedlvl; |
1253 | long elapsedshot; | 1254 | long elapsedshot; |
1254 | long startedshot; | 1255 | long startedshot; |
1255 | bool resume; | ||
1256 | struct tile playboard[BB_HEIGHT][BB_WIDTH]; | 1256 | struct tile playboard[BB_HEIGHT][BB_WIDTH]; |
1257 | }; | 1257 | }; |
1258 | 1258 | ||
1259 | struct highscore highscores[NUM_SCORES]; | ||
1260 | |||
1261 | /* used to denote available resume info */ | ||
1262 | static bool resume = false; | ||
1263 | |||
1259 | static void bubbles_init(struct game_context* bb); | 1264 | static void bubbles_init(struct game_context* bb); |
1260 | static bool bubbles_nextlevel(struct game_context* bb); | 1265 | static bool bubbles_nextlevel(struct game_context* bb); |
1261 | static void bubbles_getonboard(struct game_context* bb); | 1266 | static void bubbles_getonboard(struct game_context* bb); |
@@ -1288,8 +1293,9 @@ static void bubbles_init(struct game_context* bb) { | |||
1288 | rb->srand(*rb->current_tick); | 1293 | rb->srand(*rb->current_tick); |
1289 | 1294 | ||
1290 | /* check for resumed game */ | 1295 | /* check for resumed game */ |
1291 | if(bb->resume) { | 1296 | if (resume) |
1292 | bb->resume = false; | 1297 | { |
1298 | resume = false; | ||
1293 | return; | 1299 | return; |
1294 | } | 1300 | } |
1295 | 1301 | ||
@@ -1304,11 +1310,16 @@ static void bubbles_init(struct game_context* bb) { | |||
1304 | static bool bubbles_nextlevel(struct game_context* bb) { | 1310 | static bool bubbles_nextlevel(struct game_context* bb) { |
1305 | int i, j, pos; | 1311 | int i, j, pos; |
1306 | 1312 | ||
1313 | /* save highest level */ | ||
1314 | if (bb->level > bb->highlevel) | ||
1315 | bb->highlevel = bb->level; | ||
1316 | |||
1307 | bb->level++; | 1317 | bb->level++; |
1308 | 1318 | ||
1309 | /* check if there are no more levels */ | 1319 | /* check if there are no more levels */ |
1310 | if(bb->level > NUM_LEVELS) return false; | 1320 | if(bb->level > NUM_LEVELS) return false; |
1311 | 1321 | ||
1322 | |||
1312 | /* set up the play board */ | 1323 | /* set up the play board */ |
1313 | rb->memset(bb->playboard, 0, sizeof(bb->playboard)); | 1324 | rb->memset(bb->playboard, 0, sizeof(bb->playboard)); |
1314 | for(i=0; i<BB_LEVEL_HEIGHT; i++) { | 1325 | for(i=0; i<BB_LEVEL_HEIGHT; i++) { |
@@ -2112,11 +2123,11 @@ static void bubbles_recordscore(struct game_context* bb) { | |||
2112 | int position; | 2123 | int position; |
2113 | 2124 | ||
2114 | position = highscore_update(bb->score, bb->level, "", | 2125 | position = highscore_update(bb->score, bb->level, "", |
2115 | bb->highscores, NUM_SCORES); | 2126 | highscores, NUM_SCORES); |
2116 | if (position==0) | 2127 | if (position==0) |
2117 | rb->splash(HZ*2, "New High Score"); | 2128 | rb->splash(HZ*2, "New High Score"); |
2118 | if (position != -1) | 2129 | if (position != -1) |
2119 | highscore_show(position, bb->highscores, NUM_SCORES); | 2130 | highscore_show(position, highscores, NUM_SCORES); |
2120 | } | 2131 | } |
2121 | 2132 | ||
2122 | /***************************************************************************** | 2133 | /***************************************************************************** |
@@ -2124,11 +2135,21 @@ static void bubbles_recordscore(struct game_context* bb) { | |||
2124 | ******************************************************************************/ | 2135 | ******************************************************************************/ |
2125 | static void bubbles_loadscores(struct game_context* bb) { | 2136 | static void bubbles_loadscores(struct game_context* bb) { |
2126 | 2137 | ||
2138 | int i; | ||
2139 | int highlevel = 0; | ||
2127 | /* highlevel and highscores */ | 2140 | /* highlevel and highscores */ |
2128 | highscore_load(SCORE_FILE, &bb->highlevel, NUM_SCORES+1); | 2141 | highscore_load(SCORE_FILE, highscores, NUM_SCORES); |
2142 | |||
2143 | for (i = 0; i < NUM_SCORES; i++) | ||
2144 | { | ||
2145 | if (highscores[i].level >= highlevel) | ||
2146 | { | ||
2147 | highlevel = highscores[i].level+1; | ||
2148 | } | ||
2149 | } | ||
2129 | 2150 | ||
2130 | if( bb->highlevel.level >= NUM_LEVELS ) | 2151 | if (bb->highlevel < (unsigned)highlevel) |
2131 | bb->highlevel.level = NUM_LEVELS - 1; | 2152 | bb->highlevel = highlevel; |
2132 | } | 2153 | } |
2133 | 2154 | ||
2134 | /***************************************************************************** | 2155 | /***************************************************************************** |
@@ -2136,8 +2157,9 @@ static void bubbles_loadscores(struct game_context* bb) { | |||
2136 | ******************************************************************************/ | 2157 | ******************************************************************************/ |
2137 | static void bubbles_savescores(struct game_context* bb) { | 2158 | static void bubbles_savescores(struct game_context* bb) { |
2138 | 2159 | ||
2139 | /* highlevel and highscores */ | 2160 | /* highscores */ |
2140 | highscore_save(SCORE_FILE, &bb->highlevel, NUM_SCORES+1); | 2161 | (void)bb; |
2162 | highscore_save(SCORE_FILE, highscores, NUM_SCORES+1); | ||
2141 | } | 2163 | } |
2142 | 2164 | ||
2143 | /***************************************************************************** | 2165 | /***************************************************************************** |
@@ -2145,35 +2167,22 @@ static void bubbles_savescores(struct game_context* bb) { | |||
2145 | ******************************************************************************/ | 2167 | ******************************************************************************/ |
2146 | static bool bubbles_loadgame(struct game_context* bb) { | 2168 | static bool bubbles_loadgame(struct game_context* bb) { |
2147 | int fd; | 2169 | int fd; |
2148 | bool loaded = false; | ||
2149 | 2170 | ||
2171 | bool ret = true; | ||
2150 | /* open game file */ | 2172 | /* open game file */ |
2151 | fd = rb->open(SAVE_FILE, O_RDONLY); | 2173 | fd = rb->open(SAVE_FILE, O_RDONLY); |
2152 | if(fd < 0) return loaded; | 2174 | if(fd < 0) return false; |
2153 | 2175 | ||
2154 | /* read in saved game */ | 2176 | /* read in saved game */ |
2155 | while(true) { | 2177 | if(rb->read(fd, bb, sizeof(struct game_context)) |
2156 | if(rb->read(fd, &bb->score, sizeof(bb->score)) <= 0) break; | 2178 | < (long)sizeof(struct game_context)) |
2157 | if(rb->read(fd, &bb->level, sizeof(bb->level)) <= 0) break; | 2179 | { |
2158 | if(rb->read(fd, &bb->angle, sizeof(bb->angle)) <= 0) break; | 2180 | ret = false; |
2159 | if(rb->read(fd, &bb->shots, sizeof(bb->shots)) <= 0) break; | ||
2160 | if(rb->read(fd, &bb->compress, sizeof(bb->compress)) <= 0) break; | ||
2161 | if(rb->read(fd, &bb->onboardcnt, sizeof(bb->onboardcnt)) <= 0) break; | ||
2162 | if(rb->read(fd, bb->onboard, sizeof(bb->onboard)) <= 0) break; | ||
2163 | if(rb->read(fd, &bb->nextinq, sizeof(bb->nextinq)) <= 0) break; | ||
2164 | if(rb->read(fd, bb->queue, sizeof(bb->queue)) <= 0) break; | ||
2165 | if(rb->read(fd, &bb->elapsedlvl, sizeof(bb->elapsedlvl)) <= 0) break; | ||
2166 | if(rb->read(fd, bb->playboard, sizeof(bb->playboard)) <= 0) break; | ||
2167 | bb->resume = true; | ||
2168 | loaded = true; | ||
2169 | break; | ||
2170 | } | 2181 | } |
2171 | 2182 | ||
2183 | DEBUGF("highlevel: %d\n", bb->highlevel); | ||
2172 | rb->close(fd); | 2184 | rb->close(fd); |
2173 | 2185 | return ret; | |
2174 | /* delete saved file */ | ||
2175 | rb->remove(SAVE_FILE); | ||
2176 | return loaded; | ||
2177 | } | 2186 | } |
2178 | 2187 | ||
2179 | /***************************************************************************** | 2188 | /***************************************************************************** |
@@ -2182,22 +2191,22 @@ static bool bubbles_loadgame(struct game_context* bb) { | |||
2182 | static void bubbles_savegame(struct game_context* bb) { | 2191 | static void bubbles_savegame(struct game_context* bb) { |
2183 | int fd; | 2192 | int fd; |
2184 | 2193 | ||
2194 | if (!resume) /* nothing to save */ | ||
2195 | return; | ||
2185 | /* write out the game state to the save file */ | 2196 | /* write out the game state to the save file */ |
2186 | fd = rb->open(SAVE_FILE, O_WRONLY|O_CREAT); | 2197 | fd = rb->open(SAVE_FILE, O_WRONLY|O_CREAT); |
2187 | rb->write(fd, &bb->score, sizeof(bb->score)); | 2198 | if (fd < 0) |
2188 | rb->write(fd, &bb->level, sizeof(bb->level)); | 2199 | { |
2189 | rb->write(fd, &bb->angle, sizeof(bb->angle)); | 2200 | rb->splash(HZ/2, "Failed to save game"); |
2190 | rb->write(fd, &bb->shots, sizeof(bb->shots)); | 2201 | return; |
2191 | rb->write(fd, &bb->compress, sizeof(bb->compress)); | 2202 | } |
2192 | rb->write(fd, &bb->onboardcnt, sizeof(bb->onboardcnt)); | 2203 | if (rb->write(fd, bb, sizeof(struct game_context)) <= 0) |
2193 | rb->write(fd, bb->onboard, sizeof(bb->onboard)); | 2204 | { |
2194 | rb->write(fd, &bb->nextinq, sizeof(bb->nextinq)); | 2205 | rb->splash(HZ/2, "Failed to save game"); |
2195 | rb->write(fd, bb->queue, sizeof(bb->queue)); | 2206 | } |
2196 | rb->write(fd, &bb->elapsedlvl, sizeof(bb->elapsedlvl)); | 2207 | DEBUGF("highlevel: %d\n", bb->highlevel); |
2197 | rb->write(fd, bb->playboard, sizeof(bb->playboard)); | ||
2198 | rb->close(fd); | 2208 | rb->close(fd); |
2199 | 2209 | ||
2200 | bb->resume = true; | ||
2201 | } | 2210 | } |
2202 | 2211 | ||
2203 | /***************************************************************************** | 2212 | /***************************************************************************** |
@@ -2280,14 +2289,12 @@ static int bubbles_handlebuttons(struct game_context* bb, bool animblock, | |||
2280 | break; | 2289 | break; |
2281 | 2290 | ||
2282 | case BUBBLES_RESUME: /* save and end the game */ | 2291 | case BUBBLES_RESUME: /* save and end the game */ |
2292 | case BUBBLES_QUIT: /* end the game */ | ||
2283 | if(!animblock) { | 2293 | if(!animblock) { |
2284 | rb->splash(HZ/2, "Saving game..."); | 2294 | resume = true; |
2285 | bubbles_savegame(bb); | ||
2286 | return BB_END; | 2295 | return BB_END; |
2287 | } | 2296 | } |
2288 | break; | 2297 | break; |
2289 | case BUBBLES_QUIT: /* end the game */ | ||
2290 | return BB_END; | ||
2291 | 2298 | ||
2292 | case ACTION_UNKNOWN: | 2299 | case ACTION_UNKNOWN: |
2293 | case ACTION_NONE: /* no button pressed */ | 2300 | case ACTION_NONE: /* no button pressed */ |
@@ -2312,44 +2319,51 @@ static int bubbles(struct game_context* bb) { | |||
2312 | bool startgame = false; | 2319 | bool startgame = false; |
2313 | long timeout; | 2320 | long timeout; |
2314 | 2321 | ||
2315 | /* don't resume by default */ | ||
2316 | bb->resume = false; | ||
2317 | |||
2318 | /******************** | 2322 | /******************** |
2319 | * menu * | 2323 | * menu * |
2320 | ********************/ | 2324 | ********************/ |
2321 | MENUITEM_STRINGLIST(menu,"Bubbles Menu",NULL, | 2325 | MENUITEM_STRINGLIST(menu,"Bubbles Menu",NULL, |
2322 | "Start New Game", "Resume Game", | 2326 | "Resume Game", "Start New Game", |
2323 | "Level", "High Scores", "Playback Control", | 2327 | "Level", "High Scores", "Playback Control", |
2324 | "Quit"); | 2328 | "Quit", "Quit and Save"); |
2325 | while(!startgame){ | 2329 | while(!startgame){ |
2326 | switch (rb->do_menu(&menu, NULL, NULL, false)) | 2330 | switch (rb->do_menu(&menu, NULL, NULL, false)) |
2327 | { | 2331 | { |
2328 | case 0: /* new game */ | 2332 | case 0: /* resume game */ |
2329 | bb->level = startlevel; | 2333 | if (!resume) |
2330 | startgame = true; | 2334 | { |
2331 | break; | 2335 | rb->splash(HZ/2, "Nothing to resume"); |
2332 | case 1: /* resume game */ | 2336 | break; |
2333 | if(!bubbles_loadgame(bb)) { | 2337 | } |
2334 | rb->splash(HZ*2, "Nothing to resume"); | 2338 | else |
2335 | } else { | 2339 | { |
2340 | startlevel = bb->level - 1; | ||
2336 | startgame = true; | 2341 | startgame = true; |
2337 | } | 2342 | } |
2343 | /* delete saved file */ | ||
2344 | rb->remove(SAVE_FILE); | ||
2345 | break; | ||
2346 | case 1: /* new game */ | ||
2347 | bb->level = startlevel; | ||
2348 | startgame = true; | ||
2349 | resume = false; | ||
2338 | break; | 2350 | break; |
2339 | case 2: /* choose level */ | 2351 | case 2: /* choose level */ |
2340 | startlevel++; | 2352 | startlevel++; |
2341 | rb->set_int("Choose start level", "", UNIT_INT, &startlevel, | 2353 | rb->set_int("Choose start level", "", UNIT_INT, &startlevel, |
2342 | NULL, 1, 1, bb->highlevel.level+1, NULL); | 2354 | NULL, 1, 1, bb->highlevel+1, NULL); |
2343 | startlevel--; | 2355 | startlevel--; |
2344 | break; | 2356 | break; |
2345 | case 3: /* High scores */ | 2357 | case 3: /* High scores */ |
2346 | highscore_show(NUM_SCORES, bb->highscores, NUM_SCORES); | 2358 | highscore_show(NUM_SCORES, highscores, NUM_SCORES); |
2347 | break; | 2359 | break; |
2348 | case 4: /* Playback Control */ | 2360 | case 4: /* Playback Control */ |
2349 | playback_control(NULL); | 2361 | playback_control(NULL); |
2350 | break; | 2362 | break; |
2351 | case 5: /* quit */ | 2363 | case 5: /* quit */ |
2352 | return BB_QUIT; | 2364 | return BB_QUIT; |
2365 | case 6: /* quit and save */ | ||
2366 | return BB_QUIT_AND_SAVE; | ||
2353 | case MENU_ATTACHED_USB: | 2367 | case MENU_ATTACHED_USB: |
2354 | bubbles_callback(bb); | 2368 | bubbles_callback(bb); |
2355 | return BB_USB; | 2369 | return BB_USB; |
@@ -2404,14 +2418,16 @@ static int bubbles(struct game_context* bb) { | |||
2404 | * plugin entry point. | 2418 | * plugin entry point. |
2405 | ******************************************************************************/ | 2419 | ******************************************************************************/ |
2406 | enum plugin_status plugin_start(const void* parameter) { | 2420 | enum plugin_status plugin_start(const void* parameter) { |
2407 | struct game_context bb; | 2421 | static struct game_context bb; |
2408 | bool exit = false; | 2422 | bool exit = false; |
2423 | enum plugin_status ret = PLUGIN_OK; | ||
2409 | 2424 | ||
2410 | /* plugin init */ | 2425 | /* plugin init */ |
2411 | (void)parameter; | 2426 | (void)parameter; |
2412 | /* end of plugin init */ | 2427 | /* end of plugin init */ |
2413 | 2428 | ||
2414 | /* load files */ | 2429 | /* load files */ |
2430 | resume = bubbles_loadgame(&bb); | ||
2415 | bubbles_loadscores(&bb); | 2431 | bubbles_loadscores(&bb); |
2416 | rb->lcd_clear_display(); | 2432 | rb->lcd_clear_display(); |
2417 | 2433 | ||
@@ -2426,35 +2442,34 @@ enum plugin_status plugin_start(const void* parameter) { | |||
2426 | case BB_WIN: | 2442 | case BB_WIN: |
2427 | rb->splash(HZ*2, "You Win!"); | 2443 | rb->splash(HZ*2, "You Win!"); |
2428 | /* record high level */ | 2444 | /* record high level */ |
2429 | if( NUM_LEVELS-1 > bb.highlevel.level) { | 2445 | if( NUM_LEVELS-1 > bb.highlevel) { |
2430 | bb.highlevel.level = NUM_LEVELS-1; | 2446 | bb.highlevel = NUM_LEVELS-1; |
2431 | } | 2447 | } |
2432 | /* record high score */ | 2448 | /* record high score */ |
2433 | bubbles_recordscore(&bb); | 2449 | bubbles_recordscore(&bb); |
2434 | break; | 2450 | break; |
2435 | 2451 | ||
2436 | case BB_LOSE: | 2452 | case BB_LOSE: |
2453 | resume = false; | ||
2437 | rb->splash(HZ*2, "Game Over"); | 2454 | rb->splash(HZ*2, "Game Over"); |
2455 | /* record high score */ | ||
2456 | bubbles_recordscore(&bb); | ||
2438 | /* fall through to BB_END */ | 2457 | /* fall through to BB_END */ |
2439 | 2458 | ||
2440 | case BB_END: | 2459 | case BB_END: |
2441 | if(!bb.resume) { | ||
2442 | /* record high level */ | ||
2443 | if((int)bb.level-1 > bb.highlevel.level) { | ||
2444 | bb.highlevel.score = -1; | ||
2445 | highscore_update(0, bb.level-1, "", &bb.highlevel, 1); | ||
2446 | } | ||
2447 | /* record high score */ | ||
2448 | bubbles_recordscore(&bb); | ||
2449 | } | ||
2450 | break; | 2460 | break; |
2451 | 2461 | ||
2452 | case BB_USB: | 2462 | case BB_USB: |
2453 | rb->lcd_setfont(FONT_UI); | 2463 | ret = PLUGIN_USB_CONNECTED; |
2454 | return PLUGIN_USB_CONNECTED; | 2464 | break; |
2455 | 2465 | ||
2456 | case BB_QUIT: | 2466 | case BB_QUIT_AND_SAVE: |
2467 | rb->splash(HZ/2, "Saving Game and Scors"); | ||
2457 | bubbles_savescores(&bb); | 2468 | bubbles_savescores(&bb); |
2469 | bubbles_savegame(&bb); | ||
2470 | /* fall through */ | ||
2471 | |||
2472 | case BB_QUIT: | ||
2458 | exit = true; | 2473 | exit = true; |
2459 | break; | 2474 | break; |
2460 | 2475 | ||
@@ -2464,7 +2479,7 @@ enum plugin_status plugin_start(const void* parameter) { | |||
2464 | } | 2479 | } |
2465 | 2480 | ||
2466 | rb->lcd_setfont(FONT_UI); | 2481 | rb->lcd_setfont(FONT_UI); |
2467 | return PLUGIN_OK; | 2482 | return ret; |
2468 | } | 2483 | } |
2469 | 2484 | ||
2470 | #endif | 2485 | #endif |