Adds room objects and FIRE rooms.

This commit is contained in:
Linus Probert 2018-08-13 13:11:32 +02:00
parent 0b58e535ec
commit 6633db7aa4
17 changed files with 307 additions and 37 deletions

View File

@ -176,6 +176,7 @@ add_executable(breakhack
src/artifact
src/screen
src/hiscore
src/object
)
# Sqlite has some warnings that I we don't need to see

View File

@ -431,10 +431,13 @@ local function build_normal_room(room)
add_level_exit(room)
end
if CURRENT_LEVEL > 3 and random(10) == 1 then
if CURRENT_LEVEL > 3 and random(8) == 1 then
directions = { "LEFT", "RIGHT", "UP", "DOWN" }
room.modifier.type = "WINDY"
room.modifier.arg = directions[random(#directions)]
elseif CURRENT_LEVEL > 5 and random(8) == 1 then
room.modifier.type = "FIRE"
room.modifier.arg = ""
end
return room

View File

@ -19,6 +19,7 @@
#ifndef DEFINES_H_
#define DEFINES_H_
#include <stdint.h>
#include "config.h"
/* Room/Map dimensions */
@ -76,6 +77,13 @@
#define min(a, b) (a < b ? a : b)
#endif // _MSC_VER
typedef int8_t Sint8;
typedef uint8_t Uint8;
typedef int16_t Sint16;
typedef uint16_t Uint16;
typedef int32_t Sint32;
typedef uint32_t Uint32;
typedef enum Direction_t {
UP, DOWN, LEFT, RIGHT
} Direction;

View File

@ -523,16 +523,13 @@ run_game_update(void)
if (gGameState == IN_GAME_MENU)
menu_update(inGameMenu, &input);
map_clear_dead_monsters(gMap, gPlayer);
map_clear_collected_items(gMap);
map_clear_collected_artifacts(gMap);
populateUpdateData(&updateData, deltaTime);
if (playerLevel != gPlayer->stats.lvl) {
playerLevel = gPlayer->stats.lvl;
skillbar_check_skill_activation(gSkillBar, gPlayer);
}
map_clear_expired_entities(gMap, gPlayer);
if (gGameState == PLAYING && currentTurn == PLAYER)
player_update(&updateData);
@ -550,6 +547,7 @@ run_game_update(void)
if (player_turn_over(gPlayer)) {
currentTurn = MONSTER;
player_reset_steps(gPlayer);
map_on_new_turn(gMap);
repopulate_roommatrix();
}
} else if (currentTurn == MONSTER) {

View File

@ -55,6 +55,7 @@ map_create(void)
map->monsters = linkedlist_create();
map->items = linkedlist_create();
map->artifacts = linkedlist_create();
map->objects = linkedlist_create();
map->currentRoom = (Position) { 0, 0 };
map->renderTimer = timer_create();
map->monsterMoveTimer = timer_create();
@ -128,9 +129,9 @@ map_add_trap(Map *map, Position *pos, Trap *trap)
}
void
map_clear_dead_monsters(Map *map, Player *player)
map_clear_expired_entities(Map *map, Player *player)
{
LinkedList *cleared = linkedlist_create();
LinkedList *filtered = linkedlist_create();
while (map->monsters) {
Monster *monster = linkedlist_pop(&map->monsters);
@ -138,17 +139,12 @@ map_clear_dead_monsters(Map *map, Player *player)
monster_drop_loot(monster, map, player);
monster_destroy(monster);
} else {
linkedlist_append(&cleared, monster);
linkedlist_append(&filtered, monster);
}
}
map->monsters = cleared;
}
void
map_clear_collected_items(Map *map)
{
LinkedList *filtered = linkedlist_create();
map->monsters = filtered;
filtered = linkedlist_create();
while (map->items) {
Item *item = linkedlist_pop(&map->items);
if (item->collected)
@ -157,12 +153,8 @@ map_clear_collected_items(Map *map)
linkedlist_append(&filtered, item);
}
map->items = filtered;
}
void
map_clear_collected_artifacts(Map *map)
{
LinkedList *filtered = linkedlist_create();
filtered = linkedlist_create();
while (map->artifacts) {
Artifact *a = linkedlist_pop(&map->artifacts);
if (!a->collected)
@ -171,6 +163,16 @@ map_clear_collected_artifacts(Map *map)
artifact_destroy(a);
}
map->artifacts = filtered;
filtered = linkedlist_create();
while (map->objects) {
Object *o = linkedlist_pop(&map->objects);
if (o->dead)
object_destroy(o);
else
linkedlist_append(&filtered, o);
}
map->objects = filtered;
}
void
@ -204,7 +206,7 @@ map_move_monsters(Map *map, RoomMatrix *rm)
&& position_proximity(1, &rm->playerRoomPos, &pos))
continue;
allDone = allDone && monster_move(monster, rm);
allDone = allDone && monster_move(monster, rm, map);
}
if (allDone)
@ -259,6 +261,17 @@ void map_tile_render(Map *map, MapTile *tile, Position *pos, Camera *cam)
}
void
map_on_new_turn(Map *map)
{
LinkedList *objects = map->objects;
while (objects) {
Object *o = objects->data;
objects = objects->next;
object_step(o);
}
}
void
map_update(UpdateData *data)
{
@ -304,6 +317,8 @@ void map_render(Map *map, Camera *cam)
}
if (room->modifier.type == RMOD_TYPE_WINDY) {
particle_engine_wind(room->modifier.data.wind.direction);
} else if (room->modifier.type == RMOD_TYPE_FIRE) {
particle_engine_heat();
}
}
@ -317,6 +332,12 @@ map_render_mid_layer(Map *map, Camera *cam)
items = items->next;
}
LinkedList *objects = map->objects;
while (objects != NULL) {
object_render(objects->data, cam);
objects = objects->next;
}
LinkedList *artifacts = map->artifacts;
while (artifacts != NULL) {
artifact_render(artifacts->data, cam);
@ -410,6 +431,9 @@ void map_destroy(Map *map)
while (map->artifacts != NULL)
artifact_destroy(linkedlist_pop(&map->artifacts));
while (map->objects != NULL)
artifact_destroy(linkedlist_pop(&map->objects));
timer_destroy(map->renderTimer);
timer_destroy(map->monsterMoveTimer);
free(map);

View File

@ -31,6 +31,7 @@
#include "monster.h"
#include "player.h"
#include "map_room_modifiers.h"
#include "object.h"
typedef struct UpdateData UpdateData;
typedef struct Trap Trap;
@ -58,6 +59,7 @@ typedef struct Map_t {
LinkedList *monsters;
LinkedList *items;
LinkedList *artifacts;
LinkedList *objects;
Position currentRoom;
Timer *renderTimer;
Timer *monsterMoveTimer;
@ -89,13 +91,10 @@ bool
map_move_monsters(Map*, RoomMatrix*);
void
map_clear_dead_monsters(Map*, Player*);
map_clear_expired_entities(Map*, Player*);
void
map_clear_collected_items(Map*);
void
map_clear_collected_artifacts(Map*);
map_on_new_turn(Map*);
void
map_update(UpdateData*);

View File

@ -116,6 +116,9 @@ l_map_set_current_room_modifier(lua_State *L)
Room *room = map->rooms[map->currentRoom.x][map->currentRoom.y];
room->modifier.type = RMOD_TYPE_WINDY;
room->modifier.data.wind.direction = dir;
} else if (strcmp(modifier, "FIRE") == 0) {
Room *room = map->rooms[map->currentRoom.x][map->currentRoom.y];
room->modifier.type = RMOD_TYPE_FIRE;
} else {
luaL_error(L, "Unknown room modifier: %s", modifier);
return 1;

View File

@ -27,10 +27,11 @@ typedef struct RoomMatrix_t RoomMatrix;
typedef enum RoomModifierType_e {
RMOD_TYPE_NONE,
RMOD_TYPE_WINDY
RMOD_TYPE_WINDY,
RMOD_TYPE_FIRE
} RoomModifierType;
typedef struct WindData_t {
typedef struct WindData {
Vector2d direction;
} WindData;
@ -38,7 +39,7 @@ typedef union RoomModifierDataContainer_t {
WindData wind;
} RoomModifierDataContainer;
typedef struct RoomModifierData_t {
typedef struct RoomModifierData {
RoomModifierType type;
RoomModifierDataContainer data;
} RoomModifierData;

View File

@ -236,7 +236,7 @@ has_collided(Monster *monster, RoomMatrix *matrix, Vector2d direction)
monster_behaviour_check_post_attack(monster);
}
return space->occupied || space->lethal || space->trap;
return space->occupied || space->lethal || space->trap || space->damaging;
}
static bool
@ -376,7 +376,7 @@ monster_coward_walk(Monster *m, RoomMatrix *rm)
}
bool
monster_move(Monster *m, RoomMatrix *rm)
monster_move(Monster *m, RoomMatrix *rm, Map *map)
{
if (m->state.forceCount) {
if (m->state.stepsSinceChange >= m->state.forceCount) {
@ -392,10 +392,11 @@ monster_move(Monster *m, RoomMatrix *rm)
monster_behaviour_check(m, rm);
Position originalPosition =
Position origPos = m->sprite->pos;
Position originalMPos =
position_to_matrix_coords(&m->sprite->pos);
rm->spaces[originalPosition.x][originalPosition.y].occupied = false;
rm->spaces[originalPosition.x][originalPosition.y].monster = NULL;
rm->spaces[originalMPos.x][originalMPos.y].occupied = false;
rm->spaces[originalMPos.x][originalMPos.y].monster = NULL;
switch (m->state.current) {
case PASSIVE:
@ -420,7 +421,7 @@ monster_move(Monster *m, RoomMatrix *rm)
rm->spaces[newPos.x][newPos.y].occupied = true;
rm->spaces[newPos.x][newPos.y].monster = m;
if (!position_equals(&originalPosition, &newPos)) {
if (!position_equals(&originalMPos, &newPos)) {
Player *p = rm->spaces[rm->playerRoomPos.x][rm->playerRoomPos.y].player;
if (p) {
Uint32 range = 3 + player_has_artifact(p, IMPROVED_HEARING) * 2;
@ -434,6 +435,14 @@ monster_move(Monster *m, RoomMatrix *rm)
actiontextbuilder_create_text("!", C_WHITE, &m->sprite->pos);
}
}
}
if (!position_equals(&origPos, &m->sprite->pos) && rm->modifier->type == RMOD_TYPE_FIRE) {
Object *o = object_create_fire();
o->sprite->pos = origPos;
o->damage *= m->stats.lvl;
linkedlist_push(&map->objects, o);
}
m->steps++;
@ -576,6 +585,9 @@ monster_render(Monster *m, Camera *cam)
void
monster_render_top_layer(Monster *m, Camera *cam)
{
if (m->stats.hp <= 0)
return;
if (m->stateIndicator.displayCount != 0)
sprite_render(m->stateIndicator.sprite, cam);
}

View File

@ -77,7 +77,7 @@ void
monster_update_pos(Monster*, Position);
bool
monster_move(Monster*, RoomMatrix*);
monster_move(Monster*, RoomMatrix*, Map*);
void
monster_render(Monster*, Camera*);

82
src/object.c Normal file
View File

@ -0,0 +1,82 @@
/*
* 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 "object.h"
#include "util.h"
#include "mixer.h"
#include "random.h"
#include "texturecache.h"
Object *
object_create(void)
{
Object *o = ec_malloc(sizeof(Object));
o->sprite = sprite_create();
o->blocking = false;
o->damage = 0;
o->timeout = -1;
o->dead = false;
return o;
}
Object *
object_create_fire()
{
Object *o = object_create();
Texture *t0 = texturecache_add("Objects/Effect0.png");
Texture *t1 = texturecache_add("Objects/Effect1.png");
sprite_set_texture(o->sprite, t0, 0);
sprite_set_texture(o->sprite, t1, 1);
o->sprite->dim = GAME_DIMENSION;
o->sprite->clip = CLIP16(16, 21*16);
o->damage = 3;
o->timeout = 5;
return o;
}
void
object_render(Object *o, Camera *cam)
{
sprite_render(o->sprite, cam);
}
void
object_step(Object *o)
{
if (o->timeout < 0)
return;
o->timeout--;
if (o->timeout <= 0)
o->dead = true;
}
void
object_damage(Object *o, Player *p)
{
if (!o->damage)
return;
p->stats.hp -= o->damage;
player_hit(p, o->damage);
}
void
object_destroy(Object *o)
{
sprite_destroy(o->sprite);
free(o);
}

51
src/object.h Normal file
View File

@ -0,0 +1,51 @@
/*
* 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 <SDL.h>
#include <stdbool.h>
#include "camera.h"
#include "player.h"
#include "sprite.h"
#include "player.h"
typedef struct Object {
Sprite *sprite;
bool blocking;
Uint32 damage;
Sint32 timeout;
bool dead;
} Object;
Object *
object_create(void);
Object *
object_create_fire(void);
void
object_render(Object*, Camera*);
void
object_damage(Object*, Player*);
void
object_step(Object*);
void
object_destroy(Object*);

View File

@ -294,6 +294,49 @@ particle_engine_wind(Vector2d direction)
}
}
void
particle_engine_heat()
{
unsigned int count = 5;
Position pos = { 0, 0 };
Dimension dim = { GAME_VIEW_WIDTH, GAME_VIEW_HEIGHT };
if (dim.width == 0 || dim.height == 0)
return;
for (unsigned int i = 0; i < count; ++i) {
int x, y;
int w, h;
unsigned int lt;
Particle *p;
int yvel, xvel;
x = get_random(dim.width) + pos.x;
y = get_random(dim.height) + pos.y;
w = get_random(2) + 2;
h = get_random(2) + 2;
yvel = get_random(50) - 200;
xvel = get_random(100) * -get_random(1);
lt = get_random(500);
p = create_rect_particle();
p->particle.rect.pos = (Position) { x, y };
p->particle.rect.dim = (Dimension) { w, h };
p->velocity = (Vector2d) { (float) xvel, (float) yvel };
p->movetime = lt;
p->lifetime = lt;
if (get_random(1) == 0)
p->color = C_YELLOW;
else
p->color = C_RED;
p->fixed = true;
linkedlist_append(&engine->game_particles, p);
}
}
static void
move_particle(Particle *particle, float deltaTime)
{

View File

@ -46,6 +46,9 @@ particle_engine_sparkle(Position, Dimension, SDL_Color, bool global);
void
particle_engine_wind(Vector2d direction);
void
particle_engine_heat(void);
void
particle_engine_update(float deltatime);

View File

@ -194,6 +194,14 @@ has_collided(Player *player, RoomMatrix *matrix, Vector2d direction)
}
}
if (space->objects && !collided) {
LinkedList *objects = space->objects;
while (objects) {
object_damage(objects->data, player);
objects = objects->next;
}
}
if (space->lethal && !collided) {
mixer_play_effect(FALL0 + get_random(2) - 1);
player->state = FALLING;
@ -294,6 +302,7 @@ handle_next_move(UpdateData *data)
static unsigned int step = 1;
Player *player = data->player;
Position originPos = player->sprite->pos;
// Don't move when projectiles are still moving
if (linkedlist_size(player->projectiles) > 0)
@ -304,6 +313,14 @@ handle_next_move(UpdateData *data)
if (!vector2d_equals(nextDir, VECTOR2D_NODIR))
move(player, matrix, nextDir);
if (!position_equals(&originPos, &player->sprite->pos)
&& matrix->modifier->type == RMOD_TYPE_FIRE) {
Object *o = object_create_fire();
o->damage *= player->stats.lvl;
o->sprite->pos = originPos;
linkedlist_append(&data->map->objects, o);
}
map_room_modifier_player_effect(player, matrix, &nextDir, move);
if (!vector2d_equals(VECTOR2D_NODIR, nextDir)) {

View File

@ -27,6 +27,7 @@
#include "update_data.h"
#include "defines.h"
#include "trap.h"
#include "object.h"
static void
roommatrix_reset(RoomMatrix *m)
@ -39,6 +40,7 @@ roommatrix_reset(RoomMatrix *m)
space = &m->spaces[i][j];
space->occupied = false;
space->lethal = false;
space->damaging = false;
space->lightsource = false;
space->light = 0;
space->monster = NULL;
@ -48,6 +50,8 @@ roommatrix_reset(RoomMatrix *m)
linkedlist_pop(&space->items);
while (space->artifacts != NULL)
linkedlist_pop(&space->artifacts);
while (space->objects != NULL)
linkedlist_pop(&space->objects);
}
}
m->roomPos = (Position) { 0, 0 };
@ -62,6 +66,7 @@ RoomMatrix* roommatrix_create(void)
for (j = 0; j < MAP_ROOM_HEIGHT; ++j) {
m->spaces[i][j].items = linkedlist_create();;
m->spaces[i][j].artifacts = linkedlist_create();;
m->spaces[i][j].objects = linkedlist_create();;
}
}
roommatrix_reset(m);
@ -168,6 +173,21 @@ void roommatrix_populate_from_map(RoomMatrix *rm, Map *m)
position = position_to_matrix_coords(&a->sprite->pos);
linkedlist_push(&rm->spaces[position.x][position.y].artifacts, a);
}
LinkedList *objects = m->objects;
while (objects) {
Object *o = objects->data;
objects = objects->next;
if (!position_in_room(&o->sprite->pos, &m->currentRoom))
continue;
position = position_to_matrix_coords(&o->sprite->pos);
RoomSpace *space = &rm->spaces[position.x][position.y];
linkedlist_push(&space->objects, o);
space->occupied = space->occupied || o->blocking;
space->damaging = o->damage > 0;
}
}
void
@ -275,6 +295,8 @@ void roommatrix_destroy(RoomMatrix *m)
linkedlist_pop(&space->items);
while (space->artifacts)
linkedlist_pop(&space->artifacts);
while (space->objects)
linkedlist_pop(&space->objects);
}
}

View File

@ -33,19 +33,22 @@ typedef struct Player Player;
typedef struct Item_t Item;
typedef struct Node LinkedList;
typedef struct Trap Trap;
typedef struct Object Object;
struct UpdateData;
typedef struct {
typedef struct RoomSpace {
bool occupied;
bool lethal;
bool lightsource;
bool damaging;
int light;
Monster *monster;
Player *player;
Trap *trap;
LinkedList *items;
LinkedList *artifacts;
LinkedList *objects;
} RoomSpace;
typedef struct RoomMatrix_t {