diff --git a/assets-cg/font.png b/assets-cg/font.png index 148bcb3..1b1622c 100644 Binary files a/assets-cg/font.png and b/assets-cg/font.png differ diff --git a/assets-fx/font.png b/assets-fx/font.png index 8733b1e..b89f3dd 100644 Binary files a/assets-fx/font.png and b/assets-fx/font.png differ diff --git a/src/config.h b/src/config.h index 6afe302..c434419 100644 --- a/src/config.h +++ b/src/config.h @@ -6,6 +6,6 @@ #define GRAYMODEOK 1 #endif -#define USB_FEATURE 1 +#define USB_FEATURE 0 #endif diff --git a/src/dialogs.c b/src/dialogs.c index a6d2d44..e6c313e 100644 --- a/src/dialogs.c +++ b/src/dialogs.c @@ -13,7 +13,7 @@ extern font_t fontRPG; #define FONT_USED fontRPG -#if GRAYMODEOK==1 +#if GRAYMODEOK #include uint32_t *lightVRAMnext, *darkVRAMnext; uint32_t *lightVRAMcurrent, *darkVRAMcurrent; @@ -24,7 +24,7 @@ void blit() { dupdate(); - #if GRAYMODEOK==1 + #if GRAYMODEOK dgray_getvram( &lightVRAMnext, &darkVRAMnext ); dgray_getscreen( &lightVRAMcurrent, &darkVRAMcurrent ); @@ -35,124 +35,285 @@ void blit() int showtext_opt(Game *game, bopti_image_t *face, char *text, - int call_before_end(void), bool start_anim, bool end_anim) { + 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 update_screen, unsigned int start_i, + bool wait_continue) { 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; - /* Run a little fancy animation. */ - for(i=0;iframe_duration < 20) sleep(); + game->frame_duration = 0; + } + }else{ + /* Here I'm drawing the same as if start_anim is true, but whitout + * making an animation. */ draw(game); + drect(0, 0, DWIDTH, BOX_HEIGHT*PXSIZE, C_WHITE); + drect(0, BOX_HEIGHT*PXSIZE, DWIDTH, (BOX_HEIGHT+1)*PXSIZE, C_BLACK); + dimage(4*PXSIZE, 2*PXSIZE, face); - 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); + if(update_screen){ + blit(); - dupdate(); - - while(game->frame_duration < 20) sleep(); - game->frame_duration = 0; + while(game->frame_duration < 20) sleep(); + game->frame_duration = 0; + } } - /* We should start to drawint the text on the x axis at BOX_HEIGHT to avoid + /* We should start to drawing the text on the x axis at BOX_HEIGHT to avoid * drawing on the face. */ - /* Show a little message that showing text in dialogs is not implemented - * yet. */ - for(i=0;i0; 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; + if(*c){ + /* If we are not drawing the end of the text. */ + 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{ + /* If it is the last line of the text. */ + 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 :). */ - blit(); - while(game->frame_duration < 1000) sleep(); + if(update_screen) 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 :). */ - blit(); + if(update_screen) 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, + /* If we drew one entire screen. */ + /* Wait that the EXE key is pressed if we should. */ + if(wait_continue) while(getkey().key != KEY_EXE) sleep(); + /* Clear the text area. */ + drect(BOX_HEIGHT*PXSIZE, 0, DWIDTH, (BOX_HEIGHT-1)*PXSIZE-2, C_WHITE); /* Reset y and l. */ y = PXSIZE; l = 0; } else{ - while(game->frame_duration < 1000) sleep(); + /* Else, wait a bit for the animation. */ + while(game->frame_duration < line_duration) sleep(); game->frame_duration = 0; } } if(lframe_duration < 1000) sleep(); + if(update_screen) 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 ..."); - blit(); - while(getkey().key != KEY_EXE) sleep(); + /* Update the screen and wait for EXE being pressed, if needed. */ + if(update_screen) blit(); + if(wait_continue) while(getkey().key != KEY_EXE) sleep(); } - if(call_before_end) return_int = call_before_end(); - /* 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); + if(call_before_end) return_int = call_before_end(game, i); + if(end_anim){ + /* Run another little fancy animation if we should. */ + for(i=BOX_HEIGHT;i>0;i--){ + /* It is the same as the start animation. */ + 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(); + dupdate(); - while(game->frame_duration < 20) sleep(); - game->frame_duration = 0; + while(game->frame_duration < 20) sleep(); + game->frame_duration = 0; + } } return return_int; } -void showtext(Game *game, bopti_image_t *face, char *text) { - showtext_opt(game, face, text, NULL, true, true); +void showtext_dialog(Game *game, bopti_image_t *face, char *text, + bool dialog_start, bool dialog_end) { + /* Run showtext_opt with some default values. It makes it easier to use in + * simple dialogs. */ + showtext_opt(game, face, text, NULL, dialog_start, dialog_end, NULL, 100, + true, 0, true); } -void showtext_dialog_start(Game *game, bopti_image_t *face, char *text) { - showtext_opt(game, face, text, NULL, true, false); +#define CHOICE_BOX_HEIGHT 10 +#define CHOICE_BOX_PADDING_TOP 3 + +/* Some variables and pointers used to get some arguments passed in + * showtext_dialog_ask in _choice_call_before_end. */ +char *_choices, *_text; +int _choices_amount, _default_choice; +bopti_image_t *_face; +unsigned int _i; + +/* Get where I started drawing a dialog page, to be able to redraw the last page + * for the end animation in _choice_call_before_end. */ +void _choice_screen_call(Game *game, unsigned int i) { + _i = i; } -void showtext_dialog_mid(Game *game, bopti_image_t *face, char *text) { - showtext_opt(game, face, text, NULL, false, false); +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;iframe_duration < 20) sleep(); + game->frame_duration = 0; + } + /* Calculate the maximal size of a choice. */ + const int choice_size = DWIDTH/_choices_amount; + /* arrow_width: The space taken by the arrow that shows the selected item. + * arrow_height: The height of the arrow used to show which item is choosen. + * Used to calculate the size of the rectangle used to remove + * him. + * selected: The selected item. + * pos: The position of the item we're drawing in the choice + * string. The choice string is not really a string, it is + * made of multiple '\0' terminated strings, that are in + * memory one after the other. + */ + int arrow_width, arrow_height, selected = _default_choice, pos = 0; + /* Calculate the size of the arrow. */ + dsize(">", &FONT_USED, &arrow_width, &arrow_height); + /* Add the character spacing of the font to it. */ + 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 the player pressed the left arrow key and has not already selected + * the first possible choice. */ + 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); + + /* Move the selection arrow and update the selected item. */ + selected--; + } + /* If the player pressed the right arrow key and has not already + * selected the last possible choice. */ + 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); + + /* Move the selection arrow and update the selected item. */ + selected++; + } + /* If the user has not validated his choice by pressing EXE, we loop one + * more time. */ + }while(key != KEY_EXE); + /* Make a little animation because we looove little animations ;) */ + for(i=DWIDTH/8+1;i>0;i--){ + /* I'm drawing the same box as on the start animation */ + draw(game); + showtext_opt(game, _face, _text, NULL, false, false, NULL, 0, false, + _i, false); + drect(0, (BOX_HEIGHT+1)*PXSIZE+1, 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, i*(DWIDTH/8), + (BOX_HEIGHT+CHOICE_BOX_HEIGHT+1)*PXSIZE, C_BLACK); + dupdate(); + while(game->frame_duration < 20) sleep(); + game->frame_duration = 0; + } + /* Return the selected item because he'll also be returned by showtext_opt. + */ + return selected; } -void showtext_dialog_end(Game *game, bopti_image_t *face, char *text) { - showtext_opt(game, face, text, NULL, false, true); -} - -char **choices; - -void _choice_call_before_end(void) { - // +int showtext_dialog_ask(Game *game, bopti_image_t *face, char *text, bool start, + bool end, char *choices, int choices_amount, + int default_choice) { + /* Put some arguments in global pointers and variables to make them + * accessible by _choice_call_before_end. */ + _choices = choices; + _choices_amount = choices_amount; + _default_choice = default_choice; + _face = face; + _text = text; + /* Run showtext_opt and return his return value (the return value of + *_choice_call_before_end) */ + return showtext_opt(game, face, text, _choice_call_before_end, start, end, + _choice_screen_call, 100, true, 0, true); } diff --git a/src/dialogs.h b/src/dialogs.h index 62c9a6e..ccff4be 100644 --- a/src/dialogs.h +++ b/src/dialogs.h @@ -9,15 +9,84 @@ #define F_WIDTH (32*PXSIZE) #define F_HEIGHT (32*PXSIZE) +/* showtext_opt() + * + * Show some text in a box with word wrap for dialogs. + * + * game: The game struct of the current game. + * face: A bopti_image_t of the face of the person who's saying this + * text. This bopti_image_t should have a width of F_WIDTH and + * a height of F_HEIGHT. + * text: The text to display. + * call_before_end: A function called when the end of the text was displayed and + * the user pressed EXE (or wait_continue was true). His + * parameter game is the game struct passed to showtext_opt, + * and i is the current position in text. + * start_anim: A boolean, that, if he's true, makes that a little animation + * is shown at the start of showtext_opt. + * end_anim: A boolean, that, if he's true, makes that a little animation + * is shown at the end of showtext_opt. + * for_each_screen: A function called before a page of the dialog gets drawn. + * His parameter game is the game struct passed to + * showtext_opt, and i is the current position in text. + * line_duration: How many ms showtext_opt will wait after a line has been + * drawn. + * update_screen: When he's true showtext_opt will update the screen after + * drawing a line etc. + * start_i: At which position I start displaying the text. + * wait_continue: If I should wait that EXE is pressed after drawing a page. + */ + int showtext_opt(Game *game, bopti_image_t *face, char *text, - int call_before_end(void), bool start_anim, bool end_anim); + 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 update_screen, unsigned int start_i, + bool wait_continue); -void showtext(Game *game, bopti_image_t *face, char *text); +/* showtext_dialog() + * + * Calls showtext_opt with default parameters. + * + * game: The game struct of the current game. + * face: A bopti_image_t of the face of the person who's saying this + * text. This bopti_image_t should have a width of F_WIDTH and a + * height of F_HEIGHT. + * text: The text to display. + * dialog_start: A boolean, that, if he's true, makes that a little animation is + * shown at the start of showtext_opt. + * dialog_end: A boolean, that, if he's true, makes that a little animation is + * shown at the end of showtext_opt. + */ -void showtext_dialog_start(Game *game, bopti_image_t *face, char *text); +void showtext_dialog(Game *game, bopti_image_t *face, char *text, + bool dialog_start, bool dialog_end); -void showtext_dialog_mid(Game *game, bopti_image_t *face, char *text); +/* showtext_dialog_ask() + * + * Like showtext_dialog, but lets the user choose between multiple possible + * choices after displaying the text. + * + * game: The game struct of the current game. + * face: A bopti_image_t of the face of the person who's saying this + * text. This bopti_image_t should have a width of F_WIDTH and a + * height of F_HEIGHT. + * text: The text to display. + * start: A boolean, that, if he's true, makes that a little animation + * is shown at the start of showtext_opt. + * end: A boolean, that, if he's true, makes that a little animation + * is shown at the end of showtext_opt. + * choices: A pointer to null-terminated strings that are one after the + * other in memory. They should be one null-terminated string + * for each possible choice. + * choice_amount: The amount of possible choices in the choices zero-terminated + * strings. + * default_choice: The choice choosen by default when the dialog just opened. + */ -void showtext_dialog_end(Game *game, bopti_image_t *face, char *text); +int showtext_dialog_ask(Game *game, bopti_image_t *face, char *text, bool start, + bool end, char *choices, int choices_amount, + int default_choice); #endif diff --git a/src/game.c b/src/game.c index eb9df60..74b8e32 100644 --- a/src/game.c +++ b/src/game.c @@ -40,7 +40,7 @@ void get_inputs(Game *game) { /* if USB is enabled - keybinding for screencapture */ -#if USB_FEATURE==1 +#if USB_FEATURE if(keydown(KEY_7)) game->screenshot = true; if(keydown(KEY_8)) game->record = !game->record; diff --git a/src/main.c b/src/main.c index 121a2ee..cc72975 100644 --- a/src/main.c +++ b/src/main.c @@ -12,7 +12,7 @@ #endif //USB_FEATURE -#if GRAYMODEOK==1 +#if GRAYMODEOK #include #endif //GRAYMODEOK @@ -35,14 +35,14 @@ Game game = { /* screen capture management code */ -#if USB_FEATURE==1 +#if USB_FEATURE void USB_feature( void ) { if (game.screenshot && usb_is_open()) { - #if GRAYMODEOK==1 // This is a trick, if GRAYMODEOK is defined then - // we make the code accessible + #if GRAYMODEOK // This is a trick, if GRAYMODEOK is defined then + // we make the code accessible if (dgray_enabled()) usb_fxlink_screenshot_gray(false); @@ -58,7 +58,7 @@ Game game = { if (game.record && usb_is_open()) { - #if GRAYMODEOK==1 + #if GRAYMODEOK if (dgray_enabled()) usb_fxlink_videocapture_gray(false); @@ -87,7 +87,7 @@ int main(void) { } timer_start(timer); - #if USB_FEATURE==1 + #if USB_FEATURE usb_interface_t const *interfaces[] = {&usb_ff_bulk, NULL}; usb_open(interfaces, GINT_CALL_NULL); #endif @@ -95,11 +95,14 @@ int main(void) { /* start grayscale engine */ - #if GRAYMODEOK==1 + #if GRAYMODEOK dgray(DGRAY_ON); #endif - showtext(&game, &player_face_img, "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed non risus. Suspendisse lectus tortor, dignissim sit amet."); + showtext_dialog(&game, &player_face_img, "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed non risus. Suspendisse lectus tortor, dignissim sit amet.", true, true); + int in = showtext_dialog_ask(&game, &player_face_img, "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed non risus. Suspendisse lectus tortor, dignissim sit amet.", true, false, "Lorem\0ipsum", 2, 0); + if(in) showtext_dialog(&game, &player_face_img, "You choosed ipsum", false, true); + else showtext_dialog(&game, &player_face_img, "You choosed Lorem", false, true); do{ /* clear screen */ dclear(C_WHITE); @@ -114,7 +117,7 @@ int main(void) { dupdate(); /* Screen capture feature if enabled */ - #if USB_FEATURE==1 + #if USB_FEATURE USB_feature(); #endif @@ -129,13 +132,13 @@ int main(void) { /* shutdown grayengine*/ - #if GRAYMODEOK==1 + #if GRAYMODEOK dgray(DGRAY_OFF); #endif /* close USB */ - #if USB_FEATURE==1 + #if USB_FEATURE usb_close(); #endif diff --git a/src/map.c b/src/map.c index 361e592..dbd0ea5 100644 --- a/src/map.c +++ b/src/map.c @@ -180,9 +180,6 @@ void render_map_by_layer(Player *player, Map *map_level, int layer) { } } - - - short int get_tile(Map *map_level, int x, int y, int l) { /* Get the tile at (x, y) on layer l. Returns the tile ID or MAP_OUTSIDE if * she's not found. */