#include "rituals.hpp" #include "ai_debug.hpp" #include "ai.hpp" namespace ritual { Engine::Engine(std::string config_path) : $config(config_path) { $profile = $config["profile"]; auto& actions = $config["actions"]; for(auto& ac : actions) { auto action = ai::config_action($profile, ac); $actions.insert_or_assign(action.name, action); } for(auto& [name, sc] : $config["states"].items()) { auto state = ai::config_state($profile, sc); $states.insert_or_assign(name, state); } auto& scripts = $config["scripts"]; for(auto& [script_name, action_names] : scripts.items()) { std::vector the_script; for(auto name : action_names) { the_script.push_back($actions.at(name)); } $scripts.insert_or_assign(script_name, the_script); } } ai::State Engine::load_state(std::string name) { return $states.at(name); } void Engine::load_junk(CraftingState& ritual, const JunkItem& item) { Config config("assets/rituals.json"); auto& junk = config["junk"]; auto& item_desc = junk[item]; fmt::print("Item {} provides: ", item); for(auto& effect : item_desc["provides"]) { fmt::print("{} ", (std::string)effect); set_state(ritual, effect, true); } fmt::print("\n"); } ai::Action Engine::load_action(std::string name) { return $actions.at(name); } CraftingState Engine::start() { auto start = load_state("initial"); auto goal = load_state("final"); return {"actions", start, goal}; } void Engine::set_state(CraftingState& ritual, std::string name, bool setting) { dbc::check($profile.contains(name), fmt::format("ritual action named {} is not in profile, look in {} config", name, $config.$src_path)); ritual.start.set($profile.at(name), setting); } void CraftingState::reset() { start = original; plan.complete = false; plan.script.clear(); } void Engine::plan(CraftingState& ritual) { ritual.plan = ai::plan_actions($scripts.at(ritual.script), ritual.start, ritual.goal); } bool CraftingState::will_do(std::string name) { if(plan.script.size() == 0) return false; return plan.script[0].name == name; } ai::Action CraftingState::pop() { auto result = plan.script.front(); plan.script.pop_front(); return result; } // BUG: maybe this should be called CraftingState instead? void CraftingState::dump() { ai::dump_script(script, start, plan.script); } bool CraftingState::is_combined() { // it's only combined if it has > 1 and last is combined if(plan.script.size() <= 1) return false; auto& last = plan.script.back(); return last.name == "combined"; } Action Engine::finalize(CraftingState& ritual) { (void)ritual; Action result; auto effects = $config["effects"]; for(auto action : ritual.plan.script) { if(effects.contains(action.name)) { auto& effect = effects[action.name]; result.damage += int(effect["damage"]); result.probability *= float(effect["probability"]); if(effect.contains("kind")) result.kind = Kind(int(effect["kind"])); if(effect.contains("element")) result.element = Element(int(effect["element"])); } } return result; } void Action::dump() { fmt::print("ritual has damage {}, prob: {}, kind: {}, element: {}; named: ", damage, probability, int(kind), int(element)); for(auto& name : names) { fmt::print("{} ", name); } fmt::println("\n"); } Action& Belt::get(int index) { return equipped.at(index); } void Belt::equip(int index, Action& action) { equipped.insert_or_assign(index, action); } bool Belt::has(int index) { return equipped.contains(index); } void Belt::unequip(int index) { equipped.erase(index); } int Belt::next() { int slot = next_slot % max_slots; next_slot++; return slot; } DinkyECS::Entity Blanket::add(JunkItem name) { DinkyECS::Entity id = ++entity_counter; contents.insert_or_assign(id, name); return id; } std::string& Blanket::get(DinkyECS::Entity ent) { return contents.at(ent); } bool Blanket::has(DinkyECS::Entity ent) { return contents.contains(ent); } void Blanket::remove(DinkyECS::Entity ent) { contents.erase(ent); } void Blanket::select(DinkyECS::Entity ent) { selected.insert_or_assign(ent, true); } void Blanket::deselect(DinkyECS::Entity ent) { selected.erase(ent); } bool Blanket::is_selected(DinkyECS::Entity ent) { return selected.contains(ent) && selected.at(ent); } void Blanket::reset() { selected.clear(); } bool Blanket::no_selections() { return selected.size() == 0; } void Blanket::consume_crafting() { for(auto [item_id, setting] : selected) { contents.erase(item_id); } } }