diff options
Diffstat (limited to 'frontend')
-rw-r--r-- | frontend/CMakeLists.txt | 3 | ||||
-rw-r--r-- | frontend/Exception.cpp | 30 | ||||
-rw-r--r-- | frontend/Exception.h | 17 | ||||
-rw-r--r-- | frontend/cmd/view.cpp | 9 | ||||
-rw-r--r-- | frontend/generate_dungeon.cpp | 55 | ||||
-rw-r--r-- | frontend/generate_dungeon.h | 8 | ||||
-rw-r--r-- | frontend/load_dungeon.cpp | 78 | ||||
-rw-r--r-- | frontend/load_dungeon.h | 8 | ||||
-rw-r--r-- | frontend/main.cpp | 32 |
9 files changed, 229 insertions, 11 deletions
diff --git a/frontend/CMakeLists.txt b/frontend/CMakeLists.txt index ef64ee2..60b830c 100644 --- a/frontend/CMakeLists.txt +++ b/frontend/CMakeLists.txt @@ -4,6 +4,9 @@ target_sources(main PUBLIC strings.cpp print.cpp Player.cpp + load_dungeon.cpp + generate_dungeon.cpp + Exception.cpp ) add_subdirectory(cmd) diff --git a/frontend/Exception.cpp b/frontend/Exception.cpp new file mode 100644 index 0000000..423f4e9 --- /dev/null +++ b/frontend/Exception.cpp @@ -0,0 +1,30 @@ +#include <cstdarg> +#include <cstdio> +#include <cstdlib> + +#include "Exception.h" + +using namespace std; + +const char * Exception::what() { + return error.get(); +} + +void Exception::va_format(va_list args, const char * fmt) { + va_list args_copy; + va_copy(args_copy, args); + size_t sz = vsnprintf(NULL, 0, fmt, args_copy) + 1; + va_end(args_copy); + + this->error = unique_ptr<char>(static_cast<char *>(malloc(sz))); + + vsnprintf(this->error.get(), sz, fmt, args); +} + +Exception::Exception(const char * fmt, ...) { + va_list args; + va_start(args, fmt); + va_format(args, fmt); + va_end(args); +} + diff --git a/frontend/Exception.h b/frontend/Exception.h new file mode 100644 index 0000000..633cb4f --- /dev/null +++ b/frontend/Exception.h @@ -0,0 +1,17 @@ +#pragma once + +#include <cstdarg> +#include <exception> +#include <memory> + +class Exception : public std::exception { +public: + Exception(const char * fmt, ...); + const char * what(); + +protected: + Exception() = default; + void va_format(va_list args, const char * fmt); + std::unique_ptr<char> error = NULL; +}; + diff --git a/frontend/cmd/view.cpp b/frontend/cmd/view.cpp index 8b08a2c..7998a4a 100644 --- a/frontend/cmd/view.cpp +++ b/frontend/cmd/view.cpp @@ -7,6 +7,15 @@ FollowupAction Player::cmd_view(Argv argv) { return FollowupAction::NONE; } + if (argv[0] == "Zelf") { + lprtf("Je hebt %d levenspunten.\n", this->health_points); + lprtf("Je hebt een aanvalskans van %.0f%%.\n", this->attack_chance * 100); + // TODO: weapon + // TODO: armor + // TODO: gold + // TODO: inventory + } + return FollowupAction::NONE; } diff --git a/frontend/generate_dungeon.cpp b/frontend/generate_dungeon.cpp new file mode 100644 index 0000000..c6ddcbf --- /dev/null +++ b/frontend/generate_dungeon.cpp @@ -0,0 +1,55 @@ +#include <memory> +#include <functional> +#include <sqlite3.h> + +#include "backend/Dungeon.h" + +#include "generate_dungeon.h" +#include "Exception.h" + +using namespace std; + +class DB { + typedef unique_ptr<sqlite3, function<void(sqlite3*)>> unique_sqlite3; + typedef unique_ptr<sqlite3_stmt, function<void(sqlite3_stmt*)>> unique_sqlite3_stmt; + +public: + DB(const string & path) { + sqlite3 * db = NULL; + int ret = sqlite3_open_v2(path.c_str(), &db, SQLITE_OPEN_READONLY, NULL); + this->db = { + db, + [] (sqlite3 * db) { + sqlite3_close_v2(db); + }, + }; + if (ret != SQLITE_OK) + throw Exception("sqlite3_open_v2"); + } + + unique_sqlite3_stmt prepare(const string & query) { + sqlite3_stmt * stmt = NULL; + int ret = sqlite3_prepare_v2(this->db.get(), query.c_str(), query.size(), &stmt, NULL); + unique_sqlite3_stmt uniq_stmt = { + stmt, + [] (sqlite3_stmt * stmt) { + sqlite3_finalize(stmt); + }, + }; + if (ret != SQLITE_OK) + throw Exception("sqlite3_prepare_v2"); + return uniq_stmt; + } + +private: + unique_sqlite3 db = NULL; +}; + +unique_ptr<Dungeon> generate_dungeon() { + unique_ptr<Dungeon> dungeon = make_unique<Dungeon>(); + + DB db { "kerkersendraken.db" }; + + return dungeon; +} + diff --git a/frontend/generate_dungeon.h b/frontend/generate_dungeon.h new file mode 100644 index 0000000..6252c83 --- /dev/null +++ b/frontend/generate_dungeon.h @@ -0,0 +1,8 @@ +#pragma once + +#include <memory> + +class Dungeon; + +std::unique_ptr<Dungeon> generate_dungeon(); + diff --git a/frontend/load_dungeon.cpp b/frontend/load_dungeon.cpp new file mode 100644 index 0000000..ef8cb54 --- /dev/null +++ b/frontend/load_dungeon.cpp @@ -0,0 +1,78 @@ +#include <memory> +#include <filesystem> +#include <pugixml.hpp> +#include <map> + +#include "backend/Location.h" +#include "backend/LocationFactory.h" +#include "backend/Dungeon.h" + +#include "load_dungeon.h" +#include "Exception.h" +#include "frontend/strings.h" + +using namespace std; +using namespace pugi; + +unique_ptr<Dungeon> load_dungeon(const string & filename) { + unique_ptr<Dungeon> dungeon = make_unique<Dungeon>(); + + xml_document doc; + + string canonical = filename; + if (canonical.starts_with("~/")) + canonical = getenv("HOME") + canonical.substr(1); + try { + canonical = filesystem::canonical(canonical); + } catch (...) { + throw Exception("Kon bestand niet vinden"); + } + + xml_parse_result result = doc.load_file(canonical.c_str()); + if (!result) + throw Exception("Kon XML-bestand niet lezen"); + + xml_node locations = doc.child("locaties"); + if (!locations) + throw Exception("XML-bestand mist een <locaties> tag"); + + LocationFactory factory; + struct TempData { + Location * location; + unsigned edges[4]; + }; + map<unsigned, TempData> temp_map; + for (xml_node & tag : locations) { + const char * name = tag.text().as_string(); + const char * description = tag.child("beschrijving").text().as_string(); + + // vector<string> objects_hidden = split_string(tag.attribute("objectenverborgen").as_string(), ";"); + // vector<string> objects_visible = split_string(tag.attribute("objectenzichtbaar").as_string(), ";"); + // vector<string> enemies = split_string(tag.attribute("vijand").as_string(), ";"); + + Location * location = factory.create_location(name, description); + temp_map[tag.attribute("id").as_uint()] = { + .location = location, + .edges = { + tag.attribute("noord").as_uint(0), + tag.attribute("oost").as_uint(0), + tag.attribute("zuid").as_uint(0), + tag.attribute("west").as_uint(0), + }, + }; + dungeon->add_location(location); + } + + // connect edges after creating all locations + for (auto & [here, temp] : temp_map) { + for (Direction direction : { NORTH, EAST, SOUTH, WEST }) { + unsigned there = temp.edges[direction]; + if (temp.edges[direction] == 0) continue; + if (!temp_map.contains(there)) continue; + temp.location->set_exit(direction, temp_map[there].location); + } + } + + return dungeon; +} + diff --git a/frontend/load_dungeon.h b/frontend/load_dungeon.h new file mode 100644 index 0000000..4eff4cf --- /dev/null +++ b/frontend/load_dungeon.h @@ -0,0 +1,8 @@ +#pragma once + +#include <memory> + +class Dungeon; + +std::unique_ptr<Dungeon> load_dungeon(const std::string & filename); + diff --git a/frontend/main.cpp b/frontend/main.cpp index b9322ee..c421d9e 100644 --- a/frontend/main.cpp +++ b/frontend/main.cpp @@ -3,25 +3,35 @@ #include <memory> #include "backend/Dungeon.h" -#include "Player.h" +#include "Player.h" +#include "Exception.h" +#include "frontend/print.h" +#include "load_dungeon.h" +#include "generate_dungeon.h" #include "rl.h" #include "strings.h" -#include "print.h" using namespace std; -FollowupAction game_main() { - auto dungeon = make_unique<Dungeon>(); - - print_string(strings::INTRO); - string filename = rl(); - if (filename.size() == 0) { - lprtf("TODO: generate dungeon\n"); - } else { - lprtf("TODO: load %s\n", filename.c_str()); +static unique_ptr<Dungeon> make_dungeon() noexcept { + while (1) { + print_string(strings::INTRO); + string filename = rl(); + try { + if (filename.size() == 0) { + return generate_dungeon(); + } else { + return load_dungeon(filename); + } + } catch (Exception & e) { + lprtf("FOUT: %s\n", e.what()); + } } +} +FollowupAction game_main() { + unique_ptr<Dungeon> dungeon = make_dungeon(); Player player { *dungeon }; while (1) { |