diff --git a/data/monstergen.lua b/data/monstergen.lua index fef1517..47817dd 100644 --- a/data/monstergen.lua +++ b/data/monstergen.lua @@ -46,39 +46,39 @@ local state = { local enemies = { -- PESTS - { texturePaths.pest0, texturePaths.pest1, 0, 0, "Beetle" }, - { texturePaths.pest0, texturePaths.pest1, 16, 0, "Beetle" }, - { texturePaths.pest0, texturePaths.pest1, 32, 0, "Beetle" }, - { texturePaths.pest0, texturePaths.pest1, 48, 0, "Beetle" }, - { texturePaths.pest0, texturePaths.pest1, 64, 0, "Large Grub" }, - { texturePaths.pest0, texturePaths.pest1, 80, 0, "Small Grub" }, - { texturePaths.pest0, texturePaths.pest1, 96, 0, "Slim Worm" }, - { texturePaths.pest0, texturePaths.pest1, 112, 0, "Fat Worm" }, + { texturePaths.pest0, texturePaths.pest1, 0, 0, "A Beetle" }, + { texturePaths.pest0, texturePaths.pest1, 16, 0, "A Beetle" }, + { texturePaths.pest0, texturePaths.pest1, 32, 0, "A Beetle" }, + { texturePaths.pest0, texturePaths.pest1, 48, 0, "A Beetle" }, + { texturePaths.pest0, texturePaths.pest1, 64, 0, "A Large Grub" }, + { texturePaths.pest0, texturePaths.pest1, 80, 0, "A Small Grub" }, + { texturePaths.pest0, texturePaths.pest1, 96, 0, "A Slim Worm" }, + { texturePaths.pest0, texturePaths.pest1, 112, 0, "A Fat Worm" }, --{ texturePaths.pest0, texturePaths.pest1, 0, 16, "Female Dragonfly" }, - { texturePaths.pest0, texturePaths.pest1, 16, 16, "Fly" }, - { texturePaths.pest0, texturePaths.pest1, 32, 16, "Larva" }, - { texturePaths.pest0, texturePaths.pest1, 48, 16, "Moth" }, + { texturePaths.pest0, texturePaths.pest1, 16, 16, "A Fly" }, + { texturePaths.pest0, texturePaths.pest1, 32, 16, "A Larva" }, + { texturePaths.pest0, texturePaths.pest1, 48, 16, "A Moth" }, --{ texturePaths.pest0, texturePaths.pest1, 64, 16 }, - { texturePaths.pest0, texturePaths.pest1, 80, 16, "Gnat" }, + { texturePaths.pest0, texturePaths.pest1, 80, 16, "A Gnat" }, - { texturePaths.pest0, texturePaths.pest1, 0, 32, "Small Spider" }, - { texturePaths.pest0, texturePaths.pest1, 16, 32, "Medium Spider" }, - { texturePaths.pest0, texturePaths.pest1, 32, 32, "Large Spider" }, - { texturePaths.pest0, texturePaths.pest1, 48, 32, "Small Scorpion" }, - { texturePaths.pest0, texturePaths.pest1, 64, 32, "Medium Scorpion" }, - { texturePaths.pest0, texturePaths.pest1, 80, 32, "Large Scorpion" }, + { texturePaths.pest0, texturePaths.pest1, 0, 32, "A Small Spider" }, + { texturePaths.pest0, texturePaths.pest1, 16, 32, "A Medium Spider" }, + { texturePaths.pest0, texturePaths.pest1, 32, 32, "A Large Spider" }, + { texturePaths.pest0, texturePaths.pest1, 48, 32, "A Small Scorpion" }, + { texturePaths.pest0, texturePaths.pest1, 64, 32, "A Medium Scorpion" }, + { texturePaths.pest0, texturePaths.pest1, 80, 32, "A Large Scorpion" }, - { texturePaths.pest0, texturePaths.pest1, 0, 48, "Slug" }, - { texturePaths.pest0, texturePaths.pest1, 16, 48, "Large Slug" }, + { texturePaths.pest0, texturePaths.pest1, 0, 48, "A Slug" }, + { texturePaths.pest0, texturePaths.pest1, 16, 48, "A Large Slug" }, --{ texturePaths.pest0, texturePaths.pest1, 32, 48 }, - { texturePaths.pest0, texturePaths.pest1, 48, 48, "Red Slug" }, - { texturePaths.pest0, texturePaths.pest1, 64, 48, "Large Red Slug" }, + { texturePaths.pest0, texturePaths.pest1, 48, 48, "A Red Slug" }, + { texturePaths.pest0, texturePaths.pest1, 64, 48, "A Large Red Slug" }, - { texturePaths.pest0, texturePaths.pest1, 0, 64, "Giant Brown Ant" }, - { texturePaths.pest0, texturePaths.pest1, 16, 64, "Giant Black Ant" }, - { texturePaths.pest0, texturePaths.pest1, 32, 64, "Giant Gold Ant" }, - { texturePaths.pest0, texturePaths.pest1, 48, 64, "Giant Silver Ant" }, + { texturePaths.pest0, texturePaths.pest1, 0, 64, "A Giant Brown Ant" }, + { texturePaths.pest0, texturePaths.pest1, 16, 64, "A Giant Black Ant" }, + { texturePaths.pest0, texturePaths.pest1, 32, 64, "A Giant Gold Ant" }, + { texturePaths.pest0, texturePaths.pest1, 48, 64, "A Giant Silver Ant" }, --{ texturePaths.pest0, texturePaths.pest1, 0, 80 }, --{ texturePaths.pest0, texturePaths.pest1, 16, 80 }, @@ -113,10 +113,10 @@ local enemies = { --{ texturePaths.undead0, texturePaths.undead1, 96, 16, "", state.passive, state.agressive }; --{ texturePaths.undead0, texturePaths.undead1, 112, 16, "", state.passive, state.agressive }; - { texturePaths.undead0, texturePaths.undead1, 0, 32, "Skeleton", state.passive, state.agressive }; - { texturePaths.undead0, texturePaths.undead1, 16, 32, "Umber Skeleton", state.passive, state.agressive }; - { texturePaths.undead0, texturePaths.undead1, 32, 32, "Caustic Skeleton", state.passive, state.agressive }; - { texturePaths.undead0, texturePaths.undead1, 48, 32, "Black Skeleton", state.passive, state.agressive }; + { texturePaths.undead0, texturePaths.undead1, 0, 32, "A Skeleton", state.passive, state.agressive }; + { texturePaths.undead0, texturePaths.undead1, 16, 32, "An Umber Skeleton", state.passive, state.agressive }; + { texturePaths.undead0, texturePaths.undead1, 32, 32, "A Caustic Skeleton", state.passive, state.agressive }; + { texturePaths.undead0, texturePaths.undead1, 48, 32, "A Black Skeleton", state.passive, state.agressive }; --{ texturePaths.undead0, texturePaths.undead1, 64, 32, "", state.passive, state.agressive }; --{ texturePaths.undead0, texturePaths.undead1, 80, 32, "", state.passive, state.agressive }; --{ texturePaths.undead0, texturePaths.undead1, 96, 32, "", state.passive, state.agressive }; diff --git a/src/item.c b/src/item.c index 779d312..b075ba7 100644 --- a/src/item.c +++ b/src/item.c @@ -8,6 +8,8 @@ item_create(void) Item *item = ec_malloc(sizeof(Item)); item->sprite = NULL; item->collected = false; + m_strcpy(item->label, 50, ""); + item->value = 0.0; item->effect = NULL; return item; } @@ -23,4 +25,4 @@ item_destroy(Item *item) if (item->sprite) sprite_destroy(item->sprite); free(item); -} \ No newline at end of file +} diff --git a/src/item.h b/src/item.h index f780e69..6c96f61 100644 --- a/src/item.h +++ b/src/item.h @@ -11,6 +11,8 @@ typedef struct Item_t { Sprite *sprite; bool collected; + char label[50]; + double value; void (*effect)(struct Item_t *, Player *); } Item; @@ -23,4 +25,4 @@ item_render(Item*, Camera*); void item_destroy(Item*); -#endif // ITEM_H_ \ No newline at end of file +#endif // ITEM_H_ diff --git a/src/item_builder.c b/src/item_builder.c index 08f4e3c..cc3379a 100644 --- a/src/item_builder.c +++ b/src/item_builder.c @@ -36,48 +36,118 @@ load_texture(const char *path) } static void -add_health(Item *item, Player *player) +eat_flesh(Item *item, Player *player) { - UNUSED(item); - int original_hp = player->stats.hp; - player->stats.hp += 2; + player->stats.hp += item->value; if (player->stats.hp > player->stats.maxhp) player->stats.hp = player->stats.maxhp; - gui_log("You gained %d health", player->stats.hp - original_hp); + gui_log("You eat some foul meat and gain %d health", player->stats.hp - original_hp); +} + +static void +drink_health(Item *item, Player *player) +{ + int original_hp = player->stats.hp; + player->stats.hp += item->value; + if (player->stats.hp > player->stats.maxhp) + player->stats.hp = player->stats.maxhp; + + gui_log("You drink a health potion and gain %d health", player->stats.hp - original_hp); } static Item * -create_health(void) +create_item(const char *path, SDL_Rect clip, void (*cb)(Item*, Player*)) { Texture *t; Item *item; item = item_create(); - t = load_texture("assets/Items/Potion.png"); + t = load_texture(path); item->sprite = sprite_create(); sprite_set_texture(item->sprite, t, 0); - item->sprite->clip = (SDL_Rect) { 0, 0, 16, 16 }; - item->effect = &add_health; + item->sprite->clip = clip; + item->effect = cb; return item; } +static void +pickup_gold(Item *item, Player *player) +{ + player->gold += item->value; + gui_log("You pick up %s", &item->label); +} + +static Item * +create_treasure(void) +{ + unsigned int value = rand() % TREASURE_COUNT; + double amt = (unsigned int) rand() % 40; + char label[50]; + + SDL_Rect clip = { 0, 0, 16, 16 }; + switch (value) { + case COPPER: + m_sprintf(&label[0], 50, "%d copper", amt); + amt /= 100; + break; + case SILVER: + m_sprintf(&label[0], 50, "%d silver", amt); + clip.x = 48; + amt /= 10; + break; + case GOLD: + m_sprintf(&label[0], 50, "%d gold", amt); + clip.y = 16; + break; + case PLATINUM: + m_sprintf(&label[0], 50, "%d platinum", amt); + clip.x = 48; + clip.y = 16; + amt *= 10; + break; + default: + break; + } + + if (amt > 15 && amt < 30) + clip.x += 16; + else if (amt <= 15) + clip.x += 32; + + Item *item = create_item("assets/Items/Money.png", clip, &pickup_gold); + m_strcpy(item->label, 50, label); + item->value = amt; + return item; +} + Item * item_builder_build_item(ItemKey key) { + static const char *path_flesh = "assets/Items/Flesh.png"; + static const char *path_potion = "assets/Items/Potion.png"; + check_builder(); Item *item = NULL; switch (key) { - case HEALTH: - item = create_health(); - break; - default: - fatal("in item_builder_build() : Unhandled item key %d", key); - break; + case TREASURE: + item = create_treasure(); + break; + case FLESH: + item = create_item(path_flesh, (SDL_Rect) { 0, 0, 16, 16 }, &eat_flesh); + item->value = 1; + break; + case HEALTH: + item = create_item(path_potion, (SDL_Rect) { 0, 0, 16, 16 }, &drink_health); + item->value = 1 + (rand() % 2); + break; + default: + fatal("in item_builder_build() : Unhandled item key %d", key); + break; } return item; @@ -88,4 +158,4 @@ item_builder_close(void) { ht_destroy_custom(builder->textures, (void (*)(void*)) &texture_destroy); free(builder); -} \ No newline at end of file +} diff --git a/src/item_builder.h b/src/item_builder.h index 3783268..a04f82e 100644 --- a/src/item_builder.h +++ b/src/item_builder.h @@ -10,7 +10,18 @@ typedef struct { } ItemBuilder; typedef enum { - HEALTH + COPPER, + SILVER, + GOLD, + PLATINUM, + TREASURE_COUNT +} Treasure; + +typedef enum { + TREASURE, + FLESH, + HEALTH, + ITEM_COUNT } ItemKey; void @@ -22,4 +33,4 @@ item_builder_build_item(ItemKey key); void item_builder_close(void); -#endif // ITEMBUILDER_H_ \ No newline at end of file +#endif // ITEMBUILDER_H_ diff --git a/src/map.c b/src/map.c index 0754e6b..e568d46 100644 --- a/src/map.c +++ b/src/map.c @@ -106,13 +106,12 @@ map_clear_dead_monsters(Map *map) else last->next = current->next; - // 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); + + // Loot drops + Item *item = monster_drop_loot(monster); + if (item) + linkedlist_append(&map->items, item); monster_destroy(monster); current->data = NULL; diff --git a/src/map_lua.c b/src/map_lua.c index 4f89857..9884cb6 100644 --- a/src/map_lua.c +++ b/src/map_lua.c @@ -207,8 +207,10 @@ l_add_monster(lua_State *L) monster->state.normal = nstate; monster->state.challenge = cstate; monster->state.current = nstate; - if (strlen(label)) + if (strlen(label)) { monster->label = label; + monster->lclabel = to_lower(label); + } map_add_monster(map, monster); diff --git a/src/monster.c b/src/monster.c index 20fe925..710e35d 100644 --- a/src/monster.c +++ b/src/monster.c @@ -1,11 +1,14 @@ #include #include + #include "monster.h" #include "util.h" #include "player.h" #include "monster.h" #include "random.h" #include "gui.h" +#include "item.h" +#include "item_builder.h" static void monster_load_texts(Monster *m, SDL_Renderer *renderer) @@ -36,6 +39,7 @@ monster_create(SDL_Renderer *renderer) m->state.challenge = AGRESSIVE; m->state.current = m->state.normal; m->label = NULL; + m->lclabel = NULL; monster_load_texts(m, renderer); @@ -69,9 +73,9 @@ has_collided(Monster *monster, RoomMatrix *matrix) player_hit(space->player, dmg); if (dmg > 0) - gui_log("Monster '%s' hit you for %u damage", monster->label, dmg); + gui_log("%s hit you for %u damage", monster->label, dmg); else - gui_log("Monster '%s' missed you", monster->label); + gui_log("%s missed you", monster->label); } return space->occupied; @@ -234,6 +238,23 @@ monster_hit(Monster *monster, unsigned int dmg) monster->state.current = monster->state.challenge; } +Item * +monster_drop_loot(Monster *monster) +{ + static unsigned int drop_chance = 3; + unsigned int drop; + + if ((rand() % drop_chance) != 0) + return NULL; + + drop = rand() % ITEM_COUNT; + Item *item = item_builder_build_item(drop); + item->sprite->pos = monster->sprite->pos; + gui_log("%s dropped something", monster->label); + + return item; +} + void monster_render(Monster *m, Camera *cam) { @@ -250,6 +271,8 @@ monster_destroy(Monster *m) sprite_destroy(m->sprite); if (m->label) free(m->label); + if (m->lclabel) + free(m->lclabel); if (m->hitText) actiontext_destroy(m->hitText); if (m->missText) diff --git a/src/monster.h b/src/monster.h index 9ab4391..54bdb72 100644 --- a/src/monster.h +++ b/src/monster.h @@ -16,6 +16,7 @@ typedef struct { typedef struct Monster_t { char *label; + char *lclabel; Sprite *sprite; ActionText *hitText; ActionText *missText; @@ -33,6 +34,8 @@ void monster_render(Monster*, Camera*); void monster_hit(Monster*, unsigned int dmg); +Item *monster_drop_loot(Monster*); + void monster_destroy(Monster*); #endif // MONSTER_H_ diff --git a/src/player.c b/src/player.c index 9db45e4..41cefab 100644 --- a/src/player.c +++ b/src/player.c @@ -20,7 +20,8 @@ has_collided(Player *player, RoomMatrix *matrix) bool collided = false; Position roomCoord = position_to_room_coords(&player->sprite->pos); - if (roomCoord.x != matrix->roomPos.x || roomCoord.y != matrix->roomPos.y) { + if (roomCoord.x != matrix->roomPos.x + || roomCoord.y != matrix->roomPos.y) { return collided; } @@ -39,16 +40,18 @@ has_collided(Player *player, RoomMatrix *matrix) player->misses += 1; if (hit > 0) - gui_log("You hit '%s' for %u damage", space->monster->label, hit); + gui_log("You hit %s for %u damage", + space->monster->lclabel, hit); else - gui_log("You missed '%s'", space->monster->label); + gui_log("You missed %s", space->monster->lclabel); if (space->monster->stats.hp <= 0) { // TODO(Linus): This needs some love later on. player->kills += 1; player->xp += 10; - gui_log("You killed '%s' and gained %d xp", space->monster->label, 10); + gui_log("You killed %s and gained %d xp", + space->monster->lclabel, 10); } } else if (collided) { gui_log("Ouch! There is something in the way"); @@ -177,6 +180,7 @@ player_create(class_t class, SDL_Renderer *renderer) player->hits = 0; player->kills = 0; player->misses = 0; + player->gold = 0; char asset[100]; switch (class) { @@ -244,6 +248,7 @@ player_print(Player *p) debug("--------=== <[ Player Stats ]> ===--------"); debug("HP: %d", p->stats.hp); debug("Level: %u\tXP:\t%u", p->stats.lvl, p->xp); + debug("Gold: %.2f", p->gold); debug("Hits: %u\tMisses:\t%u", p->hits, p->misses); debug("Kills: %u", p->kills); debug("Steps: %u", p->total_steps); diff --git a/src/player.h b/src/player.h index 311d3c0..cdfdd60 100644 --- a/src/player.h +++ b/src/player.h @@ -21,6 +21,7 @@ typedef struct Player_t { unsigned int hits; unsigned int kills; unsigned int misses; + double gold; void (*handle_event)(struct Player_t*, RoomMatrix*, SDL_Event*); } Player; diff --git a/src/util.c b/src/util.c index 63548f0..a133c41 100644 --- a/src/util.c +++ b/src/util.c @@ -3,6 +3,7 @@ #include #include #include +#include #include "defines.h" @@ -140,3 +141,19 @@ timestamp(char *tstamp, size_t sz) free(tm_info); #endif // _MSC_VER } + +char * +to_lower(const char *str) +{ + char *lcstr; + unsigned int i; + + lcstr = ec_malloc((strlen(str) + 1) * sizeof(char)); + + for (i = 0; i < strlen(str); ++i) { + lcstr[i] = tolower(str[i]); + } + lcstr[i] = '\0'; + + return lcstr; +} diff --git a/src/util.h b/src/util.h index 6d03a74..09674aa 100644 --- a/src/util.h +++ b/src/util.h @@ -28,4 +28,7 @@ m_sprintf(char *dest, size_t destsz, const char *format, ...); void timestamp(char *tstamp, size_t sz); +char * +to_lower(const char *str); + #endif // UTIL_H_