Added items, so far only health that always drops.
This commit is contained in:
parent
2d05f10a44
commit
417cb78f31
|
@ -59,6 +59,8 @@ add_executable(breakhack
|
||||||
src/linkedlist
|
src/linkedlist
|
||||||
src/hashtable
|
src/hashtable
|
||||||
src/gui
|
src/gui
|
||||||
|
src/item
|
||||||
|
src/item_builder
|
||||||
)
|
)
|
||||||
|
|
||||||
target_link_libraries(breakhack
|
target_link_libraries(breakhack
|
||||||
|
|
|
@ -35,8 +35,8 @@ hash(Hashtable *table, const char *key)
|
||||||
// TODO(Linus): This isn't very good,
|
// TODO(Linus): This isn't very good,
|
||||||
// bad distribution on similar strings
|
// bad distribution on similar strings
|
||||||
while (hashval < ULONG_MAX && i < strlen(key)) {
|
while (hashval < ULONG_MAX && i < strlen(key)) {
|
||||||
hashval = hashval << 8;
|
|
||||||
hashval += key[i++];
|
hashval += key[i++];
|
||||||
|
hashval = hashval << 8;
|
||||||
}
|
}
|
||||||
|
|
||||||
return hashval % table->size;
|
return hashval % table->size;
|
||||||
|
|
|
@ -0,0 +1,25 @@
|
||||||
|
#include "item.h"
|
||||||
|
#include "util.h"
|
||||||
|
|
||||||
|
Item *
|
||||||
|
item_create(void)
|
||||||
|
{
|
||||||
|
Item *item = ec_malloc(sizeof(Item));
|
||||||
|
item->sprite = NULL;
|
||||||
|
item->collected = false;
|
||||||
|
item->effect = NULL;
|
||||||
|
return item;
|
||||||
|
}
|
||||||
|
|
||||||
|
void item_render(Item *item, Camera *cam)
|
||||||
|
{
|
||||||
|
sprite_render(item->sprite, cam);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
item_destroy(Item *item)
|
||||||
|
{
|
||||||
|
if (item->sprite)
|
||||||
|
sprite_destroy(item->sprite);
|
||||||
|
free(item);
|
||||||
|
}
|
|
@ -0,0 +1,26 @@
|
||||||
|
#ifndef ITEM_H_
|
||||||
|
#define ITEM_H_
|
||||||
|
|
||||||
|
#include <stdbool.h>
|
||||||
|
|
||||||
|
#include "sprite.h"
|
||||||
|
#include "position.h"
|
||||||
|
#include "player.h"
|
||||||
|
#include "camera.h"
|
||||||
|
|
||||||
|
typedef struct Item_t {
|
||||||
|
Sprite *sprite;
|
||||||
|
bool collected;
|
||||||
|
void (*effect)(struct Item_t *, Player *);
|
||||||
|
} Item;
|
||||||
|
|
||||||
|
Item *
|
||||||
|
item_create(void);
|
||||||
|
|
||||||
|
void
|
||||||
|
item_render(Item*, Camera*);
|
||||||
|
|
||||||
|
void
|
||||||
|
item_destroy(Item*);
|
||||||
|
|
||||||
|
#endif // ITEM_H_
|
|
@ -0,0 +1,88 @@
|
||||||
|
#include <SDL2/SDL.h>
|
||||||
|
|
||||||
|
#include "item_builder.h"
|
||||||
|
#include "texture.h"
|
||||||
|
#include "util.h"
|
||||||
|
#include "gui.h"
|
||||||
|
|
||||||
|
static ItemBuilder *builder = NULL;
|
||||||
|
|
||||||
|
void
|
||||||
|
item_builder_init(SDL_Renderer *renderer)
|
||||||
|
{
|
||||||
|
builder = ec_malloc(sizeof(ItemBuilder));
|
||||||
|
builder->textures = ht_create(20);
|
||||||
|
builder->renderer = renderer;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
check_builder()
|
||||||
|
{
|
||||||
|
if (!builder)
|
||||||
|
fatal("item_builder_init() not run");
|
||||||
|
}
|
||||||
|
|
||||||
|
static Texture *
|
||||||
|
load_texture(const char *path)
|
||||||
|
{
|
||||||
|
Texture *t = ht_get(builder->textures, path);
|
||||||
|
if (!t) {
|
||||||
|
t = texture_create();
|
||||||
|
texture_load_from_file(t, path, builder->renderer);
|
||||||
|
t->dim = (Dimension) { 32, 32 };
|
||||||
|
}
|
||||||
|
return t;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
add_health(Item *item, Player *player)
|
||||||
|
{
|
||||||
|
int original_hp = player->stats.hp;
|
||||||
|
player->stats.hp += 2;
|
||||||
|
if (player->stats.hp > player->stats.maxhp)
|
||||||
|
player->stats.hp = player->stats.maxhp;
|
||||||
|
|
||||||
|
gui_log("You gained %d health", player->stats.hp - original_hp);
|
||||||
|
}
|
||||||
|
|
||||||
|
static Item *
|
||||||
|
create_health()
|
||||||
|
{
|
||||||
|
Texture *t;
|
||||||
|
Item *item;
|
||||||
|
|
||||||
|
item = item_create();
|
||||||
|
t = load_texture("assets/Items/Potion.png");
|
||||||
|
|
||||||
|
item->sprite = sprite_create();
|
||||||
|
sprite_set_texture(item->sprite, t, 0);
|
||||||
|
item->sprite->clip = (SDL_Rect) { 0, 0, 16, 16 };
|
||||||
|
item->effect = &add_health;
|
||||||
|
|
||||||
|
return item;
|
||||||
|
}
|
||||||
|
|
||||||
|
Item *
|
||||||
|
item_builder_build_item(ItemKey key)
|
||||||
|
{
|
||||||
|
check_builder();
|
||||||
|
|
||||||
|
Item *item = NULL;
|
||||||
|
switch (key) {
|
||||||
|
case HEALTH:
|
||||||
|
item = create_health(builder);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
fatal("in item_builder_build() : Unhandled item key %d", key);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return item;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
item_builder_close()
|
||||||
|
{
|
||||||
|
ht_destroy_custom(builder->textures, (void (*)(void*)) &texture_destroy);
|
||||||
|
free(builder);
|
||||||
|
}
|
|
@ -0,0 +1,25 @@
|
||||||
|
#ifndef ITEMBUILDER_H_
|
||||||
|
#define ITEMBUILDER_H_
|
||||||
|
|
||||||
|
#include "item.h"
|
||||||
|
#include "hashtable.h"
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
Hashtable *textures;
|
||||||
|
SDL_Renderer *renderer;
|
||||||
|
} ItemBuilder;
|
||||||
|
|
||||||
|
typedef enum {
|
||||||
|
HEALTH
|
||||||
|
} ItemKey;
|
||||||
|
|
||||||
|
void
|
||||||
|
item_builder_init(SDL_Renderer *);
|
||||||
|
|
||||||
|
Item *
|
||||||
|
item_builder_build_item(ItemKey key);
|
||||||
|
|
||||||
|
void
|
||||||
|
item_builder_close();
|
||||||
|
|
||||||
|
#endif // ITEMBUILDER_H_
|
|
@ -15,6 +15,7 @@
|
||||||
#include "gamestate.h"
|
#include "gamestate.h"
|
||||||
#include "gui.h"
|
#include "gui.h"
|
||||||
#include "util.h"
|
#include "util.h"
|
||||||
|
#include "item_builder.h"
|
||||||
|
|
||||||
static SDL_Window *gWindow = NULL;
|
static SDL_Window *gWindow = NULL;
|
||||||
static SDL_Renderer *gRenderer = NULL;
|
static SDL_Renderer *gRenderer = NULL;
|
||||||
|
@ -36,7 +37,6 @@ bool initSDL(void)
|
||||||
{
|
{
|
||||||
int imgFlags = IMG_INIT_PNG;
|
int imgFlags = IMG_INIT_PNG;
|
||||||
Dimension dim = getScreenDimensions();
|
Dimension dim = getScreenDimensions();
|
||||||
//Dimension dim = (Dimension) { 1920, 1080 };
|
|
||||||
|
|
||||||
if (dim.height > 1080) {
|
if (dim.height > 1080) {
|
||||||
info("Hi resolution screen detected (%u x %u)", dim.width, dim.height);
|
info("Hi resolution screen detected (%u x %u)", dim.width, dim.height);
|
||||||
|
@ -131,6 +131,7 @@ bool init(void)
|
||||||
gCamera.renderer = gRenderer;
|
gCamera.renderer = gRenderer;
|
||||||
gRoomMatrix = roommatrix_create();
|
gRoomMatrix = roommatrix_create();
|
||||||
gGui = gui_create();
|
gGui = gui_create();
|
||||||
|
item_builder_init(gRenderer);
|
||||||
}
|
}
|
||||||
|
|
||||||
gGameState = PLAYING;
|
gGameState = PLAYING;
|
||||||
|
@ -188,6 +189,7 @@ static void
|
||||||
run_game(void)
|
run_game(void)
|
||||||
{
|
{
|
||||||
map_clear_dead_monsters(gMap);
|
map_clear_dead_monsters(gMap);
|
||||||
|
map_clear_collected_items(gMap);
|
||||||
roommatrix_populate_from_map(gRoomMatrix, gMap);
|
roommatrix_populate_from_map(gRoomMatrix, gMap);
|
||||||
roommatrix_add_lightsource(gRoomMatrix,
|
roommatrix_add_lightsource(gRoomMatrix,
|
||||||
&gPlayer->sprite->pos);
|
&gPlayer->sprite->pos);
|
||||||
|
@ -266,6 +268,7 @@ void close(void)
|
||||||
map_destroy(gMap);
|
map_destroy(gMap);
|
||||||
roommatrix_destroy(gRoomMatrix);
|
roommatrix_destroy(gRoomMatrix);
|
||||||
gui_destroy(gGui);
|
gui_destroy(gGui);
|
||||||
|
item_builder_close();
|
||||||
SDL_DestroyRenderer(gRenderer);
|
SDL_DestroyRenderer(gRenderer);
|
||||||
SDL_DestroyWindow(gWindow);
|
SDL_DestroyWindow(gWindow);
|
||||||
gWindow = NULL;
|
gWindow = NULL;
|
||||||
|
|
62
src/map.c
62
src/map.c
|
@ -2,6 +2,9 @@
|
||||||
#include "map.h"
|
#include "map.h"
|
||||||
#include "map_lua.h"
|
#include "map_lua.h"
|
||||||
#include "util.h"
|
#include "util.h"
|
||||||
|
#include "item.h"
|
||||||
|
#include "item_builder.h"
|
||||||
|
#include "gui.h"
|
||||||
|
|
||||||
static
|
static
|
||||||
Room* create_room(void)
|
Room* create_room(void)
|
||||||
|
@ -27,6 +30,7 @@ Map* map_create()
|
||||||
map->textures = linkedlist_create();
|
map->textures = linkedlist_create();
|
||||||
map->monsterTextures = ht_create(30);
|
map->monsterTextures = ht_create(30);
|
||||||
map->monsters = linkedlist_create();
|
map->monsters = linkedlist_create();
|
||||||
|
map->items = linkedlist_create();
|
||||||
map->currentRoom = (Position) { 0, 0 };
|
map->currentRoom = (Position) { 0, 0 };
|
||||||
map->renderTimer = timer_create();
|
map->renderTimer = timer_create();
|
||||||
map->level = 1;
|
map->level = 1;
|
||||||
|
@ -102,7 +106,43 @@ map_clear_dead_monsters(Map *map)
|
||||||
else
|
else
|
||||||
last->next = current->next;
|
last->next = current->next;
|
||||||
|
|
||||||
monster_destroy(current->data);
|
// TODO(Linus): We should really move this code somewhere else, perhaps to monster.c?
|
||||||
|
// Create a health drop
|
||||||
|
Monster *monster = current->data;
|
||||||
|
Item *item = item_builder_build_item(HEALTH);
|
||||||
|
item->sprite->pos = monster->sprite->pos;
|
||||||
|
linkedlist_append(&map->items, item);
|
||||||
|
gui_log("%s dropped a health potion", monster->label);
|
||||||
|
|
||||||
|
monster_destroy(monster);
|
||||||
|
current->data = NULL;
|
||||||
|
next = current->next;
|
||||||
|
current->next = NULL;
|
||||||
|
linkedlist_destroy(¤t);
|
||||||
|
current = next;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
last = current;
|
||||||
|
current = current->next;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
map_clear_collected_items(Map *map)
|
||||||
|
{
|
||||||
|
LinkedList *last, *current, *next;
|
||||||
|
|
||||||
|
last = NULL;
|
||||||
|
current = map->items;
|
||||||
|
|
||||||
|
while (current != NULL) {
|
||||||
|
if (((Item*) current->data)->collected) {
|
||||||
|
if (last == NULL)
|
||||||
|
map->items = current->next;
|
||||||
|
else
|
||||||
|
last->next = current->next;
|
||||||
|
|
||||||
|
item_destroy(current->data);
|
||||||
current->data = NULL;
|
current->data = NULL;
|
||||||
next = current->next;
|
next = current->next;
|
||||||
current->next = NULL;
|
current->next = NULL;
|
||||||
|
@ -182,6 +222,7 @@ void map_render(Map *map, Camera *cam)
|
||||||
{
|
{
|
||||||
unsigned int i, j;
|
unsigned int i, j;
|
||||||
LinkedList *monsterItem;
|
LinkedList *monsterItem;
|
||||||
|
LinkedList *items;
|
||||||
Room *room;
|
Room *room;
|
||||||
|
|
||||||
if (!timer_started(map->renderTimer)) {
|
if (!timer_started(map->renderTimer)) {
|
||||||
|
@ -215,6 +256,13 @@ void map_render(Map *map, Camera *cam)
|
||||||
monsterItem = monsterItem->next;
|
monsterItem = monsterItem->next;
|
||||||
monster_render(monster, cam);
|
monster_render(monster, cam);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
items = map->items;
|
||||||
|
while (items != NULL) {
|
||||||
|
Item *item = items->data;
|
||||||
|
items = items->next;
|
||||||
|
item_render(item, cam);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void map_set_current_room(Map *map, Position *pos)
|
void map_set_current_room(Map *map, Position *pos)
|
||||||
|
@ -269,12 +317,16 @@ void map_destroy(Map *map)
|
||||||
map_room_destroy(map->rooms[i][j]);
|
map_room_destroy(map->rooms[i][j]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
while (map->textures != NULL) {
|
|
||||||
|
while (map->textures != NULL)
|
||||||
texture_destroy(linkedlist_pop(&map->textures));
|
texture_destroy(linkedlist_pop(&map->textures));
|
||||||
}
|
|
||||||
while (map->monsters != NULL) {
|
while (map->monsters != NULL)
|
||||||
monster_destroy(linkedlist_pop(&map->monsters));
|
monster_destroy(linkedlist_pop(&map->monsters));
|
||||||
}
|
|
||||||
|
while (map->items != NULL)
|
||||||
|
item_destroy(linkedlist_pop(&map->items));
|
||||||
|
|
||||||
ht_destroy_custom(map->monsterTextures, (void (*)(void*)) texture_destroy);
|
ht_destroy_custom(map->monsterTextures, (void (*)(void*)) texture_destroy);
|
||||||
timer_destroy(map->renderTimer);
|
timer_destroy(map->renderTimer);
|
||||||
free(map);
|
free(map);
|
||||||
|
|
|
@ -33,6 +33,7 @@ typedef struct Map_t {
|
||||||
LinkedList *textures;
|
LinkedList *textures;
|
||||||
Hashtable *monsterTextures;
|
Hashtable *monsterTextures;
|
||||||
LinkedList *monsters;
|
LinkedList *monsters;
|
||||||
|
LinkedList *items;
|
||||||
Position currentRoom;
|
Position currentRoom;
|
||||||
Timer *renderTimer;
|
Timer *renderTimer;
|
||||||
int level;
|
int level;
|
||||||
|
@ -54,6 +55,8 @@ void map_move_monsters(Map*, RoomMatrix*);
|
||||||
|
|
||||||
void map_clear_dead_monsters(Map*);
|
void map_clear_dead_monsters(Map*);
|
||||||
|
|
||||||
|
void map_clear_collected_items(Map*);
|
||||||
|
|
||||||
void map_render(Map*, Camera*);
|
void map_render(Map*, Camera*);
|
||||||
|
|
||||||
void map_set_current_room(Map*, Position*);
|
void map_set_current_room(Map*, Position*);
|
||||||
|
|
|
@ -6,6 +6,7 @@
|
||||||
#include "monster.h"
|
#include "monster.h"
|
||||||
#include "util.h"
|
#include "util.h"
|
||||||
#include "gui.h"
|
#include "gui.h"
|
||||||
|
#include "item.h"
|
||||||
|
|
||||||
#define ENGINEER_STATS { 12, 12, 5, 7, 2, 1, 1 }
|
#define ENGINEER_STATS { 12, 12, 5, 7, 2, 1, 1 }
|
||||||
#define MAGE_STATS { 12, 12, 5, 7, 2, 1, 1 }
|
#define MAGE_STATS { 12, 12, 5, 7, 2, 1, 1 }
|
||||||
|
@ -53,6 +54,12 @@ has_collided(Player *player, RoomMatrix *matrix)
|
||||||
gui_log("Ouch! There is something in the way");
|
gui_log("Ouch! There is something in the way");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (space->item != NULL) {
|
||||||
|
if (space->item->effect)
|
||||||
|
space->item->effect(space->item, player);
|
||||||
|
space->item->collected = true;
|
||||||
|
}
|
||||||
|
|
||||||
return collided;
|
return collided;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -4,6 +4,7 @@
|
||||||
#include "util.h"
|
#include "util.h"
|
||||||
#include "map.h"
|
#include "map.h"
|
||||||
#include "player.h"
|
#include "player.h"
|
||||||
|
#include "item.h"
|
||||||
|
|
||||||
RoomMatrix* roommatrix_create()
|
RoomMatrix* roommatrix_create()
|
||||||
{
|
{
|
||||||
|
@ -15,10 +16,12 @@ RoomMatrix* roommatrix_create()
|
||||||
void roommatrix_populate_from_map(RoomMatrix *rm, Map *m)
|
void roommatrix_populate_from_map(RoomMatrix *rm, Map *m)
|
||||||
{
|
{
|
||||||
int i, j;
|
int i, j;
|
||||||
Position monster_matrix_pos;
|
Position position;
|
||||||
Room *r;
|
Room *r;
|
||||||
Monster *monster;
|
Monster *monster;
|
||||||
LinkedList *monsterItem;
|
LinkedList *monsterItem;
|
||||||
|
Item *item;
|
||||||
|
LinkedList *items;
|
||||||
|
|
||||||
roommatrix_reset(rm);
|
roommatrix_reset(rm);
|
||||||
|
|
||||||
|
@ -51,14 +54,26 @@ void roommatrix_populate_from_map(RoomMatrix *rm, Map *m)
|
||||||
if (!position_in_room(&monster->sprite->pos, &m->currentRoom))
|
if (!position_in_room(&monster->sprite->pos, &m->currentRoom))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
monster_matrix_pos =
|
position =
|
||||||
position_to_matrix_coords(&monster->sprite->pos);
|
position_to_matrix_coords(&monster->sprite->pos);
|
||||||
|
|
||||||
rm->spaces[monster_matrix_pos.x][monster_matrix_pos.y]
|
rm->spaces[position.x][position.y]
|
||||||
.occupied = true;
|
.occupied = true;
|
||||||
rm->spaces[monster_matrix_pos.x][monster_matrix_pos.y]
|
rm->spaces[position.x][position.y]
|
||||||
.monster = monster;
|
.monster = monster;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
items = m->items;
|
||||||
|
while (items) {
|
||||||
|
item = items->data;
|
||||||
|
items = items->next;
|
||||||
|
|
||||||
|
if (!position_in_room(&item->sprite->pos, &m->currentRoom))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
position = position_to_matrix_coords(&item->sprite->pos);
|
||||||
|
rm->spaces[position.x][position.y].item = item;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO(Linus): These should probably be macros
|
// TODO(Linus): These should probably be macros
|
||||||
|
@ -172,6 +187,7 @@ void roommatrix_reset(RoomMatrix *m)
|
||||||
m->spaces[i][j].lightsource = false;
|
m->spaces[i][j].lightsource = false;
|
||||||
m->spaces[i][j].light = 0;
|
m->spaces[i][j].light = 0;
|
||||||
m->spaces[i][j].monster = NULL;
|
m->spaces[i][j].monster = NULL;
|
||||||
|
m->spaces[i][j].item = NULL;
|
||||||
m->spaces[i][j].player = NULL;
|
m->spaces[i][j].player = NULL;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,6 +10,7 @@ typedef struct Sprite_t Sprite;
|
||||||
typedef struct Map_t Map;
|
typedef struct Map_t Map;
|
||||||
typedef struct Monster_t Monster;
|
typedef struct Monster_t Monster;
|
||||||
typedef struct Player_t Player;
|
typedef struct Player_t Player;
|
||||||
|
typedef struct Item_t Item;
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
bool occupied;
|
bool occupied;
|
||||||
|
@ -17,6 +18,7 @@ typedef struct {
|
||||||
unsigned int light;
|
unsigned int light;
|
||||||
Monster *monster;
|
Monster *monster;
|
||||||
Player *player;
|
Player *player;
|
||||||
|
Item *item;
|
||||||
} RoomSpace;
|
} RoomSpace;
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
|
|
Loading…
Reference in New Issue