aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLoek Le Blansch <loek@pipeframe.xyz>2024-11-01 22:47:42 +0100
committerLoek Le Blansch <loek@pipeframe.xyz>2024-11-01 22:47:42 +0100
commit07796bea15a2d5f43766f062379b63fc9e9e1b5d (patch)
tree2d398f161a9a933176f50779ff164e76c3871f43
parentaf76b9a0ae58dc8c87548053a5bc310ad6be25ce (diff)
WIP consumables
-rw-r--r--backend/CMakeLists.txt3
-rw-r--r--backend/ConsumableObject.cpp8
-rw-r--r--backend/ConsumableObject.h14
-rw-r--r--backend/ElixirConsumableObject.cpp8
-rw-r--r--backend/ElixirConsumableObject.h11
-rw-r--r--backend/ExpConsumableObject.cpp10
-rw-r--r--backend/ExpConsumableObject.h11
-rw-r--r--backend/ObjectFactory.cpp55
-rw-r--r--backend/ObjectFactory.h13
-rw-r--r--backend/Player.cpp18
-rw-r--r--backend/Player.h2
-rw-r--r--backend/String.cpp12
-rw-r--r--backend/String.h6
-rw-r--r--backend/TeleportConsumableObject.cpp6
-rw-r--r--backend/TeleportConsumableObject.h11
-rw-r--r--frontend/GameData.cpp20
-rw-r--r--frontend/cmd/go.cpp5
-rw-r--r--frontend/cmd/use.cpp24
18 files changed, 183 insertions, 54 deletions
diff --git a/backend/CMakeLists.txt b/backend/CMakeLists.txt
index b7e8996..814d7e9 100644
--- a/backend/CMakeLists.txt
+++ b/backend/CMakeLists.txt
@@ -16,5 +16,8 @@ target_sources(main PUBLIC
print.cpp
Player.cpp
Exception.cpp
+ ElixirConsumableObject.cpp
+ ExpConsumableObject.cpp
+ TeleportConsumableObject.cpp
)
diff --git a/backend/ConsumableObject.cpp b/backend/ConsumableObject.cpp
index cfede41..7a02a3c 100644
--- a/backend/ConsumableObject.cpp
+++ b/backend/ConsumableObject.cpp
@@ -1,3 +1,11 @@
#include "ConsumableObject.h"
+void ConsumableObject::set_potency(const Range<int> & range) {
+ this->potency_min = range.min;
+ this->potency_max = range.max;
+}
+
+Range<int> ConsumableObject::get_potency() const {
+ return { this->potency_min, this->potency_max };
+}
diff --git a/backend/ConsumableObject.h b/backend/ConsumableObject.h
index 3b4a2ce..0ecd073 100644
--- a/backend/ConsumableObject.h
+++ b/backend/ConsumableObject.h
@@ -1,9 +1,23 @@
#pragma once
#include "Object.h"
+#include "Range.h"
+
+class Player;
class ConsumableObject : public Object {
using Object::Object;
+public:
+ virtual void consume(Player & player) = 0;
+
+public:
+ void set_potency(const Range<int> & range);
+ Range<int> get_potency() const;
+
+private:
+ int potency_min = 0;
+ int potency_max = 0;
+
};
diff --git a/backend/ElixirConsumableObject.cpp b/backend/ElixirConsumableObject.cpp
new file mode 100644
index 0000000..145e74a
--- /dev/null
+++ b/backend/ElixirConsumableObject.cpp
@@ -0,0 +1,8 @@
+#include "Player.h"
+#include "RNG.h"
+#include "ElixirConsumableObject.h"
+
+void ElixirConsumableObject::consume(Player & player) {
+ player.add_health(RNG::get().rand_int(this->get_potency()));
+}
+
diff --git a/backend/ElixirConsumableObject.h b/backend/ElixirConsumableObject.h
new file mode 100644
index 0000000..a2249c6
--- /dev/null
+++ b/backend/ElixirConsumableObject.h
@@ -0,0 +1,11 @@
+#pragma once
+
+#include "ConsumableObject.h"
+
+class ElixirConsumableObject : public ConsumableObject {
+ using ConsumableObject::ConsumableObject;
+
+public:
+ virtual void consume(Player & player);
+};
+
diff --git a/backend/ExpConsumableObject.cpp b/backend/ExpConsumableObject.cpp
new file mode 100644
index 0000000..77aa37e
--- /dev/null
+++ b/backend/ExpConsumableObject.cpp
@@ -0,0 +1,10 @@
+#include "Player.h"
+#include "RNG.h"
+#include "ExpConsumableObject.h"
+
+void ExpConsumableObject::consume(Player & player) {
+ float min = static_cast<float>(this->get_potency().min) / 100;
+ float max = static_cast<float>(this->get_potency().max) / 100;
+ player.add_attack(RNG::get().rand_double(min, max));
+}
+
diff --git a/backend/ExpConsumableObject.h b/backend/ExpConsumableObject.h
new file mode 100644
index 0000000..60ffb91
--- /dev/null
+++ b/backend/ExpConsumableObject.h
@@ -0,0 +1,11 @@
+#pragma once
+
+#include "ConsumableObject.h"
+
+class ExpConsumableObject : public ConsumableObject {
+ using ConsumableObject::ConsumableObject;
+
+public:
+ virtual void consume(Player & player);
+};
+
diff --git a/backend/ObjectFactory.cpp b/backend/ObjectFactory.cpp
index 1256f98..8283b06 100644
--- a/backend/ObjectFactory.cpp
+++ b/backend/ObjectFactory.cpp
@@ -2,34 +2,49 @@
#include "ArmorObject.h"
#include "ConsumableObject.h"
+#include "TeleportConsumableObject.h"
+#include "ExpConsumableObject.h"
+#include "ElixirConsumableObject.h"
#include "GoldObject.h"
#include "WeaponObject.h"
#include "RNG.h"
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({ data.min_value, data.max_value });
+ if (data.type == "wapenrusting") {
+ ArmorObject * object = new ArmorObject(data.name, data.description);
+ object->set_protection(data.protection);
+ return object;
+ }
+
+ {
+ ConsumableObject * object = nullptr;
+
+ if (data.type == "teleportatiedrank")
+ object = new TeleportConsumableObject(data.name, data.description);
+ else if (data.type == "ervaringsdrank")
+ object = new ExpConsumableObject(data.name, data.description);
+ else if (data.type == "levenselixer")
+ object = new ElixirConsumableObject(data.name, data.description);
+
+ if (object != nullptr) {
+ object->set_potency(data.value);
return object;
}
- default: break;
}
+
+ if (data.type == "goudstukken") {
+ GoldObject * object = new GoldObject(data.name, data.description);
+ object->set_count(RNG::get().rand_int(data.value));
+ return object;
+ }
+
+ if (data.type == "wapen") {
+ WeaponObject * object = new WeaponObject(data.name, data.description);
+ object->set_damage(data.value);
+ return object;
+ }
+
+ // fallback
return ObjectFactory::create_object(data.name, data.description);
}
diff --git a/backend/ObjectFactory.h b/backend/ObjectFactory.h
index 440d4bd..735ac1f 100644
--- a/backend/ObjectFactory.h
+++ b/backend/ObjectFactory.h
@@ -1,21 +1,14 @@
#pragma once
#include "Object.h"
-
-enum ObjectType {
- ARMOR,
- CONSUMABLE,
- GOLD,
- WEAPON,
-};
+#include "Range.h"
// database object table row
struct UniversalObject {
String name;
String description;
- ObjectType type;
- int min_value;
- int max_value;
+ String type;
+ Range<int> value;
int protection;
};
diff --git a/backend/Player.cpp b/backend/Player.cpp
index 2de5632..5e3e030 100644
--- a/backend/Player.cpp
+++ b/backend/Player.cpp
@@ -43,6 +43,7 @@ Location & Player::get_location() const {
}
void Player::set_location(Location & location) {
this->location = &location;
+ lprtf("Je staat nu bij de locatie %s.\n", location.get_name().c_str());
}
void Player::equip(WeaponObject * weapon) {
@@ -69,3 +70,20 @@ void Player::equip(ArmorObject * armor) {
lprtf("doet %s aan.\n", this->armor->get_name().c_str());
}
+void Player::add_health(unsigned int bonus) {
+ if (this->is_dead()) return;
+ this->health_points += bonus;
+ lprtf("Je hebt %d levenspunt%s erbij gekregen.\n", bonus, bonus == 1 ? "" : "en");
+}
+
+void Player::add_attack(float bonus) {
+ float max_bonus = 0.90f - this->attack_chance;
+ if (max_bonus < 0.f) {
+ lprtf("Je aanvalskans is niet verder verhoogd.\n");
+ return;
+ }
+ bonus = min(max_bonus, bonus);
+ this->attack_chance += bonus;
+ lprtf("Je aanvalskans is verhoogd met %.1f%%.\n", bonus * 100);
+}
+
diff --git a/backend/Player.h b/backend/Player.h
index 061f13c..bf9815c 100644
--- a/backend/Player.h
+++ b/backend/Player.h
@@ -31,7 +31,9 @@ public:
public:
void take_damage(unsigned int dmg);
+ void add_health(unsigned int bonus);
float get_attack() const;
+ void add_attack(float bonus);
unsigned get_health() const;
Location & get_location() const;
void set_location(Location &);
diff --git a/backend/String.cpp b/backend/String.cpp
index c856d86..e5512bf 100644
--- a/backend/String.cpp
+++ b/backend/String.cpp
@@ -26,8 +26,11 @@ String::String(String && other) {
}
String & String::operator = (String && other) {
if (this == &other) return *this;
+ safe_free(this->_data);
this->_data = other._data;
this->_data_len = other._data_len;
+ other._data = nullptr;
+ other._data_len = 0;
return *this;
}
@@ -90,3 +93,12 @@ bool String::empty() const {
return this->_data_len == 0;
}
+
+bool operator == (const String & a, const String & b) {
+ return strncmp(a._data, b._data, min(a._data_len, b._data_len)) == 0;
+}
+
+bool operator != (const String & a, const String & b) {
+ return !(a == b);
+}
+
diff --git a/backend/String.h b/backend/String.h
index bca8944..4fade62 100644
--- a/backend/String.h
+++ b/backend/String.h
@@ -10,6 +10,8 @@ public:
String(const char * data, size_t size);
String(const String &);
String(String &&);
+ String & operator = (const String &);
+ String & operator = (String &&);
~String();
public:
static String va_fmt(va_list args, const char * fmt);
@@ -22,8 +24,8 @@ public:
bool empty() const;
public:
- String & operator = (const String &);
- String & operator = (String &&);
+ friend bool operator == (const String &, const String &);
+ friend bool operator != (const String &, const String &);
private:
void set(const char * data);
diff --git a/backend/TeleportConsumableObject.cpp b/backend/TeleportConsumableObject.cpp
new file mode 100644
index 0000000..5fd4459
--- /dev/null
+++ b/backend/TeleportConsumableObject.cpp
@@ -0,0 +1,6 @@
+#include "TeleportConsumableObject.h"
+
+void TeleportConsumableObject::consume(Player & player) {
+ // TODO
+}
+
diff --git a/backend/TeleportConsumableObject.h b/backend/TeleportConsumableObject.h
new file mode 100644
index 0000000..7456714
--- /dev/null
+++ b/backend/TeleportConsumableObject.h
@@ -0,0 +1,11 @@
+#pragma once
+
+#include "ConsumableObject.h"
+
+class TeleportConsumableObject : public ConsumableObject {
+ using ConsumableObject::ConsumableObject;
+
+public:
+ virtual void consume(Player & player);
+};
+
diff --git a/frontend/GameData.cpp b/frontend/GameData.cpp
index a716a57..30816c8 100644
--- a/frontend/GameData.cpp
+++ b/frontend/GameData.cpp
@@ -49,20 +49,11 @@ Enemy * GameData::create_enemy(const string & name) const {
}
}
-static const unordered_map<string, ObjectType> type_map = {
- { "teleportatiedrank", ObjectType::CONSUMABLE },
- { "ervaringsdrank", ObjectType::CONSUMABLE },
- { "levenselixer", ObjectType::CONSUMABLE },
- { "wapenrusting", ObjectType::ARMOR },
- { "wapen", ObjectType::WEAPON },
- { "goudstukken", ObjectType::GOLD },
-};
-
Object * GameData::create_object(const string & name) const {
static DBStatement query = this->db.prepare(R"(
select
- type,
omschrijving,
+ type,
minimumwaarde,
maximumwaarde,
bescherming
@@ -76,14 +67,11 @@ Object * GameData::create_object(const string & name) const {
try {
auto row = query.row();
- string type = row.col<const char *>(0);
- if (!type_map.contains(type)) throw std::exception();
return ObjectFactory::create_object({
.name = name.c_str(),
- .description = row.col<const char *>(1, nullptr),
- .type = type_map.at(type),
- .min_value = row.col<int>(2),
- .max_value = row.col<int>(3),
+ .description = row.col<const char *>(0, nullptr),
+ .type = row.col<const char *>(1, nullptr),
+ .value = { row.col<int>(2), row.col<int>(3) },
.protection = row.col<int>(4),
});
} catch (...) {
diff --git a/frontend/cmd/go.cpp b/frontend/cmd/go.cpp
index 75f6345..b8bb7e2 100644
--- a/frontend/cmd/go.cpp
+++ b/frontend/cmd/go.cpp
@@ -1,7 +1,6 @@
#include "backend/Location.h"
#include "backend/Dungeon.h"
#include "backend/Exception.h"
-#include "backend/print.h"
#include "../GameController.h"
#include "../strings.h"
@@ -30,9 +29,7 @@ void GameController::cmd_go(string & argv) {
this->dungeon->update();
- if (!player.is_dead()) {
+ if (!player.is_dead())
player.set_location(*next_location);
- lprtf("Je staat nu bij de locatie %s\n", player.get_location().get_name().c_str());
- }
}
diff --git a/frontend/cmd/use.cpp b/frontend/cmd/use.cpp
index badab10..36824b5 100644
--- a/frontend/cmd/use.cpp
+++ b/frontend/cmd/use.cpp
@@ -1,8 +1,28 @@
+#include "backend/ConsumableObject.h"
+#include "backend/Exception.h"
+#include "backend/print.h"
+
#include "../GameController.h"
+#include "../strings.h"
using namespace std;
-void GameController::cmd_use(string & argv) {
- // TODO
+void GameController::cmd_use(string & target_name) {
+ Player & player = this->dungeon->get_player();
+ Location & location = player.get_location();
+ for (Object * object : player.inventory) {
+ if (str_lower(object->get_name().c_str()) != str_lower(target_name)) continue;
+
+ auto consumable = unique_ptr<ConsumableObject>(dynamic_cast<ConsumableObject *>(object));
+ if (consumable == nullptr)
+ throw Exception("%s is niet consumeerbaar", object->get_name().c_str());
+
+ lprtf("Je drinkt %s.\n", object->get_displayname().c_str());
+ player.inventory.remove(object);
+ consumable->consume(player);
+ return;
+ }
+
+ throw Exception("object \"%s\" niet gevonden", target_name.c_str());
}