diff --git a/CMakeLists.txt b/CMakeLists.txt index de68e3b..61ad268 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -181,6 +181,7 @@ add_executable(breakhack src/sprite src/sprite_util src/util + src/event src/player src/map src/map_lua diff --git a/data/monstergen.lua b/data/monstergen.lua index 05342d5..7246cc0 100644 --- a/data/monstergen.lua +++ b/data/monstergen.lua @@ -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 diff --git a/src/event.c b/src/event.c new file mode 100644 index 0000000..c7586ef --- /dev/null +++ b/src/event.c @@ -0,0 +1,46 @@ +/* + * BreakHack - A dungeone crawler RPG + * Copyright (C) 2018 Linus Probert + * + * 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 . + */ + +#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; + } +} \ No newline at end of file diff --git a/src/event.h b/src/event.h new file mode 100644 index 0000000..dfaa414 --- /dev/null +++ b/src/event.h @@ -0,0 +1,47 @@ +/* + * BreakHack - A dungeone crawler RPG + * Copyright (C) 2018 Linus Probert + * + * 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 . + */ + +#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); \ No newline at end of file diff --git a/src/main.c b/src/main.c index 5e39315..02e9230 100644 --- a/src/main.c +++ b/src/main.c @@ -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; diff --git a/src/monster.c b/src/monster.c index 7f62d3b..1b7664d 100644 --- a/src/monster.c +++ b/src/monster.c @@ -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) { diff --git a/src/monster.h b/src/monster.h index acdbc83..1e17ddd 100644 --- a/src/monster.h +++ b/src/monster.h @@ -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*); diff --git a/src/player.c b/src/player.c index 3ee1c0f..7dafd5c 100644 --- a/src/player.c +++ b/src/player.c @@ -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); } }