#include "game/levels/level_manager.hpp" #include #include #include #include "core/resources/resource_helper.hpp" #include "external/fkyaml_node.hpp" #include "utils/defaults.hpp" #include "utils/log.hpp" namespace Levels { auto LevelManager::get() -> LevelManager& { static LevelManager instance_; return instance_; } LevelManager::LevelManager() { loadIndex(); } void LevelManager::loadIndex() { const std::string PATH = Defaults::Pyramid::LEVELS_YAML; auto bytes = Resource::Helper::loadFile(PATH); if (bytes.empty()) { throw std::runtime_error("LevelManager: no s'ha pogut obrir " + PATH); } const auto* begin = reinterpret_cast(bytes.data()); const auto* end = begin + bytes.size(); auto yaml = fkyaml::node::deserialize(begin, end); if (!yaml.contains("sequence") || !yaml["sequence"].is_sequence()) { throw std::runtime_error("LevelManager: manca o és invàlid `sequence:` a " + PATH); } const auto& seq = yaml["sequence"]; entries_.clear(); entries_.reserve(seq.size()); for (const auto& e : seq) { Entry entry{ .pyramid = e["pyramid"].get_value(), .room = e["room"].get_value(), .file = e["file"].get_value(), }; entries_.push_back(std::move(entry)); } if (entries_.empty()) { throw std::runtime_error("LevelManager: la seqüència de " + PATH + " és buida"); } index_ = 0; Log::info("LevelManager", "{} sales carregades de {} (començant a {})", entries_.size(), PATH, currentLabel()); } auto LevelManager::currentPath() const -> const std::string& { return entries_[index_].file; } auto LevelManager::currentPyramid() const -> int { return entries_[index_].pyramid; } auto LevelManager::currentRoom() const -> int { return entries_[index_].room; } auto LevelManager::currentLabel() const -> std::string { return "P" + std::to_string(currentPyramid()) + "-R" + std::to_string(currentRoom()); } auto LevelManager::index() const -> int { return index_; } auto LevelManager::count() const -> int { return static_cast(entries_.size()); } auto LevelManager::advance() -> bool { if (index_ + 1 >= count()) { return false; } ++index_; Log::info("LevelManager", "avança a {} ({})", currentLabel(), currentPath()); return true; } void LevelManager::restart() { index_ = 0; Log::info("LevelManager", "restart a {}", currentLabel()); } void LevelManager::setIndex(int new_index) { const int CLAMPED = std::clamp(new_index, 0, count() - 1); if (CLAMPED != index_) { index_ = CLAMPED; Log::info("LevelManager", "setIndex({}) → {} ({})", new_index, currentLabel(), currentPath()); } } auto LevelManager::setStartingPoint(int pyramid, int room) -> bool { for (std::size_t i = 0; i < entries_.size(); ++i) { if (entries_[i].pyramid == pyramid && entries_[i].room == room) { index_ = static_cast(i); Log::info("LevelManager", "starting_point P{}-R{} trobat a l'índex {} ({})", pyramid, room, i, currentPath()); return true; } } Log::warn("LevelManager", "starting_point P{}-R{} no trobat a levels.yaml — es manté l'índex actual ({})", pyramid, room, currentLabel()); return false; } } // namespace Levels