Adds possibility to push monsters into pits and traps.

This commit is contained in:
Linus Probert 2018-09-10 22:27:26 +02:00
parent 2316d24942
commit cb732a80ec
12 changed files with 158 additions and 50 deletions

2
.vimrc
View File

@ -1,7 +1,7 @@
nnoremap <F1> :Make<cr>
nnoremap <F2> :Make lint test<cr>
nnoremap <F3> :Termdebug _build/breakhack<cr>
nnoremap <F4> :ter ++close ./_build/breakhack<cr>
nnoremap <F4> :ter ++close env LD_LIBRARY_PATH=$LD_LIBRARY_PATH:./ ./_build/breakhack<cr>
packadd termdebug
let g:termdebug_wide = 1

View File

@ -156,7 +156,7 @@ end
local function add_pits_to_room(room)
if CURRENT_LEVEL < 3 then
if CURRENT_LEVEL < 1 then
return
elseif random(5) ~= 1 then
return

View File

@ -33,6 +33,8 @@
#include "update_data.h"
#include "actiontextbuilder.h"
#include "texturecache.h"
#include "trap.h"
#include "object.h"
static void
monster_set_sprite_clip_for_current_state(Monster *m)
@ -278,8 +280,7 @@ has_collided(Monster *monster, RoomMatrix *matrix, Vector2d direction)
if (!position_in_room(&monster->sprite->pos, &matrix->roomPos))
return true;
Position roomPos = position_to_matrix_coords(&monster->sprite->pos);
RoomSpace *space = &matrix->spaces[roomPos.x][roomPos.y];
RoomSpace *space = roommatrix_get_space_for(matrix, &monster->sprite->pos);
if (space->player && monster->state.current == AGRESSIVE) {
unsigned int dmg = stats_fight(&monster->stats,
@ -297,7 +298,7 @@ has_collided(Monster *monster, RoomMatrix *matrix, Vector2d direction)
monster_behaviour_check_post_attack(monster);
}
return space->occupied || space->lethal || space->trap || space->damaging;
return space->occupied;
}
static bool
@ -305,7 +306,9 @@ move(Monster *m, RoomMatrix *rm, Vector2d direction)
{
m->sprite->pos.x += TILE_DIMENSION * (int) direction.x;
m->sprite->pos.y += TILE_DIMENSION * (int) direction.y;
if (has_collided(m, rm, direction)) {
RoomSpace *space = roommatrix_get_space_for(rm, &m->sprite->pos);
if (has_collided(m, rm, direction) || space->lethal || space->trap || space->damaging) {
m->sprite->pos.x -= TILE_DIMENSION * (int) direction.x;
m->sprite->pos.y -= TILE_DIMENSION * (int) direction.y;
return false;
@ -439,6 +442,9 @@ monster_coward_walk(Monster *m, RoomMatrix *rm)
bool
monster_move(Monster *m, RoomMatrix *rm, Map *map)
{
if (m->stats.hp <= 0 || m->sprite->state == SPRITE_STATE_FALLING)
return true;
if (m->state.forceCount) {
if (m->state.stepsSinceChange >= m->state.forceCount) {
monster_state_change(m, m->state.last);
@ -545,6 +551,17 @@ monster_reset_steps(Monster *m)
void
monster_update(Monster *m, UpdateData *data)
{
if (m->stats.hp <= 0)
return;
sprite_update(m->sprite, data);
if (m->sprite->state == SPRITE_STATE_FALLING && m->sprite->dim.width < 4) {
m->stats.hp = 0;
player_monster_kill_check(data->player, m);
return;
}
Position monsterRoomPos = position_to_room_coords(&m->sprite->pos);
if (position_equals(&data->matrix->roomPos, &monsterRoomPos)
&& !m->stateIndicator.shownOnPlayerRoomEnter)
@ -608,23 +625,30 @@ monster_drop_loot(Monster *monster, Map *map, Player *player)
static unsigned int treasure_drop_chance = 1;
unsigned int item_drop_chance = 1;
if (monster->sprite->state == SPRITE_STATE_FALLING)
return;
Item *item;
Item *items[3];
unsigned int item_count = 0;
bool player_full_health = player->stats.hp >= player->stats.maxhp;
Position monsterTilePos = monster->sprite->pos;
monsterTilePos.x -= (monsterTilePos.x % TILE_DIMENSION);
monsterTilePos.y -= (monsterTilePos.y % TILE_DIMENSION);
if (monster->boss) {
Artifact *a = artifact_create_random(player, 2);
a->sprite->pos = monster->sprite->pos;
a->sprite->pos = monsterTilePos;
linkedlist_append(&map->artifacts, a);
Item *treasure = item_builder_build_item(TREASURE, map->level*2);
treasure->sprite->pos = monster->sprite->pos;
treasure->sprite->pos = monsterTilePos;
linkedlist_append(&map->items, treasure);
}
if (monster->stats.lvl > 2 && get_random(29) == 0) {
Artifact *a = artifact_create_random(player, 1);
a->sprite->pos = monster->sprite->pos;
a->sprite->pos = monsterTilePos;
linkedlist_append(&map->artifacts, a);
}
@ -633,19 +657,19 @@ monster_drop_loot(Monster *monster, Map *map, Player *player)
if (get_random(treasure_drop_chance) == 0) {
item = item_builder_build_item(TREASURE, map->level);
item->sprite->pos = monster->sprite->pos;
item->sprite->pos = monsterTilePos;
items[item_count++] = item;
}
if (get_random(item_drop_chance) == 0) {
ItemKey key;
key = get_random(DAGGER);
item = item_builder_build_item(key, map->level);
item->sprite->pos = monster->sprite->pos;
item->sprite->pos = monsterTilePos;
items[item_count++] = item;
}
if (!player_full_health && get_random(2) == 0) {
item = item_builder_build_item(FLESH, map->level);
item->sprite->pos = monster->sprite->pos;
item->sprite->pos = monsterTilePos;
items[item_count++] = item;
}
@ -658,7 +682,7 @@ monster_drop_loot(Monster *monster, Map *map, Player *player)
linkedlist_append(&map->items, items[0]);
} else {
Item *container = item_builder_build_sack();
container->sprite->pos = monster->sprite->pos;
container->sprite->pos = monsterTilePos;
unsigned int i;
for (i = 0; i < item_count; ++i) {
linkedlist_append(&container->items, items[i]);
@ -733,9 +757,35 @@ monster_set_state(Monster *m, StateType state, Uint8 forceCount)
}
void
monster_push(Monster *m, RoomMatrix *rm, Vector2d dir)
monster_push(Monster *m, Player *p, RoomMatrix *rm, Vector2d direction)
{
move(m, rm, dir);
m->sprite->pos.x += TILE_DIMENSION * (int) direction.x;
m->sprite->pos.y += TILE_DIMENSION * (int) direction.y;
RoomSpace *space = roommatrix_get_space_for(rm, &m->sprite->pos);
if (space->lethal) {
m->sprite->state = SPRITE_STATE_FALLING;
} else if (space->trap) {
m->stats.hp -= space->trap->damage;
monster_hit(m, space->trap->damage);
gui_log("%s takes %d damage from a trap", m->label, space->trap->damage);
} else if (space->damaging) {
LinkedList *objects = space->objects;
while (objects) {
Object *o = objects->data;
objects = objects->next;
if (!o->damage)
return;
m->stats.hp -= o->damage;
monster_hit(m, o->damage);
}
} else if (has_collided(m, rm, direction)) {
m->sprite->pos.x -= TILE_DIMENSION * (int) direction.x;
m->sprite->pos.y -= TILE_DIMENSION * (int) direction.y;
}
monster_update_pos(m, m->sprite->pos);
player_monster_kill_check(p, m);
}
void

View File

@ -108,7 +108,7 @@ void
monster_set_state(Monster *m, StateType state, Uint8 forceCount);
void
monster_push(Monster *, RoomMatrix*, Vector2d dir);
monster_push(Monster *, Player *, RoomMatrix*, Vector2d dir);
void
monster_reset_steps(Monster *m);

View File

@ -133,7 +133,7 @@ on_monster_collision(Player *player,
if (get_random(10) < player_has_artifact(player, PUSH_BACK)) {
gui_log("The force of your blow sends %s reeling",
monster->lclabel);
monster_push(monster, matrix, direction);
monster_push(monster, player, matrix, direction);
}
if (get_random(10) < player_has_artifact(player, FEAR_INDUCING)) {
@ -163,12 +163,22 @@ has_collided(Player *player, RoomMatrix *matrix, Vector2d direction)
RoomSpace *space = &matrix->spaces[matrixPos.x][matrixPos.y];
collided = space->occupied;
if (space->monster != NULL
&& (space->monster->sprite->state == SPRITE_STATE_FALLING
|| space->monster->stats.hp <= 0))
{
collided = false;
}
if (collided) {
player->sprite->pos.x -= TILE_DIMENSION * (int)direction.x;
player->sprite->pos.y -= TILE_DIMENSION * (int)direction.y;
}
if (space->monster != NULL) {
if (space->monster != NULL
&& space->monster->stats.hp > 0
&& space->monster->sprite->state != SPRITE_STATE_FALLING)
{
on_monster_collision(player, space->monster, matrix, direction);
} else if (collided) {
mixer_play_effect(BONK);
@ -595,29 +605,16 @@ void player_update(UpdateData *data)
if (player->stats.hp <= 0)
return;
sprite_update(player->sprite, data);
check_skill_activation(data);
if (player->state != FALLING && !check_skill_trigger(data))
if (player->sprite->state != SPRITE_STATE_FALLING && !check_skill_trigger(data))
handle_next_move(data);
if (player->state == FALLING && player->stats.hp > 0) {
if (!timer_started(player->animationTimer)) {
timer_start(player->animationTimer);
player->sprite->clip = CLIP16(0, 0);
} else {
if (timer_get_ticks(player->animationTimer) > 100) {
timer_start(player->animationTimer);
player->sprite->angle += 60;
player->sprite->dim.width -= 4;
player->sprite->dim.height -= 4;
player->sprite->pos.x += 2;
player->sprite->pos.y += 2;
player->sprite->rotationPoint = (SDL_Point) {
player->sprite->dim.width /2,
player->sprite->dim.height /2
};
if (player->sprite->dim.width <= 4)
if (player->sprite->state == SPRITE_STATE_FALLING && player->stats.hp > 0) {
if (player->sprite->dim.width <= 4) {
player->stats.hp = 0;
}
player->sprite->state = SPRITE_STATE_DEFAULT;
}
}
@ -705,5 +702,5 @@ void
player_set_falling(Player *player)
{
mixer_play_effect(FALL0 + get_random(1));
player->state = FALLING;
player->sprite->state = SPRITE_STATE_FALLING;
}

View File

@ -34,7 +34,7 @@ typedef struct UpdateData UpdateData;
typedef struct Animation Animation;
typedef enum PlayerClass { ENGINEER, MAGE, PALADIN, ROGUE, WARRIOR } class_t;
typedef enum PlayerState { ALIVE, DEAD, FALLING } state_t;
typedef enum PlayerState { ALIVE, DEAD } state_t;
typedef struct PlayerStatData {
unsigned int total_steps;

View File

@ -21,7 +21,7 @@
#include "defines.h"
Position
position_to_matrix_coords(Position *src)
position_to_matrix_coords(const Position *src)
{
unsigned int room_px_width, room_px_height;
Position pos;

View File

@ -32,7 +32,7 @@ typedef struct {
* Return a matrix coord position for a given position
*/
Position
position_to_matrix_coords(Position*);
position_to_matrix_coords(const Position*);
/*
* Get the room coord for the room containing the given position

View File

@ -284,6 +284,13 @@ roommatrix_render_lightmap(RoomMatrix *matrix, Camera *cam)
}
}
RoomSpace*
roommatrix_get_space_for(RoomMatrix *matrix, const Position *p)
{
Position roomPos = position_to_matrix_coords(p);
return &matrix->spaces[roomPos.x][roomPos.y];
}
void roommatrix_destroy(RoomMatrix *m)
{
// Clear the list but don't destroy the items

View File

@ -61,22 +61,33 @@ typedef struct RoomMatrix_t {
RoomMatrix* roommatrix_create(void);
void roommatrix_update(struct UpdateData*);
void
roommatrix_update(struct UpdateData*);
void roommatrix_populate_from_map(RoomMatrix*, Map*);
void
roommatrix_populate_from_map(RoomMatrix*, Map*);
void roommatrix_add_lightsource(RoomMatrix*, Position*);
void
roommatrix_add_lightsource(RoomMatrix*, Position*);
void roommatrix_build_lightmap(RoomMatrix*);
void
roommatrix_build_lightmap(RoomMatrix*);
void roommatrix_render_mouse_square(RoomMatrix*, Camera*);
void
roommatrix_render_mouse_square(RoomMatrix*, Camera*);
void roommatrix_render_lightmap(RoomMatrix*, Camera*);
void
roommatrix_render_lightmap(RoomMatrix*, Camera*);
RoomSpace*
roommatrix_get_space_for(RoomMatrix*, const Position *p);
#ifdef DEBUG
void roommatrix_render_debug(RoomMatrix*, Camera*);
void
roommatrix_render_debug(RoomMatrix*, Camera*);
#endif
void roommatrix_destroy(RoomMatrix*);
void
roommatrix_destroy(RoomMatrix*);
#endif // ROOMMATRIX_H_

View File

@ -19,11 +19,13 @@
#include <stdlib.h>
#include "sprite.h"
#include "util.h"
#include "update_data.h"
static Sprite*
sprite_create_default(void)
{
Sprite *s = ec_malloc(sizeof(Sprite));
s->state = SPRITE_STATE_DEFAULT;
s->textures[0] = NULL;
s->textures[1] = NULL;
s->clip = (SDL_Rect) { 0, 0, 0, 0 };
@ -34,6 +36,7 @@ sprite_create_default(void)
s->rotationPoint = (SDL_Point) { 0, 0 };
s->flip = SDL_FLIP_NONE;
s->renderTimer = timer_create();
s->animationTimer = timer_create();
s->texture_index = 0;
s->fixed = false;
s->animate = true;
@ -112,6 +115,33 @@ sprite_set_alpha(Sprite *s, Uint8 alpha)
texture_set_alpha(s->textures[1], alpha);
}
void
sprite_update(Sprite *s, UpdateData *data)
{
UNUSED(data);
if (s->state == SPRITE_STATE_FALLING) {
if (!timer_started(s->animationTimer)) {
timer_start(s->animationTimer);
s->clip = CLIP16(0, 0);
} else {
if (timer_get_ticks(s->animationTimer) > 100) {
timer_start(s->animationTimer);
s->angle += 60;
s->dim.width -= 4;
s->dim.height -= 4;
s->pos.x += 2;
s->pos.y += 2;
s->rotationPoint = (SDL_Point) {
s->dim.width /2,
s->dim.height /2
};
}
}
}
}
void
sprite_render(Sprite *s, Camera *cam)
{
@ -169,5 +199,6 @@ void sprite_destroy(Sprite *sprite)
texture_destroy(sprite->textures[1]);
}
timer_destroy(sprite->renderTimer);
timer_destroy(sprite->animationTimer);
free(sprite);
}

View File

@ -27,7 +27,15 @@
#include "roommatrix.h"
#include "timer.h"
typedef struct UpdateData UpdateData;
typedef enum SpriteState {
SPRITE_STATE_FALLING,
SPRITE_STATE_DEFAULT
} SpriteState;
typedef struct Sprite {
SpriteState state;
Texture* textures[2];
SDL_Rect clip;
bool destroyTextures;
@ -37,6 +45,7 @@ typedef struct Sprite {
SDL_Point rotationPoint;
SDL_RendererFlip flip;
Timer *renderTimer;
Timer *animationTimer;
unsigned int texture_index;
bool fixed;
bool animate;
@ -56,6 +65,9 @@ sprite_load_text_texture(Sprite *, const char *path, int index, int size, int ou
void
sprite_set_texture(Sprite *, Texture *, int index);
void
sprite_update(Sprite*, UpdateData *data);
void
sprite_render(Sprite*, Camera*);