From: Miriam Ruiz Date: Wed, 3 Dec 2008 10:59:37 +0000 (+0100) Subject: Imported contents: kraptor_final_apr_03_2004.tar.gz X-Git-Url: https://repo.or.cz/w/kraptor.git/commitdiff_plain/17baa3522acf709760735d12e2537422b1694378 Imported contents: kraptor_final_apr_03_2004.tar.gz Downloaded from http://kraptor.sourceforge.net/ Author: Bruno Diaz --- 17baa3522acf709760735d12e2537422b1694378 diff --git a/bin/alleg40.dll b/bin/alleg40.dll new file mode 100644 index 0000000..ccfcc68 Binary files /dev/null and b/bin/alleg40.dll differ diff --git a/bin/allegro.cfg b/bin/allegro.cfg new file mode 100644 index 0000000..269ae32 --- /dev/null +++ b/bin/allegro.cfg @@ -0,0 +1,2 @@ +[system] +language = en diff --git a/bin/cinem02.dat b/bin/cinem02.dat new file mode 100644 index 0000000..a44bc47 Binary files /dev/null and b/bin/cinem02.dat differ diff --git a/bin/cinem03.dat b/bin/cinem03.dat new file mode 100644 index 0000000..9d8063b Binary files /dev/null and b/bin/cinem03.dat differ diff --git a/bin/cinem04.dat b/bin/cinem04.dat new file mode 100644 index 0000000..2ca0694 Binary files /dev/null and b/bin/cinem04.dat differ diff --git a/bin/cinem05.dat b/bin/cinem05.dat new file mode 100644 index 0000000..e268360 Binary files /dev/null and b/bin/cinem05.dat differ diff --git a/bin/cinem06.dat b/bin/cinem06.dat new file mode 100644 index 0000000..3e6b9b1 Binary files /dev/null and b/bin/cinem06.dat differ diff --git a/bin/cinem07.dat b/bin/cinem07.dat new file mode 100644 index 0000000..f78aa83 Binary files /dev/null and b/bin/cinem07.dat differ diff --git a/bin/cinem08.dat b/bin/cinem08.dat new file mode 100644 index 0000000..09224ec Binary files /dev/null and b/bin/cinem08.dat differ diff --git a/bin/cinem09.dat b/bin/cinem09.dat new file mode 100644 index 0000000..429d4d3 Binary files /dev/null and b/bin/cinem09.dat differ diff --git a/bin/cinem10.dat b/bin/cinem10.dat new file mode 100644 index 0000000..9d0bb2e Binary files /dev/null and b/bin/cinem10.dat differ diff --git a/bin/final.dat b/bin/final.dat new file mode 100644 index 0000000..820fbfd Binary files /dev/null and b/bin/final.dat differ diff --git a/bin/gameover.dat b/bin/gameover.dat new file mode 100644 index 0000000..e496894 Binary files /dev/null and b/bin/gameover.dat differ diff --git a/bin/ia.dat b/bin/ia.dat new file mode 100644 index 0000000..6aa7503 Binary files /dev/null and b/bin/ia.dat differ diff --git a/bin/intro.dat b/bin/intro.dat new file mode 100644 index 0000000..4c2f83e Binary files /dev/null and b/bin/intro.dat differ diff --git a/bin/keyboard.dat b/bin/keyboard.dat new file mode 100644 index 0000000..7832efa Binary files /dev/null and b/bin/keyboard.dat differ diff --git a/bin/krapmain.dat b/bin/krapmain.dat new file mode 100644 index 0000000..059f6f0 Binary files /dev/null and b/bin/krapmain.dat differ diff --git a/bin/krapmnu.dat b/bin/krapmnu.dat new file mode 100644 index 0000000..6644190 Binary files /dev/null and b/bin/krapmnu.dat differ diff --git a/bin/kraptor.cfg b/bin/kraptor.cfg new file mode 100644 index 0000000..1fd6ab1 --- /dev/null +++ b/bin/kraptor.cfg @@ -0,0 +1,30 @@ +[kraptor_keyboard] +arr = 84 +abj = 85 +izq = 82 +der = 83 +sht = 26 +wpn = 24 +bmb = 3 + +[kraptor_detalle] +nivel_detalle = 10 +quiere_videos = -1 +detalle_automatico = 0 + +[kraptor_snd] +quiere_snd = -1 +volumen_sonido = 255 +quiere_musica = -1 +volumen_musica = 255 + +[KRONO_QUIERE_DEBUG] +KRONO_QUIERE_DEBUG = 0 + +[kraptor_joystick] +quiere_usar_joystick = 0 +numero_de_joystick = 0 + +[kraptor_mouse] +quiere_usar_mouse = -1 +mouse_velocidad = 32 diff --git a/bin/kraptor.exe b/bin/kraptor.exe new file mode 100644 index 0000000..16fb522 Binary files /dev/null and b/bin/kraptor.exe differ diff --git a/bin/kraptor_w32.exe b/bin/kraptor_w32.exe new file mode 100644 index 0000000..fd3f25a Binary files /dev/null and b/bin/kraptor_w32.exe differ diff --git a/bin/language.dat b/bin/language.dat new file mode 100644 index 0000000..f74e6f8 Binary files /dev/null and b/bin/language.dat differ diff --git a/bin/level1.dat b/bin/level1.dat new file mode 100644 index 0000000..6e81558 Binary files /dev/null and b/bin/level1.dat differ diff --git a/bin/level10.dat b/bin/level10.dat new file mode 100644 index 0000000..368dd13 Binary files /dev/null and b/bin/level10.dat differ diff --git a/bin/level2.dat b/bin/level2.dat new file mode 100644 index 0000000..ead83b6 Binary files /dev/null and b/bin/level2.dat differ diff --git a/bin/level3.dat b/bin/level3.dat new file mode 100644 index 0000000..b230c9f Binary files /dev/null and b/bin/level3.dat differ diff --git a/bin/level4.dat b/bin/level4.dat new file mode 100644 index 0000000..9900994 Binary files /dev/null and b/bin/level4.dat differ diff --git a/bin/level5.dat b/bin/level5.dat new file mode 100644 index 0000000..a199da2 Binary files /dev/null and b/bin/level5.dat differ diff --git a/bin/level6.dat b/bin/level6.dat new file mode 100644 index 0000000..c823c71 Binary files /dev/null and b/bin/level6.dat differ diff --git a/bin/level7.dat b/bin/level7.dat new file mode 100644 index 0000000..65af980 Binary files /dev/null and b/bin/level7.dat differ diff --git a/bin/level8.dat b/bin/level8.dat new file mode 100644 index 0000000..34f7607 Binary files /dev/null and b/bin/level8.dat differ diff --git a/bin/level9.dat b/bin/level9.dat new file mode 100644 index 0000000..3a39f17 Binary files /dev/null and b/bin/level9.dat differ diff --git a/bin/remove.me b/bin/remove.me new file mode 100644 index 0000000..99e8d22 --- /dev/null +++ b/bin/remove.me @@ -0,0 +1 @@ +This file can be safely removed \ No newline at end of file diff --git a/extras/ai/leeme.txt b/extras/ai/leeme.txt new file mode 100644 index 0000000..a7201ff --- /dev/null +++ b/extras/ai/leeme.txt @@ -0,0 +1,12 @@ +Aqui va el compilador de IA de Kraptor +Ver ia.txt para mas info. + +Uso: +parse_ia [entrada.txt] [salida.ia] + +Sintaxis de entrada.txt: +[x1],[x2],[y1],[y2],[weapon],[loop] + +Por Kronoman +En memoria de mi querido padre. +Copyright (c) 2003, Kronoman diff --git a/extras/ai/parse_ia.c b/extras/ai/parse_ia.c new file mode 100644 index 0000000..2d89e7c --- /dev/null +++ b/extras/ai/parse_ia.c @@ -0,0 +1,111 @@ +/*---------------------- +Aqui va el compilador de IA de Kraptor +Ver ia.txt para mas info. + +Uso: +parse_ia [entrada.txt] [salida.ia] + +Sintaxis de entrada.txt: +[x1],[x2],[y1],[y2],[weapon],[loop] + +Por Kronoman +En memoria de mi querido padre. +Copyright (c) 2003, Kronoman +---------------------*/ + +#include +#include + +// Esta funcion hace la joda de parsear y compilar +// in, out son archivo de entrada y salida +void do_parsing(char *in, char *out) +{ +FILE *fin, *fout; +int nlinea =0; // numero de linea, para debugging del programador +char linea[300]; // buffer de texto +char *ret; // para strtok +int params[6]; // contenedor de parametros, temporal +int idx; // indice para params[] + + fin = fopen(in, "r"); + if (fin == NULL) + { + printf("ERROR:\nNo se pudo abrir %s\n\n", in); + return; + } + + fout = fopen(out, "w"); + if (fout == NULL) + { + printf("ERROR:\nNo se pudo abrir %s\n\n", out); + return; + } + + while (fgets(linea, 256, fin) != NULL) // tomar linea + { + nlinea++; + printf("[%04d] '%s'\n\n", nlinea, linea); + + // Realizar el parsing adecuado, es decir, separar la linea en sus parametros + + ret = strtok(linea,","); + + idx = 0; + while (ret != NULL) + { + params[idx] = atoi(ret); // convertir a entero + printf("-> %s = %d \n", ret, params[idx]); + + ret = strtok(NULL, ","); + idx ++; + if (idx > 6) + { + printf("ERROR!\nDemasiados parametros!\n"); + return; + } + } + if (idx < 6) + { + printf("ERROR!\nInsuficientes parametros!\n"); + return; + } + + // escribir, los parametros del bytecode (x1,x2,y1,y2,weapon,loop) + for (idx=0; idx<6;idx++) + { + // escribo los enteros como strings, por PORTABILIDAD! + sprintf(linea,"%d", params[idx]);! + fputs(linea, fout); // como esto convierte en UTF-8, no la uso + + putc(',', fout); // separador logico + } + }; + + // listo + fclose(fout); + fclose(fin); +} + + + + + + + +int main(int argc, char *argv[] ) +{ + + + if (argc < 2) + { + printf("ERROR:\nNo especifico [entrada.txt] y [salida.ia]\n\n"); + return -1; + } + + printf( "%s -> %s \n", argv[1], argv[2] ); + do_parsing(argv[1], argv[2]); + + +return 0; +} + diff --git a/extras/doc/es/cinemati.txt b/extras/doc/es/cinemati.txt new file mode 100644 index 0000000..283f336 --- /dev/null +++ b/extras/doc/es/cinemati.txt @@ -0,0 +1,213 @@ +Engine de cinematicas mediante scripting y bitmaps y animaciones +Por Kronoman +En memoria de mi querido padre +Copyright (c) Septiembre de 2002 +--------------------------------------------------------------------- +Algunas ideas: + +El texto del script es leido desde un campo ->dat de un objeto +DATAFILE de Allegro. +Se lee como una cadena de chars, donde cada linea termina con un +caracter 10 (LF, guarda compatibilidad con archivos de Linux!) +Se va interpretando linea a linea. +Por cada linea obtenida, se separa en parametros, y luego, el 1er parametro +es tomado y se llama a la funcion que lo interpreta. +Para listar las funciones se tiene una estructura con la instruccion (char) +y el puntero a la funcion que la interpreta. +Se busca en esta lista la instruccion ingresada. +La funcion devuelve 0 si OK, -1 en falla. +La funcion no recibe parametros. Los parametros de la linea estan +almacenados en matrices globales. +Son 3 matrices globales que contienen diferentes interpretaciones +de los parametros. +1) Parametros interpretados como enteros int +2) Parametros interpretados como strings de char +3) Todo lo que quedo despues de la primera instruccion (linea completa + sin 1era instruccion) +Ademas, cada matriz contiene la cantidad de parametros interpretados, +para poder comprobar si el usuario se olvido algun parametro. +--------------------------------------------------------------------- +Multimedia: + +Las animaciones son archivos FLIC (fli/flc), y el texto subtitulado +sincronizado va en un objeto aparte sincronizado con los frames del FLIC +Las imagenes fijas son bitmaps +Los sonidos son samples +La musica es MOD (para DUMB) +La musica por AHORA NO ESTA IMPLEMENTADA, POR COMPLICACIONES CON EL +poll que precisa la musica en DUMB!!! +--------------------------------------------------------------------- +Bitmap de buffer: + +El engine dibuja a un bitmap de buffer de 640x480, donde luego +es enviado a pantalla cuando esta listo [ajustando la proporcion +a la resolucion de pantalla]. +--------------------------------------------------------------------- +Sintaxis: + +TODAS LAS INSTRUCCIONES Y PARAMETROS DEBEN IR SEPARADOS POR UN (1) ESPACIO! +EL ENGINE ES SENSIBLE A MAYUSCULAS/MINUSCULAS +Todo lo que comienze con # es comentario y esa linea es IGNORADA. +Las instrucciones son del tipo + [instruccion] [parametro] [parametro] [etc] +NOTAR el espacio entre [parametro] y [parametro], etc... +--------------------------------------------------------------------- +Juego de instrucciones para el script principal: +El script principal indica la secuencia de eventos que deben producirse, +es decir, que animaciones reproducir, que sonidos tocar, etc. +NOTAR que los parametros NO son opcionales, olvidarselos puede ocurrir +en resultados IMPREDECIBLES! (no hay comprobacion de errores...) + +# comentario + Toda linea que comienze con # es IGNORADA (se considera un comentario) + OK + +cls [r] [g] [b] + Limpia la pantalla a color [r] [g] [b] (color RGB 0..255 c/u) + OK + +fade_out [velocidad] + Realiza una transicion a color negro + [velocidad] 1..64 (lento-rapido) + OK + +fade_out_color [r] [g] [b] [velocidad] + Realiza una transicion al color [r] [g] [b] + [velocidad] 1..64 (lento-rapido) + OK + +rect [x] [y] [x2] [y2] [r] [g] [b] + Dibuja un rectangulo desde [x] [y] a [x2] [y2] + [r] [g] [b] es el color, en valores RGB 0..255 + OK + +rectfill [x] [y] [x2] [y2] [r] [g] [b] + Dibuja un rectangulo LLENO desde [x] [y] a [x2] [y2] + [r] [g] [b] es el color, en valores RGB 0..255 + OK + +line [x] [y] [x2] [y2] [r] [g] [b] + Dibuja una linea desde [x] [y] a [x2] [y2] + [r] [g] [b] es el color, en valores RGB 0..255 + OK + +locate [x] [y] [w] + Posiciona la salida de texto en [x] [y] con ancho [w] + Setea el borde [w] como 'filo' o 'borde' para las salidas de texto (echo) + Al llegar el texto a esa posicion, hace word-wrap + OK + +text_color [r] [g] [b] + Setea el color del texto a colocar en futuras llamadas + [r] [g] [b] es el color, en valores RGB 0..255 + OK + +text_back [r] [g] [b] + Setea el color del FONDO del texto a colocar en futuras llamadas + [r] [g] [b] es el color, en valores RGB 0..255 + Si algun [r] [g] [b] es < 0 (ej: -1) el fondo del texto es transparente + OK + +text_font [font] + Cambia la fuente de las salidas de echo; si no se pone [font], + se volvera al font original de la BIOS. + [font] debe ser un objeto de tipo 'font' contenido en el archivo + de la cinematica. + OK + +echo [texto] + Escribe el [texto] en pantalla, con word-wrap al borde seteado + Desplaza la coordenada [y] hacia abajo y [x] al origen anterior (salto de linea) + OK + +echo_centre_x [texto] + Escribe el [texto] centrado en [x] en pantalla, con word-wrap al borde seteado + Desplaza la coordenada [y] hacia abajo y [x] al origen anterior (salto de linea) + OK + +echo_centre_xy [texto] + Escribe el [texto] centrado en [x] e [y] en pantalla, con word-wrap al borde seteado + Desplaza la coordenada [y] hacia abajo y [x] al origen anterior (salto de linea) + OK + +rest [milisegundos] + Espera [milisegundos] antes de continuar la interpretacion... + Si [milisegundos] <= 0, espera por una tecla... + OK + +set_palette [paleta_256_colores] + Setea la paleta de colores actual al objeto PALETA [paleta_256_colores] + Esto es lento, porque ademas, calcula la tabla RGB para la paleta + OK + +set_palette_default + Setea la paleta default de la placa VGA + OK + +blit [x] [y] [bitmap] + Coloca el [bitmap] en [x] [y] + OK + +sprite [x] [y] [sprite] + Coloca el [sprite] en [x] [y] filtrando el color de mascara + OK + +stretch_blit [x] [y] [w] [h] [bitmap] + Coloca el [bitmap] en [x] [y] estirandolo a ancho [w] y alto [h] + OK + +play_sample [sample] [vol] [pan] [freq] + Lanza un sonido con el volumen, paneo y frecuencia. + El volumen y paneo van desde 0 (min/izq) hasta 255 (max/derecho), + 127 es la mitad del parlante. + Frecuencia es relativa mas que absoluta: 1000 representa la frecuencia a la que + el sonido fue grabado, 2000 es el doble, 3000 el triple, 500 la mitad, etc + OK + +clear_fli_back [r] [g] [b] + Esto es una 'bandera' que permite que cuando se ejecute un FLI, + antes de mostrar el primero cuadro, se limpie a color [r] [g] [b] + Coloque [r] [g] [b] = -1 para que no se limpie la pantalla + El default es limpiar a negro... + OK + +keyboard_cancel_fli [valor] + Esto permite que el usuario cancele una animacion fli al apretar una tecla + El default es 0 [NO] + Cualquier valor <> que 0, indica que si. (Usar -1 por las dudas) + OK + +play_fli [x] [y] [w] [h] [loop] [objeto_fli] [script_fli] + Ejecuta una animacion FLI contenida en el DAT. + NOTA: esto modifica la paleta de colores! si hubiera algo dibujado, podria + verse raro, e incluso, el fondo puede cambiar si el flag clear_fli_back no esta seteado + [x] [y] son las coordenadas de la esquina superior izquierda + donde deben ponerse los cuadros. + [w] [h] es el ancho y alto del fli (se estirara!) + [loop] Indica la cantidad de veces que deben repetirse los cuadros. + *NOTA* Al llegar al final, el script cuenta de nuevo desde el primer frame + por lo tanto, el [script_fli] comienza de nuevo. + [objeto_fli] Indica el objeto de tipo FLI a reproducir, contenido en el DAT. + [script_fli] Indica el script (objeto de tipo TXT) que contiene el sonido, + subtitulos, etc del FLI. + Ver mas adelante la documentacion para saber como es el formato. + OK +--------------------------------------------------------------------- +Formato del [scrip_fli] para el comando "play_fli" + +Es un objeto de texto tipo TXT que indica los sonidos, y subtitulos frame x frame +[NOTA DEBUG: los subtitulos NO estan implementados todavia] +NOTA: los frames se comienzan contando desde 1 + +El formato es asi: +[FRAME_n] +snd = [sample] + +---------- +Ejemplo: + +[FRAME_11] +snd = explosion + +[FRAME_48] +snd = final diff --git a/extras/doc/es/general.txt b/extras/doc/es/general.txt new file mode 100644 index 0000000..943421d --- /dev/null +++ b/extras/doc/es/general.txt @@ -0,0 +1,457 @@ +Kraptor +------- +Por Kronoman - +Comenzado en Agosto 2002 +En memoria de mi querido padre + +Engine de juego de aviones/naves +Hecho en C, con Allegro y DUMB + +Kraptor: especificaciones tecnicas +---------------------------------- + +Fondos: +600x4000 [grilla de 40x40] +Matriz de 15x100 indica si explota o no el fondo, un numero > 0 indica +que esa area es explosiva, al tocar un disparo esa area, descuenta del mapa +y finalmente explota, junto con los adyacentes. + +Matriz de 15x100 tiene un numero, > 0 indica que debe aparecer un enemigo +de esa clase-1, 0 = neutro. O sea, por ejemplo: el numero 1 indica que +debe aparecer un enemigo de clase 0, 2 de clase 1, etc (o sea, n-1, siendo 0 neutro) + +NOTA: usar siempre compresion individual de objetos en los datos, no global, + ya que ralentiza mucho el tiempo de carga. + +Archivos DATAFILES: +------------------------------------------------------- + +Datos principales del programa +--> krapmain.dat + + Contiene los datos principales del juego, tales como enemigos, + jugador, armamento, sonido, pirotecnia, premios y secuencia de niveles. + Ademas, debe contener los datos opcionales mencioados + en los scripts (tales como sprites, sonidos, etc). + NO contiene los archivos de cada nivel independiente. + + Contenido: + ========= + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + Objetos sueltos necesarios: + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + hud_font + + Font para dibujar el 'hud', es decir la informacion + de puntaje y cantidad de balas. + Si no existe, se usa el font de la BIOS + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + pal_game + + Paleta de 256 colores usada durante TODO el juego + Los enemigos, explosiones, particulas, fondos, etc DEBEN ajustarse + a esta paleta. Esto NO afecta las cinematicas o los menues. + SI afecta a la imagen de fondo del shopping + RESPETAR LAS MINUSCULAS EN EL NOMBRE, pal_game! + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + shop_bmp + + Imagen de fondo del shopping + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + burn_0 + burn_1 + burn_2 + Sprites de 40x40 para quemar el fondo. + Deben representar un hoyo de quemazon, en escala de grises + inversa, el color negro sera transparente, y los tonos + de blanco indican profundidad de quemado, siendo 255,255,255(RGB) + el mas profundo. + Deben estar hechos para poder ser rotados arbitrariamente + al azar (para dar mas variedad) + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + humo + Sprite de unos 100x100 que sera usado para generar el efecto de humo. + Esto es _opcional_, ya que todavia no funciona muy bien el efecto. + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + explo_bmp_0 + explo_bmp_1 + explo_bmp_2 + + Sprites de explosiones, todas del MISMO tama~o, usadas para renderear + explosiones. + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + explo_snd_0 + explo_snd_1 + explo_snd_2 + + Sonido de explosiones. + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + chispa_0 + chispa_1 + chispa_2 + + Chispas que las naves arrojan al explotar (bolitas de fuego peque~as). + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + gamescript + + Objeto de texto que contiene un script que indica la sucesion de niveles + del juego de manera descriptiva como un archivo de configuracion de Allegro + Se van leyendo las secciones [NIVEL_x] hasta que no se encuentra la proxima, + con lo cual se asume que el juego termino (el jugador gano). + Las cinematicas se pueden suprimir colocando valor `null` (sin las `) + + + La seccion [GAME_INTRO] contiene la cinematica cuando el jugador inicia un juego nuevo. + La seccion [GAME_OVER] contiene la cinematica cuando el jugador pierde. + + Comienza a contar de nivel 1 + Todo lo que tiene # es comentario + + Ejemplo (script de 2 niveles): + + [GAME_INTRO] + cine = intro.dat + + [GAME_OVER] + cine = gameover.dat + + [NIVEL_1] + # Titulo del nivel + titulo = Primera Batalla + + # Explicacion, hasta 256 caracteres, usa word-wrap + texto = Te aproximas al primer combate, buena suerte! + + # Cinematica de comienzo de nivel + cine_in = intro01.dat + + # Esto especifica el nivel conteniendo datos de juego + level_dat = level1.dat + + # Cinematica de fin de nivel + cine_out = null + + # Referente al efecto climatico, es opcional + # densidad del clima en particulas 0..300 + clima_c = 100 + # tipo de clima: 0 = lluvia, 1 = nieve + clima_t = 0 + # direccion de caida: 0 = izq, 1 = der + clima_d = 0 + + [NIVEL_2] + # Titulo del nivel + titulo = Final + + # Explicacion, hasta 256 caracteres, usa word-wrap + texto = Este es el final, mi unico amigo! + + # Cinematica de comienzo de nivel + cine_in = null + + # Esto especifica el nivel conteniendo datos de juego + level_dat = level1.dat + + # Cinematica de fin de nivel + cine_out = fin.dat + + # Al buscar el 3er nivel, el juego finaliza, y va a la tabla de puntos. + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + jugador + + Esto contiene una definicion de los sprites, armas y sonidos del jugador + Ejemplo: + + # Configuracion del jugador + [JUGADOR] + # Sprites del jugador izq,med,der + # DEBEN ser del MISMO tama~o y contenidos en este mismo archivo DAT + spr_0 = jugador_0 + spr_1 = jugador_1 + spr_2 = jugador_2 + + # dinero inicial con que cuenta al comenzar a jugar + init_money = 500 + + # bombas iniciales con que cuenta al comenzar a jugar + init_bombas = 1 + + # Referente a la reparacion de la nave en el shopping + [JUGADOR_REPARAR] + # Cantidad de unidades que da cada reparacion + cantidad = 10 + # Precio cada reparacion de la nave + precio = 100 + # Descripcion + desc = Reparar el 10% de los desperfectos de la nave + # Bitmap que representa la reparacion, de 116x124 preferentemente (se estirara) + bmp = bitmap_reparar + + # Referente a la bomba especial de la nave en el shopping + [JUGADOR_BOMBA_ESPECIAL] + # cantidad de bombas de cada compra + cantidad = 1 + # precio de cada item de bomba especial + precio = 100 + # descripcion + desc = Bomba de pulso de energia + # Bitmap que representa en el shopping, de 116x124 + bmp = bitmap_bomba + # sonido de lanzamiento de la bomba (OJO, cuando explota, toca sonido de explosion; esto deberia ser un speech, tipo "bomb fire" o algo asi!) + bomba_sonido = speech_bomb_fire + + # cantidad maxima que se puede comprar + max_ammo = 5 + + # Armamento disponible para el jugador (el arma 0 esta siempre y nunca se acaba) + # Va de ARMA_0 hasta ARMA_x [x es un numero] + [ARMA_0] + # Referente al modo 'shopping' del arma + # bitmap de 116x124 preferentemente (se estirara) + arma = dibujo_del_arma_en_el_shop_bitmap + # descripcion del arma para el shop: maximo 2048 caracteres + desc = Descripcion del arma + # descripcion corta para el HUD del juego: max 20 caracteres + desc_short = Wpn #0 + # precio, cuidar que sea relativo a lo que 'gana' el jugador + precio = 12345 + # cantidad de 'balas' por paquete de compra + cant_ammo = 100 + # cantidad maxima de 'balas' + cant_ammo_max = 999 + + # Referente al disparo del arma en si + spr = sprite_del_disparo + snd_0 = sonido_al_disparar_o_null + snd_1 = sonido_al_impactar_o_null + vx = 0 + vy = -0.5 + vida = 480 + punch = 3 + firerate = 100 + t = 0 + + # Estela del disparo, esto es opcional (si no aparece, no abra estela) + # Vida + est_vida_min = 1 + est_vida_max = 10 + # Cantidad + est_cant_min = 5 + est_cant_max = 10 + # color RGB + est_color_r_min = 128 + est_color_r_max = 255 + est_color_g_min = 0 + est_color_g_max = 0 + est_color_b_min = 0 + est_color_b_max = 0 + # escala aceleracion: 100 = 0.01 + est_dx_min = -100 + est_dx_max = 100 + est_dy_min = 100 + est_dy_max = 300 + # tipo de particula + est_tipo_min = 3 + est_tipo_max = 3 + # radio de la particula (si es aplicable) + est_rad_min = 1 + est_rad_max = 3 + # usar transparencia? (-1 = si, 0 = no) + est_transp = 0 + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + enemigos + + Esto contiene una definicion de los enemigos asi como de sus + tipos de armamento, y la IA que utilizan (Ver ia.txt). + Ejemplo: + + # clases de enemigos + [ENEMIGO_0] + # vida enemigo + vida = 100 + # peso del enemigo (sirve para proporcion de explosion e impacto de colision) + peso = 50 + + # string de ID de programa en bytecodes de IA (ver ia.txt) + tipo_ia = ia_1 + # la IA debe comenzar en un punto arbitrario del bytecode (al azar = -1, default: 0 = no) + ia_azar = 0 + + # este flag indica que el enemigo es un BOSS, de esa manera, el enemigo + # no se va NUNCA hacia abajo de 1/2 de pantalla (como hacen los boss) + # (default 0 = no; -1 = si) + ia_boss = 0 + + # sprites de animacion, + # se pueden obviar; hay un maximo de 4 (0..3) + # si utiliza uno solo, se puede poner spr = dibujo y listo + spr_0 = enemigo0_0 + spr_1 = enemigo0_1 + spr_2 = enemigo0_2 + spr_3 = enemigo0_3 + + # delay de animacion de los sprites (30 = 1 segundo) + spr_delay = 10 + + # dinero que paga matar a este enemigo + dinero = 50 + + # premio (indice del premio) que suelta este enemigo (-1 = ninguno) + premio_idx = 1 + # probabilidad de soltar el premio al morir (0..100 %) + premio_prob = 95 + + # clases de armas + [ARMA_0] + # dibujo del disparo + spr = laser2 + # sonido al disparar + snd_0 = sonido_al_disparar_o_null + # sonido al impactar + snd_1 = sonido_al_impactar_o_null + # velocidad x + vx = 0 + # velocidad y + vy = 2 + # duracion del disparo en tics (30 = 1 segundo) + vida = 400 + # golpe del disparo + punch = 20 + # tipo de arma + t = 2 + + # Estela del disparo, esto es opcional (si no aparece, no abra estela) + # Vida + est_vida_min = 1 + est_vida_max = 10 + # Cantidad + est_cant_min = 5 + est_cant_max = 10 + # color RGB + est_color_r_min = 128 + est_color_r_max = 255 + est_color_g_min = 0 + est_color_g_max = 0 + est_color_b_min = 0 + est_color_b_max = 0 + # ( escala aceleracion: 100 = 0.01) + est_dx_min = -100 + est_dx_max = 100 + est_dy_min = 100 + est_dy_max = 300 + # tipo de particula + est_tipo_min = 3 + est_tipo_max = 3 + # radio de la particula (si es aplicable) + est_rad_min = 1 + est_rad_max = 3 + # usar transparencia? (-1 = si, 0 = no) + est_transp = 0 + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + premios + + Este script configura los premios. + Ver el archivo premio.txt para mas informacion. + + ------------------------------------------------------------------------- +Menues: +Nota: los archivos de texto para presentar en pantalla + (ej: help, about) deben estar codificados en UTF-8 + para ello, usar el utilitario de Allegro "textconv.exe" + +--> krapmnu.dat: + + Esto contiene el fondo del menu y otros items utiles. + + main_menu_bmp <- bitmap de 640x480 que es el fondo del menu + main_menu_pal <- paleta de 256 colores del menu + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + help_txt + + Es un archivo de texto guardado tal cual (modo binario) + para mostrar en el menu Ayuda / Ayuda... + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + about_txt + + Es un archivo de texto guardado tal cual (modo binario) + para mostrar en el menu Ayuda / Acerca de... + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + about_bmp + + Es una imagen de tipo BITMAP, que se mostrara en Ayuda / Acerca de... + ajustarse a main_menu_pal! + Tama~o: 144x168 pixels! + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + ------------------------------------------------------------------------- + +Niveles: +--> level*.dat: + + Esto contiene el fondo (bitmap) y su correspondiente matrices de mapas + para los diferentes niveles de dificultad. + Se van cargando dinamicamente a medida que avanza el juego. + + Contenido: + ========= + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + mapa_fondo + + Esto es la imagen del juego, de 600x4000 pixels. + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + mapa_g + + Informacion binaria (matriz) con los sectores explosivos del mapa. + 0 indica sector no explosivo, > 0 indica energia de ese sector, + al llegar a 0, explota y queda 'quemada' el area. + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + enem_g -> opcional, dificultad unica + enem_g_0 -> dificultad FACIL + enem_g_1 -> dificultad MEDIA + enem_g_2 -> dificultad DIFICIL + + Informacion binaria (matriz) con las posiciones de aparicion de enemigos. + Contiene 0 donde no aparecen enemigo, > 0 donde aparecen enemigos. + El numero indica el indice de clase de enemigo a aparecer, y se le + restara 1, asique enemigo 1 en enem_g representa ENEMIGO_0 en + las clases de enemigos. + Nota, el engine busca el enem_g_[dificultad] + Si no existe, intenta obtener enem_g, y si no existe, aborta el programa. + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + musica + + Musica IT, XM o S3M, opcional, se escucha de fondo durante el nivel. :^P + En formato IT, XM o S3M, para mas info, ver la documentacion de DUMB + (como cargar musica desde un DAT) + Debe ser un objeto binario de tipo "IT ", "XM " o "S3M " + Los espacios adicionales no son necesarios, el grabber los pone solo. + La musica debe durar aproximadamente 133 segundos (2 mins 13 segs) + porque es lo que dura un nivel aproximadamente (4000/30 pixels x segundo) + ------------------------------------------------------------------------- +Cinematicas: +--> cine*.dat + + Esto contiene las cinematicas del juego, se cargan dinamicamente a + medida que se necesitan. + + NOTA: el 'lenguaje' usado en el script de cinematicas esta explicado + en el archivo cinemati.txt!! + + Contenido: + ========= + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + El unico contenido obligatorio es el objeto de texto (TXT) + llamado 'guion_txt' que contiene los comandos + especificados en cinemati.txt para poder mover la cinematica + NOTA: se buscara el guion acorde al lenguaje actual primero, + por ejemplo, si es espa~ol, se buscara guion_txt_es primero, + y si no existe, se usara guion_txt, y si no existe, + se intentara cargar guion_txt_en, y si no existe, se ignorara + la animacion. + O sea, para internacionalizar el juego, crear un guion_txt_es (espa~ol) + y un guion_txt_en (ingles) y los demas que sean necesarios. + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + ------------------------------------------------------------------------- diff --git a/extras/doc/es/ia.txt b/extras/doc/es/ia.txt new file mode 100644 index 0000000..c8e0ba8 --- /dev/null +++ b/extras/doc/es/ia.txt @@ -0,0 +1,78 @@ +Kraptor - Sistema de Inteligencia Artificial + + +Por Kronoman +En memoria de mi querido padre. + +-------------------------------------------------------------------------- +Este documento describe como funciona el sistema de inteligencia artificial. + + +Espacio fisico en disco: + +Los archivos de IA son _objetos binarios_ (DAT_BINARY) +con la propiedad tipo "IA" (mayusculas), guardados en el archivo de "grabber", "ia.dat", +usando compresion _individual_ de objetos. +Recomiendo que cada objeto tenga el prefijo ia_[nombre] +y que su nombre no supere los 256 caracteres, ya que sera la ID +para identificarlo al cargar las clases de enemigos. +Ejemplo: ia_agresiva, ia_simple, etc... + +-------------------------------------------------------------------------- +Mantenimiento en RAM: + +Al principio del juego, se carga el archivo krap_ia.dat, +y entonces, se crea un cache donde van todas los scripts, +ya traducidos de binario al formato de la plataforma. +Todo esto se hace con memoria dinamica y listas enlazadas. +Luego, cada vez que se carga una clase de enemigo, +se le asigna un puntero a la IA correspondiente en la lista +enlazada previamente cargada. + +Es decir: +- cargar krap_ia.dat +- copiar y traducir los scripts a una nueva lista +- descargar krap_ia.dat +- cargar clase de enemigos, y para cada clase, asignarle + el puntero a la IA asignada. + +-------------------------------------------------------------------------- +Del lenguaje de scripting: + +Las instrucciones se escriben en un archivo de texto plano, +luego se pasan por el compilador, el cual las convierte +a un fichero semi-binario (es un archivo de texto con formato simple), +el cual es agregado usando "grabber" al archivo krap_ia.dat +Lo interesante es que el "lenguaje" para el script +contiene UNA sola instruccion, ya que es muy especializada +para el manejo de los enemigos, la cual contiene +el movimiento por ciclo del enemigo (30 ciclos = 1 segundo). + +NOTA: el "compilador" es extremadamente BASICO, por lo tanto + NO EXISTEN COMENTARIOS, NO PONER ESPACIOS EXTRA, + NI NADA "RARO"; SOLO PONER LAS LINEAS CON LA SINTAXIS + ESPECIFICADA! + +La sintaxis para el codigo de texto plano es la siguiente: +[x1],[x2],[y1],[y2],[weapon],[loop] + +Donde: +[x1],[x2] son rangos de movimiento en X para el enemigo + por ejemplo, 1,2 indica un movimiento entre +1 y +2 + -5, 5 indica un movimiento entre -5 y +5 (-4,-3...0,1,etc) +[y1],[y2] funcionan igual a [x1],[x2], pero en el eje Y +[weapon] indica que el enemigo debe disparar ese numero de clase de arma. + un valor de -1 indica NO disparar. + +[loop] indica la cantidad de veces que se debe repetir esta accion + la duracion de cada instruccion es 1/30 de segundo, asique + un valor de 30, repetira la accion 1 segundo completo. + +Luego, el texto plano se pasa por un compilador, el cual +interpreta la secuencia y la salva a disco en un archivo semi-binario. +El archivo semi-binario tiene el formato de texto ASCII, donde +se colocan los numeros separados por comas, todos en una sola linea larga, +lo que permite parsearlo en tiempo de ejecucion facilmente. +ej: +1,2,3,4,5,6,7,8,9,0,1,2 [...] +-------------------------------------------------------------------------- diff --git a/extras/doc/es/language.txt b/extras/doc/es/language.txt new file mode 100644 index 0000000..2a3c3b4 --- /dev/null +++ b/extras/doc/es/language.txt @@ -0,0 +1,30 @@ +Kraptor +------- +Por Kronoman - Agosto 2002 - En memoria de mi querido padre + +Engine de juego de aviones/naves +Licencia GNU GPL +Hecho en C, con Allegro y DUMB + +Soporte de diferentes teclados de Kraptor +----------------------------------------- +Incluir el archivo keyboard.dat que trae Allegro. :^) + +Modo de soporte de multiples lenguajes de Kraptor +-------------------------------------------------- + +Kraptor soporta multiples lenguajes gracias a las facilidades de Allegro. +El archivo language.dat debe estar presente (viene con Allegro) +y cada objeto interno debe contener los textos adecuados para cada idioma. +El idioma de base es el ingles, asique, los textos en el codigo fuente +deben estar en ingles. +La GUI esta dise~ada para auto-traducirse 'al vuelo', es decir, +cada vez que se dibuja, busca el nuevo lenguaje. + +El archivo kraptor.cfg debe contener + +[system] +language = es + +Donde language puede ser: es, en, etc (es decir, el codigo de 2 letras +del lenguaje a usar). diff --git a/extras/doc/es/license.txt b/extras/doc/es/license.txt new file mode 100644 index 0000000..54f0bb7 --- /dev/null +++ b/extras/doc/es/license.txt @@ -0,0 +1,16 @@ +Kraptor Game Engine +Kraptor Game Datafiles + +Copyright (c) 2002, 2003, Kronoman +In loving memory of my father. + +This software is OSI Certified Open Source Software. +OSI Certified is a certification mark of the Open Source Initiative. + +Distributed under The MIT License + +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/extras/doc/es/premios.txt b/extras/doc/es/premios.txt new file mode 100644 index 0000000..6e6f2a4 --- /dev/null +++ b/extras/doc/es/premios.txt @@ -0,0 +1,39 @@ +Premios del juego +----------------- + +Los premios que sueltan los enemigos estan definidos en un script +de texto "premios" contenido en el archivo krapmain.dat + + +El archivo tiene este formato: + +[PREMIO_n] +premiar = [indice del objeto que premia tomar este premio, ver mas abajo] +cantidad = [cantidad que da tomar ese premio] +sprite = [imagen que lo representa (sprite) ] +vida = [vida del premio antes de desaparecer si el jugador no lo agarra] +sonido = [sonido al tomarlo ] + +Explicacion +----------- + +[PREMIO_n] indica el indice del premio, como sera referenciado en +el campo premio_idx del script de enemigos. +Va de 0..[ver codigo fuente] + +"premiar" es un indice que va desde -2 a [max armas jugador] +siendo: +-2 = premiar con bombas extra +-1 = premiar con energia extra +0 en adelante = premiar con armamento correspondiente a ese indice (MAX_ARM_CLASS en jugador.h) + +"cantidad" es la cantidad de premio que se le dara; +por ejemplo, si es 5 y premiar es -1, se le sumaran 5 puntos de energia +al jugador. + +"sprite" es el nombre del bitmap que lo representa, debe estar contenido +en krapmain.dat. + +"vida" es la duracion del premio antes de desaparecer de escena (30 = 1 segundo) + +"sonido" es un sample que se tocara cuando se junte el premio \ No newline at end of file diff --git a/extras/mapedit/eneedit.c b/extras/mapedit/eneedit.c new file mode 100644 index 0000000..42dcefc --- /dev/null +++ b/extras/mapedit/eneedit.c @@ -0,0 +1,353 @@ +/* + Editor de la matriz de enemigos para Kraptor + NOTA: si se ejecuta con krapmain.dat presente en el mismo directorio, _MUESTRA_ los enemigos + con sprites, en vez de usar los numeros. [cool!] + + Kronoman 2003 + En memoria de mi querido padre + Teclas: + DELETE = casilla a 0 + BARRA = situar valor seleccionado + FLECHAS = mover cursor + + y - del keypad: alterar valor en +1 + 1 y 2 : alterar valor en +10 + 0 : valor a 0 + C : limpiar grilla a ceros + S : salvar grilla + L : cargar grilla + V : ver fondo sin grilla + R : agregar enemigos del tipo seleccionado al azar + ESC : salir + + NOTA: los mapas se guardan con las funciones especiales de Allegro + para salvar los integers en un formato standard, de esa manera, + me ahorro los problemas con diferentes tama~os de enteros segun + la plataforma. + + */ + +#include +#include +#include + +/* Tama¤o del fondo */ +#define W_FONDO 600 +#define H_FONDO 4000 + +/* Grilla WxH */ +#define W_GR 40 +#define H_GR 40 + +/* Grilla */ +long grilla[W_FONDO / W_GR][H_FONDO / H_GR]; + +/* En vgrilla pasar -1 para dibujarla, o 0 para ver el bitmap suelto */ +int vgrilla = -1; + +int xp = 0, yp = 0, vp = 1; /* x,y, valor a colocar */ + +// cache de sprites de los enemigos, para mostrarlos en pantalla... :) +// funciona si esta presenta krapmain.dat en el lugar +#define MAX_SPR 100 // sprites cargados 0..MAX_SPR - 1 +BITMAP *sprite[MAX_SPR]; +DATAFILE *data = NULL; // datafile +/* Bitmap cargado en RAM del fondo */ +BITMAP *fnd; +PALETTE pal; /* paleta */ + +/* Buffer de dibujo */ +BITMAP *buffer; + + +// Esto carga de disco el cache de sprites +// COOL! +void cargar_cache_sprites() +{ +DATAFILE *p = NULL; // punteros necesarios +int i; // para el for +char str[1024]; // string de uso general + + for (i = 0; i < MAX_SPR; i++) sprite[i] = NULL; + + data = load_datafile("krapmain.dat"); + + if (data == NULL) return; // no esta presente el archivo - DEBUG, informar, o algo... :P + + p = find_datafile_object(data, "enemigos"); + if (p == NULL) + { + unload_datafile(data); + data = NULL; + return; + } + set_config_data((char *)p->dat, p->size); + + for (i=0; i < MAX_SPR; i++) + { + /* Seccion ENEMIGO_n */ + sprintf(str,"ENEMIGO_%d", i); + + // buscar el 1er cuadro de animacion del enemigo unicamente... + p = find_datafile_object(data, get_config_string(str, "spr", "null")); + + if (p == NULL) p = find_datafile_object(data, get_config_string(str, "spr_0", "null")); + + if (p != NULL) sprite[i] = (BITMAP *)p->dat; + + } + + // NO se debe descargar el datafile, porque suena todo! [los sprites deben permanecer en RAM] +} + +// Limpia la grilla con ceros +void limpiar_grilla() { + int xx, yy; + /* limpio la grilla a ceros */ + for (xx =0; xx < W_FONDO / W_GR; xx++) + for (yy =0; yy < H_FONDO / H_GR; yy++) + grilla[xx][yy] = 0; +} + +// Redibuja la pantalla +void redibujar() { + int iy, ix; + + clear(buffer); + blit(fnd, buffer, 0, yp * H_GR,0,0,600,480); + + /* grilla */ + if (vgrilla) + { + for (ix=0; ix < W_FONDO / W_GR; ix ++ ) + line(buffer, ix*W_GR, 0, ix*W_GR, 480, makecol(255,255,255)); + + for (iy=0; iy < H_FONDO / H_GR; iy ++ ) + line(buffer, 0, iy*H_GR, fnd->w, iy*H_GR, makecol(255,255,255)); + } + + /* cursor */ + line(buffer, xp * W_GR, 0, (xp * W_GR) + W_GR, H_GR, makecol(255, 255, 255)); + line(buffer, xp * W_GR, H_GR, (xp * W_GR) + W_GR, 0, makecol(255, 255, 255)); + + /* mostrar los valores (o sprite, si esta disponible) que contiene la matriz */ + text_mode(makecol(0,0,0)); + for (ix=0; ix < W_FONDO / W_GR; ix ++ ) + { + for (iy=0; iy < H_FONDO / H_GR; iy ++ ) + { + if (yp + iy < H_FONDO / H_GR ) + { + if (grilla[ix][yp+iy] != 0) + { + // ver si hay un sprite disponible... + if ( (grilla[ix][yp+iy] > 0) && (grilla[ix][yp+iy] < MAX_SPR) ) + { + if ( sprite[grilla[ix][yp+iy]-1] != NULL ) + { + if (vgrilla) + stretch_sprite(buffer, sprite[grilla[ix][yp+iy]-1], ix*W_GR, iy*H_GR, W_GR, H_GR); + else + draw_sprite(buffer, sprite[grilla[ix][yp+iy]-1], + (W_GR / 2) - (sprite[grilla[ix][yp+iy]-1]->w / 2) + (ix*W_GR), + (H_GR / 2) - (sprite[grilla[ix][yp+iy]-1]->h / 2) + (iy*H_GR)); + } + } + + // valor numerico + textprintf(buffer, font, + (ix*W_GR)+(W_GR/2), (iy*H_GR)+(H_GR/2), makecol(255,255,255), + "%d", (int)grilla[ix][yp+iy]); + } + } + } + } + + +/* panel de informacion */ +text_mode(-1); // texto (-1=trans, 1 solido) +textprintf(buffer, font, 600,0,makecol(255,255,255), + "x:%d", xp); + +textprintf(buffer, font, 600,20,makecol(255,255,255), + "y:%d", yp); + +textprintf(buffer, font, 600,40,makecol(255,255,255), + "v:%d", vp); + +if ((vp > 0) && (vp < MAX_SPR)) + if (sprite[vp-1] != NULL) + stretch_sprite(buffer, sprite[vp-1], 600, (text_height(font)*2)+40, 40, 40); + +/* mandar a pantalla */ +scare_mouse(); +blit(buffer, screen, 0,0, 0,0,SCREEN_W, SCREEN_H); +unscare_mouse(); +} + + +void editar_mapa() { + int k; + char salvar[1024]; /* archivo a salvar */; + salvar[0] = '\0'; + + redibujar(); + + + while (1) { + k = readkey() >> 8; + + if (k == KEY_UP) yp--; + if (k == KEY_DOWN) yp++; + if (k == KEY_LEFT) xp--; + if (k == KEY_RIGHT) xp++; + if (k == KEY_SPACE) grilla[xp][yp] = vp; + if (k == KEY_DEL) grilla[xp][yp] = 0; + if (k == KEY_PLUS_PAD) vp++; + if (k == KEY_MINUS_PAD) vp--; + if (k == KEY_0) vp = 0; + if (k == KEY_1) vp += 10; + if (k == KEY_2) vp -= 10; + + if (k == KEY_V) vgrilla = !vgrilla; + + if (k == KEY_R) { + // agregar 1 enemigo al azar... :P + // en una casilla vacia solamente + int xd, yd; + xd = rand()% (W_FONDO / W_GR); + yd = rand()% (H_FONDO / H_GR); + if (grilla[xd][yd] == 0) + { + grilla[xd][yd] = vp; + yp = yd; xp = xd; // feedback al user + } + + } + + if (k == KEY_ESC) { + if ( alert("Salir de la edicion.", "Esta seguro", "Se perderan los datos no salvados", "Si", "No", 'S', 'N') == 1) return; + } + + if (k == KEY_C) { + if ( alert("Limpiar grilla.", "Esta seguro", NULL, "Si", "No", 'S', 'N') == 1) + { limpiar_grilla(); alert("La grilla se reinicio a ceros (0)", NULL, NULL, "OK", NULL, 0, 0); } + } + + if (k == KEY_S) { + if (file_select_ex("Archivo de grilla a salvar?", salvar, NULL, 512, 0, 0)) + { + PACKFILE *fp; + int xx, yy; + if ((fp = pack_fopen(salvar, F_WRITE)) != NULL) { + + // escribo la grilla en formato Intel de 32 bits + for (xx =0; xx < W_FONDO / W_GR; xx++) + for (yy =0; yy < H_FONDO / H_GR; yy++) + pack_iputl(grilla[xx][yy], fp); + + pack_fclose(fp); + + alert("Archivo salvado.", salvar, NULL, "OK", NULL, 0, 0); + } else + { + alert("Fallo la apertura del archivo!", salvar, NULL, "OK", NULL, 0, 0); + } + }; + } + + if (k == KEY_L) + { + if (file_select_ex("Archivo a cargar?", salvar, NULL, 512, 0, 0)) + { + PACKFILE *fp; + int xx, yy; + if ((fp = pack_fopen(salvar, F_READ)) != NULL) { + + // leo la grilla en formato Intel de 32 bits + for (xx =0; xx < W_FONDO / W_GR; xx++) + for (yy =0; yy < H_FONDO / H_GR; yy++) + grilla[xx][yy] = pack_igetl(fp); + + pack_fclose(fp); + + alert("Archivo cargado.", salvar, NULL, "OK", NULL, 0, 0); + } + else + { + alert("Fallo la apertura del archivo!", salvar, NULL, "OK", NULL, 0, 0); + } + }; + } + + if (yp < 0) yp =0; + if (yp > (H_FONDO / H_GR)-1) yp = (H_FONDO / H_GR)-1; + + if (xp < 0) xp =0; + if (xp > (W_FONDO / W_GR)-1) xp = (W_FONDO / W_GR)-1; + + redibujar(); + + } + +} + + + +int main() { + RGB_MAP tmp_rgb; /* acelera los calculos de makecol, etc */ + char leerbmp[1024]; /* fondo a cargar */ + + + int card = GFX_AUTODETECT, w = 640 ,h = 480 ,color_depth = 8; /* agregado por Kronoman */ + + allegro_init(); + install_timer(); + install_keyboard(); + install_mouse(); + + srand(time(0)); + + set_color_depth(color_depth); + if (set_gfx_mode(card, w, h, 0, 0)) { + allegro_message("set_gfx_mode(%d x %d x %d bpp): %s\n", w,h, color_depth, allegro_error); + return 1; + } + + leerbmp[0] = '\0'; + + if (!file_select_ex("Cargue el fondo por favor.", leerbmp, NULL, 512, 0, 0)) return 0; + + fnd = load_bitmap(leerbmp, pal); + if (fnd == NULL || fnd->w != W_FONDO || fnd->h != H_FONDO) { + allegro_message("No se pueden cargar o es invalido \n %s!\n", leerbmp); + return 1; + } + + set_palette(pal); + clear(screen); + + cargar_cache_sprites(); // cargar la cache de sprites... COOL! + + gui_fg_color = makecol(255,255,255); + gui_bg_color = makecol(0,0,0); + set_mouse_sprite(NULL); + + /* esto aumenta un monton los fps (por el makecol acelerado... ) */ + create_rgb_table(&tmp_rgb, pal, NULL); /* rgb_map es una global de Allegro! */ + rgb_map = &tmp_rgb; + + buffer=create_bitmap(SCREEN_W, SCREEN_H); + clear(buffer); + show_mouse(screen); + + + limpiar_grilla(); + /* Rock & Roll! */ + editar_mapa(); + +if (data != NULL) unload_datafile(data); +data = NULL; + +return 0; +} +END_OF_MAIN(); diff --git a/extras/mapedit/leeme.txt b/extras/mapedit/leeme.txt new file mode 100644 index 0000000..3d6e88e --- /dev/null +++ b/extras/mapedit/leeme.txt @@ -0,0 +1,4 @@ +Aqui esta el editor de las 'capas' de los mapas +Kronoman +En memoria de mi querido padre +Agosto 2002 diff --git a/extras/mapedit/makefile b/extras/mapedit/makefile new file mode 100644 index 0000000..e4e03cc --- /dev/null +++ b/extras/mapedit/makefile @@ -0,0 +1,3 @@ +all: mapedit.c eneedit.c + gcc mapedit.c -o mapedit.exe -lalleg -mwindows -O3 -Wall + gcc eneedit.c -o eneedit.exe -lalleg -mwindows -O3 -Wall \ No newline at end of file diff --git a/extras/mapedit/makegrid.c b/extras/mapedit/makegrid.c new file mode 100644 index 0000000..82fcb27 --- /dev/null +++ b/extras/mapedit/makegrid.c @@ -0,0 +1,55 @@ +/* +Este programa fabrica la grilla en un bmp + */ + +#include +#include +#include + +/* Tama¤o del fondo */ +#define W_FONDO 600 +#define H_FONDO 4000 + +/* Grilla WxH */ +#define W_GR 40 +#define H_GR 40 + + +int main() { + BITMAP *bmp; + PALETTE pal; + int iy, ix; + + int card = GFX_AUTODETECT, w = 640 ,h = 480 ,color_depth = 8; /* agregado por Kronoman */ + + allegro_init(); + install_timer(); + install_keyboard(); + install_mouse(); + + set_color_depth(color_depth); + if (set_gfx_mode(card, w, h, 0, 0)) { + allegro_message("set_gfx_mode(%d x %d x %d bpp): %s\n", w,h, color_depth, allegro_error); + return 1; + } + + set_palette(default_palette); + clear(screen); + + get_palette(pal); + bmp = create_bitmap(W_FONDO, H_FONDO); + clear(bmp); + + for (ix=0; ix < W_FONDO / W_GR; ix ++ ) + line(bmp, ix*W_GR, 0, ix*W_GR, H_FONDO, makecol(255,255,255)); + + for (iy=0; iy < H_FONDO / H_GR; iy ++ ) + line(bmp, 0, iy*H_GR, W_FONDO, iy*H_GR, makecol(255,255,255)); + + + save_bitmap("grilla.pcx", bmp, pal); + destroy_bitmap(bmp); + +return 0; +} +END_OF_MAIN(); diff --git a/extras/mapedit/mapedit.c b/extras/mapedit/mapedit.c new file mode 100644 index 0000000..f9391c7 --- /dev/null +++ b/extras/mapedit/mapedit.c @@ -0,0 +1,254 @@ +/* + Editor de la matriz de mapa para Kraptor + Kronoman 2002 + En memoria de mi querido padre + Teclas: + DELETE = casilla a 0 + BARRA = situar valor seleccionado + FLECHAS = mover cursor + + y - del keypad: alterar valor en +1 + 1 y 2 : alterar valor en +10 + 0 : valor a 0 + C : limpiar grilla a ceros + S : salvar grilla + L : cargar grilla + V : ver fondo sin grilla + ESC : salir + + NOTA: los mapas se guardan con las funciones especiales de Allegro + para salvar los integers en un formato standard, de esa manera, + me ahorro los problemas con diferentes tama~os de enteros segun + la plataforma. + + */ + +#include +#include +#include + +/* Tama¤o del fondo */ +#define W_FONDO 600 +#define H_FONDO 4000 + +/* Grilla WxH */ +#define W_GR 40 +#define H_GR 40 + +/* Grilla */ +long grilla[W_FONDO / W_GR][H_FONDO / H_GR]; + +/* En vgrilla pasar -1 para dibujarla, o 0 para ver el bitmap suelto */ +int vgrilla = -1; + + +int xp = 0, yp = 0, vp = 30; /* x,y, valor a colocar */ + +/* Bitmap cargado en RAM del fondo */ +BITMAP *fnd; +PALETTE pal; /* paleta */ + +/* Buffer de dibujo */ +BITMAP *buffer; + +void limpiar_grilla() { + int xx, yy; + /* limpio la grilla a ceros */ + for (xx =0; xx < W_FONDO / W_GR; xx++) + for (yy =0; yy < H_FONDO / H_GR; yy++) + grilla[xx][yy] = 0; +} + +void redibujar() { + int iy, ix; + + clear(buffer); + blit(fnd, buffer, 0, yp * H_GR,0,0,600,480); + + /* grilla */ + if (vgrilla) + { + for (ix=0; ix < W_FONDO / W_GR; ix ++ ) + line(buffer, ix*W_GR, 0, ix*W_GR, 480, makecol(255,255,255)); + + for (iy=0; iy < H_FONDO / H_GR; iy ++ ) + line(buffer, 0, iy*H_GR, fnd->w, iy*H_GR, makecol(255,255,255)); + + + /* cursor */ + line(buffer, xp * W_GR, 0, (xp * W_GR) + W_GR, H_GR, makecol(255, 255, 255)); + line(buffer, xp * W_GR, H_GR, (xp * W_GR) + W_GR, 0, makecol(255, 255, 255)); + + /* mostrar los valores que contiene la matriz */ + text_mode(makecol(0,0,0)); + for (ix=0; ix < W_FONDO / W_GR; ix ++ ) + for (iy=0; iy < H_FONDO / H_GR; iy ++ ) + if (yp + iy < H_FONDO / H_GR ) + if (grilla[ix][yp+iy] != 0) + textprintf(buffer, font, + (ix*W_GR)+(W_GR/2), (iy*H_GR)+(H_GR/2), makecol(255,255,255), + "%d", (int)grilla[ix][yp+iy]); + } +/* Informacion */ +text_mode(-1); // texto (-1=trans, 1 solido) +textprintf(buffer, font, 600,0,makecol(255,255,255), + "x:%d", xp); + +textprintf(buffer, font, 600,20,makecol(255,255,255), + "y:%d", yp); + +textprintf(buffer, font, 600,40,makecol(255,255,255), + "v:%d", vp); + +/* mandar a pantalla */ +scare_mouse(); +blit(buffer, screen, 0,0, 0,0,SCREEN_W, SCREEN_H); +unscare_mouse(); +} + + +void editar_mapa() { + int k; + char salvar[1024]; /* archivo a salvar */; + salvar[0] = '\0'; + + redibujar(); + + + while (1) { + k = readkey() >> 8; + + if (k == KEY_UP) yp--; + if (k == KEY_DOWN) yp++; + if (k == KEY_LEFT) xp--; + if (k == KEY_RIGHT) xp++; + if (k == KEY_SPACE) grilla[xp][yp] = vp; + if (k == KEY_DEL) grilla[xp][yp] = 0; + if (k == KEY_PLUS_PAD) vp++; + if (k == KEY_MINUS_PAD) vp--; + if (k == KEY_0) vp = 0; + if (k == KEY_1) vp += 10; + if (k == KEY_2) vp -= 10; + + if (k == KEY_V) vgrilla = !vgrilla; + + if (k == KEY_ESC) { + if ( alert("Salir de la edicion.", "Esta seguro", "Se perderan los datos no salvados", "Si", "No", 'S', 'N') == 1) return; + } + + if (k == KEY_C) { + if ( alert("Limpiar grilla.", "Esta seguro", NULL, "Si", "No", 'S', 'N') == 1) + { limpiar_grilla(); alert("La grilla se reinicio a ceros (0)", NULL, NULL, "OK", NULL, 0, 0); } + } + + if (k == KEY_S) { + if (file_select_ex("Archivo de grilla a salvar?", salvar, NULL, 512, 0, 0)) + { + PACKFILE *fp; + int xx, yy; + if ((fp = pack_fopen(salvar, F_WRITE)) != NULL) { + + // escribo la grilla en formato Intel de 32 bits + for (xx =0; xx < W_FONDO / W_GR; xx++) + for (yy =0; yy < H_FONDO / H_GR; yy++) + pack_iputl(grilla[xx][yy], fp); + + pack_fclose(fp); + + alert("Archivo salvado.", salvar, NULL, "OK", NULL, 0, 0); + } else + { + alert("Fallo la apertura del archivo!", salvar, NULL, "OK", NULL, 0, 0); + } + }; + } + + if (k == KEY_L) + { + if (file_select_ex("Archivo a cargar?", salvar, NULL, 512, 0, 0)) + { + PACKFILE *fp; + int xx, yy; + if ((fp = pack_fopen(salvar, F_READ)) != NULL) { + // leo la grilla en formato Intel de 32 bits + for (xx =0; xx < W_FONDO / W_GR; xx++) + for (yy =0; yy < H_FONDO / H_GR; yy++) + grilla[xx][yy] = pack_igetl(fp); + + pack_fclose(fp); + + alert("Archivo cargado.", salvar, NULL, "OK", NULL, 0, 0); + } + else + { + alert("Fallo la apertura del archivo!", salvar, NULL, "OK", NULL, 0, 0); + } + }; + } + + if (yp < 0) yp =0; + if (yp > (H_FONDO / H_GR)-1) yp = (H_FONDO / H_GR)-1; + + if (xp < 0) xp =0; + if (xp > (W_FONDO / W_GR)-1) xp = (W_FONDO / W_GR)-1; + + redibujar(); + + } + +} + + + +int main() { + RGB_MAP tmp_rgb; /* acelera los calculos de makecol, etc */ + char leerbmp[1024]; /* fondo a cargar */ + + + int card = GFX_AUTODETECT, w = 640 ,h = 480 ,color_depth = 8; /* agregado por Kronoman */ + + allegro_init(); + install_timer(); + install_keyboard(); + install_mouse(); + + srand(time(0)); + + set_color_depth(color_depth); + if (set_gfx_mode(card, w, h, 0, 0)) { + allegro_message("set_gfx_mode(%d x %d x %d bpp): %s\n", w,h, color_depth, allegro_error); + return 1; + } + + leerbmp[0] = '\0'; + + if (!file_select_ex("Cargue el fondo por favor.", leerbmp, NULL, 512, 0, 0)) return 0; + + fnd = load_bitmap(leerbmp, pal); + if (fnd == NULL || fnd->w != W_FONDO || fnd->h != H_FONDO) { + allegro_message("No se pueden cargar o es invalido \n %s!\n", leerbmp); + return 1; + } + + set_palette(pal); + clear(screen); + +gui_fg_color = makecol(255,255,255); +gui_bg_color = makecol(0,0,0); +set_mouse_sprite(NULL); + + /* esto aumenta un monton los fps (por el makecol acelerado... ) */ + create_rgb_table(&tmp_rgb, pal, NULL); /* rgb_map es una global de Allegro! */ + rgb_map = &tmp_rgb; + + buffer=create_bitmap(SCREEN_W, SCREEN_H); + clear(buffer); + show_mouse(screen); + + + limpiar_grilla(); + /* Rock & Roll! */ + editar_mapa(); + +return 0; +} +END_OF_MAIN(); diff --git a/extras/shader/leeme.txt b/extras/shader/leeme.txt new file mode 100644 index 0000000..f85ac52 --- /dev/null +++ b/extras/shader/leeme.txt @@ -0,0 +1,6 @@ +Shader + + +Programa utilitario de ayuda para generar las sombras +de los edificios de los mapas de Kraptor. + diff --git a/extras/shader/makefile b/extras/shader/makefile new file mode 100644 index 0000000..f4374ed --- /dev/null +++ b/extras/shader/makefile @@ -0,0 +1,4 @@ +all: shader.exe + +shader.exe: shader.c + gcc shader.c -o shader.exe -lalleg -mwindows -O3 -Wall \ No newline at end of file diff --git a/extras/shader/shader.c b/extras/shader/shader.c new file mode 100644 index 0000000..623800a --- /dev/null +++ b/extras/shader/shader.c @@ -0,0 +1,385 @@ +/* + shader.c + Sombreador automatico para los mapas de Kraptor + Copyright (c) 2002, Kronoman + NOTA: el codigo es una porqueria, repetitivo, no optimizado, etc + lo escribi en 15" para resolver un problema especifico + + Teclado: + Arr, Abj = scroll del mapa + V = ver grilla + info, si/no + Q,W = color de la sombra + O,P = grosor de la sombra + T = ajustar a grilla on/off + ESC = salir + S = salvar bmp + L = cargar bmp + Mouse: + click izquierdo: los 2 primeros setean el rectangulo de sombreado + el 3 click sombrea (confirma primero) + + click derecho: limpia el rectangulo de seleccion +*/ + +#include +#include +#include + +/* Grilla WxH */ +#define W_GR 40 +#define H_GR 40 + +/* ancho de la sombra */ +int w_sombra = 10; +// oscuridad de sombra (0 = negro, 255 = blanco) +int c_sombra = 16; + +// scroll del mapa +int yp = 0; + +// area del rectangulo a sombrear +// -1 indica area no seleccionada +int xr1 = -1; +int yr1 = -1; +int xr2 = -1; +int yr2 = -1; + + +/* En vgrilla pasar -1 para dibujarla, o 0 para ver el bitmap suelto */ +int vgrilla = -1; + +/* ajustar a grilla? */ +int snapgrid = -1; + +/* Bitmap cargado en RAM del fondo */ +BITMAP *fnd; +PALETTE pal; /* paleta */ +RGB_MAP tmp_rgb; /* acelera los calculos de makecol, etc */ +COLOR_MAP trans_table; /* mapa de transparencia */ + +/* Doble buffer */ +BITMAP *buffer; + + +void redibujar() { + int iy, ix; + + clear(buffer); + blit(fnd, buffer, 0, yp,0,0,fnd->w,SCREEN_H); + + /* grilla */ + if (vgrilla) + { + for (ix=0; ix < fnd->w / W_GR; ix ++ ) + line(buffer, ix*W_GR, 0, ix*W_GR, 480, makecol(255,255,255)); + + for (iy=0; iy < fnd->h / H_GR; iy ++ ) + line(buffer, 0, iy*H_GR, fnd->w, iy*H_GR, makecol(255,255,255)); + + /* Informacion */ + text_mode(-1); // texto (-1=trans, 1 solido) + + textprintf(buffer, font, 600,0,makecol(255,255,255), + "%d", yp); + + if (xr1 >= 0 ) + { + textprintf(buffer, font, 600,20,makecol(255,255,255), + "x1:%d",xr1); + textprintf(buffer, font, 600,40,makecol(255,255,255), + "y1:%d",yr1); + } + + if (xr2 >= 0) + { + textprintf(buffer, font, 600,60,makecol(255,255,255), + "x2:%d",xr2); + textprintf(buffer, font, 600,80,makecol(255,255,255), + "y2:%d",yr2); + } + + textprintf(buffer, font, 600,100,makecol(255,255,255), + "g[%s]", (snapgrid) ? "*" : " " ); + + textprintf(buffer, font, 600,120,makecol(255,255,255), + "w:%d", w_sombra); + + textprintf(buffer, font, 600,140,makecol(255,255,255), + "c:%d", c_sombra); + } + + /* rectangulo de seleccion */ + if (xr1 >= 0 ) + { + if (xr2 >= 0) + { + rect(buffer, xr1, yr1-yp, xr2, yr2-yp, makecol(0,255,255) ); + line(buffer, xr1, yr1-yp, xr2, yr2-yp, makecol(0,255,255) ); + line(buffer, xr2, yr1-yp, xr1, yr2-yp, makecol(0,255,255) ); + + // preview de como queda la sombra + line(buffer, xr1, yr2-yp, xr1-w_sombra, yr2-yp+w_sombra, makecol(0,255,255) ); + line(buffer, xr1, yr1-yp, xr1-w_sombra, yr1-yp+w_sombra, makecol(0,255,255) ); + line(buffer, xr2, yr2-yp, xr2-w_sombra, yr2-yp+w_sombra, makecol(0,255,255) ); + + line(buffer, xr1-w_sombra, yr1-yp+w_sombra, xr1-w_sombra, yr2-yp+w_sombra,makecol(0,255,255) ); + line(buffer, xr1-w_sombra, yr2-yp+w_sombra, xr2-w_sombra, yr2-yp+w_sombra, makecol(0,255,255) ); + + circle(buffer, xr1, yr1-yp, 5, makecol(255,0,255)); + circle(buffer, xr2, yr2-yp, 5, makecol(255,255,0)); + } + else + { + line(buffer, xr1, yr1-yp-5, xr1, yr1-yp+5, makecol(0,255,255) ); + line(buffer, xr1-5, yr1-yp, xr1+5, yr1-yp, makecol(0,255,255) ); + circle(buffer, xr1, yr1-yp, 5, makecol(255,0,255)); + } + } + + +/* mandar a pantalla */ +scare_mouse(); + blit(buffer, screen, 0,0, 0,0,SCREEN_W, SCREEN_H); +unscare_mouse(); +} + + +void editar_mapa() { + int k; + char salvar[1024]; /* archivo a salvar */; + salvar[0] = '\0'; + + static void reset_vars() + { + yp = 0; + xr1 = -1; + yr1 = -1; + xr2 = -1; + yr2 = -1; + } + + reset_vars(); + redibujar(); + + while (1) { + + while (!keypressed() && mouse_b == 0); + + if (mouse_b == 0) + k = readkey() >> 8; + else + k = 0; + + // Selecciono boton? + if (mouse_b & 1) // boton normal, seleccionar + { + int s; // lo uso mas abajo... + + if (xr1 < 0) // asignar primer esquina + { + if (snapgrid) + { + xr1 = (mouse_x / W_GR) * W_GR; + yr1 = ((mouse_y + yp) / H_GR) * H_GR; + } + else + { + xr1 = mouse_x; + yr1 = mouse_y + yp; + } + } + else + { + if (xr2 < 0) // asignar 2nda esquina + { + if (snapgrid) + { + xr2 = (mouse_x / W_GR) * W_GR; + yr2 = ((mouse_y + yp) / H_GR) * H_GR; + } + else + { + xr2 = mouse_x; + yr2 = mouse_y + yp; + } + } + else // Sombrear + { + if ( alert("Sombrear seleccion", "Esta seguro?", "No hay UNDO!", "Si", "No", 'S', 'N') == 1) + { + int c; + + drawing_mode(DRAW_MODE_TRANS, NULL, 0,0); + c = makecol(c_sombra,c_sombra,c_sombra); + for (s = 0; s < w_sombra; s++) + { + line(fnd, xr1-s, yr1+s, xr1-s, yr2+s, c); + line(fnd, xr1-s+1, yr2+s, xr2-s, yr2+s, c); + } + solid_mode(); + } + } + } + + while (mouse_b); + + if (xr1 > xr2 && xr2 > -1) + { + s = xr2; + xr2 = xr1; + xr1 = s; + } + + if (yr1 > yr2 && yr2 > -1) + { + s = yr2; + yr2 = yr1; + yr1 = s; + } + } + + if (mouse_b & 2) // boton derecho, de-seleccionar + { + xr1 = -1; + yr1 = -1; + xr2 = -1; + yr2 = -1; + + while (mouse_b); + } + + // Teclado... + if (k == KEY_UP) yp -= 40; + if (k == KEY_DOWN) yp += 40; + + if (k == KEY_V) vgrilla = !vgrilla; + + if (k == KEY_Q) c_sombra++; + if (k == KEY_W) c_sombra--; + + if (k == KEY_O) w_sombra++; + if (k == KEY_P) w_sombra--; + + w_sombra %= 256; //ajustar a rango 0..255 + if (w_sombra < 0) w_sombra = 255; + c_sombra %= 256; //ajustar a rango 0..255 + if (c_sombra < 0) c_sombra = 255; + + if (k == KEY_T) snapgrid = !snapgrid; + + if (k == KEY_ESC) { + if ( alert("Salir de la edicion.", "Esta seguro", "Se perderan los datos no salvados", "Si", "No", 'S', 'N') == 1) return; + } + + if (k == KEY_S) { + if (file_select_ex("Archivo a salvar?", salvar, NULL, 512, 0, 0)) + { + if (!save_bitmap(salvar, fnd, pal)) { // DEBUG:falta hacer + alert("Archivo salvado.", salvar, NULL, "OK", NULL, 0, 0); + } else + { + alert("Fallo la apertura del archivo!", salvar, NULL, "OK", NULL, 0, 0); + } + }; + } + + if (k == KEY_L) { + if (file_select_ex("Cargue la imagen por favor.", salvar, NULL, 512, 0, 0)) + { + BITMAP *tmp; + tmp = load_bitmap(salvar, pal); + if (tmp != NULL) + { + destroy_bitmap(fnd); + fnd = tmp; + set_palette(pal); + clear(screen); +gui_fg_color = makecol(255,255,255); +gui_bg_color = makecol(0,0,0); +set_mouse_sprite(NULL); + + /* esto aumenta un monton los fps (por el makecol acelerado... ) */ + create_rgb_table(&tmp_rgb, pal, NULL); /* rgb_map es una global de Allegro! */ + rgb_map = &tmp_rgb; + + create_trans_table(&trans_table, pal, 128, 128, 128, NULL); // transparencias + color_map = &trans_table; + + alert("Archivo cargado.", salvar, NULL, "OK", NULL, 0, 0); + } + else + { + alert("Fallo la apertura del archivo!", salvar, NULL, "OK", NULL, 0, 0); + } + } + } + + if (yp < 0) yp =0; + if (yp > fnd->h - SCREEN_H) yp = fnd->h - SCREEN_H; + + redibujar(); + + } + +} + + + +int main() { + char leerbmp[1024]; /* fondo a cargar */ + + int card = GFX_AUTODETECT, w = 640 ,h = 480 ,color_depth = 8; + + allegro_init(); + install_timer(); + install_keyboard(); + install_mouse(); + + srand(time(0)); + + set_gfx_mode(GFX_SAFE, 0,0,0,0); + + gfx_mode_select_ex(&card, &w, &h, &color_depth); + + set_color_depth(color_depth); + if (set_gfx_mode(card, w, h, 0, 0)) { + allegro_message("set_gfx_mode(%d x %d x %d bpp): %s\n", w,h, color_depth, allegro_error); + return 1; + } + + + set_trans_blender(128, 128, 128, 128); + + leerbmp[0] = '\0'; + + if (!file_select_ex("Cargue la imagen por favor.", leerbmp, NULL, 512, 0, 0)) return 0; + + fnd = load_bitmap(leerbmp, pal); + if (fnd == NULL) { + allegro_message("No se pueden cargar o es invalido \n %s!\n", leerbmp); + return 1; + } + + set_palette(pal); + clear(screen); +gui_fg_color = makecol(255,255,255); +gui_bg_color = makecol(0,0,0); +set_mouse_sprite(NULL); + + /* esto aumenta un monton los fps (por el makecol acelerado... ) */ + create_rgb_table(&tmp_rgb, pal, NULL); /* rgb_map es una global de Allegro! */ + rgb_map = &tmp_rgb; + + create_trans_table(&trans_table, pal, 128, 128, 128, NULL); // transparencias + color_map = &trans_table; + + buffer=create_bitmap(SCREEN_W, SCREEN_H); + clear(buffer); + show_mouse(screen); + + /* Rock & Roll! */ + editar_mapa(); + +return 0; +} +END_OF_MAIN(); diff --git a/fix.bat b/fix.bat new file mode 100644 index 0000000..7bfe8d8 --- /dev/null +++ b/fix.bat @@ -0,0 +1,97 @@ +@echo off + +rem Sets makefile source code for the different platforms +rem Based on fix.bat of Allegro. +rem Modified By Kronoman - In loving memory of my father. + + +echo Kraptor Engine +echo -------------- +echo. +echo By Kronoman - In loving memory of my father +echo. +echo. + +if [%1] == [linux] goto linux +if [%1] == [djgpp] goto djgpp +if [%1] == [mingw32] goto mingw32 +if [%1] == [test] goto test +goto help + + +:test +REM REMEMBER TO ALTER THIS TEST TO SUIT YOUR NEEDS!!! + +REM You first need to configure the platform +if exist target.os goto targetok + echo Before test, you first must configure your platform. +goto help + +:targetok + +echo Testing, please wait... +make test + +if not errorlevel 0 goto testfail +if not exist test.run goto testfail + + echo. + echo * SUCESS * + echo Congratulations, the test compiled! + echo. + +goto testdone + +:testfail + echo. + echo * ERROR * + echo. + echo The compilation returned a error! + echo Check that: + echo (*) You have all compiler tools installed (gcc,make,etc) + echo (*) You have Allegro library properly installed (http://alleg.sf.net/) + echo (*) You have DUMB Music library properly installed (http://dumb.sf.net/) + echo. + +:testdone + echo Cleaning the test... + make cleantest + +goto done + +:djgpp +echo Configuring for DOS/djgpp... +echo # Warning! This file will be overwritten by configuration routines! > target.os +echo TARGET=DJGPP>> target.os +goto done + + +:mingw32 +echo Configuring for Windows/Mingw32... +echo # Warning! This file will be overwritten by configuration routines! > target.os +echo TARGET=MINGW32>> target.os +goto done + + +:linux +echo Configuring for Linux/GCC... +echo # Warning! This file will be overwritten by configuration routines! > target.os +echo TARGET=LINUX>> target.os +goto done + + +:help +echo Usage: fix platform +echo. +echo Where platform is one of: djgpp, mingw32 or linux. +echo. +echo NOTICE: +echo You can also call: fix test +echo to check if your system can compile this programs. +echo. +goto end + +:done +echo Done! + +:end \ No newline at end of file diff --git a/fix.sh b/fix.sh new file mode 100755 index 0000000..b0a56fb --- /dev/null +++ b/fix.sh @@ -0,0 +1,83 @@ +#!/bin/sh +# +# Sets makefile source code for the different platforms +# Based on fix.sh of Allegro. +# Modified By Kronoman - In loving memory of my father. + +echo "Kraptor Engine" +echo "--------------" +echo +echo "By Kronoman - In loving memory of my father" +echo +echo + + +# REMEMBER TO ALTER THIS TEST TO SUIT YOUR NEEDS!!! +proc_test() +{ + # You first need to configure the platform + if [ ! -e target.os ]; then + echo "Before test, you first must configure your platform." + proc_help; + else + echo Testing, please wait... + make test + + if [ $? -eq 0 -a -e test.run ]; then + echo + echo "* SUCESS *" + echo "Congratulations, the test compiled!" + echo + else + echo + echo "* ERROR *" + echo + echo "The compilation returned a error or can't be runned!" + echo "Check that:" + echo "(*) You have all compiler tools installed (gcc,make,etc)" + echo "(*) You have Allegro library properly installed (http://alleg.sf.net/)" + echo "(*) You have DUMB Music library properly installed (http://dumb.sf.net/)" + echo + fi + + echo "Cleaning the test..." + make cleantest + fi +} + +proc_help() +{ + echo "Usage: fix platform" + echo + echo "Where platform is one of: djgpp, mingw32 or linux. " + echo + echo "NOTICE:" + echo "You can also call: fix test" + echo "to check if your system can compile this programs." + echo + echo +} + +proc_fix() +{ + echo "Configuring for $1..." + + if [ "$2" != "none" ]; then + echo "# Warning! This file will be overwritten by configuration routines!" > target.os + echo "TARGET=$2" >> target.os + fi +} + + +# prepare for the given platform. + +case "$1" in + "djgpp" ) proc_fix "DOS (djgpp)" "DJGPP";; + "mingw32" ) proc_fix "Windows (Mingw32)" "MINGW32";; + "linux" ) proc_fix "Linux (GCC)" "LINUX";; + "test" ) proc_test;; + "help" ) proc_help;; + * ) proc_help;; +esac + +echo "Done!" diff --git a/include/azar.h b/include/azar.h new file mode 100644 index 0000000..fafc9e0 --- /dev/null +++ b/include/azar.h @@ -0,0 +1,20 @@ +// azar.h +// Macro para numeros al azar +// Elige un numero entre min y max +// Tomado de la internet + +#ifndef AZAR_H +#define AZAR_H + +#include + +/* +Esta funcion explota si min - max da 0, sorry, pero la cambie... +*/ +// #define rand_ex( min, max ) ( (rand() % (max - min)) + min ) + + +/* Prototipo */ +int rand_ex(int min, int max); + +#endif diff --git a/include/bomba.h b/include/bomba.h new file mode 100644 index 0000000..5d8b034 --- /dev/null +++ b/include/bomba.h @@ -0,0 +1,22 @@ +// -------------------------------------------------------- +// bomba.h +// -------------------------------------------------------- +// Copyright (c) Kronoman +// En memoria de mi querido padre +// -------------------------------------------------------- +// Este modulo contiene todo lo relacionado con las bombas +// del jugador... +// -------------------------------------------------------- +#ifndef BOMBA_H +#define BOMBA_H + +extern int bomba_esta_activa; +extern int bomba_detonacion; +extern SAMPLE *bomba_sonido; + +// Prototipos +void mover_bomba(); +void dibujar_bomba(); +void detonar_totalmente_el_piso(int y); + +#endif diff --git a/include/captura.h b/include/captura.h new file mode 100644 index 0000000..10839f1 --- /dev/null +++ b/include/captura.h @@ -0,0 +1,25 @@ +/* + -------------------------------------------------------- + captura.h + -------------------------------------------------------- + Copyright (c) Kronoman + En memoria de mi querido padre + -------------------------------------------------------- + Funcion para tomar una captura de pantalla + Automaticamente la salva en archivoxxx.pcx, etc + -------------------------------------------------------- +*/ +#ifndef CAPTURAR_H +#define CAPTURAR_H + +#include +#include "allegro.h" + +/* Esta funcion captura la pantalla, usando el prefijo para el archivo + Salva un PCX de 8 bits de color. +*/ +void capturar_la_pantalla(char *prefijo); + +#endif + + diff --git a/include/cinema.h b/include/cinema.h new file mode 100644 index 0000000..46ab6c0 --- /dev/null +++ b/include/cinema.h @@ -0,0 +1,61 @@ +/* + -------------------------------------------------------- + cinema.h + -------------------------------------------------------- + Copyright (c) Septiembre 2002, Kronoman + En memoria de mi querido padre + -------------------------------------------------------- + Engine de cinematicas mediante scripts y datafiles + -------------------------------------------------------- */ + +#ifndef CINEMA_H +#define CINEMA_H + + +/* Estructura que contiene la lista de funciones que puede + utilizar el script, + contiene el comando, y un puntero a la funcion... + el ultimo item debe contener NULL en todos los parametros */ +typedef struct CMD_SCRIPT_TYPE +{ + char *comando; /* comando que ejecuta el procedimiento */ + int (*proc)(); /* procedimiento que es llamado, devuelve -1 si pasa un error, -666 si se debe cancelar la cinematica */ + int min_params; /* cantidad minima de parametros que precisa */ +} CMD_SCRIPT_TYPE; + +/* Cantidad maxima de parametros que se pueden leer de un solo 'saque' */ +#define MAX_PARAMS 100 +/* Largo maximo de linea a interpretar */ +#define MAX_LINEA 2048 + +/* Prototipos */ +/* Funciones propias */ +void ejecutar_cinematica(char *file); +void ejecutar_script(const char *txt_script, const int size, DATAFILE *archivo); +int parsear_y_ejecutar_linea(); + +/* Prototipos de funciones de interpretacion */ +int cmd_cls(); +int cmd_rect(); +int cmd_rectfill(); +int cmd_line(); +int cmd_fade_out(); +int cmd_fade_out_color(); +int cmd_locate(); +int cmd_text_color(); +int cmd_text_back(); +int cmd_text_font(); +int cmd_echo(); +int cmd_echo_centre_x(); +int cmd_echo_centre_xy(); +int cmd_rest(); +int cmd_set_palette(); +int cmd_set_palette_default(); +int cmd_blit(); +int cmd_sprite(); +int cmd_stretch_blit(); +int cmd_play_sample(); +int cmd_play_fli(); +int cmd_clear_fli_back(); +int cmd_keyboard_cancel_fli(); +#endif diff --git a/include/clima.h b/include/clima.h new file mode 100644 index 0000000..e7a9919 --- /dev/null +++ b/include/clima.h @@ -0,0 +1,31 @@ +// ------------------------------------ +// clima.h +// ------------------------------------ +// Modulo de efectos climaticos +// Por Kronoman +// En memoria de mi querido padre +// Copyright (c) 2002, Kronoman +// ------------------------------------ +#ifndef CLIMA_H +#define CLIMA_H + +#include + +// Estructura de particula de clima, para ser usada como una array +typedef struct CLIMA_P { + fixed x, y; /* posicion */ + fixed dx, dy; /* direccion */ + int col, r; /* color y radio */ + int t, d; // tipo y direccion de caida +} CLIMA_P; + +// Cantidad maxima de particulas climaticas +#define MAX_CLIMA_P 300 + + +// Prototipos +void init_clima(BITMAP *bmp, int c, int t, int d); +void mover_clima(BITMAP *bmp); +void dibuja_clima(BITMAP *bmp); + +#endif diff --git a/include/combo.h b/include/combo.h new file mode 100644 index 0000000..b2116fa --- /dev/null +++ b/include/combo.h @@ -0,0 +1,28 @@ +// -------------------------------------------------------- +// combo.c +// -------------------------------------------------------- +// Copyright (c) Kronoman +// En memoria de mi querido padre +// -------------------------------------------------------- +// Esto contiene combos para agregar explosiones+particulas +// y tocar los sonidos, musica, etc +// -------------------------------------------------------- +#ifndef COMBO_H +#define COMBO_H + +#include "explos.h" + +/* prototipos */ +void poner_explosion_nave(int x, int y, int c, int r, int bmpp); +void poner_muchas_particulas( int x, int y, + int dx, int dy, + int vida, + int col, int r, int t, + BITMAP *spr, + int cant ); + +void pone_explo_pixel(EXPLOSION **explo, + int x, int y, + int r, int v, + fixed v2); +#endif diff --git a/include/config.h b/include/config.h new file mode 100644 index 0000000..a1f0d56 --- /dev/null +++ b/include/config.h @@ -0,0 +1,6 @@ +#ifndef KRAPTOR_CONFIG_H +#define KRAPTOR_CONFIG_H +void cargar_configuracion(); +void salvar_configuracion(); + +#endif diff --git a/include/data.h b/include/data.h new file mode 100644 index 0000000..946d47b --- /dev/null +++ b/include/data.h @@ -0,0 +1,23 @@ +// -------------------------------------------------------- +// data.h +// -------------------------------------------------------- +// Copyright (c) Kronoman +// En memoria de mi querido padre +// -------------------------------------------------------- +// Esto se encarga de cargar y poner en memoria +// los datos leidos de disco. +// -------------------------------------------------------- +#ifndef DATA_H +#define DATA_H + + +/* Globales exportadas */ +extern DATAFILE *krapmain; +extern DATAFILE *datmapa; +extern DATAFILE *datmenu; + +/* Prototipos */ +void cargar_datos_principales(); +int cargar_nivel(int nivel, int solo_verificar); + +#endif diff --git a/include/datafind.h b/include/datafind.h new file mode 100644 index 0000000..4adc0fb --- /dev/null +++ b/include/datafind.h @@ -0,0 +1,21 @@ +// -------------------------------------------------------- +// datafind.h +// Funciones de busqueda avanzada de objetos dentro de un archivo DAT +// -------------------------------------------------------- +// Copyright (c) 2002, Kronoman +// Escrito por Kronoman - Republica Argentina +// En memoria de mi querido padre +// -------------------------------------------------------- +// Funcion para buscar un objeto en un datafile. +// Busca primero el verdadero, si no existe, busca por aproximacion!!! +// COOL! +// -------------------------------------------------------- + +#ifndef _KRONO_DATAFIND_H +#define _KRONO_DATAFIND_H + +DATAFILE *fuzzy_find_datafile_object(AL_CONST DATAFILE *dat, AL_CONST char *objectname); +DATAFILE *find_datafile_object_type(AL_CONST DATAFILE *dat, AL_CONST char *objectname, int type_required); +DATAFILE *fuzzy_find_datafile_object_type(AL_CONST DATAFILE *dat, AL_CONST char *objectname, int type_required); + +#endif diff --git a/include/enemigo.h b/include/enemigo.h new file mode 100644 index 0000000..c262616 --- /dev/null +++ b/include/enemigo.h @@ -0,0 +1,151 @@ +// -------------------------------------------------------- +// enemigo.h +// -------------------------------------------------------- +// Copyright (c) Kronoman +// En memoria de mi querido padre +// -------------------------------------------------------- +// Todo lo relacionado con los enemigos +// -------------------------------------------------------- +#ifndef ENEMIGO_H +#define ENEMIGO_H + +#include "allegro.h" +#include "ia.h" +#include "pmask.h" + +/* friccion X,Y */ +#define FRC_X_E 0.1 +#define FRC_Y_E 0.1 + +/* velocidad maxima X, Y */ +#define MAX_VEL_E_X 15 +#define MAX_VEL_E_Y 15 + +/* Cantidad maxima de tipos de enemigos/armas, con 100 es mas que suficiente */ +#define MAX_E_CLASS 100 + +/* Esta bandera indica cuando el enemigo esta muerto + DEBE ser un valor NEGATIVO, ej: -150 + Es para que agonize en llamas... :^P + Para los monstruos (boss) se multiplica x 2 <- DEBUG: NO IMPLEMENTADO! */ +#define ENE_MUERTO -200 + +/* Tipo de datos que contiene la definicion de armas de los enemigos */ +typedef struct ARMA_ENE { + BITMAP *spr; /* sprite que representa el disparo */ + struct PMASK *mask; /* mascara de choque */ + SAMPLE *snd[2]; /* 0 = sonido al dispararlo, 1 = sonido al impactar */ + + fixed vx, vy; /* velocidad x, y */ + int vida; /* duracion del disparo, si es < 1, el tipo de arma no existe */ + int punch; /* `golpe` del arma */ + + int t; /* tipo de disparo: + 0 = recto [sale del centro] + 1 = direccion al azar + 2 = abanico triple + 3 = doble recto + 4 = 1 direccionado hacia el jugador (sale hacia el jugador) + 5 = 5 tiros direccionados (apunta al jugador, solo en X) + 6 = cuadruple al azar + 7 = 20 a 30 al azar (ideal para boss) + 8 = 20 direccionados (ideal para boss) + 9 = 20 a 30 en todas direcciones (ideal para boss) + 10 = 5 a 30 en todas direcciones (ideal para boss) + 11 = 4 a 8 en todas direcciones (para un enemigo) + */ + + /* Esto es referente a la estela de particulas que + el arma puede dejar, o no. + Cada parametro tiene 2 indices, el valor minimo y maximo que puede tomar + respectivamente (para variacion al azar) + Cabe aclarar que la dx, dy es un numero decimal multiplicado por 100 (100 = 0.01) + Si vida[0] <= 0, no deja ninguna estela */ + int est_vida[2]; /* vida de la particula */ + int est_cant[2]; /* cantidad de particulas x frame */ + int est_color[3][2]; /* color, el primer indice indica RGB, y el 2ndo min-max */ + int est_dx[2]; /* aceleracion x inicial (100 = 0.01) */ + int est_dy[2]; /* aceleracion y inicial */ + int est_tipo[2]; /* tipo(s) de particula */ + int est_rad[2]; /* radio */ + int est_transp; /* transparencia */ +} ARMA_ENE; + +/* Tipo de datos que contiene los tipos de enemigos */ +typedef struct ENEM_T { + int vida; /* vida inicial, si es < 1, la clase de enemigo no existe */ + + int peso; /* esto indica el 'peso' del enemigo, o sea, cuanta energia + le quita al jugador en caso de colision */ + + BITMAP *spr[4]; // sprites 0..3 = frames de animacion + BITMAP *spr_shadow[4]; // sombra (autogenerada al cargar data) + int spr_delay; // delay de animacion en tics (30 = 1 segundo) + + PMASK *mask[4]; /* mascara de colision de cada sprite*/ + + int dinero; /* dinero que vale matar a este enemigo */ + + int premio_idx, premio_prob; /* indice de premio y probabilidad de darlo (%) */ + + // Referente a la IA del enemigo - DEBUG, nuevo! + int ia_azar; // la IA del enemigo debe comenzar al azar? (es decir, comienza por bytecode 0 o por cualquiera?) + IA_NODE *ia_node; // nodo con bytecodes de la IA a ejecutar para esta clase de enemigo + int ia_boss; // es un BOSS? -1 = si +} ENEM_T; + +/* Nodos que contienen los enemigos, en lista enlazada */ +typedef struct ENEMIGO { + fixed x, y; /* posicion */ + + int vida; /* vida que le queda */ + + int ene_t; /* tipo de enemigo (se fija en la matriz ENEM_T) */ + + int spr_delay; // contador para la animacion + int spr_actual; // sprite actual de animacion + + int arma_actual; // lo uso como referencia para disparar + + // Referente a la IA + int bytecode_actual; // bytecode en ejecucion (indice []) + int bytecode_loop; // contador para realizar los bytecodes con loop (parametro "loop") + IA_NODE *ia_node; // nodo de IA a ejecutar, se iguala a la clase de enemigo, es para evitar sintaxis complicadas... :) + IA_BYTECODE bytecode_exe; // copia del bytecode ejecutandose (para los loops) + + /* puntero al siguiente */ + struct ENEMIGO *next; +} ENEMIGO; + +/* Nodo de disparo del enemigo, en lista enlazada */ +typedef struct DISP_ENE { + fixed x, y; /* posicion */ + fixed dx, dy; /* direccion */ + int vida; /* vida que le queda */ + + int arma; /* indice de la matriz ARMA_ENE que indica el tipo de disparo, etc */ + + /* puntero al siguiente */ + struct DISP_ENE *next; +} DISP_ENE; + + +/* GLOBALES EXPORTADAS */ +extern ARMA_ENE arma_ene[MAX_E_CLASS]; +extern ENEM_T enem_t[MAX_E_CLASS]; +extern ENEMIGO *enemigo_1; +extern DISP_ENE *disp_ene_1; +extern int cant_enemigos_debug; + +/* Prototipos de funciones */ +void agregar_enemigo(int x, int y, int tipo ); +void IA_enemigo(ENEMIGO *ene); +void mover_enemigos(int fy); +void liberar_lista_enemigos(); +void dibujar_enemigos(BITMAP *bmp, int x, int y); + +void agregar_disparo_ene(ENEMIGO *ene); +void mover_disparos_ene(int fy); +void dibujar_disp_ene(BITMAP *bmp, int x, int y); +void liberar_lista_disparos_ene(); +#endif diff --git a/include/error.h b/include/error.h new file mode 100644 index 0000000..24c6d1f --- /dev/null +++ b/include/error.h @@ -0,0 +1,14 @@ +// -------------------------------------------------------- +// error.h +// -------------------------------------------------------- +// Copyright (c) Kronoman +// En memoria de mi querido padre +// -------------------------------------------------------- +// Mensajes de error en modo texto. +// -------------------------------------------------------- +#ifndef ERROR_H +#define ERROR_H + +void levantar_error(char *msg); + +#endif diff --git a/include/explos.h b/include/explos.h new file mode 100644 index 0000000..58570cc --- /dev/null +++ b/include/explos.h @@ -0,0 +1,56 @@ +/*------------------------------------------------------- + explos.h + -------------------------------------------------------- + Copyright (c) 2002, Kronoman + En memoria de mi querido padre + Agosto - 2002 + -------------------------------------------------------- + Engine de explosiones usando una lista enlazada + muy sencilla, sirve para muchas capas de explosiones + mediante el uso de punteros. + --------------------------------------------------------*/ + +#ifndef EXPLOS_H +#define EXPLOS_H + +#include "allegro.h" + + +/* estructura de datos */ +typedef struct EXPLOSION { + fixed x, y; /* posicion */ + fixed dx, dy; /* direccion */ + int vida; /* vida que le queda */ + fixed r, dr; /* radio y decremento de radio por ciclo */ + BITMAP *spr; /* sprite que lo representa */ + int rot; /* rotacion del bitmap */ + + /* puntero al siguiente */ + struct EXPLOSION *next; +} EXPLOSION; + + + +extern int cant_explosion_debug; /* Innecesaria, para testear performance solamente */ + +/* Cache de imagenes y sonidos, para el combo de explosion */ +extern BITMAP *explo_cache_bmp[3]; +extern SAMPLE *explo_cache_snd[3]; + +/* punteros */ +extern EXPLOSION *ptr_explo_fondo; +extern EXPLOSION *ptr_explo_arriba; + + +/* prototipos */ +void agrega_explosion( EXPLOSION **prt_1era, + fixed x, fixed y, + fixed dx, fixed dy, + int vida, + fixed r, fixed dr, + int rot, + BITMAP *spr ); +void mover_explosiones(EXPLOSION **prt_1era); +void dibujar_explosion(EXPLOSION *prt_1era, BITMAP *bmp, int x, int y); +void liberar_lista_explosion(EXPLOSION **prt_1era); +#endif diff --git a/include/filedata.h b/include/filedata.h new file mode 100644 index 0000000..ed9150f --- /dev/null +++ b/include/filedata.h @@ -0,0 +1,22 @@ +// -------------------------------------------------------- +// filedata.h +// -------------------------------------------------------- +// Copyright (c) Kronoman +// En memoria de mi querido padre +// -------------------------------------------------------- +// This file is used as a wrapper for load_datafile +// I use this for reach the datafile searching in common paths +// Is specially useful for datafiles in Windows, because most +// of the time Windows don't start the program in the executable path, +// and the program is unable to find the datafile. +// -------------------------------------------------------- +#ifndef FILEDATA_H +#define FILEDATA_H + +char *where_is_the_filename(char *buffer, const char *filename); + +DATAFILE *krono_load_datafile(const char *filename); +DATAFILE *krono_load_datafile_callback(const char *filename, void (*callback)(DATAFILE *d)); +DATAFILE *krono_load_datafile_object(const char *filename, const char *objectname); + +#endif diff --git a/include/game.h b/include/game.h new file mode 100644 index 0000000..d69d2b9 --- /dev/null +++ b/include/game.h @@ -0,0 +1,9 @@ +#ifndef GAME_H +#define GAME_H + +/* Prototipos */ + +void comenzar_juego(int); + + +#endif diff --git a/include/global.h b/include/global.h new file mode 100644 index 0000000..70ff401 --- /dev/null +++ b/include/global.h @@ -0,0 +1,50 @@ +/* -------------------------------------------------------- + global.h + Variables globales, y simbolo de debug + -------------------------------------------------------- */ +#ifndef GLOBAL_H +#define GLOBAL_H + +#include + +/* Info de un nivel */ +typedef struct NIVEL_T { + char titulo[80]; /* titulo nivel */ + char texto[300]; /* introduccion de texto al nivel */ + char cine_in[1024]; /* cinematica de comienzo nivel */ + char cine_out[1024]; /* cinematica de final nivel */ + char level_dat[1024]; /* DAT del nivel */ + int clima_c, clima_t, clima_d; // info de clima, cantidad, tipo, direccion + DUH *musica; /* musica del nivel */ +} NIVEL_T; + +/* Globales exportadas */ +extern char lenguaje[3]; // lenguaje a usar, ej : es = espa~ol +extern int nivel_detalle; +extern int detalle_automatico; +extern int nivel_actual; +extern int nivel_de_dificultad; +extern int cheat_god_mode; +extern NIVEL_T info_nivel; + +extern char game_over_cine[1024]; /* cinematica de game over */ +extern char game_intro_cine[1024]; /* cinematica de introduccion */ +extern int driver_de_sonido; +extern int quiere_snd; +extern int volumen_sonido; +extern int quiere_musica; +extern int quiere_videos; +extern int volumen_musica; +extern int salir_del_juego; +extern int paso_de_nivel; +extern PALETTE pal_game; +extern COLOR_MAP tabla_transparencia; +extern RGB_MAP tabla_RGB; +extern int KRONO_QUIERE_DEBUG; +extern FONT *font_backup; +extern FONT *hud_font; +extern int quiere_usar_joystick; +extern int numero_de_joystick; +extern int quiere_usar_mouse; +extern int mouse_velocidad; +#endif diff --git a/include/guiprocs.h b/include/guiprocs.h new file mode 100644 index 0000000..07dabfc --- /dev/null +++ b/include/guiprocs.h @@ -0,0 +1,69 @@ +/* guiprocs.c - Kraptor + Esto contiene dialogos tipo 3-D para el GUI de Allegro + Fueron tomados de Allegro Dialog Editor + y modificados para su uso en Kraptor +*/ + +/* ORIGINAL: + * Allegro DIALOG Editor + * by Julien Cugniere + * + * guiprocs.h : Some thin 3d-looking GUI procs + */ + +#ifndef GUIPROCS_H +#define GUIPROCS_H + +#include + +#define F_IN 1 +#define F_LIGHT 2 + +#ifdef __cplusplus + extern "C" { +#endif + +/* colors */ +extern int gui_text_color; +extern int gui_disabled_color; +extern int gui_white_color; +extern int gui_light_color; +extern int gui_back_color; +extern int gui_dark_color; +extern int gui_black_color; +void xset_gui_colors(void); + +/* helpers */ +void gui_rect(BITMAP *bmp, int x, int y, int w, int h, int flags); +void dotted_rect(BITMAP *bmp, int x1, int y1, int x2, int y2, int fg, int bg); + +/* menus */ +void xdraw_menu(int x, int y, int w, int h); +void xdraw_menu_item(MENU *m, int x, int y, int w, int h, int bar, int sel); + + +/* gui agregados por Kronoman: */ +int xslider_proc(int msg, DIALOG* d, int c); /* slider tipo X11 */ +int xbitmap_proc(int msg, DIALOG *d, int c); /* bitmap que se ajusta a w, h */ + +/* gui procs */ +int xtext_proc (int, DIALOG*, int); +int xctext_proc (int, DIALOG*, int); +int xrtext_proc (int, DIALOG*, int); +int xlist_proc (int, DIALOG*, int); +int xtext_list_proc(int, DIALOG*, int); +int xtextbox_proc (int, DIALOG*, int); +int xbox_proc (int, DIALOG*, int); +int xcolorbox_proc (int, DIALOG*, int); +int xcheck_proc (int, DIALOG*, int); +int xbutton_proc (int, DIALOG*, int); +int xedit_proc (int, DIALOG*, int); +int xpalette_proc (int, DIALOG*, int); + +void xset_gui_colors(void); + +#ifdef __cplusplus + } +#endif + +#endif /* GUIPROCS_H */ diff --git a/include/guitrans.h b/include/guitrans.h new file mode 100644 index 0000000..9301850 --- /dev/null +++ b/include/guitrans.h @@ -0,0 +1,19 @@ +/* +guitrans.h +Por Kronoman +Copyrigth (c) 2002, Kronoman +En memoria de mi querido padre + +Este modulo se encarga de traducir estructuras +de los GUI de Allegro al idioma actual. +*/ + +#ifndef GUITRANS_H +#define GUITRANS_H + +#include + +void traducir_DIALOG_dp(DIALOG *d); +void traducir_MENU_text(MENU *d); + +#endif diff --git a/include/humo.h b/include/humo.h new file mode 100644 index 0000000..c1836ea --- /dev/null +++ b/include/humo.h @@ -0,0 +1,55 @@ +/*------------------------------------------------------- + humo.h + -------------------------------------------------------- + Copyright (c) 2002, Kronoman + En memoria de mi querido padre + Enero - 2003 + -------------------------------------------------------- + Engine de humo (para edificios en llamas) + usando una lista enlazada muy sencilla + --------------------------------------------------------*/ + +#ifndef HUMO_H +#define HUMO_H + +#include + +extern BITMAP *humo_spr; + +/* estructura de datos que contiene el humo */ +typedef struct HUMO { + fixed x, y; /* posicion */ + fixed dx, dy; /* direccion */ + int vida; /* vida que le queda a la particula */ + int col; /* color */ + fixed r, ri; /* radio, incremental de tama~o de radio */ + + struct HUMO *next; +} HUMO; + +/* estructura de datos para _emisores_ de humo */ +typedef struct EMISOR_HUMO { + fixed x, y; /* posicion */ + int vida; // vida (se 'apaga' a medida que vida se aproxima a 0) + + struct EMISOR_HUMO *next; +} EMISOR_HUMO; + +/* prototipos */ + +// Emisores de humo + +EMISOR_HUMO *agrega_emisor_humo(fixed x, fixed y, int vida ); +void mover_emisor_humo(int x, int y, int w, int h); +void liberar_emisores_humo(); + +// Humo en si... +HUMO *agrega_humo( fixed x, fixed y, + fixed dx, fixed dy, + int vida, + int col, fixed r, fixed ri); + +void mover_humo(int x, int y, int w, int h); +void dibujar_humo(BITMAP *bmp, int x, int y); +void liberar_humo(); +#endif diff --git a/include/ia.h b/include/ia.h new file mode 100644 index 0000000..bdcf1ff --- /dev/null +++ b/include/ia.h @@ -0,0 +1,46 @@ +// -------------------------------------------------------- +// ia.h +// -------------------------------------------------------- +// Copyright (c) Kronoman +// En memoria de mi querido padre +// -------------------------------------------------------- +// Sistema de inteligencia artificial utizando "ejecutables" +// binarios contenidos en un DAT +// -------------------------------------------------------- + +#ifndef KRAPTOR_IA_H +#define KRAPTOR_IA_H + + +#include "allegro.h" + + +// Estructura contenedora de una instruccion +typedef struct IA_BYTECODE +{ + int x1, y1, x2, y2; // coordenadas de movimiento + int weapon; // arma a disparar + int loop; // cantidad de veces a repetir + +} IA_BYTECODE; + + +// Estructura de la lista enlazada contenedora +// de todos los "programas" de IA precargados +typedef struct IA_NODE +{ + IA_BYTECODE *code; // puntero a matriz asignada con malloc de todas las instrucciones de esta IA particular + int size; // cantidad de bytecodes contenidos en bytecode[] + char id[1024]; // identificacion usada para identificar esta secuencia en la IA (cadena ASCCIZ) + + struct IA_NODE *next; // puntero al siguiente +} IA_NODE; + + + +// Prototipos +void hacer_chache_ia(const char *file); +void liberar_lista_ia(); +IA_NODE *buscar_lista_ia(const char *id); + +#endif diff --git a/include/joymnu.h b/include/joymnu.h new file mode 100644 index 0000000..9739b01 --- /dev/null +++ b/include/joymnu.h @@ -0,0 +1,17 @@ +/* + -------------------------------------------------------- + joymnu.h + Calibracion del joystick + -------------------------------------------------------- +*/ +#ifndef JOYMNU_H +#define JOYMNU_H + + +void probar_el_joystick(int nj); +void dialog_joystick_calibrate(int nj); +void joystick_configuration_menu(); + + + +#endif diff --git a/include/jugador.h b/include/jugador.h new file mode 100644 index 0000000..02cfced --- /dev/null +++ b/include/jugador.h @@ -0,0 +1,172 @@ +// -------------------------------------------------------- +// jugador.h +// -------------------------------------------------------- +// Copyright (c) Kronoman +// En memoria de mi querido padre +// -------------------------------------------------------- +// Este modulo contiene todo lo relacionado con el jugador +// Tal como movimiento, disparos, etc... +// Exporta ademas unas globales utiles para verificar +// colisiones con disparos enemigos y enemigos en si. +// Tiene la estructura con las teclas de control del jugador +// -------------------------------------------------------- +#ifndef JUGADOR_H +#define JUGADOR_H + +#include +#include "pmask.h" + +/* Aceleracion X, Y del jugador */ +#define VEL_X_J 2.5 +#define VEL_Y_J 2.5 + +/* friccion X,Y jugador */ +#define FRC_X_J 0.02 +#define FRC_Y_J 0.02 + +/* velocidad maxima X, Y del jugador */ +#define MAX_VEL_J_X 10.0 +#define MAX_VEL_J_Y 10.0 + +/* Cantidad maxima de tipos de armas */ +#define MAX_ARM_CLASS 15 + +/* Cantidad maxima de energia del jugador */ +#define MAX_ENERGIA 200 + +/* Esta bandera indica cuando el jugador esta muerto + DEBE ser un valor NEGATIVO, ej: -300 + Es para que agonize en llamas... :^P */ +#define JUG_MUERTO -300 + +/* Tipo de datos que contiene la definicion de armas del jugador */ +typedef struct ARMA_JUG { + /* Referente al modo 'shopping' donde se compra el arma */ + + BITMAP *arma; /* dibujo del arma en el shop */ + char desc[2049]; /* descripcion del arma larga (texto ascii) */ + char desc_short[21]; /* descripcion corta para el HUD */ + int precio; /* precio del arma, si es <=0, indica que este tipo de arma NO existe */ + int cant_ammo; /* cantidad de balas x compra */ + int cant_ammo_max; /* cantidad maxima de balas */ + + /* Referente al disparo en si */ + + BITMAP *spr; /* sprite que representa el disparo */ + PMASK *mask; /* mascara de choque */ + SAMPLE *snd[2]; /* 0 = sonido al dispararlo, 1 = sonido al impactar */ + + fixed vx, vy; /* velocidad x, y */ + int vida; /* duracion del disparo */ + int punch; /* `golpe` del arma */ + int firerate; /* ratio de disparo, referido a lastshoot */ + + int t; /* tipo de disparo: esto se cambia reprogramando la seccion correspondiente en jugador.c + 0 = recto [sale del centro] + 1 = direccion al azar + 2 = abanico triple, vx especifica la apertura del abanico (default = 5) + 3 = doble recto [salen del centro (+/-) 50% del ancho nave] + 4 = 1 del centro, 1 al azar por disparo (very cool!) + 5 = 1 del centro, 1 de la izq, 1 de la derecha (tipo misile pod, incluye una variacion del 10% al azar en la velocidad en y, para efecto misile pod) + 6 = flak, 6 al azar (ca~on de flak!), y 2 rectos de las alas + */ + + /* Esto es referente a la estela de particulas que + el arma puede dejar, o no. + Cada parametro tiene 2 indices, el valor minimo y maximo que puede tomar + respectivamente (para variacion al azar) + Cabe aclarar que la dx, dy es un numero decimal multiplicado por 100 (100 = 0.01) + Si vida[0] <= 0, no deja ninguna estela */ + int est_vida[2]; /* vida de la particula */ + int est_cant[2]; /* cantidad de particulas x frame */ + int est_color[3][2]; /* color, el primer indice indica RGB, y el 2ndo min-max */ + int est_dx[2]; /* aceleracion x inicial */ + int est_dy[2]; /* aceleracion y inicial */ + int est_tipo[2]; /* tipo(s) de particula */ + int est_rad[2]; /* radio */ + int est_transp; /* transparencia */ +} ARMA_JUG; + +/* Tipo de datos que contiene el jugador */ +typedef struct JUGADOR { + fixed x, y; /* posicion */ + fixed dx, dy; /* direccion */ + + int vida; /* vida que le queda, energia */ + + int dinero; /* dinero (puntos) que tiene */ + + BITMAP *spr[6]; /* sprites que lo representan, 0 = izq, 1 = normal, 2 = der, + 3,4,5 son las sombras de los sprites + (se generan al cargar los datos) */ + + PMASK *mask; /* mascara de colision, para spr[1] */ + + int arma[MAX_ARM_CLASS]; /* armamentos que tiene (<= 0 no tiene el arma, > 0 posee el arma, cantidad de balas que tiene) */ + + int arma_actual; /* arma seleccionada */ + + int lastshoot; /* contador para temporizar intervalo entre disparos */ + + int bombas; /* cantidad de bombas que le quedan */ + + /* Reparacion de la nave, para el shopping */ + int reparar_cantidad; /* cantidad que repara cada unidad */ + int reparar_precio; /* precio por unidad */ + char reparar_desc[2048]; /* descripcion */ + BITMAP *reparar_bmp; /* bitmap de reparacion */ + + /* Bombas de la nave, para el shopping */ + int bomba_cantidad; + int bomba_precio; + char bomba_desc[2048]; + BITMAP *bomba_bmp; + int max_bombas; + + /* dinero y bombas iniciales */ + int init_money; + int init_bombas; + +} JUGADOR; + +/* Nodo de disparo del jugador, en lista enlazada */ +typedef struct DISP_JUG { + fixed x, y; /* posicion */ + fixed dx, dy; /* direccion */ + int vida; /* vida que le queda */ + + int arma; /* indice de la matriz ARMA_JUG que indica el tipo de disparo, etc */ + + /* puntero al siguiente */ + struct DISP_JUG *next; +} DISP_JUG; + +/* Teclas de juego, corresponden al tipo key[KEY_SPACE], etc */ +typedef struct TECLADO_JUG { + /* arriba, abajo, derecha, izquierda, disparar, cambiar arma, bomba especial */ + int arr, abj, der, izq, sht, wpn, bmb; +} TECLADO_JUG; + + +/* GLOBALES EXPORTADAS */ +extern ARMA_JUG arma_tipo[MAX_ARM_CLASS]; /* tipos de armas */ +extern JUGADOR jugador; /* jugador */ +extern DISP_JUG *disp_jug_1; /* puntero al 1er disparo del jugador */ +extern TECLADO_JUG teclado_jug; /* teclado del jugador */ + +/* Prototipos de funciones */ +void dibujar_tablero(BITMAP *bmp); +void set_teclado_default(); +void reset_total_jugador(); +void reset_parcial_jugador(); +void jugador_proxima_arma(); +void interpreta_teclado(); +void dibujar_nave_jugador(BITMAP *bmp, int x, int y); +void mover_jugador(int fy); + +void agregar_disparo_jug(); +void mover_disparos_jug(int fy); +void dibujar_disp_jug(BITMAP *bmp, int x, int y); +void liberar_lista_disparos_jug(); + +#endif diff --git a/include/kfbuffer.h b/include/kfbuffer.h new file mode 100644 index 0000000..3fa29f0 --- /dev/null +++ b/include/kfbuffer.h @@ -0,0 +1,34 @@ +/* + Todo el sistema trabaja renderizando en un bitmap + de un tama~o fijo, el cual luego se estira al tama~o de pantalla + Este archivo contiene el buffer, y los parametros de su tama~o + porque varias rutinas los necesitan, especialmente + la de descartar enemigos cuando salen por la parte inferior de pantalla + + -------------------------------------------------------- + Copyright (c) Kronoman + En memoria de mi querido padre + -------------------------------------------------------- + */ +#ifndef KFBUFFER_H +#define KFBUFFER_H + +#include + +/* ancho y alto de renderizado del area de juego */ +#define ANCHO_FB 600 +#define ALTO_FB 480 + +/* ancho y alto area del buffer total */ +#define ANCHO_RFB 640 +#define ALTO_RFB 480 + + +/* globales exportadas */ +extern BITMAP *kfbufferbmp; + +/* prototipos */ +void enviar_kfbuffer2screen(); +void interlazar_kfbuffer(int r, int g, int b); + +#endif diff --git a/include/krstring.h b/include/krstring.h new file mode 100644 index 0000000..dcaaa97 --- /dev/null +++ b/include/krstring.h @@ -0,0 +1,17 @@ +// -------------------------------------------------------- +// krstring.h +// -------------------------------------------------------- +// Copyright (c) 2002, Kronoman +// En memoria de mi querido padre +// -------------------------------------------------------- +// Funciones para strings ASCIIZ auxiliares +// -------------------------------------------------------- +// ASCIIZ string function +// -------------------------------------------------------- + +#ifndef KRSTRING_H +#define KRSTRING_H + +char *krtrim(char *dest, const char *orig); + +#endif diff --git a/include/main.h b/include/main.h new file mode 100644 index 0000000..443f880 --- /dev/null +++ b/include/main.h @@ -0,0 +1,16 @@ +// -------------------------------------------------------- +// Kraptor - Call of the freedom +// -------------------------------------------------------- +// main.h +// -------------------------------------------------------- +// Copyright (c) 2002, Kronoman +// En memoria de mi querido padre +// -------------------------------------------------------- + +#ifndef MAIN_H +#define MAIN_H + +// Version del engine +#define KRAPTOR_VERSION_STR "1.0.2" + +#endif diff --git a/include/mapa.h b/include/mapa.h new file mode 100644 index 0000000..4498394 --- /dev/null +++ b/include/mapa.h @@ -0,0 +1,39 @@ +// -------------------------------------------------------- +// mapa.h +// -------------------------------------------------------- +// Copyright (c) Kronoman +// En memoria de mi querido padre +// -------------------------------------------------------- +// Esto contiene todo lo referente al mapa en si +// -------------------------------------------------------- +#ifndef MAPA_H +#define MAPA_H + +/* Tama¤o del fondo en pixeles */ +#define W_FONDO 600 +#define H_FONDO 4000 + +/* Grilla WxH en pixels */ +#define W_GR 40 +#define H_GR 40 + +/* Cantidad de cuadritos de la grilla [ancho y alto] */ +#define GRILLA_W (W_FONDO / W_GR) +#define GRILLA_H (H_FONDO / H_GR) + +/* Globales exportadas */ +extern long mapa_g[GRILLA_W][GRILLA_H]; +extern long enem_g[GRILLA_W][GRILLA_H]; +extern int scroll_mapa; +extern int scroll_mapa_speed; +extern BITMAP *mapa_fondo; +extern COLOR_MAP tabla_quemado; +extern BITMAP *burn_cache_bmp[3]; + +/* Prototipos */ +void scan_nivel_1era_vez(); +void scan_nuevos_enemigos(int y); +void quemar_area(BITMAP *bmp, int xp, int yp, int rad1, int rad2); +int explotar_fondo(int x, int y, int punch); +void crear_mapa_quemazon(AL_CONST PALETTE pal, int x, int y, RGB *rgb); +#endif diff --git a/include/menu.h b/include/menu.h new file mode 100644 index 0000000..42e748e --- /dev/null +++ b/include/menu.h @@ -0,0 +1,46 @@ +/* + -------------------------------------------------------- + menu.h + -------------------------------------------------------- + Sistema de menu de Kraptor (al estilo de Unre*l) + -------------------------------------------------------- +*/ +#ifndef K_MENU_H +#define K_MENU_H + +#include + +/* Seleccion de menu */ +#define MNU_S_NEW_GAME 1 +#define MNU_S_LOAD_GAME 2 +#define MNU_S_QUIT_GAME 3 + +#define MNU_S_CFG_SND 4 +#define MNU_S_CFG_CTRL 5 +#define MNU_S_CFG_DETAIL 6 +#define MNU_S_CFG_VIDEO 7 + +#define MNU_S_CFG_SPANISH 8 +#define MNU_S_CFG_ENGLISH 9 + +#define MNU_S_VER_HLP 10 +#define MNU_S_VER_ABOUT 11 + +/* bitmap de fondo, y paleta de colores y musica */ +extern BITMAP *bmp_menu_main; +extern PALETTE pal_menu_main; + + +extern char *texto_ayuda_juego; /* puntero a la ayuda del juego */ +extern char *texto_acerca_de_juego; /* acerca de... */ +extern BITMAP *acerca_de_bmp; /* bitmap acerca de... */ + +/* Prototipos */ +void realizar_menu_principal(); /* entrada para el menu principal */ +int modificar_sonido_mnu(void); /* menu para volumen de sonido/musica */ +int mod_teclado_jugar(void); /* menu para modificar el teclado */ +int mod_detalle_mnu(void); /* menu para modificar los detalles */ +int menu_configuracion_al_vuelo(void); /* menu de sonido, teclado, detalle */ +int ayuda_proggy_mnu(); /* ayuda */ + +#endif diff --git a/include/partic.h b/include/partic.h new file mode 100644 index 0000000..4bcda36 --- /dev/null +++ b/include/partic.h @@ -0,0 +1,65 @@ +/*------------------------------------------------------- + partic.h + -------------------------------------------------------- + Copyright (c) 2002, Kronoman + En memoria de mi querido padre + Agosto - 2002 + -------------------------------------------------------- + Engine de particulas usando una lista enlazada + muy sencilla + --------------------------------------------------------*/ + +#ifndef PARTIC_H +#define PARTIC_H + +#include "allegro.h" + +/* NOTA: + el tipo de particula 't' puede ser: + 1 = circulo + 2 = cuadrado + 3 = linea + o si spr != NULL, dibuja el bitmap rotando al azar (como que salto un pedazo + */ + +/* estructura de datos que contiene la particula */ +typedef struct PARTICULA { + fixed x, y; /* posicion */ + fixed dx, dy; /* direccion */ + int vida; /* vida que le queda a la particula */ + fixed r, rg; /* radio y valor de crecimiento del radio 'rg' */ + int col, t; /* color y tipo de grafico que la representa */ + int transp; /* la particula es transparente? -1 = si, 0 = no [solo en alto detalle ] */ + BITMAP *spr; /* sprite que lo representa, o NULL si es una figura geometrica */ + fixed rot; /* rotacion del bitmap */ + + /* puntero a la particula siguiente */ + struct PARTICULA *next; +} PARTICULA; + + +/* prototipos */ + +PARTICULA *agrega_particula( fixed x, fixed y, + fixed dx, fixed dy, + int vida, + int col, int r, int t, + int transp, fixed rg, + BITMAP *spr ); + +void mover_particulas(int x, int y, int w, int h); + +void dibujar_particulas(BITMAP *bmp, int x, int y); + +void liberar_lista_particulas(); + + + +/* DEBUG - estas variables son especificas a Kraptor */ + +/* Cache de bmps representando particulas para 'reventar' naves */ +extern BITMAP *particula_cache_bmp[3]; + +extern int cant_particulas_debug; + +#endif diff --git a/include/pmask.h b/include/pmask.h new file mode 100644 index 0000000..7455a39 --- /dev/null +++ b/include/pmask.h @@ -0,0 +1,123 @@ +#ifndef pmask_H +#define pmask_H + +/* +This is the Pixel MASK library, which does pixel-perfect collisions using +bit masks. + +There are several configuration options here, hope they aren't too +confusing. +*/ + +#define PMASK_VERSION 1 + +#define USE_ALLEGRO +//#define USE_SDL + +#ifdef USE_ALLEGRO +struct BITMAP; +#endif +#ifdef USE_SDL +struct SDL_Surface; +#endif + +#ifdef __cplusplus +#define pmask_USE_INLINE +extern "C" { +#endif + +//This is the bounding box collision detection macro. +//It is a general purpose macro. Pass it the coordinates of one rectangle and the width and +//height of it, then pass the coordinates of a second rectangle and the width and height of +//it. It will return 0 if theres not collision or 1 if there is a collision between the +//rectangles (the rectangles overlap). +//This macro works looking for out of range values, if some value is out of +//range it returns 0, if all the values are in range it returns true. +#define check_bb_collision_general(x1,y1,w1,h1,x2,y2,w2,h2) (!( ((x1)>=(x2)+(w2)) || ((x2)>=(x1)+(w1)) || ((y1)>=(y2)+(h2)) || ((y2)>=(y1)+(h1)) )) +#define check_bb_collision(mask1,mask2,x1,y1,x2,y2) check_bb_collision_general(x1,y1,mask1->w,mask1->h,x2,y2,mask2->w,mask2->h) + +//MASK_WORD_TYPE and MASK_WORD_BITBITS can be changed for your platform + +//MASK_WORD_TYPE should be the largest fast integer type available +#define MASK_WORD_TYPE unsigned long int + +//MASK_WORD_BITBITS should be the log base 2 +//of the number of bits in MASK_WORD_TYPE +//e.g. 4 for 16-bit ints, 5 for 32-bit ints, 6 for 64-bit ints +#define MASK_WORD_BITBITS 5 + + +//if SINGLE_MEMORY_BLOCK is defined +//then each mask will be allocated as +//only a single memory block. +//this means that masks will (in theory) +//be ever-so-slightly faster and more memory efficient +//however, if in single memory block mode +//then the masks are variable-sized +//so you can not use an array of them +//#define MASK_SINGLE_MEMORY_BLOCK + +typedef struct PMASK +{ + short int w;//width + short int h;//height +#ifdef MASK_SINGLE_MEMORY_BLOCK + MASK_WORD_TYPE mask[1];//mask data (single memory block) +#else + MASK_WORD_TYPE *mask;//mask data (pointer at second memory block) +#endif +} PMASK; + +void install_pmask(); //sets up library + +int check_pmask_collision(struct PMASK *mask1, struct PMASK *mask2, int x1, int y1, int x2, int y2); //checks for collision (0 = no collision, 1 = collision) + +int get_pmask_pixel(struct PMASK *mask, int x, int y) ; //returns 0 if mask is clear at those coordinates, 1 if not clear +void set_pmask_pixel(struct PMASK *mask, int x, int y, int value) ;//makes mask clear at those coordinates if value is zero, others makes mask not-clear at those coordinates + +void init_pmask (struct PMASK *mask, int w, int h); //initializes a PMASK +void pmask_load_pixels (struct PMASK *mask, void *pixels, int pitch, int bytes_per_pixel, int trans_color);//loads a pmask with pixel data from memory +void pmask_load_func (struct PMASK *mask, int x, int y, void *surface, int trans_color, int (*func)(void*,int,int));//loads a pmask with pixel data from a function +void deinit_pmask(PMASK *mask);//de-initializes a pmask + +PMASK *create_pmask (int w, int h);//creates a new pmask and initializes it +void destroy_pmask(struct PMASK *mask);//destroys a pmask created by create_pmask + +#if defined USE_ALLEGRO +void init_allegro_pmask(struct PMASK *mask, struct BITMAP *sprite); +PMASK *create_allegro_pmask(struct BITMAP *sprite); +#endif + +#if defined USE_SDL +void init_sdl_pmask(struct PMASK *mask, struct SDL_Surface *sprite, int trans_color); +PMASK *create_sdl_pmask(struct SDL_Surface *sprite, int trans_color); +#endif + +#ifdef __cplusplus +} +#endif + +#define MASK_WORD_SIZE sizeof(MASK_WORD_TYPE) +#define MASK_WORD_BITS (MASK_WORD_SIZE*8) + +#if defined pmask_USE_INLINED +inline int _get_pmask_pixel(struct PMASK *mask, int x, int y) { + //no bounds checking + return 1 & (mask->mask[(mask->h * (x >> MASK_WORD_BITBITS)) + y] >> (x & (MASK_WORD_BITS-1))); +} +inline void _set_pmask_pixel(struct PMASK *mask, int x, int y, int value) { + //no bounds checking + if (value) { + mask->mask[(mask->h * (x >> MASK_WORD_BITBITS)) + y] |= 1 << (x & (MASK_WORD_BITS-1)); + } else { + mask->mask[(mask->h * (x >> MASK_WORD_BITBITS)) + y] &=~(1 << (x & (MASK_WORD_BITS-1))); + } +} +#else +#define _get_pmask_pixel get_pmask_pixel +#define _set_pmask_pixel set_pmask_pixel +#endif + + +#endif /* ifndef PPCOL_H */ + diff --git a/include/premio.h b/include/premio.h new file mode 100644 index 0000000..122eac0 --- /dev/null +++ b/include/premio.h @@ -0,0 +1,43 @@ +/*------------------------------------------------------- + premio.h + -------------------------------------------------------- + Copyright (c) 2002, Kronoman + En memoria de mi querido padre + Enero - 2003 + -------------------------------------------------------- */ + +#ifndef PREMIO_H +#define PREMIO_H + +#include + +/* cantidad maxima de clases de premios */ +#define MAX_PREMIO_CLASS 20 + +/* contenedor de las clases de premios */ +typedef struct PREMIO_CLASS { + int premiar; + int cantidad; + int vida; + BITMAP *sprite; + SAMPLE *sonido; +} PREMIO_CLASS; + +/* estructura de datos que contiene cada premio individual; */ +typedef struct PREMIO { + fixed x, y, r; /* posicion y rotacion (efecto cool)*/ + fixed dx, dy, dr; /* direccion */ + int vida; /* vida que le queda */ + int clase; /* indice de la clase de premio */ + struct PREMIO *next; +} PREMIO; + +/* globales exportadas */ +extern PREMIO_CLASS premio_class[MAX_PREMIO_CLASS]; + +/* prototipos */ +PREMIO *agrega_premio(int premio, fixed x, fixed y); +void mover_premio(int x, int y, int w, int h); +void liberar_premio(); +void dibujar_premio(BITMAP *bmp, int x, int y); +#endif diff --git a/include/rvideo.h b/include/rvideo.h new file mode 100644 index 0000000..bf0b70e --- /dev/null +++ b/include/rvideo.h @@ -0,0 +1,31 @@ +// ---------------------------------------------------------------- +// rvideo.h +// ---------------------------------------------------------------- +// Produce un video de un juego a archivos bmp sueltos +// Ideal para generar un video promocional de un juego +// Por Kronoman +// Copyrigth Enero 2003, Kronoman +// En memoria de mi querido padre +// ---------------------------------------------------------------- +// Para que esto funcione, debe ser llamado en cada actualizacion +// logica del juego, de esa manera mantiene los fps constantes +// ---------------------------------------------------------------- + +#ifndef RVIDEO_H +#define RVIDEO_H +#include + +// Globales de configuracion +extern char rvideo_filen[1024]; +extern int rvideo_cadafsave; +extern int rvideo_step; +extern int rvideo_f_actual; +extern int rvideo_is_recording; +extern int rvideo_resize; +extern int rvideo_w, rvideo_h; + +// Prototipos +void init_rvideo(); +void rvideo_record(BITMAP *bmp, RGB *pal); +#endif + diff --git a/include/savedlg.h b/include/savedlg.h new file mode 100644 index 0000000..c7a6252 --- /dev/null +++ b/include/savedlg.h @@ -0,0 +1,38 @@ +// ------------------------------------ +// savedlg.c +// ------------------------------------ +// Sistema de salva / carga de juego +// Por Kronoman +// En memoria de mi querido padre +// Copyright (c) 2002, Kronoman +// ------------------------------------ + +#ifndef SAVEDLG_H +#define SAVEDLG_H + +#include +#include "jugador.h" +#include "global.h" + +// cantidad de slots de savegame (el dialogo tiene soporte para 7) +#define SAVE_GAME_SLOTS 7 + +// Estructura de salvado del juego a disco +// No puedo salvar directamente el JUGADOR, porque tiene punteros y boludeces que no sirven +typedef struct SAVE_GAME_ST +{ + char desc[41]; // descripcion del savegame + int es_valido; // el savegame es valido? 0 = NO, != 0 = si + int vida; /* vida que le queda, energia */ + int dinero; /* dinero (puntos) que tiene */ + int arma[MAX_ARM_CLASS]; /* armamentos que tiene (<= 0 no tiene el arma, > 0 posee el arma, cantidad de balas que tiene) */ + int arma_actual; /* arma seleccionada */ + int bombas; /* cantidad de bombas que le quedan */ + int nivel_actual; // nivel que va jugando + int nivel_de_dificultad; // nivel de dificultad +} SAVE_GAME_ST; + +// Prototipos +void salvar_juego_menu(); +int cargar_juego_menu(); +#endif diff --git a/include/shopping.h b/include/shopping.h new file mode 100644 index 0000000..e08a615 --- /dev/null +++ b/include/shopping.h @@ -0,0 +1,25 @@ +/* + -------------------------------------------------------- + shopping.h + -------------------------------------------------------- + Sistema de shopping de Kraptor + + NOTAS: TODOS LOS TEXTOS DEL MENU ESTAN EN *INGLES* + PARA PODER TRADUCIRLOS AUTOMATICAMENTE + CON EL ENGINE DE TRADUCCION. + USAR MENUES Y DIALOGOS *LOCALES* PARA QUE AL + ENTRAR/SALIR DE SCOPE, (CADA VEZ QUE SE LLAMA LA FUNCION) + SE TRADUZCAN AUTOMATICAMENTE AL LENGUAJE ORIGINAL. + -------------------------------------------------------- +*/ + +#ifndef SHOPPING_H +#define SHOPPING_H + +extern BITMAP *shop_bmp; + +void do_shopping_principal(); + + + +#endif diff --git a/include/sombras.h b/include/sombras.h new file mode 100644 index 0000000..50255e4 --- /dev/null +++ b/include/sombras.h @@ -0,0 +1,17 @@ +// -------------------------------------------------------- +// sombras.h +// -------------------------------------------------------- +// Copyright (c) Kronoman +// En memoria de mi querido padre +// -------------------------------------------------------- +// Genera las sombras del juego +// Bastante simple. :^P +// -------------------------------------------------------- +#ifndef SOMBRAS_H +#define SOMBRAS_H + +/* prototipos */ +void hacer_sombra(BITMAP *origen, BITMAP *destino); +void colocar_sombra(BITMAP *bmp, BITMAP *sombra, int px, int py); + +#endif diff --git a/include/sonido.h b/include/sonido.h new file mode 100644 index 0000000..9920da8 --- /dev/null +++ b/include/sonido.h @@ -0,0 +1,29 @@ +// -------------------------------------------------------- +// sonido.h +// -------------------------------------------------------- +// Copyright (c) Kronoman +// En memoria de mi querido padre +// -------------------------------------------------------- +// Modulo de sonido y musica +// -------------------------------------------------------- +#ifndef SONIDO_H +#define SONIDO_H +#include /* DUMB: libreria de sonido */ + + +// Prototipos + +// Sonido +void tocar_sonido_paneado(int x, SAMPLE *spl, int vol, int freq); +void tocar_sonido(SAMPLE *spl, int vol, int pan, int freq); + + +// Musica +void musica_stop(); +int musica_play(DUH *duh); +void ejecutar_poll_musica(); +void reajustar_volumen_musica(); +void pausar_musica(); +void continuar_musica(); + +#endif diff --git a/include/wordwrap.h b/include/wordwrap.h new file mode 100644 index 0000000..9055c88 --- /dev/null +++ b/include/wordwrap.h @@ -0,0 +1,20 @@ +/*-------------------------------------------------------- + wordwrap.h + -------------------------------------------------------- + Copyright (c) Kronoman + En memoria de mi querido padre + -------------------------------------------------------- + Funciones para escribir texto con 'word-wrap' + --------------------------------------------------------*/ +#ifndef KRONO_WORDWRAP_H +#define KRONO_WORDWRAP_H + +#include "allegro.h" + +/* Prototipos */ +int imprimir_wordwrap(BITMAP *bmp, + const FONT *f, + int x, int y, int color, int w, + const char *text); + +#endif diff --git a/install b/install new file mode 100644 index 0000000..d9a3bc0 --- /dev/null +++ b/install @@ -0,0 +1,38 @@ +Kraptor +------- + +Instructions for compilation of the engine from source code. + +Before compiling, check that: +(*) You have all compiler tools installed (gcc,make,etc) +(*) You have Allegro library properly installed (http://alleg.sf.net/) +(*) You have DUMB Music library properly installed (http://dumb.sf.net/) + + +The engine was tested and can be compiled with GNU GCC (Linux), MinGW (Windows), DJGPP (DOS) +It may be able to compile with other compilers too. + +-- DJGPP users: + +Type: + + fix.bat djgpp + fix.bat test + make + +-- Mingw users: + +Type: + + fix.bat mingw + fix.bat test + make + + +-- Linux users: + +Type: + + ./fix.sh linux + ./fix.sh test + make \ No newline at end of file diff --git a/license b/license new file mode 100644 index 0000000..54f0bb7 --- /dev/null +++ b/license @@ -0,0 +1,16 @@ +Kraptor Game Engine +Kraptor Game Datafiles + +Copyright (c) 2002, 2003, Kronoman +In loving memory of my father. + +This software is OSI Certified Open Source Software. +OSI Certified is a certification mark of the Open Source Initiative. + +Distributed under The MIT License + +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/makefile b/makefile new file mode 100644 index 0000000..ed32c56 --- /dev/null +++ b/makefile @@ -0,0 +1,109 @@ +# ------------------------------------------------------------------------ +# Generic makefile +# By Kronoman +# Thanks to Schwarzung for the help on making the original makefile system. +# ------------------------------------------------------------------------ + +# This has the target platform defined, this is modified by fix.bat or fix.sh +include target.os + +# Suggested by GNU Coding Stardards +SHELL = /bin/sh + +# =============================================== +# Target binary name without extension +BINARY = kraptor + +# Source directory +SRCDIR = src + +# Include directory +INCDIR = include + +# Source code suffix (.c, .cpp, etc) +SRCSUF = .c + +# Simple source code test file (must be in same dir as makefile for now) :( +# The extension will be taken from SRCSUF, don't put it! +TESTFILE = test +# =============================================== + + +# ----------------------------- +# -- Platform specific stuff -- +# ----------------------------- + +# ------------------ +# DJGPP target +# ------------------ +ifeq ($(TARGET),DJGPP) + +PLATFORMDIR=djgpp + +# compiler to invoque +GCC = gcc +# GPP = gxx + +# Binary file suffix +BINSUF = .exe +# object suffix +OBJSUF = .o + +# If you need extra link options (like more librarys, add to LFLAGS var) +LFLAGS = -s -laldmb -ldumb -lalleg + +# Compiler flags +CFLAGS = -I$(INCDIR) -Wall -O3 +endif + +# ------------------ +# MingW32 +# ------------------ +ifeq ($(TARGET),MINGW32) + +PLATFORMDIR=mingw32 + +GCC = gcc +# GPP = g++ + +# Binary file suffix +BINSUF = _w32.exe +OBJSUF = .o + +# If you need extra link options (like more librarys, add to LFLAGS var) +LFLAGS = -s -mwindows -laldmb -ldumb -lalleg + +# Compiler flags +CFLAGS = -I$(INCDIR) -Wall -O3 +endif + +# ------------------ +# Linux +# ------------------ +ifeq ($(TARGET),LINUX) + +PLATFORMDIR=linux + +GCC = gcc +# GPP = g++ + +# Binary file suffix +BINSUF = _linux.bin +OBJSUF = .o + +# If you need extra link options (like more librarys, add to LFLAGS var) +LFLAGS = -laldmb -ldumb `allegro-config --libs` + +# Compiler flags +CFLAGS = -I$(INCDIR) -Wall -O3 +endif + +# --------------------------------- +# -- Platform non-specific stuff -- +# --------------------------------- + +OBJDIR = obj/$(PLATFORMDIR) +BINDIR = bin + +# -- The rules for build are in this file -- +include makefile.all diff --git a/makefile.all b/makefile.all new file mode 100644 index 0000000..8bd7180 --- /dev/null +++ b/makefile.all @@ -0,0 +1,46 @@ +# Makefile generic - Rules to build +# Fixed at last! :), thanks to Schwarzung + +TEMP = $(wildcard $(SRCDIR)/*$(SRCSUF)) +FILES = $(if $(TEMP), $(TEMP), $(error No source code found!)) +OBJS = $(addprefix $(OBJDIR)/,$(addsuffix $(OBJSUF), $(basename $(notdir $(FILES) ) ) ) ) + +# main target, all project +.PHONY: all +all: $(BINDIR)/$(BINARY)$(BINSUF) + +$(BINDIR)/$(BINARY)$(BINSUF) : $(OBJS) + $(GCC) $^ -o $@ $(LFLAGS) + @echo The $(BINDIR)/$(BINARY)$(BINSUF) is ready! + +$(OBJDIR)/%$(OBJSUF) : $(SRCDIR)/%$(SRCSUF) + $(GCC) $(CFLAGS) -c $< -o $@ + +.PHONY: clean and also clean the test +clean: cleantest + rm -rf $(BINDIR)/$(BINARY)$(BINSUF) $(OBJS) + +# Strip symbols and compress with upx packer (http://upx.sf.net/) +.PHONY: upx +upx: + strip --strip-all $(BINDIR)/$(BINARY)$(BINSUF) + upx --best $(BINDIR)/$(BINARY)$(BINSUF) + +# Install - Please add here your custom installation functions +.PHONY: install +install: + @echo Sorry, the install feature is not done yet. + +# Test if the system can compile - PLEASE MODIFY THIS TO SUIT YOUR NEEDS! +# Compile the program +# The test.run is to check if make run or not in DJGPP enviroment (ugly hack) +# seems that DOS don't set errorlevel if fails to execute a program +.PHONY: test +test: + $(GCC) $(TESTFILE)$(SRCSUF) -o $(TESTFILE)$(BINSUF) $(CFLAGS) $(LFLAGS) + echo "don't edit me" > test.run + +# Cleans the test +.PHONY: cleantest +cleantest: + rm -rf $(TESTFILE)$(BINSUF) test.run \ No newline at end of file diff --git a/obj/djgpp/remove.me b/obj/djgpp/remove.me new file mode 100644 index 0000000..99e8d22 --- /dev/null +++ b/obj/djgpp/remove.me @@ -0,0 +1 @@ +This file can be safely removed \ No newline at end of file diff --git a/obj/linux/remove.me b/obj/linux/remove.me new file mode 100644 index 0000000..99e8d22 --- /dev/null +++ b/obj/linux/remove.me @@ -0,0 +1 @@ +This file can be safely removed \ No newline at end of file diff --git a/obj/mingw32/remove.me b/obj/mingw32/remove.me new file mode 100644 index 0000000..99e8d22 --- /dev/null +++ b/obj/mingw32/remove.me @@ -0,0 +1 @@ +This file can be safely removed \ No newline at end of file diff --git a/readme b/readme new file mode 100644 index 0000000..d83e3bb --- /dev/null +++ b/readme @@ -0,0 +1,140 @@ +Kraptor +------- + +--------------------------------------------------------------------- + +Official Web Site + +http://kraptor.sf.net/ + +--------------------------------------------------------------------- + +Copyright 2002, 2003, 2004, Kronoman +Released under the MIT license +In loving memory of my father. +Made in Argentina + +--------------------------------------------------------------------- + +After years of oppression, the slaved people of the world have raised against their masters. +You, has a mercenary pilot, has been contacted by the popular rebellion to fight against the forces of oppression. +In the morning, you jump into your cockpit and start up the engines. +Its time to get airborne and start the attack. +Get ready to scramble the scum hired by the masters. +Murder for freedom is the only way, you're a man on a mission, don't defraud us... + +--------------------------------------------------------------------- + +What is this? + +Kraptor is a classic shoot 'em up scroller game, where you must fight against tons of bad dudes. +The game offers high speed action, with massive destruction and lots of fun. +Kraptor features a powerful engine for 2D shooter scroller games. +Massive destruction, powerful weapons, all that you always wanted in this kind of games! +It is also multi-platform (DOS, Win32, Linux and more!) + +--------------------------------------------------------------------- + +Command line options + +-safe Will run the game in 'safe' mode (will try to start it no matter what) +-windowscreen Will run the game in a window (not available in DOS version) +-fullscreen Will run the game in fullscreen +-autoscreen Will try to autodetect video card and screen mode +-nosound Disables the sound +-320x200 Video mode 320x200 +-320x240 Video mode 320x240 +-640x480 Video mode 640x480 +-800x600 Video mode 800x600 +-1024x768 Video mode 1024x768 + +--------------------------------------------------------------------- + +Features + +Some of the main features of the engine and the game itself: + +# FULL SOURCE CODE AVAILABLE FREE (Under MIT license) +# Works on many platforms, including DOS, Windows and Linux! +# Supports all resolutions, like 320x200, 640x480, 1024x768, etc.; even those bizarre ones, like 160x120, 320x400, etc. +# Uses stereo positional sound (you hear the ships flying around you) +# Has a incredible particle system, that let all sorts of particle effects in the explosions, fire on the ground, the ships going down in flames,and the weapons can let a trail of smoke, beams, etc +# Has a dynamic fire, smoke and explosions system based on layers and on-fly rendering, that let show a massive destruction effect on the air and ground. +# Has a dynamic enviroment sub-engine to render rain, snow, etc. +# The ships explodes into pieces, and the builds on the ground blows up in a chain-explosion effect. +# Enemys of any size, and custom IAs and weapons. +# All kind of animated bad dudes, from tiny ones to big bad bosses. +# All the flying objects cast shadows over the background, with perspective correction. +# Support for animations and cinematic, with sound and subtitles. +# A on-fly translation system with UNICODE and UTF-8 support, that can translate on the fly all the GUIs to other language. +# Multiple weapons for player and enemies. +# Has original music sound-track. +# You can lower/raise the detail level, in low detail, the game runs good even on a 486 DX2! +# Original story, with cool movies. +# Realistic huge hi-res backgrounds levels. +# Original high quality stereo sounds and music +# Support for Spanish and English translation on-fly +# 'Black market' shop to buy new weapons, upgrade ship, etc. +# GUI driven interface like the one used in Unre*l. +# You can Save / Load your game + +--------------------------------------------------------------------- + +Thanks to: + +# All the people that made open source and free software. Without them, the world would be yet more scary. +# The guys of Allegro, DUMB, Pixelate and Allegro.cc. Cool job! +# F3N1X Team, thanks for the Linux CDs! +# Mother, thanks for the Linux T-Shirt and the new Linux CDs! Ha! Of course, thanks for live! +# Father, thanks for so many things... specially my first 386. What cool machine it was! +# Iron Chelo "The Bodyguard" +# DJ Ñanga +# GAC +# J. Monytor (no man, we need more acceleration to put that tea cup in orbit of mars) +# El Super 666, cool heavy metal CDs... thanks! +# El Mago Eddy +# Error Catastrofico +# Gabriel, thanks for lots of good heavy MP3s +# B. Gates, hope that you recover soon from your lobotomy... +# G. W. Bush, call me when you be more sober... + +--------------------------------------------------------------------- + +Software used in development + +The following software was used in the development of Kraptor +For links to download them, check the "Links" section. + +GNU GCC, DJGPP and MinGW32 where the main compilers used in Kraptor +Allegro is the game programming library used. +DUMB is the music engine. +Linux Mandrake 8.2 and 9.0 where used as the main OS for development. +The GIMP and ASE where used to do the 2D graphic artwork and FLI cinematic. +Blender, Povray, Giram, Ayam and Aqsis where used to do the 3D artwork. +PMASK is the collision library made by "orz". +Bluefish and Mozilla where used to make this web page. +Bochs, a portable x86 Emulator, really useful for testing in other OS without reboot. +Audacity, a cool free audio editor! +DLG, a dialog editor by Julien Cugniere (thanks for the GUI routines too!) +UPX was used to compress the executable in certaing platforms. +Many other software that I don't remember right now was used also. Thanks to them too. +Hardware used in development +The main development machine was a P3 450 MHz (over-clocked at 500 MHz), 320MB RAM, 2 x 40GB HD, CD, CD-RW, optical pen, scanner, web-cam, etc, with Linux Mandrake 9.0, Free-DOS and Windoze 98 +One AMD Atlhon XP 1700 with 512MB RAM, NVIDIA GForce2 MX 400, dual 80 GB HD was used to the rendering and advanced graphic and sound edition. +Also was used a 486DX2 66MHz, 8MB RAM, 540MB HD, 5 1/4 floppy, with DR-DOS for performance testing purposes. +A Palm m125 was used to take ideas and notes 'on-fly' in the streets. + +--------------------------------------------------------------------- + +Released under the MIT license +The MIT License + +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sub-license, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +--------------------------------------------------------------------- + + diff --git a/src/azar.c b/src/azar.c new file mode 100644 index 0000000..3ea1774 --- /dev/null +++ b/src/azar.c @@ -0,0 +1,36 @@ +// azar.c +// Macro para numeros al azar +// Elige un numero entre min y max +// Tomado de la internet y mejorado por Kronoman + +#ifndef AZAR_C +#define AZAR_C + +#include + +#include "azar.h" +/* +Esta funcion explota si min - max da 0, sorry, pero la cambie... +*/ +// #define rand_ex( min, max ) ( (rand() % (max - min)) + min ) + +/* esta funcion es ligeramente mas lenta, pero NO explota... */ +int rand_ex(int min, int max) +{ +int tmp; + + if (min - max == 0) return 0 + min; /* evito division por cero */ + + /* correcion nueva, medio lenta, pero para corregir algunos bugs raros + intercambio min y max si estan al reves */ + if (min > max) + { + tmp = min; + min = max; + max = tmp; + } + + return ( rand() % (max - min) ) + min; +} + +#endif diff --git a/src/bomba.c b/src/bomba.c new file mode 100644 index 0000000..1e790bb --- /dev/null +++ b/src/bomba.c @@ -0,0 +1,76 @@ +// -------------------------------------------------------- +// bomba.c +// -------------------------------------------------------- +// Copyright (c) Kronoman +// En memoria de mi querido padre +// -------------------------------------------------------- +// Este modulo contiene todo lo relacionado con las bombas +// del jugador... +// -------------------------------------------------------- +#ifndef BOMBA_C +#define BOMBA_C + +#include +#include "bomba.h" +#include "mapa.h" +#include "sonido.h" +#include "explos.h" +#include "kfbuffer.h" +#include "azar.h" + +/* globales exportadas, setearlas al lanzar una bomba, ver jugador.c */ +int bomba_esta_activa = FALSE; // esta la bomba funcionando en este momento? +int bomba_detonacion = 0; // tiempo de detonacion (30 = 1 segundo explotando) +SAMPLE *bomba_sonido = NULL; // sonido de detonacion + +/* mueve la bomba */ +void mover_bomba() +{ +int i; +if (!bomba_esta_activa) return; + +// sonido de explosiones al azar... +if (rand()%100 < 25) + tocar_sonido_paneado(rand()%ANCHO_FB, + explo_cache_snd[rand()%3], + rand_ex(128, 200), + rand_ex(800, 1300)); + +bomba_detonacion--; +if (bomba_detonacion <= 0) + { + /* sonido estruendoso de explosion */ + if (rand()%100 < 95) + for (i = 0; i < rand()%3+1; i++) + tocar_sonido_paneado(rand()%ANCHO_FB, + explo_cache_snd[rand()%3], + rand_ex(196, 256), + rand_ex(800, 1300)); + + bomba_esta_activa = FALSE; + bomba_detonacion = 0; + } +} + +/* dibuja la explosion de la bomba, actualmente, todo blanco... horrible! */ +void dibujar_bomba(BITMAP *bmp) +{ +if (!bomba_esta_activa) return; + +clear_to_color(bmp, makecol(255,255,255) ); + +} + +/* produce una detonacion total del piso del juego, + pasarle en x el 'scroll_mapa' */ +void detonar_totalmente_el_piso(int y) +{ +int x1,y1; +/* DEBUG: esto detona con retroactividad, es decir todo el mapa hacia atras! */ +for (y1 = y / H_GR; y1 < GRILLA_H; y1++) + for (x1 = 0; x1 < GRILLA_W; x1++) + explotar_fondo(x1, y1, rand()%100+100); + +} + +#endif diff --git a/src/captura.c b/src/captura.c new file mode 100644 index 0000000..71b7622 --- /dev/null +++ b/src/captura.c @@ -0,0 +1,43 @@ +/* + -------------------------------------------------------- + captura.c + -------------------------------------------------------- + Copyright (c) Kronoman + En memoria de mi querido padre + -------------------------------------------------------- + Funcion para tomar una captura de pantalla + Automaticamente la salva en archivoxxx.bmp, etc + -------------------------------------------------------- +*/ +#ifndef CAPTURAR_C +#define CAPTURAR_C + +#include +#include "allegro.h" + +/* Esta funcion captura la pantalla, usando el prefijo para el archivo + Salva un PCX de 8 bits de color. +*/ +void capturar_la_pantalla(char *prefijo) +{ + char arch[1024]; + int i = 0; + + BITMAP *bmp; + PALETTE pal; + + /* Buscar un archivo entre 0 y 4095 para salvar el archivo + Usa numeracion hexadecimal para que entren mas archivos */ + do { + sprintf(arch, "%s%x.bmp", prefijo, i); + i++; + } while (exists(arch) && i < 4096); + + + get_palette(pal); + bmp = create_sub_bitmap(screen, 0, 0, SCREEN_W, SCREEN_H); + save_bitmap(arch, bmp, pal); + destroy_bitmap(bmp); +} + +#endif diff --git a/src/cinema.c b/src/cinema.c new file mode 100644 index 0000000..d50bc77 --- /dev/null +++ b/src/cinema.c @@ -0,0 +1,749 @@ +/* + -------------------------------------------------------- + cinema.c + -------------------------------------------------------- + Copyright (c) Septiembre 2002, Kronoman + En memoria de mi querido padre + -------------------------------------------------------- + Engine de cinematicas mediante scripts y datafiles + Nota: quiere_videos afecta si esto funciona o no. :D + -------------------------------------------------------- */ + +#ifndef CINEMA_C +#define CINEMA_C + +#include +#include +#include +#include "allegro.h" + +#include "krstring.h" +#include "kfbuffer.h" /* dibuja en el buffer, debe estar funcionando OK... */ +#include "cinema.h" +#include "error.h" +#include "wordwrap.h" +#include "datafind.h" +#include "global.h" +#include "filedata.h" + +/* Listado de comandos disponibles al script principal */ +CMD_SCRIPT_TYPE cmd_list[] = +{ + { "cls", cmd_cls, 3 }, + { "fade_out", cmd_fade_out, 1 }, + { "fade_out_color", cmd_fade_out_color, 4 }, + { "rect", cmd_rect, 7 }, + { "rectfill", cmd_rectfill, 7 }, + { "line", cmd_line, 7 }, + { "locate", cmd_locate, 3 }, + { "text_color", cmd_text_color, 3 }, + { "text_back", cmd_text_back , 3 }, + { "text_font", cmd_text_font, 0 }, + { "echo", cmd_echo, 0 }, + { "echo_centre_x",cmd_echo_centre_x, 0 }, + { "echo_centre_xy", cmd_echo_centre_xy, 0 }, + { "rest", cmd_rest, 1 }, + { "set_palette", cmd_set_palette, 1 }, + { "set_palette_default", cmd_set_palette_default, 0 }, + { "blit", cmd_blit, 3 }, + { "sprite", cmd_sprite, 3 }, + { "stretch_blit", cmd_stretch_blit, 5 }, + { "stretch_blit", cmd_stretch_blit, 5 }, + { "play_sample", cmd_play_sample, 4 }, + { "play_fli", cmd_play_fli, 7 }, + { "clear_fli_back",cmd_clear_fli_back, 3 }, + { "keyboard_cancel_fli", cmd_keyboard_cancel_fli, 1 }, + { NULL, NULL, 0 } /* fin de listado */ +}; + +/* Globales, usadas en la interpretacion */ +static DATAFILE *el_archivo = NULL; /* el archivo DAT a usar... */ + +static char linea_actual[MAX_LINEA]; /* linea de comando actual, completa */ +static int n_linea_actual; /* numero de linea actual */ + +static char comando_actual[80+1]; /* comando actual leido */ +static char s2nd_param[MAX_LINEA]; /* todo lo que quedo sacando el comando principal */ + +static char str_param[MAX_PARAMS][256]; /* parametros parseados a char, maximo 256 letras c/u */ +static int c_str_param = 0; /* cantidad de parametros str leidos */ + +static int int_param[MAX_PARAMS]; /* parametros parseados a int */ +static int c_int_param = 0; /* cantidad de parametros int leidos */ + +static int teclado_cancela_fli = 0; /* puedo cancelar un FLI con teclado? */ +static int cls_el_fli[3] = { 0, 0, 0 }; /* color de limpieza antes de 'tocar' un FLI */ + +/* Referente a la salida de texto... */ +static int x_echo = 0, y_echo = 0, w_echo = ANCHO_RFB; /* pos cursor */ +static int echo_text_color, echo_text_back; /* colores */ +static FONT *echo_font; /* font a usar */ + +// DEBUG: El mapa RGB fue desactivado porque causaba problemas al usar multiples paletas... sorry gordi.. +// static RGB_MAP rgb_table_cine; /* mapa RGB para la paleta actual */ + +static PALETTE pal_cine; /* paleta actual */ + +/* ------------------------------------------------- */ +/* Globales usadas por las funciones de los comandos */ + +/* DEBUG: agregar aqui las globales extra necesarias, como 'static' */ + +/* --------------------- Funciones de los comandos --------------- */ + +/* Esta funcion limpia la pantalla al color especificado */ +int cmd_cls() { + clear_to_color(kfbufferbmp, makecol(int_param[0], int_param[1], int_param[2])); + enviar_kfbuffer2screen(); /* refrescar pantalla */ + return 0; /* todo OK */ +} + +/* Dibuja un rectangulo vacio */ +int cmd_rect() +{ + rect(kfbufferbmp, + int_param[0], int_param[1], + int_param[2], int_param[3], + makecol(int_param[4], int_param[5], int_param[6])); + enviar_kfbuffer2screen(); /* refrescar pantalla */ + return 0; +} + +/* Dibuja un rectangulo lleno */ +int cmd_rectfill() +{ + rectfill(kfbufferbmp, + int_param[0], int_param[1], + int_param[2], int_param[3], + makecol(int_param[4], int_param[5], int_param[6])); + enviar_kfbuffer2screen(); /* refrescar pantalla */ + return 0; +} + +/* Traza lineas */ +int cmd_line() +{ + line(kfbufferbmp, + int_param[0], int_param[1], + int_param[2], int_param[3], + makecol(int_param[4], int_param[5], int_param[6])); + enviar_kfbuffer2screen(); /* refrescar pantalla */ + return 0; +} + +/* Esta funcion es un wrapper de fade_out de Allegro */ +int cmd_fade_out() { + fade_out(int_param[0]); + get_palette(pal_cine); // actualizar la paleta actual + return 0; +} + +/* Esta funcion es un wrapper de fade_out de Allegro + pero ajustado para que haga un fade out al color especificado + +fade_out_color [r] [g] [b] [velocidad] + Realiza una transicion al color [r] [g] [b] + [velocidad] 1..64 (lento-rapido) + */ +int cmd_fade_out_color() { + + RGB col; // color formato (nota: esto va de 0..63, NO de 0..255!!) + PALETTE pal_dest; // paleta destino + PALETTE pal_orig; // paleta origen + int i = 0; + + // divido por 4 para que quede en rango 0..63 + // ademas, ajusto con MIN y MAX en rango... + col.r = MAX(0, MIN(63, int_param[0] / 4)); + col.g = MAX(0, MIN(63, int_param[1] / 4)); + col.b = MAX(0, MIN(63, int_param[2] / 4)); + + for (i = 0; i < 256; i++) + { + pal_dest[i].r = col.r; + pal_dest[i].g = col.g; + pal_dest[i].b = col.b; + } + + get_palette(pal_orig); + + fade_from(pal_orig, pal_dest, int_param[3]); + + get_palette(pal_cine); // actualizar la paleta actual + + return 0; +} + +/* Posiciona el cursor de texto */ +int cmd_locate() +{ + x_echo = int_param[0]; + y_echo = int_param[1]; + w_echo = int_param[2]; + return 0; +} + +/* Color de texto para echo */ +int cmd_text_color() +{ + echo_text_color = makecol(int_param[0], int_param[1], int_param[2]); + return 0; +} + +/* Color de fondo para el texto */ +int cmd_text_back() +{ + if (int_param[0] < 0 || int_param[1] < 0 || int_param[2] < 0) + echo_text_back = -1; + else + echo_text_back = makecol(int_param[0], int_param[1],int_param[2]); + + text_mode(echo_text_back); + return 0; +} + +/* Cambiar la fuente del texto */ +int cmd_text_font() +{ + DATAFILE *p = NULL; + if (c_str_param > 0) + { + p = find_datafile_object_type(el_archivo, str_param[0], DAT_FONT); + if (p == NULL) return -1; /* fallo... */ + echo_font = p->dat; + } + else + { + echo_font = font; + } + +return 0; +} + +/* Salida a pantalla de texto + escribe y avanza la linea... (como el print de Qbasic) */ +int cmd_echo() +{ +text_mode(echo_text_back); + +y_echo = imprimir_wordwrap(kfbufferbmp, + echo_font, + x_echo, y_echo, echo_text_color, w_echo, + s2nd_param); + +enviar_kfbuffer2screen(); /* refrescar pantalla */ +return 0; +} + +/* Salida de texto centrado en x */ +int cmd_echo_centre_x() +{ +int x; +text_mode(echo_text_back); +x = text_length(echo_font, s2nd_param); +x = (kfbufferbmp->w - x)/2; + +//textprintf(kfbufferbmp, echo_font, x, y_echo, echo_text_color, "%s", s2nd_param); +//y_echo += text_height(echo_font); + +// usa word-wrap... +y_echo = imprimir_wordwrap(kfbufferbmp, + echo_font, + x, y_echo, echo_text_color, w_echo, + s2nd_param); + + +enviar_kfbuffer2screen(); /* refrescar pantalla */ +return 0; +} + +/* Salida de texto centrado en x,y */ +int cmd_echo_centre_xy() +{ +int x; +text_mode(echo_text_back); +x = text_length(echo_font, s2nd_param); +x = (kfbufferbmp->w - x)/2; +y_echo = (kfbufferbmp->h - text_height(echo_font)) / 2; + +//textprintf(kfbufferbmp, echo_font, x, y_echo, echo_text_color, "%s", s2nd_param); +//y_echo += text_height(echo_font); + +// usa word-wrap... +y_echo = imprimir_wordwrap(kfbufferbmp, + echo_font, + x, y_echo, echo_text_color, w_echo, + s2nd_param); + + +enviar_kfbuffer2screen(); /* refrescar pantalla */ +return 0; +} + + +/* Pausa sincronica, puede ser cancelada con el teclado */ +int cmd_rest() +{ +long int f = 0; /* para el for */ + + if (int_param[0] <= 0 ) + { + clear_keybuf(); + readkey(); // esperar por una tecla + clear_keybuf(); + } + else + { + clear_keybuf(); + f = 0; + // el cancelar solo funciona si la pausa es > 10 ms + if (int_param[0] > 10) + { + while ((f < int_param[0]) && (!keypressed())) + { + rest (10); + f += 10; + } + } + else + { + rest((long)int_param[0]); + } + clear_keybuf(); + } +return 0; +} + +/* Setea la paleta y la tabla RGB */ +int cmd_set_palette() +{ +DATAFILE *p; +p = find_datafile_object_type(el_archivo, str_param[0], DAT_PALETTE); +if (p == NULL) return -1; /* fallo... */ + +memcpy(pal_cine, p->dat, sizeof(PALETTE)); + +// create_rgb_table(&rgb_table_cine, pal_cine, NULL); +// rgb_map = &rgb_table_cine; // DEBUG - mapa RGB desactivado + +vsync(); /* evita flicker */ +set_palette(pal_cine); + +return 0; +} + +/* Setea la paleta VGA DEFAULT y la tabla RGB */ +int cmd_set_palette_default() +{ +memcpy(pal_cine, default_palette, sizeof(PALETTE)); + +vsync(); /* evita flicker */ +set_palette(pal_cine); + +return 0; +} + +/* blitea un bitmap a pantalla */ +int cmd_blit() +{ +DATAFILE *p; +p = find_datafile_object_type(el_archivo, str_param[2], DAT_BITMAP); +if (p == NULL) return -1; /* fallo... */ + +blit((BITMAP *)p->dat, kfbufferbmp, 0, 0, int_param[0], int_param[1], ((BITMAP *)p->dat)->w, ((BITMAP *)p->dat)->h); +enviar_kfbuffer2screen(); /* refrescar pantalla */ +return 0; +} + +/* sprite a pantalla */ +int cmd_sprite() +{ +DATAFILE *p; +p = find_datafile_object_type(el_archivo, str_param[2], DAT_BITMAP); +if (p == NULL) return -1; /* fallo... */ + +draw_sprite(kfbufferbmp, (BITMAP *)p->dat, int_param[0], int_param[1]); + +enviar_kfbuffer2screen(); /* refrescar pantalla */ +return 0; +} + +/* estira un bitmap */ +int cmd_stretch_blit() +{ +DATAFILE *p; +p = find_datafile_object_type(el_archivo, str_param[4], DAT_BITMAP); +if (p == NULL) return -1; /* fallo... */ + +stretch_blit((BITMAP *)p->dat, kfbufferbmp, 0, 0, ((BITMAP *)p->dat)->w, ((BITMAP *)p->dat)->h, int_param[0], int_param[1], int_param[2], int_param[3]); +enviar_kfbuffer2screen(); /* refrescar pantalla */ +return 0; +} + +/* ejecuta un sonido (sample) */ +int cmd_play_sample() +{ +DATAFILE *p; +p = find_datafile_object_type(el_archivo, str_param[0], DAT_SAMPLE); +if (p == NULL) return -1; /* fallo... */ + +play_sample((SAMPLE *)p->dat, int_param[1], int_param[2], int_param[3], 0); + +return 0; +} + +/* +ejecuta un archivo FLI (animacion +esta funcion es complicada porque utiliza sonidos y subtitulos... :^P +NOTA: si no logra abrir el fli, NO falla + esto es para permitir facilmente hacer demostraciones con videos 'recortados' +*/ +int cmd_play_fli() +{ +int ret = 0; int loop = 0; +DATAFILE *p = NULL; /* buscador */ +DATAFILE *fli_p = NULL; /* FLI */ +int ctxt = 0; /* encontro el [script_fli]? */ +DATAFILE *psample = NULL; /* SAMPLE a ejecutar */ +char tmpstr[1024]; /* string temporal de uso vario */ +tmpstr[0] = '\0'; + +// play_fli [x] [y] [w] [h] [loop] [objeto_fli] [script_fli] +// 0 1 2 3 4 5 6 + /* buscar FLI a ejecutar */ + p = find_datafile_object_type(el_archivo, str_param[5], DAT_FLI); + if (p == NULL) return 0; /* fallo... no hay FLI..., lo ignoro */ + + fli_p = p; /* tomar el puto FLI */ + + /* buscar la configuracion [script_fli], si no existe, se ignorara */ + p = find_datafile_object(el_archivo, str_param[6]); + if (p != NULL) + { + ctxt = TRUE; /* lo encontro */ + set_config_data((char *)p->dat, p->size); + } + else + ctxt = 0; /* no lo encontro... */ + + /* mostramos el fli de la manera complicada... + ver fli.c de Allegro para mas info */ +clear_keybuf(); /* limpio el buffer de teclado */ + +rgb_map = NULL; /* anulo el mapa RGB */ + +/* ir realizando el looping adecuado */ +for (loop = int_param[4]; loop > 0; loop--) + { + if (open_memory_fli(fli_p->dat) != FLI_OK) return -1; /* no era un FLI... */ + + ret = next_fli_frame(0); + if (ret == FLI_ERROR) return -1; + + while (ret == FLI_OK) + { + /* actualiza la paleta */ + if (fli_pal_dirty_from <= fli_pal_dirty_to) + set_palette_range(fli_palette, + fli_pal_dirty_from, + fli_pal_dirty_to, TRUE); + + /* actualiza la pantalla */ + if (fli_bmp_dirty_from <= fli_bmp_dirty_to) + { + /* debo limpiar el buffer? */ + if (cls_el_fli[0] > -1 && cls_el_fli[1] > -1 && cls_el_fli[2] > -1) + clear_to_color(kfbufferbmp, makecol(cls_el_fli[0], cls_el_fli[1], cls_el_fli[2])); + + stretch_blit(fli_bitmap, kfbufferbmp, + 0, 0, + fli_bitmap->w, fli_bitmap->h, + int_param[0], int_param[1], + int_param[2], int_param[3]); + + vsync(); // tratar de evitar el flicker + enviar_kfbuffer2screen(); /* refrescar pantalla */ + } + + reset_fli_variables(); + + ret = next_fli_frame(0); + if (ret == FLI_ERROR) return -1; /* ERROR! */ + + if (ctxt) + { + /* ejecutar los sonidos adecuados al frame... */ + sprintf(tmpstr,"FRAME_%d", fli_frame); + psample = find_datafile_object_type(el_archivo, get_config_string(tmpstr, "snd", "null"), DAT_SAMPLE); + if (psample != NULL) play_sample((SAMPLE *)p->dat, 255, 128 ,1000, 0); + + /* DEBUG: subtitular en caso necesario... */ + } + + do { + /* esperar hasta proximo cuadro */ + /* si aprieta una tecla, salir... */ + if (keypressed() && teclado_cancela_fli) + { + ret = FLI_EOF; + fli_timer = 1; + loop = -1; + } + } while (fli_timer <= 0); + + } + close_fli(); /* adios... */ + } + +/* Devolver mapa RGB */ +// rgb_map = &rgb_table_cine; // DEBUG: desactivado +clear_keybuf(); /* limpio el buffer de teclado */ +return 0; +} + +/* color de limpieza del fli */ +int cmd_clear_fli_back() +{ + cls_el_fli[0] = int_param[0] % 256; + cls_el_fli[1] = int_param[1] % 256; + cls_el_fli[2] = int_param[2] % 256; +return 0; +} + +/* ajusta la bandera de cancelar los fli con el teclado */ +int cmd_keyboard_cancel_fli() +{ +teclado_cancela_fli = int_param[0]; + +return 0; +} + +/* --------------------- Funciones del motor en si --------------- */ + +/* Esta macro funcion se encarga de reproducir una cinematica + desde un archivo DAT, pasarselo en char *file, + sera cargado, ejecutado, y liberado... + Esta es la funcion de entrada que deberia usarse para ejecutar + una cinematica + la afecta quiere_videos; + */ +void ejecutar_cinematica(char *file) +{ + DATAFILE *carga = NULL; + DATAFILE *p; + char *guion_txt; + char tmp[80]; // temporal... formacion del nombre del script + + if (!quiere_videos) return; // el usuario no quiere ver videos + + carga = krono_load_datafile(file); + + if (carga == NULL) return; /* el archivo no existe... chau... */ + + /* buscar el script */ + sprintf(tmp, "guion_txt_%s", lenguaje); + p = find_datafile_object(carga, tmp); + if (p==NULL) + { + // si no existe el especifico del lenguaje, buscar el generico + p = find_datafile_object(carga, "guion_txt"); + // si no existe el generico, buscar la version en ingles + if (p==NULL) + { + p = find_datafile_object(carga, "guion_txt_en"); + if (p == NULL) return; /* no hay guion... chau... */ + } + } + guion_txt = (char *)p->dat; + + ejecutar_script(guion_txt, p->size, carga); + + unload_datafile(carga); /* liberar... */ +} + + +/* + Ejecuta el script pasado en char *txt_script + Esto podria ser un DATAFILE ->dat pasado a char, por ejemplo. + Toma el caracter 10 como salto de linea (compatible con UNIX) + El texto pasado en *txt_script puede ser del largo que se desee, + pero debe ser especificado en int size. + El char *archivo es el archivo DATAFILE que contendra + los diferentes objetos FLI, BITMAP, etc a usar por los comandos + Debe estar PRE-cargado en RAM + NOTA: kfbufferbmp sera usado como doble buffer! DEBE estar iniciado! + + + NOTA 2: Por pedido popular, ahora con ESC,SPACE o ENTER se puede cancelar + completamente la animacion +*/ +void ejecutar_script(const char *txt_script, const int size, DATAFILE *archivo) +{ + int i = 0; /* posicion x en el txt_script */ + int xl = 0; /* pos en tmp[] */ + char tmp[MAX_LINEA]; /* lectura tmp */ + + +/* Iniciar el script */ +x_echo = 0, y_echo = 0, w_echo = ANCHO_RFB; /* pos cursor */ + +echo_font = font; /* font a usar */ +echo_text_color = makecol(255,255,255); echo_text_back = -1; /* colores texto */ +text_mode(-1); + +teclado_cancela_fli = TRUE; +cls_el_fli[0] = cls_el_fli[1] = cls_el_fli[2] = 0; + +get_palette(pal_cine); /* tomo la paleta actual */ + +rgb_map = NULL; /* anulo el mapa RGB */ + +// debug: desactivado +// create_rgb_table(&rgb_table_cine, pal_cine, NULL); +// rgb_map = &rgb_table_cine; + +/* doble buffer, debe estar iniciado! */ +set_clip(kfbufferbmp, 0, 0, kfbufferbmp->w-1, kfbufferbmp->h-1); /* clipping adecuado */ +clear(kfbufferbmp); + +n_linea_actual = 0; +el_archivo = archivo; +tmp[0] = '\0'; +linea_actual[0] = '\0'; + +/* Revisar linea por linea del buffer */ + for (i = 0; i < size; i++) + { + /* Ir armando la linea */ + if (txt_script[i] == '\r' || xl == MAX_LINEA-1 || txt_script[i] == 10) /* salto de linea */ + { + tmp[xl] = '\0'; + krtrim(linea_actual, tmp); /* remover espacios */ + n_linea_actual ++; + xl = 0; + + if (parsear_y_ejecutar_linea()) return; /* interpretar comando, y cancelar si el usuario cancela */ + + tmp[0] = '\0'; + linea_actual[0] = '\0'; + } + else + { /* armando la linea */ + tmp[xl] = (txt_script[i] >= 32) ? txt_script[i] : ' '; /* filtra chars 'raros' */ + xl++; + } + } + + /* Ultima linea, interpretar tambien... */ + tmp[xl] = '\0'; + krtrim(linea_actual, tmp); /* remover espacios */ + n_linea_actual ++; + xl = 0; + + parsear_y_ejecutar_linea(); /* interpretar comando! */ + + /* Termino el show... */ +} + + +/* +Esta funcion interpreta una linea y la parsea en sus parametros +respectivos, para luego llamar a la funcion adecuada +Si el usuario presiona una tecla, devuelve TRUE (-1) (Cancelar) +Caso contrario, devuelve 0 +*/ +int parsear_y_ejecutar_linea() +{ +int i, i2; +char *tok; +char tmptok[MAX_LINEA]; + +/* es un comentario? no hacer nada... */ +if (linea_actual[0] == '#' || strlen(linea_actual) < 1 ) return 0; + +/* Limpio los parametros... */ +for (i = 0; i < MAX_PARAMS; i++) + { + int_param[i] = 0; + str_param[i][0] = '\0'; + } + +comando_actual[0] = '\0'; + +i = c_str_param = c_int_param = 0; + +/* Parsear la linea... */ +sprintf(tmptok, "%s", linea_actual); /* evito modificar el original */ +for (tok = strtok(tmptok, " ");tok;tok = strtok(0, " ")) + { + if (i == 0) + { + krtrim(comando_actual, tok); /* el 1er comando */ + } + else + { /* tomar parametros */ + krtrim(str_param[i-1], tok); /* remover espacios */ + c_str_param ++; + int_param[i-1] = atoi(tok); + c_int_param++; + } + i++; + if (i > MAX_PARAMS-1) break; /* muchos parametros */ + } + +/* Tomar todo menos el primer parametro... */ +tmptok[0] = s2nd_param[0] = '\0'; + +i2 = 0; +i = strlen(comando_actual); +while (i < strlen(linea_actual)) /* con un for no funcionaba... por que? */ + { + tmptok[i2] = linea_actual[i]; + i2++; + i++; + } + +tmptok[i2] = '\0'; + +krtrim(s2nd_param, tmptok); + +/* ----------- interpretacion ----------- */ + +/* recorro la lista en busca del comando a usar */ +i = 0; + while (cmd_list[i].comando != NULL && cmd_list[i].proc != NULL) + { + /* NOTA: cambiar strcmp x stricmp para ignorar mayus/minus, pero + no es ANSI ni POSIX */ + if (strcmp(comando_actual, cmd_list[i].comando) == 0) + { + /* Tiene suficientes parametros? */ + if (c_str_param < cmd_list[i].min_params && c_int_param < cmd_list[i].min_params) + { + sprintf(tmptok,"ERROR:\ncinema.c:\nscript:linea(%d)='%s'\nInsuficientes parametros (requiere %d)!\n", n_linea_actual,linea_actual,cmd_list[i].min_params); + levantar_error(tmptok); + } + + /* llamar a la funcion, devuelven -1 en error */ + if ( (*cmd_list[i].proc)() ) + { + sprintf(tmptok,"ERROR:\ncinema.c:\nscript:linea(%d)='%s'\nEl comando '%s' fallo\nPosibles parametros incorrectos o falta de objetos...\n", n_linea_actual,linea_actual,cmd_list[i].comando); + levantar_error(tmptok); + } + + // ver si el usuario cancelo + if (keypressed() && (key[KEY_ESC] || key[KEY_ENTER] || key[KEY_SPACE]) ) + return TRUE; + else + return 0; /* termino, proxima linea please... */ + } + i++; + } + +/* Comando no reconocido! SHIT! */ +sprintf(tmptok, "ERROR:\ncinema.c:\nscript:linea(%d)='%s'\nComando no reconocido!\n", n_linea_actual, linea_actual); +levantar_error(tmptok); + +return 0; +} +#endif diff --git a/src/clima.c b/src/clima.c new file mode 100644 index 0000000..de89a9f --- /dev/null +++ b/src/clima.c @@ -0,0 +1,172 @@ +// ------------------------------------ +// clima.c +// ------------------------------------ +// Modulo de efectos climaticos +// Por Kronoman +// En memoria de mi querido padre +// Copyright (c) 2002, Kronoman +// ------------------------------------ + + +#include +#include "clima.h" +#include "azar.h" +#include "global.h" + +static CLIMA_P clima_p[MAX_CLIMA_P]; // contenedor de particulas +static int clima_cant = 0; // cantidad de particulas 0..MAX_CLIMA_P + +// auxiliar que reinicia una particula individual +// parametros: +// idem a init_clima, +// i es el indice de la particula +static void reinit_clima_part(BITMAP *bmp, int c, int t, int d, int i ) +{ + int c2; + int minx = 50, miny = 50 , maxx = 100 , maxy = 150; // velocidades minimas y maximas + + // info extra + clima_p[i].t = t; + clima_p[i].d = d; + + // iniciar coordenadas de las particulas y direccion + clima_p[i].y = itofix( rand_ex(0, bmp->h) ); + clima_p[i].x = itofix( rand_ex(0, bmp->w) ); + + // color y radio + switch (t) + { + case 0: // lluvia + c2 = rand_ex(200, 255); + clima_p[i].col = makecol(0,128,c2); // tonos de azul + clima_p[i].r = 1; + minx = 80; + maxx = 120; + miny = 60; + maxy = 180; + break; + + case 1: // nieve + c2 = rand_ex(192, 255); + clima_p[i].col = makecol(c2,c2,c2); // tono de gris + clima_p[i].r = rand_ex(1,5); // radio + minx = 40; + maxx = 110; + miny = 50; + maxy = 150; + break; + + default: // error, el tipo no existe, no poner clima + clima_cant = 0; + return; + break; + } + +// velocidad de particulas + clima_p[i].dx = ftofix( (float)rand_ex(minx, maxx) / 10.0); + clima_p[i].dy = ftofix( (float)rand_ex(miny, maxy) / 10.0); + +// si hay que ir a la izquierda... +if (d == 0) clima_p[i].dx = fixmul(clima_p[i].dx , itofix(-1)); // a la izquierda + +} + +// Inicializa el clima +// Parametros: +// bmp = bitmap de buffer +// c = cantidad de particulas +// t = tipo: 0 = lluvia, 1 = nieve, etc +// d = direccion de caida: 0 = izquierda, 1 = derecha +// +void init_clima(BITMAP *bmp, int c, int t, int d) +{ +int i; +if (c < 1 || c > MAX_CLIMA_P) + { + clima_cant = 0; + return; + } +// iniciar particulas + +for (i=0; i < c; i ++) +{ + reinit_clima_part(bmp, c, t, d, i ); +} // fin for + + clima_cant = c; +} + + +// mueve el clima +// parametros: +// bmp = bitmap de uso +void mover_clima(BITMAP *bmp) +{ +int i; + for (i=0; i < clima_cant; i ++) + { + // mover clima + clima_p[i].x = fixadd(clima_p[i].x, clima_p[i].dx); + clima_p[i].y = fixadd(clima_p[i].y, clima_p[i].dy); + // reiniciar particula si se sale + if (clima_p[i].x < 0 || fixtoi(clima_p[i].x) > bmp->w || + clima_p[i].y < 0 || fixtoi(clima_p[i].y) > bmp->h) + { + reinit_clima_part(bmp, clima_cant, clima_p[i].t, clima_p[i].d, i ); + } + } // fin for +} + + +// dibuja el clima +// parametros: +// bmp = bitmap de uso +void dibuja_clima(BITMAP *bmp) +{ +int i; + for (i=0; i < clima_cant; i ++) + { + switch (clima_p[i].t) + { + case 0: // lluvia + + if (nivel_detalle > 9) + { + drawing_mode(DRAW_MODE_TRANS, NULL, 0,0); // lluvia transparente, cool! + triangle(bmp, + fixtoi(clima_p[i].x), + fixtoi(clima_p[i].y), + fixtoi(fixadd(clima_p[i].x, clima_p[i].dx)), + fixtoi(fixadd(clima_p[i].y, clima_p[i].dy)), + fixtoi(clima_p[i].x), + fixtoi(clima_p[i].y)+(rand()%4)+1, + clima_p[i].col); + solid_mode(); + } + else + { + line(bmp, + fixtoi(clima_p[i].x), + fixtoi(clima_p[i].y), + fixtoi(fixadd(clima_p[i].x, clima_p[i].dx)), + fixtoi(fixadd(clima_p[i].y, clima_p[i].dy)), + clima_p[i].col); + } + break; + + case 1: // nieve + circlefill(bmp, + fixtoi(clima_p[i].x), + fixtoi(clima_p[i].y), + clima_p[i].r, + clima_p[i].col); + break; + + default: // error, el tipo no existe, no dibujar + break; + } + } // fin for + + +} + diff --git a/src/combo.c b/src/combo.c new file mode 100644 index 0000000..0e7c310 --- /dev/null +++ b/src/combo.c @@ -0,0 +1,117 @@ +// -------------------------------------------------------- +// combo.c +// -------------------------------------------------------- +// Copyright (c) Kronoman +// En memoria de mi querido padre +// -------------------------------------------------------- +// Esto contiene combos para agregar explosiones+particulas +// y tocar los sonidos, musica, etc +// -------------------------------------------------------- +#ifndef COMBO_C +#define COMBO_C + +#include "allegro.h" +#include "partic.h" +#include "explos.h" +#include "azar.h" +#include "combo.h" +#include "global.h" +/* + agrega muchas particulas a la vez + cant es la cantidad + si col < 0, usara colores en gama de fuego (naranjas) +*/ +void poner_muchas_particulas( int x, int y, + int dx, int dy, + int vida, + int col, int r, int t, + BITMAP *spr, + int cant ) +{ +int i, c2; +c2 = col; + +/* si el nivel de detalle es bajo, limita la cantidad de particulas a 10 por round */ +if (nivel_detalle < 4 && cant > 10) cant = 10; +if (nivel_detalle < 2 && cant > 5) cant = 5; + +for (i = 0; i < cant; i++) + { + if (col < 0) c2 = makecol(255,rand()%255,0); + + agrega_particula( itofix(x), itofix(y), + ftofix((rand_ex(-100*dx, 100*dx))/100.0), ftofix((rand_ex(-100*dy, 100*dy))/100.0), + rand_ex(vida/4, vida), + c2, rand_ex(r/2,r)+1, t,0,0, + spr ); + } +} + +/* + agrega una explosion y particulas en x,y + con cantidad c y radio r (tambien indica duracion particulas * 2) + las particulas son trozos de nave y fuego + el radio para la explosion es el ancho/alto en pixeles... + si bmpp es !=0, pondra chispas con bitmaps tambien (Explosion final de algo grande) + */ +void poner_explosion_nave(int x, int y, int c, int r, int bmpp) +{ + +/* DEBUG: funcion mal hecha, no agrega bitmaps, solo poligonos */ +poner_muchas_particulas( x, y, + 5, 5, + r*2, + -1, 4, 3, + NULL, + c ); + + +pone_explo_pixel(&ptr_explo_arriba, x, y, r, r*2, ftofix(0.01)); + +if (bmpp && nivel_detalle > 7 ) { /* particulas con bitmaps */ + int z1; + for (z1 = 0; z1 < 3; z1++) + poner_muchas_particulas( x, y, + 5, 5, + r*rand_ex(2, 4), + -1, 4, 3, + particula_cache_bmp[z1], + c/rand_ex(2,3) ); /* poner 1/3 o 1/2 de particulas */ + } + +} + +/* +Esta funcion coloca una explosion en x,y +con radio r, el radio expresado en PIXELS! +v es la vida, v2 la combustion +NOTA: la explosion se limita en tama~o para no sobrecargar el juego +NOTA: pasarle el puntero a la capa de explosion con &puntero! +*/ +void pone_explo_pixel(EXPLOSION **explo, int x, int y, int r, int v, fixed v2) +{ +float rpx; /* para calculos luego */ +BITMAP *tmp; + +/* Limitar a 150 pixels de radio */ +if (r > 150) r= 150; + +if (nivel_detalle < 2 && r > 50) r = 50; /* el detalle limita el tama~o tambien */ + +/* explosion, calculo la proporcion entre pixeles y el tama~o del + sprite de la explosion y luego la agrego */ + +tmp = explo_cache_bmp[rand()%3]; +rpx = (float)r / (float)tmp->w; + +agrega_explosion( explo, + itofix(x), itofix(y), + 0,0, + v, + ftofix(rpx), v2, + rand()%255, + tmp ); + +} + +#endif diff --git a/src/config.c b/src/config.c new file mode 100644 index 0000000..b1d136d --- /dev/null +++ b/src/config.c @@ -0,0 +1,77 @@ +// ------------------------------------------------------------- +// config.c +// ------------------------------------------------------------- +// Se encarga de cargar / salvar la configuracion de Kraptor +// Por Kronoman +// Copyright (c) 2003, Kronoman +// En memoria de mi querido padre +// ------------------------------------------------------------- + +#include +#include "jugador.h" +#include "config.h" +#include "global.h" + +void cargar_configuracion() +{ + set_config_file("kraptor.cfg"); + teclado_jug.arr = get_config_int("kraptor_keyboard", "arr", teclado_jug.arr); + teclado_jug.abj = get_config_int("kraptor_keyboard", "abj", teclado_jug.abj); + teclado_jug.izq = get_config_int("kraptor_keyboard", "izq", teclado_jug.izq); + teclado_jug.der = get_config_int("kraptor_keyboard", "der", teclado_jug.der); + teclado_jug.sht = get_config_int("kraptor_keyboard", "sht", teclado_jug.sht); + teclado_jug.wpn = get_config_int("kraptor_keyboard", "wpn", teclado_jug.wpn); + teclado_jug.bmb = get_config_int("kraptor_keyboard", "bmb", teclado_jug.bmb); + + nivel_detalle = get_config_int("kraptor_detalle", "nivel_detalle", nivel_detalle); + detalle_automatico = get_config_int("kraptor_detalle", "detalle_automatico", detalle_automatico); + quiere_videos = get_config_int("kraptor_detalle", "quiere_videos", quiere_videos); + + quiere_snd = get_config_int("kraptor_snd", "quiere_snd", quiere_snd); + volumen_sonido = get_config_int("kraptor_snd", "volumen_sonido", volumen_sonido); + quiere_musica = get_config_int("kraptor_snd", "quiere_musica", quiere_musica); + volumen_musica = get_config_int("kraptor_snd", "volumen_musica", volumen_musica); + + KRONO_QUIERE_DEBUG = get_config_int("KRONO_QUIERE_DEBUG", "KRONO_QUIERE_DEBUG", KRONO_QUIERE_DEBUG); + quiere_usar_joystick = get_config_int("kraptor_joystick", "quiere_usar_joystick", quiere_usar_joystick); + numero_de_joystick = get_config_int("kraptor_joystick", "numero_de_joystick", numero_de_joystick); + + + quiere_usar_mouse = get_config_int("kraptor_mouse", "quiere_usar_mouse", quiere_usar_mouse); + mouse_velocidad = get_config_int("kraptor_mouse", "mouse_velocidad", mouse_velocidad); + +// load_joystick_data(NULL); // esto me dio problemas la primera vez que lo use... ojo + + +} + +void salvar_configuracion() +{ + set_config_file("kraptor.cfg"); + + set_config_int("kraptor_keyboard", "arr", teclado_jug.arr); + set_config_int("kraptor_keyboard", "abj", teclado_jug.abj); + set_config_int("kraptor_keyboard", "izq", teclado_jug.izq); + set_config_int("kraptor_keyboard", "der", teclado_jug.der); + set_config_int("kraptor_keyboard", "sht", teclado_jug.sht); + set_config_int("kraptor_keyboard", "wpn", teclado_jug.wpn); + set_config_int("kraptor_keyboard", "bmb", teclado_jug.bmb); + + set_config_int("kraptor_detalle", "nivel_detalle", nivel_detalle); + set_config_int("kraptor_detalle", "quiere_videos", quiere_videos); + set_config_int("kraptor_detalle", "detalle_automatico", detalle_automatico); + + set_config_int("kraptor_snd", "quiere_snd", quiere_snd); + set_config_int("kraptor_snd", "volumen_sonido", volumen_sonido); + set_config_int("kraptor_snd", "quiere_musica", quiere_musica); + set_config_int("kraptor_snd", "volumen_musica", volumen_musica); + set_config_int("KRONO_QUIERE_DEBUG", "KRONO_QUIERE_DEBUG", KRONO_QUIERE_DEBUG); + + set_config_int("kraptor_joystick", "quiere_usar_joystick", quiere_usar_joystick); + set_config_int("kraptor_joystick", "numero_de_joystick", numero_de_joystick); + + set_config_int("kraptor_mouse", "quiere_usar_mouse", quiere_usar_mouse); + set_config_int("kraptor_mouse", "mouse_velocidad", mouse_velocidad); + +// save_joystick_data(NULL); // esto me dio problemas la primera vez que lo use... ojo +} diff --git a/src/data.c b/src/data.c new file mode 100644 index 0000000..2eb37ba --- /dev/null +++ b/src/data.c @@ -0,0 +1,669 @@ +// -------------------------------------------------------- +// data.c +// -------------------------------------------------------- +// Copyright (c) Kronoman +// En memoria de mi querido padre +// -------------------------------------------------------- +// Esto se encarga de cargar y poner en memoria +// los datos leidos de disco. +// -------------------------------------------------------- +#ifndef DATA_C +#define DATA_C + +#include +#include +#include "allegro.h" + +#include "data.h" +#include "error.h" +#include "global.h" +#include "jugador.h" +#include "enemigo.h" +#include "pmask.h" +#include "sombras.h" +#include "datafind.h" +#include "explos.h" +#include "mapa.h" +#include "partic.h" +#include "menu.h" +#include "shopping.h" +#include "humo.h" +#include "ia.h" +#include "premio.h" +#include "filedata.h" +#include "bomba.h" + +/* Globales */ + + /* Este datafile contiene los datos principales del juego + tales como el script de secuencia de niveles, + graficos de menues, paleta de juego, armamento, + enemigos, sprites del jugador, premios, sonidos + Se carga al inicio del programa, y se descarga al salir + */ +DATAFILE *krapmain = NULL; + + /* Cada fondo y mapa de juego esta puesto por separado + en un DAT para evitar sobrecarga de memoria. + Este datafile es cargado y descargado a medida que pasan + los niveles. + Contiene el fondo (600x4000) y el mapa de juego + */ +DATAFILE *datmapa = NULL; + +/* Esto contiene los graficos para los menues */ +DATAFILE *datmenu = NULL; + +/* globales internas */ +static int byte_acumulado = 0; /* auxiliar para contar bytes leidos (no necesario) */ + +/* Funcion interna callback, que muestra cuanto se ha leido... + en la esquina superior izquierda, usando colores + del GUI para el texto + La primera vez que es llamado (byte_acumulado == 0) dibuja una caja de texto + Esta dise~ado para no atrasar mucho la carga */ +static void cargar_callback(DATAFILE *d) +{ + if (byte_acumulado <= 0) + { + byte_acumulado = 0; + /* fondo */ + rectfill(screen, 0,0,SCREEN_W-1, (text_height(font)+5)*2, gui_bg_color); + /* sombra (negro) */ + rectfill(screen, 5,5,SCREEN_W-5, (text_height(font)+10)*2, makecol(0,0,0)); + /* borde */ + rect(screen, 0,0,SCREEN_W-1, (text_height(font)+5)*2, gui_fg_color); + } + + byte_acumulado += d->size; + text_mode(gui_bg_color); + textprintf(screen, font, 2, 2, gui_fg_color, "Wait please, loading..."); + textprintf(screen, font, 2, text_height(font)+4, gui_fg_color, "-> %d", byte_acumulado); +} + + +/* Esta funcion carga los datos principales del juego en memoria, + es decir, paletas, jugador, enemigo, IA, armamento + Afecta a *krapmain + MUESTRA UN MENSAJE DE CARGA EN PANTALLA! [ESQUINA SUP-IZQ] + */ +void cargar_datos_principales() +{ + DATAFILE *p = NULL; /* puntero de busqueda */ + int i, i2; /* para los fors */ + char tmpstr[1024], tmpstr2[1024]; /* uso general */ + + if (krapmain != NULL) unload_datafile(krapmain); + if (datmenu != NULL) unload_datafile(datmenu); + + set_color_conversion(COLORCONV_TOTAL | COLORCONV_KEEP_TRANS); + + /* colores para el callback que muestra el progreso de la carga */ + gui_fg_color = makecol(255,255,255); + gui_bg_color = makecol(0,0,0); + byte_acumulado = 0; /* contador para mostrar progreso */ + + /* primero, trato de cargar SOLO la paleta de juego, + esto es para poder convertir las imagenes a los bpp adecuados */ + krapmain = krono_load_datafile_object("krapmain.dat", "pal_game"); + if (krapmain == NULL) levantar_error("ERROR: no existe pal_game en krapmain.dat"); + + /* copiar la paleta a RAM ... */ + memcpy(pal_game, krapmain->dat, sizeof(PALETTE)); + + /* Paletas de colores y mapas de transparencias... [ya estan cargadas, hago calculos...] */ + set_palette(pal_game); /* la seteo, la precisa la sombra... */ + + /* Crear mapa de transparencia de 8 bits */ + create_trans_table(&tabla_transparencia, pal_game, 128,128,128, NULL); + color_map = &tabla_transparencia; /* la rutina de sombras la precisa! */ + + /* Crear mapa RGB de 8 bits */ + create_rgb_table(&tabla_RGB, pal_game, NULL); + rgb_map = &tabla_RGB; + + /* Crear mapa para 'quemado' del fondo */ + create_color_table(&tabla_quemado, + pal_game, + crear_mapa_quemazon, + NULL); + + /* ya no preciso mas la paleta en RAM */ + unload_datafile_object(krapmain); + krapmain = NULL; + + /* Cargo el cache de inteligencia artificial */ + hacer_chache_ia("ia.dat"); + + /* Ahora si, cargar TODO el archivo de datos */ + gui_bg_color = makecol(0,0,0); gui_fg_color = makecol(255,255,255); // colores para la info de carga + krapmain = krono_load_datafile_callback("krapmain.dat", cargar_callback); + if (krapmain == NULL) levantar_error("ERROR: no se pudo cargar krapmain.dat"); + + /* DEBUG: falta ajustar datafile al modo de video actual */ + fixup_datafile(krapmain); + + p = find_datafile_object(krapmain, "gamescript"); + if (p == NULL) levantar_error("ERROR: el gamescript no esta definido en krapmain.dat"); + + set_config_data((char *)p->dat, p->size); + + + /* obtener la cinematica de introduccion al primer nivel */ + sprintf(game_intro_cine, "%s", get_config_string("game_intro", "cine", "null")); + + /* obtener la cinematica de game over */ + sprintf(game_over_cine, "%s", get_config_string("game_over", "cine", "null")); + + /* font para el 'hud' */ + p = find_datafile_object(krapmain, "hud_font"); + if (p == NULL) + hud_font = font_backup; + else + hud_font = (FONT *)p->dat; + + /* Cargar explosiones, particulas, sonidos y sprite quemador en cache */ + for (i = 0; i < 3; i++) + { + sprintf(tmpstr,"explo_bmp_%d", i); + p = find_datafile_object_type(krapmain, tmpstr, DAT_BITMAP); + if (p == NULL) levantar_error("ERROR: falta un objeto explo_bmp_[0..2]"); + explo_cache_bmp[i] = (BITMAP *)p->dat; + + sprintf(tmpstr,"explo_snd_%d", i); + p = find_datafile_object_type(krapmain, tmpstr, DAT_SAMPLE); + if (p == NULL) levantar_error("ERROR: falta un objeto explo_snd_[0..2]"); + explo_cache_snd[i] = (SAMPLE *)p->dat; + explo_cache_snd[i]->priority = 30; /* prioridad baja a las explosiones */ + + sprintf(tmpstr,"chispa_%d", i); + p = find_datafile_object_type(krapmain, tmpstr, DAT_BITMAP); + if (p == NULL) levantar_error("ERROR: falta un objeto chispa_[0..2]"); + particula_cache_bmp[i] = (BITMAP *)p->dat; + + sprintf(tmpstr,"burn_%d", i); + p = find_datafile_object_type(krapmain, tmpstr, DAT_BITMAP); + if (p == NULL) levantar_error("ERROR: falta un objeto burn_[0..2]"); + burn_cache_bmp[i] = (BITMAP *)p->dat; + + } + // Cargar humo en cache + p = find_datafile_object_type(krapmain, "humo", DAT_BITMAP); + if (p == NULL) + humo_spr = NULL; + else + humo_spr = (BITMAP *)p->dat; + + + /* Script del jugador a partir de aqui */ + + p = find_datafile_object(krapmain, "jugador"); + if (p == NULL) levantar_error("ERROR: el jugador no esta definido en krapmain.dat"); + + set_config_data((char *)p->dat, p->size); + + /* Cargar sprites del jugador */ + for (i = 0; i < 3; i++) + { + sprintf(tmpstr,"spr_%d", i); + + p = find_datafile_object_type(krapmain, get_config_string("jugador", tmpstr, "null"), DAT_BITMAP); + if (p == NULL) levantar_error("ERROR: en el jugador: spr_* no esta definido en krapmain.dat"); + jugador.spr[i] = (BITMAP *)p->dat; + + jugador.spr[i+3] = create_bitmap(jugador.spr[i]->w * 0.8, jugador.spr[i]->h * 0.8); + hacer_sombra(jugador.spr[i], jugador.spr[i+3]); + } + + /* dinero y bombas al iniciar un nuevo juego */ + jugador.init_money = get_config_int("JUGADOR","init_money", 0); + jugador.init_bombas = get_config_int("JUGADOR","init_bombas", 0); + + /* reparacion de la nave */ + jugador.reparar_cantidad = get_config_int("JUGADOR_REPARAR","cantidad", 10); + jugador.reparar_precio = get_config_int("JUGADOR_REPARAR","precio" , 1); + sprintf(jugador.reparar_desc,"%s", get_config_string("JUGADOR_REPARAR", "desc", "Fix the ship") ); + + p = find_datafile_object_type(krapmain, get_config_string("JUGADOR_REPARAR", "bmp", "null"), DAT_BITMAP); + if (p == NULL) + jugador.reparar_bmp = NULL; + else + jugador.reparar_bmp = (BITMAP *)p->dat; + + /* bombas especiales de la nave */ + jugador.bomba_cantidad = get_config_int("JUGADOR_BOMBA_ESPECIAL","cantidad", 10); + jugador.bomba_precio = get_config_int("JUGADOR_BOMBA_ESPECIAL","precio" , 10); + jugador.max_bombas = get_config_int("JUGADOR_BOMBA_ESPECIAL","max_ammo" , 5); + sprintf(jugador.bomba_desc,"%s", get_config_string("JUGADOR_BOMBA_ESPECIAL", "desc", "Special bomb") ); + + p = find_datafile_object_type(krapmain, get_config_string("JUGADOR_BOMBA_ESPECIAL", "bmp", "null"), DAT_BITMAP); + if (p == NULL) + jugador.bomba_bmp = NULL; + else + jugador.bomba_bmp = (BITMAP *)p->dat; + + p = find_datafile_object_type(krapmain, get_config_string("JUGADOR_BOMBA_ESPECIAL", "bomba_sonido", "null"), DAT_SAMPLE); + if (p == NULL) + bomba_sonido = NULL; + else + bomba_sonido = (SAMPLE *)p->dat; + + + /* mascara de colision del jugador */ + jugador.mask = create_allegro_pmask(jugador.spr[1]); + + + /* Armamento del jugador */ + for (i=0; i < MAX_ARM_CLASS; i++) + { + sprintf(tmpstr,"ARMA_%d", i); + + arma_tipo[i].arma = NULL; + p = find_datafile_object_type(krapmain, get_config_string(tmpstr, "arma", "null"), DAT_BITMAP); + if (p != NULL ) arma_tipo[i].arma = (BITMAP *)p->dat; + + sprintf(arma_tipo[i].desc,"%s", get_config_string(tmpstr, "desc", "null")); + sprintf(arma_tipo[i].desc_short,"%s", get_config_string(tmpstr, "desc_short", "null")); + arma_tipo[i].desc[2048] = '\0'; + arma_tipo[i].desc_short[20] = '\0'; + + arma_tipo[i].precio = get_config_int(tmpstr, "precio", -1); + arma_tipo[i].cant_ammo = get_config_int(tmpstr, "cant_ammo", 0); + arma_tipo[i].cant_ammo_max = get_config_int(tmpstr, "cant_ammo_max", 0); + + arma_tipo[i].spr = NULL; + p = find_datafile_object_type(krapmain, get_config_string(tmpstr, "spr", "null"), DAT_BITMAP); + if (p != NULL) arma_tipo[i].spr = (BITMAP *)p->dat; + + arma_tipo[i].mask = NULL; + + if (arma_tipo[i].spr != NULL) + { + arma_tipo[i].mask = create_allegro_pmask(arma_tipo[i].spr); + } + + arma_tipo[i].snd[0] = NULL; + p = find_datafile_object_type(krapmain, get_config_string(tmpstr, "snd_0", "null"), DAT_SAMPLE); + if (p != NULL) + { + arma_tipo[i].snd[0] = (SAMPLE *)p->dat; + arma_tipo[i].snd[0]->priority = 140; /* prioridad */ + } + + arma_tipo[i].snd[1] = NULL; + p = find_datafile_object_type(krapmain, get_config_string(tmpstr, "snd_1", "null"), DAT_SAMPLE); + if (p != NULL) + { + arma_tipo[i].snd[1] = (SAMPLE *)p->dat; + arma_tipo[i].snd[1]->priority = 50; /* prioridad */ + } + + arma_tipo[i].vx = ftofix(get_config_float(tmpstr,"vx", 0.0)); + arma_tipo[i].vy = ftofix(get_config_float(tmpstr,"vy", 0.0)); + arma_tipo[i].vida = get_config_int(tmpstr,"vida", -1); + arma_tipo[i].punch = get_config_int(tmpstr,"punch", 0); + arma_tipo[i].firerate = get_config_int(tmpstr,"firerate", 0); + arma_tipo[i].t = get_config_int(tmpstr,"t", 0); + + /* Estela del disparo... */ + arma_tipo[i].est_vida[0] = get_config_int(tmpstr, "est_vida_min", 0); + arma_tipo[i].est_vida[1] = get_config_int(tmpstr, "est_vida_max", 0); + arma_tipo[i].est_cant[0] = get_config_int(tmpstr, "est_cant_min", 0); + arma_tipo[i].est_cant[1] = get_config_int(tmpstr, "est_cant_max", 0); + + arma_tipo[i].est_color[0][0] = get_config_int(tmpstr, "est_color_r_min", 0); + arma_tipo[i].est_color[0][1] = get_config_int(tmpstr, "est_color_r_max", 0); + arma_tipo[i].est_color[1][0] = get_config_int(tmpstr, "est_color_g_min", 0); + arma_tipo[i].est_color[1][1] = get_config_int(tmpstr, "est_color_g_max", 0); + arma_tipo[i].est_color[2][0] = get_config_int(tmpstr, "est_color_b_min", 0); + arma_tipo[i].est_color[2][1] = get_config_int(tmpstr, "est_color_b_max", 0); + + arma_tipo[i].est_dx[0] = get_config_int(tmpstr, "est_dx_min", 0); + arma_tipo[i].est_dx[1] = get_config_int(tmpstr, "est_dx_max", 0); + + arma_tipo[i].est_dy[0] = get_config_int(tmpstr, "est_dy_min", 0); + arma_tipo[i].est_dy[1] = get_config_int(tmpstr, "est_dy_max", 0); + + arma_tipo[i].est_tipo[0] = get_config_int(tmpstr, "est_tipo_min", 0); + arma_tipo[i].est_tipo[1] = get_config_int(tmpstr, "est_tipo_max", 0); + + arma_tipo[i].est_rad[0] = get_config_int(tmpstr, "est_rad_min", 1); + arma_tipo[i].est_rad[1] = get_config_int(tmpstr, "est_rad_max", 2); + + arma_tipo[i].est_transp = get_config_int(tmpstr, "est_transp", 0); + } + + /* Cargar premios */ + p = find_datafile_object(krapmain, "premios"); + if (p == NULL) levantar_error("ERROR: los premios no estan definidos en krapmain.dat"); + set_config_data((char *)p->dat, p->size); + + for (i = 0; i < MAX_PREMIO_CLASS; i++) + { + sprintf(tmpstr,"PREMIO_%d", i); + premio_class[i].premiar = get_config_int(tmpstr,"premiar", -666); + premio_class[i].cantidad = get_config_int(tmpstr,"cantidad", 0); + premio_class[i].vida = get_config_int(tmpstr,"vida", 0); + + // Obtener bitmap + p = find_datafile_object_type(krapmain, get_config_string(tmpstr, "sprite", "null"), DAT_BITMAP); + if (p != NULL) + premio_class[i].sprite = (BITMAP *)p->dat; + else + premio_class[i].sprite = NULL; + + // obtener sonido + p = find_datafile_object_type(krapmain, get_config_string(tmpstr, "sonido", "null"), DAT_SAMPLE); + if (p != NULL) + premio_class[i].sonido = (SAMPLE *)p->dat; + else + premio_class[i].sonido = NULL; + + } + + /* Script de enemigos a partir de aqui */ + + /* Cargar clases de enemigos */ + p = find_datafile_object(krapmain, "enemigos"); + if (p == NULL) levantar_error("ERROR: los enemigos no estan definidos en krapmain.dat"); + set_config_data((char *)p->dat, p->size); + + /* Cargar enemigos, tipo de IA que le corresponde, y tipos de armas */ + for (i=0; i < MAX_E_CLASS; i++) + { + + /* Seccion ENEMIGO_n */ + sprintf(tmpstr,"ENEMIGO_%d", i); + + enem_t[i].vida = get_config_int(tmpstr,"vida", -1); + + enem_t[i].peso = get_config_int(tmpstr,"peso", 0); + + enem_t[i].dinero = get_config_int(tmpstr,"dinero", 0); + + /* premios que suelta el enemigo */ + enem_t[i].premio_idx = get_config_int(tmpstr,"premio_idx", -1); + enem_t[i].premio_prob = get_config_int(tmpstr,"premio_prob", -1); + + enem_t[i].spr_delay = get_config_int(tmpstr,"spr_delay", 10); //delay de animacion + + // bytecodes de tipo de IA + enem_t[i].ia_node = buscar_lista_ia(get_config_string(tmpstr,"tipo_ia","null")); + enem_t[i].ia_azar = get_config_int(tmpstr,"ia_azar", 0); // ia azaroza? + enem_t[i].ia_boss = get_config_int(tmpstr,"ia_boss", 0); // ia boss? + + // cargar los sprites de animacion del enemigo + for (i2 = 0; i2<4; i2++) + { + enem_t[i].spr[i2] = NULL; + sprintf(tmpstr2, "spr_%d", i2); + p = find_datafile_object_type(krapmain, get_config_string(tmpstr, tmpstr2, "null"), DAT_BITMAP); + // intentar con spr, si no existe spr_0 + if (i2 == 0 && p == NULL) p = find_datafile_object_type(krapmain, get_config_string(tmpstr, "spr", "null"), DAT_BITMAP); + // cuando es el primer sprite, se obvia si no existe, en caso contrario, el resto se asigna al primero + if (p != NULL) + { enem_t[i].spr[i2] = (BITMAP *)p->dat; } + else + { + if (i2 == 0) + { enem_t[i].spr[i2] = NULL; } // no hay sprite inicial + else + { enem_t[i].spr[i2] = enem_t[i].spr[0]; } // si no existe, tomo el primero + } + + enem_t[i].mask[i2] = NULL; + if (enem_t[i].spr[i2] != NULL) /* sombra y mascara de colision */ + { + enem_t[i].spr_shadow[i2] = create_bitmap(enem_t[i].spr[i2]->w * 0.8, enem_t[i].spr[i2]->h * 0.8); + hacer_sombra(enem_t[i].spr[i2] , enem_t[i].spr_shadow[i2]); // sombra + enem_t[i].mask[i2] = create_allegro_pmask(enem_t[i].spr[i2]); // mascara de colision + } + } + + /*------ Seccion ARMA_n ------*/ + sprintf(tmpstr,"ARMA_%d", i); + + arma_ene[i].spr = NULL; + p = find_datafile_object_type(krapmain, get_config_string(tmpstr, "spr", "null"), DAT_BITMAP); + if (p != NULL) arma_ene[i].spr = (BITMAP *)p->dat; + + arma_ene[i].mask = NULL; + + if (arma_ene[i].spr != NULL) + { + arma_ene[i].mask = create_allegro_pmask(arma_ene[i].spr); + } + + arma_ene[i].snd[0] = NULL; + arma_ene[i].snd[1] = NULL; + + p = find_datafile_object_type(krapmain, get_config_string(tmpstr, "snd_0", "null"), DAT_SAMPLE); + if (p != NULL) + { + arma_ene[i].snd[0] = (SAMPLE *)p->dat; + arma_ene[i].snd[0]->priority = 100; /* prioridad */ + } + + p = find_datafile_object_type(krapmain, get_config_string(tmpstr, "snd_1", "null"), DAT_SAMPLE); + if (p != NULL) + { + arma_ene[i].snd[1] = (SAMPLE *)p->dat; + arma_ene[i].snd[1]->priority = 40; /* prioridad */ + } + + arma_ene[i].vx = ftofix(get_config_float(tmpstr,"vx", 0.0)); + arma_ene[i].vy = ftofix(get_config_float(tmpstr,"vy", 0.0)); + arma_ene[i].vida = get_config_int(tmpstr,"vida", -1); + arma_ene[i].punch = get_config_int(tmpstr,"punch", 0); + arma_ene[i].t = get_config_int(tmpstr,"t", 0); + + /* Estela del disparo... */ + arma_ene[i].est_vida[0] = get_config_int(tmpstr, "est_vida_min", 0); + arma_ene[i].est_vida[1] = get_config_int(tmpstr, "est_vida_max", 0); + arma_ene[i].est_cant[0] = get_config_int(tmpstr, "est_cant_min", 0); + arma_ene[i].est_cant[1] = get_config_int(tmpstr, "est_cant_max", 0); + + arma_ene[i].est_color[0][0] = get_config_int(tmpstr, "est_color_r_min", 0); + arma_ene[i].est_color[0][1] = get_config_int(tmpstr, "est_color_r_max", 0); + arma_ene[i].est_color[1][0] = get_config_int(tmpstr, "est_color_g_min", 0); + arma_ene[i].est_color[1][1] = get_config_int(tmpstr, "est_color_g_max", 0); + arma_ene[i].est_color[2][0] = get_config_int(tmpstr, "est_color_b_min", 0); + arma_ene[i].est_color[2][1] = get_config_int(tmpstr, "est_color_b_max", 0); + + arma_ene[i].est_dx[0] = get_config_int(tmpstr, "est_dx_min", 100); + arma_ene[i].est_dx[1] = get_config_int(tmpstr, "est_dx_max", 100); + + arma_ene[i].est_dy[0] = get_config_int(tmpstr, "est_dy_min", 0); + arma_ene[i].est_dy[1] = get_config_int(tmpstr, "est_dy_max", 0); + + arma_ene[i].est_tipo[0] = get_config_int(tmpstr, "est_tipo_min", 0); + arma_ene[i].est_tipo[1] = get_config_int(tmpstr, "est_tipo_max", 0); + + arma_ene[i].est_rad[0] = get_config_int(tmpstr, "est_rad_min", 1); + arma_ene[i].est_rad[1] = get_config_int(tmpstr, "est_rad_max", 2); + + arma_ene[i].est_transp = get_config_int(tmpstr, "est_transp", 0); + + } + + // Fondo del shopping + p = find_datafile_object_type(krapmain, "shop_bmp", DAT_BITMAP); + if (p == NULL) + shop_bmp = NULL; + else + shop_bmp = (BITMAP *)p->dat; + + + /* cargar los items del menu principal */ + if (datmenu != NULL) unload_datafile(datmenu); + gui_bg_color = makecol(0,0,0); gui_fg_color = makecol(255,255,255); // colores para la info de carga + datmenu = krono_load_datafile_callback("krapmnu.dat", cargar_callback); + if (datmenu == NULL) levantar_error("ERROR: no se pudo abrir 'krapmnu.dat'"); + + /* paleta de colores */ + p = find_datafile_object(datmenu, "main_menu_pal"); + if (p == NULL) levantar_error("ERROR: no se pudo obtener 'main_menu_pal'"); + + /* copiar la paleta a RAM ... */ + memcpy(pal_menu_main, p->dat, sizeof(PALETTE)); + + /* cargar archivo de ayuda (texto) */ + p = find_datafile_object(datmenu, "help_txt"); + if (p == NULL) + { texto_ayuda_juego = NULL; } + else + { + texto_ayuda_juego = (char *)p->dat; + /* esto es necesario, sino, no tiene fin la cadena! */ + texto_ayuda_juego[p->size - 1] = '\0'; + } + + /* acerca de... */ + p = find_datafile_object(datmenu, "about_txt"); + if (p == NULL) + { texto_acerca_de_juego = NULL; } + else + { + texto_acerca_de_juego = (char *)p->dat; + /* esto es necesario, sino, no tiene fin la cadena! */ + texto_acerca_de_juego[p->size - 1] = '\0'; + } + + /* imagen de acerca de... */ + p = find_datafile_object_type(datmenu, "about_bmp", DAT_BITMAP); + if (p == NULL) + acerca_de_bmp = NULL; + else + acerca_de_bmp = (BITMAP *)p->dat; + + /* cargo el bitmap de fondo */ + p = find_datafile_object_type(datmenu, "main_menu_bmp", DAT_BITMAP); + if (p == NULL) levantar_error("ERROR: no existe 'main_menu_bmp' en 'krapmnu.dat'"); + + bmp_menu_main = (BITMAP *)p->dat; + + /* fin de los items del menu */ + + /* DEBUG: en caso necesario agregar mas datos necesarios aqui */ + +} + + +/* + Esta funcion puede hacer 2 cosas: + - verificar si el proximo nivel existe + - o verificar si existe y cargar el nivel especificado en RAM + + parametros: + nivel => nivel a cargar + solo_verificar => 0 indica que cargue el nivel en RAM, + -1 que solo verifique + SIEMPRE son cargados los datos basicos del nivel (cinematicas, titulo) + + devuelve 0 si funciona, -1 si falla (el nivel no existe, o el archivo no existe) + + SI SE VA A CARGAR EL NIVEL: + MUESTRA UN MENSAJE DE CARGA EN PANTALLA! [ESQUINA SUP-IZQ] + + Nota: grilla de nivel/enemigos se guarda en enteros Intel 32 bits, para zafar en + todas las plataformas +*/ +int cargar_nivel(int nivel, int solo_verificar) +{ + DATAFILE *p = NULL; /* puntero de busqueda */ + PACKFILE *fp; // para leer las grillas + int xx, yy; // para leer las grillas + char tmpstr[1024]; // uso general + char tmpstr2[1024]; + + if (krapmain == NULL) return -1; + + p = find_datafile_object(krapmain, "gamescript"); + if (p == NULL) levantar_error("ERROR: el gamescript no esta definido en krapmain.dat"); + + set_config_data((char *)p->dat, p->size); + + sprintf(tmpstr,"nivel_%d", nivel); + + /* cargar siempre la info basica del nivel... (si no, las cinematicas no andan! )*/ + sprintf(info_nivel.level_dat, "%s", get_config_string(tmpstr, "level_dat", "null")); + sprintf(info_nivel.cine_in, "%s", get_config_string(tmpstr, "cine_in", "null")); + sprintf(info_nivel.cine_out, "%s", get_config_string(tmpstr, "cine_out", "null")); + sprintf(info_nivel.texto, "%s", get_config_string(tmpstr, "texto", "null")); + sprintf(info_nivel.titulo, "%s", get_config_string(tmpstr, "titulo", "null")); + info_nivel.clima_c = get_config_int(tmpstr, "clima_c", 0); + info_nivel.clima_t = get_config_int(tmpstr, "clima_t", 0); + info_nivel.clima_d = get_config_int(tmpstr, "clima_d", 0); + + info_nivel.musica = NULL; /* por ahora, no se si hay musica... */ + + /* Debo SOLO verificar si el nivel existe? */ + if (solo_verificar) return !exists(info_nivel.level_dat); + + /* ------ Cargar realmente en RAM el archivo... ------ */ + + /* colores para el callback que muestra el progreso de la carga */ + gui_fg_color = makecol(255,255,255); + gui_bg_color = makecol(0,0,0); + byte_acumulado = 0; /* contador para mostrar progreso */ + + if (datmapa != NULL) + { + unload_datafile(datmapa); + datmapa = NULL; + } + gui_bg_color = makecol(0,0,0); gui_fg_color = makecol(255,255,255); // colores para la info de carga + datmapa = krono_load_datafile_callback(info_nivel.level_dat, cargar_callback); + if (datmapa == NULL) return -1; /* fallo la carga del nivel */ + + /* copiarse las grillas */ + sprintf(tmpstr2, "%s#mapa_g", info_nivel.level_dat); // cargar el mapa_g + fp = pack_fopen(tmpstr2, F_READ); + if (fp == NULL) levantar_error("ERROR: no existe mapa_g en el nivel!"); + for (xx =0; xx < W_FONDO / W_GR; xx++) + for (yy =0; yy < H_FONDO / H_GR; yy++) + mapa_g[xx][yy] = pack_igetl(fp); + + pack_fclose(fp); + +// grilla de enemigos, con soporte para varias dificultades + sprintf(tmpstr2, "%s#enem_g_%d", info_nivel.level_dat, nivel_de_dificultad); + fp = pack_fopen(tmpstr2, F_READ); + if (fp == NULL) + { + sprintf(tmpstr2, "%s#enem_g", info_nivel.level_dat ); + fp = pack_fopen(tmpstr2, F_READ); + if (fp == NULL) levantar_error("ERROR: no existe enem_g en el nivel!"); + } + + for (xx =0; xx < W_FONDO / W_GR; xx++) + for (yy =0; yy < H_FONDO / H_GR; yy++) + enem_g[xx][yy] = pack_igetl(fp); + + pack_fclose(fp); + + /* obtener el fondo y ajustar dimensiones en un mapa nuevo... + esto ayuda a conservar espacio en disco, + para demos, permitiendo usar un fondo mas chico en disco! */ + + p = find_datafile_object(datmapa, "mapa_fondo"); + if (p == NULL) levantar_error("ERROR: no existe mapa_fondo en el nivel!"); + + mapa_fondo = create_bitmap(W_FONDO, H_FONDO); /* acordarse de liberar esto luego... en game.c */ + + if (mapa_fondo == NULL) levantar_error("ERROR: data.c:cargar_nivel()\nInsuficiente memoria RAM para cargar el mapa del nivel!\n(~2.3MB requeridos!)"); + + stretch_blit((BITMAP *)p->dat, mapa_fondo, 0, 0, + ((BITMAP *)p->dat)->w, ((BITMAP *)p->dat)->h, + 0, 0, + mapa_fondo->w, mapa_fondo->h); + + /* Tomo la musica del juego */ + info_nivel.musica = NULL; + p = find_datafile_object(datmapa, "musica"); + if (p != NULL) info_nivel.musica = (DUH *)p->dat; + + return 0; /* Todo bien, negrita... */ +} + +#endif diff --git a/src/datafind.c b/src/datafind.c new file mode 100644 index 0000000..c5fa192 --- /dev/null +++ b/src/datafind.c @@ -0,0 +1,182 @@ +// -------------------------------------------------------- +// datafind.c +// Funciones de busqueda avanzada de objetos dentro de un archivo DAT +// -------------------------------------------------------- +// Copyright (c) 2002, Kronoman +// Escrito por Kronoman - Republica Argentina +// En memoria de mi querido padre +// -------------------------------------------------------- +// Funcion para buscar un objeto en un datafile. +// Busca primero el verdadero, si no existe, busca por aproximacion!!! +// COOL! +// -------------------------------------------------------- + +#ifndef _KRONO_DATAFIND_C +#define _KRONO_DATAFIND_C + +#include +#include "datafind.h" + +// -------------------------------------------------------- +// fuzzy_find_datafile_object +// Busca un objeto por nombre aproximado en un archivo DAT +// basado en el codigo de allegro en el archivo datafile.c +// IGNORA MAYUSCULAS/MINUSCULAS +// IGNORA TIPO DE OBJETO (puede devolver cualquier tipo) +// -------------------------------------------------------- +DATAFILE *fuzzy_find_datafile_object(AL_CONST DATAFILE *dat, AL_CONST char *objectname) +{ + char name[512]; + char name2[512]; + int recurse = FALSE; + int pos, c; + + + // primero ver si hay un archivo con el mismo nombre en la manera estandard +// DATAFILE *tmp = find_datafile_object(dat, objectname); // debug +// if (tmp != NULL) return tmp; + + + // sacar el nombre de archivo + pos = 0; + + while ((c = ugetxc(&objectname)) != 0) { + if ((c == '#') || (c == '/') || (c == OTHER_PATH_SEPARATOR)) { + recurse = TRUE; + break; + } + pos += usetc(name+pos, c); + } + + usetc(name+pos, 0); + + ustrupr(name); // pasar a mayusculas + + // buscar el objeto pedido (busca nombre aproximado) + for (pos=0; dat[pos].type != DAT_END; pos++) { + // obtener nombre y pasarlo a mayusculas + ustrcpy(name2, get_datafile_property(dat+pos, DAT_NAME) ); + ustrupr(name2); + + if (ustrstr( name2 , name ) == NULL) { + if (recurse) { + if (dat[pos].type == DAT_FILE) + return fuzzy_find_datafile_object(dat[pos].dat, objectname); + else + return NULL; + } + } + else + return (DATAFILE*)dat+pos; // lo encontro + } + + // el objeto no esta... shit! + return NULL; +} + +// -------------------------------------------------------- +// find_datafile_object_type +// busca un objeto en un datafile del tipo requerido +// en type_required pasar el tipo, ejemplo: DAT_BITMAP +// -------------------------------------------------------- +DATAFILE *find_datafile_object_type(AL_CONST DATAFILE *dat, AL_CONST char *objectname, int type_required) +{ + char name[512]; + int recurse = FALSE; + int pos, c; + + // obtener el nombre de archivo + pos = 0; + + while ((c = ugetxc(&objectname)) != 0) { + if ((c == '#') || (c == '/') || (c == OTHER_PATH_SEPARATOR)) { + recurse = TRUE; + break; + } + pos += usetc(name+pos, c); + } + + usetc(name+pos, 0); + + // buscar el objeto + for (pos=0; dat[pos].type != DAT_END; pos++) { + if (ustricmp(name, get_datafile_property(dat+pos, DAT_NAME)) == 0) { + if (recurse) { + if (dat[pos].type == DAT_FILE) + return find_datafile_object_type(dat[pos].dat, objectname, type_required); + else + return NULL; + } + else + if (dat[pos].type == type_required) return (DATAFILE*)dat+pos; // lo encontro + } + } + + // no esta, shit... + return NULL; +} + + + +// -------------------------------------------------------- +// fuzzy_find_datafile_object_type +// Busca un objeto por nombre aproximado en un archivo DAT +// basado en el codigo de allegro en el archivo datafile.c +// IGNORA MAYUSCULAS/MINUSCULAS +// NO IGNORA TIPO DE OBJETO +// Pasar en type_required el tipo de objeto; ej: DAT_BITMAP +// -------------------------------------------------------- +DATAFILE *fuzzy_find_datafile_object_type(AL_CONST DATAFILE *dat, AL_CONST char *objectname, int type_required) +{ + char name[512]; + char name2[512]; + int recurse = FALSE; + int pos, c; + + + // primero ver si hay un archivo con el mismo nombre en la manera estandard +// DATAFILE *tmp = find_datafile_object_type(dat, objectname, type_required); +// if (tmp != NULL) return tmp; + + + // sacar el nombre de archivo + pos = 0; + + while ((c = ugetxc(&objectname)) != 0) { + if ((c == '#') || (c == '/') || (c == OTHER_PATH_SEPARATOR)) { + recurse = TRUE; + break; + } + pos += usetc(name+pos, c); + } + + usetc(name+pos, 0); + + ustrupr(name); // pasar a mayusculas + + // buscar el objeto pedido (busca nombre aproximado) + // se fija si el objeto coincide con el tipo requerido + + for (pos=0; dat[pos].type != DAT_END; pos++) { + // obtener nombre y pasarlo a mayusculas + ustrcpy(name2, get_datafile_property(dat+pos, DAT_NAME) ); + ustrupr(name2); + + if (ustrstr( name2 , name ) == NULL) { + if (recurse) { + if (dat[pos].type == DAT_FILE) + return fuzzy_find_datafile_object_type(dat[pos].dat, objectname, type_required); + else + return NULL; + } + } + else + if (dat[pos].type == type_required ) return (DATAFILE*)dat+pos; // lo encontro + } + + // el objeto no esta... shit! + return NULL; +} + + +#endif diff --git a/src/enemigo.c b/src/enemigo.c new file mode 100644 index 0000000..80e9ead --- /dev/null +++ b/src/enemigo.c @@ -0,0 +1,675 @@ +// -------------------------------------------------------- +// enemigo.c +// -------------------------------------------------------- +// Copyright (c) Kronoman +// En memoria de mi querido padre +// -------------------------------------------------------- +// Este modulo contiene todo lo relacionado con los enemigos +// Tal como movimiento, disparos, etc... +// -------------------------------------------------------- +#ifndef ENEMIGO_C +#define ENEMIGO_C + +#include +#include "allegro.h" +#include "pmask.h" +#include "azar.h" +#include "enemigo.h" +#include "kfbuffer.h" +#include "jugador.h" /* lo preciso para poder verificar + los disparos contra el jugador... jeje */ +#include "sombras.h" +#include "combo.h" +#include "partic.h" +#include "global.h" +#include "sonido.h" +#include "bomba.h" +#include "ia.h" +#include "premio.h" +#include "error.h" +/* GLOBALES */ +ARMA_ENE arma_ene[MAX_E_CLASS]; /* armamento enemigo */ +ENEM_T enem_t[MAX_E_CLASS]; /* tipos de enemigos */ +ENEMIGO *enemigo_1 = NULL; /* puntero al 1er enemigo activo */ +DISP_ENE *disp_ene_1 = NULL; /* puntero al 1er disparo activo */ + +/* esta variable NO es necesaria, solo la uso para + ver cuantos enemigos hay en memoria, y de esa manera, + revisar la performance... */ +int cant_enemigos_debug = 0; + +/* Agrega un enemigo en x, y de tipo 'tipo' */ +void agregar_enemigo(int x, int y, int tipo ) +{ + ENEMIGO *nueva = malloc(sizeof(ENEMIGO)); + nueva->next = enemigo_1; + enemigo_1 = nueva; + + if (nueva != NULL) /* si el malloc funciono, seteo los datos... */ + { + nueva->x = itofix(x); + nueva->y = itofix(y); + nueva->vida = enem_t[tipo].vida; /* que corta es la vida de un piloto enemigo... */ + nueva->ene_t = tipo; /* que somos? yankis gallinas o pilotos de verdad? */ + // resetear la IA + nueva->bytecode_actual = -1; // aun no ejecute nada, por eso -1 + nueva->bytecode_loop = 0; // empezar con la 1era instruccion + + nueva->ia_node = enem_t[tipo].ia_node; + // debo comenzar la IA en un punto al azar? + if (enem_t[tipo].ia_azar != 0) nueva->bytecode_actual = rand_ex(-1, nueva->ia_node->size-1); + + // animaciones, etc... + nueva->spr_actual = rand()%4; + nueva->spr_delay = 0; + } +} + +/* Esta funcion altera la IA del enemigo + llamar en cada ciclo... + */ +void IA_enemigo(ENEMIGO *ene) +{ + +// interpretar bytecodes de la IA +if (ene->ia_node == NULL) return; // no tiene IA, descerebrado... +if (ene->ia_node->size < 1) return; // IA vacia, que paso? + +ene->bytecode_loop--; // ejecute 1 instruccion + + +if (ene->bytecode_loop < 0) + { + // proxima instruccion + ene->bytecode_actual ++; + if (ene->bytecode_actual > ene->ia_node->size - 1) ene->bytecode_actual = 0; + if (ene->bytecode_actual > ene->ia_node->size-1) return; // seguridad... :) + ene->bytecode_loop = ene->ia_node->code[ene->bytecode_actual].loop; + + // copiar bytecode, solo campos importantes... el resto indeterminados... :) + ene->bytecode_exe.x1 = rand_ex(ene->ia_node->code[ene->bytecode_actual].x1, ene->ia_node->code[ene->bytecode_actual].x2); + ene->bytecode_exe.y1 = rand_ex(ene->ia_node->code[ene->bytecode_actual].y1, ene->ia_node->code[ene->bytecode_actual].y2); + + } + + +if (ene->bytecode_actual > ene->ia_node->size-1) return; // seguridad... :) + + // mover enemigo + ene->x = fixadd(ene->x, itofix(ene->bytecode_exe.x1)); + ene->y = fixadd(ene->y, itofix(ene->bytecode_exe.y1)); + + + /* debo disparar ? */ + if (ene->ia_node->code[ene->bytecode_actual].weapon > -1) + { + // cambio de arma del enemigo + ene->arma_actual = ene->ia_node->code[ene->bytecode_actual].weapon; + // disparar + agregar_disparo_ene(ene); + } + + +} + + +/* + Esta funcion actualiza los enemigos + Verifica colisiones con disparos de jugador y con el jugador mismo + Precisa saber el desplazamiento del fondo, 'fy' ya que + cuando el enemigo sale de pantalla, se elimina... + */ +void mover_enemigos(int fy) +{ + ENEMIGO **tmp_p = &enemigo_1; + DISP_JUG *tmpd = NULL; + ENEMIGO *tmp = NULL; + + cant_enemigos_debug = 0; /* DEBUG: innecesario */ + + while (*tmp_p) { + + cant_enemigos_debug++; /* DEBUG: innecesario */ + + tmp = *tmp_p; + /* hacer IA del enemigo */ + IA_enemigo(tmp); + + // animacion del enemigo + tmp->spr_delay--; + if (tmp->spr_delay < 0) + { + tmp->spr_delay = enem_t[tmp->ene_t].spr_delay; // reiniciar contador + tmp->spr_actual++; // cambiar sprite + if (tmp->spr_actual > 3) tmp->spr_actual = 0; + } + + + /* verificar colisiones... */ + + /* colision contra el jugador? */ + if (check_pmask_collision(enem_t[tmp->ene_t].mask[tmp->spr_actual], jugador.mask, + fixtoi(tmp->x), fixtoi(tmp->y), + fixtoi(jugador.x), fixtoi(jugador.y) ) != 0) + { + /* DEBUG: choco al jugador!, falta sonido! */ + + pone_explo_pixel(&ptr_explo_arriba, + fixtoi(tmp->x)+rand()%enem_t[tmp->ene_t].spr[tmp->spr_actual]->w, + fixtoi(tmp->y)+rand()%enem_t[tmp->ene_t].spr[tmp->spr_actual]->h, + rand()%enem_t[tmp->ene_t].spr[tmp->spr_actual]->w+enem_t[tmp->ene_t].spr[tmp->spr_actual]->w/3, + rand()%30+20, + ftofix(0.01)); + + jugador.vida -= enem_t[tmp->ene_t].peso + rand()%5; /* restar energia al jugador */ + tmp->vida -= rand()%5 + 5; /* restarme energia tambien */ + }; + + /* loop: + recorrer disparos del jugador + DEBUG: esto es muy lento!! */ + + tmpd = disp_jug_1; + while (tmpd) { + /* chequear colision, solo si el disparo esta activo, + de la manera hecha siguiente, si el disparo esta muerto, + evito comprobar la mascara, que tarda mas...*/ + + if ( tmpd->vida > 0) + if (check_pmask_collision(enem_t[tmp->ene_t].mask[tmp->spr_actual], arma_tipo[tmpd->arma].mask, + fixtoi(tmp->x), fixtoi(tmp->y), + fixtoi(tmpd->x), fixtoi(tmpd->y) ) != 0 ) + { + + /* DEBUG: choco al disparo del jugador, restar energia, etc! */ + poner_explosion_nave(fixtoi(tmpd->x), + fixtoi(tmpd->y), + rand()%20+20, rand()%10+5+arma_tipo[tmpd->arma].punch*2, 0); + + /* DEBUG: sonido del arma + del jugador pegandole al enemigo */ + tocar_sonido_paneado(fixtoi(tmpd->x), + arma_tipo[tmpd->arma].snd[1], + rand_ex(200,255), + rand_ex(900,1100)); + + + /* Esta comparacion es para NO pagarle mas de una vez al jugador + por la muerte... */ + if (tmp->vida > 0 ) + { + + tmp->vida -= arma_tipo[tmpd->arma].punch; /* restar energia al enemigo */ + + /* DEBUG: mato al enemigo */ + if (tmp->vida <= 0) + { + int ttt; + for (ttt=0; ttt < rand()%3 + enem_t[tmp->ene_t].peso/2+1; ttt++) + { + pone_explo_pixel(&ptr_explo_arriba, + fixtoi(tmp->x)+rand()%enem_t[tmp->ene_t].spr[tmp->spr_actual]->w, + fixtoi(tmp->y)+rand()%enem_t[tmp->ene_t].spr[tmp->spr_actual]->h, + rand()%enem_t[tmp->ene_t].spr[tmp->spr_actual]->w+enem_t[tmp->ene_t].spr[tmp->spr_actual]->w/3, + rand()%30+20, + ftofix(0.01)); + } + // Soltar premio, si lo hubiera... -DEBUG- + if ( (enem_t[tmp->ene_t].premio_idx > -1) && (rand()%100+1 < enem_t[tmp->ene_t].premio_prob ) ) + agrega_premio(enem_t[tmp->ene_t].premio_idx, tmp->x, tmp->y); + + // Pagar... + jugador.dinero += enem_t[tmp->ene_t].dinero; + } + } /* fin de no pagar 2 veces */ + + tmpd->vida = -1; /* eliminar disparo, la memoria + se libera en jugador.c */ + } /* fin chequear colision */ + + tmpd = tmpd->next; /* siguiente */ + + } /* fin loop de verificar disparos */ + + /* Si esta activa la bomba especial, restar energia progresivamente */ + if (bomba_esta_activa && tmp->vida > 0) + { + tmp->vida -= rand()%10+5; + if (tmp->vida < 1) + { + jugador.dinero += enem_t[tmp->ene_t].dinero; // pagar + tmp->vida = -1; // fuerzo que se 'combustione' completamente + } + } + + /* Ir combustionando el enemigo cuando muere (energia <= 0) */ + if (tmp->vida <= 0 ) + { + tmp->vida -= rand()%10+10; + + + /* Explosiones peque~as */ + if (rand()%150 < abs((tmp->vida * 100) / ENE_MUERTO) ) /* incremental al irse combustionando */ + { + /* sonido */ + if (rand()%10 < 5) + { + tocar_sonido_paneado(fixtoi(tmp->x), + explo_cache_snd[rand()%3], + rand_ex(128,255), + rand_ex(900, 1000)); + } + + pone_explo_pixel(&ptr_explo_arriba, + fixtoi(tmp->x)+rand()%enem_t[tmp->ene_t].spr[tmp->spr_actual]->w, + fixtoi(tmp->y)+rand()%enem_t[tmp->ene_t].spr[tmp->spr_actual]->h, + rand()%enem_t[tmp->ene_t].spr[tmp->spr_actual]->w+enem_t[tmp->ene_t].spr[tmp->spr_actual]->w/3, + rand()%30+10, + ftofix(0.01)); + + /* Descontrolar enemigo */ + // tmp->dx = (rand()%100 < 50) ? ftofix(MAX_VEL_E_X * (-1.0)) : ftofix(MAX_VEL_E_X); + // tmp->dy = (rand()%100 < 50) ? ftofix(MAX_VEL_E_Y * (-1.0)) : ftofix(MAX_VEL_E_Y); + } + + /* al aproximarse al final, recontra-explotar... */ + if (tmp->vida < (ENE_MUERTO / 10)*9 && nivel_detalle > 4) + { + pone_explo_pixel(&ptr_explo_arriba, + fixtoi(tmp->x)+enem_t[tmp->ene_t].spr[tmp->spr_actual]->w/2, + fixtoi(tmp->y)+enem_t[tmp->ene_t].spr[tmp->spr_actual]->h/2, + enem_t[tmp->ene_t].spr[tmp->spr_actual]->w+rand()%10, + rand()%10+10, + ftofix(0.01)); + + /* PARTICULAS Y PEDAZOS DE NAVES AL MORIR... */ + if (tmp->vida-10 <= ENE_MUERTO) + poner_explosion_nave(fixtoi(tmp->x)+enem_t[tmp->ene_t].spr[tmp->spr_actual]->w/2, + fixtoi(tmp->y)+enem_t[tmp->ene_t].spr[tmp->spr_actual]->h/2, + rand()%20+20, + rand()%10+5, -1); + } + } /* fin combustionar */ + + + /* verificar limites de pantalla visible */ + /* nota: la IA rebota en las X, queda cool. */ + if (tmp->x < 0) { tmp->x = 0; tmp->bytecode_exe.x1 *= -1; } + + if (fixtoi(tmp->x) > ANCHO_FB - enem_t[tmp->ene_t].spr[tmp->spr_actual]->w ) + { + tmp->x = itofix(ANCHO_FB - enem_t[tmp->ene_t].spr[tmp->spr_actual]->w); + tmp->bytecode_exe.x1 *= -1; + } + + if (fixtoi(tmp->y) < fy - (enem_t[tmp->ene_t].spr[tmp->spr_actual]->h*2)) tmp->y = itofix(fy - (enem_t[tmp->ene_t].spr[tmp->spr_actual]->h*2)); + + if (fixtoi(tmp->y) < fy ) + { + tmp->y = itofix(fy+2); /* DEBUG: mejorar esto para que no 'salte' desde arriba de pantalla! */ + tmp->bytecode_exe.y1 *= -1; + } + + // es un BOSS, no pasar de 2/3 de pantalla? + if (enem_t[tmp->ene_t].ia_boss) + { + if (fixtoi(tmp->y)+enem_t[tmp->ene_t].spr[tmp->spr_actual]->h > (fy+ALTO_FB) / 3 * 2 ) + { + tmp->y = itofix((fy+ALTO_FB) / 3 * 2 - enem_t[tmp->ene_t].spr[tmp->spr_actual]->h); + tmp->bytecode_exe.y1 *= -1; + } + } + else + { // desaparecer al salir por abajo + if (fixtoi(tmp->y) > fy + ALTO_FB*1.05) tmp->vida = ENE_MUERTO; + } + + /* Verificacion para ir limpiando la lista de enemigos muertos */ + if (tmp->vida <= ENE_MUERTO) { + /* murio, eliminar y pasar al siguiente!!! */ + *tmp_p = tmp->next; + free(tmp); + } else { + tmp_p = &tmp->next; /* nadie murio, siguiente por favor! */ + } + } /* fin loop recorrer enemigos */ +} + +/* + Esta funcion dibuja los enemigos en + el bitmap, desplazado x,y, + dibuja tambien una sombra que se desplaza + en relacion al borde inferior del bitmap y el centro y del mismo + de manera de dar un look 3D (como el viejo Rapt*r :^P ) + TIENE que estar seteado el colormap de transparencia + */ +void dibujar_enemigos(BITMAP *bmp, int x, int y) +{ + ENEMIGO *tmp = enemigo_1; + + while (tmp) { + + + /* Colocar enemigo */ + if (enem_t[tmp->ene_t].spr[tmp->spr_actual] != NULL) + { + /* colocar la sombra */ + colocar_sombra(bmp, enem_t[tmp->ene_t].spr_shadow[tmp->spr_actual], fixtoi(tmp->x)-x, fixtoi(tmp->y)-y); + draw_sprite(bmp, enem_t[tmp->ene_t].spr[tmp->spr_actual], fixtoi(tmp->x)-x, fixtoi(tmp->y)-y); + } + else + { + char errstr[1024]; + sprintf(errstr, "ERROR: dibujar_enemigos, hay un enemigo sin sprite (clase: %d, sprite: %d)!", tmp->ene_t, tmp->spr_actual); + levantar_error(errstr); + } + + + /* DEBUG: mostrar energia del enemigo */ +// if (KRONO_QUIERE_DEBUG) +// { +// text_mode(0); +// textprintf(bmp, font, fixtoi(tmp->x)-x, fixtoi(tmp->y)-y, makecol(255,255,255), "%d" , tmp->vida); +// } + + tmp = tmp->next; + } +} + + +/* Esta funcion se debe llamar cuando no se precise mas la lista + Libera la RAM usada y reinicia la lista + */ +void liberar_lista_enemigos() { + ENEMIGO *tmp = enemigo_1; + enemigo_1 = NULL; + + while (tmp) { + ENEMIGO *next = tmp->next; + free(tmp); + tmp = next; + } +} + +/* ------- DISPAROS DE LOS ENEMIGOS A PARTIR DE AQUI -------- */ + +/* + Esta funcion agrega un disparo a la lista de disparos + Automaticamente lo agrega usando el arma del enemigo, etc + Ademas, verifica el timer, y todo lo demas. + Pasarle el puntero al enemigo que dispara. +*/ +void agregar_disparo_ene(ENEMIGO *ene) +{ + int c = 0, i = 0; + + if (ene->arma_actual < 0) return; /* enemigo desarmado */ + + /* DEBUG: + EJECUTAR LOS SONIDOS DEL DISPARO */ + tocar_sonido_paneado(fixtoi(ene->x), + arma_ene[ene->arma_actual].snd[0], + rand_ex(128, 200), + rand_ex(900, 1100)); + + + switch (arma_ene[ene->arma_actual].t) + { + case 0: + case 1: + case 4: + c = 1; + break; + + case 5: + c = 5; + break; + + case 2: + c = 3; + break; + + case 3: + c = 2; + break; + + case 6: + c = 4; + break; + + case 7: + c = rand_ex(20, 30); + break; + + case 8: + c = 20; + break; + + case 9: + c = rand_ex(20, 30); + break; + + case 10: + c = rand_ex(5, 30); + break; + case 11: + c = rand_ex(4, 8); + break; + + default: + /* DEBUG, que paso? */ + c = -1; /* no agregar nada! */ + break; + } + + /* Si el tipo de disparo es doble, o triple, realizar el proceso varias veces */ + for (i=0; inext = disp_ene_1; + disp_ene_1 = nueva; + + if (nueva != NULL) /* si el malloc funciono, seteo los datos... */ + { + + /* Para evitar problemas, lleno todos los valores con defaults primero... */ + /* La 'y' es comun a todos los tipos de disparos */ + nueva->x = fixadd(ene->x, itofix(enem_t[ene->ene_t].spr[ene->spr_actual]->w/2)); + nueva->y = fixadd(ene->y, itofix(enem_t[ene->ene_t].spr[ene->spr_actual]->h/2)); + nueva->dx = arma_ene[ene->arma_actual].vx; + nueva->dy = arma_ene[ene->arma_actual].vy; + nueva->arma = ene->arma_actual; + nueva->vida = arma_ene[nueva->arma].vida; + + /* Dependiendo del tipo de disparo, setear su posicion */ + switch (arma_ene[nueva->arma].t) + { + case 0: /* recto */ + nueva->x = fixadd(ene->x, itofix(rand() % enem_t[ene->ene_t].spr[ene->spr_actual]->w)); + break; + + case 1: /* direccion al azar */ + case 6: + case 7: + nueva->x = fixadd(ene->x, itofix(rand() % enem_t[ene->ene_t].spr[ene->spr_actual]->w)); + nueva->dx = ftofix((float)rand_ex(-fixtof(arma_ene[ene->arma_actual].vx)*10.0, fixtof(arma_ene[ene->arma_actual].vx)*10.0) / 10.0); + if (rand()%100 < 10) nueva->dx = 0; + + nueva->dy = fmul(arma_ene[ene->arma_actual].vy, itofix(rand_ex(1, 3)) ); + break; + + case 2: /* abanico triple */ + nueva->x = fixadd(ene->x, itofix(rand() % enem_t[ene->ene_t].spr[ene->spr_actual]->w)); + if (i == 0) nueva->dx = arma_ene[ene->arma_actual].vx; + if (i == 1) nueva->dx = 0; + if (i == 2) nueva->dx = fixmul(arma_ene[ene->arma_actual].vx, itofix(-1)) ; + nueva->dy = arma_ene[ene->arma_actual].vy; + break; + + case 3: /* doble recto */ + nueva->x = fixadd(ene->x, itofix(rand() % enem_t[ene->ene_t].spr[ene->spr_actual]->w)); + nueva->dx = arma_ene[ene->arma_actual].vx; + nueva->dy = arma_ene[ene->arma_actual].vy; + break; + + case 4: /* rastreador y en un 10% al azar */ + case 5: + case 8: + nueva->x = fixadd(ene->x, itofix(rand()% enem_t[ene->ene_t].spr[ene->spr_actual]->w)); + + if (jugador.x < ene->x ) // rastrear + nueva->dx = ftofix((float)rand_ex(-150, 0)/10.0); + else + nueva->dx = ftofix((float)rand_ex(0, 150)/10.0); + + nueva->dy = arma_ene[ene->arma_actual].vy; + + if (rand()%100 < 15) // cada tanto, al azar + { + nueva->dx = ftofix((float)rand_ex(-150, 150) / 10.0); + nueva->dy = fmul(arma_ene[ene->arma_actual].vy, itofix(rand_ex(1, 3)) ); + } + + break; + + case 9: // en todas direcciones + case 10: + case 11: + nueva->x = fixadd(ene->x, itofix(rand() % enem_t[ene->ene_t].spr[ene->spr_actual]->w)); + + if (rand()%100 < 50) + nueva->dx = ftofix((float)rand_ex(-fixtoi(arma_ene[ene->arma_actual].vx)*10, 0)/10.0); + else + nueva->dx = ftofix((float)rand_ex(fixtoi(arma_ene[ene->arma_actual].vx)*10, 0)/10.0); + + if (rand()%100 < 50) + nueva->dy = ftofix((float)rand_ex(-fixtoi(arma_ene[ene->arma_actual].vy)*10, -fixtoi(arma_ene[ene->arma_actual].vy)*5 )/10.0); + else + nueva->dy = ftofix((float)rand_ex(fixtoi(arma_ene[ene->arma_actual].vy)*10, fixtoi(arma_ene[ene->arma_actual].vy)*5)/10.0); + break; + + default: /* que paso? */ + nueva->x = fixadd(ene->x, itofix(rand() % enem_t[ene->ene_t].spr[ene->spr_actual]->w)); + nueva->dx = ftofix((float)rand_ex(-150, 150)/10.0); + nueva->dy = arma_ene[ene->arma_actual].vy; + break; + + } // fin switch + } // fin != null + } // fin for +}; + +/* + Esta funcion actualiza la logica de los disparos + y los comprueba contra el jugador + ademas de remover los que tienen vida < 0 + Precisa saber el desplazamiento del mapa (fy) + si la bomba especial del jugador esta activa, elimina los disparos! +*/ +void mover_disparos_ene(int fy) { + DISP_ENE **tmp_p = &disp_ene_1; + int i1; /* auxiliar para agregar estelas a los disparos */ + + while (*tmp_p) { + + DISP_ENE *tmp = *tmp_p; + + /* aqui muevo */ + tmp->x = fixadd(tmp->x, tmp->dx); + tmp->y = fixadd(tmp->y, tmp->dy); + (tmp->vida)--; /* DEBUG: esto es correcto?, teoricamente, si... */ + + if (bomba_esta_activa) tmp->vida = -1; // matar disparo si esta la bomba + + /* verificar si disparo CHOCA CON jugador */ + + if (check_pmask_collision(arma_ene[tmp->arma].mask, jugador.mask, + fixtoi(tmp->x), fixtoi(tmp->y), + fixtoi(jugador.x), fixtoi(jugador.y) ) != 0) + { + + /* choco al jugador! SONIDO de colision del arma */ + tocar_sonido_paneado(fixtoi(tmp->x), + arma_ene[tmp->arma].snd[1], + rand_ex(200,255), + rand_ex(900,1100)); + + tmp->vida = -1; + + jugador.vida -= arma_ene[tmp->arma].punch; + + if (nivel_detalle > 0) poner_explosion_nave(fixtoi(tmp->x), fixtoi(tmp->y), rand()%20+20, rand()%10+5+arma_ene[tmp->arma].punch*2, 0); + } + else /* si no choco al jugador, agregar estela de particulas - DEBUG */ + { + /* DEBUG: agregar estela en particulas, [eliminar en bajos detalles!] + esto podria ser una funcion aparte + porque es bastante complicada la sintaxis... */ + if (nivel_detalle > 7) + for (i1=0; + i1 < rand_ex(arma_ene[tmp->arma].est_cant[0], arma_ene[tmp->arma].est_cant[1]); + i1++) + agrega_particula( fixadd(tmp->x, itofix(arma_ene[tmp->arma].spr->w/2)), + fixadd(tmp->y, itofix(rand()%arma_ene[tmp->arma].spr->h)), + ftofix(rand_ex(arma_ene[tmp->arma].est_dx[0], arma_ene[tmp->arma].est_dx[1])/100.0), + ftofix(rand_ex(arma_ene[tmp->arma].est_dy[0], arma_ene[tmp->arma].est_dy[1])/100.0), + rand_ex(arma_ene[tmp->arma].est_vida[0], arma_ene[tmp->arma].est_vida[1]), + makecol(rand_ex(arma_ene[tmp->arma].est_color[0][0], arma_ene[tmp->arma].est_color[0][1]), + rand_ex(arma_ene[tmp->arma].est_color[1][0], arma_ene[tmp->arma].est_color[1][1]), + rand_ex(arma_ene[tmp->arma].est_color[2][0], arma_ene[tmp->arma].est_color[2][1])), + rand_ex(arma_ene[tmp->arma].est_rad[0], arma_ene[tmp->arma].est_rad[1]), + rand_ex(arma_ene[tmp->arma].est_tipo[0], arma_ene[tmp->arma].est_tipo[1]), + arma_ene[tmp->arma].est_transp,0, + NULL ); + }; + + if (fixtoi(tmp->y) > fy + ALTO_FB ) tmp->vida = -1; /* se fue por abajo... */ + if (fixtoi(tmp->y) < fy ) tmp->vida = -1; /* se fue por arriba... */ + + /* Remocion de disparos muertos */ + if (tmp->vida < 0) { + /* murio, eliminar!!! */ + *tmp_p = tmp->next; + free(tmp); + } else { + tmp_p = &tmp->next; /* siguiente por favor! */ + } + } +} + +/* Dibuja los disparos, desplazados por x,y + sobre el bitmap bmp */ +void dibujar_disp_ene(BITMAP *bmp, int x, int y) { + + DISP_ENE *tmp = disp_ene_1; + + while (tmp) { + draw_sprite(bmp, arma_ene[tmp->arma].spr, fixtoi(tmp->x)-x, fixtoi(tmp->y)-y); + + /* DEBUG: mostrar energia */ +// if (KRONO_QUIERE_DEBUG) +// { +// text_mode(0); +// textprintf(bmp, font, fixtoi(tmp->x)-x, fixtoi(tmp->y)-y, makecol(255,255,255), "%d" , tmp->vida); +// } + + tmp = tmp->next; /* proximo... */ + } +} + + +/* Esta funcion se debe llamar cuando no se precise mas la lista + Libera la RAM usada y reinicia la lista + */ +void liberar_lista_disparos_ene() { + DISP_ENE *tmp = disp_ene_1; + disp_ene_1 = NULL; + + while (tmp) { + DISP_ENE *next = tmp->next; + free(tmp); + tmp = next; + } +} + +#endif diff --git a/src/error.c b/src/error.c new file mode 100644 index 0000000..0dd6afa --- /dev/null +++ b/src/error.c @@ -0,0 +1,27 @@ +// -------------------------------------------------------- +// error.c +// -------------------------------------------------------- +// Copyright (c) Kronoman +// En memoria de mi querido padre +// -------------------------------------------------------- +// Mensajes de error en modo texto. +// -------------------------------------------------------- +#ifndef ERROR_C +#define ERROR_C + +#include +#include + +// -------------------------------------------------------- +// Vuelve a modo texto, muestra el mensaje, y finaliza. +// -------------------------------------------------------- +void levantar_error(char *msg) +{ + set_gfx_mode(GFX_TEXT, 0, 0, 0, 0); + + allegro_message("%s\n", msg); + + exit(1); // salir con error +} + +#endif diff --git a/src/explos.c b/src/explos.c new file mode 100644 index 0000000..4f56055 --- /dev/null +++ b/src/explos.c @@ -0,0 +1,157 @@ +/*------------------------------------------------------- + explos.c + -------------------------------------------------------- + Copyright (c) 2002, Kronoman + En memoria de mi querido padre + Agosto - 2002 + -------------------------------------------------------- + Engine de explosiones usando una lista enlazada + muy sencilla, sirve para muchas capas de explosiones + mediante el uso de punteros. + --------------------------------------------------------*/ + +#ifndef EXPLOS_C +#define EXPLOS_C + +#include +#include "allegro.h" + +#include "explos.h" + +/* esta variable NO es necesaria, solo la uso para + ver cuantos enemigos hay en memoria, y de esa manera, + revisar la performance... */ +int cant_explosion_debug = 0; + + +/* --- globales internas --- */ + +/* Cache de imagenes y sonidos, para el combo de explosion */ +BITMAP *explo_cache_bmp[3]; +SAMPLE *explo_cache_snd[3]; + +/* No hay puntero al 1er item de la lista, debe crearse, + permite usar muchas listas a la vez! */ + +/* Estos dos punteros deben ser puestos cada vez que se quieren usar + en las diferentes llamadas */ +EXPLOSION *ptr_explo_fondo = NULL; +EXPLOSION *ptr_explo_arriba = NULL; + +/*---- +Esta funcion agrega una nueva explosion a la lista enlazada [al principio]. +PASARLE el puntero a la primera de la lista como &puntero! +----*/ +void agrega_explosion( EXPLOSION **prt_1era, + fixed x, fixed y, + fixed dx, fixed dy, + int vida, + fixed r, fixed dr, + int rot, + BITMAP *spr ) { + + EXPLOSION *nueva = (EXPLOSION *)malloc(sizeof(EXPLOSION)); + nueva->next = *prt_1era; + *prt_1era = nueva; + + if (nueva != NULL) /* si el malloc funciono, seteo los datos... */ + { + nueva->x = x; + nueva->y = y; + nueva->dx = dx; + nueva->dy = dy; + nueva->vida = vida; + nueva->r = r; + nueva->dr = dr; + nueva->rot = rot; + nueva->spr = spr; + } + +} + +/* + Esta funcion actualiza la logica (mueve) + tambien las elimina si vida < 0 + pasarle el puntero con &puntero + */ +void mover_explosiones(EXPLOSION **prt_1era) { + EXPLOSION **tmp_p = prt_1era; + EXPLOSION *tmp = NULL; + + cant_explosion_debug = 0; /* DEBUG: innecesario */ + + while (*tmp_p) { + + cant_explosion_debug++; /* DEBUG: innecesario */ + + tmp = *tmp_p; + + /* aqui muevo */ + tmp->x = fixadd(tmp->x, tmp->dx); + tmp->y = fixadd(tmp->y, tmp->dy); + + tmp->vida--; + + /* girar sprite */ + tmp->rot += rand()%32+1; /* girar */ + if (tmp->rot > 255) tmp->rot = 0; + + /* decrementar */ + tmp->r = fixsub(tmp->r, tmp->dr); + + if (tmp->r < ftofix(0.001) ) tmp->vida = -1; /* se extinguio... */ + + if (tmp->vida < 0) { + /* murio, eliminar!!! */ + *tmp_p = tmp->next; + free(tmp); + } else { + tmp_p = &tmp->next; /* siguiente por favor! */ + } + } +} + +/* + Esta funcion dibuja en el bitmap bmp + Las dibuja desplazadas x,y + */ +void dibujar_explosion(EXPLOSION *prt_1era, BITMAP *bmp, int x, int y) { + + EXPLOSION *tmp = prt_1era; + +/* calculos */ +int x2, y2; + + + while (tmp) { + + x2 = fixtoi(tmp->x)-x; + x2 -= fixtoi(fmul(itofix(tmp->spr->w), tmp->r))/2; + + y2 = fixtoi(tmp->y)-y; + y2 -= fixtoi(fmul(itofix(tmp->spr->h), tmp->r))/2; + + /* dibujar */ + rotate_scaled_sprite(bmp, tmp->spr, x2, y2, itofix(tmp->rot), tmp->r); + + tmp = tmp->next; /* proximo... */ + } +} + +/* Esta funcion se debe llamar cuando no se precise mas la lista + Libera la RAM usada y reinicia la lista + pasar el puntero asi &puntero + */ +void liberar_lista_explosion(EXPLOSION **prt_1era) { + EXPLOSION *tmp = *prt_1era; + *prt_1era = NULL; + + while (tmp) { + EXPLOSION *next = tmp->next; + free(tmp); + tmp = next; + } + +} + +#endif diff --git a/src/filedata.c b/src/filedata.c new file mode 100644 index 0000000..73d7a20 --- /dev/null +++ b/src/filedata.c @@ -0,0 +1,80 @@ +// -------------------------------------------------------- +// filedata.c +// -------------------------------------------------------- +// Copyright (c) Kronoman +// En memoria de mi querido padre +// -------------------------------------------------------- +// This file is used as a wrapper for load_datafile and other similar +// I use this for reach the datafile searching in common paths +// Is specially useful for datafiles in Windows, because most +// of the time Windows don't start the program in the executable path, +// and the program is unable to find the datafile. +// -------------------------------------------------------- + +#include +#include +#include "filedata.h" +// -------------------------------------------------------- +// This checks for the filename in several places. +// Returns where the filename is located in buffer +// buffer should be a 2048 bytes char +// If the file is not found, return the filename... +// -------------------------------------------------------- +char *where_is_the_filename(char *buffer, const char *filename) +{ +char str[2048], str2[2048]; // buffer for path making + +// check in current executable path +get_executable_name(str, 2048); +replace_filename(str2, str, filename, 2048); + +if (! exists(filename) ) + { + if (exists(str2)) + { + sprintf(buffer,"%s", str2); + return buffer; + } + else + { + get_executable_name(str, 2048); + replace_filename(str, str, "", 2048); + if (! find_allegro_resource(str2, filename, get_extension(filename), NULL, NULL, NULL, str, 2048) ) + { + sprintf(buffer,"%s", str2); + return buffer; + } + } + } + +// default +sprintf(buffer,"%s", filename); +return buffer; +} + +// -------------------------------------------------------- +// This functions is a wrapper of load_datafile +// Just pass a file name (without path), and this will try to seach and load it +// Will return a pointer to the DATAFILE or NULL if error. +// -------------------------------------------------------- +DATAFILE *krono_load_datafile(const char *filename) +{ +char str[2048]; + +return load_datafile(where_is_the_filename(str, filename)); // return what we found... +} + + +DATAFILE *krono_load_datafile_callback(const char *filename, void (*callback)(DATAFILE *d)) +{ +char str[2048]; + +return load_datafile_callback(where_is_the_filename(str, filename), callback); // return what we found... +} + +DATAFILE *krono_load_datafile_object(const char *filename, const char *objectname) +{ +char str[2048]; + +return load_datafile_object(where_is_the_filename(str, filename), objectname); // return what we found... +} diff --git a/src/game.c b/src/game.c new file mode 100644 index 0000000..b055554 --- /dev/null +++ b/src/game.c @@ -0,0 +1,642 @@ +/* + -------------------------------------------------------- + game.c + -------------------------------------------------------- + Loop principal del juego + -------------------------------------------------------- +*/ +#ifndef GAME_C +#define GAME_C + +#include +#include +#include "shopping.h" +#include "sonido.h" +#include "guiprocs.h" +#include "guitrans.h" +#include "data.h" +#include "global.h" +#include "kfbuffer.h" +#include "error.h" +#include "jugador.h" +#include "enemigo.h" +#include "mapa.h" +#include "partic.h" +#include "explos.h" +#include "captura.h" +#include "cinema.h" +#include "menu.h" +#include "clima.h" +#include "humo.h" +#include "rvideo.h" +#include "bomba.h" +#include "premio.h" + +/* Globales */ + +volatile int speed_counter = 0; /* contador de velocidad para frame skip */ +volatile int frame_count, fps; /* para contar los fps en caso de debug... */ + +/* estos contadores son para medir los fps con mas precision, max, med y min */ +volatile int fps_min, fps_max, fps_med; + +static PALETTE pal_game_oscura; // paleta del juego 'oscura', + // sirve para cuando se ponen menus, etc + // de esa manera, hace un efecto 'oscuro' + + +// Funcion que llena la pal_game_oscura con la paleta actual oscurecida. +// Usara la paleta actual, asique setear primero la paleta adecuada +// Pasar en oscurecer la cantidad de oscurecimiento (0.01 a 1.00) +// NOTA: Ignora todos los colores que utiliza la GUI +// o sea, los colores definidos en guiprocs.c -> xset_gui_colors() +static void llenar_pal_game_oscura(float oscurecer) +{ +int i; +float h,s,v; +int r,g,b; +int ignorar = FALSE; +get_palette(pal_game_oscura); +for (i = 0; i <256; i ++ ) + { + ignorar = FALSE; + // observad que if mas horrible!!! + if (i == gui_text_color || + i == gui_back_color || + i == gui_white_color || + i == gui_light_color || + i == gui_dark_color || + i == gui_black_color || + i == gui_fg_color || + i == gui_mg_color || + i == gui_bg_color ) + { + ignorar = TRUE; // ignorar el color porque es del GUI + } + + + if (!ignorar) + { + // tomar el color + r = (int)pal_game_oscura[i].r; + g = (int)pal_game_oscura[i].g; + b = (int)pal_game_oscura[i].b; + // multiplico por 4, porque el rango va de 0..63 en paleta y de 0..255 en la funcion de hsv + rgb_to_hsv(r*4, g*4, b*4, &h, &s, &v); + // oscurecer + v -= oscurecer; + if (v < 0.0) v = 0.0; + hsv_to_rgb(h, s, v, &r, &g, &b); // generar nuevo color + r /= 4; g /= 4; b /= 4; + pal_game_oscura[i].r = r; + pal_game_oscura[i].g = g; + pal_game_oscura[i].b = b; + } + } +} + + +/* Cuenta las fps y saca promedio de fps*/ +void fps_proc() +{ + fps = frame_count; + + /* ir sacando promedio */ + fps_med += fps; + fps_med = fps_med / 2; + + frame_count = 0; +} +END_OF_FUNCTION(fps_proc); + +/* Cuenta la velocidad del juego */ +void increment_speed_counter() +{ + speed_counter++; +} +END_OF_FUNCTION(increment_speed_counter); + + +/*-------------------------------------------------------- +Actualiza la logica del juego +--------------------------------------------------------*/ +void update_game_logic() +{ + ejecutar_poll_musica(); /* continuar ejecutando la musica */ + + rvideo_record(kfbufferbmp, pal_game); // grabar 'video' a disco - DEBUG + + scroll_mapa -= ABS(scroll_mapa_speed); + if (scroll_mapa < 0) + { + scroll_mapa = 0; + + /* ver, si no quedan mas enemigos, PASO de nivel!!! */ + if (enemigo_1 == NULL && jugador.vida > 0) /* la lista esta vacia, no hay enemigos */ + { + /* adelantar al jugador, llevarlo al borde superior, y hay si, salir */ + 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 + { + if ( ANCHO_FB/2 < fixtoi(jugador.x)+jugador.spr[1]->w/2 ) + jugador.dx =fixsub(jugador.dx, ftofix(VEL_X_J*1.2)); + + if ( ANCHO_FB/2 > fixtoi(jugador.x)+jugador.spr[1]->w/2 ) + jugador.dx =fixadd(jugador.dx, ftofix(VEL_X_J*1.2)); + } + else + { jugador.dx = 0; } // avanzar recto... + + if (fixtoi(jugador.y) > 5) // ir hacia la parte superior del nivel (la salida) + { + jugador.y = fixsub(jugador.y, ftofix(MAX_VEL_J_X)); + jugador.dy = fixsub(jugador.dy, ftofix(VEL_Y_J*1.5)); + } + else + { + paso_de_nivel = TRUE; + } + } + } + + /* el jugador se tiene que mover con el mapa */ + if (scroll_mapa > 0) jugador.y = fixsub(jugador.y, itofix(1)); + + // obtener teclado si es necesario (algunas plataformas...) + if (keyboard_needs_poll()) poll_keyboard(); + + interpreta_teclado(); // teclado del jugador + mover_jugador(scroll_mapa); + mover_bomba(); /* bomba especial del jugador */ + mover_enemigos(scroll_mapa); + mover_disparos_jug(scroll_mapa); + mover_disparos_ene(scroll_mapa); + + if (nivel_detalle > 0) mover_particulas(0, scroll_mapa, ANCHO_FB, ALTO_FB); + + mover_explosiones(&ptr_explo_fondo); + mover_explosiones(&ptr_explo_arriba); + mover_emisor_humo(0, scroll_mapa, ANCHO_FB, ALTO_FB); // emisores de humo! wow! + mover_humo(0, scroll_mapa, ANCHO_FB, ALTO_FB); + + mover_premio(0, scroll_mapa, ANCHO_FB, ALTO_FB); // premios... + + if (nivel_detalle > 1) mover_clima(kfbufferbmp); // mover clima + + /* ver si aparecen nuevos enemigos */ + scan_nuevos_enemigos(scroll_mapa / H_GR); + + /* TECLADO ADICIONAL - FUNCIONES PROPIAS DEL JUEGO */ + + /* TECLA PAUSE o P, sirve para poner la PAUSA! */ + if (key[KEY_PAUSE] || key[KEY_P]) + { + pausar_musica(); + + key[KEY_PAUSE] = FALSE; + key[KEY_P] = FALSE; + clear_keybuf(); + set_palette(pal_game_oscura); + // Mensaje GUI + alert(get_config_text("Pause"), NULL, NULL, get_config_text("Continue"), NULL, 0, 0); + clear_keybuf(); + key[KEY_PAUSE] = FALSE; + key[KEY_P] = FALSE; + frame_count = fps = speed_counter = 0; /* evita salto en los fps */ + + continuar_musica(); + set_palette(pal_game); + } // fin pausa + + + /* ESC: menu con varias opciones */ + if (key[KEY_ESC]) + { + DIALOG esc_key_dlg[] = + { + /* (proc) (x) (y) (w) (h) (fg) (bg) (key) (flags) (d1) (d2) (dp) (dp2) (dp3) */ + { xbox_proc, 0, 0, 200, 128, 0, 0, 0, 0, 0, 0, NULL, NULL, NULL }, + { xbutton_proc, 8, 8, 184, 32, 0, 0, 0, D_EXIT, 0, 0, "Configuration", NULL, NULL }, + { xbutton_proc, 8, 48, 184, 32, 0, 0, 0, D_EXIT, 0, 0, "Abort Game", NULL, NULL }, + { xbutton_proc, 8, 88, 184, 32, 0, 0, 0, D_EXIT, 0, 0, "Resume game", NULL, NULL }, + { NULL, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, NULL, NULL, NULL } + }; + pausar_musica(); + + traducir_DIALOG_dp(esc_key_dlg); + centre_dialog(esc_key_dlg); + set_dialog_color(esc_key_dlg, makecol(0,0,0), makecol(255,255,255)); + key[KEY_ESC] = FALSE; + + clear_keybuf(); + set_palette(pal_game_oscura); + + /* mostrar dialogo */ + switch (popup_dialog(esc_key_dlg, 0)) + { + case 1: // configurar - DEBUG, truchisimo lo del F5 + key[KEY_F5] = TRUE; + break; + + case 2: // abortar juego + if (alert(get_config_text("Exit game"), + NULL, + NULL, + get_config_text("Yes"), + get_config_text("No"), + 0, 0) == 1) + { + salir_del_juego = TRUE; + } + break; + + default: + break; + + } + + frame_count = fps = speed_counter = 0; /* evita salto en los fps */ + continuar_musica(); + set_palette(pal_game); + } + + /* F5: menu de configuracion general, sonido, detalles, controles, etc */ + if (key[KEY_F5]) + { + int tmp1 = quiere_musica; + + pausar_musica(); + set_palette(pal_game_oscura); + key[KEY_F5] = FALSE; + clear_keybuf(); + menu_configuracion_al_vuelo(); + frame_count = fps = speed_counter = 0; /* evita salto en los fps */ + + reajustar_volumen_musica(); + continuar_musica(); + set_palette(pal_game); + + /* DEBUG: esto es para que si activa/desactiva la musica, tome efecto */ + if (tmp1 != quiere_musica) + { + musica_stop(); + musica_play(info_nivel.musica); + } + } + + + /* F1: ayuda del programa */ + if (key[KEY_F1]) + { + pausar_musica(); + set_palette(pal_game_oscura); + key[KEY_F1] = FALSE; + clear_keybuf(); + ayuda_proggy_mnu(); + frame_count = fps = speed_counter = 0; /* evita salto en los fps */ + + continuar_musica(); + set_palette(pal_game); + } + + /* F11 prende y apaga el modo DEBUG (muestra info extra) */ + if (key[KEY_F11]) /* DEBUG, al distribuir, eliminar esto!!! */ + { + key[KEY_F11] = FALSE; + KRONO_QUIERE_DEBUG = !KRONO_QUIERE_DEBUG; + } + + /* F12 sirve para capturar pantallas */ + if (key[KEY_F12]) + { + // pausar_musica(); + + key[KEY_F12] = FALSE; + clear_keybuf(); + capturar_la_pantalla("krap"); + alert("Screen captured!", NULL,NULL,"OK", NULL,0,0); + frame_count = fps = speed_counter = 0; + // continuar_musica(); + } + + /* F10 sirve para prender/apagar la grabacion de videos - DEBUG! */ + #ifdef SECCION_DESACTIVADA_PARA_EL_RELEASE + if (key[KEY_F10]) + { + rvideo_is_recording = !rvideo_is_recording; + key[KEY_F10] = FALSE; + clear_keybuf(); + } + #endif + +} + +/*-------------------------------------------------------- +Actualiza la pantalla +--------------------------------------------------------*/ +void update_display() +{ + + /* Tuberia de dibujado, en orden de abajo arriba */ + + set_clip(kfbufferbmp, 0, 0, mapa_fondo->w-1, kfbufferbmp->h-1); /* clipping adecuado */ + +// solo dibuja si la bomba especial no esta activa, sino, es desperdiciar rendering +if (!bomba_esta_activa) +{ + /* fondo */ + blit(mapa_fondo, kfbufferbmp, 0, scroll_mapa, 0, 0, mapa_fondo->w, kfbufferbmp->h); + + if (nivel_detalle > 3) dibujar_humo(kfbufferbmp, 0, scroll_mapa); + + dibujar_explosion(ptr_explo_fondo, kfbufferbmp, 0, scroll_mapa); + + dibujar_disp_ene(kfbufferbmp, 0, scroll_mapa); + + dibujar_enemigos(kfbufferbmp, 0, scroll_mapa); + + dibujar_disp_jug(kfbufferbmp, 0, scroll_mapa); + + dibujar_nave_jugador(kfbufferbmp, 0, scroll_mapa); + + dibujar_premio(kfbufferbmp, 0, scroll_mapa); + + if (nivel_detalle > 0) dibujar_particulas(kfbufferbmp, 0, scroll_mapa); + + dibujar_explosion(ptr_explo_arriba, kfbufferbmp, 0, scroll_mapa); + + if (nivel_detalle > 1) dibuja_clima(kfbufferbmp); // clima +} // fin de ver si esta detonando la bomba +else +{ + dibujar_bomba(kfbufferbmp); +} + +/* DEBUG: info de FPS, cantidades, etc */ + if (KRONO_QUIERE_DEBUG) + { + text_mode(0); + + /* DEBUG: lo saque, porque ya no lo preciso... + textprintf(kfbufferbmp, font, 0, kfbufferbmp->h - text_height(font)-2, makecol(255,255,255), + "|fps:%5d|ener:%3d|e:%5d|p:%5d|ex:%5d|" , + fps, + jugador.vida, + cant_enemigos_debug, + cant_particulas_debug, + cant_explosion_debug ); + */ + + // Solo fps... por ahora - DEBUG + textprintf(kfbufferbmp, font, 0, kfbufferbmp->h - text_height(font)-2, makecol(255,255,255), + "fps:%5d fps_max:%5d fps_min:%5d fps_med:%5d", + fps, fps_max, fps_min, fps_med); + } + + + /* Tablero */ + set_clip(kfbufferbmp, 0, 0, kfbufferbmp->w-1, kfbufferbmp->h-1); /* clipping adecuado */ + + dibujar_tablero(kfbufferbmp); + + /* a pantalla */ + enviar_kfbuffer2screen(); +} + +/* + Esta es la secuencia y loop principal del juego + Llamar para comenzar un juego nuevo + NOTA: si el parametro load_savegame != 0, se asume + que se esta cargando un juego de disco, + y no se alteran las variables del jugador!! + */ +void comenzar_juego(int load_savegame) +{ + /* funcion interna que libera listas enlazadas */ + static void liberar_listas_interno() + { + /* LIBERAR LISTAS... */ + liberar_lista_enemigos(); + liberar_lista_disparos_ene(); + liberar_lista_disparos_jug(); + liberar_lista_particulas(); + liberar_lista_explosion(&ptr_explo_fondo); + liberar_lista_explosion(&ptr_explo_arriba); + liberar_emisores_humo(); + liberar_humo(); + liberar_premio(); + } + + /* funcion interna que limpia los colores y bufferes + y coloca la paleta de juego, etc */ + static void hacer_cleanup_mapeos() + { + set_palette(pal_game); + color_map = &tabla_transparencia; /* la rutina de sombras la precisa! */ + rgb_map = &tabla_RGB; /* acelera la fabricacion de colores de 8 bits */ + set_trans_blender(128, 128, 128, 128); /* Transparencia 50% para > 8 bits */ + clear(kfbufferbmp); clear(screen); /* limpiar bufferes */ + clear_keybuf(); + xset_gui_colors(); /* setea el GUI */ + set_mouse_sprite(NULL); /* acomoda puntero del mouse para que se ajuste a los colores */ + llenar_pal_game_oscura(0.25); // prepara la paleta oscura para efectos en los menues + } + + /* Funcion interna para instalar los timers */ + static void pone_timers_juego() + { + /* Timers */ + if (install_int_ex(increment_speed_counter, BPS_TO_TIMER(30))) + levantar_error("ERROR: no hay espacio para instalar el timer a 30 fps\n"); /* a 30 fps el juego */ + + if (install_int(fps_proc, 1000)) + levantar_error("ERROR: no hay espacio para instalar el timer a 1000 milisegundos!\n"); /* a 1000 milisegundos (1 segundo) el contador de fps */ + + /* Reiniciar contadores de velocidad... */ + frame_count = fps = speed_counter = 0; /* evita salto en los fps */ + } + + /* Funcion interna para SACAR los timers */ + static void saca_timers_juego() + { + /* remover timers... */ + remove_int(fps_proc); + remove_int(increment_speed_counter); + } + + +salir_del_juego = FALSE; + +/* Reiniciar juego, solo si no esta cargando un juego de disco */ +if (!load_savegame) + { + nivel_actual = 1; + reset_total_jugador(); + } + +fps_min = INT_MAX; +fps_max = 0; +fps_med = 0; +LOCK_VARIABLE(fps_med); + +/* Frameskip timer */ +LOCK_VARIABLE(speed_counter); +LOCK_FUNCTION(increment_speed_counter); + +/* Fps timer */ +LOCK_VARIABLE(frame_count); +LOCK_VARIABLE(fps); +LOCK_FUNCTION(fps_proc); + +/* Inicia doble buffer */ +kfbufferbmp = create_system_bitmap(ANCHO_RFB, ALTO_RFB); +if (kfbufferbmp == NULL) levantar_error("ERROR: fallo la creacion del doble buffer! (falta RAM?)"); + +hacer_cleanup_mapeos(); /* limpiar pantalla y mapeos */ + +/* cinematica de introduccion al juego, solo si es el primer nivel */ +if (nivel_actual == 1) ejecutar_cinematica(game_intro_cine); + +/* iniciar engine de grabado de videos de promocion */ +init_rvideo(); + +/* Loop principal de juego */ +while (!salir_del_juego ) { + + paso_de_nivel = FALSE; + + reset_parcial_jugador(); /* reposicionar jugador, etc */ + + /* + Verifico que el proximo nivel exista, si es asi, + paso a dibujar las cinematicas, y luego, cargo el nivel en RAM (para ahorrar RAM) + */ + if (!cargar_nivel(nivel_actual, -1)) + { + liberar_listas_interno(); /* LIBERAR LISTAS... */ + scroll_mapa = H_FONDO - ALTO_FB; /* iniciar scrolling */ + + hacer_cleanup_mapeos(); + + /* ir al shopping */ + do_shopping_principal(); + + /* cinematica de entrada al nivel */ + ejecutar_cinematica(info_nivel.cine_in); + + /* Luego de las cinematicas, es necesario restaurar mapa RGB, + mapa de transparencias y paleta de color... */ + hacer_cleanup_mapeos(); + + if (cargar_nivel(nivel_actual, 0)) /* cargar el nivel en RAM, en serio... */ + levantar_error("Fallo la carga del nivel!"); /* shit! que paso - DEBUG */ + + scan_nivel_1era_vez(); /* scanear los enemigos en la pantalla por 1era vez */ + + /* Los timers deben ir EXACTAMENTE antes del while, caso contrario, + salta tantos frames como tiempo consuma todo lo anterior! */ + pone_timers_juego(); /* instala los timers... */ + + + musica_play(info_nivel.musica); /* comenzar a ejecutar musica - DEBUG */ + + // Iniciar efectos de clima + init_clima(kfbufferbmp, info_nivel.clima_c, info_nivel.clima_t, info_nivel.clima_d); + + while( !paso_de_nivel && !salir_del_juego ) + { + while (speed_counter > 0) + { + update_game_logic(); // actualizar logica del juego + speed_counter--; + } + update_display(); // actualizar pantalla + + frame_count++; // contar los fps + + /* DEBUG: conteo de fps mas preciso */ + if (fps > fps_max) fps_max = fps; + if (fps < fps_min && fps > 0) fps_min = fps; + + if (detalle_automatico) + { + nivel_detalle = (fps * 10)/30; + if (nivel_detalle > 10) nivel_detalle = 10; + if (nivel_detalle < 0) nivel_detalle = 0; + } + + } /* looping de juego en el nivel actual */ + + musica_stop(); /* parar musica - DEBUG */ + + saca_timers_juego(); /* desactiva los timers... */ + + /* eliminar los datos del nivel de RAM */ + if (datmapa != NULL) + { + unload_datafile(datmapa); + datmapa = NULL; + } + + if (mapa_fondo != NULL) + { + /* liberar RAM consumida por el nivel */ + destroy_bitmap(mapa_fondo); /* mapa de fondo */ + mapa_fondo = NULL; + } + + /* murio? */ + if (jugador.vida <= JUG_MUERTO) /* ahora si murio... */ + { + paso_de_nivel = FALSE; /* sorry gordi, no pasas si estas muerto! */ + salir_del_juego = TRUE; + + /* cinematica de game over */ + ejecutar_cinematica(game_over_cine); + + /* Luego de las cinematicas, es necesario restaurar mapa RGB, + mapa de transparencias y paleta de color... */ + hacer_cleanup_mapeos(); + + clear(screen); /* DEBUG, queda bien? */ + clear_keybuf(); + + /* mensaje */ + alert(get_config_text("Game Over"), NULL, NULL, get_config_text("OK"), NULL, 0, 0); + } + } + else /* no encontro el nivel */ + { + /* DEBUG: si no encuentra el proximo nivel, + SIGNIFICA QUE TERMINO EL JUEGO! */ + + /* Luego de las cinematicas, es necesario restaurar mapa RGB, + mapa de transparencias y paleta de color... */ + hacer_cleanup_mapeos(); + + clear(screen); /* DEBUG, queda bien? */ + clear_keybuf(); + + /* mensaje */ + alert(get_config_text("This is the end of the game"), NULL, NULL, get_config_text("OK"), NULL, 0, 0); + + salir_del_juego = TRUE; + } + + if (paso_de_nivel) /* funciones al pasar de nivel */ + { + /* ejecutar cinematica salida nivel */ + ejecutar_cinematica(info_nivel.cine_out); + + nivel_actual++; + } + +} /* looping de juego a traves de los niveles */ + +/* Liberar memoria */ +liberar_listas_interno(); /* LIBERAR LISTAS... */ +destroy_bitmap(kfbufferbmp); /* DOBLE BUFFER */ +kfbufferbmp = NULL; + +} + +#endif diff --git a/src/global.c b/src/global.c new file mode 100644 index 0000000..851a100 --- /dev/null +++ b/src/global.c @@ -0,0 +1,87 @@ +/* + global.c + Algunas globales usadas en el programa + -------------------------------------------------------- + Copyright (c) 2002, Kronoman + En memoria de mi querido padre + -------------------------------------------------------- +*/ +#ifndef GLOBAL_C +#define GLOBAL_C + +#include "allegro.h" +#include "global.h" // cantidades maximas definidas aqui + +/* Quiere ver informacion de DEBUG? (!= 0) = si */ +int KRONO_QUIERE_DEBUG = 0; + +char lenguaje[3]; // codigo de lenguaje a usar, 2 letras: ej : es = espa~ol + +/* Fonts: */ +FONT *font_backup = NULL; // esto contendra el puntero a 'font' de allegro, para poder restaurarlo +FONT *hud_font = NULL; // font para dibujar el 'hud' en el juego + +/* Detalles graficos del juego 0..10 (min..max) */ +int nivel_detalle = 10; +int detalle_automatico = 0; // desea que el detalle se ajuste automaticamente? + +/* Nivel actual */ +int nivel_actual = 0; + +/* Nivel de dificultad actual: 0 = facil, 1 = medio, 2 = dificil */ +int nivel_de_dificultad = 1; // skill level + +/* TRUCO : CHEAT - si esto es TRUE, el jugador no muere nunca */ +int cheat_god_mode = FALSE; + + +char game_over_cine[1024]; /* cinematica de game over */ +char game_intro_cine[1024]; /* cinematica de introduccion */ + +/* Datos del nivel */ +NIVEL_T info_nivel; + +/* Esta instalado el driver de sonido? */ +int driver_de_sonido = FALSE; + +/* quiere sonido? */ +int quiere_snd = TRUE; + +/* volumen del sonido 0..255 */ +int volumen_sonido = 255; + +/* quiere musica */ +int quiere_musica = TRUE; + +/* quiere videos */ +int quiere_videos = TRUE; + +/* volumen de la musica 0..255 */ +int volumen_musica = 255; + +/* Salir del juego? */ +int salir_del_juego = FALSE; + +/* paso de nivel */ +int paso_de_nivel = FALSE; + +/* Paleta del juego */ +PALETTE pal_game; + +/* Mapa de transparencia */ +COLOR_MAP tabla_transparencia; + +/* Mapa RGB a 8 bits */ +RGB_MAP tabla_RGB; + + + +/* quiere usar el joystick como controlador ? */ +int quiere_usar_joystick = FALSE; +/* que numero de joystick quiere usar? (usualmente, 0) */ +int numero_de_joystick = 0; + +/* quiere usar el mouse como controlador ? */ +int quiere_usar_mouse = FALSE; +int mouse_velocidad = 16; // cuanto mayor el numero, mas sensible el mouse, rango: 0..32 +#endif diff --git a/src/guiprocs.c b/src/guiprocs.c new file mode 100644 index 0000000..e84e862 --- /dev/null +++ b/src/guiprocs.c @@ -0,0 +1,750 @@ +/* guiprocs.c - Kraptor + Esto contiene dialogos tipo 3-D para el GUI de Kraptor + Fueron tomados de Allegro Dialog Editor + y modificados para su uso en Kraptor + Ademas, se modifico ciertos graficos, y se agregaron slider, + y otros controles 'chetos' (ver el .h) + + This has the dialogs for the GUI of Kraptor. + They where originally made by Julien Cugniere, + This source code is altered by Kronoman for the use in Kraptor. +*/ + +/* ORIGINAL: + * Allegro DIALOG Editor + * by Julien Cugniere + * + * guiprocs.c : Some thin, 3d-looking GUI procs + * + * Unless otherwise specified, d->bg is ignored. + */ +#include "guiprocs.h" +#include + +#define SET_DIALOG(d, _p, _x, _y, _w, _h, _fg, _bg, _k, _f, _d1, _d2, _dp, _dp2, _dp3) {\ + d.proc = _p; d.x = _x; d.y = _y; d.w = _w; d.h = _h; d.fg = _fg; d.bg = _bg; \ + d.key = _k; d.flags = _f; d.d1 = _d1; d.d2 = _d2; d.dp = _dp; d.dp2 = _dp2; \ + d.dp3 = _dp3; } + + + +/* additionnal colors of the 3d GUI */ +int gui_text_color; +int gui_white_color; +int gui_light_color; +int gui_back_color; +int gui_dark_color; +int gui_black_color; + +/* default color set for the GUI +Modificado por Kronoman para que ademas, inicie totalmente +el GUI de Allegro para funcionar como este GUI +*/ +void xset_gui_colors(void) +{ + gui_text_color = makecol(0, 0, 0); + gui_back_color = makecol(208, 208, 208); + gui_white_color = makecol(245, 245, 245); + gui_light_color = makecol(223, 223, 223); + gui_dark_color = makecol(187, 187, 187); + gui_black_color = makecol(156, 156, 156); + + gui_fg_color = makecol(0, 0, 0); + gui_mg_color = makecol(187, 187, 187); + gui_bg_color = makecol(208, 208, 208); + + gui_font_baseline = 0; + gui_mouse_focus = 1; + gui_shadow_box_proc = xbox_proc; + gui_ctext_proc = xctext_proc; + gui_button_proc = xbutton_proc; + gui_edit_proc = xedit_proc; + gui_list_proc = xlist_proc; + gui_text_list_proc = xtext_list_proc; + gui_menu_draw_menu = xdraw_menu; + gui_menu_draw_menu_item = xdraw_menu_item; +} + + + +/***************************************************************************/ +/********************************* Helpers *********************************/ +/***************************************************************************/ + + + +/* draws a gui box */ +void gui_rect(BITMAP *bmp, int x, int y, int w, int h, int flags) +{ + int c1, c2, c3, c4; + if(flags & F_IN) + { + c1 = gui_black_color; + c2 = gui_dark_color; + c3 = (flags & F_LIGHT) ? gui_white_color : gui_light_color; + c4 = gui_white_color; + } + else + { + c1 = gui_white_color; + c2 = (flags & F_LIGHT) ? gui_white_color : gui_light_color; + c3 = gui_dark_color; + c4 = gui_black_color; + } + + putpixel(bmp, x, y, c1); + putpixel(bmp, x+w-1, y, gui_back_color); + putpixel(bmp, x, y+h-1, gui_back_color); + putpixel(bmp, x+w-1, y+h-1, c4); + hline(bmp, x+1, y, x+w-2, c2); + vline(bmp, x, y+1, y+h-2, c2); + hline(bmp, x+1, y+h-1, x+w-2, c3); + vline(bmp, x+w-1, y+1, y+h-2, c3); +} + + + +/* directly ripped from Allegro. Maybe this function should be made + * available in aintern.h ? + */ +void dotted_rect(BITMAP *bmp, int x1, int y1, int x2, int y2, int fg, int bg) +{ + int x = ((x1+y1) & 1) ? 1 : 0; + int i; + + for (i=x1; i<=x2; i++) + { + putpixel(bmp, i, y1, (((i+y1) & 1) == x) ? fg : bg); + putpixel(bmp, i, y2, (((i+y2) & 1) == x) ? fg : bg); + } + + for (i=y1+1; iflags & D_DISABLED) + { + fg = gui_dark_color; + bg = gui_back_color; + } + else + { + fg = gui_text_color; + bg = (sel) ? gui_light_color : gui_back_color; + } + + rectfill(screen, x, y, x+w-1, y+h-1, bg); + text_mode(bg); + + if(ugetc(m->text)) + { + i = 0; + j = ugetc(m->text); + + while((j) && (j != '\t')) + { + i += usetc(buf+i, j); + j = ugetc(m->text+i); + } + usetc(buf+i, 0); + + gui_textout(screen, buf, x+8, y+1, fg, FALSE); + + if (j == '\t') + { + tok = m->text+i + uwidth(m->text+i); + gui_textout(screen, tok, x+w-gui_strlen(tok)-10, y+1, fg, FALSE); + } + + if((m->child) && (!bar)) + { + vline(screen, x+w-11, y+1, y+text_height(font), (sel) ? gui_white_color : gui_light_color); + line(screen, x+w-10, y+1, x+w-3, y+(text_height(font)/2), (sel) ? gui_white_color : gui_light_color); + line(screen, x+w-10, y+text_height(font), x+w-3, y+(text_height(font)/2)+1, gui_dark_color); + } + } + else + { + hline(screen, x, y+text_height(font)/2+1, x+w-1, gui_dark_color); + hline(screen, x, y+text_height(font)/2+2, x+w-1, gui_light_color); + putpixel(screen, x-1, y+text_height(font)/2+1, gui_back_color); + putpixel(screen, x-1, y+text_height(font)/2+2, gui_white_color); + putpixel(screen, x+w, y+text_height(font)/2+1, gui_black_color); + putpixel(screen, x+w, y+text_height(font)/2+2, gui_back_color); + } + + if(m->flags & D_SELECTED) + { + line(screen, x+1, y+text_height(font)/2+1, x+3, y+text_height(font)+1, fg); + line(screen, x+3, y+text_height(font)+1, x+6, y+2, fg); + } +} + + + +/* draws a 3d-looking scrollable frame */ +static void xdraw_scrollable_frame(DIALOG *d, int listsize, int offset, int height, int fg_color) +{ + int i, len; + int xx, yy; + + /* possibly draw scrollbar */ + if(listsize > height) + { + int focus = (d->flags & D_GOTFOCUS); + xx = d->x+d->w-12; + yy = d->y; + i = ((d->h-4) * offset + listsize/2) / listsize; + len = ((d->h-4) * height + listsize/2) / listsize; + + gui_rect(screen, d->x, d->y, d->w-12, d->h, F_IN); + gui_rect(screen, xx, yy, 12, d->h, F_IN); + rect(screen, xx+1, yy+1, xx+12-2, yy+d->h-2, gui_white_color); + + dotted_rect(screen, d->x+1, d->y+1, d->x+d->w-12-2, d->y+d->h-2, + gui_white_color, (focus) ? gui_back_color : gui_white_color); + + if(i > 0) + rectfill(screen, xx+2, yy+2, xx+2+8, yy+2+i-1, gui_white_color); + + gui_rect(screen, xx+2, yy+2+i, 8, len, (focus) ? F_LIGHT : 0); + rectfill(screen, (xx+2)+1, (yy+2+i)+1, (xx+2+8-1)-1, (yy+2+i+len-1)-1, + (focus) ? gui_light_color : gui_back_color); + + if(i+len < d->h-4) + rectfill(screen, xx+2, yy+2+i+len, xx+2+8, yy+d->h-3, gui_white_color); + } + else + { + gui_rect(screen, d->x, d->y, d->w, d->h, F_IN); + + dotted_rect(screen, d->x+1, d->y+1, d->x+d->w-2, d->y+d->h-2, + gui_white_color, (d->flags & D_GOTFOCUS) ? gui_back_color : gui_white_color); + } +} + + + +/* draws a 3d-looking list (ripped from AGUP) */ +static void xdraw_list(DIALOG *d) +{ + typedef char *(*getfuncptr)(int, int*); + int height, listsize, i, len, bar, x, y, w; + int fg, bg; + char *sel = d->dp2; + char s[512]; + + (*(getfuncptr)d->dp)(-1, &listsize); + height = (d->h-4) / text_height(font); + bar = (listsize > height); + w = (bar ? d->w-15 : d->w-3); + fg = (d->flags & D_DISABLED) ? gui_dark_color : gui_text_color; + + /* draw box contents */ + for(i=0; id2+i < listsize) + { + if((sel) && (sel[d->d2+i])) + bg = gui_light_color; + else + bg = gui_white_color; + usetc(s, 0); + ustrncat(s, (*(getfuncptr)d->dp)(i+d->d2, NULL), sizeof(s)-ucwidth(0)); + x = d->x + 2; + y = d->y + 2 + i*text_height(font); + text_mode(bg); + rectfill(screen, x, y, x+7, y+text_height(font)-1, bg); + x += 8; + len = ustrlen(s); + while (text_length(font, s) >= MAX(d->w - 1 - (bar ? 22 : 10), 1)) + { + len--; + usetat(s, len, 0); + } + textout(screen, font, s, x, y, fg); + x += text_length(font, s); + if(x <= d->x+w) + rectfill(screen, x, y, d->x+w, y+text_height(font)-1, bg); + } + else + rectfill(screen, d->x+2, d->y+2+i*text_height(font), + d->x+w, d->y+1+(i+1)*text_height(font), gui_white_color); + } + + if(d->y+2+i*text_height(font) <= d->y+d->h-3) + rectfill(screen, d->x+2, d->y+2+i*text_height(font), + d->x+w, d->y+d->h-3, gui_white_color); + + /* draw frame, maybe with scrollbar */ + xdraw_scrollable_frame(d, listsize, d->d2, height, 0); + + /* draw the focus item */ + if(d->d1 < d->d2+height && d->d1 >= d->d2) + { + y = d->y + 2 + (d->d1-d->d2)*text_height(font); + + dotted_rect(screen, d->x+2, y-1, d->x+w, y+text_height(font), + gui_dark_color, gui_white_color); + } +} + + + +/* +simple text proc, aligns the text depending on d->d1: + * 0 - left aligned + * 1 - centered on d->x + * 2 - centered on the middle of the object + * 3 - right aligned + */ +static void xdraw_text(BITMAP *bmp, DIALOG *d, int align) +{ + FONT *oldfont = font; + int rtm; + int fg = (d->flags & D_DISABLED) ? gui_dark_color : d->fg; + int x, center; + + switch(align) + { + case 1: x = d->x; center = TRUE; break; + case 2: x = d->x + d->w/2; center = TRUE; break; + case 3: x = d->x+d->w-gui_strlen(d->dp); center = FALSE; break; + default: x = d->x; center = FALSE; break; + } + if(d->dp2) + font = d->dp2; + rtm = text_mode(gui_back_color); + gui_textout(screen, d->dp, x, d->y, fg, center); + text_mode(rtm); + font = oldfont; +} + + + +/***************************************************************************/ +/************************* 3d-looking GUI objects **************************/ +/***************************************************************************/ + + + +/* simple text proc, aligns the text depending on d->d1 (see xdraw_text)*/ +int xtext_proc(int msg, DIALOG *d, int c) +{ + if(msg == MSG_DRAW) + xdraw_text(screen, d, d->d1); + return D_O_K; +} + + + +/* replacement for allegro's d_ctext_proc */ +int xctext_proc(int msg, DIALOG *d, int c) +{ + if(msg == MSG_DRAW) + xdraw_text(screen, d, 1); + return D_O_K; +} + + + +/* replacement for allegro's d_rtext_proc */ +int xrtext_proc(int msg, DIALOG *d, int c) +{ + if(msg == MSG_DRAW) + xdraw_text(screen, d, 3); + return D_O_K; +} + + + +/* 3d-looking list proc */ +int xlist_proc(int msg, DIALOG *d, int c) +{ + if(msg == MSG_DRAW) + { + xdraw_list(d); + return D_O_K; + } + return d_list_proc(msg, d, c); +} + + + +/* 3d-looking text list proc */ +int xtext_list_proc(int msg, DIALOG *d, int c) +{ + if(msg == MSG_DRAW) + { + xdraw_list(d); + return D_O_K; + } + return d_text_list_proc(msg, d, c); +} + + + +/* 3d-looking textbox proc (ripped from AGUP) */ +int xtextbox_proc(int msg, DIALOG *d, int c) +{ + if(msg == MSG_DRAW) + { + int height, bar; + int fg_color = (d->flags & D_DISABLED) ? gui_dark_color : gui_text_color; + height = (d->h-8) / text_height(font); + + /* tell the object to sort of draw, but only calculate the listsize */ + _draw_textbox(d->dp, &d->d1, + 0, /* DONT DRAW anything */ + d->d2, !(d->flags & D_SELECTED), 8, + d->x, d->y, d->w, d->h, + (d->flags & D_DISABLED), + 0, 0, 0); + + if(d->d1 > height) + bar = 11; + else + bar = d->d2 = 0; + + /* now do the actual drawing */ + _draw_textbox(d->dp, &d->d1, 1, d->d2, + !(d->flags & D_SELECTED), 8, + d->x, d->y, d->w-bar, d->h, + (d->flags & D_DISABLED), + fg_color, gui_white_color, gui_dark_color); + + /* draw the frame around */ + xdraw_scrollable_frame(d, d->d1, d->d2, height, 0); + return D_O_K; + } + + return d_textbox_proc(msg, d, c); +} + + + +/* a 3d-looking box proc. set d1 to 1 to draw it inward */ +int xbox_proc(int msg, DIALOG *d, int c) +{ + if(msg == MSG_DRAW) + { + gui_rect(screen, d->x, d->y, d->w, d->h, d->d1); + rectfill(screen, d->x+1, d->y+1, d->x+d->w-2, d->y+d->h-2, gui_back_color); + } + return D_O_K; +} + + + +/* a 3d-box displaying the color in d->bg */ +int xcolorbox_proc(int msg, DIALOG *d, int c) +{ + if(msg == MSG_DRAW) + { + gui_rect(screen, d->x, d->y, d->w, d->h, F_IN); + rectfill(screen, d->x+1, d->y+1, d->x+d->w-2, d->y+d->h-2, d->bg); + } + return D_O_K; +} + + + +/* a 3d-looking check proc. d1 ignored +*/ +int xcheck_proc(int msg, DIALOG *d, int c) +{ + d->d1 = 1; + if(msg == MSG_DRAW) + { + int dis = d->flags & D_DISABLED; + int fg = (dis) ? gui_dark_color : gui_text_color; + int bg = (dis) ? gui_light_color : gui_white_color; +// int sg = (dis) ? gui_black_color : gui_back_color; + gui_rect(screen, d->x, d->y, d->h, d->h, F_IN); + rectfill(screen, d->x+1, d->y+1, d->x+d->h-2, d->y+d->h-2, bg); + + if(d->flags & D_SELECTED) + { + /* modificado por kronoman para hacer un 'look' mas lindo al check box */ + + rectfill(screen, d->x+3, d->y+3, d->x + d->h - 4, d->y + d->h - 4, (d->flags & D_GOTFOCUS) ? gui_light_color : gui_back_color); + gui_rect(screen, d->x+2, d->y+2, d->h-4, d->h-4, (d->flags & D_GOTFOCUS) ? F_LIGHT : 0 ); + + +// line(screen, d->x+3, d->y+3, d->x+d->h-4, d->y+d->h-4, gui_light_color); +// line(screen, d->x+3, d->y+d->h-4, d->x+d->h-4, d->y+3, gui_light_color); + + } + +// if(d->flags & D_GOTFOCUS) +// dotted_rect(screen, d->x+1, d->y+1, d->x+d->h-2, d->y+d->h-2, sg, bg); + + text_mode(gui_back_color); + gui_textout(screen, d->dp, d->x+d->h-1+text_height(font)/2, d->y+(d->h-(text_height(font)-gui_font_baseline))/2, fg, FALSE); + return D_O_K; + } + else + return d_check_proc(msg, d, c); +} + + + +/* xbutton_proc + * a modified button proc that call a function instead of closing the dialog + * dp2 should contain the function: int func() + */ +int xbutton_proc(int msg, DIALOG *d, int c) +{ + int ret; + typedef int (*func_ptr)(void); + + if(msg == MSG_DRAW) + { + int p = (d->flags & D_SELECTED) ? 1 : 0; + int style = ((p) ? F_IN : 0) | ((d->flags & D_GOTFOCUS) ? F_LIGHT : 0); + gui_rect(screen, d->x, d->y, d->w, d->h, style); + rectfill(screen, d->x+1, d->y+1, d->x+d->w-2, d->y+d->h-2, (d->flags & D_GOTFOCUS) ? gui_light_color : gui_back_color); + + text_mode(-1); + gui_textout(screen, d->dp, d->x+p + d->w/2, d->y+p + (d->h-text_height(font))/2, (d->flags & D_DISABLED) ? gui_dark_color : gui_text_color, 1); + + return D_O_K; + } + else + ret = d_button_proc(msg, d, c); + + if(ret == D_CLOSE && d->dp2) + ret = ((func_ptr)d->dp2)() | D_REDRAWME; + + return ret; +} + + + +/* xedit_proc + * a tricky little mix of a proc, that behave like a d_edit_proc object, but + * can have a button at its right that calls a function. The function is in + * dp2 in the form int func(DIALOG*), and is passed the dialog calling it. + * Its return value is passed back to the dialog manager. PageDown simulates + * a click on the button. + */ +int xedit_proc(int msg, DIALOG *d, int c) +{ + int ret = D_O_K; + typedef int (*func_ptr)(DIALOG*); + int n = d->h-text_height(font); + DIALOG edit, button; + + SET_DIALOG(edit, d_edit_proc, d->x+n/2, d->y+n/2, d->w-n, d->h-n, d->fg, gui_white_color, 0, d->flags, d->d1, d->d2, d->dp, NULL, NULL); + SET_DIALOG(button, xbutton_proc, 0, d->y+1, d->h-2, d->h-2, d->fg, gui_back_color, 0, d->flags|D_EXIT, 0, 0, "...", NULL, NULL); + + if(d->dp2) + { + button.x = d->x + d->w - button.w - 1; + edit.w -= button.w; + if(font == &_default_font) + button.dp = "_"; + } + + switch(msg) + { + case MSG_START: + + /* hack to make this proc look better when used in file_select() */ + if(d->h < text_height(font)+4) + { + d->y -= (text_height(font)+4 - d->h)/2; + d->h = text_height(font)+4; + } + + case MSG_CLICK: + + if(d->dp2 && mouse_x >= button.x) + { + ret = button.proc(msg, &button, c); + if(ret & D_CLOSE) + ret = ((func_ptr)d->dp2)(d) | D_REDRAWME; + } + else + ret = edit.proc(msg, &edit, c); + + break; + + case MSG_DRAW: + + gui_rect(screen, d->x, d->y, d->w, d->h, F_IN); + rectfill(screen, d->x+1, d->y+1, (d->dp2) ? (button.x-1) : (d->x+d->w-2), d->y+d->h-2, gui_white_color); + ret = edit.proc(msg, &edit, c); + if(d->dp2) + ret |= button.proc(msg, &button, c); + break; + + case MSG_CHAR: + + if(d->dp2 && (c>>8) == KEY_PGDN) + ret = ((func_ptr)d->dp2)(d) | D_REDRAWME; + /* fall through */ + + default: + + ret |= edit.proc(msg, &edit, c); + break; + } + + d->d1 = edit.d1; + d->d2 = edit.d2; + return ret; +} + + + +/* xpalette_proc + * displays the current palette, and holds the index of the selected color + * in d1. w and h are ignored: the object is sized 130x130. Supports D_EXIT, + * allowing to return D_CLOSE on double clicks. + */ +int xpalette_proc(int msg, DIALOG* d, int c) +{ + int x, y, ret = D_O_K; + + switch(msg) + { + case MSG_START: + + d->w = d->h = 130; + break; + + case MSG_DRAW: + + for(x=0; x<16; x++) + for(y=0; y<16; y++) + rectfill(screen, d->x+1 + x*8, d->y+1 + y*8, d->x+8 + x*8, d->y+8 + y*8, palette_color[x+16*y]); + + if(d->d1 >= 0) + { + x = d->x+1 + 8*(d->d1%16); + y = d->y+1 + 8*(d->d1/16); + rect(screen, x, y, x+8, y+8, gui_back_color); + rect(screen, x-1, y-1, x+7, y+7, gui_text_color); + } + gui_rect(screen, d->x, d->y, d->w, d->h, F_IN); + break; + + case MSG_DCLICK: + + ret = D_CLOSE; + /* fall through */ + + case MSG_CLICK: + + x = (mouse_x - (d->x+1))/8; + y = (mouse_y - (d->y+1))/8; + c = x + y*16; + + if(c < 256 && c != d->d1) + { + d->d1 = c; + return D_REDRAWME | D_WANTFOCUS; + } + break; + + case MSG_WANTFOCUS: + ret = D_WANTFOCUS; + } + + return ret; +} + +/* Slider cool, tipo X11, por Kronoman, +basado en el slider original, pero mas bonito :^) */ +int xslider_proc(int msg, DIALOG* d, int c) +{ + int vert = TRUE; /* flag: is slider vertical? */ + int slx, sly, slh, slw; + int hh = 20; /* handle height (width for horizontal sliders) */ + int slp; /* slider position */ + int irange; + fixed slratio, slmax, slpos; + + if (d->h < d->w) + vert = FALSE; + + irange = (vert) ? d->h : d->w; + slmax = itofix(irange-hh); + slratio = slmax / (d->d1); + slpos = slratio * d->d2; + slp = fixtoi(slpos); + + + if(msg == MSG_DRAW) + { + /* dibujar */ + rectfill(screen, d->x, d->y, d->x+d->w-2, d->y+d->h-2,gui_white_color); + + gui_rect(screen, d->x, d->y, d->w - 1, d->h -1, F_IN); + + + /* slider */ + if (vert) { + slx = d->x+1; + sly = d->y+(d->h)-(hh+slp); + slw = d->w-5; + slh = hh-3; + } else { /* horizontal */ + slx = d->x+slp; + sly = d->y+2; + slw = hh-3; + slh = d->h-5; + } + rectfill(screen, + slx+3, sly+1, + slx+( slw-2), sly+slh-1, + (d->flags & D_GOTFOCUS) ? gui_light_color : gui_back_color); + + gui_rect(screen, + slx+2, sly, + slw-2, slh, + (d->flags & D_GOTFOCUS) ? F_LIGHT : 0 ); + + } + else + return d_slider_proc(msg, d, c); + +return D_O_K; +} + +/* xbitmap_proc: + * Muestra el bitmap en dp ajustado a w y h + */ +int xbitmap_proc(int msg, DIALOG *d, int c) +{ + BITMAP *b = (BITMAP *)d->dp; + + if (msg==MSG_DRAW && d->dp != NULL) + stretch_blit(b, screen, + 0, 0, b->w, b->h, + d->x, d->y, d->w, d->h); + + return D_O_K; +} diff --git a/src/guitrans.c b/src/guitrans.c new file mode 100644 index 0000000..d4e90be --- /dev/null +++ b/src/guitrans.c @@ -0,0 +1,66 @@ +/* +guitrans.c +Por Kronoman +Copyrigth (c) 2002, Kronoman +En memoria de mi querido padre + +Este modulo se encarga de traducir estructuras +de los GUI de Allegro al idioma actual. + + +NOTAS: + +NOTA IMPORTANTISIMA: ESTO ES MUY PELIGROSO SI TENEMOS ESTRUCTURAS +QUE USAN 'dp' PARA OTRA COSA QUE NO SEA TEXTO (Ej: d_bitmap_proc) + +Los traduce PERMANENTEMENTE, por lo tanto, es conveniente +que las estructuras se creen dinamicamente en el programa original, +de esa manera, al cambiar de idioma, todo funciona OK, +caso contrario, habra fugas de memoria, porque cambian +los punteros al cambiar el idioma! + +Conviene usar el ingles como idioma base al traducir. + +No usar espacios extra, o simbolos como ?, -, etc porque +la cadena no sera reconocida... +*/ + +#include + +/* +Traduce el puntero 'dp' de una estructura DIALOG completa +La estructura DEBE terminar con proc = NULL (como especifica Allegro) + +DEBUG!!! +NOTA IMPORTANTISIMA: ESTO ES MUY PELIGROSO SI TENEMOS ESTRUCTURAS +QUE USAN 'dp' PARA OTRA COSA QUE NO SEA TEXTO (Ej: d_bitmap_proc) + +*/ +void traducir_DIALOG_dp(DIALOG *d) +{ +int i = 0; + +while (d[i].proc != NULL) + { + if (d[i].dp != NULL) d[i].dp = (void *)get_config_text((char *)d[i].dp); + i++; + } + +} + +/* +Traduce el puntero 'text' de una estructura MENU completa +La estructura DEBE terminar con text = NULL (como especifica Allegro) +Evitar usar & y otras mierdas raras... +*/ +void traducir_MENU_text(MENU *d) +{ +int i = 0; + +while (d[i].text != NULL) + { + d[i].text = (void *)get_config_text((char *)d[i].text); + i++; + } + +} diff --git a/src/humo.c b/src/humo.c new file mode 100644 index 0000000..3bb3582 --- /dev/null +++ b/src/humo.c @@ -0,0 +1,281 @@ +/*------------------------------------------------------- + humo.c + -------------------------------------------------------- + Copyright (c) 2002, Kronoman + En memoria de mi querido padre + Enero - 2003 + -------------------------------------------------------- + Engine de humo (para edificios en llamas) + usando una lista enlazada muy sencilla + --------------------------------------------------------*/ + +#ifndef HUMO_C +#define HUMO_C + +#include +#include + +#include "humo.h" +#include "azar.h" + +/* DEBUG - estas variables son especificas a Kraptor */ +#include "global.h" // para saber el nivel de detalle unicamente... + +BITMAP *humo_spr = NULL; // sprite de representacion del humo... + +/* --- globales internas --- */ + +static HUMO *prt_1er_humo = NULL; /* puntero al comienzo de la lista */ +static EMISOR_HUMO *prt1er_emisor = NULL; /* lista de emisores de humo */ + +//======================================================================== +// Funciones de los emisores de humo, +// son zonas de 40x40 que emiten humo por un determinado espacio de tiempo + + +/* Esta funcion agrega un nuevo emisor de humo + Devuelve puntero al emisor creado. + Si vida <= 0, NO se crea... + */ +EMISOR_HUMO *agrega_emisor_humo(fixed x, fixed y, int vida ) +{ + EMISOR_HUMO *nueva = NULL; + + if (vida <= 0) return NULL; /* ni pierdo el tiempo... */ + + if (nivel_detalle < 2) return NULL; // nivel de detalle minimo, no hacer nada + + nueva = (EMISOR_HUMO *)malloc(sizeof(EMISOR_HUMO)); + nueva->next = prt1er_emisor; + prt1er_emisor = nueva; + + if (nueva != NULL) /* si el malloc funciono, seteo los datos... */ + { + nueva->x = x; + nueva->y = y; + nueva->vida = vida; + } + + return nueva; +} + +/* + Esta funcion actualiza la logica (mueve) los emisores de humo + En realidad, los emisores de humo agregan particulas, pero no se mueven... + tambien los elimina si vida < 0 o si estan fuera de pantalla + Pasar en x, y la posicion de scroll en pantalla + en w, h el ancho y alto de la pantalla + */ +void mover_emisor_humo(int x, int y, int w, int h) +{ + int i; + EMISOR_HUMO **tmp_p = &prt1er_emisor; + EMISOR_HUMO *tmp = NULL; + + while (*tmp_p) { + + tmp = *tmp_p; + + /* DEBUG: aqui agrego particulas de humo */ + // fueguito... + if (rand()%100 < 80) + agrega_humo( fixadd(tmp->x, itofix(rand_ex(-5,5))) , + fixadd(tmp->y, itofix(rand_ex(-5,5))) , + ftofix(rand_ex(-150,150) / 100.0), + ftofix(rand_ex(-150,150) / 100.0), + rand_ex(5, 15), + makecol(255,rand()%255,0), + itofix(rand_ex(2,6)), + ftofix(rand_ex(0, 10) / 100.0)); + + // agregar un 'humo' hacia la derecha y arriba + if (rand()%100 < 95) + { + i = rand_ex(0,96); // gris oscuro + agrega_humo( fixadd(tmp->x, itofix(rand_ex(-5,5))), + fixadd(tmp->y, itofix(rand_ex(-5,5))), + ftofix(rand_ex(10,200) / 100.0), + ftofix(-1.0 * (rand_ex(50,300) / 100.0)), + rand_ex(10, 50), + makecol(i,i,i), + itofix(rand_ex(3,10)), + ftofix(rand_ex(0, 25) / 100.0)); + } + + tmp->vida--; + + /* verificar si estan fuera de pantalla (da 40 pixeles de margen para + permitir que salga totalmente de pantalla) */ + // NOTA: no los elimino por arriba, sino los edificos aparecen 'apagados' +// if (tmp->y < itofix(y-80)) tmp->vida = -1; + if (tmp->y > itofix(y+h+80)) tmp->vida = -1; + if (tmp->x < itofix(x-80)) tmp->vida = -1; + if (tmp->x > itofix(x+w+80)) tmp->vida = -1; + + if (tmp->vida < 0) { + /* murio, eliminar!!! */ + *tmp_p = tmp->next; + free(tmp); + } else { + tmp_p = &tmp->next; /* siguiente por favor! */ + } + } +} + +/* Esta funcion se debe llamar cuando no se precise + mas la lista de emisores de humo + Libera la RAM usada y reinicia la lista + */ +void liberar_emisores_humo() { + EMISOR_HUMO *tmp = prt1er_emisor; + prt1er_emisor = NULL; + + while (tmp) { + EMISOR_HUMO *next = tmp->next; + free(tmp); + tmp = next; + } +} + + +//======================================================================== +// +// ---------------------- FUNCIONES DE PARTICULAS DE HUMO EN SI ---------- +// +//======================================================================== + +/* Esta funcion agrega humo a la lista enlazada [al principio]. + Devuelve puntero a la particula recien creada. + Los parametros son los parametros de la particula + Si vida <= 0, NO se crea la particula... (return derecho...) + */ +HUMO *agrega_humo( fixed x, fixed y, + fixed dx, fixed dy, + int vida, + int col, fixed r, fixed ri) +{ + HUMO *nueva = NULL; + + if (vida <= 0) return NULL; /* ni pierdo el tiempo... */ + + if (nivel_detalle < 2) return NULL; // nivel de detalle minimo, no hacer nada + + nueva =malloc(sizeof(HUMO)); + nueva->next = prt_1er_humo; + prt_1er_humo = nueva; + + if (nueva != NULL) /* si el malloc funciono, seteo los datos... */ + { + nueva->x = x; + nueva->y = y; + nueva->dx = dx; + nueva->dy = dy; + nueva->vida = vida; + nueva->col = col; + nueva->r = r; + nueva->ri = ri; + } + + return nueva; +} + +/* + Esta funcion actualiza la logica (mueve) el humo + tambien las elimina si vida < 0 o si estan fuera de pantalla + Pasar en x, y la posicion de scroll en pantalla + en w, h el ancho y alto de la pantalla + */ +void mover_humo(int x, int y, int w, int h) +{ + HUMO **tmp_p = &prt_1er_humo; + HUMO *tmp = NULL; + + while (*tmp_p) { + + tmp = *tmp_p; + + /* aqui muevo la particula */ + tmp->x = fixadd(tmp->x, tmp->dx); + + // efecto 'sacudida' para simular el humo... + tmp->x = fixadd(tmp->x, ftofix( rand_ex(-200, 200 ) / 100.0 ) ); + + tmp->y = fixadd(tmp->y, tmp->dy); + tmp->vida--; + + // aumentar el radio + tmp->r = fixadd(tmp->r, tmp->ri); + if (fixtoi(tmp->r) < 1) tmp->vida = -1; + + + /* DEBUG: verificar si estan fuera de pantalla (da 15 pixeles de margen para + permitir que la particula salga totalmente de pantalla) */ + if (tmp->y < itofix(y-15)) tmp->vida = -1; + if (tmp->y > itofix(y+h+15)) tmp->vida = -1; + if (tmp->x < itofix(x-15)) tmp->vida = -1; + if (tmp->x > itofix(x+w+15)) tmp->vida = -1; + + if (tmp->vida < 0) { + /* la particula murio, eliminar!!! */ + *tmp_p = tmp->next; + free(tmp); + } else { + tmp_p = &tmp->next; /* siguiente por favor! */ + } + } +} + +/* + Esta funcion dibuja el humo en el bitmap bmp + Las dibuja desplazadas x,y + */ +void dibujar_humo(BITMAP *bmp, int x, int y) +{ + HUMO *tmp = prt_1er_humo; + BITMAP *tbmp = NULL; // bitmap temporal para el dibujado de sprites escalados + + if (nivel_detalle > 5) + drawing_mode(DRAW_MODE_TRANS, NULL, 0,0); // usar transparencias (queda joya!) + + while (tmp) { + /* dibujar */ + + // si el nivel de detalle es maximo, usara sprites transparentes + // escalados, lo cual es *muy* lento! + if (nivel_detalle >= 10 && fixtoi(tmp->r) > 5 && humo_spr != NULL) + { + tbmp = create_bitmap(fixtoi(tmp->r)*2,fixtoi(tmp->r)*2); + if (tbmp != NULL) + { + stretch_blit(humo_spr, tbmp, 0, 0, humo_spr->w, humo_spr->h,0,0,tbmp->w, tbmp->h); + draw_trans_sprite(bmp, tbmp, fixtoi(tmp->x)-x-(tbmp->w/2), fixtoi(tmp->y)-y-(tbmp->h/2)); + destroy_bitmap(tbmp); + tbmp = NULL; + } + } + else + { circlefill(bmp, fixtoi(tmp->x)-x, fixtoi(tmp->y)-y, fixtoi(tmp->r), tmp->col);} + + tmp = tmp->next; /* proximo... */ + } + + solid_mode(); +} + +/* Esta funcion se debe llamar cuando no se precise mas el humo + Libera la RAM usada y reinicia la lista + */ +void liberar_humo() +{ + HUMO *tmp = prt_1er_humo; + prt_1er_humo = NULL; + + while (tmp) { + HUMO *next = tmp->next; + free(tmp); + tmp = next; + } + +} + +#endif diff --git a/src/ia.c b/src/ia.c new file mode 100644 index 0000000..cb7de2c --- /dev/null +++ b/src/ia.c @@ -0,0 +1,149 @@ +// -------------------------------------------------------- +// ia.c +// -------------------------------------------------------- +// Copyright (c) Kronoman +// En memoria de mi querido padre +// -------------------------------------------------------- +// Sistema de inteligencia artificial utizando "ejecutables" +// binarios contenidos en un DAT +// -------------------------------------------------------- + +#include "allegro.h" +#include "error.h" +#include "ia.h" +#include "filedata.h" + +#include + +// Globales + +// Primer nodo de la lista enlazada +static IA_NODE *first_ia_node = NULL; + + +// Busca en la lista enlazada de IAs la que corresponde +// al nombre pasado, y devuelve un puntero a ella, o NULL si no se encuentra +IA_NODE *buscar_lista_ia(const char *id) +{ + IA_NODE *nodo = first_ia_node; + + // recorrer la lista enlazada + while (nodo) + { + if (ustricmp(id, nodo->id) == 0 ) return nodo; // lo encontro + nodo = nodo->next; + } + + return NULL; +} + +// Libera la lista enlazada de la IA +void liberar_lista_ia() +{ +IA_NODE *nodo = first_ia_node; +first_ia_node = NULL; + + while (nodo) + { + IA_NODE *next = nodo->next; + free(nodo->code); // debug, dudoso... + free(nodo); + nodo = next; + } +} + + +// Agrega un nodo de IA a la lista enlazada +// Pasarle un puntero al objeto conteniendo el script de IA (nodo nuevo) +static void agregar_nodo_ia(DATAFILE *dat) +{ + int i; + char *p; + char tmp[256]; // formacion de token + int tok = 0; // posicion en token + int params[6],idx = 0; // parametros y parametro leyendo ahora + int bytecode_actual = 0; // bytecodes cargados + IA_NODE *nodo = NULL; // nodo nuevo + + p = (char *)dat->dat; //stream de lectura y parsing + + // alocar RAM para el nodo + // nodo + nodo = (IA_NODE *)malloc(sizeof(IA_NODE)); + if (nodo == NULL) levantar_error ("FATAL!: Sin memoria en agregar_nodo_ia()!"); + nodo->next = first_ia_node; + first_ia_node = nodo; + + // bytecodes en el nodo, y propiedades extra + nodo->code = NULL; + + sprintf(nodo->id, "%s", get_datafile_property(dat, DAT_NAME)); + tmp[0] = '\0'; tok = 0; + + for (i=0; i < dat->size; i++) + { + + // llego al token? + if (p[i] == ',') + { + tmp[tok] = '\0'; + params[idx] = atoi(tmp); + + + idx++; + tok = 0; + if (idx == 6) // fin del bytecode + { + idx = 0; + if (nodo->code == NULL) + nodo->code = malloc(sizeof(IA_BYTECODE)); + else + nodo->code = realloc(nodo->code, sizeof(nodo->code) + sizeof(IA_BYTECODE)*(bytecode_actual+1)); + + // copiar info + nodo->code[bytecode_actual].x1 = params[0]; + nodo->code[bytecode_actual].x2 = params[1]; + nodo->code[bytecode_actual].y1 = params[2]; + nodo->code[bytecode_actual].y2 = params[3]; + nodo->code[bytecode_actual].weapon = params[4]; + nodo->code[bytecode_actual].loop = params[5]; + + bytecode_actual++; // otro bytecode mas... + } + } + else + { + tmp[tok] = p[i]; + tok++; + } + + } +nodo->size = bytecode_actual; +} + + +// Funcion que hace el cache de la IA en si +// Llamar solo al comienzo del juego, pasarle el nombre del archivo DAT a cargar +// Si falla, aborta el programa +// NOTA: la info de como funciona internamente el grabber, fue tomada de grabber.txt +void hacer_chache_ia(const char *file) +{ +DATAFILE *tmp = NULL; +int pos; + + tmp = krono_load_datafile(file); + if (tmp == NULL ) levantar_error("ERROR: fallo hacer_cache_ia();"); + + // Recorrer todo el archivo, buscando los de tipo IA + // DAT_ID es una macro que genera el identificador type (ver grabber.txt y get_datafile_property) + for (pos=0; tmp[pos].type != DAT_END; pos++) + { + if (tmp[pos].type == DAT_ID('I','A',' ',' ')) // tiene ID de "IA " ? + { + // encontro objeto en la IA, agregar nodo + agregar_nodo_ia((DATAFILE *)tmp+pos); + } + } + + unload_datafile(tmp); +} diff --git a/src/joymnu.c b/src/joymnu.c new file mode 100644 index 0000000..24aaa38 --- /dev/null +++ b/src/joymnu.c @@ -0,0 +1,264 @@ +/* + -------------------------------------------------------- + joymnu.c + Menu de calibracion del joystick + -------------------------------------------------------- +*/ + +#include +#include "joymnu.h" +#include "global.h" +#include "guitrans.h" +#include "guiprocs.h" + +/* + Probar el joystick + Pasarle el numero de joystick a probar +*/ +void probar_el_joystick(int nj) +{ + /* este objeto para dialogo dibuja hacia donde esta apuntando el joystick + y cambia de color cuando presiona el boton 1,2 o 3 + usa d2 para propositos internos... + */ + static int xbox_joystick_test_proc(int msg, DIALOG *d, int c) + { + int new_pos = 0; + int pos_x = 0 , pos_y = 0; // posicion (-1 = abj,izq, 1 = arr,der ) + if (msg == MSG_START) + { + d->d2 = -1; + } + + if(msg == MSG_DRAW) + { + rectfill(screen, d->x, d->y, d->x+d->w-2, d->y+d->h-2,gui_white_color); + gui_rect(screen, d->x, d->y, d->w - 1, d->h - 1, F_IN); + + // dibujar pos del joystick - chetoooo! + switch (d->d2) + { + case 1: + rectfill(screen, d->x, d->y+d->h/3*2-1, d->x+d->w/3-2, d->y+d->h-2, gui_light_color); + gui_rect(screen, d->x, d->y+d->h/3*2-1, d->w/3, d->h/3, F_LIGHT); + break; + + case 2: + rectfill(screen, d->x+d->w/3, d->y+d->h/3*2-1, d->x+d->w/3*2-2, d->y+d->h-2, gui_light_color); + gui_rect(screen, d->x+d->w/3, d->y+d->h/3*2-1, d->w/3, d->h/3, F_LIGHT); + break; + + case 3: + rectfill(screen, d->x+d->w/3*2, d->y+d->h/3*2-1, d->x+d->w-2, d->y+d->h-2, gui_light_color); + gui_rect(screen, d->x+d->w/3*2, d->y+d->h/3*2-1, d->w/3, d->h/3, F_LIGHT); + break; + + case 4: + rectfill(screen, d->x, d->y+d->h/3-1, d->x+d->w/3-2, d->y+d->h/3*2-2, gui_light_color); + gui_rect(screen, d->x, d->y+d->h/3-1, d->w/3, d->h/3, F_LIGHT); + break; + + case 5: + rectfill(screen, d->x+d->w/3, d->y+d->h/3-1, d->x+d->w/3*2-2, d->y+d->h/3*2-2, gui_light_color); + gui_rect(screen, d->x+d->w/3, d->y+d->h/3-1, d->w/3, d->h/3, F_LIGHT); + break; + + case 6: + rectfill(screen, d->x+d->w/3*2, d->y+d->h/3-1, d->x+d->w-2, d->y+d->h/3*2-2, gui_light_color); + gui_rect(screen, d->x+d->w/3*2, d->y+d->h/3-1, d->w/3, d->h/3, F_LIGHT); + break; + + case 7: + rectfill(screen, d->x, d->y+d->h/3-2, d->x+d->w/3-2, d->y, gui_light_color); + gui_rect(screen, d->x, d->y, d->w/3, d->h/3, F_LIGHT); + break; + + case 8: + rectfill(screen, d->x+d->w/3, d->y+d->h/3-2, d->x+d->w/3*2-2, d->y, gui_light_color); + gui_rect(screen, d->x+d->w/3,d->y, d->w/3, d->h/3, F_LIGHT); + break; + + case 9: + rectfill(screen, d->x+d->w/3*2, d->y+d->h/3-2, d->x+d->w-2, d->y, gui_light_color); + gui_rect(screen, d->x+d->w/3*2,d->y, d->w/3, d->h/3, F_LIGHT); + break; + + default: + msg = MSG_IDLE; // chequear que paso... + break; + } + } + + /* cuando esta idle, dibujar la posicion del joystick */ + if (msg == MSG_IDLE) + { + poll_joystick(); // absolutamente NECESARIO + + if (joy[nj].stick[0].axis[0].d1) pos_x = -1; + if (joy[nj].stick[0].axis[0].d2) pos_x = 1; + + if (joy[nj].stick[0].axis[1].d2) pos_y = -1; + if (joy[nj].stick[0].axis[1].d1) pos_y = 1; + if (pos_x == -1) + { + if (pos_y == -1) + new_pos = 1; + else + if (pos_y == 1) new_pos = 7; + else + new_pos = 4; + } + else + if (pos_x == 1) + { + if (pos_y == -1) + new_pos = 3; + else + if (pos_y == 1) new_pos = 9; + else + new_pos = 6; + + } + else + { + if (pos_y == -1) + new_pos = 2; + else + if (pos_y == 1) new_pos = 8; + else + new_pos = 5; + } + + if (new_pos != d->d2) + { + d->d2 = new_pos; + return D_REDRAWME; + } + } // fin IDLE + + return D_O_K; + } // fin del proc de test del joystick + + /* dialogo de prueba */ + DIALOG joy_test_dlg[] = + { + /* (proc) (x) (y) (w) (h) (fg) (bg) (key) (flags) (d1) (d2) (dp) (dp2) (dp3) */ + { xbox_proc, 0, 0, 160, 160, 0, 0, 0, 0, 0, 0, NULL, NULL, NULL }, + { xtext_proc, 4, 4, 152, 16, 0, 0, 0, 0, 0, 0, "Joystick", NULL, NULL }, + { xtext_proc, 4, 16, 152, 16, 0, 0, 0, 0, 0, 0, "Test", NULL, NULL }, + { xbox_joystick_test_proc, 35, 40, 90, 90, 0, 0, 0, 0, 0, 0, NULL, NULL, NULL }, + { xbutton_proc, 28, 140, 104, 16, 0, 0, 0, D_EXIT, 0, 0, "OK", NULL, NULL }, + { NULL, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, NULL, NULL, NULL } + }; + + /* ver si debo calibrar primero */ + if (joy[nj].flags & JOYFLAG_CALIBRATE) dialog_joystick_calibrate(nj); + + /* mostrar el dialogo */ + traducir_DIALOG_dp(joy_test_dlg); + centre_dialog(joy_test_dlg); + set_dialog_color(joy_test_dlg, makecol(0,0,0), makecol(255,255,255)); + + popup_dialog(joy_test_dlg, 0); + +} + +/* +Calibrar el joystick +Pasarle el numero de joystick a calibrar +*/ +void dialog_joystick_calibrate(int nj) +{ +AL_CONST char *msg; /* mensaje de calibracion */ + + /* reiniciar el joystick */ + remove_joystick(); + + alert(get_config_text("Center the joystick"), NULL, NULL, get_config_text("OK"), NULL, 0, 0); + + if (install_joystick(JOY_TYPE_AUTODETECT) != 0) + { + alert(get_config_text("Error initialising joystick"), get_config_text(allegro_error), NULL, get_config_text("OK"), NULL, 0, 0); + quiere_usar_joystick = FALSE; + return; + } + + /* Tenemos un joystick presente? */ + if (!num_joysticks) + { + alert(get_config_text("No joystick found"), NULL, NULL, get_config_text("OK"), NULL, 0, 0); + quiere_usar_joystick = FALSE; + return; + } + + /* calibrar si es necesario */ + while (joy[nj].flags & JOYFLAG_CALIBRATE) + { + msg = calibrate_joystick_name(nj); + + /* informar la accion a tomar */ + alert(get_config_text(msg), get_config_text("and press ENTER"), NULL, get_config_text("ENTER"), NULL, 0, 0); + + if (calibrate_joystick(nj) != 0) + { + alert(get_config_text("Error calibrating joystick!"), NULL, NULL, get_config_text("OK"), NULL, 0, 0); + return; + } + } +} + + +/* + Esto hace el menu de configuracion y calibracion del joystick +*/ +void joystick_configuration_menu() +{ +int ret = -1; + DIALOG joystick_config_dlg[] = +{ + /* (proc) (x) (y) (w) (h) (fg) (bg) (key) (flags) (d1) (d2) (dp) (dp2) (dp3) */ + { xbox_proc, 0, 0, 200, 136, 0, 0, 0, 0, 0, 0, NULL, NULL, NULL }, + { xtext_proc, 8, 4, 180, 12, 0, 0, 0, 0, 0, 0, "Joystick", NULL, NULL }, + { xcheck_proc, 8, 24, 184, 16, 0, 0, 0, 0, 1, 0, "Enable", NULL, NULL }, + { xbutton_proc, 8, 44, 184, 24, 0, 0, 0, D_EXIT, 0, 0, "Test", NULL, NULL }, + { xbutton_proc, 8, 72, 184, 24, 0, 0, 0, D_EXIT, 0, 0, "Calibrate", NULL, NULL }, + { xbutton_proc, 46, 104, 100, 24, 0, 0, 0, D_EXIT, 0, 0, "OK", NULL, NULL }, + { NULL, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, NULL, NULL, NULL } +}; + + /* Tenemos un joystick presente? */ + if (!num_joysticks) + { + alert(get_config_text("No joystick found"), NULL, NULL, get_config_text("OK"), NULL, 0, 0); + quiere_usar_joystick = FALSE; + return; + } + + traducir_DIALOG_dp(joystick_config_dlg); + centre_dialog(joystick_config_dlg); + set_dialog_color(joystick_config_dlg, makecol(0,0,0), makecol(255,255,255)); + + joystick_config_dlg[2].flags = (quiere_usar_joystick) ? D_SELECTED : 0 ; + + while (ret != 5) + { + ret = popup_dialog(joystick_config_dlg, 0); /* mostrar dialogo */ + if (ret == 3) // testear + { + probar_el_joystick(numero_de_joystick); + } + + if (ret == 4) // calibrar + { + /* calibrar el joystick */ + if ((numero_de_joystick < 0) || (numero_de_joystick > num_joysticks-1)) numero_de_joystick = 0; + dialog_joystick_calibrate(numero_de_joystick); + } + } + + + if (joystick_config_dlg[2].flags & D_SELECTED) + quiere_usar_joystick = TRUE; + else + quiere_usar_joystick = FALSE; +} diff --git a/src/jugador.c b/src/jugador.c new file mode 100644 index 0000000..a2a8348 --- /dev/null +++ b/src/jugador.c @@ -0,0 +1,764 @@ +// -------------------------------------------------------- +// jugador.c +// -------------------------------------------------------- +// Copyright (c) Kronoman +// En memoria de mi querido padre +// -------------------------------------------------------- +// Este modulo contiene todo lo relacionado con el jugador +// Tal como movimiento, disparos, etc... +// -------------------------------------------------------- +#ifndef JUGADOR_C +#define JUGADOR_C + +#include +#include +#include "pmask.h" +#include "azar.h" +#include "jugador.h" +#include "kfbuffer.h" +#include "sombras.h" +#include "mapa.h" +#include "combo.h" +#include "error.h" +#include "global.h" +#include "partic.h" +#include "sonido.h" +#include "bomba.h" + +/* GLOBALES, son exportadas para usarlas en otros modulos... */ +ARMA_JUG arma_tipo[MAX_ARM_CLASS]; /* tipos de armas */ +JUGADOR jugador; /* jugador */ +DISP_JUG *disp_jug_1 = NULL; /* puntero al 1er disparo del jugador */ +TECLADO_JUG teclado_jug; /* teclado del jugador */ + +/* ----------- RUTINAS DEL JUGADOR ----------------- */ + +/* Esta funcion dibuja el tablero del jugador + La barra de energia va al costado, parada (como R...) */ +void dibujar_tablero(BITMAP *bmp) +{ +char tablero_txt[2048]; // buffer texto del tablero +int y = 0; + +/* vaciar la parte vacia.. :P */ + rectfill(bmp, + bmp->w - 38, bmp->h - 2, + bmp->w - 2 , 2, + makecol(16,0,0) ); + +y = bmp->h - (jugador.vida * (bmp->h-2) / MAX_ENERGIA); + +// Barra de energia +if (jugador.vida > 0) + rectfill(bmp, + bmp->w - 38, bmp->h - 2, + bmp->w - 2 , y, + makecol(128,0,0) ); + + +// Colocar el % de energia que queda +if (nivel_detalle > 3) +{ + text_mode(-1); + textprintf_centre(bmp, hud_font, bmp->w - 20, (y < bmp->h -text_height(hud_font)) ? y : bmp->h - text_height(hud_font), makecol(255,255,255), "%d%%", (jugador.vida > 0) ? jugador.vida * 100 / MAX_ENERGIA : 0); +} + +// Borde rojo +rect(bmp, + bmp->w - 38, bmp->h - 2, + bmp->w - 2 , 2, + makecol(255,0,0) ); + +// si el nivel de detalle es muy bajo, chau... +if (nivel_detalle < 1) return; + + +// Dinero y cantidad de balas +sprintf(tablero_txt,"[$%09d][%s:%04d][B:%d]", jugador.dinero, arma_tipo[jugador.arma_actual].desc_short,jugador.arma[jugador.arma_actual], jugador.bombas); + +text_mode(-1); + + +// dependiendo del nivel de detalle, usa transparencia, o lo rebordea, o nada +if (nivel_detalle < 9) + { + textprintf(bmp, hud_font, 4, 4,makecol(0,0,0), "%s", tablero_txt); + } +else + { + drawing_mode(DRAW_MODE_TRANS, NULL, 0,0); // DEBUG, LENTO! + rectfill(bmp, 0,0, text_length(hud_font, tablero_txt)+6, text_height(hud_font)+2, makecol(32,32,32)); + solid_mode(); + } + +textprintf(bmp, hud_font, 2, 2,makecol(255,255,255), "%s", tablero_txt); +} + +/* Esta funcion setea el teclado a default */ +void set_teclado_default() +{ + teclado_jug.arr = KEY_UP; + teclado_jug.abj = KEY_DOWN; + teclado_jug.izq = KEY_LEFT; + teclado_jug.der = KEY_RIGHT; + teclado_jug.sht = KEY_Z; + teclado_jug.wpn = KEY_X; + teclado_jug.bmb = KEY_C; +} + +/* +Esto resetea totalmente el jugador. +Ideal para COMENZAR UN NUEVO JUEGO. +*/ +void reset_total_jugador() +{ + int i; + reset_parcial_jugador(); + jugador.dinero = jugador.init_money; + jugador.bombas = jugador.init_bombas; + + jugador.vida = MAX_ENERGIA; /* 100 % de energia */ + + /* no tiene ningun arma, excepto la 0 */ + for(i = 0; i < MAX_ARM_CLASS; i++) + jugador.arma[i] = 0; + + jugador.arma_actual = 0; /* arma 0 seleccionada */ + jugador.arma[0] = 1; /* tiene el arma 0 */ +} + +/* +Esto resetea el jugador parcialmente, util para cuando se pasa de nivel +Setea la posicion al inicio del nivel, saca la aceleracion, y recarga el timer del arma +*/ +void reset_parcial_jugador() +{ + jugador.x = itofix((W_FONDO - jugador.spr[1]->w) / 2); + jugador.y = itofix(H_FONDO - jugador.spr[1]->h - 5); + jugador.dx = jugador.dy = 0; + jugador.lastshoot = 0; + // Darle suficientes balas del arma 0, que es inifinita + jugador.arma[0] = 9999; + + /* TRUCO / CHEAT - DEBUG - MODO 'DIOS' */ + if (cheat_god_mode) jugador.dinero += 15000; // darle plata $$$ +} + +/* Esta funcion cambia a la proxima arma disponible */ +void jugador_proxima_arma() +{ + /* recorre el array de armas desde la actual hasta dar un loop, y + coloca la proxima 1era arma que aparezca */ + int i, i2; + i2 = jugador.arma_actual; + + for(i = 0; i < MAX_ARM_CLASS; i++) + { + i2++; + if (i2 > MAX_ARM_CLASS-1) i2 = 0; + if ( jugador.arma[i2] > 0 && jugador.arma_actual != i2) + { + jugador.arma_actual = i2; + break; + }; + } +} + +/* + Esta funcion debe ser llamada en la actualizacion logica + para leer el teclado y actuar en consecuencia + */ +void interpreta_teclado() +{ + + /* esta mascara de bits es el dummy driver, que el teclado, mouse o joystick modifican */ + int tk_driver = 0; + + #define ARR 1 + #define ABJ 2 + #define IZQ 4 + #define DER 8 + #define SHT 16 + #define WPN 32 + #define BMB 64 + + /* driver del mouse */ + if (quiere_usar_mouse) + { + int mickeyx = 0; int mickeyy = 0; + + if (mouse_needs_poll()) poll_mouse(); // debug, necesario ? + get_mouse_mickeys(&mickeyx, &mickeyy); + + if (mickeyx < -32 + mouse_velocidad) tk_driver |= IZQ; + if (mickeyx > 32 - mouse_velocidad) tk_driver |= DER; + + if (mickeyy < -32 + mouse_velocidad) tk_driver |= ARR; + if (mickeyy > 32 - mouse_velocidad) tk_driver |= ABJ; + + if (mouse_b & 1) tk_driver |= SHT; + if (mouse_b & 2) tk_driver |= WPN; + if (mouse_b & 4) tk_driver |= BMB; + } + + /* driver de joystick */ + if (quiere_usar_joystick) + { + poll_joystick(); // absolutamente NECESARIO + + // uso modo digital del joystick + if (joy[numero_de_joystick].stick[0].axis[0].d1) tk_driver |= IZQ; + if (joy[numero_de_joystick].stick[0].axis[0].d2) tk_driver |= DER; + + if (joy[numero_de_joystick].stick[0].axis[1].d1) tk_driver |= ARR; + if (joy[numero_de_joystick].stick[0].axis[1].d2) tk_driver |= ABJ; + + // botones - DEBUG: permitir configurar + // solo tomo los 3 primeros botones _existentes_ + if (joy[numero_de_joystick].num_buttons > 0) + if (joy[numero_de_joystick].button[0].b) tk_driver |= SHT; + + if (joy[numero_de_joystick].num_buttons > 1) + if (joy[numero_de_joystick].button[1].b) + { + joy[numero_de_joystick].button[1].b = 0; // hack horrible! + tk_driver |= WPN; + } + + if (joy[numero_de_joystick].num_buttons > 2) + { + if (joy[numero_de_joystick].button[2].b) tk_driver |= BMB; + } + else if (joy[numero_de_joystick].num_buttons > 1) /* emular 3er boton, con los dos primeros apretados */ + { + if ((joy[numero_de_joystick].button[0].b) && (joy[numero_de_joystick].button[1].b)) tk_driver |= BMB; + } + } + + /* driver de teclado, siempre funciona */ + if (keyboard_needs_poll()) poll_keyboard(); + + if (key[teclado_jug.der] ) tk_driver |= DER; + if (key[teclado_jug.izq] ) tk_driver |= IZQ; + if (key[teclado_jug.abj] ) tk_driver |= ABJ; + if (key[teclado_jug.arr] ) tk_driver |= ARR; + + if (key[teclado_jug.wpn] ) + { + tk_driver |= WPN; + key[teclado_jug.wpn] = FALSE; /* hack horrible! */ + } + if (key[teclado_jug.sht] ) tk_driver |= SHT; + if (key[teclado_jug.bmb] ) tk_driver |= BMB; + + + + /* Notar que el movimiento izq-der es instantaneo (imito a R??t?r) */ + if (tk_driver & DER) // derecha + { + if (jugador.dx < 0) + jugador.dx = 0; + else + jugador.dx = fixadd(jugador.dx, ftofix(VEL_X_J)); + + } + + if (tk_driver & IZQ) // izquierda + { + if (jugador.dx > 0) + jugador.dx = 0; + else + jugador.dx = fixsub(jugador.dx, ftofix(VEL_X_J)); + + } + + if (tk_driver & ARR) + { + if (jugador.dy > 0) + jugador.dy = 0; + else + jugador.dy = fixsub(jugador.dy, ftofix(VEL_Y_J)); + + } + + if (tk_driver & ABJ) + { + if (jugador.dy < 0) + jugador.dy = 0; + else + jugador.dy = fixadd(jugador.dy, ftofix(VEL_Y_J)); + + } + + if (tk_driver & SHT) agregar_disparo_jug(); /* disparar */ + + if (tk_driver & WPN) /* proxima arma... */ + { + jugador_proxima_arma(); + } + +/* +Agregado 16/12/2003 + esto soluciona un 'bug' en el cual, si se presiona LEFT/RIGHT, se aprieta UP/DOWN y se suelta, +la cosa sigue moviendo loca, no se porque + +descripcion del problema reportado por Ysaneya +For example, say your ship is at the bottom center of the screen. You press the up and left arrows at the same time, to make it go into the up-left direction. Your ship starts moving, fine. +Now, while the ship is moving, you release the up arrow, keeping the left arrow pressed. Your ship should logically move to the left, and slowly stop moving up, right ? +Well no, it continues the exact same movement in the up-left direction. That's why it's unplayable. Can't avoid any bullets. + +*/ +if (jugador.vida > 1) +{ + if (!(tk_driver & DER) && !(tk_driver & IZQ)) jugador.dx = 0; + if (!(tk_driver & ARR) && !(tk_driver & ABJ)) jugador.dy = 0; +} + + if (tk_driver & BMB) // lanzar bomba especial + { + if (jugador.bombas > 0 && !bomba_esta_activa) + { + jugador.bombas --; + bomba_esta_activa = TRUE; + bomba_detonacion = 7; // tiempo de destruccion masiva... :) + detonar_totalmente_el_piso(scroll_mapa); + + // sonido! + if (bomba_sonido != NULL) tocar_sonido(bomba_sonido, 255, 128, 1000); + } + } + + +} + +/* Esta funcion mueve el jugador, y no permite que se salga de pantalla, etc + Precisa saber el desplazamiento 'y' del mapa + Ademas, verifica la vida que le queda al jugador,hecha humo, lo explota y lo mata... :P +*/ +void mover_jugador(int fy) { + + /* TRUCO / CHEAT - DEBUG - MODO 'DIOS' */ + if (cheat_god_mode) jugador.vida = MAX_ENERGIA; + + if (jugador.dx > ftofix(MAX_VEL_J_X) ) jugador.dx = ftofix(MAX_VEL_J_X); + if (jugador.dy > ftofix(MAX_VEL_J_Y) ) jugador.dy = ftofix(MAX_VEL_J_Y); + + if (jugador.dx < ftofix(MAX_VEL_J_X * (-1.0)) ) jugador.dx = ftofix(MAX_VEL_J_X * (-1.0)); + if (jugador.dy < ftofix(MAX_VEL_J_Y * (-1.0)) ) jugador.dy = ftofix(MAX_VEL_J_Y * (-1.0)); + + jugador.x = fixadd (jugador.x, jugador.dx); + jugador.y = fixadd (jugador.y, jugador.dy); + + if (jugador.dx > 0) { + jugador.dx = fixsub(jugador.dx, ftofix(FRC_X_J)); + if (jugador.dx < 0) jugador.dx = 0; + } + + if (jugador.dx < 0) { + jugador.dx = fixadd(jugador.dx, ftofix(FRC_X_J)); + if (jugador.dx > 0) jugador.dx = 0; + } + + if (jugador.dy > 0) { + jugador.dy = fixsub(jugador.dy, ftofix(FRC_Y_J)); + if (jugador.dy < 0) jugador.dy = 0; + } + + if (jugador.dy < 0) { + jugador.dy = fixadd(jugador.dy, ftofix(FRC_Y_J)); + if (jugador.dy > 0) jugador.dy = 0; + } + + if (jugador.y < 0) jugador.y = 0; + + if (jugador.x < 0) jugador.x = 0; + + if (fixtoi(jugador.x) > ANCHO_FB - jugador.spr[1]->w ) jugador.x = itofix(ANCHO_FB - jugador.spr[1]->w); + + if (fixtoi(jugador.y) < fy ) jugador.y = itofix(fy); + if (fixtoi(jugador.y) > fy + ALTO_FB - jugador.spr[1]->h ) jugador.y = itofix(fy + ALTO_FB - jugador.spr[1]->h); + + jugador.lastshoot--; /* ir recargando arma */ + if (jugador.lastshoot < 0) jugador.lastshoot = 0; + + + /* Energia del jugador... exploto? combustionar al maldito! + y hacerle perder el control! */ + if (jugador.vida < 1) + { + jugador.vida -= rand()%3+1; /* combustiono la nave */ + + if (rand()%100 < abs((jugador.vida * 100) / JUG_MUERTO) ) /* incremental al irse combustionando */ + { + /* agregar explosiones peque~as... */ + pone_explo_pixel(&ptr_explo_arriba, + fixtoi(jugador.x)+rand()%jugador.spr[1]->w, + fixtoi(jugador.y)+rand()%jugador.spr[1]->h, + rand()%jugador.spr[1]->w + jugador.spr[1]->w/3, + rand()%30+10, + ftofix(0.01)); + /* descontrolar la nave */ + if (rand()%100 < 25) + { + jugador.dx = (rand()%100 < 50) ? ftofix(MAX_VEL_J_X * (-1.0)) : ftofix(MAX_VEL_J_X); + jugador.dy = (rand()%100 < 50) ? ftofix(MAX_VEL_J_Y * (-1.0)) : ftofix(MAX_VEL_J_Y); + } + } + + /* al aproximarse al final, recontra-explotar con pedazos y todo... */ + if (jugador.vida < (JUG_MUERTO / 4) ) + poner_explosion_nave(fixtoi(jugador.x)+jugador.spr[1]->w/2, fixtoi(jugador.y)+jugador.spr[1]->h/2, rand()%20+20, rand()%40+40, (rand()%100 < 25) ? -1 : 0); + + if (jugador.vida <= JUG_MUERTO) /* ahora si murio... */ + { + /* accionar en consecuencia... */ + salir_del_juego = TRUE; + } + } + else + { + /* Si aun esta vivo, y la energia del jugador es < 20 %, hechar humo y chispas, proporcional al jugador */ + if ((jugador.vida * 100 / MAX_ENERGIA < 30) && (nivel_detalle > 8) ) + { + if (rand()%((jugador.vida * 100 / MAX_ENERGIA)+1)< 15) // a medida que se quema, larga mas humo, notar el +1 impide division por 0 + { + int col, it; + col = rand()%32+16; + // humo + for (it=0; it < rand()%3+1; it++) + agrega_particula( fixadd(jugador.x, itofix(jugador.spr[1]->w/2 + rand_ex(10,-10))), fixadd(jugador.y, itofix(jugador.spr[1]->h + rand_ex(0, -5))), + fixmul(jugador.dx, ftofix( (float)rand_ex(0, -25)/100.0 ) ), ftofix((float)rand_ex(25, 70)/10.0), + rand_ex(5,15), + makecol(col,col,col), rand_ex(3,5), 1, + -1, ftofix((float)rand_ex(5, 15)/10.0), + NULL); + // chispa + for (it=0; it < rand()%3+1; it++) + agrega_particula( fixadd(jugador.x, itofix(jugador.spr[1]->w/2 + rand_ex(10,-10))), fixadd(jugador.y, itofix(jugador.spr[1]->h + rand_ex(0, -5))), + ftofix( (float)rand_ex(25, -25)/10.0 ), + ftofix((float)rand_ex(10, 30)/10.0), + rand_ex(3,10), + makecol(255,rand()%255,0), + rand_ex(1,2), + 1, + 0, 0,NULL); + } + } + + } +} + + +/* + Esta funcion dibuja la nave del jugador en + el bitmap, desplazado x,y, + dibuja tambien una sombra que se desplaza + en relacion al borde inferior del bitmap y el centro y del mismo + de manera de dar un look 3D (como el viejo Rapt*r :^P ) + TIENE que estar seteado el colormap de transparencia + */ +void dibujar_nave_jugador(BITMAP *bmp, int x, int y) +{ + int idx = 0; + /* Ver que sprite dibujar, si se esta inclinando izq-med-der */ + if (jugador.dx > ftofix(-4.5) && jugador.dx < ftofix(4.5)) /* medio.. */ + { + idx = 1; + } + else + { + if (jugador.dx < 0) /* izq */ + idx = 0; + else + idx = 2; + } + /* colocar la sombra */ + colocar_sombra(bmp, jugador.spr[idx+3], fixtoi(jugador.x)-x, fixtoi(jugador.y)-y); + + /* FALTA dibujar estela del motor - DEBUG */ + + /* Colocar jugador */ + draw_sprite(bmp, jugador.spr[idx], fixtoi(jugador.x)-x, fixtoi(jugador.y)-y); +} + +/* ----------- RUTINAS DE LA LISTA DE DISPAROS ----------------- */ + +/* + Esta funcion agrega un disparo a la lista de disparos + Automaticamente lo agrega usando el arma del jugador, etc + Ademas, verifica el timer, y todo lo demas. +*/ +void agregar_disparo_jug() +{ + int c = 0, i = 0; // auxiliares + + if (jugador.arma_actual < 0) return; /* jugador desarmado? shit! */ + + if (jugador.lastshoot > 0 ) return; /* NO es tiempo de poder disparar todavia */ + + if (jugador.vida < 0) return; /* esta muerto... no tenes armas! chau salame... */ + + // Verificar cantidad de balas, a menos que sea el arma 'infinita' (0) + if (jugador.arma[jugador.arma_actual] < 1 && jugador.arma_actual != 0) + { + // poner el arma siguiente disponible + jugador_proxima_arma(); + return; + } + else + { + // Descontar balas + if (jugador.arma_actual != 0) jugador.arma[jugador.arma_actual]--; + if (jugador.arma[jugador.arma_actual] < 0) jugador.arma[jugador.arma_actual] = 0; + } + + jugador.lastshoot = arma_tipo[jugador.arma_actual].firerate; + + /* EJECUTAR LOS SONIDOS DEL DISPARO EN GLORIOSO STEREO */ + tocar_sonido_paneado(fixtoi(jugador.x), + arma_tipo[jugador.arma_actual].snd[0], + rand_ex(240, 255), + rand_ex(900, 1100)); + + switch (arma_tipo[jugador.arma_actual].t) + { + case 1: + case 0: + c = 1; + break; + + case 2: + case 5: + c = 3; + break; + + case 3: + case 4: + c = 2; + break; + + case 6: // flak... invento especial... :P + c = 8; + break; + + default: + /* DEBUG: arma desconocida, no agregar nada.. */ + c = -1; + break; + } + + /* ir agregando disparos */ + for (i=0; inext = disp_jug_1; + disp_jug_1 = nueva; + + if (nueva != NULL) /* si el malloc funciono, seteo los datos... */ + { + nueva->arma = jugador.arma_actual; + nueva->vida = arma_tipo[jugador.arma_actual].vida; + + // valores default de coordenadas, genericos para todos los disparos + nueva->y = fixadd(jugador.y, itofix(jugador.spr[1]->h - arma_tipo[jugador.arma_actual].spr->h)); // la y sale del fondo de la nave + nueva->x = fixadd(jugador.x, itofix(jugador.spr[1]->w/2 - arma_tipo[jugador.arma_actual].spr->w / 2)); // la x sale del centro de la nave + + nueva->dx = arma_tipo[jugador.arma_actual].vx; + nueva->dy = arma_tipo[jugador.arma_actual].vy; + + /* Dependiendo del tipo de disparo, setear su posicion */ + switch (arma_tipo[jugador.arma_actual].t) + { + case 0: /* recto */ + nueva->dx = arma_tipo[jugador.arma_actual].vx; + nueva->dy = arma_tipo[jugador.arma_actual].vy; + break; + + case 1: /* direccion al azar */ + if (arma_tipo[jugador.arma_actual].vx == 0) arma_tipo[jugador.arma_actual].vx = itofix(5); + + nueva->dx = ftofix((float)rand_ex(-fixtoi(arma_tipo[jugador.arma_actual].vx)*10, fixtoi(arma_tipo[jugador.arma_actual].vx)*10)/10.0); + nueva->dy = arma_tipo[jugador.arma_actual].vy; + break; + + case 2: /* abanico triple */ + /* verificacion de seguridad */ + if (arma_tipo[jugador.arma_actual].vx == 0) arma_tipo[jugador.arma_actual].vx = itofix(5); + + if (i == 0) nueva->dx = arma_tipo[jugador.arma_actual].vx; + if (i == 1) nueva->dx = 0; + if (i == 2) nueva->dx = fixmul(itofix(-1), arma_tipo[jugador.arma_actual].vx); + nueva->dy = arma_tipo[jugador.arma_actual].vy; + break; + + case 3: /* doble recto, vx controla la apertura del disparo (debe ser >= 0) */ + + if (i == 0) + { + nueva->x = fixadd(jugador.x, itofix(jugador.spr[1]->w - arma_tipo[jugador.arma_actual].spr->w/2)); + nueva->dx = arma_tipo[jugador.arma_actual].vx; + } + else + { + nueva->x = fixsub(jugador.x, itofix(arma_tipo[jugador.arma_actual].spr->w/2)); + nueva->dx = fixmul(itofix(-1),arma_tipo[jugador.arma_actual].vx); + } + + nueva->dy = arma_tipo[jugador.arma_actual].vy; + break; + + case 4: /* 1 del centro, 1 al azar por disparo */ + if (i == 0) + { + nueva->dx = arma_tipo[jugador.arma_actual].vx; + nueva->dy = arma_tipo[jugador.arma_actual].vy; + } + else + { + nueva->dx = ftofix((float)rand_ex(-50, 50)/10.0); + nueva->dy = arma_tipo[jugador.arma_actual].vy; + } + break; + + case 5: // 1 del centro, 1 de la izq, 1 de la derecha (tipo misile pod, incluye una variacion del 10% al azar en la velocidad en y, para efecto misile pod) + // el disparo 0 sale del centro, por default + if (i == 1) nueva->x = fixadd(jugador.x, itofix(jugador.spr[1]->w - arma_tipo[jugador.arma_actual].spr->w/2)); + if (i == 2) nueva->x = fixsub(jugador.x, itofix(arma_tipo[jugador.arma_actual].spr->w/2)); + nueva->dy = fixmul(nueva->dy, ftofix( (float)(100 + rand_ex(-10, 10))/100.0 ) ); + break; + case 6: // ca~on de flak + if (i == 0) nueva->x = fixadd(jugador.x, itofix(jugador.spr[1]->w - arma_tipo[jugador.arma_actual].spr->w/2)); + if (i == 1) nueva->x = fixsub(jugador.x, itofix(arma_tipo[jugador.arma_actual].spr->w/2)); + + if (i > 1) + nueva->dx = ftofix((float)rand_ex(-fixtoi(arma_tipo[jugador.arma_actual].vx)*10, fixtoi(arma_tipo[jugador.arma_actual].vx)*10)/10.0); + else + nueva->dx = 0; + + break; + + default: /* ARMA desconocida - DEBUG */ + nueva->dx = 0; + nueva->dy = itofix(-15); + break; + + } /* fin switch */ + + /* Al terminar de setear el disparo, agrego una explosion, indicando + que de alli salio el disparo... */ + /* DEBUG, con el dibujo de la explosion se ve horrible! habria que + dibujar algo mejor... tipo una flama larga o algo */ + + // pone_explo_pixel(&ptr_explo_arriba, + // fixtoi(nueva->x), + // fixtoi(nueva->y), + // rand()%15+10, + // rand()%5+5, + // ftofix(0.01)); + + } /* fin != NULL */ + } /* fin for */ +}; + +/* + Esta funcion actualiza la logica de los disparos + ademas de remover los que tienen vida < 0 + y colocar particulas donde se mueven (si tiene un proyector de particulas ON) + Precisa saber el desplazamiento del mapa (fy) +*/ +void mover_disparos_jug(int fy) { + DISP_JUG **tmp_p = &disp_jug_1; + int i1; /* auxiliar para el for de la particula */ + + + while (*tmp_p) { + DISP_JUG *tmp = *tmp_p; + + /* aqui muevo */ + tmp->x = fixadd(tmp->x, tmp->dx); + tmp->y = fixadd(tmp->y, tmp->dy); + (tmp->vida)--; + + /* DEBUG: agregar estela en particulas, + esto podria ser una funcion aparte porque es bastante complicada la sintaxis... */ + if (nivel_detalle > 5) + for (i1=0; + i1 < rand_ex(arma_tipo[tmp->arma].est_cant[0], arma_tipo[tmp->arma].est_cant[1]); + i1++) + agrega_particula( fixadd(tmp->x, itofix(arma_tipo[tmp->arma].spr->w/2)), + fixadd(tmp->y, itofix(arma_tipo[tmp->arma].spr->h)), + ftofix(rand_ex(arma_tipo[tmp->arma].est_dx[0], arma_tipo[tmp->arma].est_dx[1])/100.0), + ftofix(rand_ex(arma_tipo[tmp->arma].est_dy[0], arma_tipo[tmp->arma].est_dy[1])/100.0), + rand_ex(arma_tipo[tmp->arma].est_vida[0], arma_tipo[tmp->arma].est_vida[1]), + makecol(rand_ex(arma_tipo[tmp->arma].est_color[0][0], arma_tipo[tmp->arma].est_color[0][1]), + rand_ex(arma_tipo[tmp->arma].est_color[1][0], arma_tipo[tmp->arma].est_color[1][1]), + rand_ex(arma_tipo[tmp->arma].est_color[2][0], arma_tipo[tmp->arma].est_color[2][1])), + rand_ex(arma_tipo[tmp->arma].est_rad[0],arma_tipo[tmp->arma].est_rad[1]), + rand_ex(arma_tipo[tmp->arma].est_tipo[0], arma_tipo[tmp->arma].est_tipo[1]), + arma_tipo[tmp->arma].est_transp,0, + NULL ); + + + /* LA VERIFICACION SI CHOCA EL DISPARO CONTRA LOS ENEMIGOS SE HACE EN enemigo.c!!! */ + + /* Verificar si rompio el fondo y quemarlo!!!! */ + /* Si explota, el disparo se elimina gradualmente */ + if (explotar_fondo((fixtoi(tmp->x)+arma_tipo[tmp->arma].spr->w/2)/W_GR, + (fixtoi(tmp->y)+arma_tipo[tmp->arma].spr->h/2)/H_GR, + arma_tipo[tmp->arma].punch*1.5)) + { + tmp->vida /= 2; + } + + if (fixtoi(tmp->y) < fy - ALTO_FB/4 ) tmp->vida = -1; /* el disparo se fue por arriba */ + if (fixtoi(tmp->y) > fy + ALTO_FB*2 ) tmp->vida = -1; /* el disparo se fue por abajo */ + + /* Remocion de disparos muertos */ + if (tmp->vida < 0) { + /* murio, eliminar!!! */ + *tmp_p = tmp->next; + free(tmp); + } + else + { + tmp_p = &tmp->next; /* siguiente por favor! */ + } + } +} + +/* Dibuja los disparos, desplazados por x,y + sobre el bitmap bmp */ +void dibujar_disp_jug(BITMAP *bmp, int x, int y) { + + DISP_JUG *tmp = disp_jug_1; + + while (tmp) + { + draw_sprite(bmp, arma_tipo[tmp->arma].spr, fixtoi(tmp->x)-x, fixtoi(tmp->y)-y); + +// if (KRONO_QUIERE_DEBUG) +// { +// text_mode(0); +// textprintf(bmp, font, fixtoi(tmp->x)-x, fixtoi(tmp->y)-y, makecol(255,255,255), "%d" , tmp->vida); +// } + + tmp = tmp->next; /* proximo... */ + } +} + + +/* Esta funcion se debe llamar cuando no se precise mas la lista + Libera la RAM usada y reinicia la lista + */ +void liberar_lista_disparos_jug() { + DISP_JUG *tmp = disp_jug_1; + disp_jug_1 = NULL; + + while (tmp) { + DISP_JUG *next = tmp->next; + free(tmp); + tmp = next; + } +} + +#endif diff --git a/src/kfbuffer.c b/src/kfbuffer.c new file mode 100644 index 0000000..e699b87 --- /dev/null +++ b/src/kfbuffer.c @@ -0,0 +1,55 @@ +/* + Todo el sistema trabaja renderizando en un bitmap + de un tama~o fijo, el cual luego se estira al tama~o de pantalla + Este archivo contiene el buffer, y los parametros de su tama~o + porque varias rutinas los necesitan, especialmente + la de descartar enemigos cuando salen por la parte inferior de pantalla + + -------------------------------------------------------- + Copyright (c) Kronoman + En memoria de mi querido padre + -------------------------------------------------------- + */ +#ifndef KFBUFFER_C +#define KFBUFFER_C + +#include "allegro.h" +#include "kfbuffer.h" + +/* globales */ + +/* BITMAP de dibujado, aqui debe dibujar toda la salida del programa */ +BITMAP *kfbufferbmp = NULL; + +/* Funcion que oscurece el buffer (ya dibujado) + con un interlazado en el color especificado + Sirve para boludeces + */ +void interlazar_kfbuffer(int r, int g, int b) +{ +int y = 0; +int c = makecol(r,g,b); +for (y = 0; y < kfbufferbmp->h; y+=2) + line(kfbufferbmp, 0, y, kfbufferbmp->w, y, c); + +} + +/* +Funcion que envia el buffer a pantalla. +Si el buffer no esta iniciado, lo inicia. +*/ +void enviar_kfbuffer2screen() +{ + if (kfbufferbmp == NULL) return; // kfbufferbmp = create_bitmap(ANCHO_RFB, ALTO_RFB); + +// acquire_screen(); /* acelera todo en windoze? creo que NO */ + + if (ALTO_RFB == SCREEN_H && ANCHO_RFB == SCREEN_W) + blit(kfbufferbmp, screen, 0, 0, 0, 0, kfbufferbmp->w, kfbufferbmp->h); + else + stretch_blit(kfbufferbmp, screen, 0, 0, kfbufferbmp->w, kfbufferbmp->h, 0, 0, SCREEN_W, SCREEN_H); + +// release_screen(); /* acordarse de hacer esto si se usa acquire_screen! */ +} + +#endif diff --git a/src/krstring.c b/src/krstring.c new file mode 100644 index 0000000..b4d522b --- /dev/null +++ b/src/krstring.c @@ -0,0 +1,65 @@ +// -------------------------------------------------------- +// krstring.c +// -------------------------------------------------------- +// Copyright (c) 2002, Kronoman +// En memoria de mi querido padre +// -------------------------------------------------------- +// Funciones para strings ASCII auxiliares +// -------------------------------------------------------- + +#ifndef KRSTRING_C +#define KRSTRING_C + +#include + +// -------------------------------------------------------- +// krtrim - +// Funcion equivalente a trim$ de qbasic, elimina +// los espacios adelante y atras de orig, y lo coloca en dest +// devuelve dest.- +// Es algo lenta ya que recorre varias veces la cadena +// dest debe tener espacio suficiente para alojar a orig!!! y un char '0' al final +// -------------------------------------------------------- +char *krtrim(char *dest, const char *orig) +{ +int ret, x1 = 0, x2 = 0, x3 = 0; + +dest[0] = '\0'; // por ahora vacia + +/* primero veo si son todos espacios... */ +ret = -1; +for (x1= 0; x1 < strlen(orig); x1++) if (orig[x1] != ' ') ret = 0; + +if (ret) return dest; /* la cadena es solo espacios... */ + +x1 = 0; // comienzo cadena + +x2 = strlen(orig)-1; + +// buscar cadena al final +while ( (orig[x2] == ' ') && (x2 >= 0) ) + { + x2--; + } + +if (x2 < 0) x2 = 0; + +// buscar cadena al principio +while ( (orig[x1] == ' ') && (x1 <= x2 ) ) + { + x1++; + } + +if (x1 > strlen(orig)-1 ) x1 = strlen(orig-1); + +// copiar +for (ret = x1; ret < x2+1; ret++) + { + dest[x3] = orig[ret]; + x3++; + } +dest[x3] = '\0'; + +return dest; +} +#endif diff --git a/src/main.c b/src/main.c new file mode 100644 index 0000000..a250914 --- /dev/null +++ b/src/main.c @@ -0,0 +1,197 @@ +// -------------------------------------------------------- +// Kraptor - Call of the freedom +// -------------------------------------------------------- +// main.c +// -------------------------------------------------------- +// Copyright (c) 2002-2004, Kronoman +// En memoria de mi querido padre +// -------------------------------------------------------- +// Este modulo es el 'arranque' del programa +// Inicia el video, carga los datos, etc... +// -------------------------------------------------------- +// Ultima revision: 18/ENERO/2004 + +#ifndef MAIN_C +#define MAIN_C + +// -------------------------------------------------------- +// Inclusiones +// -------------------------------------------------------- +#include +#include +#include +#include +#include /* DUMB: musica MOD, XM, etc */ +#include "main.h" +#include "error.h" +#include "game.h" +#include "data.h" +#include "jugador.h" +#include "global.h" +#include "menu.h" +#include "mapa.h" +#include "config.h" + + +int main(int argc, char *argv[] ) +{ + int i1; // para el for de los parametros + int rx = 640, ry = 480; // para permitir que el usuario elija la resolucion + int vid_card = GFX_AUTODETECT; // placa de video por defecto + + int snd = TRUE; // quiere sonido + lenguaje[0]='e'; + lenguaje[1]='s'; + lenguaje[2]= '\0'; + + /* Iniciar Allegro y el hardware */ + allegro_init(); + atexit(&dumb_exit); + + /* setear allegro al idioma configurado, default = en (ingles) */ + strncpy(lenguaje, get_config_string("system", "language", "en"), 2); + reload_config_texts(lenguaje); + + /* configuracion de DUMB, por default, CASI la mas baja (1), la mas baja es 0 :^) */ + dumb_resampling_quality = get_config_int("sound", "dumb_resampling_quality", 1); + dumb_it_max_to_mix = get_config_int("sound", "dumb_it_max_to_mix", 8); + + /* registro los IT, XM y S3M para cargarlos con DUMB */ + dumb_register_dat_it(DUMB_DAT_IT); + dumb_register_dat_xm(DUMB_DAT_XM); + dumb_register_dat_s3m(DUMB_DAT_S3M); + + + srand(time(0)); + if (install_timer() != 0) levantar_error("ERROR: Fallo el inicio del temporizador!"); + if (install_keyboard() != 0) levantar_error("ERROR: Imposible acceder al teclado!"); + + install_mouse(); /* Tambien uso el mouse para los menus! */ + + // -------------------------------------------------------- + // Interpretar parametros + // -------------------------------------------------------- + for (i1=1; i1 GRILLA_W-1) return 0; + if (y > GRILLA_H-1) return 0; + + if (mapa_g[x][y] == 0) return 0; /* este sector no es explosivo */ + + if (mapa_g[x][y] > 0) + { + mapa_g[x][y] -= punch; + + if (punch == -666) + { + mapa_g[x][y] = -1; /* explosion obligatoria */ + punch = rand()%10+10; /* evita un bug que impide explosiones, dejando areas superduras */ + } + + if (mapa_g[x][y] <= 0) /* EXPLOTO! */ + { + + /* Quemar area (le paso el punto central en x,y) */ + quemar_area(mapa_fondo, x * W_GR + W_GR/2+rand_ex(-5,5) , y * H_GR + H_GR/2+rand_ex(-5,5) , 30, 40); + + /* explosion */ + pone_explo_pixel(&ptr_explo_fondo, + x * W_GR + W_GR/2+rand_ex(-5,5), + y * H_GR + H_GR/2+rand_ex(-5,5), + rand()%W_GR/2+W_GR, rand()%W_GR/2+W_GR/2, + ftofix((float)(rand()%10+10)/1000.0) ); + + /* sonido */ + tocar_sonido_paneado(x * W_GR, + explo_cache_snd[rand()%3], + rand_ex(32, 64), + rand_ex(800, 1200)); + + /* emisor de humo en el piso - WOW! */ + agrega_emisor_humo(itofix(x * W_GR + W_GR/2 + rand_ex(-5,5)), + itofix(y * H_GR + H_GR/2 + rand_ex(-5,5)), + rand_ex(30,100)); + + mapa_g[x][y] = 0; /* seguridad */ + /* explotar los 4 contiguos + (diagonales no son necesarias, + los contiguos las atrapan ), + + DEBUG: + si explota el contiguo, quemar el area intermedia + para darle mas efecto. */ + + /* explosion obligatoria contigua */ + explotar_fondo(x-1, y, -666); + explotar_fondo(x+1, y, -666); + explotar_fondo(x, y-1, -666); + explotar_fondo(x, y+1, -666); + + return -1; /* EXPLOTO */ + } + + /* no exploto, pero toco, explotar poquisimo */ + pone_explo_pixel(&ptr_explo_fondo, + x * W_GR + W_GR/2+rand_ex(-5,5), + y * H_GR + H_GR/2+rand_ex(-5,5), + rand()%10+10, rand()%10+10, + ftofix((float)(rand()%10+10)/1000.0) ); + + return -2; + } + + if (mapa_g[x][y] < 0) mapa_g[x][y] = 0; /* seguridad */ + return 0; +} + +/* + Esta funcion se llama cuando inicia un nuevo nivel, para escanear todas + las lineas visibles de mapa en la primera pantalla +*/ +void scan_nivel_1era_vez() +{ + int y; + for (y=H_FONDO-ALTO_FB; y < H_FONDO; y++) scan_nuevos_enemigos(y / H_GR); +} + +/* + Esta funcion escanea una linea de la grilla + y agrega los nuevos enemigos. + Pasar en y la linea de la grilla a escanear (no pixels!) + NOTA: Por lo general sera: scroll_mapa / H_GR +*/ +void scan_nuevos_enemigos(int y) +{ + int x; + int cx, cy; // para calcular el centro, auxiliares + + if (y < 0) y = 0; + if (y > GRILLA_H-1) y = GRILLA_H-1; + + for (x = 0; x < GRILLA_W; x++) + { + + // coloca el enemigo centrado... + if (enem_g[x][y] > 0) + { + // desplazamiento para centrarlo + cx = (W_GR / 2) - (enem_t[enem_g[x][y]-1].spr[0]->w / 2); + cy = (H_GR / 2) - (enem_t[enem_g[x][y]-1].spr[0]->h / 2); + + // agregarlo... + agregar_enemigo(cx + (x*W_GR), cy + (y*H_GR), enem_g[x][y]-1 ); + } + + /* cada linea escaneada se coloca a 0, para no volver a usarla */ + enem_g[x][y] = 0; + } +} + +/* + Esta funcion quema un area del bitmap + utiliza funciones de transparencia + Pasarle las coordenadas en pixeles y el bmp a 'quemar' + ademas del radio del impacto (rad1) y el radio de las esquirlas (rad2) + + Las coordenadas son el *centro* de la quemazon! + + NOTA: mucho fue desabilitado a proposito (aunque funciona) porque + queda mas lindo de esta manera... ;^) + + */ +void quemar_area(BITMAP *bmp, int xp, int yp, int rad1, int rad2) +{ +int x = xp, y = yp, r = 0, i = 0 , c = 0, c2 = 0; + COLOR_MAP *color_map_bak = color_map; /* para restaur el color map */ + +// solid_mode(); + +drawing_mode(DRAW_MODE_TRANS, NULL, 0,0); + + +/* Impacto circular */ + +// c = makecol(0,0,0); + + +// r = rand_ex(nivel_detalle/2, nivel_detalle); +// r=r+2; +// for(i =0; i < r; i++) +// { +// c2 = rand()%16; +// c = makecol(c2,c2,c2); +// circlefill(bmp, +// x + rand_ex(-rad1/4, rad1/4), y + rand_ex(-rad1/4, rad1/4), +// rand_ex(rad1/4, rad1/2 ), c); /* entre 1/4 y 1/2 del radio */ +// } + + +/* Esquirlas */ +r = rand_ex(nivel_detalle/2, nivel_detalle); +r=r+2; + for(i =0; i < r; i++) + { + c2 = rand()%64; + c = makecol(c2,c2,c2); + + //if (rand()%100 < 30) + // line(bmp, x, y, x + rand_ex(-rad2, rad2), y + rand_ex(-rad2, rad2), c); + //else + triangle(bmp, + x + rand_ex(-rad2/3, rad2/3), y + rand_ex(-rad2/3, rad2/3), + x + rand_ex(-rad2/3, rad2/3), y + rand_ex(-rad2/3, rad2/3), + x + rand_ex(-rad2, rad2), y + rand_ex(-rad2, rad2), c); + } + + +/* Sub impacto triangular */ +// r = rand_ex(nivel_detalle/3, nivel_detalle/2); +// r=r+2; +// for(i =0; i < r; i++) +// { +// c2 = rand()%32; +// c = makecol(c2,c2,c2); +// +// triangle(bmp, +// x + rand_ex(-rad1, rad1), y + rand_ex(-rad1, rad1), +// x + rand_ex(-rad1, rad1), y + rand_ex(-rad1, rad1), +// x + rand_ex(-rad1, rad1), y + rand_ex(-rad1, rad1), c); +// } + +solid_mode(); + +// DEBUG: nuevo metodo, usa un sprite transparente rotado +// y un efecto de 'burn' +color_map = &tabla_quemado; + /* centrar el bitmap de quemazon */ + c = rand_ex(0,2); + x = xp - burn_cache_bmp[c]->w / 2; + y = yp - burn_cache_bmp[c]->h / 2; + draw_trans_sprite(mapa_fondo, burn_cache_bmp[c], x, y); +color_map = color_map_bak; + + +} + + +/* Esta funcion crea el mapa de transparencias +necesario para quemar, donde los tonos de negro dejan +el color igual, y los blancos queman el fondo +llamar: + create_color_table(&tabla_a_crear, + paleta_a_usar, + crear_mapa_quemazon, + NULL); + +NOTA: x es el color a dibujar + y es el color sobre el que se dibuja + + +*/ +void crear_mapa_quemazon(AL_CONST PALETTE pal, int x, int y, RGB *rgb) +{ + int r, g, b, r2, g2, b2; + float h,s,v, h2,s2,v2; + + r = (int)pal[x].r; + g = (int)pal[x].g; + b = (int)pal[x].b; + + r2 = (int)pal[y].r; + g2 = (int)pal[y].g; + b2 = (int)pal[y].b; + +/* si el color es suficientemente claro (oscuro para quemar), usarlo */ +if (r > 3 && g > 3 && b > 3) + { + /* invertir el color */ + r = 63 - r; + g = 63 - g; + b = 63 - b; + + /* no permitir demasiado brillo */ + r = MIN(48, r); + g = MIN(48, g); + b = MIN(48, b); + + /* tonalizar color destino (mult/div por 4 porque es 0..255) */ + rgb_to_hsv(r*4, g*4, b*4, &h, &s, &v); + + rgb_to_hsv(r2*4, g2*4, b2*4, &h2, &s2, &v2); + + /* tomo el valor minimo de luz, para que las cosas muy oscuras + no sean afectadas y aclaradas por mi quemazon (quedaria mal) */ + hsv_to_rgb(h2, s2, MIN(v, v2), &r, &g, &b); + + r /= 4; + g /= 4; + b /= 4; + } + else /* dejar color original */ + { + r = r2; + g = g2; + b = b2; + } + +rgb->r = r; +rgb->g = g; +rgb->b = b; +} // fin crear_mapa_aditivo + + +#endif diff --git a/src/menu.c b/src/menu.c new file mode 100644 index 0000000..2c3235b --- /dev/null +++ b/src/menu.c @@ -0,0 +1,672 @@ +/* + -------------------------------------------------------- + menu.c + -------------------------------------------------------- + Sistema de menu de Kraptor (al estilo de Unre*l) + Tiene el menu principal, y algunos otros menues cools (sonido, etc) + + NOTAS: TODOS LOS TEXTOS DEL MENU ESTAN EN *INGLES* + PARA PODER TRADUCIRLOS AUTOMATICAMENTE + CON EL ENGINE DE TRADUCCION. + USAR MENUES Y DIALOGOS *LOCALES* PARA QUE AL + ENTRAR/SALIR DE SCOPE, (CADA VEZ QUE SE LLAMA LA FUNCION) + SE TRADUZCAN AUTOMATICAMENTE AL LENGUAJE ORIGINAL. + -------------------------------------------------------- +*/ +#ifndef K_MENU_C +#define K_MENU_C + +#include +#include "main.h" +#include "guitrans.h" +#include "guiprocs.h" +#include "error.h" +#include "game.h" +#include "data.h" +#include "menu.h" +#include "global.h" +#include "jugador.h" +#include "savedlg.h" +#include "joymnu.h" + +/* Accion seleccionada en el menu, ver los #define en menu.h */ +static int menu_seleccionado = 0; + +BITMAP *bmp_menu_main = NULL; /* bitmap de fondo */ +PALETTE pal_menu_main; /* paleta del menu */ + +/* puntero a la ayuda del juego */ +char *texto_ayuda_juego = NULL; +char *texto_acerca_de_juego = NULL; /* acerca de... */ +BITMAP *acerca_de_bmp = NULL; /* bitmap acerca de... */ + +/* boton 'especial' que se usa para configurar el teclado + cuando se da click, muestra un mensaje, espera por + una tecla, y la almacena en la variable que apunta dp3 + dp3 debe ser un *int (ej: &jugador.arr) + si dp3 es NULL, llama a la funcion que resetea el teclado + del jugador. + Muestra el nombre de la tecla asignada en dp3 (readkey() >> 8) +*/ +static int keybutton_proc(int msg, DIALOG *d, int c) +{ + + /* nombres de teclas, extraido del ejemplo de Allegro, exkeys.c + y modificado para simplificar el display */ + char *key_names[] = + { + "(None)", "A", "B", "C", + "D", "E", "F", "G", + "H", "I", "J", "K", + "L", "M", "N", "O", + "P", "Q", "R", "S", + "T", "U", "V", "W", + "X", "Y", "Z", "0", + "1", "2", "3", "4", + "5", "6", "7", "8", + "9", "0 Pad", "1 Pad", "2 Pad", + "3 Pad", "4 Pad", "5 Pad", "6 Pad", + "7 Pad", "8 Pad", "9 Pad", "F1", + "F2", "F3", "F4", "F5", + "F6", "F7", "F8", "F9", + "F10", "F11", "F12", "Esc", + "`", "-", "=", "Backspace", + "Tab", "[", "]", "Enter", + ":", "'", "\\", "\\", + ",", ".", "/", "Space", + "Insert", "Del", "Home", "End", + "Pgup", "Pgdn", "Left", "Right", + "Up", "Down", "/ Pad", "*", + "- Pad", "+ Pad", "Del Pad", "Enter Pad", + "Prtscr", "Pause", "Abnt_C1", "Yen", + "Kana", "Convert", "Noconvert", "At", + "Circumflex", "Colon2", "Kanji", + "Lshift", "Rshift", "Lcontrol", "Rcontrol", + "Alt", "Altgr", "Lwin", "Rwin", + "Menu", "Scrlock", "Numlock", "Capslock", + "Max" + }; + + /* si selecciona, pedir tecla... */ + if (msg == MSG_CLICK || msg == MSG_KEY) + { + /* pone un ??? en el caption */ + int p = (d->flags & D_SELECTED) ? 1 : 0; + int style = ((p) ? F_IN : 0) | ((d->flags & D_GOTFOCUS) ? F_LIGHT : 0); + + scare_mouse(); + + gui_rect(screen, d->x, d->y, d->w, d->h, style); + rectfill(screen, d->x+1, d->y+1, d->x+d->w-2, d->y+d->h-2, (d->flags & D_GOTFOCUS) ? gui_light_color : gui_back_color); + + text_mode(-1); + gui_textout(screen, "???", d->x+p + d->w/2, d->y+p + (d->h-text_height(font))/2, (d->flags & D_DISABLED) ? gui_dark_color : gui_text_color, 1); + + unscare_mouse(); + + clear_keybuf(); + if (d->dp3 == NULL) + { + set_teclado_default(); + alert(get_config_text("Default keyboard"), NULL, NULL, get_config_text("OK"), NULL, 0, 0); + return D_REDRAW; + } + else + { + *((int *)d->dp3) = readkey() >> 8; /* leer tecla */ + } + + return D_REDRAWME; + } + else + { + + if(msg == MSG_DRAW && d->dp3 != NULL) /* al dibujar, setear el nombre de la tecla al actual */ + { + if ( *((int *)d->dp3) > -1 && *((int *)d->dp3) < 114) /* limitar rango */ + d->dp = (void *)get_config_text(key_names[*((int *)d->dp3)]); /* poner tecla en el caption, traducida y todo... */ + else + d->dp = (void *)get_config_text("Unknown"); + } + + return xbutton_proc(msg, d, c); /* sobrecarga la funcion base */ + } + return D_O_K; +} + + + + + +/* + Esta funcion fabrica el menu principal + tiene un monton de mierdas propias + dentro del mismo scope +*/ +static void hacer_el_menu_principal_helper() +{ + // comenzar un nuevo juego + static int nuevo_juego_mnu() + { + DIALOG skill_select_dlg[] = + { + /* (proc) (x) (y) (w) (h) (fg) (bg) (key) (flags) (d1) (d2) (dp) (dp2) (dp3) */ + { xbox_proc, 0, 0, 160, 128, 0, 0, 0, 0, 0, 0, NULL, NULL, NULL }, + { xbutton_proc, 8, 32, 144, 24, 0, 0, 0, D_EXIT, 0, 0, "Easy", NULL, NULL }, + { xbutton_proc, 8, 64, 144, 24, 0, 0, 0, D_EXIT, 0, 0, "Medium", NULL, NULL }, + { xbutton_proc, 8, 96, 144, 24, 0, 0, 0, D_EXIT, 0, 0, "Hard", NULL, NULL }, + { xtext_proc, 8, 8, 144, 16, 0, 0, 0, 0, 0, 0, "Skill", NULL, NULL }, + { NULL, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, NULL, NULL, NULL } + }; + + /* nivel de dificultad, */ + menu_seleccionado = MNU_S_NEW_GAME; + + traducir_DIALOG_dp(skill_select_dlg); + centre_dialog(skill_select_dlg); + set_dialog_color(skill_select_dlg, makecol(0,0,0), makecol(255,255,255)); + + nivel_de_dificultad = do_dialog(skill_select_dlg, 2) - 1; + if (nivel_de_dificultad < 0 || nivel_de_dificultad > 2) nivel_de_dificultad = 1; + + return D_CLOSE; + } + + // Carga un juego + static int cargar_mnu() + { + menu_seleccionado = MNU_S_LOAD_GAME; + + return D_CLOSE; + } + + static int salir_mnu() + { + menu_seleccionado = MNU_S_QUIT_GAME; + + return D_CLOSE; + } + + /* Permite seleccionar un nuevo modo de video */ + static int choose_video_mnu() + { + int card = 0, w = SCREEN_W, h = SCREEN_H; + + /* permitir elegir el modo de video */ + if (!gfx_mode_select(&card, &w, &h)) return D_REDRAW; + + set_color_depth(8); /* setear a 8bpp, en otros modos, no ANDA! */ + // DEBUG: FALTA INFORMAR SI FALLA EL MODO DE VIDEO + if (set_gfx_mode(card, w, h, 0, 0)) + if (set_gfx_mode(GFX_SAFE, 640, 480, 0, 0)) + if (set_gfx_mode(GFX_SAFE, 320, 200, 0, 0)) + levantar_error("ERROR: imposible utilizar algun modo grafico de 8bpp!"); + + return D_CLOSE; + } + + /* Acerca de... */ + static int acercade_proggy_mnu() + { + DIALOG acerca_de_dlg[] = + { + /* (proc) (x) (y) (w) (h) (fg) (bg) (key) (flags) (d1) (d2) (dp) (dp2) (dp3) */ + { xbox_proc, 0, 0, 320, 200, 0, 0, 0, 0, 0, 0, NULL, NULL, NULL }, + { xtextbox_proc, 4, 20, 152, 160, 0, 0, 0, 0, 0, 0, NULL, NULL, NULL }, + { xbutton_proc, 300, 4, 16, 12, 0, 0, 0, D_EXIT, 0, 0, "X", NULL, NULL }, + { xbox_proc, 164, 20, 152, 176, 0, 0, 0, 0, 0, 0, NULL, NULL, NULL }, + { xtext_proc, 4, 4, 100, 12, 0, 0, 0, 0, 0, 0, "About", NULL, NULL }, + { xbitmap_proc, 168, 24, 144, 168, 0, 0, 0, 0, 0, 0, NULL, NULL, NULL }, + { xtext_proc, 4, 184, 100, 12, 0, 0, 0, 0, 0, 0, "Version x.x.x", NULL, NULL }, + { NULL, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, NULL, NULL, NULL } + }; + + if (texto_acerca_de_juego == NULL || acerca_de_bmp == NULL) + { + alert("ERROR:", "No hay informacion disponible!", NULL, "Aceptar", NULL, 0, 0); + return D_REDRAW; + } + + /* DEBUG: alterar los indices [x] si cambia el dialogo! */ + acerca_de_dlg[1].dp = texto_acerca_de_juego; /* setear el texto de ayuda de disco */ + acerca_de_dlg[4].dp = (void *)get_config_text("About"); /* traducir el caption */ + acerca_de_dlg[5].dp = acerca_de_bmp; + acerca_de_dlg[6].dp = KRAPTOR_VERSION_STR; + + centre_dialog(acerca_de_dlg); + set_dialog_color(acerca_de_dlg, makecol(0,0,0), makecol(255,255,255)); + popup_dialog(acerca_de_dlg, 0); + + return D_REDRAW; + } + + /* idioma -> espa¤ol */ + static int cambia_espanol(void) + { + menu_seleccionado = MNU_S_CFG_SPANISH; + return D_CLOSE; + } + + /* idioma -> ingles */ + static int cambia_ingles(void) + { + menu_seleccionado = MNU_S_CFG_ENGLISH; + return D_CLOSE; + } + + /* Menu Juego */ + MENU menu_juego[] = + { + // text proc , child , flags, dp + { "New game", nuevo_juego_mnu, NULL, 0, NULL }, + { "Load game", cargar_mnu, NULL, 0, NULL }, + { "", NULL, NULL, 0, NULL }, + { "Exit game", salir_mnu, NULL, 0, NULL }, + { NULL, NULL, NULL, 0, NULL } + }; + + + /* Menu Configuracion */ + MENU menu_cfg[] = + { + // text proc , child , flags, dp + { "Sound", modificar_sonido_mnu, NULL, 0, NULL }, + { "Controls", mod_teclado_jugar, NULL, 0, NULL }, + { "Details", mod_detalle_mnu, NULL, 0, NULL }, + { "", NULL, NULL, 0, NULL }, + { "Video", choose_video_mnu, NULL, 0, NULL }, + { "", NULL, NULL, 0, NULL }, + { "Spanish", cambia_espanol, NULL, 0, NULL }, + { "English", cambia_ingles, NULL, 0, NULL }, + { NULL, NULL, NULL, 0, NULL } + }; + + /* Menu Ayuda */ + MENU menu_ayuda[] = + { + // text proc , child , flags, dp + { "Help", ayuda_proggy_mnu, NULL, 0, NULL }, + { "About", acercade_proggy_mnu,NULL, 0, NULL }, + { NULL, NULL, NULL, 0, NULL } + }; + + + /* Menu superior */ + MENU menu_top[] = + { + // text proc , child , flags, dp + { "&Game", NULL, menu_juego, 0, NULL }, + { "&Configuration", NULL, menu_cfg, 0, NULL }, + { "&Help", NULL, menu_ayuda, 0, NULL }, + { NULL, NULL, NULL, 0, NULL } + }; + + + /* Dialogo principal */ + DIALOG main_dlg[] = + { + /* (dialog proc) (x) (y) (w) (h) (fg) (bg) (key) (flags) (d1) (d2) (dp) (dp2) (dp3) */ + { d_menu_proc, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, menu_top, NULL, NULL }, + { NULL, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, NULL, NULL, NULL } + }; + + /* traducir menus 'al vuelo' */ + traducir_MENU_text(menu_juego); + traducir_MENU_text(menu_cfg); + traducir_MENU_text(menu_ayuda); + traducir_MENU_text(menu_top); + + menu_seleccionado = 0; + do_dialog(main_dlg, -1); + +} + + +/* +Funcion que muestra el menu principal + y actual en consecuencia */ +void realizar_menu_principal() +{ + menu_seleccionado = 0; + + while (menu_seleccionado != MNU_S_QUIT_GAME) + { + set_palette(pal_menu_main); + color_map = NULL; + rgb_map = NULL; + xset_gui_colors(); + + clear_keybuf(); + + set_mouse_sprite(NULL); /* acomoda puntero del mouse para que se ajuste a los colores */ + + stretch_blit(bmp_menu_main, + screen, + 0, 0, + bmp_menu_main->w, + bmp_menu_main->h, + 0, 0, + SCREEN_W, + SCREEN_H); + + /* hacer menu */ + hacer_el_menu_principal_helper(); + + switch (menu_seleccionado) + { + case MNU_S_NEW_GAME: // comenzar juego nuevo + comenzar_juego(FALSE); /* Rock 'n roll! */ + break; + + case MNU_S_LOAD_GAME: // cargar un juego + if (cargar_juego_menu()) + comenzar_juego(TRUE); // comenzar el juego, pero sin alterar las vars cargadas + break; + + case MNU_S_QUIT_GAME: /* Salir, confirmar primero */ + if (alert(get_config_text("Exit game"), + NULL, + NULL, + get_config_text("Yes"), + get_config_text("No"), + 0, 0) != 1) + { + menu_seleccionado = 0; + } + break; + + case MNU_S_CFG_SPANISH: // cambiar a espa~ol + reload_config_texts("es"); + lenguaje[0]='e'; + lenguaje[1]='s'; + lenguaje[2]= '\0'; + break; + + case MNU_S_CFG_ENGLISH: // cambiar a ingles + reload_config_texts("en"); + lenguaje[0]='e'; + lenguaje[1]='n'; + lenguaje[2]= '\0'; + break; + + default: + break; + } + } + + + +} + + +/* +Menu para modificar parametros de sonido y musica +SE PUEDE LLAMAR DESDE OTROS LADOS (ej: desde game.c) +*/ +int modificar_sonido_mnu(void) +{ + DIALOG sonido_dlg[] = + { + /* (proc) (x) (y) (w) (h) (fg) (bg) (key) (flags) (d1) (d2) (dp) (dp2) (dp3) */ + { xbox_proc, 0, 0, 150, 92, 0, 0, 0, 0, 0, 0, NULL, NULL, NULL }, + { xcheck_proc, 4, 4, 140, 12, 0, 0, 0, 0, 1, 0, "Sound", NULL, NULL }, + { xslider_proc, 4, 20, 140, 12, 0, 0, 0, 0, 255, 255, NULL, NULL, NULL }, + { xcheck_proc, 4, 36, 140, 12, 0, 0, 0, 0, 1, 0, "Music", NULL, NULL }, + { xslider_proc, 4, 52, 140, 12, 0, 0, 0, 0, 255, 255, NULL, NULL, NULL }, + { xbutton_proc, 35, 72, 80, 16, 0, 0, 0, D_EXIT, 0, 0, "OK", NULL, NULL }, + { NULL, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, NULL, NULL, NULL } + }; + + + traducir_DIALOG_dp(sonido_dlg); + centre_dialog(sonido_dlg); + set_dialog_color(sonido_dlg, makecol(0,0,0), makecol(255,255,255)); + + + /* setear parametros actuales */ + sonido_dlg[1].flags |= (quiere_snd) ? D_SELECTED : 0 ; + sonido_dlg[2].d2 = volumen_sonido; + sonido_dlg[3].flags |= (quiere_musica) ? D_SELECTED : 0 ; + sonido_dlg[4].d2 = volumen_musica; + + popup_dialog(sonido_dlg, 0); /* mostrar dialogo */ + + /* ajustar nuevos parametros */ + if (sonido_dlg[1].flags & D_SELECTED) + quiere_snd = TRUE; + else + quiere_snd = FALSE; + + volumen_sonido = sonido_dlg[2].d2; + + if (sonido_dlg[3].flags & D_SELECTED) + quiere_musica = TRUE; + else + quiere_musica = FALSE; + + volumen_musica = sonido_dlg[4].d2; + + return D_REDRAW; +} + +/* Esto permite configurar el teclado solamente */ +int configurar_el_teclado_solo(void) +{ + /* dialogo de configuracion */ + DIALOG dlg_teclado_config[] = + { + /* (proc) (x) (y) (w) (h) (fg) (bg) (key) (flags) (d1) (d2) (dp) (dp2) (dp3) */ + { xbox_proc, 0, 0, 248, 184, 0, 0, 0, 0, 0, 0, NULL, NULL, NULL }, + { xtext_proc, 8, 8, 188, 12, 0, 0, 0, 0, 0, 0, "Controls", NULL, NULL }, + { xbutton_proc, 8, 152, 72, 24, 0, 0, 0, D_EXIT, 0, 0, "OK", NULL, NULL }, + { keybutton_proc, 80, 24, 88, 24, 0, 0, 0, 0, 0, 0, "Up", NULL, NULL }, + { keybutton_proc, 8, 56, 88, 24, 0, 0, 0, 0, 0, 0, "Left", NULL, NULL }, + { keybutton_proc, 80, 88, 88, 24, 0, 0, 0, 0, 0, 0, "Down", NULL, NULL }, + { keybutton_proc, 152, 56, 88, 24, 0, 0, 0, 0, 0, 0, "Right", NULL, NULL }, + { keybutton_proc, 8, 120, 72, 24, 0, 0, 0, 0, 0, 0, "Shoot", NULL, NULL }, + { keybutton_proc, 88, 120, 72, 24, 0, 0, 0, 0, 0, 0, "Weapon", NULL, NULL }, + { keybutton_proc, 168, 120, 72, 24, 0, 0, 0, 0, 0, 0, "Special", NULL, NULL }, + { keybutton_proc, 168, 152, 72, 24, 0, 0, 0, 0, 0, 0, "Default", NULL, NULL }, + { NULL, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, NULL, NULL, NULL } + }; + + /* inicializo el dialogo (el compilador no permite inicializarlo arriba) */ + dlg_teclado_config[3].dp3 = &teclado_jug.arr; + dlg_teclado_config[4].dp3 = &teclado_jug.izq; + dlg_teclado_config[5].dp3 = &teclado_jug.abj; + dlg_teclado_config[6].dp3 = &teclado_jug.der; + dlg_teclado_config[7].dp3 = &teclado_jug.sht; + dlg_teclado_config[8].dp3 = &teclado_jug.wpn; + dlg_teclado_config[9].dp3 = &teclado_jug.bmb; + + traducir_DIALOG_dp(dlg_teclado_config); + centre_dialog(dlg_teclado_config); + set_dialog_color(dlg_teclado_config, makecol(0,0,0), makecol(255,255,255)); + + popup_dialog(dlg_teclado_config, 0); /* mostrar dialogo */ + +return D_REDRAW; +} + +/* permite configurar el mouse */ +int configurar_el_mouse(void) +{ +DIALOG mouse_cfg_dlg[] = +{ + /* (proc) (x) (y) (w) (h) (fg) (bg) (key) (flags) (d1) (d2) (dp) (dp2) (dp3) */ + { xbox_proc, 0, 0, 140, 128, 0, 0, 0, 0, 0, 0, NULL, NULL, NULL }, + { xtext_proc, 4, 4, 132, 16, 0, 0, 0, 0, 0, 0, "Mouse", NULL, NULL }, + { xcheck_proc, 4, 28, 132, 16, 0, 0, 0, 0, 1, 0, "Enable", NULL, NULL }, + { xtext_proc, 4, 56, 128, 16, 0, 0, 0, 0, 0, 0, "Speed", NULL, NULL }, + { xslider_proc, 4, 72, 132, 16, 0, 0, 0, 0, 32, 0, NULL, NULL, NULL }, + { xbutton_proc, 20, 100, 100, 20, 0, 0, 0, D_EXIT, 0, 0, "OK", NULL, NULL }, + { NULL, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, NULL, NULL, NULL } +}; + + traducir_DIALOG_dp(mouse_cfg_dlg); + centre_dialog(mouse_cfg_dlg); + set_dialog_color(mouse_cfg_dlg, makecol(0,0,0), makecol(255,255,255)); + + mouse_cfg_dlg[2].flags = (quiere_usar_mouse) ? D_SELECTED : 0 ; + mouse_cfg_dlg[4].d2 = mouse_velocidad; + + popup_dialog(mouse_cfg_dlg, 0); /* mostrar dialogo */ + + if (mouse_cfg_dlg[2].flags & D_SELECTED) + { quiere_usar_mouse = TRUE; } + else + { quiere_usar_mouse = FALSE; } + + mouse_velocidad = mouse_cfg_dlg[4].d2; + +return D_REDRAW; +} + + +/* +Permite configurar los controles, entre ellos, teclado, mouse, joystick +DEBUG: esta sin terminar +Puede ser llamado desde otros lados, ej: game.c +*/ +int mod_teclado_jugar(void) +{ +int ret = -1; + DIALOG controls_config_dlg[] = + { + /* (proc) (x) (y) (w) (h) (fg) (bg) (key) (flags) (d1) (d2) (dp) (dp2) (dp3) */ + { xbox_proc, 0, 0, 200, 168, 0, 0, 0, 0, 0, 0, NULL, NULL, NULL }, + { xtext_proc, 8, 4, 184, 16, 0, 0, 0, 0, 0, 0, "Controls", NULL, NULL }, + { xbutton_proc, 8, 24, 184, 32, 0, 0, 0, D_EXIT, 0, 0, "Keyboard config", NULL, NULL }, + { xbutton_proc, 8, 60, 184, 32, 0, 0, 0, D_EXIT, 0, 0, "Mouse config", NULL, NULL }, + { xbutton_proc, 8, 96, 184, 32, 0, 0, 0, D_EXIT, 0, 0, "Joystick config", NULL, NULL }, + { xbutton_proc, 50, 136, 100, 24, 0, 0, 0, D_EXIT, 0, 0, "OK", NULL, NULL }, + { NULL, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, NULL, NULL, NULL } + }; + + traducir_DIALOG_dp(controls_config_dlg); + centre_dialog(controls_config_dlg); + set_dialog_color(controls_config_dlg, makecol(0,0,0), makecol(255,255,255)); + + while (ret != 5) + { + ret = popup_dialog(controls_config_dlg, 0); /* mostrar dialogo */ + + if (ret == 2) configurar_el_teclado_solo(); + + if (ret == 3) configurar_el_mouse(); + + if (ret == 4) joystick_configuration_menu(); + } +return D_REDRAW; +} + +/* +Permite configurar los detalles +Puede ser llamado desde otros lados, ej: game.c +*/ +int mod_detalle_mnu(void) +{ + DIALOG detalle_dlg[] = +{ + /* (proc) (x) (y) (w) (h) (fg) (bg) (key) (flags) (d1) (d2) (dp) (dp2) (dp3) */ + { xbox_proc, 0, 0, 150, 96, 0, 0, 0, 0, 0, 0, NULL, NULL, NULL }, + { xtext_proc, 4, 4, 140, 12, 0, 0, 0, 0, 0, 0, "Detail level", NULL, NULL }, + { xslider_proc, 4, 18, 140, 14, 0, 0, 0, 0, 10, 10, NULL, NULL, NULL }, + { xbutton_proc, 32, 76, 80, 16, 0, 0, 0, D_EXIT, 0, 0, "OK", NULL, NULL }, + { xcheck_proc, 4, 36, 140, 12, 0, 0, 0, 0, 1, 0, "Auto adjust", NULL, NULL }, + { xcheck_proc, 4, 56, 140, 12, 0, 0, 0, 0, 1, 0, "Play videos", NULL, NULL }, + { NULL, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, NULL, NULL, NULL } +}; + + + traducir_DIALOG_dp(detalle_dlg); + centre_dialog(detalle_dlg); + set_dialog_color(detalle_dlg, makecol(0,0,0), makecol(255,255,255)); + + /* setear parametros actuales */ + detalle_dlg[2].d2 = nivel_detalle; + detalle_dlg[4].flags |= (detalle_automatico) ? D_SELECTED : 0 ; + detalle_dlg[5].flags |= (quiere_videos) ? D_SELECTED : 0; + + popup_dialog(detalle_dlg, 0); /* mostrar dialogo */ + + nivel_detalle = detalle_dlg[2].d2; + + if (detalle_dlg[4].flags & D_SELECTED) + detalle_automatico = TRUE; + else + detalle_automatico = FALSE; + + if (detalle_dlg[5].flags & D_SELECTED) + quiere_videos = TRUE; + else + quiere_videos = FALSE; + + return D_REDRAW; +} + +/* +Este menu generico es para ser llamado +desde game.c, presenta la configuracion 'al vuelo' +de sonido, teclado y detalles +*/ +int menu_configuracion_al_vuelo(void) +{ + DIALOG configurar_dlg[] = + { + /* (proc) (x) (y) (w) (h) (fg) (bg) (key) (flags) (d1) (d2) (dp) (dp2) (dp3) */ + { xbox_proc, 0, 0, 128, 152, 0, 0, 0, 0, 0, 0, NULL, NULL, NULL }, + { xtext_proc, 8, 8, 112, 8, 0, 0, 0, 0, 0, 0, "Configuration", NULL, NULL }, + { xbutton_proc, 8, 24, 112, 24, 0, 0, 0, D_EXIT, 0, 0, "Sound", modificar_sonido_mnu, NULL }, + { xbutton_proc, 8, 56, 112, 24, 0, 0, 0, D_EXIT, 0, 0, "Controls", mod_teclado_jugar, NULL }, + { xbutton_proc, 8, 88, 112, 24, 0, 0, 0, D_EXIT, 0, 0, "Details", mod_detalle_mnu, NULL }, + { xbutton_proc, 8, 128, 112, 16, 0, 0, 0, D_EXIT, 0, 0, "OK", NULL, NULL }, + { NULL, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, NULL, NULL, NULL } + }; + + traducir_DIALOG_dp(configurar_dlg); + centre_dialog(configurar_dlg); + set_dialog_color(configurar_dlg, makecol(0,0,0), makecol(255,255,255)); + + /* setear parametros actuales */ + + popup_dialog(configurar_dlg, 0); /* mostrar dialogo */ + + return D_REDRAW; +} + +/* Ayuda del programa +Puede ser llamado desde otros lados, ej: game.c +*/ +int ayuda_proggy_mnu() +{ + /* dialogo que muestra la ayuda */ + DIALOG ayuda_dlg[] = + { + /* (proc) (x) (y) (w) (h) (fg) (bg) (key) (flags) (d1) (d2) (dp) (dp2) (dp3) */ + { xbox_proc, 0, 0, 320, 200, 0, 0, 0, 0, 0, 0, NULL, NULL, NULL }, + { xtextbox_proc, 4, 20, 312, 176, 0, 0, 0, 0, 0, 0, NULL, NULL, NULL }, + { xbutton_proc, 300, 4, 16, 12, 0, 0, 0, D_EXIT, 0, 0, "X", NULL, NULL }, + { xtext_proc, 4, 4, 100, 12, 0, 0, 0, 0, 0, 0, "Help", NULL, NULL }, + { NULL, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, NULL, NULL, NULL } + }; + + if (texto_ayuda_juego == NULL) + { + alert("ERROR:", "No hay ayuda disponible!", NULL, "Aceptar", NULL, 0, 0); + return D_REDRAW; + } + + /* DEBUG: alterar los indices [x] si cambia el dialogo! */ + ayuda_dlg[1].dp = texto_ayuda_juego; /* setear el texto de ayuda de disco */ + ayuda_dlg[3].dp = (void *)get_config_text("Help"); /* traducir el caption */ + + centre_dialog(ayuda_dlg); + set_dialog_color(ayuda_dlg, makecol(0,0,0), makecol(255,255,255)); + popup_dialog(ayuda_dlg, 0); + + return D_REDRAW; +} + + +#endif diff --git a/src/partic.c b/src/partic.c new file mode 100644 index 0000000..7e80f6a --- /dev/null +++ b/src/partic.c @@ -0,0 +1,200 @@ +/*------------------------------------------------------- + partic.c + -------------------------------------------------------- + Copyright (c) 2002, Kronoman + En memoria de mi querido padre + Agosto - 2002 + -------------------------------------------------------- + Engine de particulas usando una lista enlazada + muy sencilla + --------------------------------------------------------*/ + +#ifndef PARTIC_C +#define PARTIC_C + +#include +#include "allegro.h" + +#include "partic.h" + + +/* DEBUG - estas variables son especificas a Kraptor */ + +#include "global.h" // para saber el nivel de detalle unicamente... + +/* Cache de bmps representando particulas para 'reventar' naves */ +BITMAP *particula_cache_bmp[3]; + +/* esta variable NO es necesaria, solo la uso para + ver cuantos enemigos hay en memoria, y de esa manera, + revisar la performance... */ +int cant_particulas_debug = 0; + + +/* --- globales internas --- */ + +static PARTICULA *prt_1era = NULL; /* puntero al comienzo de la lista de particulas */ + + +/* Esta funcion agrega una nueva particula a la lista enlazada [al principio]. + Devuelve puntero a la particula recien creada. + Los parametros son los parametros de la particula + Si vida <= 0, NO se crea la particula... (return derecho...) + */ +PARTICULA *agrega_particula( fixed x, fixed y, + fixed dx, fixed dy, + int vida, + int col, int r, int t, + int transp, fixed rg, + BITMAP *spr ) +{ + PARTICULA *nueva = NULL; + + if (vida <= 0) return NULL; /* ni pierdo el tiempo... */ + + if (nivel_detalle < 1) return NULL; // nivel de detalle minimo, no hacer nada + + nueva = malloc(sizeof(PARTICULA)); + nueva->next = prt_1era; + prt_1era = nueva; + + if (nueva != NULL) /* si el malloc funciono, seteo los datos... */ + { + nueva->x = x; + nueva->y = y; + nueva->transp = transp; + nueva->dx = dx; + nueva->dy = dy; + nueva->vida = vida; + nueva->col = col; + nueva->r = itofix(r); + nueva->rg = rg; + nueva->t = t; + nueva->spr = spr; + nueva->rot = itofix(rand()%255); /* rotacion del bitmap */ + } + + return nueva; +} + +/* + Esta funcion actualiza la logica (mueve) las particulas + tambien las elimina si vida < 0 o si estan fuera de pantalla + Pasar en x, y la posicion de scroll en pantalla + en w, h el ancho y alto de la pantalla + */ +void mover_particulas(int x, int y, int w, int h) +{ + PARTICULA **tmp_p = &prt_1era; + PARTICULA *tmp = NULL; + + cant_particulas_debug = 0; /* DEBUG: innecesario, solo para testear performance */ + + while (*tmp_p) { + + cant_particulas_debug++; /* DEBUG: innecesario, solo para testear performance */ + + tmp = *tmp_p; + + /* aqui muevo la particula */ + tmp->x = fixadd(tmp->x, tmp->dx); + tmp->y = fixadd(tmp->y, tmp->dy); + tmp->vida--; + + /* crecer radio si es necesario */ + tmp->r = fixadd ( tmp->r , tmp->rg ); + + /* girar sprite (si lo hubiere... */ + tmp->rot = fixadd(tmp->rot, itofix(rand()%16)+1); /* girar */ + if (fixtoi(tmp->rot) > 255) tmp->rot = 0; + + /* DEBUG: verificar si estan fuera de pantalla (da 5 pixeles de margen para + permitir que la particula salga totalmente de pantalla) */ + if (tmp->y < itofix(y-5)) tmp->vida = -1; + if (tmp->y > itofix(y+h+5)) tmp->vida = -1; + if (tmp->x < itofix(x-5)) tmp->vida = -1; + if (tmp->x > itofix(x+w+5)) tmp->vida = -1; + + if (tmp->vida < 0) { + /* la particula murio, eliminar!!! */ + *tmp_p = tmp->next; + free(tmp); + } else { + tmp_p = &tmp->next; /* siguiente por favor! */ + } + } +} + +/* + Esta funcion dibuja las particulas en el bitmap bmp + Las dibuja desplazadas x,y + */ +void dibujar_particulas(BITMAP *bmp, int x, int y) { + + PARTICULA *tmp = prt_1era; + + while (tmp) { + + /* dibujar */ + + // es transparente, y hay suf nivel de detalle? + if ((tmp->transp) && (nivel_detalle > 9)) drawing_mode(DRAW_MODE_TRANS, NULL, 0,0); + + if (tmp->spr == NULL) { + switch(tmp->t) + { + case 0: /* pixel */ + putpixel(bmp, fixtoi(tmp->x)-x, fixtoi(tmp->y)-y, tmp->col); + break; + + case 1: /* circulo */ + circlefill(bmp, fixtoi(tmp->x)-x, fixtoi(tmp->y)-y, fixtoi(tmp->r), tmp->col); + break; + + case 2: /* cuadrado (QU*KE?) */ + rectfill(bmp, fixtoi(tmp->x)-x, fixtoi(tmp->y)-y, fixtoi(tmp->x)+fixtoi(tmp->r)-x,fixtoi(tmp->y)+fixtoi(tmp->r)-y , tmp->col); + break; + + case 3: /* linea */ + line(bmp, fixtoi(tmp->x)-x, fixtoi(tmp->y)-y, fixtoi(fixadd(tmp->x, tmp->dx))-x, fixtoi(fixadd(tmp->y, tmp->dy))-y, tmp->col); + break; + + case 4: /* triangulo */ + triangle(bmp, + fixtoi(tmp->x)-x, fixtoi(tmp->y)-y, + fixtoi(tmp->x)+fixtoi(tmp->r)-x, fixtoi(tmp->y)+fixtoi(tmp->r)-y, + fixtoi(tmp->x)-fixtoi(tmp->r)-x, fixtoi(tmp->y)+fixtoi(tmp->r)-y, + tmp->col); + break; + + default: /* default: */ + /* si no coincide con ninguno, eliminar la particula... sorry */ + tmp->vida = 0; + break; + } + } else { /* tiene un sprite de imagen */ + rotate_sprite(bmp, tmp->spr, fixtoi(tmp->x)-x, fixtoi(tmp->y)-y, tmp->rot); + } + + solid_mode(); // sacar transparencia... + + tmp = tmp->next; /* proximo... */ + } +} + +/* Esta funcion se debe llamar cuando no se precise mas la lista + Libera la RAM usada y reinicia la lista + */ +void liberar_lista_particulas() { + PARTICULA *tmp = prt_1era; + prt_1era = NULL; + + while (tmp) { + PARTICULA *next = tmp->next; + free(tmp); + tmp = next; + } + +} + +#endif diff --git a/src/pmask.c b/src/pmask.c new file mode 100644 index 0000000..5817057 --- /dev/null +++ b/src/pmask.c @@ -0,0 +1,325 @@ +#include +#include +#include "pmask.h" + +#ifdef USE_ALLEGRO +#include +#endif + +#ifdef main +#undef main +#endif + +#ifdef USE_SDL +#include +#include +#endif + +#define COMPILE_TIME_ASSERT(condition) typedef char _compile_time_assert__[(condition) ? 1 : -1]; + +#define MAX_INTVAL(int_type) ((((unsigned int_type)(-1))-1)/2) + +int get_pmask_pixel(struct PMASK *mask, int x, int y) { + return 1 & (mask->mask[(mask->h * (x >> MASK_WORD_BITBITS)) + y] >> (x & (MASK_WORD_BITS-1))); +} +void set_pmask_pixel(struct PMASK *mask, int x, int y, int value) { + if (value) { + mask->mask[(mask->h * (x >> MASK_WORD_BITBITS)) + y] |= 1 << (x & (MASK_WORD_BITS-1)); + } else { + mask->mask[(mask->h * (x >> MASK_WORD_BITBITS)) + y] &=~(1 << (x & (MASK_WORD_BITS-1))); + } +} + +void install_pmask() { + COMPILE_TIME_ASSERT((1 << MASK_WORD_BITBITS) == MASK_WORD_BITS); + return; +} + +void init_pmask (struct PMASK *mask, int w, int h) +{ + int words, total_words, x; + + if ((w > MAX_INTVAL(short int)) || (h > MAX_INTVAL(short int)) || (w < 0) || (h < 0)) + { + mask->w = mask->h = 0; +#ifndef MASK_SINGLE_MEMORY_BLOCK + mask->mask = NULL; +#endif + return; + } + + words = 1 + ((w-1) >> MASK_WORD_BITBITS); + + total_words = words * h; + +#ifdef MASK_SINGLE_MEMORY_BLOCK + +#else + mask->mask = (MASK_WORD_TYPE *) malloc( + MASK_WORD_SIZE * total_words); + if (!mask->mask) { + mask->w = mask->h = 0; + return; + } +#endif + + //Now we initialize some of the fields of the structure... + mask->w = w; + mask->h = h; + +#ifdef CLEAR_pmask + //Now we have a proper mask structure allocated and mostly initialized, but the mask data has garbage! We have to initialize it to 0's: + for(x=0; x < total_words; x+=1) { + maskt->mask[x] = 0; + } +#else + //only clear right hand edge if CLEAR_MASK is not defined + for(x=total_words-h; x < total_words; x+=1) { + mask->mask[x] = 0; + } +#endif + return; +} + +void deinit_pmask(struct PMASK *mask) { + mask->w = 0; + mask->h = 0; +#ifndef MASK_SINGLE_MEMORY_BLOCK + if (mask->mask) free(mask->mask); + mask->mask = NULL; +#endif + return; +} + +void destroy_pmask(struct PMASK *mask) { + deinit_pmask(mask); + free(mask); + return; +} + +PMASK *create_pmask (int w, int h) { + struct PMASK *maskout; + +#ifdef MASK_SINGLE_MEMORY_BLOCK + int words, total_words; + words = 1 + ((w-1) >> MASK_WORD_BITBITS); + total_words = words * h; + maskout = (PMASK *) malloc( + sizeof(PMASK) + + MASK_WORD_SIZE * total_words ); + if(!maskout) return NULL; +#else + maskout = (PMASK *) malloc(sizeof(PMASK)); + if(!maskout) return NULL; +#endif + + init_pmask(maskout, w, h); + +#ifndef MASK_SINGLE_MEMORY_BLOCK + if (!maskout->mask) { + destroy_pmask(maskout); + return NULL; + } +#endif + + return maskout; +} + +void pmask_load_func (struct PMASK *mask, int _x, int _y, void *surface, int trans_color, int (*func)(void*,int,int)) +{ + int words, x, y, x2, w, h; + if(!mask) return; + + w = mask->w; + h = mask->h; + + words = 1 + ((w-1) >> MASK_WORD_BITBITS); + + //Now we have to create the bit mask array for the sprite: + for(x=0; x < words; x+=1) { + for(y=0; y < h; y+=1) { + MASK_WORD_TYPE m = 0; + for (x2=MASK_WORD_BITS-1; x2 >= 0; x2-=1) { + int x3 = (x << MASK_WORD_BITBITS) + x2 + _x; + m <<= 1; + if ( x3 < w ) { + if ( func(surface, x3, y+_y) != trans_color ) { + m |= 1; + } + } + } + mask->mask[y+x*h] = m; + } + } + return; +} + +void pmask_load_pixels (struct PMASK *mask, void *pixels, int pitch, int bytes_per_pixel, int trans_color) +{ + int words, x, y, x2, w, h; + if(!mask) return; + + w = mask->w; + h = mask->h; + + words = 1 + ((w-1) >> MASK_WORD_BITBITS); + + //Now we have to create the bit mask array for the sprite: + for(x=0; x < words; x+=1) { + for(y=0; y < h; y+=1) { + MASK_WORD_TYPE m = 0; + for (x2=MASK_WORD_BITS-1; x2 >= 0; x2-=1) { + int x3 = (x << MASK_WORD_BITBITS) + x2; + m <<= 1; + if ( x3mask[y+x*h] = m; + } + } + return; +} + +#ifdef USE_ALLEGRO +void init_allegro_pmask(struct PMASK *mask, struct BITMAP *sprite) { + pmask_load_func (mask, 0, 0, sprite, bitmap_mask_color(sprite), (int (*)(void*,int,int))getpixel); +} +PMASK *create_allegro_pmask(struct BITMAP *sprite) { + PMASK *ret; + ret = create_pmask(sprite->w, sprite->h); + init_allegro_pmask(ret, sprite); + return ret; +} +#endif + +#ifdef USE_SDL +static int SDL_getpixel(void *_surface, int x, int y) +{ + int bpp = ((SDL_Surface*)_surface)->format->BytesPerPixel; + /* Here p is the address to the pixel we want to retrieve */ + Uint8 *p = (Uint8 *)((SDL_Surface*)_surface)->pixels + y * ((SDL_Surface*)_surface)->pitch + x * bpp; + + switch(bpp) { + case 1: + return *p; + + case 2: + return *(Uint16 *)p; + + case 3: + if(SDL_BYTEORDER == SDL_BIG_ENDIAN) + return p[0] << 16 | p[1] << 8 | p[2]; + else + return p[0] | p[1] << 8 | p[2] << 16; + + case 4: + return *(Uint32 *)p; + + default: + return 0; /* shouldn't happen, but avoids warnings */ + } +} +void init_sdl_pmask(struct PMASK *mask, struct SDL_Surface *sprite, int trans_color) { + pmask_load_func (mask, 0, 0, sprite, trans_color, SDL_getpixel); +} +PMASK *create_sdl_pmask(struct SDL_Surface *sprite, int trans_color) { + PMASK *ret; + ret = create_pmask(sprite->w, sprite->h); + init_sdl_pmask(ret, sprite, trans_color); + return ret; +} +#endif + + +int check_pmask_collision(struct PMASK *mask1, struct PMASK *mask2, int x1, int y1, int x2, int y2) +{ + int h1, h2, words1, words2, max1, max2; + int dx1, dx2, dy1, dy2; //We will use this deltas... + int py; //This will store the Y position... + int maxh; //This will store the maximum height... + int block1, block2; + + //First we do normal bounding box collision detection... + if( !check_bb_collision(mask1, mask2, x1,y1, x2,y2) ) //If there is not bounding box collision... + return 0; //return that there is not collision... + + if (0) { //swap 1 & 2 + int tmp; + PMASK *mtmp; + tmp = x1; x1 = x2; x2 = tmp;//swap x + tmp = y1; y1 = y2; y2 = tmp;//swap y + mtmp = mask1; mask1 = mask2; mask2 = mtmp;//swap masks + } + + //First we need to see how much we have to shift the coordinates of the masks... + if(x1>x2) { + dx1=0; //don't need to shift mask 1. + dx2=x1-x2; //shift mask 2 left. Why left? Because we have the mask 1 being on the right of the mask 2, so we have to move mask 2 to the left to do the proper pixel perfect collision... + } else { + dx1=x2-x1; //shift mask 1 left. + dx2=0; //don't need to shift mask 2. + } + if(y1>y2) { + dy1=0; + dy2=y1-y2; //we need to move this many rows up mask 2. Why up? Because we have mask 1 being down of mask 2, so we have to move mask 2 up to do the proper pixel perfect collision detection... + } else { + dy1=y2-y1; //we need to move this many rows up mask 1. + dy2=0; + } + + block1 = dx1>>MASK_WORD_BITBITS; + block2 = dx2>>MASK_WORD_BITBITS; + dx1 &= MASK_WORD_BITS-1; + dx2 &= MASK_WORD_BITS-1; + + //This will calculate the maximum height that we will reach... + if(mask1->h-dy1 > mask2->h-dy2) { + maxh=mask2->h-dy2; + } else { + maxh=mask1->h-dy1; + } + maxh--; + + h1 = mask1->h; + h2 = mask2->h; + words1 = 1 + ((mask1->w-1) >> MASK_WORD_BITBITS); + words2 = 1 + ((mask2->w-1) >> MASK_WORD_BITBITS); + max1 = words1 * h1; + max2 = words2 * h2; + block1 = block1 * h1 + dy1; + block2 = block2 * h2 + dy2; + + while((block1=0;py--) { //Search vertically + if( + (mask1->mask[py + block1] >> dx1) & + (mask2->mask[py + block2] >> dx2) + ) + return 1; + } + //Now we have to move to the next block... + //we do blocks twice because of the shift + if( (!dx1) && (!dx2) ) { //In case both masks are lined up on the x axis... + block1 += h1; + block2 += h2; + } else { + if(!dx1) { + block2 += h2; + dx1 = MASK_WORD_BITS - dx2; + dx2 = 0; + } else { + if(!dx2) { + block1 += h1; + dx2 = MASK_WORD_BITS - dx1; + dx1 = 0; + } + } + } + } + return 0; +} + diff --git a/src/premio.c b/src/premio.c new file mode 100644 index 0000000..2b41ab0 --- /dev/null +++ b/src/premio.c @@ -0,0 +1,213 @@ +/*------------------------------------------------------- + premio.c + -------------------------------------------------------- + Copyright (c) 2002, Kronoman + En memoria de mi querido padre + Enero - 2003 + -------------------------------------------------------- + Engine de premios + usando una lista enlazada muy sencilla + --------------------------------------------------------*/ + +#ifndef PREMIO_C +#define PREMIO_C + +#include +#include + +#include "jugador.h" +#include "premio.h" +#include "azar.h" +#include "pmask.h" +#include "combo.h" // para las particulas +#include "global.h" // para chequear el nivel de detalle +#include "jugador.h" // para poder darle los premios +#include "sonido.h" + +/* globales exportadas */ +PREMIO_CLASS premio_class[MAX_PREMIO_CLASS]; + +/* --- globales internas --- */ +static PREMIO *prt_1er_premio = NULL; /* puntero al comienzo de la lista */ + +/* Esta funcion agrega un nuevo premio + Devuelve puntero al creado. + Si vida <= 0, NO se crea... + Pasarle el indice de la clase de premio a crear y su posicion + La direccion es elegida al azar... :) + */ +PREMIO *agrega_premio(int premio, fixed x, fixed y) +{ + PREMIO *nueva = NULL; + if (premio < 0 || premio > MAX_PREMIO_CLASS-1) return NULL; /* fuera de rango */ + if (premio_class[premio].vida <= 0) return NULL; /* ni pierdo el tiempo... */ + + + nueva = (PREMIO *)malloc(sizeof(PREMIO)); + nueva->next = prt_1er_premio; + prt_1er_premio = nueva; + + if (nueva != NULL) /* si el malloc funciono, seteo los datos... */ + { + nueva->x = x; + nueva->y = y; + nueva->r = itofix(rand()%256); + nueva->dx = ftofix((float)rand_ex(-500, 500) / 100.0); + nueva->dy = ftofix((float)rand_ex(-500, 500) / 100.0); + nueva->dr = ftofix((float)rand_ex(-160, 160) / 10.0); + nueva->vida = premio_class[premio].vida; + nueva->clase = premio; + } + + return nueva; +} + +/* + Esta funcion actualiza la logica (mueve) los premios + tambien los elimina si vida < 0 o si estan fuera de pantalla + Pasar en x, y la posicion de scroll en pantalla + en w, h el ancho y alto de la pantalla + Comprueba si toca al jugador, para darle el premio tambien... + */ +void mover_premio(int x, int y, int w, int h) +{ +// int i; + PREMIO **tmp_p = &prt_1er_premio; + PREMIO *tmp = NULL; + + while (*tmp_p) { + + tmp = *tmp_p; + tmp->x = fixadd(tmp->x, tmp->dx); + tmp->y = fixadd(tmp->y, tmp->dy); + tmp->r = fixadd(tmp->r, tmp->dr); // rotar + + /* debug: comprobar si toco al jugador; bounding box pedorro */ + if (check_bb_collision_general(fixtoi(tmp->x),fixtoi(tmp->y), + premio_class[tmp->clase].sprite->w, + premio_class[tmp->clase].sprite->h, + fixtoi(jugador.x),fixtoi(jugador.y), + jugador.spr[1]->w ,jugador.spr[1]->h) != 0) + { + /* toco al jugador, dar premio! */ + + switch (premio_class[tmp->clase].premiar) + { + case -2: // bombas + jugador.bombas += premio_class[tmp->clase].cantidad; + + if (jugador.bombas > jugador.max_bombas) + jugador.bombas = jugador.max_bombas; + + break; + + case -1: // energia + jugador.vida += premio_class[tmp->clase].cantidad; + if (jugador.vida >= MAX_ENERGIA) jugador.vida = MAX_ENERGIA; + break; + + default: // arma + jugador.arma[premio_class[tmp->clase].premiar] += premio_class[tmp->clase].cantidad; + + if (jugador.arma[premio_class[tmp->clase].premiar] > arma_tipo[premio_class[tmp->clase].premiar].cant_ammo_max) + jugador.arma[premio_class[tmp->clase].premiar] = arma_tipo[premio_class[tmp->clase].premiar].cant_ammo_max; + + // seleccionar el arma - DEBUG, no se si es lo mejor... + jugador.arma_actual = premio_class[tmp->clase].premiar; + break; + } + + // tocar el sonido!! + if (premio_class[tmp->clase].sonido != NULL) + tocar_sonido(premio_class[tmp->clase].sonido, 255, 128, 1000); + + tmp->vida = 0; + } + + + tmp->vida--; + + /* verificar si estan fuera de pantalla y hacerlos rebotar */ + + if (tmp->y < itofix(y)) + { + tmp->y = itofix(y); + tmp->dy = fixmul(tmp->dy, itofix(-1)); + } + if (tmp->x < itofix(x)) + { + tmp->x = itofix(x); + tmp->dx = fixmul(tmp->dx, itofix(-1)); + } + + if (tmp->x > itofix(x + w - premio_class[tmp->clase].sprite->w)) + { + tmp->x = itofix(x + w - premio_class[tmp->clase].sprite->w); + tmp->dx = fixmul(tmp->dx, itofix(-1)); + } + + if (tmp->y > itofix(y + h - premio_class[tmp->clase].sprite->h)) + { + tmp->y = itofix(y + h - premio_class[tmp->clase].sprite->h); + tmp->dy = fixmul(tmp->dy, itofix(-1)); + } + + if (tmp->vida < 0) { + /* murio, eliminar!!! */ + + /* explotan con algunas particulas */ + if (nivel_detalle > 7) + poner_muchas_particulas( fixtoi(tmp->x), fixtoi(tmp->y), + 5,5, + 10, + -1, 1, 1, + NULL, + rand()%10+30 ); + + + *tmp_p = tmp->next; + + free(tmp); + + } else { + tmp_p = &tmp->next; /* siguiente por favor! */ + } + } +} + +/* Esta funcion se debe llamar cuando no se precise + mas la lista de premios + Libera la RAM usada y reinicia la lista + */ +void liberar_premio() +{ + PREMIO *tmp = prt_1er_premio; + prt_1er_premio = NULL; + + while (tmp) { + PREMIO *next = tmp->next; + free(tmp); + tmp = next; + } +} + +/* + Esta funcion dibuja los premios en el bitmap bmp + Las dibuja desplazado x,y + */ +void dibujar_premio(BITMAP *bmp, int x, int y) +{ + PREMIO *tmp = prt_1er_premio; + + while (tmp) { + /* dibujar */ + if (premio_class[tmp->clase].sprite != NULL) + rotate_sprite(bmp, premio_class[tmp->clase].sprite, fixtoi(tmp->x)-x, fixtoi(tmp->y)-y, tmp->r); + else + circlefill(bmp, fixtoi(tmp->x)-x, fixtoi(tmp->y)-y, 5, makecol(255,255,255)); + + tmp = tmp->next; /* proximo... */ + } +} + +#endif diff --git a/src/rvideo.c b/src/rvideo.c new file mode 100644 index 0000000..cbd4b7d --- /dev/null +++ b/src/rvideo.c @@ -0,0 +1,75 @@ +// ---------------------------------------------------------------- +// rvideo.c +// ---------------------------------------------------------------- +// Produce un video de un juego a archivos bmp sueltos +// Ideal para generar un video promocional de un juego +// Por Kronoman +// Copyrigth Enero 2003, Kronoman +// En memoria de mi querido padre +// ---------------------------------------------------------------- +// Para que esto funcione, debe ser llamado en cada actualizacion +// logica del juego, de esa manera mantiene los fps constantes +// ---------------------------------------------------------------- + + +#include +#include +#include "rvideo.h" + +// Globales de configuracion +char rvideo_filen[1024]; // prefijo del video, setear a algo antes de empezar! +int rvideo_cadafsave = 10; // cada cuantas llamadas salvar el frame (1 =todas, 2 = la mitad, etc) +int rvideo_step = 0; // frame actual del step antes de salvar el frame (cuando esto = rvideo_cadafsave, salva el frame) +int rvideo_f_actual = 0; // frame actual de grabacion +int rvideo_is_recording = FALSE; // estoy grabando? (permite hacer pausas, etc) +int rvideo_resize = TRUE; // reacomodar el tama~o de salida? SI/NO +int rvideo_w = 320, rvideo_h = 200; + +// Funcion de inicializacion, solo por seguridad... :) +void init_rvideo() +{ + rvideo_cadafsave = 10; // default 1/10 de los fps logicos del juego + rvideo_step = 0; + rvideo_f_actual = 1; // empezo a grabar de 0001 + sprintf(rvideo_filen, "rvideo"); // prefijo default + rvideo_is_recording = FALSE; + rvideo_resize = TRUE; + rvideo_w = 320; + rvideo_h = 200; +} + +// Funcion de grabacion, llamar en las actualizaciones logicas del juego +// pasarle el bitmap que contiene la imagen, y la paleta +void rvideo_record(BITMAP *bmp, RGB *pal) +{ +char filename[2048]; // archivo a salvar +BITMAP *tmp = NULL; + +if (!rvideo_is_recording) return; // no estamos grabando +rvideo_step++; +if (rvideo_step < rvideo_cadafsave) return; // todavia no salvar + +sprintf(filename, "%s%04d.bmp", rvideo_filen, rvideo_f_actual); + +rvideo_f_actual++; +// salvar frame +if (rvideo_resize && rvideo_w != bmp->w && rvideo_h != bmp->h) + { + // el frame debe ser reajustado en tama~o + tmp = create_bitmap(rvideo_w, rvideo_h); + if (tmp == NULL) return; + + stretch_blit(bmp, tmp, 0, 0, bmp->w, bmp->h, 0, 0, tmp->w, tmp->h); + save_bmp(filename, tmp, pal); // salvar + + if (tmp != NULL) destroy_bitmap(tmp); + } +else + { + // frame 'tal cual' + save_bmp(filename, bmp, pal); // salvar + } + +rvideo_step = 0; +} + diff --git a/src/savedlg.c b/src/savedlg.c new file mode 100644 index 0000000..be91106 --- /dev/null +++ b/src/savedlg.c @@ -0,0 +1,230 @@ +// ------------------------------------ +// savedlg.c +// ------------------------------------ +// Sistema de salva / carga de juego +// Por Kronoman +// En memoria de mi querido padre +// Copyright (c) 2002, Kronoman +// ------------------------------------ + +#include +#include +#include +#include +#include "savedlg.h" +#include "jugador.h" +#include "global.h" +#include "guitrans.h" +#include "guiprocs.h" + +static SAVE_GAME_ST save_cache[SAVE_GAME_SLOTS]; // save games en cache... ;-P + +// Auxiliar que carga los savegames de disco a cache... +static void cachear_savegames() +{ + int i; + PACKFILE *f; + char fname[80]; + for (i=0; i < SAVE_GAME_SLOTS; i ++) save_cache[i].es_valido = FALSE; + + for (i=0; i < SAVE_GAME_SLOTS; i ++) + { + sprintf(fname, "krap%02d.ksv", i); + f = pack_fopen(fname, F_READ_PACKED); // usa compresion! ojo! + if (f != NULL) + { + // leer el chunk de una... + if (pack_fread(&save_cache[i], sizeof(SAVE_GAME_ST), f) != sizeof(SAVE_GAME_ST)) + { + save_cache[i].es_valido = FALSE; // este slot no se pudo leer OK + } + pack_fclose(f); + } + else + { + save_cache[i].es_valido = FALSE; // no pudo abrir el archivo + } + } +} + +// Auxiliar que salva los savegames de cache a disco... +static void salvar_cache_savegames() +{ + int i; + PACKFILE *f; + char fname[80]; + + for (i=0; i < SAVE_GAME_SLOTS; i ++) + { + if (save_cache[i].es_valido) + { + sprintf(fname, "krap%02d.ksv", i); + f = pack_fopen(fname, F_WRITE_PACKED); // usa compresion! ojo! + if (f != NULL) + { + // salvar el chunk de una... + pack_fwrite(&save_cache[i], sizeof(SAVE_GAME_ST), f); + pack_fclose(f); + } + } + } +} + +// Esto presenta el menu de salvar juego +void salvar_juego_menu() +{ + int ret = 0; + int i = 0; + struct tm the_time; // hora/fecha actual, para la desc del savegame + time_t current_time; + struct tm *t; // para obtener la hora/fecha actual + +DIALOG save_dlg[] = +{ + /* (proc) (x) (y) (w) (h) (fg) (bg) (key) (flags) (d1) (d2) (dp) (dp2) (dp3) */ + { xbox_proc, 96, 40, 320, 200, 0, 0, 0, 0, 0, 0, NULL, NULL, NULL }, + { xtext_proc, 104, 48, 144, 12, 0, 0, 0, 0, 0, 0, "Save game", NULL, NULL }, + { xbutton_proc, 104, 64, 304, 16, 0, 0, 0, D_EXIT, 0, 0, "Free slot", NULL, NULL }, + { xbutton_proc, 104, 84, 304, 16, 0, 0, 0, D_EXIT, 0, 0, "Free slot", NULL, NULL }, + { xbutton_proc, 104, 104, 304, 16, 0, 0, 0, D_EXIT, 0, 0, "Free slot", NULL, NULL }, + { xbutton_proc, 104, 124, 304, 16, 0, 0, 0, D_EXIT, 0, 0, "Free slot", NULL, NULL }, + { xbutton_proc, 104, 144, 304, 16, 0, 0, 0, D_EXIT, 0, 0, "Free slot", NULL, NULL }, + { xbutton_proc, 104, 164, 304, 16, 0, 0, 0, D_EXIT, 0, 0, "Free slot", NULL, NULL }, + { xbutton_proc, 104, 184, 304, 16, 0, 0, 0, D_EXIT, 0, 0, "Free slot", NULL, NULL }, + { xbutton_proc, 208, 208, 104, 24, 0, 0, 0, D_EXIT, 0, 0, "OK", NULL, NULL }, + { NULL, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, NULL, NULL, NULL } +}; + + traducir_DIALOG_dp(save_dlg); + centre_dialog(save_dlg); + set_dialog_color(save_dlg, makecol(0,0,0), makecol(255,255,255)); + + + cachear_savegames(); // levantar los savegames en cache... + // colocar los savegames en el menu + for (i=0; i < SAVE_GAME_SLOTS; i ++) + if (save_cache[i].es_valido) save_dlg[i+2].dp = save_cache[i].desc; + + do + { + ret = popup_dialog(save_dlg, 0); /* mostrar dialogo */ + if (ret >= 2 && ret <= 8) + { + // salvar + // confirmar! + if (alert(get_config_text("Save game"), + NULL, + NULL, + get_config_text("Yes"), + get_config_text("No"), + 0, 0) == 1) + { + // Prepara un nombre de savegame descriptivo + // sprintf(save_cache[ret-2].desc, "Game/Juego #%d", ret-1); + // obtener la hora actual + current_time = time(NULL); + t = localtime(¤t_time); + the_time = *t; + // descripcion: hora+fecha+nivel+dinero, + // 5+1+10+1+4+1+10= 32 caracteres + sprintf(save_cache[ret-2].desc, + "%02d:%02d %02d/%02d/%04d L%03d $%09d", + the_time.tm_hour, + the_time.tm_min, + the_time.tm_mday, + the_time.tm_mon+1, + the_time.tm_year+1900, + nivel_actual, + jugador.dinero ); + + save_cache[ret-2].desc[40] = '\0'; + save_cache[ret-2].es_valido = TRUE; + save_cache[ret-2].vida = jugador.vida; + save_cache[ret-2].dinero = jugador.dinero; + memcpy(save_cache[ret-2].arma, jugador.arma, sizeof(int)*MAX_ARM_CLASS); + save_cache[ret-2].arma_actual = jugador.arma_actual; + save_cache[ret-2].bombas = jugador.bombas; + save_cache[ret-2].nivel_actual = nivel_actual; + save_cache[ret-2].nivel_de_dificultad = nivel_de_dificultad; + + salvar_cache_savegames(); + // mensaje avisando + alert(get_config_text("Game saved"), + NULL, NULL, + get_config_text("OK"), + NULL, 0, 0); + ret = 9; // salir + } + } + } while (ret != 9); + +}; + +// Esto presenta el menu de cargar juego +// Los datos son cargados en RAM +// Devuelve: +// TRUE = si se cargo un juego, por lo tanto, al salir de esta funcion, se deberia comenzar el juego... +// FALSE = si no se cargo nada +int cargar_juego_menu() +{ + int ret = 0; + int i = 0; + +DIALOG load_dlg[] = +{ + /* (proc) (x) (y) (w) (h) (fg) (bg) (key) (flags) (d1) (d2) (dp) (dp2) (dp3) */ + { xbox_proc, 96, 40, 320, 200, 0, 0, 0, 0, 0, 0, NULL, NULL, NULL }, + { xtext_proc, 104, 48, 144, 12, 0, 0, 0, 0, 0, 0, "Load game", NULL, NULL }, + { xbutton_proc, 104, 64, 304, 16, 0, 0, 0, D_EXIT, 0, 0, "Free slot", NULL, NULL }, + { xbutton_proc, 104, 84, 304, 16, 0, 0, 0, D_EXIT, 0, 0, "Free slot", NULL, NULL }, + { xbutton_proc, 104, 104, 304, 16, 0, 0, 0, D_EXIT, 0, 0, "Free slot", NULL, NULL }, + { xbutton_proc, 104, 124, 304, 16, 0, 0, 0, D_EXIT, 0, 0, "Free slot", NULL, NULL }, + { xbutton_proc, 104, 144, 304, 16, 0, 0, 0, D_EXIT, 0, 0, "Free slot", NULL, NULL }, + { xbutton_proc, 104, 164, 304, 16, 0, 0, 0, D_EXIT, 0, 0, "Free slot", NULL, NULL }, + { xbutton_proc, 104, 184, 304, 16, 0, 0, 0, D_EXIT, 0, 0, "Free slot", NULL, NULL }, + { xbutton_proc, 208, 208, 104, 24, 0, 0, 0, D_EXIT, 0, 0, "OK", NULL, NULL }, + { NULL, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, NULL, NULL, NULL } +}; + + traducir_DIALOG_dp(load_dlg); + centre_dialog(load_dlg); + set_dialog_color(load_dlg, makecol(0,0,0), makecol(255,255,255)); + + + cachear_savegames(); // levantar los savegames en cache... + // colocar los savegames en el menu + for (i=0; i < SAVE_GAME_SLOTS; i ++) + if (save_cache[i].es_valido) load_dlg[i+2].dp = save_cache[i].desc; + + do + { + ret = do_dialog(load_dlg, 0); /* mostrar dialogo */ + if (ret >= 2 && ret <= 8) + { + // cargar + if (save_cache[ret-2].es_valido) + { + jugador.vida = save_cache[ret-2].vida; + jugador.dinero = save_cache[ret-2].dinero; + memcpy(jugador.arma, save_cache[ret-2].arma, sizeof(int)*MAX_ARM_CLASS); + jugador.arma_actual = save_cache[ret-2].arma_actual; + jugador.bombas = save_cache[ret-2].bombas; + nivel_actual = save_cache[ret-2].nivel_actual; + nivel_de_dificultad = save_cache[ret-2].nivel_de_dificultad; + + return TRUE; // al salir de esta funcion, se deberia comenzar el juego... + } + else + { + // Avisar que no hay juego salvado + alert(get_config_text("Is not a saved game"), + NULL, NULL, + get_config_text("OK"), + NULL, 0, 0); + } + } + + } while (ret != 9); + +return FALSE; +}; diff --git a/src/shopping.c b/src/shopping.c new file mode 100644 index 0000000..4a0bd79 --- /dev/null +++ b/src/shopping.c @@ -0,0 +1,381 @@ +/* + -------------------------------------------------------- + shopping.c + -------------------------------------------------------- + Sistema de shopping de Kraptor + + NOTAS: TODOS LOS TEXTOS DEL MENU ESTAN EN *INGLES* + PARA PODER TRADUCIRLOS AUTOMATICAMENTE + CON EL ENGINE DE TRADUCCION. + USAR MENUES Y DIALOGOS *LOCALES* PARA QUE AL + ENTRAR/SALIR DE SCOPE, (CADA VEZ QUE SE LLAMA LA FUNCION) + SE TRADUZCAN AUTOMATICAMENTE AL LENGUAJE ORIGINAL. + -------------------------------------------------------- +*/ + +#include +#include +#include "guitrans.h" +#include "guiprocs.h" +#include "shopping.h" +#include "jugador.h" +#include "savedlg.h" + +// Imagen de fondo +BITMAP *shop_bmp = NULL; + + +/* + Esta funcion es la principal + Muestra el shop en pantalla y comienza todo. + Llamar con la paleta de juego ya seteada. +*/ +void do_shopping_principal() +{ +/* variables que se muestran en el dialogo */ +char str_cant[256], str_money[256], str_desc[2048], str_precio[256]; +int ret = 0; /* respuesta del dialogo */ +int item_idx = -2; /* indice del item mostrado, -1 = energia, -2 = bomba */ + +/* indices de items importantes en el dialogo */ +#define IDX_PREV_BTN 3 +#define IDX_NEXT_BTN 4 +#define IDX_BUY_BTN 5 +#define IDX_SELL_BTN 6 +#define IDX_SAVE_BTN 7 +#define IDX_EXIT_BTN 8 +#define IDX_DESC 9 +#define IDX_BMP 10 +#define IDX_MONEY 12 +#define IDX_CANT 14 +#define IDX_PRICE 16 + + DIALOG shop_main_dlg[] = + { + /* (proc) (x) (y) (w) (h) (fg) (bg) (key) (flags) (d1) (d2) (dp) (dp2) (dp3) */ + { xbox_proc, 0, 0, 320, 192, 0, 0, 0, 0, 0, 0, NULL, NULL, NULL }, + { xbox_proc, 76, 4, 240, 184, 0, 0, 0, 0, 1, 0, NULL, NULL, NULL }, + { xbox_proc, 84, 8, 228, 160, 0, 0, 0, 0, 1, 0, NULL, NULL, NULL }, + { xbutton_proc, 4, 4, 32, 16, 0, 0, 0, D_EXIT, 0, 0, "<<", NULL, NULL }, + { xbutton_proc, 40, 4, 32, 16, 0, 0, 0, D_EXIT, 0, 0, ">>", NULL, NULL }, + { xbutton_proc, 4, 28, 68, 24, 0, 0, 0, D_EXIT, 0, 0, "Buy", NULL, NULL }, + { xbutton_proc, 4, 60, 68, 24, 0, 0, 0, D_EXIT, 0, 0, "Sell", NULL, NULL }, + { xbutton_proc, 4, 116, 68, 44, 0, 0, 0, D_EXIT, 0, 0, "Save", NULL, NULL }, + { xbutton_proc, 4, 168, 68, 20, 0, 0, 0, D_EXIT, 0, 0, "OK", NULL, NULL }, + { xtextbox_proc, 200, 12, 108, 124, 0, 0, 0, 0, 0, 0, NULL, NULL, NULL }, + { xbitmap_proc, 88, 12, 108, 124, 0, 0, 0, 0, 0, 0, NULL, NULL, NULL }, + { xtext_proc, 88, 172, 68, 12, 0, 0, 0, 0, 0, 0, "Money", NULL, NULL }, + { xtext_proc, 160, 172, 148, 12, 0, 0, 0, 0, 0, 0, "1234567890", NULL, NULL }, + { xtext_proc, 88, 140, 68, 12, 0, 0, 0, 0, 0, 0, "Amount", NULL, NULL }, + { xtext_proc, 160, 140, 148, 12, 0, 0, 0, 0, 0, 0, "1234567890", NULL, NULL }, + { xtext_proc, 88, 152, 68, 12, 0, 0, 0, 0, 0, 0, "Price", NULL, NULL }, + { xtext_proc, 160, 152, 148, 12, 0, 0, 0, 0, 0, 0, "1234567890", NULL, NULL }, + { NULL, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, NULL, NULL, NULL } + }; + + traducir_DIALOG_dp(shop_main_dlg); + centre_dialog(shop_main_dlg); + set_dialog_color(shop_main_dlg, makecol(0,0,0), makecol(255,255,255)); + + + clear(screen); + if (shop_bmp != NULL) + stretch_blit( shop_bmp, + screen, + 0, 0, + shop_bmp->w, + shop_bmp->h, + 0, 0, + SCREEN_W, + SCREEN_H); // Fondo + + /* looping principal */ + ret = 0; + while (ret != IDX_EXIT_BTN) + { + /* setear variables a mostrar */ + sprintf(str_cant," %9d",0); + sprintf(str_money,"$ %9d", jugador.dinero); + sprintf(str_desc, get_config_text("Unknown")); + sprintf(str_precio,"$ %9d", 0); + shop_main_dlg[IDX_MONEY].dp = (void *)str_money; /* dinero del jugador */ + + shop_main_dlg[IDX_DESC].dp = (void *)str_desc; /* descripcion */ + shop_main_dlg[IDX_BMP].dp = NULL; /* bitmap */ + shop_main_dlg[IDX_CANT].dp = (void *)str_cant; /* cantidad que tiene */ + shop_main_dlg[IDX_PRICE].dp = (void *)str_precio; /* precio */ + + + + if (ret == IDX_NEXT_BTN) // proximo item + { + int i, i2; + i2 = item_idx; + + for(i = 0; i < MAX_ARM_CLASS; i++) + { + i2++; + if (i2 > MAX_ARM_CLASS-1) i2 = -2; + if (i2 > -1) + { + if ( arma_tipo[i2].precio >= 0) + { + item_idx = i2; + break; + }; + } + if (i2 == -1 || i2 == -2) + { + item_idx = i2; + break; + } + } + } // fin proximo item + + if (ret == IDX_PREV_BTN) // item anterior + { + int i, i2; + i2 = item_idx; + + for(i = 0; i < MAX_ARM_CLASS; i++) + { + i2--; + if (i2 < -2) i2 = MAX_ARM_CLASS-1; + + if (i2 > -1) + { + if ( arma_tipo[i2].precio >= 0) + { + item_idx = i2; + break; + }; + } + if (i2 == -1 || i2 == -2) + { + item_idx = i2; + break; + } + } + } // fin item anterior + + // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + /* Setear informacion real */ + if (item_idx < 0) // es la energia o la bomba? + { + if (item_idx == -1) + { + /* item - energia */ + shop_main_dlg[IDX_DESC].dp = (void *)jugador.reparar_desc; + + sprintf(str_precio,"$ %9d x %4d", jugador.reparar_precio, jugador.reparar_cantidad); + + sprintf(str_cant,"%4d / %4d", jugador.vida, MAX_ENERGIA); + + shop_main_dlg[IDX_BMP].dp = (void *)jugador.reparar_bmp; + } + + if (item_idx == -2) + { + /* item - bomba */ + shop_main_dlg[IDX_DESC].dp = (void *)jugador.bomba_desc; + + sprintf(str_precio,"$ %9d x %4d", jugador.bomba_precio, jugador.bomba_cantidad); + + sprintf(str_cant,"%4d / %4d", jugador.bombas, jugador.max_bombas); + + shop_main_dlg[IDX_BMP].dp = (void *)jugador.bomba_bmp; + } + } + else + { /* arma */ + shop_main_dlg[IDX_BMP].dp = (void *)arma_tipo[item_idx].arma; + shop_main_dlg[IDX_DESC].dp = (void *)arma_tipo[item_idx].desc; + // si es el arma 0, es infinita... + if (item_idx == 0) + { + sprintf(str_precio, "N/A"); + sprintf(str_cant, "N/A"); + } + else // arma normal + { + sprintf(str_precio,"$ %9d x %4d", arma_tipo[item_idx].precio, arma_tipo[item_idx].cant_ammo); + sprintf(str_cant,"%4d / %4d", jugador.arma[item_idx], arma_tipo[item_idx].cant_ammo_max ); + } + } + + + + if (item_idx < -2) item_idx = -2; + + /* desabilita el boton 'vender' si es la energia, bombas o el arma 0 */ + if (item_idx <= 0) + shop_main_dlg[IDX_SELL_BTN].flags = D_DISABLED | D_EXIT; + else + { + shop_main_dlg[IDX_SELL_BTN].flags = D_EXIT; + /* desabilita el boton 'vender' si no tiene suficiente para vender */ + if (jugador.arma[item_idx] < arma_tipo[item_idx].cant_ammo) shop_main_dlg[IDX_SELL_BTN].flags = D_DISABLED | D_EXIT; + } + + /* desabilita el boton 'comprar' si es el arma 0 */ + if (item_idx == 0) + shop_main_dlg[IDX_BUY_BTN].flags = D_DISABLED | D_EXIT; + else + shop_main_dlg[IDX_BUY_BTN].flags = D_EXIT; + + // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + set_mouse_sprite(NULL); /* acomoda puntero del mouse para que se ajuste a los colores */ + + ret = do_dialog(shop_main_dlg, ret); /* mostrar dialogo */ + + // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + /* comprar */ + if (ret == IDX_BUY_BTN) + { + if (item_idx > -1) + { + /* comprar armamento */ + if ( jugador.dinero >= arma_tipo[item_idx].precio ) // tiene la plata? + { + if (jugador.arma[item_idx] + arma_tipo[item_idx].cant_ammo > arma_tipo[item_idx].cant_ammo_max) // tiene espacio para mas? + { + alert(get_config_text("You reached the maximum capacity of load"), + NULL, NULL, + get_config_text("OK"), + NULL, 0, 0); + } + else + { + if (alert(get_config_text("Buy this weapon"), + NULL, + NULL, + get_config_text("Yes"), + get_config_text("No"), + 0, 0) == 1) + { + jugador.arma[item_idx] += arma_tipo[item_idx].cant_ammo; + jugador.dinero -= arma_tipo[item_idx].precio; + jugador.arma_actual = item_idx; /* arma seleccionada */ + } + } + } + else + { + /* no tiene dinero */ + alert(get_config_text("You need more money"), + NULL, NULL, + get_config_text("OK"), + NULL, 0, 0); + } + } + else + { + if (item_idx == -1) + { + /* compro energia */ + if ( jugador.dinero >= jugador.reparar_precio ) + { + if (jugador.vida >= MAX_ENERGIA) + { + alert(get_config_text("You have the maximum"), + NULL, NULL, + get_config_text("OK"), + NULL, 0, 0); + } + else + { + if (alert(get_config_text("Buy"), + NULL, + NULL, + get_config_text("Yes"), + get_config_text("No"), + 0, 0) == 1) + { + jugador.vida += jugador.reparar_cantidad; + if (jugador.vida >= MAX_ENERGIA) jugador.vida = MAX_ENERGIA; + jugador.dinero -= jugador.reparar_precio; + } + } + } + else + { + /* no tiene dinero */ + alert(get_config_text("You need more money"), + NULL, NULL, + get_config_text("OK"), + NULL, 0, 0); + } + } + + if (item_idx == -2) + { + /* compro bombas */ + if ( jugador.dinero >= jugador.bomba_precio ) + { + if (jugador.bombas >= jugador.max_bombas) + { + alert(get_config_text("You have the maximum"), + NULL, NULL, + get_config_text("OK"), + NULL, 0, 0); + } + else + { + if (alert(get_config_text("Buy"), + NULL, + NULL, + get_config_text("Yes"), + get_config_text("No"), + 0, 0) == 1) + { + jugador.bombas += jugador.bomba_cantidad; + if (jugador.bombas >= jugador.max_bombas) jugador.bombas = jugador.max_bombas; + jugador.dinero -= jugador.bomba_precio; + } + } + } + else + { + /* no tiene dinero */ + alert(get_config_text("You need more money"), + NULL, NULL, + get_config_text("OK"), + NULL, 0, 0); + } + } + } + } // fin comprar + + /* vender */ + if (ret == IDX_SELL_BTN) + { + char tmp[512]; + sprintf(tmp, "$ %d", arma_tipo[item_idx].precio/2); + + if (item_idx > -1) /* la energia no se puede vender.. sorry.. */ + { + /* vender armamento */ + if (jugador.arma[item_idx] >= arma_tipo[item_idx].cant_ammo) // solo si tiene suficiente + { + if (alert(get_config_text("Sell this weapon"), + get_config_text("Price"), + tmp, + get_config_text("Yes"), + get_config_text("No"), + 0, 0) == 1) + { + jugador.arma[item_idx] -= arma_tipo[item_idx].cant_ammo; + jugador.dinero += arma_tipo[item_idx].precio / 2; + jugador.arma_actual = 0; /* arma 0 seleccionada, esto para evitar un bug al vender armas */ + } + } + } + } // fin vender + + if (ret == IDX_SAVE_BTN) // salvar + { + salvar_juego_menu(); + } // fin salvar + + } // fin loop principal +} diff --git a/src/sombras.c b/src/sombras.c new file mode 100644 index 0000000..ebe7ec1 --- /dev/null +++ b/src/sombras.c @@ -0,0 +1,65 @@ +// -------------------------------------------------------- +// sombras.c +// -------------------------------------------------------- +// Copyright (c) Kronoman +// En memoria de mi querido padre +// -------------------------------------------------------- +// Genera las sombras del juego y dibuja sombras en pantalla tambien. +// Bastante simple. :^P +// Lo afecta el nivel de detalle. +// -------------------------------------------------------- +#ifndef SOMBRAS_C +#define SOMBRAS_C + +#include "allegro.h" +#include "sombras.h" + +#include "global.h" + +/* Genera una sombra del origen en destino + origen y destino son dos bitmaps, PREVIAMENTE alocados + destino sera borrado a negro 0, y luego, se dibuja la sombra con gris de 32 RGB + TENER LA PALETA CARGADA, O LOS COLORES VAN A SALIR MAL + LA SOMBRA ES ESCALADA AL TAMA~O DE DESTINO! + */ +void hacer_sombra(BITMAP *origen, BITMAP *destino) +{ + int x, y, c; + BITMAP *tmp; + + tmp = create_bitmap(origen->w, origen->h); + if (tmp == NULL) return; /* fallo! */ + + clear_bitmap(destino); + clear_bitmap(tmp); + + c = makecol(32,32,32); /* color de sombra */ + + solid_mode(); /* dibujar solido... */ + + for (x=0; x < origen->w; x++) + for (y=0; y < origen->h; y++) + if (getpixel(origen, x, y) > 0 ) putpixel(tmp, x, y, c); + + stretch_blit(tmp, destino, 0, 0, tmp->w, tmp->h, 0, 0, destino->w, destino->h); + + destroy_bitmap(tmp); + +} + +/* Coloca la sombra de un jugador/enemigo + + NOTA: codigo original era + alterando la posicion de la sombra de acuerdo a la posicion del enemigo + en una pantalla de 600x480 + + Actualmente (16/12/03) la sombra se dibuja hacia la izquierda abajo, para + concordar con el foco de luz que le da sombra a los edificios +*/ +void colocar_sombra(BITMAP *bmp, BITMAP *sombra, int px, int py) +{ + /* if (nivel_detalle > 5) draw_trans_sprite(bmp, sombra, px+(300-px)/8, py+(400-py)/10); */ + if (nivel_detalle > 5) draw_trans_sprite(bmp, sombra, px-(sombra->w*0.15)-10, py+(sombra->h*0.15)+10); +} + +#endif diff --git a/src/sonido.c b/src/sonido.c new file mode 100644 index 0000000..c5eb746 --- /dev/null +++ b/src/sonido.c @@ -0,0 +1,149 @@ +// -------------------------------------------------------- +// sonido.c +// -------------------------------------------------------- +// Copyright (c) Kronoman +// En memoria de mi querido padre +// -------------------------------------------------------- +// Modulo de sonido y musica +// -------------------------------------------------------- +#ifndef SONIDO_C +#define SONIDO_C + +#include + +#include /* DUMB: libreria de sonido */ + +#include "sonido.h" +#include "global.h" +#include "kfbuffer.h" + +/* player para la musica */ +static AL_DUH_PLAYER *musica_dp = NULL; + + +/* +Esta peque~a rutina toca un sonido +Pasarle el volumen +El paneo stereo es calculado de acuerdo a la posicion del objeto +parametros: +x = posicion x del objeto que emite el sonido (para hacer el panning correcto) +spl = puntero al sample a tocar +vol = volumen +freq = frecuencia (velocidad, 1000 = 1, 2000 = 2, etc) + +*/ +void tocar_sonido_paneado(int x, SAMPLE *spl, int vol, int freq) +{ +int pan = 0; + +if (!(quiere_snd && driver_de_sonido)) return; /* no esta usando el sonido */ +if (spl == NULL) return; /* evito errores */ + +pan = ( x * 255 ) / ANCHO_FB; + +tocar_sonido(spl, vol, pan, freq); + +} + +/* +Esta funcion toca un sonido, es equivalente a play_sample, +pero ajusta el volumen de manera relativa a la variable global +llamada 'volumen_sonido'. +NOTA: se deberia USAR SIEMPRE esta funcion para enviar un sonido +a la placa de sonido, de esa manera, se respetan los settings del usuario +*/ +void tocar_sonido(SAMPLE *spl, int vol, int pan, int freq) +{ +int vol2 = 255; + +if (!(quiere_snd && driver_de_sonido)) return; /* no esta usando el sonido */ +if (spl == NULL) return; /* evito errores */ + + vol2 = (vol * volumen_sonido) / 255; + if (vol2 > 0) play_sample(spl, vol2, pan, freq, 0); +} + + + +/* Rutina para comenzar a tocar un archivo de DUMB +pasarle el puntero al archivo +devuelve 0 si todo OK, -1 si falla +*/ +int musica_play(DUH *duh) +{ +float vol = 1.0; + +if (duh == NULL) return -1; + +if (musica_dp != NULL) musica_stop(); + +if (!quiere_musica) return 0; + +vol = (float)volumen_musica / 255.0; + +/* ajusta el stereo y los khz de acuerdo al nivel de detalle */ + musica_dp = al_start_duh(duh, + (nivel_detalle > 5) ? 2 : 1, + 0, + vol, + 2048, + 11025); + +if (musica_dp == NULL) return -1; + +return 0; +} + +/* Rutina para parar DEFINITIVAMENTE de tocar la musica */ +void musica_stop() +{ +if (musica_dp == NULL) return; + + al_stop_duh(musica_dp); + musica_dp = NULL; +} + +/* Llamar a esta funcion MUY seguido, para que la musica se escuche! */ +void ejecutar_poll_musica() +{ + if (musica_dp != NULL) al_poll_duh(musica_dp); +} + +/* Llamar a esta funcion luego de cambiar el volumen +de la musica */ +void reajustar_volumen_musica() +{ +float vol = 1.0; + +if (musica_dp == NULL) return; + +vol = (float)volumen_musica / 255.0; + + al_duh_set_volume(musica_dp, vol); +} + +/* Esta funcion pausa la musica */ +void pausar_musica() +{ + if (!quiere_musica) + { + musica_stop(); + return; + } + + if (musica_dp == NULL) return; + + al_pause_duh(musica_dp); +} + +/* Esta funcion continua la musica */ +void continuar_musica() +{ +if (!quiere_musica) return; + + if (musica_dp == NULL) return; + + al_resume_duh(musica_dp); +} + +#endif diff --git a/src/wordwrap.c b/src/wordwrap.c new file mode 100644 index 0000000..ed56c64 --- /dev/null +++ b/src/wordwrap.c @@ -0,0 +1,92 @@ +/*-------------------------------------------------------- + wordwrap.c + -------------------------------------------------------- + Copyright (c) Kronoman + En memoria de mi querido padre + -------------------------------------------------------- + Funciones para escribir texto con 'word-wrap' + --------------------------------------------------------*/ +#ifndef KRONO_WORDWRAP_C +#define KRONO_WORDWRAP_C + + +#include +#include "allegro.h" + +#include "wordwrap.h" + +/* +Esta funcion imprime texto con word-wrap a 'w' caracteres... +NOTA: no puede usar palabras mayores a 1 Kb (1024 bytes!) +NOTA: no funciona muy bien con palabras muy largas (es decir, si no entran en el wrap, se salen del borde...) +NOTA: NO uso strtok porque se 'come' el separador de palabras! +NOTA: \n puede ser usado para saltar la linea +Parametros: +bmp = bitmap donde escribir +f = font a usar +x, y = coordenadas en pixeles +color = color a usar +w = ancho del borde, donde el texto 'cae' (wrap-edge) +text = texto a escribir + +Devuelve: +0 si falla +si funciona, devuelve la coordenada 'y' inferior hasta donde imprimio +*/ +int imprimir_wordwrap(BITMAP *bmp, + const FONT *f, + int x, int y, int color, int w, + const char *text) +{ +char tok[1024]; /* token actual */ +char st[2]; /* caracter de busqueda (lo trato como string) */ +char *limites = " ,;.<>()[]{}/*-+=\\|"; /* limitadores de token */ +int i1, i2; /* auxiliares */ +int xp = 0; /* posicion actual en pantalla */ + +xp = x; +i1 = 0; + +if (w < text_length(f, "X")) return 0; /* evita bucle infinito, creo... :^P */ + +while (i1 < strlen(text)) + { + /* buscar un token, e imprimirlo */ + i2 = i1; + tok[0] = st[0] = st[1] = '\0'; /* blanquear strings */ + + do { + tok[i2-i1] = text[i2]; + + st[0] = text[i2]; /* caracter de comprobacion */ + + if (text[i2] == '\n') /* salto de linea */ + { + xp = x; + y += text_height(f); // + 1; + break; + } + + i2++; + } while (i2 < strlen(text) && !strstr(limites, st) && i2 - i1 < 1023 && x+text_length(f, tok) < x + w ); + + tok[i2-i1] = '\0'; + + /* avanzar: el +1 evita bucles infinitos, creo... */ + i1 += (strlen(tok) > 0) ? strlen(tok) : 1; + + /* Si la palabra llega al borde, salto */ + if (xp+text_length(f, tok) > x + w) + { + xp = x; + y += text_height(f); // + 1; + } + + textprintf(bmp, f, xp, y, color, "%s", tok); + + xp += text_length(f, tok); + } + +return y += text_height(f); // + 1; +} +#endif diff --git a/test.c b/test.c new file mode 100644 index 0000000..fd54737 --- /dev/null +++ b/test.c @@ -0,0 +1,19 @@ +/* +test.c +This is a test program +The only purpose of this program is to check if you can compile Allegro programs. +By Kronoman - In lovin memory of my father - October 2003 +*/ + +#include +#include + +int main() +{ + allegro_init(); + + allegro_message("This is a test program to check if you can compile Allegro programs.\nYou can safely erase this program.\n"); + +return 0; +} +END_OF_MAIN(); diff --git a/version b/version new file mode 100644 index 0000000..0c2651c --- /dev/null +++ b/version @@ -0,0 +1,2 @@ +Final release 1.0.2 +Released: 03 April 2004