Use an absolute directory under /usr/share/games/ for game data
[kraptor.git] / src / game.c
blob03ae5a346ccd80dce70bd38270fff7bebc0a30aa
1 /*
2 --------------------------------------------------------
3 game.c
4 --------------------------------------------------------
5 Loop principal del juego
6 --------------------------------------------------------
7 */
8 #ifndef GAME_C
9 #define GAME_C
11 #include <allegro.h>
12 #include <limits.h>
13 #include "shopping.h"
14 #include "sonido.h"
15 #include "guiprocs.h"
16 #include "guitrans.h"
17 #include "data.h"
18 #include "global.h"
19 #include "kfbuffer.h"
20 #include "error.h"
21 #include "jugador.h"
22 #include "enemigo.h"
23 #include "mapa.h"
24 #include "partic.h"
25 #include "explos.h"
26 #include "captura.h"
27 #include "cinema.h"
28 #include "menu.h"
29 #include "clima.h"
30 #include "humo.h"
31 #include "rvideo.h"
32 #include "bomba.h"
33 #include "premio.h"
35 /* Globales */
37 volatile int speed_counter = 0; /* contador de velocidad para frame skip */
38 volatile int frame_count, fps; /* para contar los fps en caso de debug... */
40 /* estos contadores son para medir los fps con mas precision, max, med y min */
41 volatile int fps_min, fps_max, fps_med;
43 static PALETTE pal_game_oscura; // paleta del juego 'oscura',
44 // sirve para cuando se ponen menus, etc
45 // de esa manera, hace un efecto 'oscuro'
48 // Funcion que llena la pal_game_oscura con la paleta actual oscurecida.
49 // Usara la paleta actual, asique setear primero la paleta adecuada
50 // Pasar en oscurecer la cantidad de oscurecimiento (0.01 a 1.00)
51 // NOTA: Ignora todos los colores que utiliza la GUI
52 // o sea, los colores definidos en guiprocs.c -> xset_gui_colors()
53 static void llenar_pal_game_oscura(float oscurecer)
55 int i;
56 float h,s,v;
57 int r,g,b;
58 int ignorar = FALSE;
59 get_palette(pal_game_oscura);
60 for (i = 0; i <256; i ++ )
62 ignorar = FALSE;
63 // observad que if mas horrible!!!
64 if (i == gui_text_color ||
65 i == gui_back_color ||
66 i == gui_white_color ||
67 i == gui_light_color ||
68 i == gui_dark_color ||
69 i == gui_black_color ||
70 i == gui_fg_color ||
71 i == gui_mg_color ||
72 i == gui_bg_color )
74 ignorar = TRUE; // ignorar el color porque es del GUI
78 if (!ignorar)
80 // tomar el color
81 r = (int)pal_game_oscura[i].r;
82 g = (int)pal_game_oscura[i].g;
83 b = (int)pal_game_oscura[i].b;
84 // multiplico por 4, porque el rango va de 0..63 en paleta y de 0..255 en la funcion de hsv
85 rgb_to_hsv(r*4, g*4, b*4, &h, &s, &v);
86 // oscurecer
87 v -= oscurecer;
88 if (v < 0.0) v = 0.0;
89 hsv_to_rgb(h, s, v, &r, &g, &b); // generar nuevo color
90 r /= 4; g /= 4; b /= 4;
91 pal_game_oscura[i].r = r;
92 pal_game_oscura[i].g = g;
93 pal_game_oscura[i].b = b;
99 /* Cuenta las fps y saca promedio de fps*/
100 void fps_proc()
102 fps = frame_count;
104 /* ir sacando promedio */
105 fps_med += fps;
106 fps_med = fps_med / 2;
108 frame_count = 0;
110 END_OF_FUNCTION(fps_proc);
112 /* Cuenta la velocidad del juego */
113 void increment_speed_counter()
115 speed_counter++;
117 END_OF_FUNCTION(increment_speed_counter);
120 /*--------------------------------------------------------
121 Actualiza la logica del juego
122 --------------------------------------------------------*/
123 void update_game_logic()
125 ejecutar_poll_musica(); /* continuar ejecutando la musica */
127 rvideo_record(kfbufferbmp, pal_game); // grabar 'video' a disco - DEBUG
129 scroll_mapa -= ABS(scroll_mapa_speed);
130 if (scroll_mapa < 0)
132 scroll_mapa = 0;
134 /* ver, si no quedan mas enemigos, PASO de nivel!!! */
135 if (enemigo_1 == NULL && jugador.vida > 0) /* la lista esta vacia, no hay enemigos */
137 /* adelantar al jugador, llevarlo al borde superior, y hay si, salir */
138 if (ABS((fixtoi(jugador.x)+(jugador.spr[1]->w/2)) - (ANCHO_FB/2)) > jugador.spr[1]->w*2) // evita un efecto raro al acercarse al centro
140 if ( ANCHO_FB/2 < fixtoi(jugador.x)+jugador.spr[1]->w/2 )
141 jugador.dx =fixsub(jugador.dx, ftofix(VEL_X_J*1.2));
143 if ( ANCHO_FB/2 > fixtoi(jugador.x)+jugador.spr[1]->w/2 )
144 jugador.dx =fixadd(jugador.dx, ftofix(VEL_X_J*1.2));
146 else
147 { jugador.dx = 0; } // avanzar recto...
149 if (fixtoi(jugador.y) > 5) // ir hacia la parte superior del nivel (la salida)
151 jugador.y = fixsub(jugador.y, ftofix(MAX_VEL_J_X));
152 jugador.dy = fixsub(jugador.dy, ftofix(VEL_Y_J*1.5));
154 else
156 paso_de_nivel = TRUE;
161 /* el jugador se tiene que mover con el mapa */
162 if (scroll_mapa > 0) jugador.y = fixsub(jugador.y, itofix(1));
164 // obtener teclado si es necesario (algunas plataformas...)
165 if (keyboard_needs_poll()) poll_keyboard();
167 interpreta_teclado(); // teclado del jugador
168 mover_jugador(scroll_mapa);
169 mover_bomba(); /* bomba especial del jugador */
170 mover_enemigos(scroll_mapa);
171 mover_disparos_jug(scroll_mapa);
172 mover_disparos_ene(scroll_mapa);
174 if (nivel_detalle > 0) mover_particulas(0, scroll_mapa, ANCHO_FB, ALTO_FB);
176 mover_explosiones(&ptr_explo_fondo);
177 mover_explosiones(&ptr_explo_arriba);
178 mover_emisor_humo(0, scroll_mapa, ANCHO_FB, ALTO_FB); // emisores de humo! wow!
179 mover_humo(0, scroll_mapa, ANCHO_FB, ALTO_FB);
181 mover_premio(0, scroll_mapa, ANCHO_FB, ALTO_FB); // premios...
183 if (nivel_detalle > 1) mover_clima(kfbufferbmp); // mover clima
185 /* ver si aparecen nuevos enemigos */
186 scan_nuevos_enemigos(scroll_mapa / H_GR);
188 /* TECLADO ADICIONAL - FUNCIONES PROPIAS DEL JUEGO */
190 /* TECLA PAUSE o P, sirve para poner la PAUSA! */
191 if (key[KEY_PAUSE] || key[KEY_P])
193 pausar_musica();
195 key[KEY_PAUSE] = FALSE;
196 key[KEY_P] = FALSE;
197 clear_keybuf();
198 set_palette(pal_game_oscura);
199 // Mensaje GUI
200 alert(get_config_text("Pause"), NULL, NULL, get_config_text("Continue"), NULL, 0, 0);
201 clear_keybuf();
202 key[KEY_PAUSE] = FALSE;
203 key[KEY_P] = FALSE;
204 frame_count = fps = speed_counter = 0; /* evita salto en los fps */
206 continuar_musica();
207 set_palette(pal_game);
208 } // fin pausa
211 /* ESC: menu con varias opciones */
212 if (key[KEY_ESC])
214 DIALOG esc_key_dlg[] =
216 /* (proc) (x) (y) (w) (h) (fg) (bg) (key) (flags) (d1) (d2) (dp) (dp2) (dp3) */
217 { xbox_proc, 0, 0, 200, 128, 0, 0, 0, 0, 0, 0, NULL, NULL, NULL },
218 { xbutton_proc, 8, 8, 184, 32, 0, 0, 0, D_EXIT, 0, 0, "Configuration", NULL, NULL },
219 { xbutton_proc, 8, 48, 184, 32, 0, 0, 0, D_EXIT, 0, 0, "Abort Game", NULL, NULL },
220 { xbutton_proc, 8, 88, 184, 32, 0, 0, 0, D_EXIT, 0, 0, "Resume game", NULL, NULL },
221 { NULL, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, NULL, NULL, NULL }
223 pausar_musica();
225 traducir_DIALOG_dp(esc_key_dlg);
226 centre_dialog(esc_key_dlg);
227 set_dialog_color(esc_key_dlg, makecol(0,0,0), makecol(255,255,255));
228 key[KEY_ESC] = FALSE;
230 clear_keybuf();
231 set_palette(pal_game_oscura);
233 /* mostrar dialogo */
234 switch (popup_dialog(esc_key_dlg, 0))
236 case 1: // configurar - DEBUG, truchisimo lo del F5
237 key[KEY_F5] = TRUE;
238 break;
240 case 2: // abortar juego
241 if (alert(get_config_text("Exit game"),
242 NULL,
243 NULL,
244 get_config_text("Yes"),
245 get_config_text("No"),
246 0, 0) == 1)
248 salir_del_juego = TRUE;
250 break;
252 default:
253 break;
257 frame_count = fps = speed_counter = 0; /* evita salto en los fps */
258 continuar_musica();
259 set_palette(pal_game);
262 /* F5: menu de configuracion general, sonido, detalles, controles, etc */
263 if (key[KEY_F5])
265 int tmp1 = quiere_musica;
267 pausar_musica();
268 set_palette(pal_game_oscura);
269 key[KEY_F5] = FALSE;
270 clear_keybuf();
271 menu_configuracion_al_vuelo();
272 frame_count = fps = speed_counter = 0; /* evita salto en los fps */
274 reajustar_volumen_musica();
275 continuar_musica();
276 set_palette(pal_game);
278 /* DEBUG: esto es para que si activa/desactiva la musica, tome efecto */
279 if (tmp1 != quiere_musica)
281 musica_stop();
282 musica_play(info_nivel.musica);
287 /* F1: ayuda del programa */
288 if (key[KEY_F1])
290 pausar_musica();
291 set_palette(pal_game_oscura);
292 key[KEY_F1] = FALSE;
293 clear_keybuf();
294 ayuda_proggy_mnu();
295 frame_count = fps = speed_counter = 0; /* evita salto en los fps */
297 continuar_musica();
298 set_palette(pal_game);
301 /* F11 prende y apaga el modo DEBUG (muestra info extra) */
302 if (key[KEY_F11]) /* DEBUG, al distribuir, eliminar esto!!! */
304 key[KEY_F11] = FALSE;
305 KRONO_QUIERE_DEBUG = !KRONO_QUIERE_DEBUG;
308 /* F12 sirve para capturar pantallas */
309 if (key[KEY_F12])
311 // pausar_musica();
313 key[KEY_F12] = FALSE;
314 clear_keybuf();
315 capturar_la_pantalla("krap");
316 alert("Screen captured!", NULL,NULL,"OK", NULL,0,0);
317 frame_count = fps = speed_counter = 0;
318 // continuar_musica();
321 /* F10 sirve para prender/apagar la grabacion de videos - DEBUG! */
322 #ifdef SECCION_DESACTIVADA_PARA_EL_RELEASE
323 if (key[KEY_F10])
325 rvideo_is_recording = !rvideo_is_recording;
326 key[KEY_F10] = FALSE;
327 clear_keybuf();
329 #endif
333 /*--------------------------------------------------------
334 Actualiza la pantalla
335 --------------------------------------------------------*/
336 void update_display()
339 /* Tuberia de dibujado, en orden de abajo arriba */
341 set_clip(kfbufferbmp, 0, 0, mapa_fondo->w-1, kfbufferbmp->h-1); /* clipping adecuado */
343 // solo dibuja si la bomba especial no esta activa, sino, es desperdiciar rendering
344 if (!bomba_esta_activa)
346 /* fondo */
347 blit(mapa_fondo, kfbufferbmp, 0, scroll_mapa, 0, 0, mapa_fondo->w, kfbufferbmp->h);
349 if (nivel_detalle > 3) dibujar_humo(kfbufferbmp, 0, scroll_mapa);
351 dibujar_explosion(ptr_explo_fondo, kfbufferbmp, 0, scroll_mapa);
353 dibujar_disp_ene(kfbufferbmp, 0, scroll_mapa);
355 dibujar_enemigos(kfbufferbmp, 0, scroll_mapa);
357 dibujar_disp_jug(kfbufferbmp, 0, scroll_mapa);
359 dibujar_nave_jugador(kfbufferbmp, 0, scroll_mapa);
361 dibujar_premio(kfbufferbmp, 0, scroll_mapa);
363 if (nivel_detalle > 0) dibujar_particulas(kfbufferbmp, 0, scroll_mapa);
365 dibujar_explosion(ptr_explo_arriba, kfbufferbmp, 0, scroll_mapa);
367 if (nivel_detalle > 1) dibuja_clima(kfbufferbmp); // clima
368 } // fin de ver si esta detonando la bomba
369 else
371 dibujar_bomba(kfbufferbmp);
374 /* DEBUG: info de FPS, cantidades, etc */
375 if (KRONO_QUIERE_DEBUG)
377 text_mode(0);
379 /* DEBUG: lo saque, porque ya no lo preciso...
380 textprintf(kfbufferbmp, font, 0, kfbufferbmp->h - text_height(font)-2, makecol(255,255,255),
381 "|fps:%5d|ener:%3d|e:%5d|p:%5d|ex:%5d|" ,
382 fps,
383 jugador.vida,
384 cant_enemigos_debug,
385 cant_particulas_debug,
386 cant_explosion_debug );
389 // Solo fps... por ahora - DEBUG
390 textprintf(kfbufferbmp, font, 0, kfbufferbmp->h - text_height(font)-2, makecol(255,255,255),
391 "fps:%5d fps_max:%5d fps_min:%5d fps_med:%5d",
392 fps, fps_max, fps_min, fps_med);
396 /* Tablero */
397 set_clip(kfbufferbmp, 0, 0, kfbufferbmp->w-1, kfbufferbmp->h-1); /* clipping adecuado */
399 dibujar_tablero(kfbufferbmp);
401 /* a pantalla */
402 enviar_kfbuffer2screen();
406 Esta es la secuencia y loop principal del juego
407 Llamar para comenzar un juego nuevo
408 NOTA: si el parametro load_savegame != 0, se asume
409 que se esta cargando un juego de disco,
410 y no se alteran las variables del jugador!!
412 void comenzar_juego(int load_savegame)
414 /* funcion interna que libera listas enlazadas */
415 void liberar_listas_interno()
417 /* LIBERAR LISTAS... */
418 liberar_lista_enemigos();
419 liberar_lista_disparos_ene();
420 liberar_lista_disparos_jug();
421 liberar_lista_particulas();
422 liberar_lista_explosion(&ptr_explo_fondo);
423 liberar_lista_explosion(&ptr_explo_arriba);
424 liberar_emisores_humo();
425 liberar_humo();
426 liberar_premio();
429 /* funcion interna que limpia los colores y bufferes
430 y coloca la paleta de juego, etc */
431 void hacer_cleanup_mapeos()
433 set_palette(pal_game);
434 color_map = &tabla_transparencia; /* la rutina de sombras la precisa! */
435 rgb_map = &tabla_RGB; /* acelera la fabricacion de colores de 8 bits */
436 set_trans_blender(128, 128, 128, 128); /* Transparencia 50% para > 8 bits */
437 clear(kfbufferbmp); clear(screen); /* limpiar bufferes */
438 clear_keybuf();
439 xset_gui_colors(); /* setea el GUI */
440 set_mouse_sprite(NULL); /* acomoda puntero del mouse para que se ajuste a los colores */
441 llenar_pal_game_oscura(0.25); // prepara la paleta oscura para efectos en los menues
444 /* Funcion interna para instalar los timers */
445 void pone_timers_juego()
447 /* Timers */
448 if (install_int_ex(increment_speed_counter, BPS_TO_TIMER(30)))
449 levantar_error("ERROR: no hay espacio para instalar el timer a 30 fps\n"); /* a 30 fps el juego */
451 if (install_int(fps_proc, 1000))
452 levantar_error("ERROR: no hay espacio para instalar el timer a 1000 milisegundos!\n"); /* a 1000 milisegundos (1 segundo) el contador de fps */
454 /* Reiniciar contadores de velocidad... */
455 frame_count = fps = speed_counter = 0; /* evita salto en los fps */
458 /* Funcion interna para SACAR los timers */
459 void saca_timers_juego()
461 /* remover timers... */
462 remove_int(fps_proc);
463 remove_int(increment_speed_counter);
467 salir_del_juego = FALSE;
469 /* Reiniciar juego, solo si no esta cargando un juego de disco */
470 if (!load_savegame)
472 nivel_actual = 1;
473 reset_total_jugador();
476 fps_min = INT_MAX;
477 fps_max = 0;
478 fps_med = 0;
479 LOCK_VARIABLE(fps_med);
481 /* Frameskip timer */
482 LOCK_VARIABLE(speed_counter);
483 LOCK_FUNCTION(increment_speed_counter);
485 /* Fps timer */
486 LOCK_VARIABLE(frame_count);
487 LOCK_VARIABLE(fps);
488 LOCK_FUNCTION(fps_proc);
490 /* Inicia doble buffer */
491 kfbufferbmp = create_system_bitmap(ANCHO_RFB, ALTO_RFB);
492 if (kfbufferbmp == NULL) levantar_error("ERROR: fallo la creacion del doble buffer! (falta RAM?)");
494 hacer_cleanup_mapeos(); /* limpiar pantalla y mapeos */
496 /* cinematica de introduccion al juego, solo si es el primer nivel */
497 if (nivel_actual == 1) ejecutar_cinematica(game_intro_cine);
499 /* iniciar engine de grabado de videos de promocion */
500 init_rvideo();
502 /* Loop principal de juego */
503 while (!salir_del_juego ) {
505 paso_de_nivel = FALSE;
507 reset_parcial_jugador(); /* reposicionar jugador, etc */
510 Verifico que el proximo nivel exista, si es asi,
511 paso a dibujar las cinematicas, y luego, cargo el nivel en RAM (para ahorrar RAM)
513 if (!cargar_nivel(nivel_actual, -1))
515 liberar_listas_interno(); /* LIBERAR LISTAS... */
516 scroll_mapa = H_FONDO - ALTO_FB; /* iniciar scrolling */
518 hacer_cleanup_mapeos();
520 /* ir al shopping */
521 do_shopping_principal();
523 /* cinematica de entrada al nivel */
524 ejecutar_cinematica(info_nivel.cine_in);
526 /* Luego de las cinematicas, es necesario restaurar mapa RGB,
527 mapa de transparencias y paleta de color... */
528 hacer_cleanup_mapeos();
530 if (cargar_nivel(nivel_actual, 0)) /* cargar el nivel en RAM, en serio... */
531 levantar_error("Fallo la carga del nivel!"); /* shit! que paso - DEBUG */
533 scan_nivel_1era_vez(); /* scanear los enemigos en la pantalla por 1era vez */
535 /* Los timers deben ir EXACTAMENTE antes del while, caso contrario,
536 salta tantos frames como tiempo consuma todo lo anterior! */
537 pone_timers_juego(); /* instala los timers... */
540 musica_play(info_nivel.musica); /* comenzar a ejecutar musica - DEBUG */
542 // Iniciar efectos de clima
543 init_clima(kfbufferbmp, info_nivel.clima_c, info_nivel.clima_t, info_nivel.clima_d);
545 while( !paso_de_nivel && !salir_del_juego )
547 while (speed_counter > 0)
549 update_game_logic(); // actualizar logica del juego
550 speed_counter--;
552 update_display(); // actualizar pantalla
554 frame_count++; // contar los fps
556 /* DEBUG: conteo de fps mas preciso */
557 if (fps > fps_max) fps_max = fps;
558 if (fps < fps_min && fps > 0) fps_min = fps;
560 if (detalle_automatico)
562 nivel_detalle = (fps * 10)/30;
563 if (nivel_detalle > 10) nivel_detalle = 10;
564 if (nivel_detalle < 0) nivel_detalle = 0;
567 } /* looping de juego en el nivel actual */
569 musica_stop(); /* parar musica - DEBUG */
571 saca_timers_juego(); /* desactiva los timers... */
573 /* eliminar los datos del nivel de RAM */
574 if (datmapa != NULL)
576 unload_datafile(datmapa);
577 datmapa = NULL;
580 if (mapa_fondo != NULL)
582 /* liberar RAM consumida por el nivel */
583 destroy_bitmap(mapa_fondo); /* mapa de fondo */
584 mapa_fondo = NULL;
587 /* murio? */
588 if (jugador.vida <= JUG_MUERTO) /* ahora si murio... */
590 paso_de_nivel = FALSE; /* sorry gordi, no pasas si estas muerto! */
591 salir_del_juego = TRUE;
593 /* cinematica de game over */
594 ejecutar_cinematica(game_over_cine);
596 /* Luego de las cinematicas, es necesario restaurar mapa RGB,
597 mapa de transparencias y paleta de color... */
598 hacer_cleanup_mapeos();
600 clear(screen); /* DEBUG, queda bien? */
601 clear_keybuf();
603 /* mensaje */
604 alert(get_config_text("Game Over"), NULL, NULL, get_config_text("OK"), NULL, 0, 0);
607 else /* no encontro el nivel */
609 /* DEBUG: si no encuentra el proximo nivel,
610 SIGNIFICA QUE TERMINO EL JUEGO! */
612 /* Luego de las cinematicas, es necesario restaurar mapa RGB,
613 mapa de transparencias y paleta de color... */
614 hacer_cleanup_mapeos();
616 clear(screen); /* DEBUG, queda bien? */
617 clear_keybuf();
619 /* mensaje */
620 alert(get_config_text("This is the end of the game"), NULL, NULL, get_config_text("OK"), NULL, 0, 0);
622 salir_del_juego = TRUE;
625 if (paso_de_nivel) /* funciones al pasar de nivel */
627 /* ejecutar cinematica salida nivel */
628 ejecutar_cinematica(info_nivel.cine_out);
630 nivel_actual++;
633 } /* looping de juego a traves de los niveles */
635 /* Liberar memoria */
636 liberar_listas_interno(); /* LIBERAR LISTAS... */
637 destroy_bitmap(kfbufferbmp); /* DOBLE BUFFER */
638 kfbufferbmp = NULL;
642 #endif