Introduces particle emitters on monsters

Also adds the bleed emitter to monsters for later use with the mage.
This commit is contained in:
Linus Probert 2019-05-07 11:52:30 +02:00
parent 826cbe11ff
commit 0476d4d1bd
8 changed files with 182 additions and 18 deletions

View File

@ -213,6 +213,7 @@ add_executable(breakhack
src/pointer src/pointer
src/gui_button src/gui_button
src/particle_engine src/particle_engine
src/particle_emitter
src/menu src/menu
src/collisions src/collisions
src/keyboard src/keyboard

View File

@ -1,18 +1,18 @@
all: all:
@ninja -C _build/debug @make -C _build/debug
.PHONY: all .PHONY: all
release: release:
@ninja -C _build/release @make -C _build/release
.PHONY: release .PHONY: release
clean: clean:
@ninja clean -C _build/debug @make clean -C _build/debug
@ninja clean -C _build/release @make clean -C _build/release
.PHONY: clean .PHONY: clean
test: test:
@ninja test -C _build/debug @make test -C _build/debug
.PHONY: test .PHONY: test
run: $(all) run: $(all)
@ -24,9 +24,9 @@ playtest: $(all)
.PHONY: run .PHONY: run
lint: lint:
@ninja lint -C _build/debug @make lint -C _build/debug
.PHONY: lint .PHONY: lint
package: package:
@ninja package -C _build/release @make package -C _build/release
.PHONY: package .PHONY: package

View File

@ -233,6 +233,24 @@ monster_behaviour_check(Monster *m, RoomMatrix *rm)
} }
} }
static void
create_emitters(Monster *m)
{
// Bloodlust
ParticleEmitter *emitter = particle_emitter_create();
emitter->timestep = 0;
emitter->enabled = false;
emitter->particle_func = particle_engine_bloodlust;
m->emitters.bloodlust = emitter;
emitter = particle_emitter_create();
emitter->timestep = 1000;
emitter->enabled = false;
emitter->particle_func = particle_engine_bleed;
m->emitters.bleed = emitter;
}
Monster* Monster*
monster_create(void) monster_create(void)
{ {
@ -265,9 +283,9 @@ monster_create(void)
m->stateIndicator.shownOnPlayerRoomEnter = false; m->stateIndicator.shownOnPlayerRoomEnter = false;
m->state.forceCount = 0; m->state.forceCount = 0;
m->boss = false; m->boss = false;
m->bloodlust = false;
m->items.keyType = LOCK_NONE; m->items.keyType = LOCK_NONE;
monster_set_behaviour(m, NORMAL); monster_set_behaviour(m, NORMAL);
create_emitters(m);
return m; return m;
} }
@ -586,6 +604,19 @@ monster_reset_steps(Monster *m)
m->steps = 0; m->steps = 0;
} }
static void
update_emitters(Monster *m)
{
Position pos = m->sprite->pos;
pos.x += 6;
pos.y += 6;
particle_emitter_update(m->emitters.bloodlust, pos, DIM(20, 20));
pos.x += 5;
pos.y += 5;
particle_emitter_update(m->emitters.bleed, pos, DIM(10, 10));
}
void void
monster_update(Monster *m, UpdateData *data) monster_update(Monster *m, UpdateData *data)
{ {
@ -593,6 +624,7 @@ monster_update(Monster *m, UpdateData *data)
return; return;
sprite_update(m->sprite, data); sprite_update(m->sprite, data);
update_emitters(m);
if (m->sprite->state == SPRITE_STATE_PLUMMETED) { if (m->sprite->state == SPRITE_STATE_PLUMMETED) {
m->stats.hp = 0; m->stats.hp = 0;
@ -762,13 +794,8 @@ monster_render(Monster *m, Camera *cam)
if (m->stats.hp <= 0) if (m->stats.hp <= 0)
return; return;
if (m->bloodlust) { particle_emitter_render(m->emitters.bloodlust);
Position pos = m->sprite->pos; particle_emitter_render(m->emitters.bleed);
pos.x += 6;
pos.y += 6;
particle_engine_sparkle(pos, DIM(20, 20), C_RED, false);
}
sprite_render(m->sprite, cam); sprite_render(m->sprite, cam);
} }
@ -856,11 +883,11 @@ monster_push(Monster *m, Player *p, RoomMatrix *rm, Vector2d direction)
void void
monster_set_bloodlust(Monster *m, bool bloodlust) monster_set_bloodlust(Monster *m, bool bloodlust)
{ {
if (m->bloodlust == bloodlust || m->stats.hp <= 0) { if (m->emitters.bloodlust->enabled == bloodlust || m->stats.hp <= 0) {
return; return;
} }
m->bloodlust = bloodlust; m->emitters.bloodlust->enabled = bloodlust;
if (bloodlust) { if (bloodlust) {
gui_log("%s rages with bloodlust", m->label); gui_log("%s rages with bloodlust", m->label);
monster_set_behaviour(m, HOSTILE); monster_set_behaviour(m, HOSTILE);
@ -882,6 +909,12 @@ monster_set_bloodlust(Monster *m, bool bloodlust)
} }
} }
void
monster_set_bleeding(Monster *m)
{
m->emitters.bleed->enabled = true;
}
void void
monster_destroy(Monster *m) monster_destroy(Monster *m)
{ {
@ -890,6 +923,10 @@ monster_destroy(Monster *m)
free(m->label); free(m->label);
if (m->lclabel) if (m->lclabel)
free(m->lclabel); free(m->lclabel);
particle_emitter_destroy(m->emitters.bloodlust);
particle_emitter_destroy(m->emitters.bleed);
sprite_destroy(m->stateIndicator.sprite); sprite_destroy(m->stateIndicator.sprite);
free(m); free(m);
} }

View File

@ -26,6 +26,7 @@
#include "player.h" #include "player.h"
#include "linkedlist.h" #include "linkedlist.h"
#include "doorlocktype.h" #include "doorlocktype.h"
#include "particle_emitter.h"
struct UpdateData; struct UpdateData;
@ -68,6 +69,11 @@ typedef struct MonsterItems {
enum DoorLockType keyType; enum DoorLockType keyType;
} MonsterItems; } MonsterItems;
typedef struct ParticleEmitters {
ParticleEmitter *bloodlust;
ParticleEmitter *bleed;
} ParticleEmitters;
typedef struct Monster { typedef struct Monster {
char *label; char *label;
char *lclabel; char *lclabel;
@ -77,9 +83,9 @@ typedef struct Monster {
MonsterStateIndicator stateIndicator; MonsterStateIndicator stateIndicator;
MonsterBehaviour behaviour; MonsterBehaviour behaviour;
MonsterItems items; MonsterItems items;
ParticleEmitters emitters;
unsigned int steps; unsigned int steps;
bool boss; bool boss;
bool bloodlust;
} Monster; } Monster;
Monster* monster_create(void); Monster* monster_create(void);
@ -123,6 +129,9 @@ monster_reset_steps(Monster *m);
void void
monster_set_bloodlust(Monster*, bool bloodlust); monster_set_bloodlust(Monster*, bool bloodlust);
void
monster_set_bleeding(Monster*);
void void
monster_destroy(Monster*); monster_destroy(Monster*);

55
src/particle_emitter.c Normal file
View File

@ -0,0 +1,55 @@
#include "particle_emitter.h"
#include "util.h"
#include <stdlib.h>
ParticleEmitter *
particle_emitter_create(void)
{
ParticleEmitter *emitter = ec_malloc(sizeof(ParticleEmitter));
emitter->pos = POS(0, 0);
emitter->dim = DIM(32, 32);
emitter->particle_func = NULL;
emitter->timer = _timer_create();
emitter->timestep = 1;
emitter->enabled = false;
return emitter;
}
void
particle_emitter_render(ParticleEmitter *emitter)
{
if (!emitter->enabled)
return;
if (!timer_started(emitter->timer)) {
timer_start(emitter->timer);
return;
}
if (timer_get_ticks(emitter->timer) < emitter->timestep)
return;
timer_stop(emitter->timer);
timer_start(emitter->timer);
if (emitter->particle_func)
emitter->particle_func(emitter->pos, emitter->dim);
else
error("Particle emitter missing particle_func");
}
void
particle_emitter_update(ParticleEmitter *emitter, Position pos, Dimension dim)
{
emitter->pos = pos;
emitter->dim = dim;
}
void
particle_emitter_destroy(ParticleEmitter *emitter)
{
timer_destroy(emitter->timer);
emitter->timer = NULL;
free(emitter);
}

44
src/particle_emitter.h Normal file
View File

@ -0,0 +1,44 @@
/*
* 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 "timer.h"
#include "position.h"
#include "dimension.h"
typedef struct ParticleEmitter {
unsigned int timestep;
Timer *timer;
Position pos;
Dimension dim;
void (*particle_func)(Position, Dimension);
bool enabled;
} ParticleEmitter;
ParticleEmitter *
particle_emitter_create(void);
void
particle_emitter_render(ParticleEmitter*);
void
particle_emitter_update(ParticleEmitter*, Position, Dimension);
void
particle_emitter_destroy(ParticleEmitter*);

View File

@ -100,6 +100,12 @@ particle_engine_init(void)
engine->global_particles = linkedlist_create(); engine->global_particles = linkedlist_create();
} }
void
particle_engine_bleed(Position pos, Dimension dim)
{
particle_engine_bloodspray(pos, dim, 5);
}
void void
particle_engine_bloodspray(Position pos, Dimension dim, unsigned int count) particle_engine_bloodspray(Position pos, Dimension dim, unsigned int count)
{ {
@ -254,6 +260,12 @@ particle_engine_speed_lines(Position pos, Dimension dim, bool horizontal)
} }
} }
void
particle_engine_bloodlust(Position pos, Dimension dim)
{
particle_engine_sparkle(pos, dim, C_RED, false);
}
void void
particle_engine_sparkle(Position pos, Dimension dim, SDL_Color color, bool global) particle_engine_sparkle(Position pos, Dimension dim, SDL_Color color, bool global)
{ {

View File

@ -28,6 +28,9 @@
void void
particle_engine_init(void); particle_engine_init(void);
void
particle_engine_bleed(Position pos, Dimension dim);
void void
particle_engine_bloodspray(Position, Dimension, unsigned int count); particle_engine_bloodspray(Position, Dimension, unsigned int count);
@ -43,6 +46,9 @@ particle_engine_dust_puff(Position, Dimension);
void void
particle_engine_speed_lines(Position, Dimension, bool horizontal); particle_engine_speed_lines(Position, Dimension, bool horizontal);
void
particle_engine_bloodlust(Position, Dimension);
void void
particle_engine_sparkle(Position, Dimension, SDL_Color, bool global); particle_engine_sparkle(Position, Dimension, SDL_Color, bool global);