From 095c93e5b2e57c0a9eb961a558abf3f9cd98b1b8 Mon Sep 17 00:00:00 2001 From: Linus Probert Date: Wed, 8 Aug 2018 00:14:24 +0200 Subject: [PATCH] Began #2: Added artifacts and the PIERCING_DAGGERS modifier Still need to add the rest of the artifact effects but that should be simpler from this point. --- CMakeLists.txt | 1 + src/artifact.c | 99 ++++++++++++++++++++++++++++++++++++++++ src/artifact.h | 58 +++++++++++++++++++++++ src/main.c | 1 + src/map.c | 27 ++++++++++- src/map.h | 4 ++ src/map_room_modifiers.h | 2 +- src/monster.c | 6 ++- src/player.c | 54 +++++++++++++++++++--- src/player.h | 28 +++++++++--- src/projectile.c | 23 +++++++++- src/projectile.h | 10 ++-- src/roommatrix.c | 22 +++++++-- src/roommatrix.h | 3 +- src/skill.c | 7 +++ src/skill.h | 4 +- src/sprite.h | 18 +++++--- src/util.c | 14 +++++- src/util.h | 3 ++ 19 files changed, 346 insertions(+), 38 deletions(-) create mode 100644 src/artifact.c create mode 100644 src/artifact.h diff --git a/CMakeLists.txt b/CMakeLists.txt index c7fc473..ffb78e2 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -173,6 +173,7 @@ add_executable(breakhack src/actiontextbuilder src/animation src/trap + src/artifact ) # Sqlite has some warnings that I we don't need to see diff --git a/src/artifact.c b/src/artifact.c new file mode 100644 index 0000000..48ba651 --- /dev/null +++ b/src/artifact.c @@ -0,0 +1,99 @@ +/* + * 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 "artifact.h" +#include "util.h" +#include "texturecache.h" + +static void +artifact_set_effect(Artifact *a, MagicalEffect effect) +{ + a->effect = effect; + switch (effect) { + case IMPROVED_HEARING: + a->info.name = "Potion of ear juice"; + a->info.desc = "Your hearing is slightly improved"; + break; + case TRAP_AVOIDANCE: + a->info.name = "Boot with nails inside"; + a->info.desc = "You are lighter on your feet"; + break; + case PIERCING_DAGGERS: + a->info.name = "Whetstone"; + a->info.desc = "Your daggers are sharper"; + Texture *t = texturecache_add("Items/Rock.png"); + sprite_set_texture(a->sprite, t, 0); + a->sprite->clip = CLIP16(0, 0); + break; + case CHARGE_THROUGH: + a->info.name = "Greasy shield"; + a->info.desc = "You glide through obstructions"; + break; + case PUSH_BACK: + a->info.name = "Glove of strength"; + a->info.desc = "Your arm is stronger"; + break; + case DAGGER_RECOVERY: + a->info.name = "Forging hammer"; + a->info.desc = "Your daggers are more durable"; + break; + case INCREASED_STUN: + a->info.name = "Solid shield"; + a->info.desc = "Your shield is harder"; + break; + case FEAR_INDUCING: + a->info.name = "Ugly shirt"; + a->info.desc = "You look disgusting"; + break; + default: + break; + } +} + +Artifact * +artifact_create(MagicalEffect effect) +{ + Artifact *a = ec_malloc(sizeof(Artifact)); + a->sprite = sprite_create(); + a->sprite->dim = GAME_DIMENSION; + a->collected = false; + a->level = 1; + artifact_set_effect(a, effect); + return a; +} + +Artifact * +artifact_copy(Artifact *a) +{ + Artifact *new = ec_malloc(sizeof(Artifact)); + *new = *a; + return new; +} + +void +artifact_render(Artifact *a, Camera *cam) +{ + sprite_render(a->sprite, cam); +} + +void +artifact_destroy(Artifact *a) +{ + sprite_destroy(a->sprite); + free(a); +} diff --git a/src/artifact.h b/src/artifact.h new file mode 100644 index 0000000..ece86e9 --- /dev/null +++ b/src/artifact.h @@ -0,0 +1,58 @@ +/* + * 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 . + */ +#pragma once + +#include "sprite.h" +#include "camera.h" + +typedef enum MagicalEffect { + IMPROVED_HEARING, + TRAP_AVOIDANCE, + PIERCING_DAGGERS, + CHARGE_THROUGH, + PUSH_BACK, + DAGGER_RECOVERY, + INCREASED_STUN, + FEAR_INDUCING, + LAST_ARTIFACT_EFFECT // Sentinel +} MagicalEffect; + +typedef struct ArtifactInfo { + const char *name; + const char *desc; +} ArtifactInfo; + +typedef struct Artifact { + Sprite *sprite; + MagicalEffect effect; + ArtifactInfo info; + bool collected; + int level; +} Artifact; + +Artifact * +artifact_create(MagicalEffect); + +Artifact * +artifact_copy(Artifact*); + +void +artifact_render(Artifact*, Camera*); + +void +artifact_destroy(Artifact*); diff --git a/src/main.c b/src/main.c index 82f3002..bc567e8 100644 --- a/src/main.c +++ b/src/main.c @@ -494,6 +494,7 @@ run_game_update(void) map_clear_dead_monsters(gMap, gPlayer); map_clear_collected_items(gMap); + map_clear_collected_artifacts(gMap); populateUpdateData(&updateData, deltaTime); if (playerLevel != gPlayer->stats.lvl) { diff --git a/src/map.c b/src/map.c index 240de5d..21b3e1f 100644 --- a/src/map.c +++ b/src/map.c @@ -54,6 +54,7 @@ map_create(void) map->textures = linkedlist_create(); map->monsters = linkedlist_create(); map->items = linkedlist_create(); + map->artifacts = linkedlist_create(); map->currentRoom = (Position) { 0, 0 }; map->renderTimer = timer_create(); map->monsterMoveTimer = timer_create(); @@ -158,6 +159,20 @@ map_clear_collected_items(Map *map) map->items = filtered; } +void +map_clear_collected_artifacts(Map *map) +{ + LinkedList *filtered = linkedlist_create(); + while (map->artifacts) { + Artifact *a = linkedlist_pop(&map->artifacts); + if (!a->collected) + linkedlist_append(&filtered, a); + else + artifact_destroy(a); + } + map->artifacts = filtered; +} + void map_add_monster(Map *map, Monster *m) { @@ -305,9 +320,14 @@ map_render_top_layer(Map *map, Camera *cam) LinkedList *items = map->items; while (items != NULL) { - Item *item = items->data; + item_render(items->data, cam); items = items->next; - item_render(item, cam); + } + + LinkedList *artifacts = map->artifacts; + while (artifacts != NULL) { + artifact_render(artifacts->data, cam); + artifacts = artifacts->next; } } @@ -376,6 +396,9 @@ void map_destroy(Map *map) while (map->items != NULL) item_destroy(linkedlist_pop(&map->items)); + while (map->artifacts != NULL) + artifact_destroy(linkedlist_pop(&map->artifacts)); + timer_destroy(map->renderTimer); timer_destroy(map->monsterMoveTimer); free(map); diff --git a/src/map.h b/src/map.h index 2524b7c..6be60e8 100644 --- a/src/map.h +++ b/src/map.h @@ -57,6 +57,7 @@ typedef struct Map_t { LinkedList *textures; LinkedList *monsters; LinkedList *items; + LinkedList *artifacts; Position currentRoom; Timer *renderTimer; Timer *monsterMoveTimer; @@ -93,6 +94,9 @@ map_clear_dead_monsters(Map*, Player*); void map_clear_collected_items(Map*); +void +map_clear_collected_artifacts(Map*); + void map_update(UpdateData*); diff --git a/src/map_room_modifiers.h b/src/map_room_modifiers.h index 875dfb1..8f0b9b5 100644 --- a/src/map_room_modifiers.h +++ b/src/map_room_modifiers.h @@ -22,7 +22,7 @@ #include "vector2d.h" // Forward declares -typedef struct Player_t Player; +typedef struct Player Player; typedef struct RoomMatrix_t RoomMatrix; typedef enum RoomModifierType_e { diff --git a/src/monster.c b/src/monster.c index 9979f14..7ab1819 100644 --- a/src/monster.c +++ b/src/monster.c @@ -493,8 +493,8 @@ void monster_drop_loot(Monster *monster, Map *map, Player *player) { static unsigned int treasure_drop_chance = 1; - unsigned int item_drop_chance = 1; + Item *item; Item *items[3]; unsigned int item_count = 0; @@ -537,6 +537,10 @@ monster_drop_loot(Monster *monster, Map *map, Player *player) } linkedlist_append(&map->items, container); } + + Artifact *a = artifact_create(PIERCING_DAGGERS); + a->sprite->pos = monster->sprite->pos; + linkedlist_append(&map->artifacts, a); } void diff --git a/src/player.c b/src/player.c index 9fd4e63..9680573 100644 --- a/src/player.c +++ b/src/player.c @@ -165,6 +165,14 @@ has_collided(Player *player, RoomMatrix *matrix, Vector2d direction) } } + if (space->artifacts != NULL && !collided) { + LinkedList *artifacts = space->artifacts; + while (artifacts) { + player_add_artifact(player, artifacts->data); + artifacts = artifacts->next; + } + } + if (space->lethal && !collided) { mixer_play_effect(FALL0 + get_random(2) - 1); player->state = FALLING; @@ -407,9 +415,11 @@ player_create(class_t class, SDL_Renderer *renderer) build_sword_animation(player, renderer); - for (size_t i = 0; i < PLAYER_SKILL_COUNT; ++i) { - player->skills[i] = NULL; - } + memset(&player->skills, + 0, PLAYER_SKILL_COUNT * sizeof(Skill*)); + + for (size_t i = 0; i < LAST_ARTIFACT_EFFECT; ++i) + player->equipment.artifacts[i].level = 0; char asset[100]; switch (class) { @@ -571,9 +581,21 @@ void player_update(UpdateData *data) animation_update(player->swordAnimation); } +static void +player_reset(Player *player) +{ + for (size_t i = 0; i < LAST_ARTIFACT_EFFECT; ++i) + player->equipment.artifacts[i].level = 0; + + while (player->projectiles) + projectile_destroy(linkedlist_pop(&player->projectiles)); +} + void player_destroy(Player *player) { + player_reset(player); + if (player->sprite) sprite_destroy(player->sprite); @@ -586,9 +608,6 @@ player_destroy(Player *player) player->skills[i] = NULL; } - while (player->projectiles) - projectile_destroy(linkedlist_pop(&player->projectiles)); - free(player); } @@ -597,3 +616,26 @@ player_turn_over(Player *player) { return player->stat_data.steps >= player->stats.speed; } + +Uint32 +player_has_artifact(Player *p, MagicalEffect effect) +{ + return p->equipment.artifacts[effect].level; +} + +void +player_add_artifact(Player *p, Artifact *a) +{ + if (a->collected) + return; + + a->collected = true; + + ArtifactData *ad = &p->equipment.artifacts[a->effect]; + ad->name = a->info.name; + ad->desc = a->info.desc; + ad->level += a->level; + + gui_log("You pick an ancient %s", ad->name); + gui_log("%s (%u)", ad->desc, ad->level); +} diff --git a/src/player.h b/src/player.h index fe5d18a..ecb6c54 100644 --- a/src/player.h +++ b/src/player.h @@ -15,9 +15,7 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ - -#ifndef PLAYER_H_ -#define PLAYER_H_ +#pragma once #include #include "sprite.h" @@ -27,6 +25,7 @@ #include "skill.h" #include "linkedlist.h" #include "input.h" +#include "artifact.h" #define PLAYER_SKILL_COUNT 5 @@ -37,7 +36,7 @@ typedef struct Animation Animation; typedef enum PlayerClass { ENGINEER, MAGE, PALADIN, ROGUE, WARRIOR } class_t; typedef enum PlayerState { ALIVE, DEAD, FALLING } state_t; -typedef struct PlayerStatData_t { +typedef struct PlayerStatData { unsigned int total_steps; unsigned int steps; unsigned int hits; @@ -45,14 +44,24 @@ typedef struct PlayerStatData_t { unsigned int misses; } PlayerStatData; -typedef struct ExperienceData_t { +typedef struct ExperienceDatat { unsigned int previousLevel; unsigned int current; unsigned int nextLevel; unsigned int level; } ExperienceData; -typedef struct Player_t { +typedef struct ArtifactData { + const char *name; + const char *desc; + Uint32 level; +} ArtifactData; + +typedef struct PlayerEquipment { + ArtifactData artifacts[LAST_ARTIFACT_EFFECT]; +} PlayerEquipment; + +typedef struct Player { Sprite *sprite; Stats stats; unsigned int daggers; @@ -66,6 +75,7 @@ typedef struct Player_t { Skill *skills[PLAYER_SKILL_COUNT]; Timer *animationTimer; Animation *swordAnimation; + PlayerEquipment equipment; } Player; Player* @@ -104,4 +114,8 @@ player_destroy(Player*); bool player_turn_over(Player*); -#endif // PLAYER_H_ +Uint32 +player_has_artifact(Player *, MagicalEffect); + +void +player_add_artifact(Player*, Artifact*); diff --git a/src/projectile.c b/src/projectile.c index 3f43a56..271db68 100644 --- a/src/projectile.c +++ b/src/projectile.c @@ -47,6 +47,10 @@ projectile_dagger_create(void) p->sprite->clip = CLIP16(0, 0); p->sprite->dim = (Dimension) { 32, 32 }; p->sprite->rotationPoint = (SDL_Point) { 16, 16 }; + p->collisionCount = 0; + memset(&p->processedSpaces, + false, + sizeof(p->processedSpaces[0][0]) * MAP_ROOM_WIDTH * MAP_ROOM_HEIGHT); return p; } @@ -66,6 +70,8 @@ projectile_create(void) void projectile_update(Projectile *p, UpdateData *data) { + bool alive = false; + p->sprite->pos.x += (int) (p->velocity.x * data->deltatime); p->sprite->pos.y += (int) (p->velocity.y * data->deltatime); @@ -78,7 +84,16 @@ projectile_update(Projectile *p, UpdateData *data) if(p->velocity.y > 0) collisionPos.y += TILE_DIMENSION; + if (!position_in_room(&collisionPos, &data->map->currentRoom)) { + p->alive = false; + return; + } + Position roomPos = position_to_matrix_coords(&collisionPos); + if (p->processedSpaces[roomPos.x][roomPos.y]) + return; + p->processedSpaces[roomPos.x][roomPos.y] = true; + RoomSpace *space = &data->matrix->spaces[roomPos.x][roomPos.y]; if (!space->occupied) return; @@ -94,16 +109,20 @@ projectile_update(Projectile *p, UpdateData *data) gui_log("Your dagger pierced %s for %u damage", space->monster->lclabel, dmg); data->player->stat_data.hits += 1; } - if (get_random(2) >= 1) { + if (get_random(5) == 0 + || get_random(5) < player_has_artifact(data->player, DAGGER_RECOVERY)) { Item *item = item_builder_build_item(DAGGER, 1); item->sprite->pos = space->monster->sprite->pos; linkedlist_append(&data->map->items, item); } monster_hit(space->monster, dmg); player_monster_kill_check(data->player, space->monster); + + alive = player_has_artifact(data->player, PIERCING_DAGGERS) > p->collisionCount; } mixer_play_effect(SWORD_HIT); - p->alive = false; + p->alive = alive; + p->collisionCount++; } void diff --git a/src/projectile.h b/src/projectile.h index 4f3996a..f835007 100644 --- a/src/projectile.h +++ b/src/projectile.h @@ -26,18 +26,18 @@ #include "timer.h" #include "roommatrix.h" #include "update_data.h" +#include "defines.h" #define DAGGER_VELOCITY 500 -// Forward declare -struct Player_t; - -typedef struct Projectile_t { +typedef struct Projectile { Sprite *sprite; Vector2d velocity; Timer *lifetime; bool alive; - void (*onRender)(struct Projectile_t*); + Uint32 collisionCount; + bool processedSpaces[MAP_ROOM_WIDTH][MAP_ROOM_HEIGHT]; + void (*onRender)(struct Projectile*); } Projectile; Projectile * diff --git a/src/roommatrix.c b/src/roommatrix.c index dc57a6f..7f43e1b 100644 --- a/src/roommatrix.c +++ b/src/roommatrix.c @@ -46,6 +46,8 @@ roommatrix_reset(RoomMatrix *m) space->trap = NULL; while (space->items != NULL) linkedlist_pop(&space->items); + while (space->artifacts != NULL) + linkedlist_pop(&space->artifacts); } } m->roomPos = (Position) { 0, 0 }; @@ -58,7 +60,8 @@ RoomMatrix* roommatrix_create(void) RoomMatrix *m = ec_malloc(sizeof(RoomMatrix)); for (i = 0; i < MAP_ROOM_WIDTH; ++i) { for (j = 0; j < MAP_ROOM_HEIGHT; ++j) { - m->spaces[i][j].items = NULL; + m->spaces[i][j].items = linkedlist_create();; + m->spaces[i][j].artifacts = linkedlist_create();; } } roommatrix_reset(m); @@ -97,7 +100,6 @@ void roommatrix_populate_from_map(RoomMatrix *rm, Map *m) Monster *monster; LinkedList *monsterItem; Item *item; - LinkedList *items; roommatrix_reset(rm); @@ -143,7 +145,7 @@ void roommatrix_populate_from_map(RoomMatrix *rm, Map *m) .monster = monster; } - items = m->items; + LinkedList *items = m->items; while (items) { item = items->data; items = items->next; @@ -154,6 +156,18 @@ void roommatrix_populate_from_map(RoomMatrix *rm, Map *m) position = position_to_matrix_coords(&item->sprite->pos); linkedlist_push(&rm->spaces[position.x][position.y].items, item); } + + LinkedList *artifacts = m->artifacts; + while (artifacts) { + Artifact *a = artifacts->data; + artifacts = artifacts->next; + + if (!position_in_room(&a->sprite->pos, &m->currentRoom)) + continue; + + position = position_to_matrix_coords(&a->sprite->pos); + linkedlist_push(&rm->spaces[position.x][position.y].artifacts, a); + } } void @@ -259,6 +273,8 @@ void roommatrix_destroy(RoomMatrix *m) RoomSpace *space = &m->spaces[i][j]; while (space->items) linkedlist_pop(&space->items); + while (space->artifacts) + linkedlist_pop(&space->artifacts); } } diff --git a/src/roommatrix.h b/src/roommatrix.h index 14e9748..5a447b9 100644 --- a/src/roommatrix.h +++ b/src/roommatrix.h @@ -29,7 +29,7 @@ typedef struct Sprite Sprite; typedef struct Map_t Map; typedef struct Monster_t Monster; -typedef struct Player_t Player; +typedef struct Player Player; typedef struct Item_t Item; typedef struct Node LinkedList; typedef struct Trap Trap; @@ -45,6 +45,7 @@ typedef struct { Player *player; Trap *trap; LinkedList *items; + LinkedList *artifacts; } RoomSpace; typedef struct RoomMatrix_t { diff --git a/src/skill.c b/src/skill.c index d7c5517..48bf3ea 100644 --- a/src/skill.c +++ b/src/skill.c @@ -33,6 +33,7 @@ #include "linkedlist.h" #include "item.h" #include "animation.h" +#include "artifact.h" static Skill * create_default(const char *s_label, Sprite *s) @@ -298,6 +299,12 @@ skill_charge(Skill *skill, SkillData *data) items = items->next; item_collected(item, player); } + LinkedList *artifacts = space->artifacts; + while (artifacts != NULL) { + Artifact *artifact = artifacts->data; + artifacts = artifacts->next; + player_add_artifact(player, artifact); + } } space = &matrix->spaces[destination.x][destination.y]; steps++; diff --git a/src/skill.h b/src/skill.h index 6ad2644..a027cea 100644 --- a/src/skill.h +++ b/src/skill.h @@ -25,7 +25,7 @@ #include "vector2d.h" // Forward declaration -struct Player_t; +struct Player; enum SkillType { FLURRY, @@ -36,7 +36,7 @@ enum SkillType { }; typedef struct SkillData_t { - struct Player_t *player; + struct Player *player; RoomMatrix *matrix; Vector2d direction; } SkillData; diff --git a/src/sprite.h b/src/sprite.h index 38b0c56..87c393d 100644 --- a/src/sprite.h +++ b/src/sprite.h @@ -44,16 +44,22 @@ typedef struct Sprite { void (*onRender)(Sprite*); } Sprite; -Sprite* sprite_create(void); +Sprite* +sprite_create(void); -void sprite_load_texture(Sprite *, const char *path, int index, SDL_Renderer *); +void +sprite_load_texture(Sprite *, const char *path, int index, SDL_Renderer *); -void sprite_load_text_texture(Sprite *, const char *path, int index, int size, int outline); +void +sprite_load_text_texture(Sprite *, const char *path, int index, int size, int outline); -void sprite_set_texture(Sprite *, Texture *, int index); +void +sprite_set_texture(Sprite *, Texture *, int index); -void sprite_render(Sprite*, Camera*); +void +sprite_render(Sprite*, Camera*); -void sprite_destroy(Sprite *); +void +sprite_destroy(Sprite *); #endif // SPRITE_H_ diff --git a/src/util.c b/src/util.c index 846b0fa..cad19f5 100644 --- a/src/util.c +++ b/src/util.c @@ -127,8 +127,8 @@ log_print(FILE *out, printf("\n"); } -void -*ec_malloc(unsigned long size) +void * +ec_malloc(unsigned long size) { void *ptr; ptr = malloc(size); @@ -137,6 +137,16 @@ void return ptr; } +void * +ec_calloc(size_t count, unsigned long size) +{ + void *ptr; + ptr = calloc(count, size); + if (ptr == NULL) + fatal("in ec_calloc() on memory allocation"); + return ptr; +} + void timestamp(char *tstamp, size_t sz) { diff --git a/src/util.h b/src/util.h index fdaf1e1..b2b92c4 100644 --- a/src/util.h +++ b/src/util.h @@ -53,6 +53,9 @@ log_print(FILE *out, void * ec_malloc(unsigned long size); +void * +ec_calloc(size_t count, unsigned long size); + void m_strcpy(char *dest, size_t destsz, const char *src);