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.
This commit is contained in:
Linus Probert 2018-08-08 00:14:24 +02:00
parent 611d8ef4d6
commit 095c93e5b2
19 changed files with 346 additions and 38 deletions

View File

@ -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

99
src/artifact.c Normal file
View File

@ -0,0 +1,99 @@
/*
* BreakHack - A dungeone crawler RPG
* Copyright (C) 2018 Linus Probert <linus.probert@gmail.com>
*
* 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 <http://www.gnu.org/licenses/>.
*/
#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);
}

58
src/artifact.h Normal file
View File

@ -0,0 +1,58 @@
/*
* BreakHack - A dungeone crawler RPG
* Copyright (C) 2018 Linus Probert <linus.probert@gmail.com>
*
* 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 <http://www.gnu.org/licenses/>.
*/
#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*);

View File

@ -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) {

View File

@ -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);

View File

@ -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*);

View File

@ -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 {

View File

@ -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

View File

@ -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);
}

View File

@ -15,9 +15,7 @@
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef PLAYER_H_
#define PLAYER_H_
#pragma once
#include <SDL.h>
#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*);

View File

@ -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

View File

@ -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 *

View File

@ -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);
}
}

View File

@ -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 {

View File

@ -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++;

View File

@ -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;

View File

@ -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_

View File

@ -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)
{

View File

@ -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);