Adds monster bloodlust

- Introduces the beginning of an event listener system
- Introduces fairies. When they are killed monsters in the room rage!
This commit is contained in:
Linus Probert 2019-03-10 00:15:47 +01:00
parent d749861477
commit fd3a625249
8 changed files with 186 additions and 2 deletions

View File

@ -181,6 +181,7 @@ add_executable(breakhack
src/sprite
src/sprite_util
src/util
src/event
src/player
src/map
src/map_lua

View File

@ -169,6 +169,18 @@ for i=1,#misc do
misc[i] = concat({ texturePaths.misc0, texturePaths.misc1 }, misc[i])
end
local fairies = {
{ stats.misc, 0, 48, "A Fairy", behaviour.pacifist },
{ stats.misc, 16, 48, "A Fairy", behaviour.pacifist },
{ stats.misc, 32, 48, "A Fairy", behaviour.pacifist },
{ stats.misc, 48, 48, "A Fairy", behaviour.pacifist },
{ stats.misc, 64, 48, "A Fairy", behaviour.pacifist },
{ stats.misc, 80, 48, "A Fairy", behaviour.pacifist },
}
for i=1,#fairies do
fairies[i] = concat({ texturePaths.humanoid0, texturePaths.humanoid1 }, fairies[i])
end
local reanimated = {
{ stats.undead, 0, 32, "A Skeleton", behaviour.normal },
{ stats.undead, 48, 32, "A Black Skeleton", behaviour.normal },
@ -273,7 +285,6 @@ local eastereggs = {
{ stats.misc, 0*16, 7*16, "Adnis, the Ranger", behaviour.passive },
{ stats.misc, 7*16, 8*16, "Ti, the Mage", behaviour.passive },
}
for i=1,#eastereggs do
eastereggs[i] = concat({ texturePaths.player0, texturePaths.player1 }, eastereggs[i])
end
@ -360,6 +371,7 @@ if(CURRENT_LEVEL > 0) then
end
local addSpecialInLevel = random(100) == 1
local addFairyToLevel = random(3) == 1;
local function add_monster_to_tile(room, roomx, roomy, rx, ry, monster)
local x = (roomx * 512) + rx * 32
@ -372,7 +384,8 @@ local function add_monster_to_tile(room, roomx, roomy, rx, ry, monster)
end
function module.add_monsters_to_room(room, roomx, roomy)
local addSpecial = addSpecialInLevel and random(5) == 1
local addSpecial = addSpecialInLevel and random(2) == 1
local addFairy = random(2) == 1
local count = random(3)
if (CURRENT_LEVEL > 3) then
count = random(4)
@ -387,6 +400,9 @@ function module.add_monsters_to_room(room, roomx, roomy)
addSpecialInLevel = false
addSpecial = false
add_monster_to_tile(room, roomx, roomy, rx, ry, eastereggs[random(#eastereggs)])
elseif addFairyToLevel and addFairy then
addFairyToLevel = false
add_monster_to_tile(room, roomx, roomy, rx, ry, fairies[random(#fairies)])
else
add_monster_to_tile(room, roomx, roomy, rx, ry, enemies[random(#enemies)])
end

46
src/event.c Normal file
View File

@ -0,0 +1,46 @@
/*
* 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 "event.h"
#include "util.h"
#include "linkedlist.h"
static LinkedList *callbacks = NULL;
void
event_register_listener(EventCallback cb)
{
linkedlist_append(&callbacks, cb);
}
void
event_clear_listeners(void)
{
while (callbacks)
linkedlist_pop(&callbacks);
}
void
event_trigger(Event *event)
{
LinkedList *cbs = callbacks;
while (cbs) {
((EventCallback) cbs->data)(event);
cbs = cbs->next;
}
}

47
src/event.h Normal file
View File

@ -0,0 +1,47 @@
/*
* 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 "player.h"
typedef enum EventType {
MONSTER_KILLED_EVENT
} EventType;
typedef struct MonsterKilledEvent {
EventType *type;
Player *player;
Monster *monster;
} MonsterKilledEvent;
typedef union Event {
EventType type;
MonsterKilledEvent monsterKilled;
} Event;
typedef void (*EventCallback)(Event*);
void
event_register_listener(EventCallback cb);
void
event_clear_listeners(void);
void
event_trigger(Event *event);

View File

@ -56,6 +56,7 @@
#include "gamecontroller.h"
#include "time.h"
#include "sprite_util.h"
#include "event.h"
#ifdef STEAM_BUILD
#include "steam/steamworks_api_wrapper.h"
@ -646,6 +647,22 @@ resetGame(void)
repopulate_roommatrix();
}
static void
on_event_callback(Event *event)
{
if (event->type == MONSTER_KILLED_EVENT) {
if (strcmp(event->monsterKilled.monster->label, "A Fairy") == 0) {
LinkedList *monsters = gMap->monsters;
while (monsters) {
Monster *monster = monsters->data;
monsters = monsters->next;
if (position_in_room(&monster->sprite->pos, &gMap->currentRoom))
monster_set_bloodlust(monster, true);
}
}
}
}
static bool
init(void)
{
@ -668,6 +685,8 @@ init(void)
return false;
}
event_register_listener(on_event_callback);
settings_init();
hiscore_init();
initMainMenu();
@ -1333,6 +1352,7 @@ void close(void)
#endif // STEAM_BUILD
gamecontroller_close();
event_clear_listeners();
SDL_DestroyRenderer(gRenderer);
SDL_DestroyWindow(gWindow);
gWindow = NULL;

View File

@ -265,6 +265,7 @@ monster_create(void)
m->stateIndicator.shownOnPlayerRoomEnter = false;
m->state.forceCount = 0;
m->boss = false;
m->bloodlust = false;
monster_set_behaviour(m, NORMAL);
return m;
@ -697,6 +698,12 @@ monster_drop_loot(Monster *monster, Map *map, Player *player)
linkedlist_append(&map->items, treasure);
}
if (strcmp(monster->label, "A Fairy") == 0) {
Item *treasure = item_builder_build_treasure(PLATINUM, 3 * monster->stats.lvl);
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 = monsterTilePos;
@ -748,6 +755,13 @@ monster_render(Monster *m, Camera *cam)
if (m->stats.hp <= 0)
return;
if (m->bloodlust) {
Position pos = m->sprite->pos;
pos.x += 6;
pos.y += 6;
particle_engine_sparkle(pos, DIM(20, 20), C_RED, false);
}
sprite_render(m->sprite, cam);
}
@ -832,6 +846,35 @@ monster_push(Monster *m, Player *p, RoomMatrix *rm, Vector2d direction)
player_monster_kill_check(p, m);
}
void
monster_set_bloodlust(Monster *m, bool bloodlust)
{
if (m->bloodlust == bloodlust || m->stats.hp <= 0) {
return;
}
m->bloodlust = bloodlust;
if (bloodlust) {
gui_log("%s rages with bloodlust", m->label);
monster_set_behaviour(m, HOSTILE);
m->stats.advantage = true;
m->stats.atk += 2;
m->stats.def += 2;
m->stats.dmg += 2;
m->stats.hp += 10;
m->stats.maxhp += 10;
} else {
gui_log("%s calms down from it's bloodlust", m->label);
monster_set_behaviour(m, NORMAL);
m->stats.advantage = false;
m->stats.atk -= 2;
m->stats.def -= 2;
m->stats.dmg -= 2;
m->stats.hp -= 10;
m->stats.maxhp -= 10;
}
}
void
monster_destroy(Monster *m)
{

View File

@ -73,6 +73,7 @@ typedef struct Monster {
MonsterBehaviour behaviour;
unsigned int steps;
bool boss;
bool bloodlust;
} Monster;
Monster* monster_create(void);
@ -113,6 +114,9 @@ monster_push(Monster *, Player *, RoomMatrix*, Vector2d dir);
void
monster_reset_steps(Monster *m);
void
monster_set_bloodlust(Monster*, bool bloodlust);
void
monster_destroy(Monster*);

View File

@ -36,6 +36,7 @@
#include "animation.h"
#include "trap.h"
#include "gamecontroller.h"
#include "event.h"
#ifdef STEAM_BUILD
#include "steam/steamworks_api_wrapper.h"
@ -610,6 +611,12 @@ player_monster_kill_check(Player *player, Monster *monster)
if (strcmp("The Trader", monster->label) == 0) {
player->stateData.shopOwnerKiller = true;
}
Event event;
event.type = MONSTER_KILLED_EVENT;
event.monsterKilled.monster = monster;
event.monsterKilled.player = player;
event_trigger(&event);
}
}