From 5dff9a9452173a1f573eedc290163b40cb7c7a2b Mon Sep 17 00:00:00 2001 From: Linus Probert Date: Wed, 31 Jan 2018 13:52:11 +0100 Subject: [PATCH] Added an XP bar. Need some text to go with it next --- src/gui.c | 126 ++++++++++++++++++++++++++++++++++++++++++++++----- src/gui.h | 29 ++++++++---- src/main.c | 26 ++++++++--- src/player.c | 30 ++++++++---- src/player.h | 11 +++++ src/sprite.c | 4 ++ src/sprite.h | 1 + 7 files changed, 194 insertions(+), 33 deletions(-) diff --git a/src/gui.c b/src/gui.c index fc51cf1..612cfd1 100644 --- a/src/gui.c +++ b/src/gui.c @@ -8,6 +8,7 @@ #include "util.h" #define DEFAULT_LOG { NULL, 50, 0, 200 } +#define POS_Y_XPBAR 96 static SDL_Rect frame_top_left = { 16, 160, 16, 16 }; static SDL_Rect frame_top_right = { 48, 160, 16, 16 }; @@ -26,6 +27,19 @@ static struct LogData_t { unsigned int strlen; } log_data = DEFAULT_LOG; +static Texture* +add_texture(Gui *gui, const char *path, SDL_Renderer *renderer) +{ + Texture *t = ht_get(gui->textures, path); + if (t == NULL) { + t = texture_create(); + texture_load_from_file(t, path, renderer); + t->dim = (Dimension) { 16, 16 }; + ht_set(gui->textures, path, t); + } + return t; +} + static void gui_malloc_log(void) { @@ -39,8 +53,56 @@ gui_malloc_log(void) log_data.log[i] = NULL; } +static void +init_sprites(Gui *gui, SDL_Renderer *renderer) +{ + Texture *t; + Sprite *s; + unsigned int i; + + t = add_texture(gui, "assets/GUI/GUI0.png", renderer); + + /* + * Add XP bar decoration + */ + + // Left end + s = sprite_create(); + sprite_set_texture(s, t, 0); + s->fixed = true; + s->clip = (SDL_Rect) { 6 * 16, 0, 16, 16 }; + s->pos = (Position) { 16 , POS_Y_XPBAR }; + linkedlist_append(&gui->sprites, s); + + // Right end + s = sprite_create(); + sprite_set_texture(s, t, 0); + s->fixed = true; + s->clip = (SDL_Rect) { 8 * 16, 0, 16, 16 }; + s->pos = (Position) { 16 + (16 * 7), POS_Y_XPBAR }; + linkedlist_append(&gui->sprites, s); + + for (i = 1; i < 7; ++i) { + s = sprite_create(); + sprite_set_texture(s, t, 0); + s->fixed = true; + s->clip = (SDL_Rect) { 7 * 16, 0, 16, 16 }; + s->pos = (Position) { 16 + (i * 16), POS_Y_XPBAR }; + linkedlist_append(&gui->sprites, s); + } + + for (i = 0; i < 8; ++i) { + s = sprite_create(); + sprite_set_texture(s, t, 0); + s->fixed = true; + s->clip = (SDL_Rect) { 6 * 16, 4 * 16, 16, 16 }; + s->pos = (Position) { 16 + (i * 16), POS_Y_XPBAR }; + linkedlist_append(&gui->xp_bar, s); + } +} + Gui* -gui_create() +gui_create(SDL_Renderer *renderer) { Texture *t; unsigned int i; @@ -48,6 +110,7 @@ gui_create() Gui *gui = ec_malloc(sizeof(Gui)); gui->sprites = linkedlist_create(); gui->health = linkedlist_create(); + gui->xp_bar = linkedlist_create(); gui->textures = ht_create(5); for (i = 0; i < LOG_LINES_COUNT; ++i) { @@ -58,6 +121,8 @@ gui_create() gui_malloc_log(); + init_sprites(gui, renderer); + return gui; } @@ -76,7 +141,7 @@ gui_set_max_health(Gui *gui, int max, SDL_Renderer *renderer) while (gui->health != NULL) sprite_destroy(linkedlist_pop(&gui->health)); - texture = gui_add_texture(gui, "assets/GUI/GUI0.png", renderer); + texture = add_texture(gui, "assets/GUI/GUI0.png", renderer); for (i = 0; i < max/3; ++i) { Sprite *sprite = sprite_create(); @@ -114,17 +179,48 @@ gui_set_current_health(Gui *gui, int current) } } -Texture* -gui_add_texture(Gui *gui, const char *path, SDL_Renderer *renderer) +void +gui_set_current_xp(Gui *gui, ExperienceData data) { - Texture *t = ht_get(gui->textures, path); - if (t == NULL) { - t = texture_create(); - texture_load_from_file(t, path, renderer); - t->dim = (Dimension) { 16, 16 }; - ht_set(gui->textures, path, t); + static unsigned int last_level = 0; + unsigned int xp_from_levelup, xp_required_from_last_level; + float xp_step, xp_current_step; + unsigned int full_xp_blocks, partial_xp_block; + LinkedList *xp_bars; + unsigned int i; + + xp_from_levelup = data.current - data.previousLevel; + xp_required_from_last_level = data.nextLevel - data.previousLevel; + xp_step = ((float) xp_required_from_last_level) / 32; // 4 * 8 + xp_current_step = xp_from_levelup / xp_step; + + partial_xp_block = ((unsigned int) xp_current_step) % 4; + full_xp_blocks = (unsigned int)((xp_current_step - partial_xp_block) / 4); + + xp_bars = gui->xp_bar; + i = 0; + while (xp_bars != NULL) { + Sprite *s = xp_bars->data; + s->hidden = false; + xp_bars = xp_bars->next; + + if (i < full_xp_blocks) { + s->clip.x = 6 * 16; + } else if (i == full_xp_blocks && partial_xp_block != 0) { + s->clip.x = (6 * 16) + (16 * (4 - partial_xp_block)); + } else { + s->hidden = true; + } + + ++i; } - return t; + + if (last_level != data.level) { + // TODO(Linus): Update the indicators + last_level = data.level; + } + + } static void @@ -173,6 +269,12 @@ gui_render_panel(Gui *gui, unsigned int width, unsigned int height, Camera *cam) sprite_render(s, cam); item = item->next; } + item = gui->xp_bar; + while (item != NULL) { + Sprite *s = item->data; + sprite_render(s, cam); + item = item->next; + } item = gui->sprites; while (item != NULL) { Sprite *s = item->data; @@ -262,6 +364,8 @@ gui_destroy(Gui *gui) sprite_destroy(linkedlist_pop(&gui->sprites)); while (gui->health != NULL) sprite_destroy(linkedlist_pop(&gui->health)); + while (gui->xp_bar != NULL) + sprite_destroy(linkedlist_pop(&gui->xp_bar)); ht_destroy_custom(gui->textures, (void (*)(void*)) &texture_destroy); free(gui); diff --git a/src/gui.h b/src/gui.h index 709dc54..e0214d1 100644 --- a/src/gui.h +++ b/src/gui.h @@ -8,28 +8,41 @@ #include "hashtable.h" #include "sprite.h" #include "camera.h" +#include "player.h" typedef struct { LinkedList *sprites; LinkedList *health; + LinkedList *xp_bar; Hashtable *textures; Texture *log_lines[LOG_LINES_COUNT]; } Gui; -Gui* gui_create(void); +Gui* +gui_create(SDL_Renderer *renderer); -void gui_set_max_health(Gui*, int max, SDL_Renderer*); +void +gui_set_max_health(Gui*, int max, SDL_Renderer*); -void gui_set_current_health(Gui*, int current); +void +gui_set_current_health(Gui*, int current); -Texture* gui_add_texture(Gui*, const char *path, SDL_Renderer*); +void +gui_set_current_xp(Gui*, ExperienceData); -void gui_render_panel(Gui*, unsigned int width, unsigned int height, Camera*); +void +gui_set_xp_data(Gui*, ExperienceData); -void gui_render_log(Gui*, unsigned int width, unsigned int height, Camera*); +void +gui_render_panel(Gui*, unsigned int width, unsigned int height, Camera*); -void gui_log(const char *fmt, ...); +void +gui_render_log(Gui*, unsigned int width, unsigned int height, Camera*); -void gui_destroy(Gui*); +void +gui_log(const char *fmt, ...); + +void +gui_destroy(Gui*); #endif // GUI_H_ diff --git a/src/main.c b/src/main.c index 16ef3f6..99a98c1 100644 --- a/src/main.c +++ b/src/main.c @@ -115,9 +115,7 @@ initViewports(void) static bool initGame(void) { - initViewports(); gMap = map_lua_generator_run(cLevel, gRenderer); - gPointer = pointer_create(gRenderer); return true; } @@ -129,11 +127,13 @@ bool init(void) result = result && initSDL(); result = result && initGame(); if (result) { + initViewports(); gCamera.pos = (Position) { 0, 0 }; gCamera.renderer = gRenderer; gRoomMatrix = roommatrix_create(); - gGui = gui_create(); + gGui = gui_create(gRenderer); item_builder_init(gRenderer); + gPointer = pointer_create(gRenderer); } gGameState = PLAYING; @@ -201,17 +201,31 @@ check_next_level(void) static void run_game(void) { + static unsigned int player_max_hp = 0; + static unsigned int player_current_hp = 0; + static unsigned int player_current_xp = 0; + SDL_RenderSetViewport(gRenderer, NULL); map_clear_dead_monsters(gMap); map_clear_collected_items(gMap); roommatrix_populate_from_map(gRoomMatrix, gMap); roommatrix_add_lightsource(gRoomMatrix, - &gPlayer->sprite->pos); + &gPlayer->sprite->pos); roommatrix_build_lightmap(gRoomMatrix); - gui_set_max_health(gGui, gPlayer->stats.maxhp, gRenderer); - gui_set_current_health(gGui, gPlayer->stats.hp); + if (player_max_hp != gPlayer->stats.maxhp) { + gui_set_max_health(gGui, gPlayer->stats.maxhp, gRenderer); + player_max_hp = gPlayer->stats.maxhp; + } + if (player_current_hp != gPlayer->stats.hp) { + gui_set_current_health(gGui, gPlayer->stats.hp); + player_current_hp = gPlayer->stats.hp; + } + if (player_current_xp != gPlayer->xp) { + gui_set_current_xp(gGui, player_get_xp_data(gPlayer)); + player_current_xp = gPlayer->xp; + } if (gPlayer->steps == gPlayer->stats.speed) { player_reset_steps(gPlayer); roommatrix_update_with_player(gRoomMatrix, gPlayer); diff --git a/src/player.c b/src/player.c index 7ec70af..d7902ca 100644 --- a/src/player.c +++ b/src/player.c @@ -22,6 +22,10 @@ player_levelup(Player *player) player->stats.dmg += 5; player->stats.atk += 1; player->stats.def += 1; + + // Limit health to 3 rows of hearts + if (player->stats.maxhp > 72) + player->stats.maxhp = 72; } unsigned int @@ -115,8 +119,8 @@ move_left(Player *player, RoomMatrix *matrix) player_step(player); } -static -void move_right(Player *player, RoomMatrix *matrix) +static void +move_right(Player *player, RoomMatrix *matrix) { player->sprite->clip.y = 32; player->sprite->pos.x += TILE_DIMENSION; @@ -126,8 +130,8 @@ void move_right(Player *player, RoomMatrix *matrix) player_step(player); } -static -void move_up(Player *player, RoomMatrix *matrix) +static void +move_up(Player *player, RoomMatrix *matrix) { player->sprite->clip.y = 48; player->sprite->pos.y -= TILE_DIMENSION; @@ -137,8 +141,8 @@ void move_up(Player *player, RoomMatrix *matrix) player_step(player); } -static -void move_down(Player *player, RoomMatrix *matrix) +static void +move_down(Player *player, RoomMatrix *matrix) { player->sprite->clip.y = 0; player->sprite->pos.y += TILE_DIMENSION; @@ -148,8 +152,8 @@ void move_down(Player *player, RoomMatrix *matrix) player_step(player); } -static -void handle_player_input(Player *player, RoomMatrix *matrix, SDL_Event *event) +static void +handle_player_input(Player *player, RoomMatrix *matrix, SDL_Event *event) { static unsigned int step = 1; @@ -251,6 +255,16 @@ player_create(class_t class, SDL_Renderer *renderer) return player; } +ExperienceData player_get_xp_data(Player *p) +{ + ExperienceData data; + data.previousLevel = next_level_threshold(p->stats.lvl - 1); + data.current = p->xp; + data.nextLevel = next_level_threshold(p->stats.lvl); + data.level = p->stats.lvl; + return data; +} + void player_hit(Player *p, unsigned int dmg) { diff --git a/src/player.h b/src/player.h index 625862c..a04a781 100644 --- a/src/player.h +++ b/src/player.h @@ -10,6 +10,14 @@ enum PlayerClass { ENGINEER, MAGE, PALADIN, ROGUE, WARRIOR }; typedef enum PlayerClass class_t; + +typedef struct ExperienceData_t { + unsigned int previousLevel; + unsigned int current; + unsigned int nextLevel; + unsigned int level; +} ExperienceData; + typedef struct Player_t { Sprite *sprite; ActionText *hitText; @@ -28,6 +36,9 @@ typedef struct Player_t { Player* player_create(class_t, SDL_Renderer*); +ExperienceData +player_get_xp_data(Player*); + void player_hit(Player*, unsigned int dmg); diff --git a/src/sprite.c b/src/sprite.c index de62de5..945af6c 100644 --- a/src/sprite.c +++ b/src/sprite.c @@ -14,6 +14,7 @@ Sprite* sprite_create_default(void) s->renderTimer = timer_create(); s->texture_index = 0; s->fixed = false; + s->hidden = false; return s; } @@ -55,6 +56,9 @@ sprite_set_texture(Sprite *s, Texture *t, int index) void sprite_render(Sprite *s, Camera *cam) { + if (s->hidden) + return; + if (s->textures[1]) { if (!timer_started(s->renderTimer)) timer_start(s->renderTimer); diff --git a/src/sprite.h b/src/sprite.h index 66a8ef2..3275dfa 100644 --- a/src/sprite.h +++ b/src/sprite.h @@ -17,6 +17,7 @@ typedef struct Sprite_t { Timer *renderTimer; unsigned int texture_index; bool fixed; + bool hidden; } Sprite; Sprite* sprite_create(void);