Nova clau opcional al debug.yaml:
starting_level: { pyramid: 2, room: 3 }
DebugConfig::resolveStartingLevel retorna optional<StartingLevel>; el
Director, abans de crear el GameScene, demana al LevelManager
setStartingPoint(pyramid, room) — que cerca l'entrada al levels.yaml
i hi posiciona l'índex. Si la clau no està (cas habitual) o
(pyramid, room) no existeix, la progressió arrenca a la primera sala
amb un avís a stderr. createDefaultIfMissing documenta la nova clau
sense escriure-la (la deixem opcional).
Drive-by: NOLINT puntual al capture de STARTING_PLAYERS al Director.
És pre-existent i s'ha activat ara perquè el commit toca director.cpp;
la captura és imprescindible en Debug (valor runtime), clang la veu
redundant en Release on és constexpr literal.
105 lines
3.8 KiB
C++
105 lines
3.8 KiB
C++
#include "game/levels/level_manager.hpp"
|
|
|
|
#include <algorithm>
|
|
#include <iostream>
|
|
#include <stdexcept>
|
|
#include <utility>
|
|
|
|
#include "core/resources/resource_helper.hpp"
|
|
#include "external/fkyaml_node.hpp"
|
|
#include "utils/defaults.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<const char*>(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<int>(),
|
|
.room = e["room"].get_value<int>(),
|
|
.file = e["file"].get_value<std::string>(),
|
|
};
|
|
entries_.push_back(std::move(entry));
|
|
}
|
|
if (entries_.empty()) {
|
|
throw std::runtime_error("LevelManager: la seqüència de " + PATH + " és buida");
|
|
}
|
|
index_ = 0;
|
|
std::cout << "LevelManager: " << entries_.size() << " sales carregades de "
|
|
<< PATH << " (començant a " << currentLabel() << ")\n";
|
|
}
|
|
|
|
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<int>(entries_.size()); }
|
|
|
|
auto LevelManager::advance() -> bool {
|
|
if (index_ + 1 >= count()) { return false; }
|
|
++index_;
|
|
std::cout << "LevelManager: avança a " << currentLabel()
|
|
<< " (" << currentPath() << ")\n";
|
|
return true;
|
|
}
|
|
|
|
void LevelManager::restart() {
|
|
index_ = 0;
|
|
std::cout << "LevelManager: restart a " << currentLabel() << '\n';
|
|
}
|
|
|
|
void LevelManager::setIndex(int new_index) {
|
|
const int CLAMPED = std::clamp(new_index, 0, count() - 1);
|
|
if (CLAMPED != index_) {
|
|
index_ = CLAMPED;
|
|
std::cout << "LevelManager: setIndex(" << new_index << ") → "
|
|
<< currentLabel() << " (" << currentPath() << ")\n";
|
|
}
|
|
}
|
|
|
|
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<int>(i);
|
|
std::cout << "LevelManager: starting_point P" << pyramid << "-R" << room
|
|
<< " trobat a l'índex " << i << " (" << currentPath() << ")\n";
|
|
return true;
|
|
}
|
|
}
|
|
std::cerr << "LevelManager: starting_point P" << pyramid << "-R" << room
|
|
<< " no trobat a levels.yaml — es manté l'índex actual ("
|
|
<< currentLabel() << ")\n";
|
|
return false;
|
|
}
|
|
|
|
} // namespace Levels
|