2 --------------------------------------------------------
4 --------------------------------------------------------
5 Copyright (c) Septiembre 2002, Kronoman
6 En memoria de mi querido padre
7 --------------------------------------------------------
8 Engine de cinematicas mediante scripts y datafiles
9 Nota: quiere_videos afecta si esto funciona o no. :D
10 -------------------------------------------------------- */
21 #include "kfbuffer.h" /* dibuja en el buffer, debe estar funcionando OK... */
29 /* Listado de comandos disponibles al script principal */
30 CMD_SCRIPT_TYPE cmd_list
[] =
32 { "cls", cmd_cls
, 3 },
33 { "fade_out", cmd_fade_out
, 1 },
34 { "fade_out_color", cmd_fade_out_color
, 4 },
35 { "rect", cmd_rect
, 7 },
36 { "rectfill", cmd_rectfill
, 7 },
37 { "line", cmd_line
, 7 },
38 { "locate", cmd_locate
, 3 },
39 { "text_color", cmd_text_color
, 3 },
40 { "text_back", cmd_text_back
, 3 },
41 { "text_font", cmd_text_font
, 0 },
42 { "echo", cmd_echo
, 0 },
43 { "echo_centre_x",cmd_echo_centre_x
, 0 },
44 { "echo_centre_xy", cmd_echo_centre_xy
, 0 },
45 { "rest", cmd_rest
, 1 },
46 { "set_palette", cmd_set_palette
, 1 },
47 { "set_palette_default", cmd_set_palette_default
, 0 },
48 { "blit", cmd_blit
, 3 },
49 { "sprite", cmd_sprite
, 3 },
50 { "stretch_blit", cmd_stretch_blit
, 5 },
51 { "stretch_blit", cmd_stretch_blit
, 5 },
52 { "play_sample", cmd_play_sample
, 4 },
53 { "play_fli", cmd_play_fli
, 7 },
54 { "clear_fli_back",cmd_clear_fli_back
, 3 },
55 { "keyboard_cancel_fli", cmd_keyboard_cancel_fli
, 1 },
56 { NULL
, NULL
, 0 } /* fin de listado */
59 /* Globales, usadas en la interpretacion */
60 static DATAFILE
*el_archivo
= NULL
; /* el archivo DAT a usar... */
62 static char linea_actual
[MAX_LINEA
]; /* linea de comando actual, completa */
63 static int n_linea_actual
; /* numero de linea actual */
65 static char comando_actual
[80+1]; /* comando actual leido */
66 static char s2nd_param
[MAX_LINEA
]; /* todo lo que quedo sacando el comando principal */
68 static char str_param
[MAX_PARAMS
][256]; /* parametros parseados a char, maximo 256 letras c/u */
69 static int c_str_param
= 0; /* cantidad de parametros str leidos */
71 static int int_param
[MAX_PARAMS
]; /* parametros parseados a int */
72 static int c_int_param
= 0; /* cantidad de parametros int leidos */
74 static int teclado_cancela_fli
= 0; /* puedo cancelar un FLI con teclado? */
75 static int cls_el_fli
[3] = { 0, 0, 0 }; /* color de limpieza antes de 'tocar' un FLI */
77 /* Referente a la salida de texto... */
78 static int x_echo
= 0, y_echo
= 0, w_echo
= ANCHO_RFB
; /* pos cursor */
79 static int echo_text_color
, echo_text_back
; /* colores */
80 static FONT
*echo_font
; /* font a usar */
82 // DEBUG: El mapa RGB fue desactivado porque causaba problemas al usar multiples paletas... sorry gordi..
83 // static RGB_MAP rgb_table_cine; /* mapa RGB para la paleta actual */
85 static PALETTE pal_cine
; /* paleta actual */
87 /* ------------------------------------------------- */
88 /* Globales usadas por las funciones de los comandos */
90 /* DEBUG: agregar aqui las globales extra necesarias, como 'static' */
92 /* --------------------- Funciones de los comandos --------------- */
94 /* Esta funcion limpia la pantalla al color especificado */
96 clear_to_color(kfbufferbmp
, makecol(int_param
[0], int_param
[1], int_param
[2]));
97 enviar_kfbuffer2screen(); /* refrescar pantalla */
98 return 0; /* todo OK */
101 /* Dibuja un rectangulo vacio */
105 int_param
[0], int_param
[1],
106 int_param
[2], int_param
[3],
107 makecol(int_param
[4], int_param
[5], int_param
[6]));
108 enviar_kfbuffer2screen(); /* refrescar pantalla */
112 /* Dibuja un rectangulo lleno */
115 rectfill(kfbufferbmp
,
116 int_param
[0], int_param
[1],
117 int_param
[2], int_param
[3],
118 makecol(int_param
[4], int_param
[5], int_param
[6]));
119 enviar_kfbuffer2screen(); /* refrescar pantalla */
127 int_param
[0], int_param
[1],
128 int_param
[2], int_param
[3],
129 makecol(int_param
[4], int_param
[5], int_param
[6]));
130 enviar_kfbuffer2screen(); /* refrescar pantalla */
134 /* Esta funcion es un wrapper de fade_out de Allegro */
136 fade_out(int_param
[0]);
137 get_palette(pal_cine
); // actualizar la paleta actual
141 /* Esta funcion es un wrapper de fade_out de Allegro
142 pero ajustado para que haga un fade out al color especificado
144 fade_out_color [r] [g] [b] [velocidad]
145 Realiza una transicion al color [r] [g] [b]
146 [velocidad] 1..64 (lento-rapido)
148 int cmd_fade_out_color() {
150 RGB col
; // color formato (nota: esto va de 0..63, NO de 0..255!!)
151 PALETTE pal_dest
; // paleta destino
152 PALETTE pal_orig
; // paleta origen
155 // divido por 4 para que quede en rango 0..63
156 // ademas, ajusto con MIN y MAX en rango...
157 col
.r
= MAX(0, MIN(63, int_param
[0] / 4));
158 col
.g
= MAX(0, MIN(63, int_param
[1] / 4));
159 col
.b
= MAX(0, MIN(63, int_param
[2] / 4));
161 for (i
= 0; i
< 256; i
++)
163 pal_dest
[i
].r
= col
.r
;
164 pal_dest
[i
].g
= col
.g
;
165 pal_dest
[i
].b
= col
.b
;
168 get_palette(pal_orig
);
170 fade_from(pal_orig
, pal_dest
, int_param
[3]);
172 get_palette(pal_cine
); // actualizar la paleta actual
177 /* Posiciona el cursor de texto */
180 x_echo
= int_param
[0];
181 y_echo
= int_param
[1];
182 w_echo
= int_param
[2];
186 /* Color de texto para echo */
189 echo_text_color
= makecol(int_param
[0], int_param
[1], int_param
[2]);
193 /* Color de fondo para el texto */
196 if (int_param
[0] < 0 || int_param
[1] < 0 || int_param
[2] < 0)
199 echo_text_back
= makecol(int_param
[0], int_param
[1],int_param
[2]);
201 text_mode(echo_text_back
);
205 /* Cambiar la fuente del texto */
211 p
= find_datafile_object_type(el_archivo
, str_param
[0], DAT_FONT
);
212 if (p
== NULL
) return -1; /* fallo... */
223 /* Salida a pantalla de texto
224 escribe y avanza la linea... (como el print de Qbasic) */
227 text_mode(echo_text_back
);
229 y_echo
= imprimir_wordwrap(kfbufferbmp
,
231 x_echo
, y_echo
, echo_text_color
, w_echo
,
234 enviar_kfbuffer2screen(); /* refrescar pantalla */
238 /* Salida de texto centrado en x */
239 int cmd_echo_centre_x()
242 text_mode(echo_text_back
);
243 x
= text_length(echo_font
, s2nd_param
);
244 x
= (kfbufferbmp
->w
- x
)/2;
246 //textprintf(kfbufferbmp, echo_font, x, y_echo, echo_text_color, "%s", s2nd_param);
247 //y_echo += text_height(echo_font);
250 y_echo
= imprimir_wordwrap(kfbufferbmp
,
252 x
, y_echo
, echo_text_color
, w_echo
,
256 enviar_kfbuffer2screen(); /* refrescar pantalla */
260 /* Salida de texto centrado en x,y */
261 int cmd_echo_centre_xy()
264 text_mode(echo_text_back
);
265 x
= text_length(echo_font
, s2nd_param
);
266 x
= (kfbufferbmp
->w
- x
)/2;
267 y_echo
= (kfbufferbmp
->h
- text_height(echo_font
)) / 2;
269 //textprintf(kfbufferbmp, echo_font, x, y_echo, echo_text_color, "%s", s2nd_param);
270 //y_echo += text_height(echo_font);
273 y_echo
= imprimir_wordwrap(kfbufferbmp
,
275 x
, y_echo
, echo_text_color
, w_echo
,
279 enviar_kfbuffer2screen(); /* refrescar pantalla */
284 /* Pausa sincronica, puede ser cancelada con el teclado */
287 long int f
= 0; /* para el for */
289 if (int_param
[0] <= 0 )
292 readkey(); // esperar por una tecla
299 // el cancelar solo funciona si la pausa es > 10 ms
300 if (int_param
[0] > 10)
302 while ((f
< int_param
[0]) && (!keypressed()))
310 rest((long)int_param
[0]);
317 /* Setea la paleta y la tabla RGB */
318 int cmd_set_palette()
321 p
= find_datafile_object_type(el_archivo
, str_param
[0], DAT_PALETTE
);
322 if (p
== NULL
) return -1; /* fallo... */
324 memcpy(pal_cine
, p
->dat
, sizeof(PALETTE
));
326 // create_rgb_table(&rgb_table_cine, pal_cine, NULL);
327 // rgb_map = &rgb_table_cine; // DEBUG - mapa RGB desactivado
329 vsync(); /* evita flicker */
330 set_palette(pal_cine
);
335 /* Setea la paleta VGA DEFAULT y la tabla RGB */
336 int cmd_set_palette_default()
338 memcpy(pal_cine
, default_palette
, sizeof(PALETTE
));
340 vsync(); /* evita flicker */
341 set_palette(pal_cine
);
346 /* blitea un bitmap a pantalla */
350 p
= find_datafile_object_type(el_archivo
, str_param
[2], DAT_BITMAP
);
351 if (p
== NULL
) return -1; /* fallo... */
353 blit((BITMAP
*)p
->dat
, kfbufferbmp
, 0, 0, int_param
[0], int_param
[1], ((BITMAP
*)p
->dat
)->w
, ((BITMAP
*)p
->dat
)->h
);
354 enviar_kfbuffer2screen(); /* refrescar pantalla */
358 /* sprite a pantalla */
362 p
= find_datafile_object_type(el_archivo
, str_param
[2], DAT_BITMAP
);
363 if (p
== NULL
) return -1; /* fallo... */
365 draw_sprite(kfbufferbmp
, (BITMAP
*)p
->dat
, int_param
[0], int_param
[1]);
367 enviar_kfbuffer2screen(); /* refrescar pantalla */
371 /* estira un bitmap */
372 int cmd_stretch_blit()
375 p
= find_datafile_object_type(el_archivo
, str_param
[4], DAT_BITMAP
);
376 if (p
== NULL
) return -1; /* fallo... */
378 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]);
379 enviar_kfbuffer2screen(); /* refrescar pantalla */
383 /* ejecuta un sonido (sample) */
384 int cmd_play_sample()
387 p
= find_datafile_object_type(el_archivo
, str_param
[0], DAT_SAMPLE
);
388 if (p
== NULL
) return -1; /* fallo... */
390 play_sample((SAMPLE
*)p
->dat
, int_param
[1], int_param
[2], int_param
[3], 0);
396 ejecuta un archivo FLI (animacion
397 esta funcion es complicada porque utiliza sonidos y subtitulos... :^P
398 NOTA: si no logra abrir el fli, NO falla
399 esto es para permitir facilmente hacer demostraciones con videos 'recortados'
403 int ret
= 0; int loop
= 0;
404 DATAFILE
*p
= NULL
; /* buscador */
405 DATAFILE
*fli_p
= NULL
; /* FLI */
406 int ctxt
= 0; /* encontro el [script_fli]? */
407 DATAFILE
*psample
= NULL
; /* SAMPLE a ejecutar */
408 char tmpstr
[1024]; /* string temporal de uso vario */
411 // play_fli [x] [y] [w] [h] [loop] [objeto_fli] [script_fli]
413 /* buscar FLI a ejecutar */
414 p
= find_datafile_object_type(el_archivo
, str_param
[5], DAT_FLI
);
415 if (p
== NULL
) return 0; /* fallo... no hay FLI..., lo ignoro */
417 fli_p
= p
; /* tomar el puto FLI */
419 /* buscar la configuracion [script_fli], si no existe, se ignorara */
420 p
= find_datafile_object(el_archivo
, str_param
[6]);
423 ctxt
= TRUE
; /* lo encontro */
424 set_config_data((char *)p
->dat
, p
->size
);
427 ctxt
= 0; /* no lo encontro... */
429 /* mostramos el fli de la manera complicada...
430 ver fli.c de Allegro para mas info */
431 clear_keybuf(); /* limpio el buffer de teclado */
433 rgb_map
= NULL
; /* anulo el mapa RGB */
435 /* ir realizando el looping adecuado */
436 for (loop
= int_param
[4]; loop
> 0; loop
--)
438 if (open_memory_fli(fli_p
->dat
) != FLI_OK
) return -1; /* no era un FLI... */
440 ret
= next_fli_frame(0);
441 if (ret
== FLI_ERROR
) return -1;
443 while (ret
== FLI_OK
)
445 /* actualiza la paleta */
446 if (fli_pal_dirty_from
<= fli_pal_dirty_to
)
447 set_palette_range(fli_palette
,
449 fli_pal_dirty_to
, TRUE
);
451 /* actualiza la pantalla */
452 if (fli_bmp_dirty_from
<= fli_bmp_dirty_to
)
454 /* debo limpiar el buffer? */
455 if (cls_el_fli
[0] > -1 && cls_el_fli
[1] > -1 && cls_el_fli
[2] > -1)
456 clear_to_color(kfbufferbmp
, makecol(cls_el_fli
[0], cls_el_fli
[1], cls_el_fli
[2]));
458 stretch_blit(fli_bitmap
, kfbufferbmp
,
460 fli_bitmap
->w
, fli_bitmap
->h
,
461 int_param
[0], int_param
[1],
462 int_param
[2], int_param
[3]);
464 vsync(); // tratar de evitar el flicker
465 enviar_kfbuffer2screen(); /* refrescar pantalla */
468 reset_fli_variables();
470 ret
= next_fli_frame(0);
471 if (ret
== FLI_ERROR
) return -1; /* ERROR! */
475 /* ejecutar los sonidos adecuados al frame... */
476 sprintf(tmpstr
,"FRAME_%d", fli_frame
);
477 psample
= find_datafile_object_type(el_archivo
, get_config_string(tmpstr
, "snd", "null"), DAT_SAMPLE
);
478 if (psample
!= NULL
) play_sample((SAMPLE
*)p
->dat
, 255, 128 ,1000, 0);
480 /* DEBUG: subtitular en caso necesario... */
484 /* esperar hasta proximo cuadro */
485 /* si aprieta una tecla, salir... */
486 if (keypressed() && teclado_cancela_fli
)
492 } while (fli_timer
<= 0);
495 close_fli(); /* adios... */
498 /* Devolver mapa RGB */
499 // rgb_map = &rgb_table_cine; // DEBUG: desactivado
500 clear_keybuf(); /* limpio el buffer de teclado */
504 /* color de limpieza del fli */
505 int cmd_clear_fli_back()
507 cls_el_fli
[0] = int_param
[0] % 256;
508 cls_el_fli
[1] = int_param
[1] % 256;
509 cls_el_fli
[2] = int_param
[2] % 256;
513 /* ajusta la bandera de cancelar los fli con el teclado */
514 int cmd_keyboard_cancel_fli()
516 teclado_cancela_fli
= int_param
[0];
521 /* --------------------- Funciones del motor en si --------------- */
523 /* Esta macro funcion se encarga de reproducir una cinematica
524 desde un archivo DAT, pasarselo en char *file,
525 sera cargado, ejecutado, y liberado...
526 Esta es la funcion de entrada que deberia usarse para ejecutar
528 la afecta quiere_videos;
530 void ejecutar_cinematica(char *file
)
532 DATAFILE
*carga
= NULL
;
535 char tmp
[80]; // temporal... formacion del nombre del script
537 if (!quiere_videos
) return; // el usuario no quiere ver videos
539 carga
= krono_load_datafile(file
);
541 if (carga
== NULL
) return; /* el archivo no existe... chau... */
543 /* buscar el script */
544 sprintf(tmp
, "guion_txt_%s", lenguaje
);
545 p
= find_datafile_object(carga
, tmp
);
548 // si no existe el especifico del lenguaje, buscar el generico
549 p
= find_datafile_object(carga
, "guion_txt");
550 // si no existe el generico, buscar la version en ingles
553 p
= find_datafile_object(carga
, "guion_txt_en");
554 if (p
== NULL
) return; /* no hay guion... chau... */
557 guion_txt
= (char *)p
->dat
;
559 ejecutar_script(guion_txt
, p
->size
, carga
);
561 unload_datafile(carga
); /* liberar... */
566 Ejecuta el script pasado en char *txt_script
567 Esto podria ser un DATAFILE ->dat pasado a char, por ejemplo.
568 Toma el caracter 10 como salto de linea (compatible con UNIX)
569 El texto pasado en *txt_script puede ser del largo que se desee,
570 pero debe ser especificado en int size.
571 El char *archivo es el archivo DATAFILE que contendra
572 los diferentes objetos FLI, BITMAP, etc a usar por los comandos
573 Debe estar PRE-cargado en RAM
574 NOTA: kfbufferbmp sera usado como doble buffer! DEBE estar iniciado!
577 NOTA 2: Por pedido popular, ahora con ESC,SPACE o ENTER se puede cancelar
578 completamente la animacion
580 void ejecutar_script(const char *txt_script
, const int size
, DATAFILE
*archivo
)
582 int i
= 0; /* posicion x en el txt_script */
583 int xl
= 0; /* pos en tmp[] */
584 char tmp
[MAX_LINEA
]; /* lectura tmp */
587 /* Iniciar el script */
588 x_echo
= 0, y_echo
= 0, w_echo
= ANCHO_RFB
; /* pos cursor */
590 echo_font
= font
; /* font a usar */
591 echo_text_color
= makecol(255,255,255); echo_text_back
= -1; /* colores texto */
594 teclado_cancela_fli
= TRUE
;
595 cls_el_fli
[0] = cls_el_fli
[1] = cls_el_fli
[2] = 0;
597 get_palette(pal_cine
); /* tomo la paleta actual */
599 rgb_map
= NULL
; /* anulo el mapa RGB */
601 // debug: desactivado
602 // create_rgb_table(&rgb_table_cine, pal_cine, NULL);
603 // rgb_map = &rgb_table_cine;
605 /* doble buffer, debe estar iniciado! */
606 set_clip(kfbufferbmp
, 0, 0, kfbufferbmp
->w
-1, kfbufferbmp
->h
-1); /* clipping adecuado */
610 el_archivo
= archivo
;
612 linea_actual
[0] = '\0';
614 /* Revisar linea por linea del buffer */
615 for (i
= 0; i
< size
; i
++)
617 /* Ir armando la linea */
618 if (txt_script
[i
] == '\r' || xl
== MAX_LINEA
-1 || txt_script
[i
] == 10) /* salto de linea */
621 krtrim(linea_actual
, tmp
); /* remover espacios */
625 if (parsear_y_ejecutar_linea()) return; /* interpretar comando, y cancelar si el usuario cancela */
628 linea_actual
[0] = '\0';
631 { /* armando la linea */
632 tmp
[xl
] = (txt_script
[i
] >= 32) ? txt_script
[i
] : ' '; /* filtra chars 'raros' */
637 /* Ultima linea, interpretar tambien... */
639 krtrim(linea_actual
, tmp
); /* remover espacios */
643 parsear_y_ejecutar_linea(); /* interpretar comando! */
645 /* Termino el show... */
650 Esta funcion interpreta una linea y la parsea en sus parametros
651 respectivos, para luego llamar a la funcion adecuada
652 Si el usuario presiona una tecla, devuelve TRUE (-1) (Cancelar)
653 Caso contrario, devuelve 0
655 int parsear_y_ejecutar_linea()
659 char tmptok
[MAX_LINEA
];
661 /* es un comentario? no hacer nada... */
662 if (linea_actual
[0] == '#' || strlen(linea_actual
) < 1 ) return 0;
664 /* Limpio los parametros... */
665 for (i
= 0; i
< MAX_PARAMS
; i
++)
668 str_param
[i
][0] = '\0';
671 comando_actual
[0] = '\0';
673 i
= c_str_param
= c_int_param
= 0;
675 /* Parsear la linea... */
676 sprintf(tmptok
, "%s", linea_actual
); /* evito modificar el original */
677 for (tok
= strtok(tmptok
, " ");tok
;tok
= strtok(0, " "))
681 krtrim(comando_actual
, tok
); /* el 1er comando */
684 { /* tomar parametros */
685 krtrim(str_param
[i
-1], tok
); /* remover espacios */
687 int_param
[i
-1] = atoi(tok
);
691 if (i
> MAX_PARAMS
-1) break; /* muchos parametros */
694 /* Tomar todo menos el primer parametro... */
695 tmptok
[0] = s2nd_param
[0] = '\0';
698 i
= strlen(comando_actual
);
699 while (i
< strlen(linea_actual
)) /* con un for no funcionaba... por que? */
701 tmptok
[i2
] = linea_actual
[i
];
708 krtrim(s2nd_param
, tmptok
);
710 /* ----------- interpretacion ----------- */
712 /* recorro la lista en busca del comando a usar */
714 while (cmd_list
[i
].comando
!= NULL
&& cmd_list
[i
].proc
!= NULL
)
716 /* NOTA: cambiar strcmp x stricmp para ignorar mayus/minus, pero
717 no es ANSI ni POSIX */
718 if (strcmp(comando_actual
, cmd_list
[i
].comando
) == 0)
720 /* Tiene suficientes parametros? */
721 if (c_str_param
< cmd_list
[i
].min_params
&& c_int_param
< cmd_list
[i
].min_params
)
723 sprintf(tmptok
,"ERROR:\ncinema.c:\nscript:linea(%d)='%s'\nInsuficientes parametros (requiere %d)!\n", n_linea_actual
,linea_actual
,cmd_list
[i
].min_params
);
724 levantar_error(tmptok
);
727 /* llamar a la funcion, devuelven -1 en error */
728 if ( (*cmd_list
[i
].proc
)() )
730 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
);
731 levantar_error(tmptok
);
734 // ver si el usuario cancelo
735 if (keypressed() && (key
[KEY_ESC
] || key
[KEY_ENTER
] || key
[KEY_SPACE
]) )
738 return 0; /* termino, proxima linea please... */
743 /* Comando no reconocido! SHIT! */
744 sprintf(tmptok
, "ERROR:\ncinema.c:\nscript:linea(%d)='%s'\nComando no reconocido!\n", n_linea_actual
, linea_actual
);
745 levantar_error(tmptok
);