Collab_RPG/src/dialogs.c

256 lines
9.4 KiB
C

#include "dialogs.h"
#include <gint/keyboard.h>
#include <gint/cpu.h>
#include <string.h>
#include "config.h"
#define BOX_HEIGHT (F_HEIGHT/PXSIZE+8)
extern font_t fontRPG;
#define FONT_USED fontRPG
#if GRAYMODEOK
#include <gint/gray.h>
uint32_t *lightVRAMnext, *darkVRAMnext;
uint32_t *lightVRAMcurrent, *darkVRAMcurrent;
#endif //GRAYMODEOK
void blit()
{
dupdate();
#if GRAYMODEOK
dgray_getvram( &lightVRAMnext, &darkVRAMnext );
dgray_getscreen( &lightVRAMcurrent, &darkVRAMcurrent );
memcpy( lightVRAMnext, lightVRAMcurrent, 256*sizeof( uint32_t) );
memcpy( darkVRAMnext, darkVRAMcurrent, 256*sizeof( uint32_t) );
#endif
}
int showtext_opt(Game *game, bopti_image_t *face, char *text,
int call_before_end(Game *game, unsigned int i),
bool start_anim,
bool end_anim,
void for_each_screen(Game *game, unsigned int i),
int line_duration, bool line_anim, unsigned int start_i) {
dfont(&FONT_USED);
unsigned int i, n, y = PXSIZE, l = 0;
int line_max_chars, return_int = 0;
unsigned int max_lines_amount = (BOX_HEIGHT-2)*PXSIZE/
(FONT_USED.line_height+PXSIZE);
const char *c;
draw(game);
if(start_anim){
/* Run a little fancy animation. */
for(i=0;i<BOX_HEIGHT;i++){
drect(0, 0, DWIDTH, i*PXSIZE, C_WHITE);
drect(0, i*PXSIZE, DWIDTH, (i+1)*PXSIZE, C_BLACK);
dsubimage(4*PXSIZE, 2*PXSIZE, face, 0, 0, F_WIDTH, (i-8)*PXSIZE,
DIMAGE_NONE);
while(game->frame_duration < 20) sleep();
game->frame_duration = 0;
}
}else{
drect(0, 0, DWIDTH, (BOX_HEIGHT-1)*PXSIZE, C_WHITE);
drect(0, (BOX_HEIGHT-1)*PXSIZE, DWIDTH, BOX_HEIGHT*PXSIZE, C_BLACK);
dsubimage(4*PXSIZE, 2*PXSIZE, face, 0, 0, F_WIDTH,
(BOX_HEIGHT-7)*PXSIZE, DIMAGE_NONE);
if(line_anim) dupdate();
while(game->frame_duration < 20) sleep();
game->frame_duration = 0;
}
/* We should start to drawing the text on the x axis at BOX_HEIGHT to avoid
* drawing on the face. */
for(i=start_i;i<strlen(text);i++){
if(!l) for_each_screen(game, i);
/* Get how many chars we can draw on screen with a padding on the left
* of BOX_HEIGHT px and on the right of 1 px. */
c = drsize(text+i, &FONT_USED, DWIDTH-(BOX_HEIGHT*PXSIZE+PXSIZE), NULL);
/* c is a pointer to the last char that can be drawn. So: */
line_max_chars = c-(text+i);
/* TODO: Handle lines that are longer than what I can draw. */
/* Loop from the end to the start for word wrap. */
if(*(c+1) != '\0'){
for(n=line_max_chars; n>0; n--) {
/* If we found a space, we can draw this line and do the same
* for the next line. */
if(text[i+n] == ' '){
dtext_opt(BOX_HEIGHT*PXSIZE, y, C_BLACK, C_NONE, DTEXT_LEFT,
DTEXT_TOP, text+i, n); /* Draw everything. */
/* Increment y by the line height. */
y += FONT_USED.line_height+PXSIZE;
i += n; /* We drew everything to i+n */
l++; /* We drew one more line. */
break;
}
}
}else{
dtext_opt(BOX_HEIGHT*PXSIZE, y, C_BLACK, C_NONE, DTEXT_LEFT,
DTEXT_TOP, text+i, line_max_chars);
y += FONT_USED.line_height+PXSIZE;
i += line_max_chars;
l++;
}
if(l>=max_lines_amount-1){
/* We drew one entire screen, reset everything to draw the next one.
*/
/* Make a little animation :). */
if(line_anim) blit();
while(game->frame_duration < line_duration) sleep();
game->frame_duration = 0;
/* Ask the user to press EXE to continue. */
dtext(BOX_HEIGHT*PXSIZE, y, C_BLACK, "[EXE] to continue ...");
}
/* Make a little animation :). */
if(line_anim) blit();
if(l>=max_lines_amount-1){
while(getkey().key != KEY_EXE) sleep();
/* Clear the screen. */
drect(BOX_HEIGHT*PXSIZE, 0, DWIDTH, (BOX_HEIGHT-1)*PXSIZE-1,
C_WHITE);
/* Reset y and l. */
y = PXSIZE;
l = 0;
}
else{
while(game->frame_duration < line_duration) sleep();
game->frame_duration = 0;
}
}
if(l<max_lines_amount-1){
/* If we have not filled everthing with text at the end. */
/* Make a little animation :). */
if(line_anim) blit();
while(game->frame_duration < line_duration) sleep();
game->frame_duration = 0;
/* Ask the user to press EXE to continue. */
dtext(BOX_HEIGHT*PXSIZE, y, C_BLACK, "[EXE] to continue ...");
if(line_anim) blit();
while(getkey().key != KEY_EXE) sleep();
}
if(call_before_end) return_int = call_before_end(game, i);
if(end_anim){
/* Run another little fancy animation. */
for(i=40;i>0;i--){
draw(game);
drect(0, 0, DWIDTH, i*PXSIZE, C_WHITE);
drect(0, i*PXSIZE, DWIDTH, (i+1)*PXSIZE, C_BLACK);
dsubimage(4*PXSIZE, 2*PXSIZE, face, 0, 0, F_WIDTH, (i-8)*PXSIZE,
DIMAGE_NONE);
dupdate();
while(game->frame_duration < 20) sleep();
game->frame_duration = 0;
}
}
return return_int;
}
void showtext_dialog(Game *game, bopti_image_t *face, char *text,
bool dialog_start, bool dialog_end) {
showtext_opt(game, face, text, NULL, dialog_start, dialog_end, NULL, 100,
true, 0);
}
#define CHOICE_BOX_HEIGHT 10
#define CHOICE_BOX_PADDING_TOP 3
char *_choices, *_text;
int _choices_amount, _default_choice;
bopti_image_t *_face;
unsigned int _i;
void _choice_screen_call(Game *game, unsigned int i) {
_i = i;
}
int _choice_call_before_end(Game *game, unsigned int org_i) {
int i, key;
/* Make a little animation because we looove little animations ;) */
for(i=0;i<DWIDTH/8+1;i++){
drect(0, BOX_HEIGHT*PXSIZE, i*(DWIDTH/8),
(BOX_HEIGHT+CHOICE_BOX_HEIGHT)*PXSIZE, C_WHITE);
drect(i*(DWIDTH/8), BOX_HEIGHT*PXSIZE, i*(DWIDTH/8)+PXSIZE-1,
(BOX_HEIGHT+CHOICE_BOX_HEIGHT+1)*PXSIZE, C_BLACK);
drect(0, (BOX_HEIGHT+CHOICE_BOX_HEIGHT)*PXSIZE+1, i*(DWIDTH/8),
(BOX_HEIGHT+CHOICE_BOX_HEIGHT+1)*PXSIZE, C_BLACK);
blit();
while(game->frame_duration < 20) sleep();
game->frame_duration = 0;
}
const int choice_size = DWIDTH/_choices_amount;
int arrow_width, arrow_height, selected = _default_choice, pos = 0;
dsize(">", &FONT_USED, &arrow_width, &arrow_height);
arrow_width += FONT_USED.char_spacing;
do{
/* Display the diffrent choices. */
for(i=0;i<_choices_amount;i++){
if(i == selected) dtext(i*choice_size+PXSIZE,
(BOX_HEIGHT+CHOICE_BOX_PADDING_TOP)*PXSIZE,
C_BLACK, ">");
dtext(i*choice_size+arrow_width+PXSIZE,
(BOX_HEIGHT+CHOICE_BOX_PADDING_TOP)*PXSIZE, C_BLACK,
_choices+pos+i);
pos += strlen(_choices+pos);
}
blit();
key = getkey().key;
if(key == KEY_LEFT && selected > 0){
/* Remove the old arrow. */
drect(selected*choice_size+PXSIZE,
(BOX_HEIGHT+CHOICE_BOX_PADDING_TOP)*PXSIZE,
selected*choice_size+PXSIZE+arrow_width,
(BOX_HEIGHT+CHOICE_BOX_PADDING_TOP)*PXSIZE+arrow_height,
C_WHITE);
selected--;
}
else if(key == KEY_RIGHT && selected < _choices_amount-1){
/* Remove the old arrow. */
drect(selected*choice_size+PXSIZE,
(BOX_HEIGHT+CHOICE_BOX_PADDING_TOP)*PXSIZE,
selected*choice_size+PXSIZE+arrow_width,
(BOX_HEIGHT+CHOICE_BOX_PADDING_TOP)*PXSIZE+arrow_height,
C_WHITE);
selected++;
}
}while(key != KEY_EXE);
/* Make a little animation because we looove little animations ;) */
for(i=DWIDTH/8+1;i>0;i--){
draw(game);
showtext_opt(game, _face, _text, NULL, false, false, NULL, 0, false,
_i);
drect(0, BOX_HEIGHT*PXSIZE, i*(DWIDTH/8),
(BOX_HEIGHT+CHOICE_BOX_HEIGHT)*PXSIZE, C_WHITE);
drect(i*(DWIDTH/8), BOX_HEIGHT*PXSIZE, i*(DWIDTH/8)+PXSIZE-1,
(BOX_HEIGHT+CHOICE_BOX_HEIGHT+1)*PXSIZE, C_BLACK);
drect(0, (BOX_HEIGHT+CHOICE_BOX_HEIGHT)*PXSIZE+1, i*(DWIDTH/8),
(BOX_HEIGHT+CHOICE_BOX_HEIGHT+1)*PXSIZE, C_BLACK);
dupdate();
while(game->frame_duration < 20) sleep();
game->frame_duration = 0;
}
return selected;
}
int showtext_dialog_ask(Game *game, bopti_image_t *face, char *text, bool start,
bool end, char *choices, int choices_amount,
int default_choice) {
_choices = choices;
_choices_amount = choices_amount;
_default_choice = default_choice;
_face = face;
_text = text;
return showtext_opt(game, face, text, _choice_call_before_end, start, end,
_choice_screen_call, 100, true, 0);
}