diff options
| author | Loek Le Blansch <loek@pipeframe.xyz> | 2024-11-01 22:47:42 +0100 | 
|---|---|---|
| committer | Loek Le Blansch <loek@pipeframe.xyz> | 2024-11-01 22:47:42 +0100 | 
| commit | 07796bea15a2d5f43766f062379b63fc9e9e1b5d (patch) | |
| tree | 2d398f161a9a933176f50779ff164e76c3871f43 | |
| parent | af76b9a0ae58dc8c87548053a5bc310ad6be25ce (diff) | |
WIP consumables
| -rw-r--r-- | backend/CMakeLists.txt | 3 | ||||
| -rw-r--r-- | backend/ConsumableObject.cpp | 8 | ||||
| -rw-r--r-- | backend/ConsumableObject.h | 14 | ||||
| -rw-r--r-- | backend/ElixirConsumableObject.cpp | 8 | ||||
| -rw-r--r-- | backend/ElixirConsumableObject.h | 11 | ||||
| -rw-r--r-- | backend/ExpConsumableObject.cpp | 10 | ||||
| -rw-r--r-- | backend/ExpConsumableObject.h | 11 | ||||
| -rw-r--r-- | backend/ObjectFactory.cpp | 55 | ||||
| -rw-r--r-- | backend/ObjectFactory.h | 13 | ||||
| -rw-r--r-- | backend/Player.cpp | 18 | ||||
| -rw-r--r-- | backend/Player.h | 2 | ||||
| -rw-r--r-- | backend/String.cpp | 12 | ||||
| -rw-r--r-- | backend/String.h | 6 | ||||
| -rw-r--r-- | backend/TeleportConsumableObject.cpp | 6 | ||||
| -rw-r--r-- | backend/TeleportConsumableObject.h | 11 | ||||
| -rw-r--r-- | frontend/GameData.cpp | 20 | ||||
| -rw-r--r-- | frontend/cmd/go.cpp | 5 | ||||
| -rw-r--r-- | frontend/cmd/use.cpp | 24 | 
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());  }  |