BossFightUI is not managed by the level manager since it is kind of a new level, just with a different mini game.

master
Zed A. Shaw 6 days ago
parent a3f6ba3c03
commit ca18422930
  1. 8
      assets/bosses.json
  2. 6
      assets/devices.json
  3. 22
      assets/enemies.json
  4. 12
      assets/items.json
  5. 27
      boss_fight_ui.cpp
  6. 11
      boss_fight_ui.hpp
  7. 3
      components.hpp
  8. 16
      gui_fsm.cpp
  9. 2
      gui_fsm.hpp
  10. 5
      levelmanager.cpp
  11. 2
      levelmanager.hpp
  12. 2
      main_ui.cpp

@ -3,11 +3,9 @@
"background": "boss_fight_background", "background": "boss_fight_background",
"weapon_sound": "Sword_Hit_2", "weapon_sound": "Sword_Hit_2",
"components": [ "components": [
{"_type": "Combat", "hp": 50, "max_hp": 50, "damage": 50, "dead": false}, {"_type": "Combat", "hp": 20, "max_hp": 20, "damage": 20, "dead": false},
{"_type": "Motion", "dx": 0, "dy": 0, "random": false}, {"_type": "Animation", "easing": 2, "ease_rate": 0.2, "scale": 0.2, "simple": false, "frames": 2, "speed": 0.02, "scale": 0.2},
{"_type": "EnemyConfig", "hearing_distance": 3}, {"_type": "Sprite", "name": "rat_king_boss", "width": 720, "height": 720, "scale": 0.8},
{"_type": "Animation", "easing": 2, "ease_rate": 0.2, "scale": 0.2, "simple": false, "frames": 2, "speed": 0.02},
{"_type": "Sprite", "name": "rat_king_boss", "width": 720, "height": 720},
{"_type": "Sound", "attack": "Marmot_Scream_1", "death": "Creature_Death_1"} {"_type": "Sound", "attack": "Marmot_Scream_1", "death": "Creature_Death_1"}
] ]
} }

@ -14,7 +14,7 @@
{"_type": "Device", {"_type": "Device",
"config": {"test": true}, "config": {"test": true},
"events": ["Events::GUI::STAIRS_DOWN"]}, "events": ["Events::GUI::STAIRS_DOWN"]},
{"_type": "Sprite", "name": "well_down", "width": 256, "height": 256} {"_type": "Sprite", "name": "well_down", "width": 256, "height": 256, "scale": 1.0}
] ]
}, },
"STAIRS_UP": { "STAIRS_UP": {
@ -31,7 +31,7 @@
{"_type": "Device", {"_type": "Device",
"config": {"test": true}, "config": {"test": true},
"events": ["Events::GUI::STAIRS_UP"]}, "events": ["Events::GUI::STAIRS_UP"]},
{"_type": "Sprite", "name": "rope_vines_up", "width": 256, "height": 256} {"_type": "Sprite", "name": "rope_vines_up", "width": 256, "height": 256, "scale": 1.0}
] ]
}, },
"TRIPWIRE_TRAP": { "TRIPWIRE_TRAP": {
@ -47,7 +47,7 @@
{"_type": "Device", {"_type": "Device",
"config": {"test": true}, "config": {"test": true},
"events": ["Events::GUI::TRAP"]}, "events": ["Events::GUI::TRAP"]},
{"_type": "Sprite", "name": "tripwire_trap", "width": 256, "height": 256} {"_type": "Sprite", "name": "tripwire_trap", "width": 256, "height": 256, "scale": 1.0}
] ]
} }
} }

@ -21,7 +21,7 @@
{"_type": "Motion", "dx": 0, "dy": 0, "random": false}, {"_type": "Motion", "dx": 0, "dy": 0, "random": false},
{"_type": "EnemyConfig", "hearing_distance": 5}, {"_type": "EnemyConfig", "hearing_distance": 5},
{"_type": "Animation", "easing": 1, "ease_rate": 0.2, "scale": 0.1, "simple": true, "frames": 10, "speed": 0.3}, {"_type": "Animation", "easing": 1, "ease_rate": 0.2, "scale": 0.1, "simple": true, "frames": 10, "speed": 0.3},
{"_type": "Sprite", "name": "armored_knight", "width": 256, "height": 256, "width": 256, "height": 256}, {"_type": "Sprite", "name": "armored_knight", "width": 256, "height": 256, "width": 256, "height": 256, "scale": 1.0},
{"_type": "Sound", "attack": "Sword_Hit_2", "death": "Humanoid_Death_1"} {"_type": "Sound", "attack": "Sword_Hit_2", "death": "Humanoid_Death_1"}
] ]
}, },
@ -34,25 +34,11 @@
{"_type": "Combat", "hp": 40, "max_hp": 40, "damage": 10, "dead": false}, {"_type": "Combat", "hp": 40, "max_hp": 40, "damage": 10, "dead": false},
{"_type": "Motion", "dx": 0, "dy": 0, "random": true}, {"_type": "Motion", "dx": 0, "dy": 0, "random": true},
{"_type": "EnemyConfig", "hearing_distance": 5}, {"_type": "EnemyConfig", "hearing_distance": 5},
{"_type": "Sprite", "name": "axe_ranger", "width": 256, "height": 256}, {"_type": "Sprite", "name": "axe_ranger", "width": 256, "height": 256, "scale": 1.0},
{"_type": "Animation", "easing": 3, "ease_rate": 0.5, "scale": 0.1, "simple": false, "frames": 2, "speed": 0.6}, {"_type": "Animation", "easing": 3, "ease_rate": 0.5, "scale": 0.1, "simple": false, "frames": 2, "speed": 0.6},
{"_type": "Sound", "attack": "Sword_Hit_2", "death": "Ranger_1"} {"_type": "Sound", "attack": "Sword_Hit_2", "death": "Ranger_1"}
] ]
}, },
"EVIL_EYE": {
"components": [
{"_type": "Tile", "display": "\u0758",
"foreground": [205, 164, 246],
"background": [30, 20, 75]
},
{"_type": "Combat", "hp": 50, "max_hp": 50, "damage": 50, "dead": false},
{"_type": "Motion", "dx": 0, "dy": 0, "random": false},
{"_type": "EnemyConfig", "hearing_distance": 5},
{"_type": "Sprite", "name": "evil_eye", "width": 256, "height": 256},
{"_type": "Animation", "easing": 3, "ease_rate": 0.1, "scale": 0.1, "simple": false, "frames": 2, "speed": 0.1},
{"_type": "Sound", "attack": "Evil_Eye_Sound_2", "death": "Evil_Eye_Sound_1"}
]
},
"RAT_GIANT": { "RAT_GIANT": {
"components": [ "components": [
{"_type": "Tile", "display": "\u08ac", {"_type": "Tile", "display": "\u08ac",
@ -63,7 +49,7 @@
{"_type": "Motion", "dx": 0, "dy": 0, "random": false}, {"_type": "Motion", "dx": 0, "dy": 0, "random": false},
{"_type": "EnemyConfig", "hearing_distance": 10}, {"_type": "EnemyConfig", "hearing_distance": 10},
{"_type": "Animation", "easing": 3, "ease_rate": 0.5, "scale": 0.1, "simple": true, "frames": 10, "speed": 1.0}, {"_type": "Animation", "easing": 3, "ease_rate": 0.5, "scale": 0.1, "simple": true, "frames": 10, "speed": 1.0},
{"_type": "Sprite", "name": "rat_with_sword", "width": 256, "height": 256}, {"_type": "Sprite", "name": "rat_with_sword", "width": 256, "height": 256, "scale": 1.0},
{"_type": "Sound", "attack": "Small_Rat", "death": "Creature_Death_1"} {"_type": "Sound", "attack": "Small_Rat", "death": "Creature_Death_1"}
] ]
}, },
@ -77,7 +63,7 @@
{"_type": "Motion", "dx": 0, "dy": 0, "random": false}, {"_type": "Motion", "dx": 0, "dy": 0, "random": false},
{"_type": "EnemyConfig", "hearing_distance": 10}, {"_type": "EnemyConfig", "hearing_distance": 10},
{"_type": "Animation", "easing": 2, "ease_rate": 0.5, "scale": 0.1, "simple": true, "frames": 10, "speed": 1.0}, {"_type": "Animation", "easing": 2, "ease_rate": 0.5, "scale": 0.1, "simple": true, "frames": 10, "speed": 1.0},
{"_type": "Sprite", "name": "hairy_spider", "width": 256, "height": 256}, {"_type": "Sprite", "name": "hairy_spider", "width": 256, "height": 256, "scale": 1.0},
{"_type": "Sound", "attack": "Spider_1", "death": "Spider_2"} {"_type": "Sound", "attack": "Spider_1", "death": "Spider_2"}
] ]
} }

@ -10,7 +10,7 @@
"foreground": [24, 120, 189], "foreground": [24, 120, 189],
"background": [230,120, 120] "background": [230,120, 120]
}, },
{"_type": "Sprite", "name": "torch_horizontal_floor", "width": 256, "height": 256}, {"_type": "Sprite", "name": "torch_horizontal_floor", "width": 256, "height": 256, "scale": 1.0},
{"_type": "Sound", "attack": "pickup", "death": "blank"} {"_type": "Sound", "attack": "pickup", "death": "blank"}
] ]
}, },
@ -25,7 +25,7 @@
"foreground": [24, 120, 189], "foreground": [24, 120, 189],
"background": [24, 120, 189] "background": [24, 120, 189]
}, },
{"_type": "Sprite", "name": "cinqueda", "width": 256, "height": 256}, {"_type": "Sprite", "name": "cinqueda", "width": 256, "height": 256, "scale": 1.0},
{"_type": "Sound", "attack": "pickup", "death": "blank"} {"_type": "Sound", "attack": "pickup", "death": "blank"}
] ]
}, },
@ -39,7 +39,7 @@
"background": [150, 100, 189] "background": [150, 100, 189]
}, },
{"_type": "Loot", "amount": 10}, {"_type": "Loot", "amount": 10},
{"_type": "Sprite", "name": "barrel_small", "width": 256, "height": 256}, {"_type": "Sprite", "name": "barrel_small", "width": 256, "height": 256, "scale": 1.0},
{"_type": "Sound", "attack": "pickup", "death": "blank"} {"_type": "Sound", "attack": "pickup", "death": "blank"}
], ],
"inventory_count": 1 "inventory_count": 1
@ -55,7 +55,7 @@
"background": [24, 205, 210] "background": [24, 205, 210]
}, },
{"_type": "LightSource", "strength": 50, "radius": 2.8}, {"_type": "LightSource", "strength": 50, "radius": 2.8},
{"_type": "Sprite", "name": "torch_pillar", "width": 256, "height": 256}, {"_type": "Sprite", "name": "torch_pillar", "width": 256, "height": 256, "scale": 1.0},
{"_type": "Sound", "attack": "pickup", "death": "blank"} {"_type": "Sound", "attack": "pickup", "death": "blank"}
] ]
}, },
@ -70,7 +70,7 @@
"background": [255, 205, 189] "background": [255, 205, 189]
}, },
{"_type": "Curative", "hp": 20}, {"_type": "Curative", "hp": 20},
{"_type": "Sprite", "name": "healing_potion_small", "width": 256, "height": 256}, {"_type": "Sprite", "name": "healing_potion_small", "width": 256, "height": 256, "scale": 1.0},
{"_type": "Sound", "attack": "pickup", "death": "blank"} {"_type": "Sound", "attack": "pickup", "death": "blank"}
] ]
}, },
@ -85,7 +85,7 @@
"background": [24, 205, 189] "background": [24, 205, 189]
}, },
{"_type": "Loot", "amount": 10}, {"_type": "Loot", "amount": 10},
{"_type": "Sprite", "name": "grave_stone", "width": 256, "height": 256}, {"_type": "Sprite", "name": "grave_stone", "width": 256, "height": 256, "scale": 1.0},
{"_type": "Sound", "attack": "pickup", "death": "blank"} {"_type": "Sound", "attack": "pickup", "death": "blank"}
] ]
} }

@ -3,9 +3,10 @@
#include "sound.hpp" #include "sound.hpp"
namespace gui { namespace gui {
BossFightUI::BossFightUI(GameLevel level, std::string boss_name) using namespace guecs;
: $level(level),
$config($level.world->get_the<components::GameConfig>()), BossFightUI::BossFightUI(DinkyECS::World& world, std::string boss_name)
: $config(world.get_the<components::GameConfig>()),
$boss_name(boss_name) $boss_name(boss_name)
{ {
$status.position(0, 0, BOSS_VIEW_X, SCREEN_HEIGHT); $status.position(0, 0, BOSS_VIEW_X, SCREEN_HEIGHT);
@ -24,6 +25,7 @@ namespace gui {
"[overlay_13|overlay_14|overlay_16]"); "[overlay_13|overlay_14|overlay_16]");
$sounds = components::get<components::Sound>($config.bosses[boss_name]); $sounds = components::get<components::Sound>($config.bosses[boss_name]);
$combat = components::get<components::Combat>($config.bosses[boss_name]);
$weapon_hit_sound = $config.bosses[$boss_name]["weapon_sound"]; $weapon_hit_sound = $config.bosses[$boss_name]["weapon_sound"];
} }
@ -36,7 +38,7 @@ namespace gui {
$boss_image = textures::get($sprite_config.name); $boss_image = textures::get($sprite_config.name);
sf::IntRect frame_rect{{0,0},{$sprite_config.width,$sprite_config.height}}; sf::IntRect frame_rect{{0,0},{$sprite_config.width,$sprite_config.height}};
$boss_image.sprite->setTextureRect(frame_rect); $boss_image.sprite->setTextureRect(frame_rect);
$boss_image.sprite->setScale($scale); $boss_image.sprite->setScale({$sprite_config.scale, $sprite_config.scale});
auto bounds = $boss_image.sprite->getLocalBounds(); auto bounds = $boss_image.sprite->getLocalBounds();
auto bg_bounds = $boss_background.sprite->getLocalBounds(); auto bg_bounds = $boss_background.sprite->getLocalBounds();
@ -60,7 +62,7 @@ namespace gui {
[this, name](auto, auto){ fmt::println("STATUS: {}", name); } [this, name](auto, auto){ fmt::println("STATUS: {}", name); }
}); });
if(name == "main_status") { if(name == "main_status") {
$status.set<Textual>(button, {fmt::format("HP: {}", $boss_hp)}); $status.set<Textual>(button, {fmt::format("HP: {}", $combat.hp)});
} else { } else {
$status.set<Label>(button, {"Attack"}); $status.set<Label>(button, {"Attack"});
} }
@ -86,7 +88,7 @@ namespace gui {
void BossFightUI::bounce_boss(sf::RenderWindow& window) { void BossFightUI::bounce_boss(sf::RenderWindow& window) {
sf::IntRect frame_rect{{0,0},{$sprite_config.width,$sprite_config.height}}; sf::IntRect frame_rect{{0,0},{$sprite_config.width,$sprite_config.height}};
auto scale = $scale; sf::Vector2f scale{$sprite_config.scale, $sprite_config.scale};
$animation.step(scale, frame_rect); $animation.step(scale, frame_rect);
$boss_image.sprite->setScale(scale); $boss_image.sprite->setScale(scale);
@ -111,7 +113,7 @@ namespace gui {
window.draw(*$boss_image.sprite); window.draw(*$boss_image.sprite);
} }
if($boss_hp == 0) { if($combat.hp == 0) {
$overlay.show_label("overlay_1", "YOU WON!"); $overlay.show_label("overlay_1", "YOU WON!");
$overlay.show_label("overlay_4", "CLICK TO CONTINUE..."); $overlay.show_label("overlay_4", "CLICK TO CONTINUE...");
} }
@ -129,18 +131,9 @@ namespace gui {
$animation.play(); $animation.play();
sound::play("Sword_Hit_1"); sound::play("Sword_Hit_1");
$boss_hit = !$boss_hit; $boss_hit = !$boss_hit;
$boss_hp--; $combat.hp--;
} }
return false; return false;
} }
void BossFightUI::update_level(GameLevel &level) {
$level = level;
$boss_hp = 10 * $level.index + 1; // make him stronger
$boss_hit = false;
$overlay.close<Label>("overlay_1");
$overlay.close<Label>("overlay_4");
init();
}
} }

@ -1,5 +1,4 @@
#pragma once #pragma once
#include "levelmanager.hpp"
#include <SFML/Graphics/RenderWindow.hpp> #include <SFML/Graphics/RenderWindow.hpp>
#include <SFML/Graphics/Font.hpp> #include <SFML/Graphics/Font.hpp>
#include "guecs.hpp" #include "guecs.hpp"
@ -14,20 +13,17 @@
// Side panel = 300/1080 // Side panel = 300/1080
namespace gui { namespace gui {
using namespace guecs;
using std::string; using std::string;
class BossFightUI { class BossFightUI {
public: public:
sf::Clock $clock; sf::Clock $clock;
int $boss_hp = 10;
bool $boss_hit = false; bool $boss_hit = false;
sf::Vector2f $scale{0.8, 0.8};
std::string $weapon_hit_sound; std::string $weapon_hit_sound;
components::Combat $combat;
components::Sprite $sprite_config; components::Sprite $sprite_config;
components::Sound $sounds; components::Sound $sounds;
components::Animation $animation; components::Animation $animation;
GameLevel $level;
components::GameConfig& $config; components::GameConfig& $config;
std::string $boss_name; std::string $boss_name;
guecs::UI $status; guecs::UI $status;
@ -35,14 +31,13 @@ namespace gui {
textures::SpriteTexture $boss_image; textures::SpriteTexture $boss_image;
textures::SpriteTexture $boss_background; textures::SpriteTexture $boss_background;
BossFightUI(GameLevel level, std::string boss_name); BossFightUI(DinkyECS::World& world, std::string boss_name);
void init(); void init();
void render(sf::RenderWindow& window); void render(sf::RenderWindow& window);
bool mouse(float x, float y); bool mouse(float x, float y);
void bounce_boss(sf::RenderWindow& window); void bounce_boss(sf::RenderWindow& window);
bool boss_dead() { return $boss_hp < 0; } bool boss_dead() { return $combat.hp < 0; }
void update_level(GameLevel& level);
void configure_sprite(); void configure_sprite();
void configure_background(); void configure_background();
void configure_gui(); void configure_gui();

@ -94,6 +94,7 @@ namespace components {
string name; string name;
int width; int width;
int height; int height;
float scale;
}; };
struct Sound { struct Sound {
@ -121,7 +122,7 @@ namespace components {
template <typename T> struct NameOf; template <typename T> struct NameOf;
ENROLL_COMPONENT(Tile, display, foreground, background); ENROLL_COMPONENT(Tile, display, foreground, background);
ENROLL_COMPONENT(Sprite, name, width, height); ENROLL_COMPONENT(Sprite, name, width, height, scale);
ENROLL_COMPONENT(Curative, hp); ENROLL_COMPONENT(Curative, hp);
ENROLL_COMPONENT(LightSource, strength, radius); ENROLL_COMPONENT(LightSource, strength, radius);
ENROLL_COMPONENT(Weapon, damage); ENROLL_COMPONENT(Weapon, damage);

@ -20,7 +20,6 @@ namespace gui {
$map_ui($level), $map_ui($level),
$combat_ui($level), $combat_ui($level),
$status_ui($level), $status_ui($level),
$boss_fight_ui($level, "RAT_KING"),
$font{FONT_FILE_NAME} $font{FONT_FILE_NAME}
{ {
} }
@ -50,7 +49,9 @@ namespace gui {
$status_ui.init(); $status_ui.init();
$status_ui.log("Welcome to the game!"); $status_ui.log("Welcome to the game!");
$status_ui.update(); $status_ui.update();
$boss_fight_ui.init();
$boss_fight_ui = $levels.create_bossfight($level.world);
$boss_fight_ui->init();
$renderer.init_terminal(); $renderer.init_terminal();
$map_ui.create_render(); $map_ui.create_render();
@ -249,9 +250,9 @@ namespace gui {
if(mouse->button == sf::Mouse::Button::Left) { if(mouse->button == sf::Mouse::Button::Left) {
sf::Vector2f pos = $window.mapPixelToCoords(mouse->position); sf::Vector2f pos = $window.mapPixelToCoords(mouse->position);
if(in_state(State::NEXT_LEVEL)) { if(in_state(State::NEXT_LEVEL)) {
$boss_fight_ui.mouse(pos.x, pos.y); $boss_fight_ui->mouse(pos.x, pos.y);
if($boss_fight_ui.boss_dead()) { if($boss_fight_ui->boss_dead()) {
event(Event::STAIRS_DOWN); event(Event::STAIRS_DOWN);
} }
} else { } else {
@ -315,7 +316,7 @@ namespace gui {
void FSM::draw_gui() { void FSM::draw_gui() {
if(in_state(State::NEXT_LEVEL)) { if(in_state(State::NEXT_LEVEL)) {
$boss_fight_ui.render($window); $boss_fight_ui->render($window);
} else { } else {
$main_ui.render(); $main_ui.render();
$status_ui.render($window); $status_ui.render($window);
@ -330,7 +331,7 @@ namespace gui {
$renderer.draw($map_ui); $renderer.draw($map_ui);
} else if(in_state(State::NEXT_LEVEL)) { } else if(in_state(State::NEXT_LEVEL)) {
$window.clear(); $window.clear();
$boss_fight_ui.render($window); $boss_fight_ui->render($window);
} else { } else {
draw_gui(); draw_gui();
} }
@ -422,7 +423,8 @@ namespace gui {
$combat_ui.update_level($level); $combat_ui.update_level($level);
$map_ui.update_level($level); $map_ui.update_level($level);
$main_ui.update_level($level); $main_ui.update_level($level);
$boss_fight_ui.update_level($level); $boss_fight_ui = $levels.create_bossfight($level.world);
$boss_fight_ui->init();
run_systems(); run_systems();
} }

@ -52,10 +52,10 @@ namespace gui {
MainUI $main_ui; MainUI $main_ui;
SFMLRender $renderer; SFMLRender $renderer;
GameLevel $level; GameLevel $level;
shared_ptr<BossFightUI> $boss_fight_ui = nullptr;
MapViewUI $map_ui; MapViewUI $map_ui;
CombatUI $combat_ui; CombatUI $combat_ui;
StatusUI $status_ui; StatusUI $status_ui;
BossFightUI $boss_fight_ui;
sf::Font $font; sf::Font $font;
FSM(); FSM();

@ -21,6 +21,11 @@ LevelScaling LevelManager::scale_level() {
}; };
} }
shared_ptr<gui::BossFightUI> LevelManager::create_bossfight(shared_ptr<DinkyECS::World> prev_world) {
dbc::check(prev_world != nullptr, "Starter world for boss fights can't be null.");
return make_shared<gui::BossFightUI>(*prev_world, "RAT_KING");
}
size_t LevelManager::create_level(shared_ptr<DinkyECS::World> prev_world) { size_t LevelManager::create_level(shared_ptr<DinkyECS::World> prev_world) {
auto world = make_shared<DinkyECS::World>(); auto world = make_shared<DinkyECS::World>();

@ -7,6 +7,7 @@
#include <memory> #include <memory>
#include "spatialmap.hpp" #include "spatialmap.hpp"
#include "components.hpp" #include "components.hpp"
#include "boss_fight_ui.hpp"
using std::shared_ptr; using std::shared_ptr;
@ -32,6 +33,7 @@ class LevelManager {
LevelManager(); LevelManager();
shared_ptr<gui::BossFightUI> create_bossfight(shared_ptr<DinkyECS::World> prev_world);
size_t create_level(shared_ptr<DinkyECS::World> prev_world = nullptr); size_t create_level(shared_ptr<DinkyECS::World> prev_world = nullptr);
GameLevel &next(); GameLevel &next();
GameLevel &previous(); GameLevel &previous();

@ -153,7 +153,7 @@ namespace gui {
} }
void MainUI::dead_entity(DinkyECS::Entity entity) { void MainUI::dead_entity(DinkyECS::Entity entity) {
auto &sprite = $level.world->get<Sprite>(entity); auto &sprite = $level.world->get<components::Sprite>(entity);
$rayview.update_sprite(entity, sprite); $rayview.update_sprite(entity, sprite);
} }

Loading…
Cancel
Save