The attack is now fully configurable in attacks.json and the name for each attack is generated from the ritual crafting.
This commit is contained in:
parent
adcfbb883e
commit
09b61f17a7
11 changed files with 77 additions and 45 deletions
28
assets/attacks.json
Normal file
28
assets/attacks.json
Normal file
|
|
@ -0,0 +1,28 @@
|
|||
{
|
||||
"MAGICK_FIRE": {
|
||||
"animation": "burning_animation",
|
||||
"shader": "flame",
|
||||
"components": [
|
||||
{"_type": "Sprite", "name": "burning_animation", "scale": 1.0},
|
||||
{"_type": "LightSource", "strength": 25, "radius": 2.0},
|
||||
{"_type": "Temporary", "is": true}
|
||||
]
|
||||
},
|
||||
"MAGICK_LIGHTNING": {
|
||||
"animation": "lightning_animation",
|
||||
"shader": "lightning",
|
||||
"components": [
|
||||
{"_type": "Sprite", "name": "lightning_animation", "scale": 1.0},
|
||||
{"_type": "LightSource", "strength": 35, "radius": 2.5},
|
||||
{"_type": "Temporary", "is": true}
|
||||
]
|
||||
},
|
||||
"PHYSICAL_NONE": {
|
||||
"animation": "lightning_animation",
|
||||
"shader": "flame",
|
||||
"components": [
|
||||
{"_type": "Sprite", "name": "lightning_animation", "scale": 1.0},
|
||||
{"_type": "Temporary", "is": true}
|
||||
]
|
||||
}
|
||||
}
|
||||
|
|
@ -6,12 +6,12 @@
|
|||
"foreground": "enemies/fg:player",
|
||||
"background": "color:transparent"
|
||||
},
|
||||
{"_type": "Combat", "hp": 200, "max_hp": 200, "ap": 0, "max_ap": 12, "ap_delta": 6, "damage": 50, "dead": false, "attack_rating": 0.60, "toughness_rating": 0.0},
|
||||
{"_type": "Combat", "hp": 200, "max_hp": 200, "ap": 0, "max_ap": 12, "ap_delta": 6, "damage": 500, "dead": false, "attack_rating": 1.0, "toughness_rating": 0.0},
|
||||
{"_type": "Motion", "dx": 0, "dy": 0, "random": false},
|
||||
{"_type": "Collision", "has": true},
|
||||
{"_type": "EnemyConfig", "ai_script": "Host::actions", "ai_start_name": "Host::initial_state", "ai_goal_name": "Host::final_state"},
|
||||
{"_type": "Personality", "hearing_distance": 5, "tough": false},
|
||||
{"_type": "LightSource", "strength": 35, "radius": 2.0}
|
||||
{"_type": "LightSource", "strength": 20, "radius": 1.0}
|
||||
]
|
||||
},
|
||||
"GOLD_SAVIOR": {
|
||||
|
|
|
|||
|
|
@ -30,6 +30,7 @@ namespace components {
|
|||
components::enroll<Sprite>(MAP);
|
||||
components::enroll<Sound>(MAP);
|
||||
components::enroll<Collision>(MAP);
|
||||
components::enroll<Temporary>(MAP);
|
||||
MAP_configured = true;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -74,6 +74,7 @@ namespace components {
|
|||
settings::Config rituals;
|
||||
settings::Config stories;
|
||||
settings::Config scenes;
|
||||
settings::Config attacks;
|
||||
};
|
||||
|
||||
struct Personality {
|
||||
|
|
@ -174,6 +175,7 @@ namespace components {
|
|||
ENROLL_COMPONENT(Storyboard, image, audio, layout, beats);
|
||||
ENROLL_COMPONENT(Sound, attack, death);
|
||||
ENROLL_COMPONENT(Collision, has);
|
||||
ENROLL_COMPONENT(Temporary, is);
|
||||
|
||||
template<typename COMPONENT> COMPONENT convert(nlohmann::json &data) {
|
||||
COMPONENT result;
|
||||
|
|
|
|||
|
|
@ -130,6 +130,7 @@ namespace GameDB {
|
|||
}
|
||||
|
||||
void load_configs(DinkyECS::World &world) {
|
||||
// TODO: Could have a simple meta-config file that loads these....
|
||||
world.set_the<GameConfig>({
|
||||
settings::get("config"),
|
||||
settings::get("enemies"),
|
||||
|
|
@ -139,7 +140,8 @@ namespace GameDB {
|
|||
settings::get("bosses"),
|
||||
settings::get("rituals"),
|
||||
settings::get("stories"),
|
||||
settings::get("scenes")
|
||||
settings::get("scenes"),
|
||||
settings::get("attacks")
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
#include "game/rituals.hpp"
|
||||
#include "ai/ai_debug.hpp"
|
||||
#include "ai/ai.hpp"
|
||||
#include <magic_enum/magic_enum.hpp>
|
||||
|
||||
namespace ritual {
|
||||
Engine::Engine(std::string config_path) :
|
||||
|
|
@ -129,6 +130,12 @@ namespace ritual {
|
|||
fmt::println("\n");
|
||||
}
|
||||
|
||||
std::string Action::name() {
|
||||
return fmt::format("{}_{}",
|
||||
magic_enum::enum_name(kind),
|
||||
magic_enum::enum_name(element));
|
||||
}
|
||||
|
||||
Action& Belt::get(int index) {
|
||||
return equipped.at(index);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -49,6 +49,7 @@ namespace ritual {
|
|||
std::vector<std::string> names;
|
||||
|
||||
void dump();
|
||||
std::string name();
|
||||
};
|
||||
|
||||
struct Engine {
|
||||
|
|
|
|||
|
|
@ -241,7 +241,7 @@ void System::death() {
|
|||
}
|
||||
}
|
||||
|
||||
void System::combat(int attack_id) {
|
||||
void System::combat(int belt_id) {
|
||||
auto& level = GameDB::current_level();
|
||||
auto& collider = *level.collision;
|
||||
auto& world = *level.world;
|
||||
|
|
@ -285,8 +285,9 @@ void System::combat(int attack_id) {
|
|||
.enemy_did=0
|
||||
};
|
||||
|
||||
// TODO: Need a "miss" animation/sound
|
||||
if(result.player_did > 0) {
|
||||
spawn_attack(world, attack_id, enemy.entity);
|
||||
spawn_attack(world, belt_id, enemy.entity);
|
||||
}
|
||||
|
||||
if(enemy_action == "kill_enemy") {
|
||||
|
|
@ -666,31 +667,34 @@ void System::clear_attack() {
|
|||
}
|
||||
}
|
||||
|
||||
void System::spawn_attack(World& world, int attack_id, DinkyECS::Entity enemy) {
|
||||
void System::spawn_attack(World& world, int belt_id, DinkyECS::Entity enemy) {
|
||||
auto& config = world.get_the<GameConfig>().attacks;
|
||||
|
||||
using enum ritual::Element; // for FIRE vs LIGHTNING
|
||||
auto& the_belt = world.get_the<ritual::Belt>();
|
||||
|
||||
dbc::check(the_belt.has(attack_id), "STOP passing invalid attack IDs to the system.");
|
||||
dbc::check(the_belt.has(belt_id), "STOP passing invalid attack IDs to the system.");
|
||||
|
||||
auto& ritual = the_belt.get(attack_id);
|
||||
auto& ritual = the_belt.get(belt_id);
|
||||
fmt::println("RITUAL NAME: {}", ritual.name());
|
||||
|
||||
auto effect = ritual.element == FIRE ? "burning_animation" : "lightning_animation";
|
||||
auto attack_id = world.entity();
|
||||
auto& attack_config = config[ritual.name()];
|
||||
|
||||
auto effect_id = world.entity();
|
||||
world.set<Sprite>(effect_id, {effect, 1.0f});
|
||||
world.set<Temporary>(effect_id, {true});
|
||||
components::configure_entity(world, attack_id, attack_config["components"]);
|
||||
|
||||
auto shader = shaders::get(ritual.element == FIRE ? "flame" : "lightning");
|
||||
world.set<SpriteEffect>(effect_id, {100, shader});
|
||||
auto shader = shaders::get(attack_config["shader"]);
|
||||
world.set<SpriteEffect>(attack_id, {100, shader});
|
||||
|
||||
// also add the same effect to the enemy
|
||||
world.set<SpriteEffect>(enemy, {50, shader});
|
||||
|
||||
auto anim = animation::load("assets/animation.json", effect);
|
||||
auto anim = animation::load("assets/animation.json", attack_config["animation"]);
|
||||
anim.play();
|
||||
world.set<animation::Animation>(effect_id, anim);
|
||||
world.set<animation::Animation>(attack_id, anim);
|
||||
|
||||
drop_item(effect_id);
|
||||
//BUG: THIS IS BULLSHIT! Should have a generic place item thing.
|
||||
drop_item(attack_id);
|
||||
}
|
||||
|
||||
void System::init(Registry& reg) {
|
||||
|
|
|
|||
|
|
@ -25,7 +25,7 @@ namespace System {
|
|||
void drop_item(Entity item);
|
||||
|
||||
void enemy_ai();
|
||||
void combat(int attack_id);
|
||||
void combat(int belt_id);
|
||||
|
||||
std::shared_ptr<sf::Shader> sprite_effect(Entity entity);
|
||||
void player_status();
|
||||
|
|
@ -70,7 +70,7 @@ namespace System {
|
|||
}
|
||||
|
||||
void clear_attack();
|
||||
void spawn_attack(World& world, int attack_id, DinkyECS::Entity enemy);
|
||||
void spawn_attack(World& world, int belt_id, DinkyECS::Entity enemy);
|
||||
void init(Registry& reg);
|
||||
void restart();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,4 +1,3 @@
|
|||
#define FSM_DEBUG 1
|
||||
#include "gui/fsm.hpp"
|
||||
#include <iostream>
|
||||
#include <chrono>
|
||||
|
|
@ -14,6 +13,7 @@
|
|||
#include "gui/guecstra.hpp"
|
||||
#include "game/level.hpp"
|
||||
#include "boss/system.hpp"
|
||||
#include <magic_enum/magic_enum.hpp>
|
||||
|
||||
namespace gui {
|
||||
using namespace components;
|
||||
|
|
@ -60,8 +60,6 @@ namespace gui {
|
|||
$map_ui.init();
|
||||
$map_ui.log(L"Welcome to the game!");
|
||||
|
||||
run_systems();
|
||||
|
||||
state(State::IDLE);
|
||||
}
|
||||
|
||||
|
|
@ -69,7 +67,6 @@ namespace gui {
|
|||
// this should be an optional that returns a point
|
||||
if(auto move_to = $main_ui.play_move()) {
|
||||
$systems.runMoving(*move_to);
|
||||
run_systems();
|
||||
$main_ui.dirty();
|
||||
state(State::IDLE);
|
||||
}
|
||||
|
|
@ -90,8 +87,6 @@ namespace gui {
|
|||
something_died(std::any_cast<DinkyECS::Entity>(data));
|
||||
break;
|
||||
case TICK:
|
||||
run_systems();
|
||||
|
||||
if(!$main_ui.hands_playing()) {
|
||||
// run combat one more time
|
||||
state(State::IDLE);
|
||||
|
|
@ -159,11 +154,7 @@ namespace gui {
|
|||
$map_open = !$map_open;
|
||||
break;
|
||||
case ATTACK:
|
||||
$main_ui.play_hands();
|
||||
$main_ui.dirty();
|
||||
$systems.runCombat(0);
|
||||
run_systems();
|
||||
$status_ui.update();
|
||||
play_attack(std::any_cast<int>(data));
|
||||
state(State::ATTACKING);
|
||||
break;
|
||||
case CLOSE:
|
||||
|
|
@ -238,7 +229,6 @@ namespace gui {
|
|||
auto& sprite = world->get<components::Sprite>(entity);
|
||||
$main_ui.$rayview->update_sprite(entity, sprite);
|
||||
$main_ui.dirty();
|
||||
run_systems();
|
||||
}
|
||||
|
||||
void FSM::something_died(DinkyECS::Entity entity) {
|
||||
|
|
@ -254,6 +244,13 @@ namespace gui {
|
|||
}
|
||||
}
|
||||
|
||||
void FSM::play_attack(int attack_id) {
|
||||
$main_ui.play_hands();
|
||||
$main_ui.dirty();
|
||||
$systems.runCombat(attack_id);
|
||||
$status_ui.update();
|
||||
}
|
||||
|
||||
void FSM::CUT_SCENE_PLAYING(Event ev, std::any data) {
|
||||
if($boss_scene->playing()) {
|
||||
if(ev == game::Event::MOUSE_CLICK) {
|
||||
|
|
@ -404,22 +401,18 @@ namespace gui {
|
|||
}
|
||||
|
||||
void FSM::update() {
|
||||
if(in_state(State::BOSS_FIGHT)) {
|
||||
$boss_fight->update();
|
||||
} else if(in_state(State::CUT_SCENE_PLAYING)) {
|
||||
$boss_scene->update();
|
||||
} else {
|
||||
// BUG: look at draw_gui for the update for here
|
||||
}
|
||||
$systems.runUpdate();
|
||||
}
|
||||
|
||||
void FSM::render() {
|
||||
$window.clear();
|
||||
|
||||
if(in_state(State::BOSS_FIGHT)) {
|
||||
$boss_fight->update();
|
||||
$boss_fight->render($window);
|
||||
// this clears any attack animations, like fire
|
||||
} else if(in_state(State::CUT_SCENE_PLAYING)) {
|
||||
$boss_scene->update();
|
||||
$boss_scene->render($window);
|
||||
} else {
|
||||
// this clears any attack animations, like fire
|
||||
|
|
@ -431,10 +424,6 @@ namespace gui {
|
|||
$window.display();
|
||||
}
|
||||
|
||||
void FSM::run_systems() {
|
||||
$systems.runUpdate();
|
||||
}
|
||||
|
||||
bool FSM::active() {
|
||||
return !in_state(State::END);
|
||||
}
|
||||
|
|
@ -487,7 +476,5 @@ namespace gui {
|
|||
$main_ui.update_level();
|
||||
$loot_ui.update_level();
|
||||
}
|
||||
|
||||
run_systems();
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -74,7 +74,6 @@ namespace gui {
|
|||
void update();
|
||||
void render();
|
||||
bool active();
|
||||
void run_systems();
|
||||
void handle_events();
|
||||
void handle_boss_fight_events();
|
||||
void next_level(bool bossfight);
|
||||
|
|
@ -82,5 +81,6 @@ namespace gui {
|
|||
void take_screenshot();
|
||||
void something_died(DinkyECS::Entity entity);
|
||||
void entity_spawned(DinkyECS::Entity entity);
|
||||
void play_attack(int attack_id);
|
||||
};
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue