1 // -----------------------------------------------
4 // Copyright (c) 2003,2004,2005, Kronoman
5 // In loving memory of my father
6 // -----------------------------------------------
8 // -----------------------------------------------
9 // Game main loop and kernel
10 // -----------------------------------------------
12 #include "gkernel.h" // kernel header
14 #include "gerror.h" // to show any error that may arise
15 #include "misc_def.h" // some definitions
17 #include "savescrs.h" // for screenshoots
20 // -----------------------------------------------
22 // -----------------------------------------------
23 // Counter for the main timer
24 static volatile int speed_counter
= 0;
26 // this 2 counters are for count the fps
27 static volatile int frame_count
, fps
;
29 // ---- End of global variables declaration ----
31 // -----------------------------------------------
33 // -----------------------------------------------
34 // Timer callback for the speed counter
35 void increment_speed_counter()
40 END_OF_FUNCTION(increment_speed_counter
);
42 // Timer callback for measuring the frames per second
49 END_OF_FUNCTION(fps_proc
);
51 // ==========================================================================
52 // KERNEL CLASS ITSELF BELOW THIS
53 // ==========================================================================
55 int CGameKernel::timer_installed_count
= 0; // how many times we installed the timer; when this is 0, remove/install timers
57 // -------------------------------------
59 // -------------------------------------
60 CGameKernel::CGameKernel()
62 mtracer
.add("CGameKernel::CGameKernel()");
66 dbuffer
= NULL
; // doble buffer
68 backdropbmp
= NULL
; // background bitmap for current level
70 current_level_file_name
[0] = '\0';
72 stats
.reset(); // reset stats
75 // -------------------------------------
77 // -------------------------------------
78 CGameKernel::~CGameKernel()
80 mtracer
.add("CGameKernel::~CGameKernel()");
85 // -------------------------------------------------------------------
86 // Initializes game (sets timers, loads data, etc)
87 // -------------------------------------------------------------------
88 void CGameKernel::init()
90 mtracer
.add("CGameKernel::init()");
93 dbuffer
= create_bitmap(SCREEN_W
, SCREEN_H
); // create doble buffer bitmap
96 raise_error("CGameKernel::init()\nERROR: unable to create doble buffer bitmap!\n");
100 textout_centre_ex(screen
, font
, "[ Please wait... loading... ]", SCREEN_W
/ 2, SCREEN_H
/ 2, makecol(255, 255, 255), makecol(0, 0, 64));
102 // Load general data for the game
103 char tmp_file_buf
[2048];
105 if (game_map
.load_tile_set_from_file(where_is_the_filename(tmp_file_buf
, TILESET_FILE
)) )
106 raise_error("CGameKernel::init()\nERROR!\nCan't load \"%s\" file!\n", TILESET_FILE
); // load tileset
108 if (main_data_file
.load_datafile(where_is_the_filename(tmp_file_buf
, SPRITES_FILE
)) )
109 raise_error("CGameKernel::init()\nERROR!\nUnable to load \"%s\" file!\n", SPRITES_FILE
);
111 mtracer
.add("\tGeneral data loaded OK");
113 // find the ball's sprite texture and mask
114 player_ball
.spr
= (BITMAP
*)main_data_file
.get_resource_dat("BALL");
116 if (player_ball
.spr
== NULL
)
117 raise_error("CGameKernel::init()\nERROR! Can't find BALL sprite!\n");
119 player_ball
.spr_shadow
= (BITMAP
*)main_data_file
.get_resource_dat("BALL_MASK_SHADOW");
121 if (player_ball
.spr_shadow
== NULL
)
122 raise_error("CGameKernel::init()\nERROR! Can't find BALL_MASK_SHADOW sprite!\n");
124 mtracer
.add("\tBall data loaded OK");
127 game_time_font
= (FONT
*)main_data_file
.get_resource_dat("GAME_TIME_FONT");
129 game_score_font
= (FONT
*)main_data_file
.get_resource_dat("GAME_SCORE_FONT");
131 game_messages_font
= (FONT
*)main_data_file
.get_resource_dat("GAME_MESSAGES_FONT");
134 game_map
.timer_tick_rate
= GKERNEL_FPSQ
; // set timer ratio for map
137 if (timer_installed_count
== 0)
139 LOCK_VARIABLE(speed_counter
);
140 LOCK_FUNCTION((void *)increment_speed_counter
);
143 LOCK_VARIABLE(frame_count
);
144 LOCK_FUNCTION((void *)fps_proc
);
147 if (install_int_ex(increment_speed_counter
, BPS_TO_TIMER(GKERNEL_FPSQ
)))
148 raise_error("CGameKernel::init() : Can't install timer at %d bps\n", GKERNEL_FPSQ
);
150 if (install_int(fps_proc
, 1000))
151 raise_error("CGameKernel::init() : Can't install timer to measure fps.");
153 mtracer
.add("\tTimer installed for first time");
156 timer_installed_count
++; // just to make sure that nobody else will remove our precious timer until we are ready too
158 mtracer
.add("\ttimer_installed_count = %d", timer_installed_count
);
160 // here start all the variables and all stuff
162 frame_count
= fps
= 0;
164 current_level_file_name
[0] = '\0';
167 // -------------------------------------------------------------------
168 // shuts down game (unsets timers, unloads data, etc)
169 // -------------------------------------------------------------------
170 void CGameKernel::shutdown()
172 mtracer
.add("CGameKernel::shutdown()");
174 // remove timer(s), only if active
175 if (timer_installed_count
> 0)
177 timer_installed_count
--;
179 mtracer
.add("\ttimer_installed_count = %d", timer_installed_count
);
181 if (timer_installed_count
== 0)
183 remove_int(increment_speed_counter
);
184 remove_int(fps_proc
);
185 timer_installed_count
= 0;
187 mtracer
.add("\tTimer totally removed");
192 game_map
.free_memory();
194 main_data_file
.nuke_datafile();
196 particle_manager
.nuke_particle_list();
200 destroy_bitmap(dbuffer
);
204 if (backdropbmp
!= NULL
)
206 destroy_bitmap(backdropbmp
);
210 current_level_file_name
[0] = '\0';
212 music_loader
.free_memory();
214 background_loader
.free_memory();
217 // -------------------------------------------------------------------
218 // This is the main game loop
221 // YOU **MUST** CALL IN THIS ORDER:
223 // gkernel.load_level_file("level.map");
224 // gkernel.game_loop();
225 // gkernel.shutdown();
227 // Will return CBALL_IS_DEAD, or CBALL_EXIT_LEVEL (dead, or won level)
229 // **NOTE** THE SPECIAL RETURN VALUE 'GKERNEL_USER_FINISHED_GAME' MEANS THAT THE PLAYER
230 // DON'T WANT TO PLAY (HE HIT ESC, SO ABORT THE GAME)
231 // -------------------------------------------------------------------
232 int CGameKernel::game_loop()
235 mtracer
.add("CGameKernel::game_loop()");
238 game_over
= false; // we start just now :P
243 soundw
.music_start();
245 while (game_over
== false || ret
== 0) // don't go out if this particular game is not over, and if ret don't has a valid value (!= 0)
247 while (speed_counter
> 0)
249 ret
= this->update_logic(); // update game logic
255 ret
= GKERNEL_USER_FINISHED_GAME
;
256 } // with ESC you end the game
258 if (ret
== CBALL_IS_DEAD
|| ret
== CBALL_EXIT_LEVEL
)
259 game_over
= true; // end of this game session
262 this->update_screen(); // update screen
264 frame_count
++; // count fps
266 if (key
[KEY_F12
]) // with F12 you take a screenshoot
268 soundw
.music_pause();
271 textout_right_ex(screen
, font
, "(C) 2004, Kronoman", SCREEN_W
, SCREEN_H
- text_height(font
), makecol(64, 64, 64),-1);
273 save_screenshoot("kball", 0, "bmp"); // save
275 // add confirmation message
277 ui_misc_text_out_shadow(screen
, font
, "Screenshoot saved", SCREEN_W
/ 2, SCREEN_H
/ 2, makecol(0, 0, 0), makecol(255, 255, 255));
281 this->update_screen();
284 soundw
.music_resume();
287 if (key
[KEY_ESC
] || ret
== GKERNEL_USER_FINISHED_GAME
) // with ESC you end the program
289 soundw
.music_pause();
291 // add confirmation message
292 ui_misc_dark_bmp(screen
);
293 ui_misc_text_out_shadow(screen
, game_messages_font
, "END GAME? Y/N", SCREEN_W
/ 2, SCREEN_H
/ 2, makecol(0, 0, 0), makecol(0, 255, 255));
298 if ((readkey() >> 8) == KEY_Y
)
301 ret
= GKERNEL_USER_FINISHED_GAME
;
306 ret
= 0; // abort the exit -- DEBUG this, may be the misterious 0 value returned... :P
309 this->update_screen();
313 soundw
.music_resume();
317 } // end of main game loop
325 // -------------------------------------------------------------------
326 // this updates 1 logic update of game ; also has code to PAUSE the game (KEY P or PAUSE)
327 // will return CBALL_IS_DEAD, CBALL_IS_FINE, or CBALL_EXIT_LEVEL
328 // -------------------------------------------------------------------
329 int CGameKernel::update_logic()
331 int ret
= CBALL_IS_FINE
;
335 // para contar el tiempo
336 static int last_t_s
= 0;
337 if (++last_t_s
> GKERNEL_FPSQ
)
339 stats
.add_time(0,0,1);
343 stats
.score
= player_ball
.score
;
346 if (key
[KEY_PAUSE
] || key
[KEY_P
]) // - pause the game -
348 soundw
.music_pause();
350 ui_misc_dark_bmp(screen
);
352 ui_misc_text_out_shadow(screen
, game_messages_font
, "- PAUSE -", SCREEN_W
/ 2, SCREEN_H
/ 2, makecol(0, 0, 0), makecol(0, 255, 255));
354 ui_misc_wait_for_input();
356 this->update_screen();
359 soundw
.music_resume();
362 game_map
.update_logic();
363 particle_manager
.update_logic();
365 ret
= player_ball
.update_logic(); // return value
367 if (game_map
.time_m
*60 + game_map
.time_s
<= 10) // we are running low in time!, put a warning count
369 static int old_time
= 0;
371 if (old_time
!= game_map
.time_s
) // only each second
373 old_time
= game_map
.time_s
;
376 usprintf(tmp_str
, "%d", game_map
.time_s
);
378 particle_manager
.add_particle(new CExplosiveTextParticle(player_ball
.x
+ player_ball
.spr
->w
/ 2, player_ball
.y
, (float)(rand() % 100 - 50) / 100.0, (float)((rand() % 300) + 150) / -100.0, makecol(rand() % 55 + 200, 0, 0), rand() % 15 + 25, tmp_str
, game_time_font
));
382 if (game_map
.time_m
*60 + game_map
.time_s
<= 0) // time out, we are so DEAD!
387 if (ret
== CBALL_EXIT_LEVEL
) // end of level :^D
389 if (game_map
.prize_map_indispensable
> 0) // we can't exit if we have prizes left.
391 // the user can't exit now, so drop a visual text saying it
392 if (rand() % 100 < 40)
393 particle_manager
.add_particle(new CTextParticle(player_ball
.x
+ player_ball
.spr
->w
/ 2, player_ball
.y
+ player_ball
.spr
->h
/ 2, (float)(rand() % 300 - 150) / 100.0, (float)(rand() % 300) / -100.0, makecol(rand() % 55 + 200, 0, 255), rand() % 25 + 15, string("CAN'T EXIT"), font
));
395 ret
= CBALL_IS_FINE
; // abort level exit
405 // -------------------------------------------------------------------
406 // This updates the screen
407 // -------------------------------------------------------------------
408 void CGameKernel::update_screen()
410 int xc
, yc
; // x y of camera
411 static int blink_counter
= 0; // counter for blink text timer... :P
412 static bool show_fps
= false; // show fps ? F11 turns it
414 if (key
[KEY_F11
]) // show fps
415 show_fps
= !show_fps
;
419 if (blink_counter
> GKERNEL_FPSQ
)
423 xc
= (int)player_ball
.x
- SCREEN_W
/ 2;
425 yc
= (int)player_ball
.y
- SCREEN_H
/ 2;
433 if (xc
> TMAP_SIZE
*TMAPS_W
- SCREEN_W
)
434 xc
= TMAP_SIZE
* TMAPS_W
- SCREEN_W
;
436 if (yc
> TMAP_SIZE
*TMAPS_H
- SCREEN_H
)
437 yc
= TMAP_SIZE
* TMAPS_H
- SCREEN_H
;
440 blit(backdropbmp
, dbuffer
, 0, 0, 0, 0, backdropbmp
->w
, backdropbmp
->h
); // blit background
442 //text_mode( -1); // transparent background for text
447 textprintf_ex(dbuffer
, font
, 0, SCREEN_H
- text_height(font
), makecol(255, 255, 255), -1, "%4d fps", fps
);
448 textout_ex(dbuffer
, font
, "Copyright (c) 2003, 2004, 2005, Kronoman", 0, SCREEN_H
- text_height(font
)*3, makecol(128, 128, 255),-1);
451 // ---- 3D scene (this items are draw using the Allegro's 3D software polygon routines)
453 clear_scene(dbuffer
); // clear 3D scene zbuffer
455 player_ball
.draw(dbuffer
, xc
, yc
); // draw ball
457 game_map
.draw_map(dbuffer
, xc
, yc
, SCREEN_W
, SCREEN_H
, 0, false); // draw map
459 game_map
.draw_map(dbuffer
, xc
, yc
, SCREEN_W
, SCREEN_H
, 1, false); // draw top layer (the one with prizes =D)
461 render_scene(); // render the 3D scene to the bitmap
464 // ---- end of 3D scene
466 // draw particles, they are 2D
467 particle_manager
.render(dbuffer
, xc
, yc
);
470 textprintf_centre_ex(dbuffer
, game_time_font
, dbuffer
->w
/ 2 + 3, 3, (game_map
.time_m
*60 + game_map
.time_s
> 10) ? makecol(100, 0, 128) : makecol(128, 0, 0),-1,"%02d:%02d", game_map
.time_m
, game_map
.time_s
);
472 textprintf_centre_ex(dbuffer
, game_time_font
, dbuffer
->w
/ 2, 0, (game_map
.time_m
*60 + game_map
.time_s
> 10) ? makecol(200, 0, 255) : makecol(255, 0, 0),-1, "%02d:%02d", game_map
.time_m
, game_map
.time_s
);
475 textprintf_ex(dbuffer
, game_score_font
, 3, 3, makecol(128, 100, 0), -1,"%010ld", player_ball
.score
);
477 textprintf_ex(dbuffer
, game_score_font
, 0, 0, makecol(255, 200, 0), -1,"%010ld", player_ball
.score
);
479 // prizes left message
480 if (game_map
.prize_map_indispensable
> 0)
482 textprintf_right_ex(dbuffer
, game_score_font
, dbuffer
->w
+ 3, 3, makecol(0, 64, 128),-1, "%04d", game_map
.prize_map_indispensable
);
483 textprintf_right_ex(dbuffer
, game_score_font
, dbuffer
->w
, 0, makecol(0, 128, 255),-1, "%04d", game_map
.prize_map_indispensable
);
487 int cc1
, cc2
; // text color for blink text
488 // the EXIT blinks... :D
489 if (blink_counter
< GKERNEL_FPSQ
/ 2)
491 cc1
= makecol(0, 100, 128);
492 cc2
= makecol(0, 200, 255);
496 cc1
= makecol(128, 100, 0);
497 cc2
= makecol(255, 200, 0);
501 textprintf_right_ex(dbuffer
, game_score_font
, dbuffer
->w
+ 3, 3, cc1
,-1, "EXIT");
502 textprintf_right_ex(dbuffer
, game_score_font
, dbuffer
->w
, 0, cc2
,-1, "EXIT");
505 // lives left message
506 textprintf_ex(dbuffer
, game_score_font
, 0 + 3, (int)(text_height(game_score_font
)*1.05) + 3, makecol(128, 110, 0),-1, "Balls:%2d", player_ball
.lives
);
508 textprintf_ex(dbuffer
, game_score_font
, 0, (int)(text_height(game_score_font
)*1.05), makecol(255, 220, 0),-1, "Balls:%2d", player_ball
.lives
);
510 // debug, remove this!
511 //textprintf(dbuffer, font,0,0,makecol(255,255,0), "x%3f,y%3f", player_ball.anglex,player_ball.angley);
514 //stats.print(dbuffer, 50, makecol(255,255,255), -1, font); // DEBUG -- REMOVE THIS OR MAKE IT TOGGEABLE WITH A KEY
516 blit(dbuffer
, screen
, 0, 0, 0, 0, dbuffer
->w
, dbuffer
->h
); // dump the render to screen
518 // yield_timeslice(); // play nice with multitask
519 //rest(0); // the way of playing nice with multitask since Allegro 4.1.15 WIP
522 // -------------------------------------------------------------------
523 // Helper function, takes a bitmap, and returns a new allocated bitmap
524 // with the 1st bitmap tiled in the size of the screen
525 // this serves for the background imagen
526 // -------------------------------------------------------------------
527 BITMAP
*CGameKernel::tile_bmp_to_screen_size(BITMAP
*bmp
)
532 raise_error("CGameKernel::tile_bmp_to_screen_size()\nERROR: bitmap null; can't tile it!\n");
534 b
= create_bitmap(SCREEN_W
, SCREEN_H
);
537 raise_error("CGameKernel::tile_bmp_to_screen_size()\nERROR: unable to create bitmap!\n");
539 for (int y
= 0; y
< SCREEN_H
+ bmp
->h
; y
+= bmp
->h
)
540 for (int x
= 0; x
< SCREEN_W
+ bmp
->w
; x
+= bmp
->w
)
541 blit(bmp
, b
, 0, 0, x
, y
, bmp
->w
, bmp
->h
);
546 // -----------------------------------------------------------------------
547 // Loads a level from a file, and sets the game ready to play on that level
549 // *MUST* BE CALLED BEFORE STARTING THE GAME LOOP!
550 // WILL LOAD THE MAP, BACKGROUND, etc
551 // -----------------------------------------------------------------------
552 void CGameKernel::load_level_file(const char *file
)
554 mtracer
.add("CGameKernel::load_level_file(\"%s\")", file
);
556 if (game_map
.load_map_from_file(file
))
557 raise_error("CGameKernel::load_level_file()\nERROR!\nCan't load level '%s'!\n", file
);
559 usprintf(current_level_file_name
, "%s", file
); // save current file name
561 // set the player position and properties
562 player_ball
.x
= (game_map
.sxp
* TMAPS_W
) + (TMAPS_W
- BALL_RADIUS
* 2) / 2;
564 player_ball
.y
= (game_map
.syp
* TMAPS_H
) + (TMAPS_H
- BALL_RADIUS
* 2) / 2;
568 player_ball
.dx
= player_ball
.dy
= player_ball
.dz
= 0.0;
570 player_ball
.ctmap
= &game_map
;
572 player_ball
.particle_manager
= &particle_manager
;
574 particle_manager
.nuke_particle_list(); // CLEAN THE PARTICLES FOR THE NEW LEVEL :P
576 // DEBUG -- BACKGROUND! - DECIDIR QUE CORNO HAGO CON ESTO
577 // Load the background from info stored on the level map
578 if (backdropbmp
!= NULL
)
580 destroy_bitmap(backdropbmp
);
584 backdropbmp
= tile_bmp_to_screen_size( background_loader
.get_background("backgr.dat", game_map
.background_index
) );
586 mtracer
.add("\tLoaded background (%d) of level OK", game_map
.background_index
);
589 soundw
.music_load(music_loader
.get_music("music_l.dat", game_map
.music_index
));
590 mtracer
.add("\tLoaded music (%d) of level OK", game_map
.music_index
);
594 // -----------------------------------------------------------------------
595 // This will start a single level game
596 // Will return CBALL_IS_DEAD(totally DEAD, full game over, 0 lives)
597 // CBALL_EXIT_LEVEL (only useful for campaign), or GKERNEL_USER_FINISHED_GAME if player cancelled game
598 // -----------------------------------------------------------------------
599 int CGameKernel::play_a_single_level(char *level_filename
)
602 bool do_the_loop
= true; // loop, for loading level many times, etc
603 int old_score
= 0; // this is for restoring the score when the player loses a ball
605 mtracer
.add("\nCGameKernel::play_a_single_level('%s');\n", level_filename
);
607 this->init(); // init game kernel
609 old_score
= player_ball
.score
;
613 mtracer
.add("\tLoading and playing level.");
615 this->load_level_file(level_filename
);
617 ret
= this->game_loop();
619 mtracer
.add("\t--> this->game_loop = %4d\n", ret
);
621 // according to ret value, show the player, if we won, we lose, or if we have lives to keep playing, etc
622 // the { } in the case <x>: are there to force the scope, so don't remove them (I know what I'm doing...)
626 case CBALL_EXIT_LEVEL
:
628 // the player won the level, OK, so we exit
629 // this value will be used by campaign function, if available
631 this->update_screen();
633 ui_misc_dark_bmp(screen
);
634 ui_misc_text_out_shadow(screen
, game_messages_font
, "YOU WON THE LEVEL!", SCREEN_W
/ 2, SCREEN_H
/ 2, makecol(0, 0, 0), makecol(0, 255, 255));
638 //text_mode(makecol(0, 0, 64));
644 rectfill(screen
, 0, SCREEN_H
/ 2 + text_height(game_messages_font
), SCREEN_W
, SCREEN_H
, makecol(0, 0, 64));
647 textout_centre_ex(screen
, game_messages_font
, "TIME BONUS", SCREEN_W
/ 2, SCREEN_H
/ 2 + text_height(game_messages_font
), makecol(0, 255, 255),makecol(0,0,64));
649 for (int i
= 0; i
< game_map
.time_m
*60 + game_map
.time_s
; i
++)
651 textprintf_centre_ex(screen
, game_messages_font
, SCREEN_W
/ 2, SCREEN_H
/ 2 + text_height(game_messages_font
)*2, makecol(0, 255, 255),makecol(0,0,64), " %04d x 100 = %07d ", i
, bonus
);
652 bonus
+= 100; // 100 bonus points for each second
654 // DEBUG -- falta SONIDO!
656 if (keypressed() || mouse_b
|| joy
[0].button
[0].b
)
657 break; // let the user cancel the count
661 if (keyboard_needs_poll())
664 if (mouse_needs_poll())
671 bonus
= (game_map
.time_m
* 60 + game_map
.time_s
) * 100;
673 player_ball
.score
+= bonus
;
674 stats
.score
= player_ball
.score
;
676 textprintf_centre_ex(screen
, game_messages_font
, SCREEN_W
/ 2, SCREEN_H
/ 2 + text_height(game_messages_font
)*2, makecol(0, 255, 255), makecol(0,0,64)," %04d x 100 = %07d ", game_map
.time_m
*60 + game_map
.time_s
, bonus
);
678 textprintf_centre_ex(screen
, game_messages_font
, SCREEN_W
/ 2, SCREEN_H
/ 2 + text_height(game_messages_font
)*3, makecol(0, 255, 255), makecol(0,0,64),"Score = %010ld", player_ball
.score
);
682 textout_centre_ex(screen
, font
, "-- Hit any key to continue --", SCREEN_W
/ 2, SCREEN_H
- text_height(font
), makecol(255, 255, 255),-1);
684 ui_misc_wait_for_input();
689 break; // CBALL_EXIT_LEVEL
694 this->update_screen();
696 ui_misc_dark_bmp(screen
);
698 if (game_map
.time_m
*60 + game_map
.time_s
> 0)
699 ui_misc_text_out_shadow(screen
, game_messages_font
, "YOU LOST THE BALL!", SCREEN_W
/ 2, SCREEN_H
/ 2, makecol(0, 0, 0), makecol(0, 255, 255));
701 ui_misc_text_out_shadow(screen
, game_messages_font
, "TIME UP!", SCREEN_W
/ 2, SCREEN_H
/ 2, makecol(0, 0, 0), makecol(0, 255, 255));
703 textout_centre_ex(screen
, font
, "-- Hit any key to continue --", SCREEN_W
/ 2, SCREEN_H
- text_height(font
), makecol(255, 255, 255),-1);
705 ui_misc_wait_for_input();
707 // the player died, rest one live
709 stats
.blost
++; // statistics
710 stats
.score
= player_ball
.score
;
712 player_ball
.anglex
= player_ball
.angley
= 0.0; // reset ball rotations
714 if (player_ball
.lives
< 0) // the player is dead. 0 lives. GAME OVER. :(
717 BITMAP
*bmp_game_over
= (BITMAP
*)main_data_file
.get_resource_dat("GAME_OVER_BMP");
719 blit(bmp_game_over
, screen
, 0, 0, 0, 0, bmp_game_over
->w
, bmp_game_over
->h
);
721 stats
.score
= player_ball
.score
;
722 stats
.print(screen
, 150, makecol(255,255,0), -1, game_score_font
); // print stats
725 SAMPLE
*game_over_smp
= (SAMPLE
*)main_data_file
.get_resource_dat("GAME_OVER_WAV");
726 play_sample(game_over_smp
,255,128,1000,0);
728 textout_centre_ex(screen
, font
, "-- Hit any key to continue --", SCREEN_W
/ 2, SCREEN_H
- text_height(font
), makecol(128, 0, 0),-1);
730 ui_misc_wait_for_input();
734 stats
.reset(); // reset stats
738 // perdio una vida, pero le queda, jugar de nuevo el nivel
739 do_the_loop
= true; // load the next level, damn
740 player_ball
.score
= old_score
; // restore score
745 break; // end of CBALL_IS_DEAD
747 case GKERNEL_USER_FINISHED_GAME
:
748 do_the_loop
= false; // the player hit <ESC>, end of game :(
749 break; // GKERNEL_USER_FINISHED_GAME
751 default: // it should NEVER come here
752 raise_error("ERROR at CGameKernel::play_a_single_level\nGuru meditation:\ngame_loop returned a invalid value (ret = %d)\n", ret
);
758 this->shutdown(); // shutdown this beauty...
764 // -----------------------------------------------------------------------
765 // This will start a full campaign game
766 // -----------------------------------------------------------------------
767 void CGameKernel::play_a_full_campaign(char *level_filename
)
769 char tmp_str
[4096]; // buffer to handle level filenames
770 int current_level
= 1; // current level number
771 bool finished
= false;
774 mtracer
.add("\nCGameKernel::play_a_full_campaign('%s')\n", level_filename
);
778 // load and play level
779 usprintf(tmp_str
, "%s#%d_MAP", level_filename
, current_level
);
780 fix_filename_slashes(tmp_str
);
782 // check if the level exits before trying to play it -- DEBUG -- slow code here! do some better
783 PACKFILE
*fp_test
= pack_fopen(tmp_str
, F_READ
);
787 // EL NIVEL NO EXISTE, LISTO, GANO
789 // the player won the campaign
791 // NOTA: dado que cuando llega aca, ya hizo el this->shutdown, los .DAT estan DESCARGADOS
792 // por eso, recargo el bitmap y font en RAM y el sonido...
794 clear_bitmap(screen
);
795 textout_centre_ex(screen
, font
, "[ Please wait... loading... ]", SCREEN_W
/ 2, SCREEN_H
/ 2, makecol(255, 255, 255), makecol(0, 0, 64));
797 DATAFILE
*dattmp
= load_datafile_object(SPRITES_FILE
, "WON_BMP");
799 raise_error("CGameKernel::play_a_full_campaign\nCan't load %s -> WON_BMP\n", SPRITES_FILE
);
800 BITMAP
*bmp_won
= (BITMAP
*)dattmp
->dat
;
802 DATAFILE
*dattmp2
= load_datafile_object(SPRITES_FILE
, "GAME_SCORE_FONT");
804 raise_error("CGameKernel::play_a_full_campaign\nCan't load %s -> GAME_SCORE_FONT\n", SPRITES_FILE
);
805 FONT
*fs
= (FONT
*)dattmp2
->dat
;
808 blit(bmp_won
, screen
, 0, 0, 0, 0, bmp_won
->w
, bmp_won
->h
);
810 stats
.print(screen
, 150, makecol(0,0,255), -1, fs
);
813 DATAFILE
*dattmp3
= load_datafile_object(SPRITES_FILE
, "WON_WAV");
816 play_sample((SAMPLE
*)dattmp3
->dat
,255,128,1000,0);
819 textout_centre_ex(screen
, font
, "-- Hit any key to continue --", SCREEN_W
/ 2, SCREEN_H
- text_height(font
), makecol(255, 255, 0),-1);
821 ui_misc_wait_for_input();
823 unload_datafile_object(dattmp
); // bye bye bitmap... :)
824 unload_datafile_object(dattmp2
); // bye bye font... :)
826 unload_datafile_object(dattmp3
); // bye bye sample
832 return ; // chau... finalizo!
835 pack_fclose(fp_test
);
837 ret
= this->play_a_single_level(tmp_str
);
839 mtracer
.add("\t--> this->play_a_single_level('%s') = %4d\n", tmp_str
, ret
);
841 if (ret
== CBALL_EXIT_LEVEL
) // exit level!
848 finished
= true; // any other value means GAME OVER, sorry d00d, insert coin :P