Fixes: #29 and #17 New skill: bash

Adds the bash skill and the stunned state.
Stunned enemies have disadvantage while stunned.
This commit is contained in:
Linus Probert 2018-08-04 23:52:52 +02:00
parent 72772358bd
commit 9fe2edee85
11 changed files with 131 additions and 32 deletions

Binary file not shown.

Before

Width:  |  Height:  |  Size: 848 B

After

Width:  |  Height:  |  Size: 5.1 KiB

View File

@ -68,6 +68,9 @@
#define C_YELLOW (SDL_Color) { 255, 255, 0, 255 }
#define C_BLACK (SDL_Color) { 0, 0, 0, 255 }
#define max(a, b) (a > b ? a : b)
#define min(a, b) (a < b ? a : b)
typedef enum Direction_t {
UP, DOWN, LEFT, RIGHT
} Direction;

View File

@ -231,7 +231,7 @@ lua_checkstats(lua_State *L, int index)
// Reset the stack
lua_pop(L, 6);
Stats stats = { hp, hp, dmg, atk, def, speed, 1 };
Stats stats = { hp, hp, dmg, atk, def, speed, 1, false, false };
return stats;
}

View File

@ -51,6 +51,9 @@ monster_set_sprite_clip_for_current_state(Monster *m)
case SLEEPING:
m->stateIndicator.sprite->clip = CLIP16(16 * 10, 16 * 4);
break;
case STUNNED:
m->stateIndicator.sprite->clip = CLIP16(16 * 13, 16 * 3);
break;
case SCANNING:
m->stateIndicator.sprite->clip = CLIP16(16 * 13, 16 * 4);
default:
@ -64,6 +67,7 @@ monster_state_change(Monster *m, StateType newState)
if (m->state.current == newState)
return;
m->state.last = m->state.current;
m->state.current = newState;
m->state.stepsSinceChange = 0;
@ -72,12 +76,19 @@ monster_state_change(Monster *m, StateType newState)
else
m->stateIndicator.displayCount = 5;
if (newState == STUNNED)
m->stats.disadvantage = true;
else if (m->state.last == STUNNED)
m->stats.disadvantage = false;
monster_set_sprite_clip_for_current_state(m);
}
static void
monster_behaviour_check_post_hit(Monster *m)
{
if (m->state.current == STUNNED)
return;
switch (m->behaviour) {
case PACIFIST:
case COWARD:
@ -156,7 +167,9 @@ monster_create(void)
0, // atk
0, // def
1, // speed
1 // lvl
1, // lvl
false, // advantage
false // disadvantage
};
m->label = NULL;
@ -350,6 +363,16 @@ monster_move(Monster *m, RoomMatrix *rm)
{
Position monsterRoomPos;
if (m->state.current == STUNNED) {
if (m->state.stepsSinceChange < 3) {
m->state.stepsSinceChange += 1;
return true;
} else {
monster_state_change(m, m->state.last);
monster_behaviour_check_post_hit(m);
}
}
monster_behaviour_check(m, rm);
monsterRoomPos = position_to_matrix_coords(&m->sprite->pos);
@ -525,6 +548,12 @@ monster_set_behaviour(Monster *m, MonsterBehaviour behaviour)
monster_set_sprite_clip_for_current_state(m);
}
void
monster_set_stunned(Monster *m)
{
monster_state_change(m, STUNNED);
}
void
monster_destroy(Monster *m)
{

View File

@ -43,11 +43,13 @@ typedef enum {
SCARED,
STATIONARY,
SLEEPING,
SCANNING
SCANNING,
STUNNED
} StateType;
typedef struct {
typedef struct State {
StateType current;
StateType last;
unsigned int stepsSinceChange;
} State;
@ -94,6 +96,9 @@ monster_drop_loot(Monster*, Map*, Player*);
void
monster_set_behaviour(Monster *, MonsterBehaviour behaviour);
void
monster_set_stunned(Monster *m);
void
monster_destroy(Monster*);

View File

@ -35,11 +35,11 @@
#include "actiontextbuilder.h"
#include "animation.h"
#define ENGINEER_STATS { 12, 12, 5, 7, 2, 2, 1 }
#define MAGE_STATS { 12, 12, 5, 7, 1, 2, 1 }
#define PALADIN_STATS { 12, 12, 8, 9, 3, 1, 1 }
#define ROGUE_STATS { 12, 12, 5, 7, 1, 2, 1 }
#define WARRIOR_STATS { 12, 12, 8, 9, 3, 1, 1 }
#define ENGINEER_STATS { 12, 12, 5, 7, 2, 2, 1, false, false }
#define MAGE_STATS { 12, 12, 5, 7, 1, 2, 1, false, false }
#define PALADIN_STATS { 12, 12, 8, 9, 3, 1, 1, false, false }
#define ROGUE_STATS { 12, 12, 5, 7, 1, 2, 1, false, false }
#define WARRIOR_STATS { 12, 12, 8, 9, 3, 1, 1, false, false }
static void
player_levelup(Player *player)
@ -428,8 +428,9 @@ player_create(class_t class, SDL_Renderer *renderer)
m_strcpy(asset, 100, "Commissions/Warrior.png");
player->stats = (Stats) WARRIOR_STATS;
player->skills[0] = skill_create(FLURRY);
player->skills[1] = skill_create(CHARGE);
player->skills[2] = skill_create(DAGGER_THROW);
player->skills[1] = skill_create(BASH);
player->skills[2] = skill_create(CHARGE);
player->skills[3] = skill_create(DAGGER_THROW);
break;
}

View File

@ -25,6 +25,7 @@
#include "player.h"
#include "item.h"
#include "update_data.h"
#include "defines.h"
static void
roommatrix_reset(RoomMatrix *m)
@ -152,25 +153,6 @@ void roommatrix_populate_from_map(RoomMatrix *rm, Map *m)
}
}
// TODO(Linus): These should probably be macros
#undef min
#ifndef min
static int
min(int a, int b)
{
return a > b ? b : a;
}
#endif // min
#undef max
#ifndef max
static int
max(int a, int b)
{
return a > b ? a : b;
}
#endif // max
void
roommatrix_add_lightsource(RoomMatrix *matrix, Position *pos)
{

View File

@ -177,6 +177,67 @@ create_throw_dagger(void)
return skill;
}
static bool
skill_bash(Skill *skill, SkillData *data)
{
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;
player_turn(data->player, &data->direction);
if (!position_in_roommatrix(&targetPos)) {
return false;
}
animation_run(data->player->swordAnimation);
Monster *monster = data->matrix->spaces[targetPos.x][targetPos.y].monster;
mixer_play_effect(SWING1);
if (monster) {
gui_log("You bash %s with your shield", monster->lclabel);
unsigned int dmg = stats_fight(&data->player->stats, &monster->stats);
if (dmg > 0) {
gui_log("You hit for %u damage", dmg);
if (monster->stats.hp > 0) {
gui_log("%s seems dazed and confused", monster->label);
monster_set_stunned(monster);
}
mixer_play_effect(SWORD_HIT);
data->player->stat_data.hits += 1;
} else {
gui_log("You missed %s", monster->lclabel);
}
monster_hit(monster, dmg);
} else {
gui_log("You bash your shield at nothing");
}
player_monster_kill_check(data->player, monster);
return true;
}
static Skill *
create_bash(void)
{
Texture *t = texturecache_add("Extras/Skills.png");
Sprite *s = sprite_create();
sprite_set_texture(s, t, 0);
s->dim = GAME_DIMENSION;
s->clip = CLIP32(96, 0);
s->fixed = true;
Skill *skill = create_default("Bash", s);
skill->levelcap = 3;
skill->instantUse = false;
skill->resetTime = 2;
skill->available = NULL;
skill->use = skill_bash;
skill->actionRequired = true;
return skill;
}
static bool
skill_sip_health_available(Player *player)
{
@ -316,6 +377,8 @@ skill_create(enum SkillType t)
return create_charge();
case DAGGER_THROW:
return create_throw_dagger();
case BASH:
return create_bash();
default:
fatal("Unknown SkillType %u", (unsigned int) t);
return NULL;

View File

@ -29,6 +29,7 @@ struct Player_t;
enum SkillType {
FLURRY,
BASH,
CHARGE,
DAGGER_THROW,
SIP_HEALTH

View File

@ -25,6 +25,7 @@
#include "stats.h"
#include "random.h"
#include "util.h"
#include "defines.h"
unsigned int
stats_fight(Stats *attacker, Stats *defender)
@ -32,11 +33,23 @@ stats_fight(Stats *attacker, Stats *defender)
int atkRoll, defRoll, dmgRoll;
bool critical = false;
atkRoll = get_random(19) + 1;
if (attacker->advantage)
atkRoll = max(get_random(19), get_random(19)) + 1;
else if (attacker->disadvantage)
atkRoll = min(get_random(19), get_random(19)) + 1;
else
atkRoll = get_random(19) + 1;
if (atkRoll == 20)
critical = true;
atkRoll += attacker->atk;
defRoll = (get_random(19) + 1) + defender->def;
if (defender->advantage)
defRoll = max(get_random(19), get_random(19)) + 1 + defender->def;
else if (defender->disadvantage)
defRoll = min(get_random(19), get_random(19)) + 1 + defender->def;
else
defRoll = get_random(19) + 1 + defender->def;
dmgRoll = 0;
if (atkRoll >= defRoll) {

View File

@ -27,6 +27,8 @@ typedef struct Stats_t {
int def; /* Defence rating */
unsigned int speed; /* Speed */
unsigned int lvl; /* Level */
bool advantage;
bool disadvantage;
} Stats;
unsigned int