Using clang-format

This commit is contained in:
mibi88 2024-07-29 11:36:11 +02:00
parent eb6cd35830
commit dafe7032f3
18 changed files with 839 additions and 884 deletions

7
.clang-format Normal file
View file

@ -0,0 +1,7 @@
BasedOnStyle: LLVM
IndentWidth: 4
PointerAlignment: Right
SpaceBeforeParens: Custom
SpaceBeforeParensOptions:
AfterControlStatements: false

View file

@ -1,7 +1,6 @@
#ifndef CONFIG_H #ifndef CONFIG_H
#define CONFIG_H #define CONFIG_H
#define USB_FEATURE 0 #define USB_FEATURE 0
#define DEBUGMODE 0 #define DEBUGMODE 0
@ -9,48 +8,45 @@
/* Enable GrayMode on either FX and FX_G3A targets */ /* Enable GrayMode on either FX and FX_G3A targets */
#if GINT_RENDER_MONO && defined(COLOR2BIT) #if GINT_RENDER_MONO && defined(COLOR2BIT)
#define GRAYMODEOK 1 #define GRAYMODEOK 1
#endif #endif
#if GINT_RENDER_RGB #if GINT_RENDER_RGB
/* The tile size */ /* The tile size */
#define T_HEIGHT 16 #define T_HEIGHT 16
#define T_WIDTH 16 #define T_WIDTH 16
/* The size of a pixel */ /* The size of a pixel */
#define PXSIZE 2 #define PXSIZE 2
#define PATH_COLOR C_RED #define PATH_COLOR C_RED
/* The size of the player */ /* The size of the player */
#define P_WIDTH 16 #define P_WIDTH 16
#define P_HEIGHT 16 #define P_HEIGHT 16
#else #else
/* The tile size */ /* The tile size */
#define T_HEIGHT 8 #define T_HEIGHT 8
#define T_WIDTH 8 #define T_WIDTH 8
/* The pixel size */ /* The pixel size */
#define PXSIZE 1 #define PXSIZE 1
#define PATH_COLOR C_BLACK #define PATH_COLOR C_BLACK
/* The player size */ /* The player size */
#define P_WIDTH 8 #define P_WIDTH 8
#define P_HEIGHT 8 #define P_HEIGHT 8
#endif #endif
/* SPEED should NOT be 8 or bigger: it may cause bugs when handling /* SPEED should NOT be 8 or bigger: it may cause bugs when handling
* collisions! */ * collisions! */
#define SPEED (PXSIZE*2) #define SPEED (PXSIZE * 2)
/* The face size (in the dialogs) */ /* The face size (in the dialogs) */
#define F_WIDTH (32*PXSIZE) #define F_WIDTH (32 * PXSIZE)
#define F_HEIGHT (32*PXSIZE) #define F_HEIGHT (32 * PXSIZE)
/* the color of the text to go to the next dialog phase */ /* the color of the text to go to the next dialog phase */
/* it improves readability to have something lighter */ /* it improves readability to have something lighter */
#if GRAYMODEOK || (GINT_RENDER_RGB && !defined(COLOR1BIT)) #if GRAYMODEOK || (GINT_RENDER_RGB && !defined(COLOR1BIT))
#define NEXT_COLOR C_DARK #define NEXT_COLOR C_DARK
#else #else
#define NEXT_COLOR C_BLACK #define NEXT_COLOR C_BLACK
#endif #endif
#endif #endif

View file

@ -1,197 +1,210 @@
#include "dialogs.h" #include "dialogs.h"
#include <gint/keyboard.h>
#include <gint/cpu.h> #include <gint/cpu.h>
#include <gint/keyboard.h>
#include <string.h> #include <string.h>
#include "config.h" #include "config.h"
#include "events.h"
#include "game.h" #include "game.h"
#include "npc.h" #include "npc.h"
#include "events.h"
#define BOX_HEIGHT (F_HEIGHT / PXSIZE + 8)
#define BOX_HEIGHT (F_HEIGHT/PXSIZE+8)
#define CHOICE_BOX_HEIGHT 10 #define CHOICE_BOX_HEIGHT 10
#define CHOICE_BOX_PADDING_TOP 3 #define CHOICE_BOX_PADDING_TOP 3
extern font_t fontRPG; extern font_t fontRPG;
#define FONT_USED fontRPG #define FONT_USED fontRPG
#if GRAYMODEOK #if GRAYMODEOK
#include <gint/gray.h> #include <gint/gray.h>
uint32_t *lightVRAMnext, *darkVRAMnext; uint32_t *lightVRAMnext, *darkVRAMnext;
uint32_t *lightVRAMcurrent, *darkVRAMcurrent; uint32_t *lightVRAMcurrent, *darkVRAMcurrent;
#endif //GRAYMODEOK #endif // GRAYMODEOK
void blit() { void blit() {
dupdate(); dupdate();
#if GRAYMODEOK && !GINT_HW_CG #if GRAYMODEOK && !GINT_HW_CG
dgray_getvram( &lightVRAMnext, &darkVRAMnext ); dgray_getvram(&lightVRAMnext, &darkVRAMnext);
dgray_getscreen( &lightVRAMcurrent, &darkVRAMcurrent ); dgray_getscreen(&lightVRAMcurrent, &darkVRAMcurrent);
memcpy( lightVRAMnext, lightVRAMcurrent, 256*sizeof( uint32_t) ); memcpy(lightVRAMnext, lightVRAMcurrent, 256 * sizeof(uint32_t));
memcpy( darkVRAMnext, darkVRAMcurrent, 256*sizeof( uint32_t) ); memcpy(darkVRAMnext, darkVRAMcurrent, 256 * sizeof(uint32_t));
#endif #endif
} }
int dialogs_text_opt(Game *game, bopti_image_t *face, char *text, int dialogs_text_opt(Game *game, bopti_image_t *face, char *text,
int call_before_end(Game *game, unsigned int i), int call_before_end(Game *game, unsigned int i),
bool start_anim, bool start_anim, bool end_anim,
bool end_anim,
void for_each_screen(Game *game, unsigned int i), void for_each_screen(Game *game, unsigned int i),
int line_duration, bool update_screen, unsigned int start_i, int line_duration, bool update_screen,
bool wait_continue) { unsigned int start_i, bool wait_continue) {
text = events_parse_string(&game->handler, text); text = events_parse_string(&game->handler, text);
dfont(&FONT_USED); dfont(&FONT_USED);
unsigned int i, n, y = PXSIZE, l = 0; unsigned int i, n, y = PXSIZE, l = 0;
int line_max_chars, return_int = 0; int line_max_chars, return_int = 0;
unsigned int max_lines_amount = (BOX_HEIGHT-2)*PXSIZE/ unsigned int max_lines_amount =
(FONT_USED.line_height+PXSIZE); (BOX_HEIGHT - 2) * PXSIZE / (FONT_USED.line_height + PXSIZE);
const char *c; const char *c;
if(start_anim){ if(start_anim) {
/* Run a little fancy animation. */ /* Run a little fancy animation. */
for(i=0;i<=BOX_HEIGHT;i++){ for(i = 0; i <= BOX_HEIGHT; i++) {
/* Redrawing the entire screen, because maybe there was no dialog /* Redrawing the entire screen, because maybe there was no dialog
displayed before. */ displayed before. */
update_npcs(game); update_npcs(game);
game_draw(game); game_draw(game);
/* Fill the dialog box with white */ /* Fill the dialog box with white */
drect(0, 0, DWIDTH, i*PXSIZE, C_WHITE); drect(0, 0, DWIDTH, i * PXSIZE, C_WHITE);
/* Draw a thick black line on the bottom of the dialog. */ /* Draw a thick black line on the bottom of the dialog. */
drect(0, i*PXSIZE, DWIDTH, (i+1)*PXSIZE, C_BLACK); drect(0, i * PXSIZE, DWIDTH, (i + 1) * PXSIZE, C_BLACK);
/* Draw the part of the face of the player that can fit correctly in /* Draw the part of the face of the player that can fit correctly in
* the dialog drawn. */ * the dialog drawn. */
dsubimage(4*PXSIZE, 2*PXSIZE, face, 0, 0, F_WIDTH, (i-8)*PXSIZE, dsubimage(4 * PXSIZE, 2 * PXSIZE, face, 0, 0, F_WIDTH,
DIMAGE_NONE); (i - 8) * PXSIZE, DIMAGE_NONE);
blit(); blit();
while(game->frame_duration < 20) sleep(); while(game->frame_duration < 20)
sleep();
game->frame_duration = 0; game->frame_duration = 0;
} }
}else{ } else {
/* Here I'm drawing the same as if start_anim is true, but whitout /* Here I'm drawing the same as if start_anim is true, but whitout
* making an animation. */ * making an animation. */
game_draw(game); game_draw(game);
drect(0, 0, DWIDTH, BOX_HEIGHT*PXSIZE, C_WHITE); drect(0, 0, DWIDTH, BOX_HEIGHT * PXSIZE, C_WHITE);
drect(0, BOX_HEIGHT*PXSIZE, DWIDTH, (BOX_HEIGHT+1)*PXSIZE, C_BLACK); drect(0, BOX_HEIGHT * PXSIZE, DWIDTH, (BOX_HEIGHT + 1) * PXSIZE,
dimage(4*PXSIZE, 2*PXSIZE, face); C_BLACK);
dimage(4 * PXSIZE, 2 * PXSIZE, face);
if(update_screen){ if(update_screen) {
blit(); blit();
while(game->frame_duration < 20) sleep(); while(game->frame_duration < 20)
sleep();
game->frame_duration = 0; game->frame_duration = 0;
} }
} }
/* We should start to drawing 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. */ * drawing on the face. */
for(i=start_i;i<strlen(text);i++){ for(i = start_i; i < strlen(text); i++) {
if(!l && for_each_screen) for_each_screen(game, i); if(!l && for_each_screen)
for_each_screen(game, i);
/* Get how many chars we can draw on screen with a padding on the left /* 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. */ * of BOX_HEIGHT px and on the right of 1 px. */
c = drsize(text+i, &FONT_USED, DWIDTH-(BOX_HEIGHT*PXSIZE+PXSIZE), NULL); 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: */ /* c is a pointer to the last char that can be drawn. So: */
line_max_chars = c-(text+i); line_max_chars = c - (text + i);
/* TODO: Handle lines that are longer than what I can draw and '\n'. */ /* TODO: Handle lines that are longer than what I can draw and '\n'. */
/* Loop from the end to the start for word wrap. */ /* Loop from the end to the start for word wrap. */
if(*c){ if(*c) {
/* If we are not drawing the end of the text. */ /* If we are not drawing the end of the text. */
for(n=line_max_chars; n>0; n--) { for(n = line_max_chars; n > 0; n--) {
/* If we found a space, we can draw this line and do the same /* If we found a space, we can draw this line and do the same
* for the next line. */ * for the next line. */
if(text[i+n] == ' '){ if(text[i + n] == ' ') {
dtext_opt(BOX_HEIGHT*PXSIZE, y, C_BLACK, C_NONE, DTEXT_LEFT, dtext_opt(BOX_HEIGHT * PXSIZE, y, C_BLACK, C_NONE,
DTEXT_TOP, text+i, n); /* Draw everything. */ DTEXT_LEFT, DTEXT_TOP, text + i,
n); /* Draw everything. */
/* Increment y by the line height. */ /* Increment y by the line height. */
y += FONT_USED.line_height+PXSIZE; y += FONT_USED.line_height + PXSIZE;
i += n; /* We drew everything to i+n */ i += n; /* We drew everything to i+n */
l++; /* We drew one more line. */ l++; /* We drew one more line. */
break; break;
} }
} }
}else{ } else {
/* If it is the last line of the text. */ /* If it is the last line of the text. */
dtext_opt(BOX_HEIGHT*PXSIZE, y, C_BLACK, C_NONE, DTEXT_LEFT, dtext_opt(BOX_HEIGHT * PXSIZE, y, C_BLACK, C_NONE, DTEXT_LEFT,
DTEXT_TOP, text+i, line_max_chars); DTEXT_TOP, text + i, line_max_chars);
y += FONT_USED.line_height+PXSIZE; y += FONT_USED.line_height + PXSIZE;
i += line_max_chars; i += line_max_chars;
l++; l++;
} }
if(l>=max_lines_amount-1){ if(l >= max_lines_amount - 1) {
/* We drew one entire screen, reset everything to draw the next one. /* We drew one entire screen, reset everything to draw the next one.
*/ */
/* Make a little animation :). */ /* Make a little animation :). */
if(update_screen) blit(); if(update_screen)
while(game->frame_duration < line_duration) sleep(); blit();
while(game->frame_duration < line_duration)
sleep();
game->frame_duration = 0; game->frame_duration = 0;
/* Ask the user to press SHIFT to continue. */ /* Ask the user to press SHIFT to continue. */
dtext(BOX_HEIGHT*PXSIZE, y, NEXT_COLOR, "[SHIFT] : suite..."); dtext(BOX_HEIGHT * PXSIZE, y, NEXT_COLOR, "[SHIFT] : suite...");
} }
/* Make a little animation :). */ /* Make a little animation :). */
if(update_screen) blit(); if(update_screen)
if(l>=max_lines_amount-1){ blit();
if(l >= max_lines_amount - 1) {
/* If we drew one entire screen. */ /* If we drew one entire screen. */
/* Wait that the SHIFT key is pressed if we should. */ /* Wait that the SHIFT key is pressed if we should. */
if(wait_continue){ if(wait_continue) {
while(getkey_opt(GETKEY_DEFAULT & ~GETKEY_MOD_SHIFT & while(getkey_opt(GETKEY_DEFAULT & ~GETKEY_MOD_SHIFT &
~GETKEY_MOD_ALPHA, NULL).key != KEY_SHIFT){ ~GETKEY_MOD_ALPHA,
NULL)
.key != KEY_SHIFT) {
sleep(); sleep();
} }
} }
/* Clear the text area. */ /* Clear the text area. */
drect(BOX_HEIGHT*PXSIZE, 0, DWIDTH, (BOX_HEIGHT-1)*PXSIZE-2, drect(BOX_HEIGHT * PXSIZE, 0, DWIDTH, (BOX_HEIGHT - 1) * PXSIZE - 2,
C_WHITE); C_WHITE);
/* Reset y and l. */ /* Reset y and l. */
y = PXSIZE; y = PXSIZE;
l = 0; l = 0;
} } else {
else{
/* Else, wait a bit for the animation. */ /* Else, wait a bit for the animation. */
while(game->frame_duration < line_duration) sleep(); while(game->frame_duration < line_duration)
sleep();
game->frame_duration = 0; game->frame_duration = 0;
} }
} }
if(l<max_lines_amount-1){ if(l < max_lines_amount - 1) {
/* If we have not filled everthing with text at the end. */ /* If we have not filled everthing with text at the end. */
/* Make a little animation :). */ /* Make a little animation :). */
if(update_screen) blit(); if(update_screen)
while(game->frame_duration < line_duration) sleep(); blit();
while(game->frame_duration < line_duration)
sleep();
game->frame_duration = 0; game->frame_duration = 0;
/* Ask the user to press SHIFT to continue. */ /* Ask the user to press SHIFT to continue. */
dtext(BOX_HEIGHT*PXSIZE, y, NEXT_COLOR, "[SHIFT] : suite..."); dtext(BOX_HEIGHT * PXSIZE, y, NEXT_COLOR, "[SHIFT] : suite...");
/* Update the screen and wait for SHIFT being pressed, if needed. */ /* Update the screen and wait for SHIFT being pressed, if needed. */
if(update_screen) blit(); if(update_screen)
if(wait_continue){ blit();
if(wait_continue) {
while(getkey_opt(GETKEY_DEFAULT & ~GETKEY_MOD_SHIFT & while(getkey_opt(GETKEY_DEFAULT & ~GETKEY_MOD_SHIFT &
~GETKEY_MOD_ALPHA, NULL).key != KEY_SHIFT){ ~GETKEY_MOD_ALPHA,
NULL)
.key != KEY_SHIFT) {
sleep(); sleep();
} }
} }
} }
if(call_before_end) return_int = call_before_end(game, i); if(call_before_end)
if(end_anim){ return_int = call_before_end(game, i);
if(end_anim) {
/* Run another little fancy animation if we should. */ /* Run another little fancy animation if we should. */
for(i=BOX_HEIGHT;i>0;i--){ for(i = BOX_HEIGHT; i > 0; i--) {
/* It is the same as the start animation. */ /* It is the same as the start animation. */
update_npcs(game); update_npcs(game);
game_draw(game); game_draw(game);
drect(0, 0, DWIDTH, i*PXSIZE, C_WHITE); drect(0, 0, DWIDTH, i * PXSIZE, C_WHITE);
drect(0, i*PXSIZE, DWIDTH, (i+1)*PXSIZE, C_BLACK); drect(0, i * PXSIZE, DWIDTH, (i + 1) * PXSIZE, C_BLACK);
dsubimage(4*PXSIZE, 2*PXSIZE, face, 0, 0, F_WIDTH, (i-8)*PXSIZE, dsubimage(4 * PXSIZE, 2 * PXSIZE, face, 0, 0, F_WIDTH,
DIMAGE_NONE); (i - 8) * PXSIZE, DIMAGE_NONE);
dupdate(); dupdate();
while(game->frame_duration < 20) sleep(); while(game->frame_duration < 20)
sleep();
game->frame_duration = 0; game->frame_duration = 0;
} }
} }
@ -202,11 +215,10 @@ void dialogs_text(Game *game, bopti_image_t *face, char *text,
bool dialog_start, bool dialog_end) { bool dialog_start, bool dialog_end) {
/* Run showtext_opt with some default values. It makes it easier to use in /* Run showtext_opt with some default values. It makes it easier to use in
* simple dialogs. */ * simple dialogs. */
dialogs_text_opt(game, face, text, NULL, dialog_start, dialog_end, NULL, 100, dialogs_text_opt(game, face, text, NULL, dialog_start, dialog_end, NULL,
true, 0, true); 100, true, 0, true);
} }
/* Some variables and pointers used to get some arguments passed in /* Some variables and pointers used to get some arguments passed in
* showtext_dialog_ask in _choice_call_before_end. */ * showtext_dialog_ask in _choice_call_before_end. */
char *_choices, *_text; char *_choices, *_text;
@ -216,31 +228,33 @@ unsigned int _i;
/* Get where I started drawing a dialog page, to be able to redraw the last page /* 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. */ * for the end animation in _choice_call_before_end. */
void _choice_screen_call( [[maybe_unused]] Game *game, unsigned int i) { void _choice_screen_call([[maybe_unused]] Game *game, unsigned int i) {
_i = i; _i = i;
} }
int _choice_call_before_end(Game *game, [[maybe_unused]] unsigned int org_i) { int _choice_call_before_end(Game *game, [[maybe_unused]] unsigned int org_i) {
int i, key; int i, key;
/* Make a little animation because we looove little animations ;) */ /* Make a little animation because we looove little animations ;) */
for(i=0;i<DWIDTH/8+1;i++){ for(i = 0; i < DWIDTH / 8 + 1; i++) {
/* Fill the interaction box with white */ /* Fill the interaction box with white */
drect(0, (BOX_HEIGHT+1)*PXSIZE+1, i*(DWIDTH/8), drect(0, (BOX_HEIGHT + 1) * PXSIZE + 1, i * (DWIDTH / 8),
(BOX_HEIGHT+CHOICE_BOX_HEIGHT)*PXSIZE, C_WHITE); (BOX_HEIGHT + CHOICE_BOX_HEIGHT) * PXSIZE, C_WHITE);
/* Draw a thick border on the right of the box. */ /* Draw a thick border on the right of the box. */
drect(i*(DWIDTH/8), BOX_HEIGHT*PXSIZE, i*(DWIDTH/8)+PXSIZE-1, drect(i * (DWIDTH / 8), BOX_HEIGHT * PXSIZE,
(BOX_HEIGHT+CHOICE_BOX_HEIGHT+1)*PXSIZE, C_BLACK); i * (DWIDTH / 8) + PXSIZE - 1,
(BOX_HEIGHT + CHOICE_BOX_HEIGHT + 1) * PXSIZE, C_BLACK);
/* Draw a thick border on the bottom of the box. */ /* Draw a thick border on the bottom of the box. */
drect(0, (BOX_HEIGHT+CHOICE_BOX_HEIGHT)*PXSIZE, i*(DWIDTH/8), drect(0, (BOX_HEIGHT + CHOICE_BOX_HEIGHT) * PXSIZE, i * (DWIDTH / 8),
(BOX_HEIGHT+CHOICE_BOX_HEIGHT+1)*PXSIZE, C_BLACK); (BOX_HEIGHT + CHOICE_BOX_HEIGHT + 1) * PXSIZE, C_BLACK);
/* Show everyting on screen. */ /* Show everyting on screen. */
blit(); blit();
/* Wait some ms so that the animation isn't too fast. */ /* Wait some ms so that the animation isn't too fast. */
while(game->frame_duration < 20) sleep(); while(game->frame_duration < 20)
sleep();
game->frame_duration = 0; game->frame_duration = 0;
} }
/* Calculate the maximal size of a choice. */ /* Calculate the maximal size of a choice. */
const int choice_size = DWIDTH/_choices_amount; const int choice_size = DWIDTH / _choices_amount;
/* arrow_width: The space taken by the arrow that shows the selected item. /* 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. * 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 * Used to calculate the size of the rectangle used to remove
@ -256,29 +270,32 @@ int _choice_call_before_end(Game *game, [[maybe_unused]] unsigned int org_i) {
dsize(">", &FONT_USED, &arrow_width, &arrow_height); dsize(">", &FONT_USED, &arrow_width, &arrow_height);
/* Add the character spacing of the font to it. */ /* Add the character spacing of the font to it. */
arrow_width += FONT_USED.char_spacing; arrow_width += FONT_USED.char_spacing;
for(i=0;i<_choices_amount;i++){ for(i = 0; i < _choices_amount; i++) {
dtext(i*choice_size+arrow_width+PXSIZE, dtext(i * choice_size + arrow_width + PXSIZE,
(BOX_HEIGHT+CHOICE_BOX_PADDING_TOP)*PXSIZE, C_BLACK, (BOX_HEIGHT + CHOICE_BOX_PADDING_TOP) * PXSIZE, C_BLACK,
_choices+pos); _choices + pos);
pos += strlen(_choices+pos)+1; pos += strlen(_choices + pos) + 1;
} }
do{ do {
/* Display the diffrent choices. */ /* Display the diffrent choices. */
for(i=0;i<_choices_amount;i++){ for(i = 0; i < _choices_amount; i++) {
if(i == selected) dtext(i*choice_size+PXSIZE, if(i == selected)
(BOX_HEIGHT+CHOICE_BOX_PADDING_TOP)*PXSIZE, dtext(i * choice_size + PXSIZE,
C_BLACK, ">"); (BOX_HEIGHT + CHOICE_BOX_PADDING_TOP) * PXSIZE, C_BLACK,
">");
} }
blit(); blit();
key = getkey_opt( GETKEY_DEFAULT & ~GETKEY_MOD_SHIFT & ~GETKEY_MOD_ALPHA, NULL).key; key = getkey_opt(GETKEY_DEFAULT & ~GETKEY_MOD_SHIFT & ~GETKEY_MOD_ALPHA,
NULL)
.key;
/* If the player pressed the left arrow key and has not already selected /* If the player pressed the left arrow key and has not already selected
* the first possible choice. */ * the first possible choice. */
if(key == KEY_LEFT && selected > 0){ if(key == KEY_LEFT && selected > 0) {
/* Remove the old arrow. */ /* Remove the old arrow. */
drect(selected*choice_size+PXSIZE, drect(selected * choice_size + PXSIZE,
(BOX_HEIGHT+CHOICE_BOX_PADDING_TOP)*PXSIZE, (BOX_HEIGHT + CHOICE_BOX_PADDING_TOP) * PXSIZE,
selected*choice_size+PXSIZE+arrow_width, selected * choice_size + PXSIZE + arrow_width,
(BOX_HEIGHT+CHOICE_BOX_PADDING_TOP)*PXSIZE+arrow_height, (BOX_HEIGHT + CHOICE_BOX_PADDING_TOP) * PXSIZE + arrow_height,
C_WHITE); C_WHITE);
/* Move the selection arrow and update the selected item. */ /* Move the selection arrow and update the selected item. */
@ -286,35 +303,37 @@ int _choice_call_before_end(Game *game, [[maybe_unused]] unsigned int org_i) {
} }
/* If the player pressed the right arrow key and has not already /* If the player pressed the right arrow key and has not already
* selected the last possible choice. */ * selected the last possible choice. */
else if(key == KEY_RIGHT && selected < _choices_amount-1){ else if(key == KEY_RIGHT && selected < _choices_amount - 1) {
/* Remove the old arrow. */ /* Remove the old arrow. */
drect(selected*choice_size+PXSIZE, drect(selected * choice_size + PXSIZE,
(BOX_HEIGHT+CHOICE_BOX_PADDING_TOP)*PXSIZE, (BOX_HEIGHT + CHOICE_BOX_PADDING_TOP) * PXSIZE,
selected*choice_size+PXSIZE+arrow_width, selected * choice_size + PXSIZE + arrow_width,
(BOX_HEIGHT+CHOICE_BOX_PADDING_TOP)*PXSIZE+arrow_height, (BOX_HEIGHT + CHOICE_BOX_PADDING_TOP) * PXSIZE + arrow_height,
C_WHITE); C_WHITE);
/* Move the selection arrow and update the selected item. */ /* Move the selection arrow and update the selected item. */
selected++; selected++;
} }
/* If the user has not validated his choice by pressing SHIFT, we loop one /* If the user has not validated his choice by pressing SHIFT, we loop
* more time. */ * one more time. */
}while(key != KEY_SHIFT); } while(key != KEY_SHIFT);
/* Make a little animation because we looove little animations ;) */ /* Make a little animation because we looove little animations ;) */
for(i=DWIDTH/8+1;i>0;i--){ for(i = DWIDTH / 8 + 1; i > 0; i--) {
/* I'm drawing the same box as on the start animation */ /* I'm drawing the same box as on the start animation */
update_npcs(game); update_npcs(game);
game_draw(game); game_draw(game);
dialogs_text_opt(game, _face, _text, NULL, false, false, NULL, 0, false, dialogs_text_opt(game, _face, _text, NULL, false, false, NULL, 0, false,
_i, false); _i, false);
drect(0, (BOX_HEIGHT+1)*PXSIZE+1, i*(DWIDTH/8), drect(0, (BOX_HEIGHT + 1) * PXSIZE + 1, i * (DWIDTH / 8),
(BOX_HEIGHT+CHOICE_BOX_HEIGHT)*PXSIZE, C_WHITE); (BOX_HEIGHT + CHOICE_BOX_HEIGHT) * PXSIZE, C_WHITE);
drect(i*(DWIDTH/8), BOX_HEIGHT*PXSIZE, i*(DWIDTH/8)+PXSIZE-1, drect(i * (DWIDTH / 8), BOX_HEIGHT * PXSIZE,
(BOX_HEIGHT+CHOICE_BOX_HEIGHT+1)*PXSIZE, C_BLACK); i * (DWIDTH / 8) + PXSIZE - 1,
drect(0, (BOX_HEIGHT+CHOICE_BOX_HEIGHT)*PXSIZE, i*(DWIDTH/8), (BOX_HEIGHT + CHOICE_BOX_HEIGHT + 1) * PXSIZE, C_BLACK);
(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(); dupdate();
while(game->frame_duration < 20) sleep(); while(game->frame_duration < 20)
sleep();
game->frame_duration = 0; game->frame_duration = 0;
} }
/* Return the selected item because he'll also be returned by showtext_opt. /* Return the selected item because he'll also be returned by showtext_opt.
@ -338,42 +357,41 @@ int dialogs_ask(Game *game, bopti_image_t *face, char *text, bool start,
end, _choice_screen_call, 100, true, 0, true); end, _choice_screen_call, 100, true, 0, true);
} }
void dialogs_initiate_sequence(Game *game, bopti_image_t *face, void dialogs_initiate_sequence(Game *game, bopti_image_t *face,
uint32_t dialogNumber) { uint32_t dialogNumber) {
Dialog *currentDiag = &game->map_level->dialogs[dialogNumber]; Dialog *currentDiag = &game->map_level->dialogs[dialogNumber];
/* we collect the information */ /* we collect the information */
char *text = currentDiag->dialog; char *text = currentDiag->dialog;
char *choices = currentDiag->choices ; char *choices = currentDiag->choices;
char *conclusion1 = currentDiag->conclusion1; char *conclusion1 = currentDiag->conclusion1;
int next1 = currentDiag->next1; int next1 = currentDiag->next1;
char *conclusion2 = currentDiag->conclusion2; char *conclusion2 = currentDiag->conclusion2;
int next2 = currentDiag->next2; int next2 = currentDiag->next2;
int nextOther = currentDiag->nextOther; int nextOther = currentDiag->nextOther;
int isQuestion = currentDiag->isQuestion; int isQuestion = currentDiag->isQuestion;
/* we treat the action - i.e. we show a dialog */ /* we treat the action - i.e. we show a dialog */
if (isQuestion == 1){ if(isQuestion == 1) {
/* we have to manage a question */ /* we have to manage a question */
int answer = dialogs_ask(game, face, text, true, true, int answer = dialogs_ask(game, face, text, true, true, choices, 2, 0);
choices, 2, 0);
/* TO DO we need to split the strings conclusion1 and conclusion2 */ /* TO DO we need to split the strings conclusion1 and conclusion2 */
/* to extract the "gift" part */ /* to extract the "gift" part */
if(answer==0){ if(answer == 0) {
dialogs_text(game, face, conclusion1, true, true); dialogs_text(game, face, conclusion1, true, true);
if (next1!=-1) dialogs_initiate_sequence(game, face, next1); if(next1 != -1)
}else{ dialogs_initiate_sequence(game, face, next1);
dialogs_text(game, face, conclusion2, true, true); } else {
if (next2!=-1) dialogs_initiate_sequence(game, face, next2); dialogs_text(game, face, conclusion2, true, true);
} if(next2 != -1)
}else{ dialogs_initiate_sequence(game, face, next2);
dialogs_text(game, face, text, true, true);
if (nextOther!=-1) dialogs_initiate_sequence(game, face, nextOther);
} }
} else {
dialogs_text(game, face, text, true, true);
if(nextOther != -1)
dialogs_initiate_sequence(game, face, nextOther);
}
} }

View file

@ -1,11 +1,11 @@
#ifndef DIALOG_H #ifndef DIALOG_H
#define DIALOG_H #define DIALOG_H
#include <gint/display.h> #include "config.h"
#include <string.h>
#include "game.h" #include "game.h"
#include "map.h" #include "map.h"
#include "config.h" #include <gint/display.h>
#include <string.h>
/* dialogs_text_opt() /* dialogs_text_opt()
* *
@ -37,8 +37,7 @@
int dialogs_text_opt(Game *game, bopti_image_t *face, char *text, int dialogs_text_opt(Game *game, bopti_image_t *face, char *text,
int call_before_end(Game *game, unsigned int i), int call_before_end(Game *game, unsigned int i),
bool start_anim, bool start_anim, bool end_anim,
bool end_anim,
void for_each_screen(Game *game, unsigned int i), void for_each_screen(Game *game, unsigned int i),
int line_duration, bool update_screen, int line_duration, bool update_screen,
unsigned int start_i, bool wait_continue); unsigned int start_i, bool wait_continue);

View file

@ -1,62 +1,45 @@
#include "events.h"
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
#include "events.h"
void events_init_handler(EventHandler *handler) { void events_init_handler(EventHandler *handler) { handler->vars = 0; }
handler->vars = 0;
}
int events_bind_variable(EventHandler *handler, int *var, char *name) { int events_bind_variable(EventHandler *handler, int *var, char *name) {
if(handler->vars < MAX_VARIABLES){ if(handler->vars < MAX_VARIABLES) {
handler->variables[handler->vars] = var; handler->variables[handler->vars] = var;
handler->var_names[handler->vars++] = name; handler->var_names[handler->vars++] = name;
}else{ } else {
return 1; return 1;
} }
return 0; return 0;
} }
char op_chars[OP_AMOUNT+1] = " =+-/*%"; char op_chars[OP_AMOUNT + 1] = " =+-/*%";
int _op_null(int a, int b) { int _op_null(int a, int b) { return 0; }
return 0;
}
int _op_set(int a, int b) { int _op_set(int a, int b) { return b; }
return b;
}
int _op_add(int a, int b) { int _op_add(int a, int b) { return a + b; }
return a+b;
}
int _op_sub(int a, int b) { int _op_sub(int a, int b) { return a - b; }
return a-b;
}
int _op_div(int a, int b) { int _op_div(int a, int b) {
if(b == 0) return 0; if(b == 0)
return a/b; return 0;
return a / b;
} }
int _op_mul(int a, int b) { int _op_mul(int a, int b) { return a * b; }
return a*b;
}
int _op_mod(int a, int b) { int _op_mod(int a, int b) {
if(b == 0) return 0; if(b == 0)
return a%b; return 0;
return a % b;
} }
int (*_operations[OP_AMOUNT])(int, int) = { int (*_operations[OP_AMOUNT])(int, int) = {_op_null, _op_set, _op_add, _op_sub,
_op_null, _op_div, _op_mul, _op_mod};
_op_set,
_op_add,
_op_sub,
_op_div,
_op_mul,
_op_mod
};
#define MIN(a, b) a < b ? a : b #define MIN(a, b) a < b ? a : b
@ -73,19 +56,19 @@ char *events_parse_string(EventHandler *handler, char *message) {
char c; char c;
size_t i, n; size_t i, n;
int *var; int *var;
for(i=0;i<strlen(message);i++){ for(i = 0; i < strlen(message); i++) {
c = message[i]; c = message[i];
if(c == '`'){ if(c == '`') {
in_token = !in_token; in_token = !in_token;
if(!in_token){ if(!in_token) {
if(tok_type == T_VAR_EDIT){ if(tok_type == T_VAR_EDIT) {
/* Do the calculation */ /* Do the calculation */
var_name[MIN(name_pos, TOKEN_MAX_SZ)] = '\0'; var_name[MIN(name_pos, TOKEN_MAX_SZ)] = '\0';
num[MIN(num_pos, TOKEN_MAX_SZ)] = '\0'; num[MIN(num_pos, TOKEN_MAX_SZ)] = '\0';
for(n=0;n<handler->vars;n++){ for(n = 0; n < handler->vars; n++) {
if(!strcmp(var_name, handler->var_names[n])){ if(!strcmp(var_name, handler->var_names[n])) {
var = handler->variables[n]; var = handler->variables[n];
if(var_op){ if(var_op) {
*var = _operations[var_op](*var, atoi(num)); *var = _operations[var_op](*var, atoi(num));
} }
break; break;
@ -98,22 +81,25 @@ char *events_parse_string(EventHandler *handler, char *message) {
var_op = OP_NULL; var_op = OP_NULL;
num_pos = 0; num_pos = 0;
} }
}else if(!in_token){ } else if(!in_token) {
if(message_pos < TOKEN_MAX_SZ) _message_buffer[message_pos++] = c; if(message_pos < TOKEN_MAX_SZ)
_message_buffer[message_pos++] = c;
} }
if(in_token && c != ' '){ if(in_token && c != ' ') {
if(tok_type == T_VAR_EDIT){ if(tok_type == T_VAR_EDIT) {
if(var_op != OP_NULL){ if(var_op != OP_NULL) {
if(num_pos < TOKEN_MAX_SZ) num[num_pos++] = c; if(num_pos < TOKEN_MAX_SZ)
num[num_pos++] = c;
} }
if(strchr(op_chars, c)){ if(strchr(op_chars, c)) {
var_op = (Operation)(strchr(op_chars, c)-op_chars); var_op = (Operation)(strchr(op_chars, c) - op_chars);
} }
if(var_op == OP_NULL){ if(var_op == OP_NULL) {
if(name_pos < TOKEN_MAX_SZ) var_name[name_pos++] = c; if(name_pos < TOKEN_MAX_SZ)
var_name[name_pos++] = c;
} }
} }
if(c == '$'){ if(c == '$') {
tok_type = T_VAR_EDIT; tok_type = T_VAR_EDIT;
} }
} }

View file

@ -15,11 +15,7 @@ typedef struct {
unsigned int vars; unsigned int vars;
} EventHandler; } EventHandler;
typedef enum { typedef enum { T_NULL, T_VAR_EDIT, T_AMOUNT } Token;
T_NULL,
T_VAR_EDIT,
T_AMOUNT
} Token;
typedef enum { typedef enum {
OP_NULL, OP_NULL,

View file

@ -4,39 +4,37 @@
#include "config.h" #include "config.h"
#include <stdlib.h>
#include <string.h>
#include <gint/keyboard.h>
#include <gint/cpu.h> #include <gint/cpu.h>
#include <gint/display.h> #include <gint/display.h>
#include <gint/keyboard.h>
#include <stdlib.h>
#include <string.h>
#include "npc.h" #include "npc.h"
extern bopti_image_t SignAction_img; extern bopti_image_t SignAction_img;
extern Dialog *dialogRPG; extern Dialog *dialogRPG;
extern NPC *npcRPG; extern NPC *npcRPG;
extern uint32_t nbNPC; extern uint32_t nbNPC;
#define MAX_INTERACTION_DISTANCE 12 #define MAX_INTERACTION_DISTANCE 12
void game_logic(Game *game) { void game_logic(Game *game) {
update_npcs( game ); update_npcs(game);
/* we check if interactions are possible close to the player */ /* we check if interactions are possible close to the player */
for( uint32_t i=0; i<game->map_level->nbextradata; i++ ){ for(uint32_t i = 0; i < game->map_level->nbextradata; i++) {
/* simple distance check along X and Y axis */ /* simple distance check along X and Y axis */
/* Be careful to use world coordinates, not local (i.e.map) ones */ /* Be careful to use world coordinates, not local (i.e.map) ones */
if ((abs((int) game->player.wx - if((abs((int)game->player.wx -
(int) game->map_level->extradata[i].x*PXSIZE ) (int)game->map_level->extradata[i].x * PXSIZE) <
< MAX_INTERACTION_DISTANCE*PXSIZE) MAX_INTERACTION_DISTANCE * PXSIZE) &&
&& (abs((int) game->player.wy - (abs((int)game->player.wy -
(int) game->map_level->extradata[i].y*PXSIZE ) (int)game->map_level->extradata[i].y * PXSIZE) <
< MAX_INTERACTION_DISTANCE*PXSIZE) MAX_INTERACTION_DISTANCE * PXSIZE) &&
&& strcmp(game->map_level->extradata[i].type, "NPC") != 0){ strcmp(game->map_level->extradata[i].type, "NPC") != 0) {
/* the player can do something */ /* the player can do something */
game->player.canDoSomething = true; game->player.canDoSomething = true;
/* we mark the action for futur treatment in player_action() */ /* we mark the action for futur treatment in player_action() */
@ -47,16 +45,14 @@ void game_logic(Game *game) {
} }
} }
for(uint32_t i=0; i<nbNPC; i++){ for(uint32_t i = 0; i < nbNPC; i++) {
/* simple distance check along X and Y axis */ /* simple distance check along X and Y axis */
/* Be careful to use world coordinates, not local (i.e.map) ones */ /* Be careful to use world coordinates, not local (i.e.map) ones */
if ((abs((int) game->player.wx - if((abs((int)game->player.wx - (int)npcRPG[i].curx * PXSIZE) <
(int) npcRPG[i].curx*PXSIZE ) MAX_INTERACTION_DISTANCE * PXSIZE) &&
< MAX_INTERACTION_DISTANCE*PXSIZE) (abs((int)game->player.wy - (int)npcRPG[i].cury * PXSIZE) <
&& (abs((int) game->player.wy - MAX_INTERACTION_DISTANCE * PXSIZE) &&
(int) npcRPG[i].cury*PXSIZE ) strcmp(game->map_level->extradata[i].type, "NPC") != 0) {
< MAX_INTERACTION_DISTANCE*PXSIZE)
&& strcmp( game->map_level->extradata[i].type, "NPC") !=0){
/* the player can do something */ /* the player can do something */
game->player.canDoSomething = true; game->player.canDoSomething = true;
/* we mark the action for futur treatment in player_action() */ /* we mark the action for futur treatment in player_action() */
@ -67,7 +63,6 @@ void game_logic(Game *game) {
} }
} }
/* else nothing to be done here */ /* else nothing to be done here */
game->player.canDoSomething = false; game->player.canDoSomething = false;
game->player.whichAction = -1; game->player.whichAction = -1;
@ -75,16 +70,15 @@ void game_logic(Game *game) {
return; return;
} }
void game_render_indicator(Game *game) { void game_render_indicator(Game *game) {
/* nothing to do for the player so we quit */ /* nothing to do for the player so we quit */
if(game->player.canDoSomething==false) return; if(game->player.canDoSomething == false)
return;
/* else we draw a small indicator on the screen */ /* else we draw a small indicator on the screen */
dimage(5, 5, &SignAction_img); dimage(5, 5, &SignAction_img);
} }
void game_draw(Game *game) { void game_draw(Game *game) {
/* Draw everything. */ /* Draw everything. */
dclear(C_WHITE); dclear(C_WHITE);
@ -106,18 +100,24 @@ void game_get_inputs(Game *game) {
/*************************************/ /*************************************/
if(keydown(KEY_EXIT)) game->exittoOS = true; if(keydown(KEY_EXIT))
game->exittoOS = true;
/* Player actions - Prototypes in player.h and implementation in player.c */ /* Player actions - Prototypes in player.h and implementation in player.c */
if(keydown(KEY_LEFT)) player_move(game, D_LEFT); if(keydown(KEY_LEFT))
if(keydown(KEY_RIGHT)) player_move(game, D_RIGHT); player_move(game, D_LEFT);
if(keydown(KEY_UP)) player_move(game, D_UP); if(keydown(KEY_RIGHT))
if(keydown(KEY_DOWN)) player_move(game, D_DOWN); player_move(game, D_RIGHT);
if(keydown(KEY_SHIFT)) player_action(game); if(keydown(KEY_UP))
if(keydown(KEY_OPTN)){ player_move(game, D_UP);
if(keydown(KEY_DOWN))
player_move(game, D_DOWN);
if(keydown(KEY_SHIFT))
player_action(game);
if(keydown(KEY_OPTN)) {
game->player.is_male = !game->player.is_male; game->player.is_male = !game->player.is_male;
/* TODO: Make something cleaner */ /* TODO: Make something cleaner */
while(keydown(KEY_OPTN)){ while(keydown(KEY_OPTN)) {
clearevents(); clearevents();
sleep(); sleep();
} }
@ -136,12 +136,13 @@ void game_get_inputs(Game *game) {
} }
#endif #endif
/* if USB is enabled - keybinding for screencapture */ /* if USB is enabled - keybinding for screencapture */
#if USB_FEATURE #if USB_FEATURE
if(keydown(KEY_7)) game->screenshot = true; if(keydown(KEY_7))
if(keydown(KEY_8)) game->record = !game->record; game->screenshot = true;
if(keydown(KEY_8))
game->record = !game->record;
#endif //USB_FEATURE #endif // USB_FEATURE
} }

View file

@ -1,39 +1,24 @@
#ifndef GAME_H #ifndef GAME_H
#define GAME_H #define GAME_H
#include <gint/display.h> #include <gint/display.h>
#include <stdint.h> #include <stdint.h>
#include "events.h" #include "events.h"
/* The direction where the player is going to. */ /* The direction where the player is going to. */
typedef enum { typedef enum { D_UP, D_DOWN, D_LEFT, D_RIGHT } Direction;
D_UP,
D_DOWN,
D_LEFT,
D_RIGHT
} Direction;
typedef enum {
P_LEFTUP = -1,
P_CENTER = 0,
P_RIGHTDOWN = 1
} Checkpos;
typedef enum { P_LEFTUP = -1, P_CENTER = 0, P_RIGHTDOWN = 1 } Checkpos;
/* Struct that define player parameters */ /* Struct that define player parameters */
typedef struct { typedef struct {
int16_t x, y; /* The position of the player int the current map */ int16_t x, y; /* The position of the player int the current map */
uint16_t px, py; /* The position of the player on screen */ uint16_t px, py; /* The position of the player on screen */
int16_t wx, wy; /* position of the player in the world */ int16_t wx, wy; /* position of the player in the world */
int8_t life; /* How many lives the player still has between 0 and 100. */ int8_t life; /* How many lives the player still has between 0 and 100. */
int8_t speed; /* The speed of the movement of the player. */ int8_t speed; /* The speed of the movement of the player. */
/* set to true if a action can be done in the current position of the map */ /* set to true if a action can be done in the current position of the map */
bool canDoSomething; bool canDoSomething;
/* indicates which data are relevant to the current action in the */ /* indicates which data are relevant to the current action in the */
@ -46,7 +31,6 @@ typedef struct {
bool is_male; bool is_male;
} Player; } Player;
typedef struct { typedef struct {
uint32_t ID; uint32_t ID;
/* data to be shown in the dialog*/ /* data to be shown in the dialog*/
@ -64,7 +48,6 @@ typedef struct {
int32_t nextOther; int32_t nextOther;
} Dialog; } Dialog;
typedef struct { typedef struct {
/* position of the item */ /* position of the item */
uint32_t x; uint32_t x;
@ -91,7 +74,6 @@ typedef struct {
/* ... this can be extended as per needs ... */ /* ... this can be extended as per needs ... */
} ExtraData; } ExtraData;
typedef struct { typedef struct {
/* width, height and the number of layer of the map */ /* width, height and the number of layer of the map */
uint32_t w; uint32_t w;
@ -114,7 +96,8 @@ typedef struct {
uint8_t *walkable; uint8_t *walkable;
/* structure that contains all the items on the map to interract with */ /* structure that contains all the items on the map to interract with */
/* each portion of the map has its own list to avoid scrutinizing too much */ /* each portion of the map has its own list to avoid scrutinizing too much
*/
/* data when lloking for proximity of items */ /* data when lloking for proximity of items */
uint32_t nbextradata; uint32_t nbextradata;
ExtraData *extradata; ExtraData *extradata;
@ -127,14 +110,12 @@ typedef struct {
uint16_t *layers[]; uint16_t *layers[];
} Map; } Map;
/* This struct will contain all the data of the game. It will make it possible /* This struct will contain all the data of the game. It will make it possible
* to pass it to the NPCs to let them interact with the player and the rest of * to pass it to the NPCs to let them interact with the player and the rest of
* the world. */ * the world. */
typedef struct { typedef struct {
Map *map_level; /* The level that the player is currently playing */ Map *map_level; /* The level that the player is currently playing */
Player player; /* The player data. */ Player player; /* The player data. */
EventHandler handler; /* The event handler (see events.h). */ EventHandler handler; /* The event handler (see events.h). */
/* Some global variables */ /* Some global variables */
/* Set to true when asked for exit */ /* Set to true when asked for exit */
@ -180,4 +161,3 @@ void game_render_indicator(Game *game);
void game_get_inputs(Game *game); void game_get_inputs(Game *game);
#endif #endif

View file

@ -1,27 +1,26 @@
#include <gint/cpu.h>
#include <gint/display.h> #include <gint/display.h>
#include <gint/keyboard.h> #include <gint/keyboard.h>
#include <gint/timer.h> #include <gint/timer.h>
#include <gint/cpu.h>
#include <fxlibc/printf.h> #include <fxlibc/printf.h>
#include "config.h" #include "config.h"
#include "npc.h"
#include "events.h" #include "events.h"
#include "npc.h"
#if USB_FEATURE #if USB_FEATURE
#include <gint/usb-ff-bulk.h> #include <gint/usb-ff-bulk.h>
#include <gint/usb.h> #include <gint/usb.h>
#endif //USB_FEATURE #endif // USB_FEATURE
#if GRAYMODEOK #if GRAYMODEOK
#include <gint/gray.h> #include <gint/gray.h>
#endif //GRAYMODEOK #endif // GRAYMODEOK
#include <stdint.h>
#include <stdbool.h> #include <stdbool.h>
#include <stdint.h>
#include "game.h" #include "game.h"
#include "mapdata.h" #include "mapdata.h"
@ -30,56 +29,59 @@
extern bopti_image_t player_face_img; extern bopti_image_t player_face_img;
extern Map *worldRPG[]; extern Map *worldRPG[];
/* Game data (defined in "game.h")*/ /* Game data (defined in "game.h")*/
Game game = { Game game = {NULL,
NULL, {12 * PXSIZE, 36 * PXSIZE, 0, 0, 12 * PXSIZE, 36 * PXSIZE, 100,
{12*PXSIZE, 36*PXSIZE, 0, 0, 12*PXSIZE, 36*PXSIZE, 100, SPEED, false, 0, false, false, true}, SPEED, false, 0, false, false, true},
{{}, {}, 0}, {{}, {}, 0},
false, false, false, 0 false,
false,
false,
0
/* debug variables*/ /* debug variables*/
, false, false, false, 100 ,
}; false,
false,
false,
100};
/* screen capture management code. TODO: Clean this up! */ /* screen capture management code. TODO: Clean this up! */
#if USB_FEATURE #if USB_FEATURE
void USB_feature( void ) void USB_feature(void) {
{ if(game.screenshot && usb_is_open()) {
if (game.screenshot && usb_is_open()) {
#if GRAYMODEOK // This is a trick, if GRAYMODEOK is defined then #if GRAYMODEOK // This is a trick, if GRAYMODEOK is defined then
// we make the code accessible // we make the code accessible
if (dgray_enabled()) if(dgray_enabled())
usb_fxlink_screenshot_gray(false); usb_fxlink_screenshot_gray(false);
else else
#endif #endif
// else we just let the usual screeshot function // else we just let the usual screeshot function
usb_fxlink_screenshot(false); usb_fxlink_screenshot(false);
game.screenshot = false; game.screenshot = false;
} }
if(game.record && usb_is_open()) {
if (game.record && usb_is_open()) { #if GRAYMODEOK
#if GRAYMODEOK if(dgray_enabled())
usb_fxlink_videocapture_gray(false);
else
if (dgray_enabled()) #endif
usb_fxlink_videocapture_gray(false);
else
#endif
usb_fxlink_videocapture(false); usb_fxlink_videocapture(false);
}
} }
}
#endif #endif
@ -96,75 +98,76 @@ int main(void) {
int timer; int timer;
timer = timer_configure(TIMER_TMU, 1000, GINT_CALL(update_time)); timer = timer_configure(TIMER_TMU, 1000, GINT_CALL(update_time));
if(timer < 0){ if(timer < 0) {
return -1; return -1;
} }
timer_start(timer); timer_start(timer);
game.map_level = worldRPG[0]; game.map_level = worldRPG[0];
events_init_handler(&game.handler); events_init_handler(&game.handler);
events_bind_variable(&game.handler, (int*)&game.player.life, "life"); events_bind_variable(&game.handler, (int *)&game.player.life, "life");
events_bind_variable(&game.handler, &game.mana, "mana"); events_bind_variable(&game.handler, &game.mana, "mana");
reload_npc(&game); reload_npc(&game);
#if USB_FEATURE #if USB_FEATURE
usb_interface_t const *interfaces[] = {&usb_ff_bulk, NULL}; usb_interface_t const *interfaces[] = {&usb_ff_bulk, NULL};
usb_open(interfaces, GINT_CALL_NULL); usb_open(interfaces, GINT_CALL_NULL);
#endif #endif
/* start grayscale engine */ /* start grayscale engine */
#if GRAYMODEOK #if GRAYMODEOK
dgray(DGRAY_ON); dgray(DGRAY_ON);
#endif #endif
do{ do {
/* clear screen */ /* clear screen */
dclear(C_WHITE); dclear(C_WHITE);
/* render the map */ /* render the map */
game_draw(&game); game_draw(&game);
#if DEBUGMODE && GINT_RENDER_RGB #if DEBUGMODE && GINT_RENDER_RGB
if (game.debug_map) if(game.debug_map) {
{ dfont(NULL);
dfont( NULL ); drect(5, 5, 390, 55, C_WHITE);
drect( 5, 5,390, 55, C_WHITE ); dprint(10, 10, C_RED, "Map[%d] : Xmn %d Ymn %d Xmx %d Ymx %d", 0,
dprint(10, 10, C_RED, "Map[%d] : Xmn %d Ymn %d Xmx %d Ymx %d", worldRPG[0]->xmin, worldRPG[0]->ymin, worldRPG[0]->xmax,
0, worldRPG[0]->xmin, worldRPG[0]->ymin, worldRPG[0]->ymax);
worldRPG[0]->xmax, worldRPG[0]->ymax); dprint(10, 20, C_RED, "Map[%d] : Xmn %d Ymn %d Xmx %d Ymx %d", 1,
dprint(10, 20, C_RED, "Map[%d] : Xmn %d Ymn %d Xmx %d Ymx %d", worldRPG[1]->xmin, worldRPG[1]->ymin, worldRPG[1]->xmax,
1, worldRPG[1]->xmin, worldRPG[1]->ymin, worldRPG[1]->ymax);
worldRPG[1]->xmax, worldRPG[1]->ymax); dprint(10, 30, C_RED, "Map[%d] : Xmn %d Ymn %d Xmx %d Ymx %d", 2,
dprint(10, 30, C_RED, "Map[%d] : Xmn %d Ymn %d Xmx %d Ymx %d", worldRPG[2]->xmin, worldRPG[2]->ymin, worldRPG[2]->xmax,
2, worldRPG[2]->xmin, worldRPG[2]->ymin, worldRPG[2]->ymax);
worldRPG[2]->xmax, worldRPG[2]->ymax); dprint(10, 40, C_RED, "Map[%d] : Xmn %d Ymn %d Xmx %d Ymx %d", 3,
dprint(10, 40, C_RED, "Map[%d] : Xmn %d Ymn %d Xmx %d Ymx %d", worldRPG[3]->xmin, worldRPG[3]->ymin, worldRPG[3]->xmax,
3, worldRPG[3]->xmin, worldRPG[3]->ymin, worldRPG[3]->ymax);
worldRPG[3]->xmax, worldRPG[3]->ymax); }
} if(game.debug_player) {
if (game.debug_player) dfont(NULL);
{ drect(5, 55, 390, 75, C_WHITE);
dfont( NULL ); dprint(10, 60, C_BLUE, "X= %d - Y= %d / Wx= %d - Wy= %d",
drect( 5, 55,390, 75, C_WHITE ); game.player.x, game.player.y, game.player.wx,
dprint( 10, 60, C_BLUE, "X= %d - Y= %d / Wx= %d - Wy= %d", game.player.wy);
game.player.x, game.player.y, game.player.wx, }
game.player.wy ); if(game.debug_extra) {
} dfont(NULL);
if (game.debug_extra) for(int i = 0; i < game.map_level->nbextradata; i++)
{ dprint(10, 90 + i * 15, C_RED,
dfont( NULL ); "X= %d - Y= %d - T: %d - ID: %d - S: %c",
for (int i=0; i<game.map_level->nbextradata; i++ ) game.map_level->extradata[i].x,
dprint( 10, 90+i*15, C_RED, "X= %d - Y= %d - T: %d - ID: %d - S: %c", game.map_level->extradata[i].y,
game.map_level->extradata[i].x, game.map_level->extradata[i].dialogID,
game.map_level->extradata[i].y, game.map_level
game.map_level->extradata[i].dialogID, ->dialogs[game.map_level->extradata[i].dialogID]
game.map_level->dialogs[ game.map_level->extradata[i].dialogID ].ID, .ID,
game.map_level->dialogs[ game.map_level->extradata[i].dialogID ].conclusion1[0] ); game.map_level
} ->dialogs[game.map_level->extradata[i].dialogID]
#endif .conclusion1[0]);
}
#endif
/* start the logic of the game */ /* start the logic of the game */
game_logic(&game); game_logic(&game);
@ -172,33 +175,30 @@ int main(void) {
/* Screen blit */ /* Screen blit */
dupdate(); dupdate();
/* Screen capture feature if enabled */ /* Screen capture feature if enabled */
#if USB_FEATURE #if USB_FEATURE
USB_feature(); USB_feature();
#endif #endif
/* Management of the inputs */ /* Management of the inputs */
game_get_inputs(&game); game_get_inputs(&game);
/* Run the game at max. 50fps */ /* Run the game at max. 50fps */
while(game.frame_duration < 20) sleep(); while(game.frame_duration < 20)
sleep();
/* Reset frame_duration for the next frame */ /* Reset frame_duration for the next frame */
game.frame_duration = 0; game.frame_duration = 0;
}while(!game.exittoOS); // want to exit ? } while(!game.exittoOS); // want to exit ?
/* shutdown grayengine*/
#if GRAYMODEOK
dgray(DGRAY_OFF);
#endif
/* close USB */
/* shutdown grayengine*/ #if USB_FEATURE
#if GRAYMODEOK usb_close();
dgray(DGRAY_OFF); #endif
#endif
/* close USB */
#if USB_FEATURE
usb_close();
#endif
timer_stop(timer); timer_stop(timer);
return 1; return 1;
} }

148
src/map.c
View file

@ -5,8 +5,7 @@
#include <gint/display.h> #include <gint/display.h>
extern Map *worldRPG[]; extern Map *worldRPG[];
//extern ExtraData *extraRPG[]; // extern ExtraData *extraRPG[];
void map_render(Game *game) { void map_render(Game *game) {
@ -25,9 +24,10 @@ void map_render(Game *game) {
unsigned char mx, my; unsigned char mx, my;
/* dw and dh contain the amount of tiles that will be drawn on x and on /* dw and dh contain the amount of tiles that will be drawn on x and on
* y. */ * y. */
unsigned char dw = DWIDTH/T_WIDTH+2, dh = DHEIGHT/T_HEIGHT+1; unsigned char dw = DWIDTH / T_WIDTH + 2, dh = DHEIGHT / T_HEIGHT + 1;
/* mw and mh will contain the height and the width of the map. */ /* mw and mh will contain the height and the width of the map. */
unsigned short int mw = map_level->w*T_WIDTH, mh = map_level->h*T_HEIGHT; unsigned short int mw = map_level->w * T_WIDTH,
mh = map_level->h * T_HEIGHT;
/* tile contains the tile to draw. */ /* tile contains the tile to draw. */
short int tile; short int tile;
/* The position where I start drawing */ /* The position where I start drawing */
@ -39,62 +39,62 @@ void map_render(Game *game) {
/* The index of the current tile we're drawing in the layer. */ /* The index of the current tile we're drawing in the layer. */
int current_index; int current_index;
/* Fix sx. */ /* Fix sx. */
if(player->x<DWIDTH/2){ if(player->x < DWIDTH / 2) {
/* If I can't center the player because I'm near the left border of /* If I can't center the player because I'm near the left border of
* the map. */ * the map. */
player->px = player->x; player->px = player->x;
sx = 0; sx = 0;
}else if(player->x+DWIDTH/2>mw){ } else if(player->x + DWIDTH / 2 > mw) {
/* If I can't center the player because I'm near the right border of /* If I can't center the player because I'm near the right border of
* the map. */ * the map. */
sx = mw-DWIDTH; sx = mw - DWIDTH;
player->px = player->x-sx; player->px = player->x - sx;
}else{ } else {
/* I can center the player. */ /* I can center the player. */
player->px = DWIDTH/2; player->px = DWIDTH / 2;
sx = player->x-player->px; sx = player->x - player->px;
} }
/* Fix sy. */ /* Fix sy. */
if(player->y<DHEIGHT/2){ if(player->y < DHEIGHT / 2) {
/* If I can't center the player because I'm near the top border of /* If I can't center the player because I'm near the top border of
* the map. */ * the map. */
player->py = player->y; player->py = player->y;
sy = 0; sy = 0;
}else if(player->y+DHEIGHT/2>mh){ } else if(player->y + DHEIGHT / 2 > mh) {
/* If I can't center the player because I'm near the bottom border /* If I can't center the player because I'm near the bottom border
* of the map. */ * of the map. */
sy = mh-DHEIGHT; sy = mh - DHEIGHT;
player->py = player->y-sy; player->py = player->y - sy;
}else{ } else {
/* I can center the player. */ /* I can center the player. */
player->py = DHEIGHT/2; player->py = DHEIGHT / 2;
sy = player->y-player->py; sy = player->y - player->py;
} }
tx = sx/T_WIDTH; tx = sx / T_WIDTH;
ty = sy/T_HEIGHT; ty = sy / T_HEIGHT;
mx = sx-tx*T_WIDTH; mx = sx - tx * T_WIDTH;
my = sy-ty*T_HEIGHT; my = sy - ty * T_HEIGHT;
for (l = 0; l < map_level->nblayers-1; l++){ for(l = 0; l < map_level->nblayers - 1; l++) {
/* Draw a layer of the map on screen. */ /* Draw a layer of the map on screen. */
for(y=0;y<dh;y++){ for(y = 0; y < dh; y++) {
for(x=0;x<dw;x++){ for(x = 0; x < dw; x++) {
/* I get the tile number if his position is inside the map. Then /* I get the tile number if his position is inside the map. Then
* I draw it. */ * I draw it. */
if(tx+x>=0 && tx+x < map_level->w && if(tx + x >= 0 && tx + x < map_level->w && ty + y >= 0 &&
ty+y>=0 && ty+y < map_level->h){ ty + y < map_level->h) {
/* index of the current tile */ /* index of the current tile */
current_index = (y+ty) * map_level->w + tx+x; current_index = (y + ty) * map_level->w + tx + x;
/* we get the ID of the tile in the current drawable layers /* we get the ID of the tile in the current drawable layers
*/ */
tile = map_level->layers[l][current_index]; tile = map_level->layers[l][current_index];
/* tile == -1 means nothing to be drawn */ /* tile == -1 means nothing to be drawn */
if(tile >= 0){ if(tile >= 0) {
/* get x and y position in the tileset image */ /* get x and y position in the tileset image */
xtile = (tile % map_level->tileset_size) * T_WIDTH; xtile = (tile % map_level->tileset_size) * T_WIDTH;
ytile = (tile / map_level->tileset_size) * T_HEIGHT; ytile = (tile / map_level->tileset_size) * T_HEIGHT;
/* render */ /* render */
dsubimage(x*T_WIDTH-mx, y*T_HEIGHT-my, dsubimage(x * T_WIDTH - mx, y * T_HEIGHT - my,
map_level->tileset, xtile, ytile, T_WIDTH, map_level->tileset, xtile, ytile, T_WIDTH,
T_HEIGHT, DIMAGE_NONE); T_HEIGHT, DIMAGE_NONE);
} }
@ -121,9 +121,10 @@ void map_render_by_layer(Game *game, int layer) {
unsigned char mx, my; unsigned char mx, my;
/* dw and dh contain the amount of tiles that will be drawn on x and on /* dw and dh contain the amount of tiles that will be drawn on x and on
* y. */ * y. */
unsigned char dw = DWIDTH/T_WIDTH+2, dh = DHEIGHT/T_HEIGHT+1; unsigned char dw = DWIDTH / T_WIDTH + 2, dh = DHEIGHT / T_HEIGHT + 1;
/* mw and mh will contain the height and the width of the map. */ /* mw and mh will contain the height and the width of the map. */
unsigned short int mw = map_level->w*T_WIDTH, mh = map_level->h*T_HEIGHT; unsigned short int mw = map_level->w * T_WIDTH,
mh = map_level->h * T_HEIGHT;
/* tile contains the tile to draw. */ /* tile contains the tile to draw. */
short int tile; short int tile;
/* The position where I start drawing */ /* The position where I start drawing */
@ -131,63 +132,63 @@ void map_render_by_layer(Game *game, int layer) {
/* The position of the tile in the tileset. */ /* The position of the tile in the tileset. */
unsigned short int xtile, ytile; unsigned short int xtile, ytile;
/* Fix sx. */ /* Fix sx. */
if(player->x<DWIDTH/2){ if(player->x < DWIDTH / 2) {
/* If I can't center the player because I'm near the left border of /* If I can't center the player because I'm near the left border of
* the map. */ * the map. */
player->px = player->x; player->px = player->x;
sx = 0; sx = 0;
}else if(player->x+DWIDTH/2>mw){ } else if(player->x + DWIDTH / 2 > mw) {
/* If I can't center the player because I'm near the right border of /* If I can't center the player because I'm near the right border of
* the map. */ * the map. */
sx = mw-DWIDTH; sx = mw - DWIDTH;
player->px = player->x-sx; player->px = player->x - sx;
}else{ } else {
/* I can center the player. */ /* I can center the player. */
player->px = DWIDTH/2; player->px = DWIDTH / 2;
sx = player->x-player->px; sx = player->x - player->px;
} }
/* Fix sy. */ /* Fix sy. */
if(player->y<DHEIGHT/2){ if(player->y < DHEIGHT / 2) {
/* If I can't center the player because I'm near the top border of /* If I can't center the player because I'm near the top border of
* the map. */ * the map. */
player->py = player->y; player->py = player->y;
sy = 0; sy = 0;
}else if(player->y+DHEIGHT/2>mh){ } else if(player->y + DHEIGHT / 2 > mh) {
/* If I can't center the player because I'm near the bottom border /* If I can't center the player because I'm near the bottom border
* of the map. */ * of the map. */
sy = mh-DHEIGHT; sy = mh - DHEIGHT;
player->py = player->y-sy; player->py = player->y - sy;
}else{ } else {
/* I can center the player. */ /* I can center the player. */
player->py = DHEIGHT/2; player->py = DHEIGHT / 2;
sy = player->y-player->py; sy = player->y - player->py;
} }
tx = sx/T_WIDTH; tx = sx / T_WIDTH;
ty = sy/T_HEIGHT; ty = sy / T_HEIGHT;
mx = sx-tx*T_WIDTH; mx = sx - tx * T_WIDTH;
my = sy-ty*T_HEIGHT; my = sy - ty * T_HEIGHT;
/* Draw a layer of the map on screen. */ /* Draw a layer of the map on screen. */
for(y=0;y<dh;y++){ for(y = 0; y < dh; y++) {
for(x=0;x<dw;x++){ for(x = 0; x < dw; x++) {
/* I get the tile number if his position is inside the map. Then /* I get the tile number if his position is inside the map. Then
* I draw it. */ * I draw it. */
if(tx+x>=0 && tx+x < map_level->w && if(tx + x >= 0 && tx + x < map_level->w && ty + y >= 0 &&
ty+y>=0 && ty+y < map_level->h){ ty + y < map_level->h) {
/* index of the current tile */ /* index of the current tile */
int currentIndex = (y+ty) * map_level->w + tx+x; int currentIndex = (y + ty) * map_level->w + tx + x;
/* we get the ID of the tile in the current drawable layers /* we get the ID of the tile in the current drawable layers
*/ */
tile = map_level->layers[layer][currentIndex]; tile = map_level->layers[layer][currentIndex];
/* tile == -1 means nothing to be drawn */ /* tile == -1 means nothing to be drawn */
if(tile >= 0){ if(tile >= 0) {
/* get x and y position in the tileset image */ /* get x and y position in the tileset image */
xtile = (tile % map_level->tileset_size) * T_WIDTH; xtile = (tile % map_level->tileset_size) * T_WIDTH;
ytile = (tile / map_level->tileset_size) * T_HEIGHT; ytile = (tile / map_level->tileset_size) * T_HEIGHT;
/* render */ /* render */
dsubimage(x*T_WIDTH-mx, y*T_HEIGHT-my, dsubimage(x * T_WIDTH - mx, y * T_HEIGHT - my,
map_level->tileset, xtile, ytile, T_WIDTH, map_level->tileset, xtile, ytile, T_WIDTH,
T_HEIGHT, DIMAGE_NONE); T_HEIGHT, DIMAGE_NONE);
} }
} }
} }
@ -200,8 +201,9 @@ short int map_get_tile(Game *game, int x, int y, int l) {
/* Get the tile at (x, y) on layer l. Returns the tile ID or MAP_OUTSIDE if /* Get the tile at (x, y) on layer l. Returns the tile ID or MAP_OUTSIDE if
* it's not found. */ * it's not found. */
return (x>=0 && x < (int) map_level->w && y>=0 && y < (int) map_level->h) ? return (x >= 0 && x < (int)map_level->w && y >= 0 && y < (int)map_level->h)
map_level->layers[l][y * map_level->w + x] : MAP_OUTSIDE; ? map_level->layers[l][y * map_level->w + x]
: MAP_OUTSIDE;
} }
short int map_get_walkable(Game *game, int x, int y) { short int map_get_walkable(Game *game, int x, int y) {
@ -209,29 +211,29 @@ short int map_get_walkable(Game *game, int x, int y) {
Map *map_level = game->map_level; Map *map_level = game->map_level;
/* Get the tile at (x, y). Returns the tile ID or MAP_OUTSIDE if she's not /* Get the tile at (x, y). Returns the tile ID or MAP_OUTSIDE if she's not
* found. */ * found. */
return (x>=0 && x < (int) map_level->w && y>=0 && y < (int) map_level->h) ? return (x >= 0 && x < (int)map_level->w && y >= 0 && y < (int)map_level->h)
map_level->walkable[y * map_level->w + x] : MAP_OUTSIDE; ? map_level->walkable[y * map_level->w + x]
: MAP_OUTSIDE;
} }
/* return the pointer to the map containing the given position */ /* return the pointer to the map containing the given position */
Map *map_get_for_coordinates( Game *game, int x, int y ) Map *map_get_for_coordinates(Game *game, int x, int y) {
{
/* check if the current map contains the point */ /* check if the current map contains the point */
if (x>= (int)game->map_level->xmin && x< (int)game->map_level->xmax && if(x >= (int)game->map_level->xmin && x < (int)game->map_level->xmax &&
y>= (int)game->map_level->ymin && y< (int)game->map_level->ymax){ y >= (int)game->map_level->ymin && y < (int)game->map_level->ymax) {
return game->map_level; return game->map_level;
} }
/* else we check in worldRPG if there is a mal containing that point */ /* else we check in worldRPG if there is a mal containing that point */
int i = 0; int i = 0;
Map *current = worldRPG[i]; Map *current = worldRPG[i];
do{ do {
if (x>= (int)current->xmin && x< (int)current->xmax && if(x >= (int)current->xmin && x < (int)current->xmax &&
y>= (int)current->ymin && y< (int)current->ymax) y >= (int)current->ymin && y < (int)current->ymax)
return current; return current;
i++; i++;
current = worldRPG[i]; current = worldRPG[i];
}while (current!=NULL); } while(current != NULL);
/* else we return NULL cause the point is a not within a map */ /* else we return NULL cause the point is a not within a map */
return NULL; return NULL;

View file

@ -1,24 +1,20 @@
#ifndef MAP_H #ifndef MAP_H
#define MAP_H #define MAP_H
#define BACKGROUND 0 #define BACKGROUND 0
#define FOREGROUND 1 #define FOREGROUND 1
#define MAP_OUTSIDE -2 /* Returned by get_tile_at_pos if the point is outside of #define MAP_OUTSIDE \
* the map. */ -2 /* Returned by get_tile_at_pos if the point is outside of \
* the map. */
#include "game.h" #include "game.h"
#include "player.h" #include "player.h"
/* Structure 'Map' has been moved to game.h */ /* Structure 'Map' has been moved to game.h */
/* to avoid circular references between map.h, game.h and player.h */ /* to avoid circular references between map.h, game.h and player.h */
/* only methods propotypes are now in dedicated header files */ /* only methods propotypes are now in dedicated header files */
/* map_render() /* map_render()
* *
* Draws the map map on the entire screen to be viewed by the player player. * Draws the map map on the entire screen to be viewed by the player player.
@ -61,6 +57,6 @@ short int map_get_walkable(Game *game, int x, int y);
* x: The coordinates to look at. * x: The coordinates to look at.
* y: The coordinates to look at. * y: The coordinates to look at.
*/ */
Map* map_get_for_coordinates(Game *game, int x, int y ); Map *map_get_for_coordinates(Game *game, int x, int y);
#endif #endif

View file

@ -1,10 +1,9 @@
#ifndef MAPDATA_H #ifndef MAPDATA_H
#define MAPDATA_H #define MAPDATA_H
#include <stdint.h>
#include "game.h" #include "game.h"
#include <stdint.h>
extern Map *worldRPG[]; extern Map *worldRPG[];
#endif #endif

View file

@ -2,11 +2,10 @@
bool memory_is_in(short int *array, short int array_length, short int item) { bool memory_is_in(short int *array, short int array_length, short int item) {
short int i; short int i;
for(i=0;i<array_length;i++){ for(i = 0; i < array_length; i++) {
if(array[i] == item){ if(array[i] == item) {
return true; return true;
} }
} }
return false; return false;
} }

View file

@ -12,4 +12,3 @@
bool memory_is_in(short int *array, short int array_length, short int item); bool memory_is_in(short int *array, short int array_length, short int item);
#endif #endif

398
src/npc.c
View file

@ -1,32 +1,26 @@
#include "npc.h" #include "npc.h"
#include "config.h"
#include "dialogs.h" #include "dialogs.h"
#include "game.h" #include "game.h"
#include "map.h" #include "map.h"
#include "config.h"
#include <gint/display.h> #include <gint/display.h>
#include <gint/keyboard.h> /*debug*/ #include <gint/keyboard.h> /*debug*/
#include <math.h>
#include <stdint.h> #include <stdint.h>
#include <stdlib.h> #include <stdlib.h>
#include <math.h>
extern bopti_image_t tiny_npc_male; extern bopti_image_t tiny_npc_male;
extern bopti_image_t tiny_npc_female; extern bopti_image_t tiny_npc_female;
extern bopti_image_t tiny_npc_milkman; extern bopti_image_t tiny_npc_milkman;
extern bopti_image_t tiny_npc_police; extern bopti_image_t tiny_npc_police;
NPC *npcRPG; NPC *npcRPG;
uint32_t nbNPC = 0; uint32_t nbNPC = 0;
float length( float x, float y ) float length(float x, float y) { return sqrtf(x * x + y * y); }
{
return sqrtf( x*x+y*y );
}
int npc_clear_path(NPC *npc) int npc_clear_path(NPC *npc) {
{
npc->currentPoint = 0; npc->currentPoint = 0;
npc->hasPath = 0; npc->hasPath = 0;
npc->path_length = 0; npc->path_length = 0;
@ -34,47 +28,46 @@ int npc_clear_path(NPC *npc)
free(npc->ypath); free(npc->ypath);
npc->xpath = malloc(4); npc->xpath = malloc(4);
npc->ypath = malloc(4); npc->ypath = malloc(4);
if(npc->xpath == NULL || npc->ypath == NULL) return 1; if(npc->xpath == NULL || npc->ypath == NULL)
return 1;
return 0; return 0;
} }
int npc_append_path(uint16_t x, uint16_t y, NPC *npc) int npc_append_path(uint16_t x, uint16_t y, NPC *npc) {
{ npc->xpath = realloc(npc->xpath, npc->path_length * 2 + 2);
npc->xpath = realloc(npc->xpath, npc->path_length*2+2); npc->ypath = realloc(npc->ypath, npc->path_length * 2 + 2);
npc->ypath = realloc(npc->ypath, npc->path_length*2+2); if(npc->xpath == NULL || npc->ypath == NULL)
if(npc->xpath == NULL || npc->ypath == NULL) return 1; return 1;
npc->path_length++; npc->path_length++;
npc->xpath[npc->path_length-1] = x - npc->x; npc->xpath[npc->path_length - 1] = x - npc->x;
npc->ypath[npc->path_length-1] = y - npc->y; npc->ypath[npc->path_length - 1] = y - npc->y;
return 0; return 0;
} }
void as_clean(uint8_t *visited, uint8_t *gscore, uint8_t *fscore) void as_clean(uint8_t *visited, uint8_t *gscore, uint8_t *fscore) {
{
free(visited); free(visited);
free(gscore); free(gscore);
free(fscore); free(fscore);
} }
int as_reconstruct_path(int16_t *came_from, int w, int h, int16_t spos, int as_reconstruct_path(int16_t *came_from, int w, int h, int16_t spos,
int16_t dest, NPC *npc) int16_t dest, NPC *npc) {
{ if(npc_clear_path(npc))
if(npc_clear_path(npc)) goto as_recons_fail; goto as_recons_fail;
int16_t next = came_from[dest]; int16_t next = came_from[dest];
unsigned int i; unsigned int i;
for(i = 0; i < 64; i++) for(i = 0; i < 64; i++) {
{ if(npc_append_path((next % w) * T_WIDTH, (next / h) * T_HEIGHT, npc)) {
if(npc_append_path((next%w)*T_WIDTH,(next/h)*T_HEIGHT, npc))
{
goto as_recons_fail; goto as_recons_fail;
} }
next = came_from[next]; next = came_from[next];
if(next == spos){ if(next == spos) {
if(npc_append_path((spos%w)*T_WIDTH,(spos/h)*T_HEIGHT, npc)) if(npc_append_path((spos % w) * T_WIDTH, (spos / h) * T_HEIGHT,
npc))
goto as_recons_fail; goto as_recons_fail;
break; break;
} }
@ -82,16 +75,15 @@ int as_reconstruct_path(int16_t *came_from, int w, int h, int16_t spos,
uint16_t tx, ty; uint16_t tx, ty;
//Flip the path because it started from the end // Flip the path because it started from the end
for(i = 0; i < npc->path_length/2; i++) for(i = 0; i < npc->path_length / 2; i++) {
{
tx = npc->xpath[i]; tx = npc->xpath[i];
ty = npc->ypath[i]; ty = npc->ypath[i];
npc->xpath[i] = npc->xpath[npc->path_length-i-1]; npc->xpath[i] = npc->xpath[npc->path_length - i - 1];
npc->ypath[i] = npc->ypath[npc->path_length-i-1]; npc->ypath[i] = npc->ypath[npc->path_length - i - 1];
npc->ypath[npc->path_length-i-1] = tx; npc->ypath[npc->path_length - i - 1] = tx;
npc->ypath[npc->path_length-i-1] = ty; npc->ypath[npc->path_length - i - 1] = ty;
} }
free(came_from); free(came_from);
@ -100,95 +92,103 @@ int as_reconstruct_path(int16_t *came_from, int w, int h, int16_t spos,
return 0; return 0;
as_recons_fail: as_recons_fail:
free(came_from); free(came_from);
return 1; return 1;
} }
//Returns non zero error code on failure // Returns non zero error code on failure
//Custom a* implemetation // Custom a* implemetation
//Unoptimized, may become an issue // Unoptimized, may become an issue
int npc_pathfind(int32_t dest_x, int32_t dest_y, Map *full_map, NPC *npc) int npc_pathfind(int32_t dest_x, int32_t dest_y, Map *full_map, NPC *npc) {
{
int32_t i, j; int32_t i, j;
int32_t w = full_map->w; int32_t w = full_map->w;
int32_t h = full_map->h; int32_t h = full_map->h;
int32_t x = floor(npc->curx)/T_WIDTH; int32_t x = floor(npc->curx) / T_WIDTH;
int32_t y = floor(npc->cury)/T_HEIGHT; int32_t y = floor(npc->cury) / T_HEIGHT;
dest_x /= T_WIDTH; dest_x /= T_WIDTH;
dest_y /= T_HEIGHT; dest_y /= T_HEIGHT;
int32_t spos = y*w+x; int32_t spos = y * w + x;
uint8_t *map = full_map->walkable; uint8_t *map = full_map->walkable;
if(dest_x < 0 || dest_x > w || dest_y < 0 || dest_x > h) return 2; if(dest_x < 0 || dest_x > w || dest_y < 0 || dest_x > h)
if(map[spos]) return 2; return 2;
if(map[dest_y*w+dest_x]) return 2; if(map[spos])
return 2;
if(map[dest_y * w + dest_x])
return 2;
npc_clear_path(npc); npc_clear_path(npc);
uint8_t *visited = malloc(w*h); uint8_t *visited = malloc(w * h);
for(i=0; i<w*h; i++) visited[i] = 1; for(i = 0; i < w * h; i++)
visited[i] = 1;
visited[spos] = 0; visited[spos] = 0;
int16_t *came_from = malloc(w*h*2); int16_t *came_from = malloc(w * h * 2);
for(i=0; i<w*h; i++) came_from[i] = -1; for(i = 0; i < w * h; i++)
came_from[i] = -1;
uint8_t *gscore = malloc(w*h*2); uint8_t *gscore = malloc(w * h * 2);
for(i=0; i<w*h; i++) gscore[i] = 255; for(i = 0; i < w * h; i++)
gscore[i] = 255;
gscore[spos] = 0; gscore[spos] = 0;
uint8_t *fscore = malloc(w*h*2); uint8_t *fscore = malloc(w * h * 2);
for(i=0; i<w*h; i++) fscore[i] = 255; for(i = 0; i < w * h; i++)
fscore[spos] = length(dest_x-x, dest_y-y); fscore[i] = 255;
fscore[spos] = length(dest_x - x, dest_y - y);
uint8_t bscore; uint8_t bscore;
int32_t bx = x; int32_t bx = x;
int32_t by = y; int32_t by = y;
for(int iter=0; iter < 64; iter++) for(int iter = 0; iter < 64; iter++) {
{
bscore = 255; bscore = 255;
//Cheapest known tile // Cheapest known tile
for(i = 0; i <= w*h; i++) for(i = 0; i <= w * h; i++) {
{ if(visited[i])
if(visited[i]) continue; continue;
if(map[i] == 1) continue; if(map[i] == 1)
if(fscore[i] > bscore) continue; continue;
bx = i%w; if(fscore[i] > bscore)
by = i/w; continue;
bx = i % w;
by = i / w;
bscore = fscore[i]; bscore = fscore[i];
} }
if(bx == dest_x && by == dest_y) if(bx == dest_x && by == dest_y) {
{
as_clean(visited, gscore, fscore); as_clean(visited, gscore, fscore);
return as_reconstruct_path(came_from, w, h, spos, return as_reconstruct_path(came_from, w, h, spos,
dest_y*w+dest_x, npc); dest_y * w + dest_x, npc);
} }
visited[by*w+bx] = 1; visited[by * w + bx] = 1;
int att_score; int att_score;
for(i = bx-1; i < bx+2; i++) for(i = bx - 1; i < bx + 2; i++) {
{ if(i > w)
if(i > w) break; break;
for(j = by-1; j < by+2; j++) for(j = by - 1; j < by + 2; j++) {
{ if(j > h)
if(j > h) break; break;
if(map[j*w+i] == 1) continue; if(map[j * w + i] == 1)
if(i == bx && j == by) continue; continue;
att_score = gscore[by*w+bx] + round(length(bx-i,by-j)); if(i == bx && j == by)
if(att_score < gscore[j*w+i]) continue;
{ att_score = gscore[by * w + bx] + round(length(bx - i, by - j));
came_from[j*w+i] = by*w+bx; if(att_score < gscore[j * w + i]) {
gscore[j*w+i] = att_score; came_from[j * w + i] = by * w + bx;
fscore[j*w+i] = att_score + round( gscore[j * w + i] = att_score;
length(dest_x-i, dest_y-j)); fscore[j * w + i] =
if(visited[j*w+i]) visited[j*w+i] = 0; att_score + round(length(dest_x - i, dest_y - j));
if(visited[j * w + i])
visited[j * w + i] = 0;
} }
} }
} }
@ -200,101 +200,87 @@ int npc_pathfind(int32_t dest_x, int32_t dest_y, Map *full_map, NPC *npc)
return 3; return 3;
} }
NPC *npc_create() NPC *npc_create() {
{ // Use temp pointer to avoid breaking the whole npcRPG on failure
//Use temp pointer to avoid breaking the whole npcRPG on failure void *temp = realloc(npcRPG, (nbNPC + 1) * sizeof(NPC));
void *temp = realloc(npcRPG, (nbNPC+1)*sizeof(NPC)); if(temp == NULL)
if(temp == NULL) return NULL; return NULL;
npcRPG = temp; npcRPG = temp;
nbNPC++; nbNPC++;
NPC *npc = &npcRPG[nbNPC-1]; NPC *npc = &npcRPG[nbNPC - 1];
npc->xpath = malloc(2); npc->xpath = malloc(2);
npc->ypath = malloc(2); npc->ypath = malloc(2);
return npc; return npc;
} }
void npc_remove(NPC *npc) void npc_remove(NPC *npc) {
{ uint32_t pos = ((uint32_t)npc - (uint32_t)npcRPG) / sizeof(NPC);
uint32_t pos = ((uint32_t)npc - (uint32_t)npcRPG)/sizeof(NPC); if(pos > nbNPC - 1)
if(pos > nbNPC-1) return; return;
if(pos == nbNPC-1) if(pos == nbNPC - 1) {
{
nbNPC--; nbNPC--;
return; return;
} }
memmove(npc, &npc[1], (nbNPC-pos-1)*sizeof(NPC)); memmove(npc, &npc[1], (nbNPC - pos - 1) * sizeof(NPC));
} }
//Refactoring to make adding complexity cleaner // Refactoring to make adding complexity cleaner
void update_npcs([[maybe_unused]] Game *game) void update_npcs([[maybe_unused]] Game *game) {
{ for(uint32_t u = 0; u < nbNPC; u++) {
for( uint32_t u=0; u<nbNPC; u++ )
{
update_npc(&npcRPG[u]); update_npc(&npcRPG[u]);
} }
} }
void update_npc(NPC *npc) void update_npc(NPC *npc) {
{
/* if the NPC has no path or is paused, skip it */ /* if the NPC has no path or is paused, skip it */
if (!npc->hasPath || npc->paused==true) return; if(!npc->hasPath || npc->paused == true)
return;
float vecX = (float) (npc->xpath[ npc->currentPoint ] + float vecX = (float)(npc->xpath[npc->currentPoint] + npc->x) - npc->curx;
npc->x) - npc->curx; float vecY = (float)(npc->ypath[npc->currentPoint] + npc->y) - npc->cury;
float vecY = (float) (npc->ypath[ npc->currentPoint ] +
npc->y) - npc->cury;
float vecN = length(vecX, vecY); float vecN = length(vecX, vecY);
if (vecN>0.5f) if(vecN > 0.5f) {
{ vecX /= vecN * 2.0;
vecX /= vecN*2.0; vecY /= vecN * 2.0;
vecY /= vecN*2.0; } else {
}
else
{
npc->currentPoint++; npc->currentPoint++;
npc->currentPoint = npc->currentPoint % npc->path_length; npc->currentPoint = npc->currentPoint % npc->path_length;
} }
npc->curx += vecX; npc->curx += vecX;
npc->cury += vecY; npc->cury += vecY;
} }
void reload_npc(Game *game) void reload_npc(Game *game) {
{ if(npcRPG != NULL) {
if (npcRPG!=NULL)
{
free(npcRPG); free(npcRPG);
npcRPG = NULL; npcRPG = NULL;
} }
nbNPC = 0; nbNPC = 0;
for(uint32_t u = 0; u < game->map_level->nbextradata; u++) {
for (uint32_t u=0; u<game->map_level->nbextradata; u++)
{
ExtraData *Data = &game->map_level->extradata[u]; ExtraData *Data = &game->map_level->extradata[u];
if (strcmp(Data->type, "NPC")==0) /* the current data is a NPC */ if(strcmp(Data->type, "NPC") == 0) /* the current data is a NPC */
{ {
nbNPC++; nbNPC++;
} }
} }
npcRPG = (NPC*) malloc( nbNPC * sizeof(NPC) ); npcRPG = (NPC *)malloc(nbNPC * sizeof(NPC));
if(npcRPG == NULL) return; if(npcRPG == NULL)
int currentNPC=0; return;
int currentNPC = 0;
for (uint32_t u=0; u<game->map_level->nbextradata; u++) for(uint32_t u = 0; u < game->map_level->nbextradata; u++) {
{
ExtraData *Data = &game->map_level->extradata[u]; ExtraData *Data = &game->map_level->extradata[u];
if (strcmp(Data->type, "NPC")==0) /* the current data is a NPC */ if(strcmp(Data->type, "NPC") == 0) /* the current data is a NPC */
{ {
npcRPG[currentNPC].curx = (float) Data->x; npcRPG[currentNPC].curx = (float)Data->x;
npcRPG[currentNPC].cury = (float) Data->y; npcRPG[currentNPC].cury = (float)Data->y;
npcRPG[currentNPC].x = Data->x; npcRPG[currentNPC].x = Data->x;
npcRPG[currentNPC].y = Data->y; npcRPG[currentNPC].y = Data->y;
npcRPG[currentNPC].dialogID = Data->dialogID; npcRPG[currentNPC].dialogID = Data->dialogID;
@ -313,107 +299,107 @@ void reload_npc(Game *game)
void npc_draw(Game *game) { void npc_draw(Game *game) {
Player *pl = &game->player; Player *pl = &game->player;
size_t i; size_t i;
const Face npc_sprites[FACES] = { const Face npc_sprites[FACES] = {{"MALE", &tiny_npc_male},
{"MALE", &tiny_npc_male}, {"FEMALE", &tiny_npc_female},
{"FEMALE", &tiny_npc_female}, {"MILKMAN", &tiny_npc_milkman},
{"MILKMAN", &tiny_npc_milkman}, {"POLICE", &tiny_npc_police}};
{"POLICE", &tiny_npc_police}
};
for (uint32_t u=0; u<nbNPC; u++) for(uint32_t u = 0; u < nbNPC; u++) {
{
NPC *Data = &npcRPG[u]; NPC *Data = &npcRPG[u];
/* Render the path if in debug*/ /* Render the path if in debug*/
#if DEBUGMODE #if DEBUGMODE
if (Data->hasPath==1) /* this NPC has a trajectory */ if(Data->hasPath == 1) /* this NPC has a trajectory */
{ {
int NbPoints = Data->path_length+1; int NbPoints = Data->path_length + 1;
for(int v=0; v<NbPoints; v++) for(int v = 0; v < NbPoints; v++) {
{
int16_t deltaX1=((int16_t) (Data->x + int16_t deltaX1 =
Data->xpath[v % NbPoints]) * PXSIZE) ((int16_t)(Data->x + Data->xpath[v % NbPoints]) * PXSIZE) -
-(int16_t) pl->wx; (int16_t)pl->wx;
int16_t deltaY1=((int16_t) (Data->y + int16_t deltaY1 =
Data->ypath[v % NbPoints]) * PXSIZE) ((int16_t)(Data->y + Data->ypath[v % NbPoints]) * PXSIZE) -
-(int16_t) pl->wy; (int16_t)pl->wy;
int16_t deltaX2=((int16_t) (Data->x + int16_t deltaX2 =
Data->xpath[(v+1) % NbPoints]) * PXSIZE) ((int16_t)(Data->x + Data->xpath[(v + 1) % NbPoints]) *
-(int16_t) pl->wx; PXSIZE) -
int16_t deltaY2=((int16_t) (Data->y + (int16_t)pl->wx;
Data->ypath[(v+1) % NbPoints]) * PXSIZE) int16_t deltaY2 =
-(int16_t) pl->wy; ((int16_t)(Data->y + Data->ypath[(v + 1) % NbPoints]) *
PXSIZE) -
(int16_t)pl->wy;
dline( pl->px + deltaX1, pl->py + deltaY1, dline(pl->px + deltaX1, pl->py + deltaY1, pl->px + deltaX2,
pl->px + deltaX2, pl->py + deltaY2, pl->py + deltaY2, PATH_COLOR);
PATH_COLOR);
}
} }
#endif // DEBUGMODE }
#endif // DEBUGMODE
int16_t delX=((int16_t) (Data->curx * PXSIZE))-(int16_t) pl->wx; int16_t delX = ((int16_t)(Data->curx * PXSIZE)) - (int16_t)pl->wx;
int16_t delY=((int16_t) (Data->cury * PXSIZE))-(int16_t) pl->wy; int16_t delY = ((int16_t)(Data->cury * PXSIZE)) - (int16_t)pl->wy;
bopti_image_t *face = &tiny_npc_male; bopti_image_t *face = &tiny_npc_male;
for(i=0;i<FACES;i++){ for(i = 0; i < FACES; i++) {
if(!strcmp(npc_sprites[i].name, Data->face)){ if(!strcmp(npc_sprites[i].name, Data->face)) {
face = npc_sprites[i].face; face = npc_sprites[i].face;
} }
} }
dimage( pl->px-P_WIDTH/2+delX, pl->py-P_HEIGHT/2+delY, face); dimage(pl->px - P_WIDTH / 2 + delX, pl->py - P_HEIGHT / 2 + delY, face);
} }
} }
void OLD_npc_draw(Game *game) { void OLD_npc_draw(Game *game) {
Player *player = &game->player; Player *player = &game->player;
for (uint32_t u=0; u<game->map_level->nbextradata; u++) //uint pour enlever un warning for(uint32_t u = 0; u < game->map_level->nbextradata;
u++) // uint pour enlever un warning
{ {
ExtraData *Data = &game->map_level->extradata[u]; ExtraData *Data = &game->map_level->extradata[u];
if(strcmp(Data->type, "NPC") == 0) /* the current data is a NPC */
if (strcmp(Data->type, "NPC")==0) /* the current data is a NPC */
{ {
/* TODO : This is for debugging purpose, JUste to render the path */ /* TODO : This is for debugging purpose, JUste to render the path */
/* to be followed by the NPC when this will be implemented */ /* to be followed by the NPC when this will be implemented */
#if DEBUGMODE #if DEBUGMODE
if (Data->hasPath==1) /* this NPC has a trajectory */ if(Data->hasPath == 1) /* this NPC has a trajectory */
{ {
int NbPoints = Data->path_length+1; int NbPoints = Data->path_length + 1;
for(int v=0; v<NbPoints; v++) for(int v = 0; v < NbPoints; v++) {
{
int16_t deltaX1 =
((int16_t)(Data->x + Data->xpath[v % NbPoints]) *
PXSIZE) -
(int16_t)player->wx;
int16_t deltaY1 =
((int16_t)(Data->y + Data->ypath[v % NbPoints]) *
PXSIZE) -
(int16_t)player->wy;
int16_t deltaX1=((int16_t) (Data->x + Data->xpath[v % NbPoints]) * PXSIZE)-(int16_t) player->wx; int16_t deltaX2 =
int16_t deltaY1=((int16_t) (Data->y + Data->ypath[v % NbPoints]) * PXSIZE)-(int16_t) player->wy; ((int16_t)(Data->x + Data->xpath[(v + 1) % NbPoints]) *
PXSIZE) -
(int16_t)player->wx;
int16_t deltaY2 =
((int16_t)(Data->y + Data->ypath[(v + 1) % NbPoints]) *
PXSIZE) -
(int16_t)player->wy;
int16_t deltaX2=((int16_t) (Data->x + Data->xpath[(v+1) % NbPoints]) * PXSIZE)-(int16_t) player->wx; dline(player->px + deltaX1, player->py + deltaY1,
int16_t deltaY2=((int16_t) (Data->y + Data->ypath[(v+1) % NbPoints]) * PXSIZE)-(int16_t) player->wy; player->px + deltaX2, player->py + deltaY2,
PATH_COLOR);
dline( player->px + deltaX1, player->py + deltaY1,
player->px + deltaX2, player->py + deltaY2,
PATH_COLOR);
}
} }
}
#endif // DEBUGMODE #endif // DEBUGMODE
int16_t deltaX=((int16_t) (Data->x * PXSIZE))-(int16_t) player->wx;
int16_t deltaY=((int16_t) (Data->y * PXSIZE))-(int16_t) player->wy;
dimage( player->px-P_WIDTH/2+deltaX,
player->py-P_HEIGHT/2+deltaY,
&tiny_npc_male);
int16_t deltaX =
((int16_t)(Data->x * PXSIZE)) - (int16_t)player->wx;
int16_t deltaY =
((int16_t)(Data->y * PXSIZE)) - (int16_t)player->wy;
dimage(player->px - P_WIDTH / 2 + deltaX,
player->py - P_HEIGHT / 2 + deltaY, &tiny_npc_male);
} }
} }
} }

View file

@ -1,29 +1,27 @@
#ifndef NPC_H #ifndef NPC_H
#define NPC_H #define NPC_H
#include <stdbool.h> #include <stdbool.h>
#include <stdint.h> #include <stdint.h>
#include "game.h" #include "game.h"
#include "memory.h" #include "memory.h"
enum enum {
{
NPC_NONE = 0, NPC_NONE = 0,
NPC_FRIENDLY = 1, //The player's team NPC_FRIENDLY = 1, // The player's team
NPC_HOSTILE = 2, //to the player NPC_HOSTILE = 2, // to the player
NPC_ALL = 3 NPC_ALL = 3
}; };
typedef struct typedef struct {
{
/* current coordinates of the NPC */ /* current coordinates of the NPC */
float curx, cury; float curx, cury;
/* initial coordinates of the NPC (needed to get absolute coordinates of path) */ /* initial coordinates of the NPC (needed to get absolute coordinates of
* path) */
uint32_t x; uint32_t x;
uint32_t y; uint32_t y;
/* the ID of the first element of the dialog */ /* the ID of the first element of the dialog */
@ -49,24 +47,24 @@ typedef struct
char *face; char *face;
} NPC; } NPC;
//Frees then malloc()s a new path to npc // Frees then malloc()s a new path to npc
//Useful if you want to safely edit a path // Useful if you want to safely edit a path
int npc_clear_path(NPC *npc); int npc_clear_path(NPC *npc);
//Adds point x,y to the path of npc // Adds point x,y to the path of npc
//Won't work on static NPCs, use npc_clear_path before or make them on the heap // Won't work on static NPCs, use npc_clear_path before or make them on the heap
int npc_append_path(uint16_t x, uint16_t y, NPC *npc); int npc_append_path(uint16_t x, uint16_t y, NPC *npc);
//Clears the NPCs path and creates a new one going to dest, // Clears the NPCs path and creates a new one going to dest,
//avoiding non-walkable tiles // avoiding non-walkable tiles
//Returns non-zero on failure // Returns non-zero on failure
int npc_pathfind(int32_t dest_x, int32_t dest_y, Map *full_map, NPC *npc); int npc_pathfind(int32_t dest_x, int32_t dest_y, Map *full_map, NPC *npc);
//realloc()s npcRPG to adequate size and returns a pointer to the new element // realloc()s npcRPG to adequate size and returns a pointer to the new element
//Returns NULL on failure // Returns NULL on failure
NPC *npc_create(); NPC *npc_create();
//Pops the NPC from npcRPG // Pops the NPC from npcRPG
void npc_remove(NPC *npc); void npc_remove(NPC *npc);
/* Draws the player player. This function should be called after drawing the /* Draws the player player. This function should be called after drawing the
@ -80,4 +78,3 @@ void update_npc(NPC *npc);
void reload_npc(Game *game); void reload_npc(Game *game);
#endif #endif

View file

@ -1,8 +1,8 @@
#include "player.h" #include "player.h"
#include "config.h"
#include "dialogs.h" #include "dialogs.h"
#include "game.h" #include "game.h"
#include "map.h" #include "map.h"
#include "config.h"
#include "npc.h" #include "npc.h"
#include <gint/display.h> #include <gint/display.h>
@ -15,82 +15,73 @@ extern bopti_image_t npc_police;
extern bopti_image_t SGN_Icon_img; extern bopti_image_t SGN_Icon_img;
extern bopti_image_t INFO_Icon_img; extern bopti_image_t INFO_Icon_img;
const Face faces[FACES] = { const Face faces[FACES] = {{"MALE", &npc_male},
{"MALE", &npc_male}, {"FEMALE", &npc_female},
{"FEMALE", &npc_female}, {"MILKMAN", &npc_milkman},
{"MILKMAN", &npc_milkman}, {"POLICE", &npc_police}};
{"POLICE", &npc_police}
};
const char one_px_mov[8] = { const char one_px_mov[8] = {
0, -1, /* Up */ 0, -1, /* Up */
0, 1, /* Down */ 0, 1, /* Down */
-1, 0, /* Left */ -1, 0, /* Left */
1, 0 /* Right */ 1, 0 /* Right */
}; };
/* TODO: Search for all hard tiles in the tileset. hard_tiles is a list of their /* TODO: Search for all hard tiles in the tileset. hard_tiles is a list of their
* IDs */ * IDs */
/* The speed of the player on the diffrent tiles in the walkable layer. */ /* The speed of the player on the diffrent tiles in the walkable layer. */
#define WALKABLE_TILE_MAX 4 #define WALKABLE_TILE_MAX 4
const short int walkable_speed[WALKABLE_TILE_MAX] = { const short int walkable_speed[WALKABLE_TILE_MAX] = {SPEED, 0, PXSIZE, PXSIZE};
SPEED, 0, PXSIZE, PXSIZE
};
/* How much damage the player takes on the diffrent tiles in the walkable /* How much damage the player takes on the diffrent tiles in the walkable
* layer. */ * layer. */
const char damage_taken_walkable[WALKABLE_TILE_MAX] = { const char damage_taken_walkable[WALKABLE_TILE_MAX] = {0, 0, 5, 0};
0, 0, 5, 0
};
extern bopti_image_t demo_player_img; extern bopti_image_t demo_player_img;
extern NPC *npcRPG; extern NPC *npcRPG;
extern uint32_t nbNPC; extern uint32_t nbNPC;
void player_draw(Game *game) { void player_draw(Game *game) {
Player *player = &game->player; Player *player = &game->player;
dimage(player->px-P_WIDTH/2, player->py-P_HEIGHT/2, dimage(player->px - P_WIDTH / 2, player->py - P_HEIGHT / 2,
player->is_male ? &player_male_img : &player_female_img); player->is_male ? &player_male_img : &player_female_img);
} }
void player_move(Game *game, Direction direction) { void player_move(Game *game, Direction direction) {
Player *player = &game->player; Player *player = &game->player;
/* How this player movement will modify the player x and y. */ /* How this player movement will modify the player x and y. */
char dx, dy; char dx, dy;
/* If the player will collide with a hard tile or if the will go outside of /* If the player will collide with a hard tile or if the will go outside of
* the map. */ * the map. */
if(player_collision(game, direction, P_CENTER)){ if(player_collision(game, direction, P_CENTER)) {
/* If the will collide with the center of the player. */ /* If the will collide with the center of the player. */
dx = one_px_mov[direction*2]*player->speed; dx = one_px_mov[direction * 2] * player->speed;
dy = one_px_mov[direction*2+1]*player->speed; dy = one_px_mov[direction * 2 + 1] * player->speed;
player_fix_position(game, dx, dy); player_fix_position(game, dx, dy);
} } else {
else{
if(player_collision(game, direction, P_RIGHTDOWN) || if(player_collision(game, direction, P_RIGHTDOWN) ||
player_collision(game, direction, P_LEFTUP)){ player_collision(game, direction, P_LEFTUP)) {
/* If the will collide with the edges of the player. */ /* If the will collide with the edges of the player. */
/* I fix his position so he won't be partially in the tile. */ /* I fix his position so he won't be partially in the tile. */
/* I invert dx and dy to fix the axis where he is not moving on. */ /* I invert dx and dy to fix the axis where he is not moving on. */
/* Do not replace dx==0 with !dx or dy==0 with !dy, it won't work! /* Do not replace dx==0 with !dx or dy==0 with !dy, it won't work!
*/ */
dx = one_px_mov[direction*2]*player->speed; dx = one_px_mov[direction * 2] * player->speed;
dy = one_px_mov[direction*2+1]*player->speed; dy = one_px_mov[direction * 2 + 1] * player->speed;
player_fix_position(game, dx==0, dy==0); player_fix_position(game, dx == 0, dy == 0);
} }
/* If he won't collide with the center, so I just move him normally */ /* If he won't collide with the center, so I just move him normally */
dx = one_px_mov[direction*2]*player->speed; dx = one_px_mov[direction * 2] * player->speed;
dy = one_px_mov[direction*2+1]*player->speed; dy = one_px_mov[direction * 2 + 1] * player->speed;
player->x += dx; player->x += dx;
player->y += dy; player->y += dy;
@ -103,38 +94,39 @@ void player_move(Game *game, Direction direction) {
void player_action(Game *game) { void player_action(Game *game) {
register size_t i; register size_t i;
/* already doing something (action IS NOT with an NPC) */ /* already doing something (action IS NOT with an NPC) */
if(game->player.isDoingAction) return; if(game->player.isDoingAction)
return;
if(game->player.canDoSomething && !game->player.isInteractingWithNPC){ if(game->player.canDoSomething && !game->player.isInteractingWithNPC) {
/* we can do something */ /* we can do something */
/* we indicate that the player is occupied */ /* we indicate that the player is occupied */
game->player.isDoingAction = true; game->player.isDoingAction = true;
ExtraData *currentData = &game->map_level->extradata[game->player.whichAction]; ExtraData *currentData =
&game->map_level->extradata[game->player.whichAction];
/* we use the correct image as per the class of the item */ /* we use the correct image as per the class of the item */
bopti_image_t *face; bopti_image_t *face;
/* we use the correct image as per the class of the item */ /* we use the correct image as per the class of the item */
if(strcmp("INFO", currentData->type) == 0) {
if (strcmp("INFO", currentData->type)==0){
face = &INFO_Icon_img; face = &INFO_Icon_img;
}else if (strcmp("SGN", currentData->type)==0){ } else if(strcmp("SGN", currentData->type) == 0) {
face = &SGN_Icon_img; face = &SGN_Icon_img;
}else{ } else {
/* It's a NPC */ /* It's a NPC */
/* (Mibi88) TODO: Use string hash + strcmp if the hashes match for /* (Mibi88) TODO: Use string hash + strcmp if the hashes match for
* fast string comparison. */ * fast string comparison. */
face = NULL; face = NULL;
for(i=0;i<FACES;i++){ for(i = 0; i < FACES; i++) {
Face current_face = faces[i]; Face current_face = faces[i];
if(!strcmp(current_face.name, currentData->face)){ if(!strcmp(current_face.name, currentData->face)) {
face = current_face.face; face = current_face.face;
} }
} }
if(!face) face = &npc_male; if(!face)
face = &npc_male;
} }
uint32_t dialogStart = currentData->dialogID; uint32_t dialogStart = currentData->dialogID;
@ -143,7 +135,8 @@ void player_action(Game *game) {
/* when done we release the occupied status of the player */ /* when done we release the occupied status of the player */
game->player.isDoingAction = false; game->player.isDoingAction = false;
}else if(game->player.canDoSomething && game->player.isInteractingWithNPC){ } else if(game->player.canDoSomething &&
game->player.isInteractingWithNPC) {
/* we can do something (action IS with an NPC) */ /* we can do something (action IS with an NPC) */
/* we indicate that the player is occupied */ /* we indicate that the player is occupied */
game->player.isDoingAction = true; game->player.isDoingAction = true;
@ -152,18 +145,20 @@ void player_action(Game *game) {
/* we use the correct image as per the class of the item */ /* we use the correct image as per the class of the item */
ExtraData *currentData = &game->map_level->extradata[game->player.whichAction]; ExtraData *currentData =
&game->map_level->extradata[game->player.whichAction];
bopti_image_t *face = &npc_male; bopti_image_t *face = &npc_male;
/* It's a NPC */ /* It's a NPC */
/* (Mibi88) TODO: Use string hash + strcmp if the hashes match for /* (Mibi88) TODO: Use string hash + strcmp if the hashes match for
* fast string comparison. */ * fast string comparison. */
face = NULL; face = NULL;
for(i=0;i<FACES;i++){ for(i = 0; i < FACES; i++) {
Face current_face = faces[i]; Face current_face = faces[i];
if(!strcmp(current_face.name, currentNPC->face)){ if(!strcmp(current_face.name, currentNPC->face)) {
face = current_face.face; face = current_face.face;
} }
if(!face) face = &npc_male; if(!face)
face = &npc_male;
} }
dtext(2, 64, C_BLACK, currentData->type); dtext(2, 64, C_BLACK, currentData->type);
uint32_t dialogStart = currentNPC->dialogID; uint32_t dialogStart = currentNPC->dialogID;
@ -172,7 +167,6 @@ void player_action(Game *game) {
* talking (the rest of the NPCs pursue their action) */ * talking (the rest of the NPCs pursue their action) */
currentNPC->paused = true; currentNPC->paused = true;
dialogs_initiate_sequence(game, face, dialogStart); dialogs_initiate_sequence(game, face, dialogStart);
/* when done we release the occupied status of the player */ /* when done we release the occupied status of the player */
@ -180,9 +174,6 @@ void player_action(Game *game) {
currentNPC->paused = false; currentNPC->paused = false;
} }
} }
bool player_collision(Game *game, Direction direction, bool player_collision(Game *game, Direction direction,
@ -191,32 +182,32 @@ bool player_collision(Game *game, Direction direction,
Player *player = &game->player; Player *player = &game->player;
/* Where is the tile where he will go to from his position. */ /* Where is the tile where he will go to from his position. */
char dx = one_px_mov[direction*2]; char dx = one_px_mov[direction * 2];
char dy = one_px_mov[direction*2+1]; char dy = one_px_mov[direction * 2 + 1];
if(!dx){ if(!dx) {
dx += nomov_axis_check; dx += nomov_axis_check;
}else if(!dy){ } else if(!dy) {
dy += nomov_axis_check; dy += nomov_axis_check;
} }
dx = dx*(P_WIDTH/2+1); dx = dx * (P_WIDTH / 2 + 1);
dy = dy*(P_HEIGHT/2+1); dy = dy * (P_HEIGHT / 2 + 1);
/* The tile he will go to. */ /* The tile he will go to. */
int player_tile_x = player->x+dx; int player_tile_x = player->x + dx;
int player_tile_y = player->y+dy; int player_tile_y = player->y + dy;
/* check where the player is expected to go on the next move */ /* check where the player is expected to go on the next move */
/* if outside the map, we check if there is a map on the other */ /* if outside the map, we check if there is a map on the other */
/* side of the current map*/ /* side of the current map*/
if (map_get_walkable(game, player_tile_x, player_tile_y) == MAP_OUTSIDE){ if(map_get_walkable(game, player_tile_x, player_tile_y) == MAP_OUTSIDE) {
// we compute the expected world coordinates accordingly // we compute the expected world coordinates accordingly
// while taking care of the scaling between fx and cg models (PXSIZE) // while taking care of the scaling between fx and cg models (PXSIZE)
int worldX = (player->wx+dx) / PXSIZE; int worldX = (player->wx + dx) / PXSIZE;
int worldY = (player->wy+dy) / PXSIZE; int worldY = (player->wy + dy) / PXSIZE;
Map *map = map_get_for_coordinates(game, worldX, worldY); Map *map = map_get_for_coordinates(game, worldX, worldY);
if (map!=NULL && map!=game->map_level){ if(map != NULL && map != game->map_level) {
Map *backupmap = game->map_level; Map *backupmap = game->map_level;
int backupx = player->x; int backupx = player->x;
int backupy = player->y; int backupy = player->y;
@ -228,19 +219,20 @@ bool player_collision(Game *game, Direction direction,
player->wx = worldX * PXSIZE; player->wx = worldX * PXSIZE;
player->wy = worldY * PXSIZE; player->wy = worldY * PXSIZE;
player->x = (worldX - map->xmin ) * PXSIZE; player->x = (worldX - map->xmin) * PXSIZE;
player->y = (worldY - map->ymin ) * PXSIZE; player->y = (worldY - map->ymin) * PXSIZE;
int on_walkable = map_get_walkable(game, player->x/T_WIDTH, int on_walkable = map_get_walkable(game, player->x / T_WIDTH,
player->y/T_HEIGHT); player->y / T_HEIGHT);
int speed = (on_walkable >= 0 && on_walkable < WALKABLE_TILE_MAX) ? int speed = (on_walkable >= 0 && on_walkable < WALKABLE_TILE_MAX)
walkable_speed[on_walkable] : 0; ? walkable_speed[on_walkable]
: 0;
/* if he's on a hard tile and we need to revert the changes as */ /* if he's on a hard tile and we need to revert the changes as */
/* tile on the next side of the border is not walkable */ /* tile on the next side of the border is not walkable */
if(!speed){ if(!speed) {
game->map_level = backupmap; game->map_level = backupmap;
player->x = backupx; player->x = backupx;
player->y = backupy; player->y = backupy;
@ -257,21 +249,25 @@ bool player_collision(Game *game, Direction direction,
} }
} }
/* Handle a negative position differently than a positive one. */ /* Handle a negative position differently than a positive one. */
if(player_tile_x < 0) player_tile_x = player_tile_x/T_WIDTH-1; if(player_tile_x < 0)
else player_tile_x = player_tile_x/T_WIDTH; player_tile_x = player_tile_x / T_WIDTH - 1;
else
player_tile_x = player_tile_x / T_WIDTH;
if(player_tile_y < 0) player_tile_y = player_tile_y/T_HEIGHT-1; if(player_tile_y < 0)
else player_tile_y = player_tile_y/T_HEIGHT; player_tile_y = player_tile_y / T_HEIGHT - 1;
else
player_tile_y = player_tile_y / T_HEIGHT;
int on_walkable = map_get_walkable(game, player_tile_x, player_tile_y); int on_walkable = map_get_walkable(game, player_tile_x, player_tile_y);
int speed = (on_walkable >= 0 && on_walkable < WALKABLE_TILE_MAX) ? int speed = (on_walkable >= 0 && on_walkable < WALKABLE_TILE_MAX)
walkable_speed[on_walkable] : 0; ? walkable_speed[on_walkable]
: 0;
/* if he's on a hard tile */ /* if he's on a hard tile */
if(!speed){ if(!speed) {
return true; /* He will collide with it. */ return true; /* He will collide with it. */
} }
@ -286,16 +282,17 @@ void player_fix_position(Game *game, bool fix_x, bool fix_y) {
/* I fix his poition on x or/and on y if y need to, so that he won't be over /* I fix his poition on x or/and on y if y need to, so that he won't be over
* the hard tile that he collided with. */ * the hard tile that he collided with. */
if(fix_x) player->x = player->x/T_WIDTH*T_WIDTH+P_WIDTH/2; if(fix_x)
player->x = player->x / T_WIDTH * T_WIDTH + P_WIDTH / 2;
if(fix_y) player->y = player->y/T_HEIGHT*T_HEIGHT+P_HEIGHT/2; if(fix_y)
player->y = player->y / T_HEIGHT * T_HEIGHT + P_HEIGHT / 2;
} }
void player_damage(Game *game, int amount) { void player_damage(Game *game, int amount) {
Player *player = &game->player; Player *player = &game->player;
player->life-=amount; player->life -= amount;
/* TODO: Let the player dye if life < 1. */ /* TODO: Let the player dye if life < 1. */
}; };

View file

@ -1,10 +1,10 @@
#ifndef PLAYER_H #ifndef PLAYER_H
#define PLAYER_H #define PLAYER_H
#include <stdbool.h>
#include "config.h" #include "config.h"
#include "game.h" #include "game.h"
#include "memory.h" #include "memory.h"
#include <stdbool.h>
typedef struct { typedef struct {
const char *name; const char *name;
@ -17,7 +17,6 @@ typedef struct {
/* to avoid circular references between map.h, game.h and player.h */ /* to avoid circular references between map.h, game.h and player.h */
/* only methods propotypes are now in dedicated header files */ /* only methods propotypes are now in dedicated header files */
/* player_draw() /* player_draw()
* *
* Draws the player. This function should be called after drawing the * Draws the player. This function should be called after drawing the
@ -58,7 +57,6 @@ bool player_collision(Game *game, Direction direction,
*/ */
void player_fix_position(Game *game, bool fix_x, bool fix_y); void player_fix_position(Game *game, bool fix_x, bool fix_y);
/* player_damage() /* player_damage()
* *
* Apply damage to player * Apply damage to player
@ -68,4 +66,3 @@ void player_fix_position(Game *game, bool fix_x, bool fix_y);
void player_damage(Game *game, int amount); void player_damage(Game *game, int amount);
#endif #endif