diff --git a/.vimrc b/.vimrc index e55b035..9ece217 100644 --- a/.vimrc +++ b/.vimrc @@ -3,4 +3,4 @@ nnoremap :Make clean nnoremap :Make lint test nnoremap :!./_build/breakhack -let g:syntastic_c_include_dirs = [ 'build', '/usr/include/SDL2' ] +let g:syntastic_c_include_dirs = [ '_build', '/usr/include/SDL2' ] diff --git a/CMakeLists.txt b/CMakeLists.txt index 9c9bf6b..4f88f7c 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -165,6 +165,7 @@ add_executable(breakhack src/sqlite3 src/db src/settings + src/actiontextbuilder ) # Sqlite has some warnings that I we don't need to see @@ -244,6 +245,7 @@ if (NOT DEBUG_BUILD) "maproombuilder.lua" "menumapgen.lua" "monstergen.lua" + "pitlayouts.dat" WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/data ) if (WIN32) diff --git a/src/actiontext.c b/src/actiontext.c index 424593d..6e0e927 100644 --- a/src/actiontext.c +++ b/src/actiontext.c @@ -19,54 +19,49 @@ #include #include "actiontext.h" #include "util.h" +#include "update_data.h" ActionText* -actiontext_create() +actiontext_create(Sprite *sprite) { ActionText *t = ec_malloc(sizeof(ActionText)); t->pos = (Position) { 0, 0 }; - t->texture = texture_create(); + t->sprite = sprite; t->timer = timer_create(); - t->active = false; + t->dead = false; + t->velocity = (Vector2d) { 100, -100 }; t->color = (SDL_Color) { 255, 255, 255, 255 }; return t; } void -actiontext_load_font(ActionText *t, const char *path, unsigned int size) +actiontext_update(ActionText *t, UpdateData *data) { - texture_load_font(t->texture, path, size); -} - -void -actiontext_set_text(ActionText *t, const char *text, SDL_Renderer *renderer) -{ - texture_load_from_text(t->texture, text, t->color, renderer); + t->sprite->pos.x += (int) (t->velocity.x * data->deltatime); + t->sprite->pos.y += (int) (t->velocity.y * data->deltatime); } void actiontext_render(ActionText *t, Camera *cam) { - if (!t->active) + if (t->dead) return; - if (t->active && !timer_started(t->timer)) + if (!t->dead && !timer_started(t->timer)) timer_start(t->timer); - Position cameraPos = camera_to_camera_position(cam, &t->pos); - SDL_Rect box = { cameraPos.x, cameraPos.y, t->texture->dim.width, t->texture->dim.height }; - if (timer_get_ticks(t->timer) < 300) { - texture_render(t->texture, &box, cam); + if (timer_get_ticks(t->timer) < 500) { + sprite_render(t->sprite, cam); } else { timer_stop(t->timer); - t->active = false; + t->dead = true; } } void actiontext_destroy(ActionText *t) { - texture_destroy(t->texture); + sprite_destroy(t->sprite); timer_destroy(t->timer); free(t); } diff --git a/src/actiontext.h b/src/actiontext.h index 49badf3..a2ff479 100644 --- a/src/actiontext.h +++ b/src/actiontext.h @@ -23,22 +23,24 @@ #include #include "position.h" -#include "texture.h" +#include "sprite.h" #include "timer.h" +#include "vector2d.h" + +struct UpdateData_t; typedef struct { Position pos; - Texture *texture; - bool active; + Sprite *sprite; + bool dead; Timer *timer; + Vector2d velocity; SDL_Color color; } ActionText; -ActionText* actiontext_create(void); +ActionText* actiontext_create(Sprite*); -void actiontext_load_font(ActionText*, const char *path, unsigned int size); - -void actiontext_set_text(ActionText*, const char *text, SDL_Renderer*); +void actiontext_update(ActionText*, struct UpdateData_t*); void actiontext_render(ActionText*, Camera*); diff --git a/src/actiontextbuilder.c b/src/actiontextbuilder.c new file mode 100644 index 0000000..68bb4a3 --- /dev/null +++ b/src/actiontextbuilder.c @@ -0,0 +1,77 @@ +/* + * BreakHack - A dungeone crawler RPG + * Copyright (C) 2018 Linus Probert + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include +#include "actiontextbuilder.h" +#include "util.h" +#include "linkedlist.h" + +static SDL_Renderer *gRenderer = NULL; +static LinkedList *actiontexts; + +void +actiontextbuilder_init(SDL_Renderer *renderer) +{ + gRenderer = renderer; + actiontexts = linkedlist_create(); +} + +void +actiontextbuilder_create_text(const char *msg, SDL_Color color, Position *p) +{ + assert (gRenderer != NULL); + Sprite *sprite = sprite_create(); + sprite->pos = *p; + sprite_load_text_texture(sprite, "GUI/SDS_8x8.ttf", 0, 14); + texture_load_from_text(sprite->textures[0], msg, color, gRenderer); + sprite->dim = sprite->textures[0]->dim; + linkedlist_push(&actiontexts, actiontext_create(sprite)); +} + +void +actiontextbuilder_update(UpdateData *data) +{ + LinkedList *remaining = linkedlist_create(); + while (actiontexts) { + ActionText *text = linkedlist_pop(&actiontexts); + if (text->dead) { + actiontext_destroy(text); + } else { + actiontext_update(text, data); + linkedlist_push(&remaining, text); + } + } + actiontexts = remaining; +} + +void +actiontextbuilder_render(Camera *cam) +{ + LinkedList *actiontext = actiontexts; + while (actiontext) { + actiontext_render(actiontext->data, cam); + actiontext = actiontext->next; + } +} + +void +actiontextbuilder_close(void) +{ + while (actiontexts) + actiontext_destroy(linkedlist_pop(&actiontexts)); +} diff --git a/src/actiontextbuilder.h b/src/actiontextbuilder.h new file mode 100644 index 0000000..6c60435 --- /dev/null +++ b/src/actiontextbuilder.h @@ -0,0 +1,43 @@ +/* + * BreakHack - A dungeone crawler RPG + * Copyright (C) 2018 Linus Probert + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef ACTIONTEXTBUILDER_H_ +#define ACTIONTEXTBUILDER_H_ + +#include +#include "actiontext.h" +#include "camera.h" +#include "update_data.h" + +void +actiontextbuilder_init(SDL_Renderer*); + +void +actiontextbuilder_update(UpdateData*); + +void +actiontextbuilder_render(Camera*); + +void +actiontextbuilder_create_text(const char *msg, SDL_Color, Position*); + +void +actiontextbuilder_close(void); + +#endif // ACTIONTEXTBUILDER_H_ + diff --git a/src/main.c b/src/main.c index e29a3ce..e8d5f1e 100644 --- a/src/main.c +++ b/src/main.c @@ -47,6 +47,7 @@ #include "texturecache.h" #include "update_data.h" #include "settings.h" +#include "actiontextbuilder.h" typedef enum Turn_t { PLAYER, @@ -196,6 +197,7 @@ initGame(void) gPointer = pointer_create(gRenderer); particle_engine_init(); menuTimer = timer_create(); + actiontextbuilder_init(gRenderer); return true; } @@ -482,6 +484,9 @@ run_game(void) gui_update_player_stats(gGui, gPlayer, gMap, gRenderer); camera_update(gCamera, updateData.deltatime); particle_engine_update(deltaTime); + + actiontextbuilder_update(&updateData); + map_update(&updateData); player_update(&updateData); roommatrix_update_with_player(gRoomMatrix, gPlayer); @@ -501,6 +506,7 @@ run_game(void) SDL_RenderSetViewport(gRenderer, &gameViewport); map_render(gMap, gCamera); + actiontextbuilder_render(gCamera); particle_engine_render_game(gCamera); if (!is_player_dead()) @@ -639,6 +645,7 @@ void close(void) gui_destroy(gGui); skillbar_destroy(gSkillBar); pointer_destroy(gPointer); + actiontextbuilder_close(); item_builder_close(); particle_engine_close(); timer_destroy(menuTimer); diff --git a/src/map.c b/src/map.c index 8627fbb..e929d41 100644 --- a/src/map.c +++ b/src/map.c @@ -24,6 +24,7 @@ #include "item_builder.h" #include "gui.h" #include "particle_engine.h" +#include "update_data.h" static Room* create_room(void) @@ -230,6 +231,18 @@ void map_tile_render(Map *map, MapTile *tile, Position *pos, Camera *cam) } +void +map_update(UpdateData *data) +{ + Map *map = data->map; + LinkedList *monster = map->monsters; + while (monster) { + Monster *m = monster->data; + monster = monster->next; + monster_update(m, data); + } +} + void map_render(Map *map, Camera *cam) { unsigned int i, j; diff --git a/src/map.h b/src/map.h index b10879a..c130be4 100644 --- a/src/map.h +++ b/src/map.h @@ -32,6 +32,8 @@ #include "player.h" #include "map_room_modifiers.h" +struct UpdateData_t; + typedef struct MapTile_t { int textureIndex0; int textureIndex1; @@ -86,6 +88,9 @@ map_clear_dead_monsters(Map*, Player*); void map_clear_collected_items(Map*); +void +map_update(struct UpdateData_t*); + void map_render(Map*, Camera*); diff --git a/src/map_lua.c b/src/map_lua.c index 48811c8..29f89f3 100644 --- a/src/map_lua.c +++ b/src/map_lua.c @@ -285,10 +285,8 @@ l_add_monster(lua_State *L) const char *texture_path_1, *texture_path_2, *tmp_label; char *label; Texture *texture1, *texture2; - SDL_Renderer *renderer; Stats stats; - renderer = luaL_checksdlrenderer(L); map = luaL_checkmap(L, 1); x = (int) luaL_checkinteger(L, 2); y = (int) luaL_checkinteger(L, 3); @@ -325,7 +323,7 @@ l_add_monster(lua_State *L) lua_pop(L, 8); - monster = monster_create(renderer); + monster = monster_create(); monster->sprite->clip = (SDL_Rect) { clip_x, clip_y, 16, 16 }; monster_update_pos(monster, (Position) { x, y }); sprite_set_texture(monster->sprite, texture1, 0); diff --git a/src/monster.c b/src/monster.c index bb22388..c65ac14 100644 --- a/src/monster.c +++ b/src/monster.c @@ -30,27 +30,11 @@ #include "map.h" #include "particle_engine.h" #include "defines.h" - -static void -monster_load_texts(Monster *m, SDL_Renderer *renderer) -{ - ActionText *t = actiontext_create(); - actiontext_load_font(t, "GUI/SDS_6x6.ttf", 14); - t->color = (SDL_Color) { 255, 100, 0, 255 }; - actiontext_set_text(t, "HIT", renderer); - t->pos = m->sprite->pos; - m->hitText = t; - - t = actiontext_create(); - actiontext_load_font(t, "GUI/SDS_6x6.ttf", 14); - t->color = (SDL_Color) { 255, 255, 0, 255 }; - actiontext_set_text(t, "MISS", renderer); - t->pos = m->sprite->pos; - m->missText = t; -} +#include "update_data.h" +#include "actiontextbuilder.h" Monster* -monster_create(SDL_Renderer *renderer) +monster_create(void) { Monster *m = ec_malloc(sizeof(Monster)); m->sprite = sprite_create(); @@ -74,8 +58,6 @@ monster_create(SDL_Renderer *renderer) m->lclabel = NULL; m->steps = 0; - monster_load_texts(m, renderer); - return m; } @@ -86,8 +68,6 @@ monster_update_pos(Monster *m, Position pos) Position textPos = pos; textPos.y += 10; - m->hitText->pos = textPos; - m->missText->pos = textPos; } static bool @@ -276,23 +256,38 @@ monster_move(Monster *m, RoomMatrix *rm) m->steps = 0; return true; } + return false; } +void +monster_update(Monster *m, UpdateData *data) +{ + UNUSED(m); + UNUSED(data); +} + void monster_hit(Monster *monster, unsigned int dmg) { + static SDL_Color c_red = { 255, 0, 0, 255 }; + static SDL_Color c_yellow = { 255, 255, 0, 255 }; + if (dmg > 0) { - monster->hitText->active = true; - monster->missText->active = false; Position p = monster->sprite->pos; p.x += 8; p.y += 8; Dimension d = { 8, 8 }; particle_engine_bloodspray(p, d, dmg); + char msg[5]; + m_sprintf(msg, 5, "-%d", dmg); + actiontextbuilder_create_text(msg, + c_red, + &monster->sprite->pos); } else { - monster->missText->active = true; - monster->hitText->active = false; + actiontextbuilder_create_text("Dodged", + c_yellow, + &monster->sprite->pos); } monster->state.current = monster->state.challenge; @@ -363,10 +358,6 @@ void monster_render(Monster *m, Camera *cam) { sprite_render(m->sprite, cam); - if (m->hitText) - actiontext_render(m->hitText, cam); - if (m->missText) - actiontext_render(m->missText, cam); } void @@ -377,9 +368,5 @@ monster_destroy(Monster *m) free(m->label); if (m->lclabel) free(m->lclabel); - if (m->hitText) - actiontext_destroy(m->hitText); - if (m->missText) - actiontext_destroy(m->missText); free(m); } diff --git a/src/monster.h b/src/monster.h index a765640..310b7cb 100644 --- a/src/monster.h +++ b/src/monster.h @@ -24,6 +24,9 @@ #include "stats.h" #include "actiontext.h" #include "player.h" +#include "linkedlist.h" + +struct UpdateData_t; typedef enum { PASSIVE, AGRESSIVE, SCARED } StateType; @@ -37,14 +40,12 @@ typedef struct Monster_t { char *label; char *lclabel; Sprite *sprite; - ActionText *hitText; - ActionText *missText; Stats stats; State state; unsigned int steps; } Monster; -Monster* monster_create(SDL_Renderer*); +Monster* monster_create(void); void monster_update_pos(Monster*, Position); @@ -61,6 +62,9 @@ monster_hit(Monster*, unsigned int dmg); void monster_update_stats_for_level(Monster*, unsigned int level); +void +monster_update(Monster*, struct UpdateData_t*); + void monster_drop_loot(Monster*, Map*, Player*); diff --git a/src/player.c b/src/player.c index cd374e2..d2d6d6a 100644 --- a/src/player.c +++ b/src/player.c @@ -32,6 +32,7 @@ #include "projectile.h" #include "texturecache.h" #include "vector2d.h" +#include "actiontextbuilder.h" #define ENGINEER_STATS { 12, 12, 5, 7, 2, 2, 1 } #define MAGE_STATS { 12, 12, 5, 7, 1, 2, 1 } @@ -73,11 +74,17 @@ next_level_threshold(unsigned int current_level) static void player_gain_xp(Player *player, unsigned int xp_gain) { + static SDL_Color c_green = { 0, 255, 0, 255 }; + char msg[10]; + m_sprintf(msg, 5, "+%dxp", xp_gain); + actiontextbuilder_create_text(msg, c_green, &player->sprite->pos); + player->xp += xp_gain; if (player->xp >= next_level_threshold(player->stats.lvl)) { player_levelup(player); gui_log("You have reached level %u", player->stats.lvl); gui_event_message("You reached level %u", player->stats.lvl); + actiontextbuilder_create_text("Level up", c_green, &player->sprite->pos); } } @@ -97,8 +104,6 @@ static void player_step(Player *p) { action_spent(p); - p->missText->pos = p->sprite->pos; - p->hitText->pos = p->sprite->pos; } static bool @@ -335,24 +340,6 @@ handle_player_input(Player *player, RoomMatrix *matrix, SDL_Event *event) handle_movement_input(player, matrix, event); } -static void -player_load_texts(Player *p, SDL_Renderer *renderer) -{ - ActionText *t = actiontext_create(); - actiontext_load_font(t, "GUI/SDS_6x6.ttf", 14); - t->color = (SDL_Color) { 255, 100, 0, 255 }; - actiontext_set_text(t, "HIT", renderer); - t->pos = p->sprite->pos; - p->hitText = t; - - t = actiontext_create(); - actiontext_load_font(t, "GUI/SDS_6x6.ttf", 14); - t->color = (SDL_Color) { 255, 255, 0, 255 }; - actiontext_set_text(t, "MISS", renderer); - t->pos = p->sprite->pos; - p->missText = t; -} - Player* player_create(class_t class, SDL_Renderer *renderer) { @@ -410,7 +397,6 @@ player_create(class_t class, SDL_Renderer *renderer) player->sprite->dim = GAME_DIMENSION; player->sprite->clip = (SDL_Rect) { 0, 0, 16, 16 }; player->handle_event = &handle_player_input; - player_load_texts(player, renderer); return player; } @@ -444,35 +430,42 @@ player_monster_kill_check(Player *player, Monster *monster) void player_hit(Player *p, unsigned int dmg) { + static SDL_Color c_red = { 255, 0, 0, 255 }; + static SDL_Color c_yellow = { 255, 255, 0, 255 }; + if (p->stats.hp <= 0) { dmg = 200; } if (dmg > 0) { - p->hitText->active = true; - p->missText->active = false; Position pos = p->sprite->pos; pos.x += 8; pos.y += 8; particle_engine_bloodspray(pos, (Dimension) { 8, 8 }, dmg); mixer_play_effect(PLAYER_HIT0 + get_random(2)); + char msg[5]; + m_sprintf(msg, 5, "-%d", dmg); + actiontextbuilder_create_text(msg, + c_red, + &p->sprite->pos); } else { - p->missText->active = true; - p->hitText->active = false; + actiontextbuilder_create_text("Dodged", + c_yellow, + &p->sprite->pos); } + } void player_render(Player *player, Camera *cam) { sprite_render(player->sprite, cam); - actiontext_render(player->hitText, cam); - actiontext_render(player->missText, cam); LinkedList *projectile = player->projectiles; while (projectile) { projectile_render(projectile->data, cam); projectile = projectile->next; } + } void @@ -506,11 +499,7 @@ void player_update(UpdateData *data) } } - if (!player->projectiles) - return; - LinkedList *remaining = linkedlist_create(); - while (player->projectiles) { Projectile *p = linkedlist_pop(&player->projectiles); projectile_update(p, data); @@ -531,8 +520,6 @@ player_destroy(Player *player) { if (player->sprite) sprite_destroy(player->sprite); - actiontext_destroy(player->hitText); - actiontext_destroy(player->missText); timer_destroy(player->animationTimer); diff --git a/src/player.h b/src/player.h index 0129ca0..88c58a8 100644 --- a/src/player.h +++ b/src/player.h @@ -52,8 +52,6 @@ typedef struct ExperienceData_t { typedef struct Player_t { Sprite *sprite; - ActionText *hitText; - ActionText *missText; Stats stats; unsigned int daggers; LinkedList *projectiles;