Adds skills, 'flurry' skill and sip_potion skill.
Removes shift-h sipping.
This commit is contained in:
parent
20cb94b529
commit
2253479532
|
@ -137,14 +137,14 @@ if (NOT WIN32)
|
|||
)
|
||||
endif (NOT WIN32)
|
||||
|
||||
if (WIN32)
|
||||
if (MSVC)
|
||||
set_target_properties(breakhack PROPERTIES LINK_FLAGS_DEBUG "/SUBSYSTEM:CONSOLE")
|
||||
set_target_properties(breakhack PROPERTIES COMPILE_DEFINITIONS_DEBUG "_CONSOLE")
|
||||
set_target_properties(breakhack PROPERTIES LINK_FLAGS_RELWITHDEBINFO "/SUBSYSTEM:CONSOLE")
|
||||
set_target_properties(breakhack PROPERTIES COMPILE_DEFINITIONS_RELWITHDEBINFO "_CONSOLE")
|
||||
set_target_properties(breakhack PROPERTIES LINK_FLAGS_RELEASE "/SUBSYSTEM:WINDOWS")
|
||||
set_target_properties(breakhack PROPERTIES LINK_FLAGS_MINSIZEREL "/SUBSYSTEM:WINDOWS")
|
||||
endif (WIN32)
|
||||
endif (MSVC)
|
||||
|
||||
# TESTS:
|
||||
IF (CHECK_FOUND AND NOT WIN32)
|
||||
|
@ -187,7 +187,6 @@ if (NOT CMAKE_BUILD_TYPE MATCHES Debug)
|
|||
)
|
||||
endif (NOT CMAKE_BUILD_TYPE MATCHES Debug)
|
||||
|
||||
SET(CMAKE_INSTALL_UCRT_LIBRARIES TRUE)
|
||||
SET(CMAKE_INSTALL_SYSTEM_RUNTIME_COMPONENT "Release")
|
||||
SET(CMAKE_INSTALL_SYSTEM_RUNTIME_DESTINATION ".")
|
||||
SET(CMAKE_INSTALL_SYSTEM_RUNTIME_LIBS
|
||||
|
|
|
@ -95,7 +95,7 @@ static Item *
|
|||
create_treasure(int current_level)
|
||||
{
|
||||
double amt;
|
||||
char label[50];
|
||||
char label[50] = "";
|
||||
unsigned int highest_treasure;
|
||||
unsigned int value;
|
||||
|
||||
|
@ -109,25 +109,25 @@ create_treasure(int current_level)
|
|||
highest_treasure = GOLD;
|
||||
}
|
||||
|
||||
value = get_random(highest_treasure);
|
||||
value = get_random(highest_treasure) - 1;
|
||||
|
||||
SDL_Rect clip = CLIP16(0, 0);
|
||||
switch (value) {
|
||||
case COPPER:
|
||||
m_sprintf(&label[0], 50, "%.0f copper", amt);
|
||||
m_sprintf(label, 50, "%.0f copper", amt);
|
||||
amt /= 100;
|
||||
break;
|
||||
case SILVER:
|
||||
m_sprintf(&label[0], 50, "%.0f silver", amt);
|
||||
m_sprintf(label, 50, "%.0f silver", amt);
|
||||
clip.x = 48;
|
||||
amt /= 10;
|
||||
break;
|
||||
case GOLD:
|
||||
m_sprintf(&label[0], 50, "%.0f gold", amt);
|
||||
m_sprintf(label, 50, "%.0f gold", amt);
|
||||
clip.y = 16;
|
||||
break;
|
||||
case PLATINUM:
|
||||
m_sprintf(&label[0], 50, "%.0f platinum", amt);
|
||||
m_sprintf(label, 50, "%.0f platinum", amt);
|
||||
clip.x = 48;
|
||||
clip.y = 16;
|
||||
amt *= 10;
|
||||
|
|
|
@ -489,7 +489,7 @@ run_game(void)
|
|||
RIGHT_GUI_HEIGHT, &gCamera);
|
||||
|
||||
SDL_RenderSetViewport(gRenderer, &skillBarViewport);
|
||||
skillbar_render(gSkillBar, &gCamera);
|
||||
skillbar_render(gSkillBar, gPlayer, &gCamera);
|
||||
|
||||
SDL_RenderSetViewport(gRenderer, &bottomGuiViewport);
|
||||
gui_render_log(gGui, BOTTOM_GUI_WIDTH,
|
||||
|
|
|
@ -94,7 +94,7 @@ particle_engine_bloodspray(Position pos, Dimension dim, unsigned int count)
|
|||
}
|
||||
|
||||
static void
|
||||
create_explosion(Position pos, Dimension dim, size_t c_count, ...)
|
||||
create_explosion(Position pos, Dimension dim, unsigned int c_count, ...)
|
||||
{
|
||||
SDL_Color *colors = ec_malloc(c_count * sizeof(SDL_Color));
|
||||
|
||||
|
|
133
src/player.c
133
src/player.c
|
@ -113,15 +113,8 @@ has_collided(Player *player, RoomMatrix *matrix)
|
|||
else
|
||||
gui_log("You missed %s", space->monster->lclabel);
|
||||
|
||||
if (space->monster->stats.hp <= 0) {
|
||||
unsigned int gained_xp = 5 * space->monster->stats.lvl;
|
||||
player->kills += 1;
|
||||
player_monster_kill_check(player, space->monster);
|
||||
|
||||
mixer_play_effect(DEATH);
|
||||
gui_log("You killed %s and gained %d xp",
|
||||
space->monster->lclabel, gained_xp);
|
||||
player_gain_xp(player, gained_xp);
|
||||
}
|
||||
} else if (collided) {
|
||||
mixer_play_effect(BONK);
|
||||
gui_log("Ouch! There is something in the way");
|
||||
|
@ -146,6 +139,11 @@ player_step(Player *p)
|
|||
p->steps++;
|
||||
p->missText->pos = p->sprite->pos;
|
||||
p->hitText->pos = p->sprite->pos;
|
||||
|
||||
for (size_t i = 0; i < PLAYER_SKILL_COUNT; ++i) {
|
||||
if (p->skills[i] != NULL && p->skills[i]->resetCountdown > 0)
|
||||
p->skills[i]->resetCountdown--;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
|
@ -192,8 +190,8 @@ move_down(Player *player, RoomMatrix *matrix)
|
|||
player_step(player);
|
||||
}
|
||||
|
||||
static void
|
||||
sip_health(Player *player)
|
||||
void
|
||||
player_sip_health(Player *player)
|
||||
{
|
||||
if (player->potion_sips > 0) {
|
||||
--player->potion_sips;
|
||||
|
@ -244,17 +242,92 @@ handle_movement_input(Player *player, RoomMatrix *matrix, SDL_Event *event)
|
|||
}
|
||||
}
|
||||
|
||||
static void
|
||||
check_skill_activation(Player *player, RoomMatrix *matrix, SDL_Event *event)
|
||||
{
|
||||
// TODO(Linus): This could be "smarter"
|
||||
unsigned int selected = 0;
|
||||
if (keyboard_press(SDLK_1, event)) {
|
||||
selected = 1;
|
||||
}
|
||||
else if (keyboard_press(SDLK_2, event)) {
|
||||
selected = 2;
|
||||
}
|
||||
else if (keyboard_press(SDLK_3, event)) {
|
||||
selected = 3;
|
||||
}
|
||||
else if (keyboard_press(SDLK_4, event)) {
|
||||
selected = 4;
|
||||
}
|
||||
else if (keyboard_press(SDLK_5, event)) {
|
||||
selected = 5;
|
||||
}
|
||||
|
||||
if (selected == 0)
|
||||
return;
|
||||
|
||||
for (size_t i = 0; i < PLAYER_SKILL_COUNT; ++i) {
|
||||
if (!player->skills[i])
|
||||
continue;
|
||||
|
||||
Skill *skill = player->skills[i];
|
||||
skill->active = (selected - 1) == i && !skill->active && skill->resetCountdown == 0;
|
||||
if (skill->active && skill->instantUse) {
|
||||
SkillData skillData = { player, matrix, VECTOR2D_NODIR };
|
||||
skill->active = false;
|
||||
skill->use(skill, &skillData);
|
||||
if (skill->actionRequired)
|
||||
player_step(player);
|
||||
skill->resetCountdown = skill->resetTime;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static bool
|
||||
check_skill_trigger(Player *player, RoomMatrix *matrix, SDL_Event *event)
|
||||
{
|
||||
int activeSkill = -1;
|
||||
for (size_t i = 0; i < PLAYER_SKILL_COUNT; ++i) {
|
||||
if (player->skills[i] && player->skills[i]->active) {
|
||||
activeSkill = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (activeSkill < 0)
|
||||
return false;
|
||||
|
||||
Vector2d dir;
|
||||
if (keyboard_direction_press(UP, event))
|
||||
dir = VECTOR2D_UP;
|
||||
else if (keyboard_direction_press(DOWN, event))
|
||||
dir = VECTOR2D_DOWN;
|
||||
else if (keyboard_direction_press(LEFT, event))
|
||||
dir = VECTOR2D_LEFT;
|
||||
else if (keyboard_direction_press(RIGHT, event))
|
||||
dir = VECTOR2D_RIGHT;
|
||||
else
|
||||
return false;
|
||||
|
||||
SkillData skillData = { player, matrix, dir };
|
||||
player->skills[activeSkill]->use(player->skills[activeSkill], &skillData);
|
||||
player->skills[activeSkill]->active = false;
|
||||
if (player->skills[activeSkill]->actionRequired)
|
||||
player_step(player);
|
||||
player->skills[activeSkill]->resetCountdown = player->skills[activeSkill]->resetTime;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static void
|
||||
handle_player_input(Player *player, RoomMatrix *matrix, SDL_Event *event)
|
||||
{
|
||||
if (event->type != SDL_KEYDOWN)
|
||||
return;
|
||||
|
||||
if (keyboard_mod_press(SDLK_h, KMOD_SHIFT, event)) {
|
||||
sip_health(player);
|
||||
} else {
|
||||
check_skill_activation(player, matrix, event);
|
||||
if (!check_skill_trigger(player, matrix, event))
|
||||
handle_movement_input(player, matrix, event);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
|
@ -282,7 +355,7 @@ player_create(class_t class, SDL_Renderer *renderer)
|
|||
player->sprite = sprite_create();
|
||||
player->total_steps = 0;
|
||||
player->steps = 0;
|
||||
player->xp = 0;
|
||||
player->xp = 0;
|
||||
player->hits = 0;
|
||||
player->kills = 0;
|
||||
player->misses = 0;
|
||||
|
@ -290,6 +363,10 @@ player_create(class_t class, SDL_Renderer *renderer)
|
|||
player->potion_sips = 0;
|
||||
player->class = class;
|
||||
|
||||
for (size_t i = 0; i < PLAYER_SKILL_COUNT; ++i) {
|
||||
player->skills[i] = NULL;
|
||||
}
|
||||
|
||||
char asset[100];
|
||||
switch (class) {
|
||||
case ENGINEER:
|
||||
|
@ -311,9 +388,12 @@ player_create(class_t class, SDL_Renderer *renderer)
|
|||
case WARRIOR:
|
||||
m_strcpy(asset, 100, "Commissions/Warrior.png");
|
||||
player->stats = (Stats) WARRIOR_STATS;
|
||||
player->skills[0] = skill_create(FLURRY);
|
||||
break;
|
||||
}
|
||||
|
||||
player->skills[4] = skill_create(SIP_HEALTH);
|
||||
|
||||
sprite_load_texture(player->sprite, asset, 0, renderer);
|
||||
player->sprite->pos = (Position) { TILE_DIMENSION, TILE_DIMENSION };
|
||||
player->sprite->dim = GAME_DIMENSION;
|
||||
|
@ -334,6 +414,23 @@ ExperienceData player_get_xp_data(Player *p)
|
|||
return data;
|
||||
}
|
||||
|
||||
void
|
||||
player_monster_kill_check(Player *player, Monster *monster)
|
||||
{
|
||||
if (!monster)
|
||||
return;
|
||||
|
||||
if (monster->stats.hp <= 0) {
|
||||
unsigned int gained_xp = 5 * monster->stats.lvl;
|
||||
player->kills += 1;
|
||||
|
||||
mixer_play_effect(DEATH);
|
||||
gui_log("You killed %s and gained %d xp",
|
||||
monster->lclabel, gained_xp);
|
||||
player_gain_xp(player, gained_xp);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
player_hit(Player *p, unsigned int dmg)
|
||||
{
|
||||
|
@ -393,5 +490,11 @@ player_destroy(Player *player)
|
|||
actiontext_destroy(player->hitText);
|
||||
actiontext_destroy(player->missText);
|
||||
|
||||
for (size_t i = 0; i < PLAYER_SKILL_COUNT; ++i) {
|
||||
if (player->skills[i])
|
||||
skill_destroy(player->skills[i]);
|
||||
player->skills[i] = NULL;
|
||||
}
|
||||
|
||||
free(player);
|
||||
}
|
||||
|
|
10
src/player.h
10
src/player.h
|
@ -24,6 +24,9 @@
|
|||
#include "stats.h"
|
||||
#include "actiontext.h"
|
||||
#include "camera.h"
|
||||
#include "skill.h"
|
||||
|
||||
#define PLAYER_SKILL_COUNT 5
|
||||
|
||||
enum PlayerClass { ENGINEER, MAGE, PALADIN, ROGUE, WARRIOR };
|
||||
typedef enum PlayerClass class_t;
|
||||
|
@ -49,6 +52,7 @@ typedef struct Player_t {
|
|||
double gold;
|
||||
unsigned int potion_sips;
|
||||
class_t class;
|
||||
Skill *skills[PLAYER_SKILL_COUNT];
|
||||
void (*handle_event)(struct Player_t*, RoomMatrix*, SDL_Event*);
|
||||
} Player;
|
||||
|
||||
|
@ -58,6 +62,12 @@ player_create(class_t, SDL_Renderer*);
|
|||
ExperienceData
|
||||
player_get_xp_data(Player*);
|
||||
|
||||
void
|
||||
player_monster_kill_check(Player*, Monster*);
|
||||
|
||||
void
|
||||
player_sip_health(Player*);
|
||||
|
||||
void
|
||||
player_hit(Player*, unsigned int dmg);
|
||||
|
||||
|
|
|
@ -31,4 +31,4 @@ get_random(unsigned int max)
|
|||
}
|
||||
|
||||
return rand() % (max + 1);
|
||||
}
|
||||
}
|
61
src/skill.c
61
src/skill.c
|
@ -21,6 +21,13 @@
|
|||
#include "texturecache.h"
|
||||
#include "skill.h"
|
||||
#include "util.h"
|
||||
#include "player.h"
|
||||
#include "roommatrix.h"
|
||||
#include "stats.h"
|
||||
#include "monster.h"
|
||||
#include "mixer.h"
|
||||
#include "gui.h"
|
||||
#include "random.h"
|
||||
|
||||
static Skill *
|
||||
create_default(const char *s_label, Sprite *s)
|
||||
|
@ -30,6 +37,9 @@ create_default(const char *s_label, Sprite *s)
|
|||
skill->resetTime = 5;
|
||||
skill->resetCountdown = 0;
|
||||
skill->icon = s;
|
||||
skill->actionRequired = true;
|
||||
skill->instantUse = false;
|
||||
skill->active = false;
|
||||
skill->use = NULL;
|
||||
return skill;
|
||||
}
|
||||
|
@ -37,9 +47,29 @@ create_default(const char *s_label, Sprite *s)
|
|||
static bool
|
||||
skill_use_flurry(Skill *skill, SkillData *data)
|
||||
{
|
||||
Position pos = position_to_matrix_coords(&data->player->sprite->pos);
|
||||
UNUSED(pos);
|
||||
UNUSED(skill);
|
||||
Position playerPos = position_to_matrix_coords(&data->player->sprite->pos);
|
||||
Position targetPos = playerPos;
|
||||
targetPos.x += (int) data->direction.x;
|
||||
targetPos.y += (int) data->direction.y;
|
||||
|
||||
Monster *monster = data->matrix->spaces[targetPos.x][targetPos.y].monster;
|
||||
if (monster) {
|
||||
gui_log("You attack %s with a flurry of strikes", monster->lclabel);
|
||||
for (size_t i = 0; i < 3; ++i) {
|
||||
unsigned int dmg = stats_fight(&data->player->stats, &monster->stats);
|
||||
mixer_play_effect((SWING0 - 1) + get_random(3));
|
||||
if (dmg > 0) {
|
||||
gui_log("You hit for %u damage", dmg);
|
||||
mixer_play_effect(SWORD_HIT);
|
||||
monster_hit(monster, dmg);
|
||||
}
|
||||
}
|
||||
|
||||
} else {
|
||||
gui_log("You swing at thin air with a flurry of strikes");
|
||||
}
|
||||
player_monster_kill_check(data->player, monster);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -57,12 +87,37 @@ create_flurry(void)
|
|||
return skill;
|
||||
}
|
||||
|
||||
static bool
|
||||
skill_sip_health(Skill *skill, SkillData *data)
|
||||
{
|
||||
player_sip_health(data->player);
|
||||
return true;
|
||||
}
|
||||
|
||||
static Skill *
|
||||
create_sip_health()
|
||||
{
|
||||
Texture *t = texturecache_add("Items/Potion.png");
|
||||
Sprite *s = sprite_create();
|
||||
sprite_set_texture(s, t, 0);
|
||||
s->dim = DEFAULT_DIMENSION;
|
||||
s->clip = CLIP16(0, 0);
|
||||
s->fixed = true;
|
||||
Skill *skill = create_default("Sip health", s);
|
||||
skill->instantUse = true;
|
||||
skill->use = skill_sip_health;
|
||||
skill->resetTime = 0;
|
||||
return skill;
|
||||
}
|
||||
|
||||
Skill*
|
||||
skill_create(enum SkillType t)
|
||||
{
|
||||
switch (t) {
|
||||
case FLURRY:
|
||||
return create_flurry();
|
||||
case SIP_HEALTH:
|
||||
return create_sip_health();
|
||||
default:
|
||||
fatal("Unknown SkillType %u", (unsigned int) t);
|
||||
return NULL;
|
||||
|
|
11
src/skill.h
11
src/skill.h
|
@ -20,17 +20,20 @@
|
|||
#define SKILL_H_
|
||||
|
||||
#include <stdbool.h>
|
||||
#include "player.h"
|
||||
#include "roommatrix.h"
|
||||
#include "sprite.h"
|
||||
#include "vector2d.h"
|
||||
|
||||
// Forward declaration
|
||||
struct Player_t;
|
||||
|
||||
enum SkillType {
|
||||
FLURRY
|
||||
FLURRY,
|
||||
SIP_HEALTH
|
||||
};
|
||||
|
||||
typedef struct SkillData_t {
|
||||
Player *player;
|
||||
struct Player_t *player;
|
||||
RoomMatrix *matrix;
|
||||
Vector2d direction;
|
||||
} SkillData;
|
||||
|
@ -40,6 +43,8 @@ typedef struct Skill_t {
|
|||
Sprite *icon;
|
||||
unsigned int resetTime;
|
||||
unsigned int resetCountdown;
|
||||
bool actionRequired;
|
||||
bool instantUse;
|
||||
bool active;
|
||||
bool (*use)(struct Skill_t*, SkillData*);
|
||||
} Skill;
|
||||
|
|
|
@ -34,7 +34,7 @@ load_texture(SkillBar *bar, const char *path, SDL_Renderer *renderer)
|
|||
t->dim.width = 16;
|
||||
t->dim.height = 16;
|
||||
|
||||
for (unsigned int i = 0; i < 4; ++i) {
|
||||
for (unsigned int i = 0; i < 5; ++i) {
|
||||
char buffer[4];
|
||||
Sprite *s = sprite_create();
|
||||
s->pos = (Position) { i * 32 + 20, 20 };
|
||||
|
@ -113,11 +113,56 @@ render_activation_indicator(SkillBar *bar, Camera *cam)
|
|||
SDL_RenderDrawRect(cam->renderer, &square);
|
||||
}
|
||||
|
||||
static void
|
||||
render_skills(SkillBar *bar, Player *player, Camera *cam)
|
||||
{
|
||||
static SDL_Rect activeSkillBox = { 0, 0, 32, 32 };
|
||||
|
||||
for (size_t i = 0; i < PLAYER_SKILL_COUNT; ++i) {
|
||||
if (!player->skills[i])
|
||||
continue;
|
||||
|
||||
Skill *skill = player->skills[i];
|
||||
skill->icon->pos = (Position) { 8 + i * 32, 8 };
|
||||
sprite_render(skill->icon, cam);
|
||||
|
||||
if (player->skills[i]->active) {
|
||||
activeSkillBox.x = i * 32;
|
||||
SDL_SetRenderDrawColor(cam->renderer, 0, 0, 255, 100);
|
||||
SDL_RenderFillRect(cam->renderer, &activeSkillBox);
|
||||
}
|
||||
if (player->skills[i]->resetCountdown > 0) {
|
||||
activeSkillBox.x = i * 32;
|
||||
SDL_SetRenderDrawColor(cam->renderer, 255, 0, 0, 100);
|
||||
SDL_RenderFillRect(cam->renderer, &activeSkillBox);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
render_skill_unavailable(SkillBar *bar, Player *player, Camera *cam)
|
||||
{
|
||||
static SDL_Rect unavailableSkillBox = { 0, 0, 32, 32 };
|
||||
|
||||
for (size_t i = 0; i < PLAYER_SKILL_COUNT; ++i) {
|
||||
if (!player->skills[i])
|
||||
continue;
|
||||
|
||||
if (player->skills[i]->resetCountdown > 0) {
|
||||
unavailableSkillBox.x = i * 32;
|
||||
SDL_SetRenderDrawColor(cam->renderer, 255, 0, 0, 70);
|
||||
SDL_RenderFillRect(cam->renderer, &unavailableSkillBox);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
skillbar_render(SkillBar *bar, Camera *cam)
|
||||
skillbar_render(SkillBar *bar, Player *player, Camera *cam)
|
||||
{
|
||||
render_frame(cam);
|
||||
render_skills(bar, player, cam);
|
||||
render_sprites(bar, cam);
|
||||
render_skill_unavailable(bar, player, cam);
|
||||
render_activation_indicator(bar, cam);
|
||||
}
|
||||
|
||||
|
@ -136,6 +181,8 @@ skillbar_handle_event(SkillBar *bar, SDL_Event *event)
|
|||
key = 3;
|
||||
else if (keyboard_press(SDLK_4, event))
|
||||
key = 4;
|
||||
else if (keyboard_press(SDLK_5, event))
|
||||
key = 5;
|
||||
|
||||
if (key != 0) {
|
||||
bar->lastActivation = key;
|
||||
|
|
|
@ -23,6 +23,7 @@
|
|||
#include "linkedlist.h"
|
||||
#include "camera.h"
|
||||
#include "timer.h"
|
||||
#include "player.h"
|
||||
|
||||
typedef struct SkillBar_t {
|
||||
LinkedList *sprites;
|
||||
|
@ -34,7 +35,7 @@ SkillBar *
|
|||
skillbar_create(SDL_Renderer*);
|
||||
|
||||
void
|
||||
skillbar_render(SkillBar*, Camera*);
|
||||
skillbar_render(SkillBar*, Player*, Camera*);
|
||||
|
||||
void
|
||||
skillbar_handle_event(SkillBar*, SDL_Event*);
|
||||
|
|
|
@ -19,6 +19,7 @@
|
|||
#ifndef VECTOR2D_H_
|
||||
#define VECTOR2D_H_
|
||||
|
||||
#define VECTOR2D_NODIR (Vector2d) { 0, 0 }
|
||||
#define VECTOR2D_RIGHT (Vector2d) { 1, 0 }
|
||||
#define VECTOR2D_LEFT (Vector2d) { -1, 0 }
|
||||
#define VECTOR2D_UP (Vector2d) { 0, -1 }
|
||||
|
|
Loading…
Reference in New Issue