From b1d5d7936bed17a684daff15b0294ef70754e8b9 Mon Sep 17 00:00:00 2001 From: Loek Le Blansch Date: Wed, 30 Oct 2024 12:24:43 +0100 Subject: more more WIP --- backend/ArmorObject.cpp | 6 ++++++ backend/ArmorObject.h | 3 +++ backend/CMakeLists.txt | 4 ++++ backend/ConsumableObject.cpp | 3 +++ backend/GoldObject.cpp | 6 ++++++ backend/GoldObject.h | 3 +++ backend/ObjectFactory.cpp | 33 ++++++++++++++++++++++++++------- backend/ObjectFactory.h | 12 +++++++++++- backend/WeaponObject.cpp | 10 ++++++++++ backend/WeaponObject.h | 4 ++++ frontend/DB.cpp | 24 ++++++++++++++++++++---- frontend/DB.h | 4 +++- frontend/GameData.cpp | 35 +++++++++++++++++++++++++++++------ frontend/Player.h | 2 +- frontend/cmd/view.cpp | 7 ++++--- frontend/load_dungeon.cpp | 10 +++++----- 16 files changed, 138 insertions(+), 28 deletions(-) create mode 100644 backend/ArmorObject.cpp create mode 100644 backend/ConsumableObject.cpp create mode 100644 backend/GoldObject.cpp create mode 100644 backend/WeaponObject.cpp diff --git a/backend/ArmorObject.cpp b/backend/ArmorObject.cpp new file mode 100644 index 0000000..5b921fe --- /dev/null +++ b/backend/ArmorObject.cpp @@ -0,0 +1,6 @@ +#include "ArmorObject.h" + +void ArmorObject::set_protection(int protection) { + this->protection = protection; +} + diff --git a/backend/ArmorObject.h b/backend/ArmorObject.h index 112997b..a476740 100644 --- a/backend/ArmorObject.h +++ b/backend/ArmorObject.h @@ -5,6 +5,9 @@ class ArmorObject : public Object { using Object::Object; +public: + void set_protection(int protection); + private: int protection = 0; diff --git a/backend/CMakeLists.txt b/backend/CMakeLists.txt index b508654..8797bca 100644 --- a/backend/CMakeLists.txt +++ b/backend/CMakeLists.txt @@ -7,5 +7,9 @@ target_sources(main PUBLIC Location.cpp util.cpp RNG.cpp + ArmorObject.cpp + ConsumableObject.cpp + GoldObject.cpp + WeaponObject.cpp ) diff --git a/backend/ConsumableObject.cpp b/backend/ConsumableObject.cpp new file mode 100644 index 0000000..cfede41 --- /dev/null +++ b/backend/ConsumableObject.cpp @@ -0,0 +1,3 @@ +#include "ConsumableObject.h" + + diff --git a/backend/GoldObject.cpp b/backend/GoldObject.cpp new file mode 100644 index 0000000..624fdf9 --- /dev/null +++ b/backend/GoldObject.cpp @@ -0,0 +1,6 @@ +#include "GoldObject.h" + +void GoldObject::set_count(int count) { + this->count = count; +} + diff --git a/backend/GoldObject.h b/backend/GoldObject.h index 6f65c1d..ea473d4 100644 --- a/backend/GoldObject.h +++ b/backend/GoldObject.h @@ -5,6 +5,9 @@ class GoldObject : public Object { using Object::Object; +public: + void set_count(int count); + private: int count = 0; }; diff --git a/backend/ObjectFactory.cpp b/backend/ObjectFactory.cpp index 4a0642b..d8e1c21 100644 --- a/backend/ObjectFactory.cpp +++ b/backend/ObjectFactory.cpp @@ -4,15 +4,34 @@ #include "ConsumableObject.h" #include "GoldObject.h" #include "WeaponObject.h" +#include "RNG.h" -Object * ObjectFactory::create_object(ObjectType type, const char * name, const char * description) { - switch (type) { - case ARMOR: return new ArmorObject(name, description); - case CONSUMABLE: return new ConsumableObject(name, description); - case GOLD: return new GoldObject(name, description); - case WEAPON: return new WeaponObject(name, description); +Object * ObjectFactory::create_object(const UniversalObject & data) { + switch (data.type) { + case ARMOR: { + ArmorObject * object = new ArmorObject(data.name, data.description); + object->set_protection(data.protection); + return object; + } + case CONSUMABLE: { + ConsumableObject * object = new ConsumableObject(data.name, data.description); + // TODO: read database item explanation + return object; + } + case GOLD: { + GoldObject * object = new GoldObject(data.name, data.description); + object->set_count(RNG::get().rand_int(data.min_value, data.max_value)); + return object; + } + case WEAPON: { + WeaponObject * object = new WeaponObject(data.name, data.description); + object->set_damage_min(data.min_value); + object->set_damage_max(data.max_value); + return object; + } + default: break; } - return ObjectFactory::create_object(name, description); + return ObjectFactory::create_object(data.name, data.description); } Object * ObjectFactory::create_object(const char * name, const char * description) { diff --git a/backend/ObjectFactory.h b/backend/ObjectFactory.h index adf960b..60123bd 100644 --- a/backend/ObjectFactory.h +++ b/backend/ObjectFactory.h @@ -9,9 +9,19 @@ enum ObjectType { WEAPON, }; +// database object table row +struct UniversalObject { + const char * name; + const char * description; + ObjectType type; + int min_value; + int max_value; + int protection; +}; + class ObjectFactory { public: - static Object * create_object(ObjectType type, const char * name = "", const char * description = ""); + static Object * create_object(const UniversalObject & universal); static Object * create_object(const char * name = "", const char * description = ""); private: diff --git a/backend/WeaponObject.cpp b/backend/WeaponObject.cpp new file mode 100644 index 0000000..ac7defd --- /dev/null +++ b/backend/WeaponObject.cpp @@ -0,0 +1,10 @@ +#include "WeaponObject.h" + +void WeaponObject::set_damage_min(int damage_min) { + this->damage_min = damage_min; +} + +void WeaponObject::set_damage_max(int damage_max) { + this->damage_max = damage_max; +} + diff --git a/backend/WeaponObject.h b/backend/WeaponObject.h index 8b1bc58..d4cfa7a 100644 --- a/backend/WeaponObject.h +++ b/backend/WeaponObject.h @@ -5,6 +5,10 @@ class WeaponObject : public Object { using Object::Object; +public: + void set_damage_min(int damage_min); + void set_damage_max(int damage_max); + private: int damage_min; int damage_max; diff --git a/frontend/DB.cpp b/frontend/DB.cpp index 28fd164..d4527b8 100644 --- a/frontend/DB.cpp +++ b/frontend/DB.cpp @@ -51,7 +51,10 @@ DBStatement & DBStatement::bind(const int & number) { return *this; } -DBStatement & DBStatement::unbind() { +DBStatement & DBStatement::reset() { + int ret = sqlite3_reset(this->stmt.get()); + if (ret != SQLITE_OK) + throw Exception("sqlite3_reset: %d", ret); this->param_index = 1; return *this; } @@ -64,7 +67,7 @@ void DBStatement::execute() { DBQueryRow DBStatement::row() { int ret = sqlite3_step(this->stmt.get()); - if (ret != SQLITE_ROW) + if (ret != SQLITE_ROW && ret != SQLITE_DONE) throw Exception("sqlite3_step: %d", ret); return { *this }; @@ -72,13 +75,26 @@ DBQueryRow DBStatement::row() { DBQueryRow::DBQueryRow(DBStatement & parent) : parent(parent) { } + template <> -const char * DBQueryRow::col(int index) { +const char * DBQueryRow::col(int index, const char * const & default_value) { + int type = sqlite3_column_type(this->parent.stmt.get(), index); + if (type == SQLITE_NULL) return default_value; return reinterpret_cast(sqlite3_column_text(this->parent.stmt.get(), index)); } +template <> +const char * DBQueryRow::col(int index) { + return this->col(index, ""); +} template <> -int DBQueryRow::col(int index) { +int DBQueryRow::col(int index, const int & default_value) { + int type = sqlite3_column_type(this->parent.stmt.get(), index); + if (type == SQLITE_NULL) return default_value; return sqlite3_column_int(this->parent.stmt.get(), index); } +template <> +int DBQueryRow::col(int index) { + return this->col(index, 0); +} diff --git a/frontend/DB.h b/frontend/DB.h index 77b3f7a..f6907bc 100644 --- a/frontend/DB.h +++ b/frontend/DB.h @@ -12,6 +12,8 @@ public: DBQueryRow(DBStatement &); public: + template + T col(int index, const T & default_value); template T col(int index); @@ -52,7 +54,7 @@ public: DBStatement(DB &, const std::string & query); public: - DBStatement & unbind(); + DBStatement & reset(); DBStatement & bind(const std::string & text); DBStatement & bind(const int & number); public: diff --git a/frontend/GameData.cpp b/frontend/GameData.cpp index b036695..c8f47e3 100644 --- a/frontend/GameData.cpp +++ b/frontend/GameData.cpp @@ -34,24 +34,47 @@ static const unordered_map type_map = { }; Object * GameData::create_object(const string & name) { - DBStatement query = this->db->prepare("select type, omschrijving from Objecten where naam = ?"); - query.bind(name); + static DBStatement query = this->db->prepare(R"( + select + type, + omschrijving, + minimumwaarde, + maximumwaarde, + bescherming + from Objecten + where lower(naam) = lower(?) + limit 1 + )"); + query.reset() + .bind(name) + ; try { auto row = query.row(); string type = row.col(0); - const char * description = row.col(1); if (!type_map.contains(type)) throw std::exception(); - return ObjectFactory::create_object(type_map.at(type), name.c_str(), description); + return ObjectFactory::create_object({ + .name = name.c_str(), + .description = row.col(1), + .type = type_map.at(type), + .min_value = row.col(2), + .max_value = row.col(3), + .protection = row.col(4), + }); } catch (...) { return ObjectFactory::create_object(name.c_str()); } } void GameData::leaderbord_add(const string & name, unsigned int gold) { - this->db->prepare("insert into Leaderboard (naam, goudstukken) values (?, ?)") + static DBStatement stmt = this->db->prepare(R"( + insert into Leaderboard (naam, goudstukken) + values (?, ?) + )"); + stmt.reset() .bind(name) .bind(gold) - .execute(); + ; + stmt.execute(); } diff --git a/frontend/Player.h b/frontend/Player.h index c590aa9..94ec6a3 100644 --- a/frontend/Player.h +++ b/frontend/Player.h @@ -22,8 +22,8 @@ private: std::string name; unsigned int health_points = 20; float attack_chance = 0.4; + unsigned int gold = 0; // TODO: WeaponObject[] - // TODO: GoldObject[] // TODO: ArmorObject[] Location & location; bool cheating = false; diff --git a/frontend/cmd/view.cpp b/frontend/cmd/view.cpp index 7998a4a..0636cac 100644 --- a/frontend/cmd/view.cpp +++ b/frontend/cmd/view.cpp @@ -1,5 +1,6 @@ #include "../print.h" #include "../Player.h" +#include "../strings.h" FollowupAction Player::cmd_view(Argv argv) { if (argv.size() == 0) { @@ -7,12 +8,12 @@ FollowupAction Player::cmd_view(Argv argv) { return FollowupAction::NONE; } - if (argv[0] == "Zelf") { + if (str_lower(argv[0]) == "zelf") { lprtf("Je hebt %d levenspunten.\n", this->health_points); - lprtf("Je hebt een aanvalskans van %.0f%%.\n", this->attack_chance * 100); + lprtf("Je hebt een aanvalskans van %.0f%%.\n", this->get_attack() * 100); // TODO: weapon // TODO: armor - // TODO: gold + lprtf("Je hebt %u goundstuk%s.\n", this->gold, this->gold == 1 ? "" : "ken"); // TODO: inventory } diff --git a/frontend/load_dungeon.cpp b/frontend/load_dungeon.cpp index 41c7fc4..23b4094 100644 --- a/frontend/load_dungeon.cpp +++ b/frontend/load_dungeon.cpp @@ -31,7 +31,7 @@ unique_ptr load_dungeon(const string & filename) { throw Exception("Kon bestand niet vinden"); } - xml_parse_result result = doc.load_file(canonical.c_str()); + xml_parse_result result = doc.load_file(canonical.c_str(), parse_default, encoding_latin1); if (!result) throw Exception("Kon XML-bestand niet lezen"); @@ -48,10 +48,10 @@ unique_ptr load_dungeon(const string & filename) { map temp_map; for (xml_node & tag : locations) { - const char * name = tag.text().as_string(); - const char * description = tag.child("beschrijving").text().as_string(); - - Location * location = LocationFactory::create_location(name, description); + Location * location = LocationFactory::create_location( + tag.text().as_string(), + tag.child("beschrijving").text().as_string() + ); vector objects_hidden = str_split(tag.attribute("objectenverborgen").as_string(), ";"); for (string & name : objects_hidden) { -- cgit v1.2.3