This commit is contained in:
NaiJi ✨ 2021-05-08 04:36:26 +03:00
commit 159b7e4673
27 changed files with 739 additions and 0 deletions

1
.gitignore vendored Normal file
View File

@ -0,0 +1 @@
*.user

11
CMakeLists.txt Normal file
View File

@ -0,0 +1,11 @@
cmake_minimum_required(VERSION 3.5)
project(slumber-quest LANGUAGES CXX)
set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall")
file(GLOB SOURCES "*.h" "*.cpp" "*/*.h" "*/*.cpp")
include_directories(${CMAKE_SOURCE_DIR} ${CMAKE_SOURCE_DIR}/actors ${CMAKE_SOURCE_DIR}/controllers ${CMAKE_SOURCE_DIR}/entities ${CMAKE_SOURCE_DIR}/policies)
add_executable(slumber-quest ${SOURCES})

7
actors/actor.cpp Normal file
View File

@ -0,0 +1,7 @@
#include "actor.h"
Actor::Actor()
{}
Actor::~Actor()
{}

26
actors/actor.h Normal file
View File

@ -0,0 +1,26 @@
#ifndef ACTOR_H
#define ACTOR_H
#include <memory>
#include <list>
class Location;
class Item;
class Actor
{
public:
explicit Actor();
virtual ~Actor() = 0;
virtual void commitAction() = 0;
virtual void moveToLocation(const std::shared_ptr<Location>& location) = 0;
virtual void giveItem(const std::shared_ptr<Item>& item) = 0;
virtual void useItem(const std::shared_ptr<Item>& item) = 0;
protected:
std::shared_ptr<Location> _current_location;
std::list<std::shared_ptr<Item>> _inventory;
};
#endif // ACTOR_H

80
actors/player.cpp Normal file
View File

@ -0,0 +1,80 @@
#include <algorithm>
#include <iostream>
#include <cctype>
#include "player.h"
#include "location.h"
#include "controller.h"
#include "item.h"
Player::Player()
{}
Player::~Player()
{}
void Player::commitAction()
{
std::cout << ">> ";
std::string input;
std::cin >> input;
std::cout << "\n";
std::transform(input.begin(), input.end(), input.begin(),
[](unsigned char c){ return std::tolower(c); });
if (input == "inventory")
{
std::cout << showInventory() << "\n\n";
return;
}
for (auto& controller : _current_location->controllers())
{
if (controller->validateInput(input))
{
std::shared_ptr<Actor> player_as_actor = shared_from_this();
std::cout << controller->interact(player_as_actor) << "\n\n";
return;
}
}
std::cout << "Nothing to do with that. Please think again." << "\n\n";
}
void Player::moveToLocation(const std::shared_ptr<Location> &location)
{
_current_location = location;
}
void Player::giveItem(const std::shared_ptr<Item>& item)
{
item->setReceived(true);
_inventory.push_back(item);
}
void Player::useItem(const std::shared_ptr<Item>& item)
{
item->setReceived(false);
_inventory.remove(item);
}
std::string Player::showInventory() const
{
if (_inventory.empty())
{
return "Your pockets are empty.";
}
std::string inventory_message = "Currently you have ";
for (const auto& item : _inventory)
{
inventory_message += item->label();
inventory_message += ", ";
}
inventory_message.pop_back();
inventory_message.pop_back();
inventory_message += ".";
return inventory_message;
}

21
actors/player.h Normal file
View File

@ -0,0 +1,21 @@
#ifndef PLAYER_H
#define PLAYER_H
#include "actor.h"
class Player : public Actor, public std::enable_shared_from_this<Player>
{
public:
explicit Player();
virtual ~Player() override;
virtual void commitAction() override;
virtual void moveToLocation(const std::shared_ptr<Location>& location) override;
virtual void giveItem(const std::shared_ptr<Item>& item) override;
virtual void useItem(const std::shared_ptr<Item>& item) override;
private:
std::string showInventory() const;
};
#endif // PLAYER_H

View File

@ -0,0 +1,46 @@
#include "controller.h"
#include "policy.h"
#include <algorithm>
Controller::Controller(Initializer&& initializer) :
_keywords(initializer.keywords),
_interaction_message(initializer.message)
{}
Controller::~Controller()
{}
bool Controller::validateInput(const std::string &input_word) const
{
return std::find(_keywords.begin(), _keywords.end(), input_word) != _keywords.end();
}
void Controller::setValidationPolicies(const std::list<std::shared_ptr<Policy>>& policies)
{
_validation_policies = policies;
}
Controller::ValidationResult Controller::validatePolicies() const
{
if (_validation_policies.empty())
return {true, ""};
std::string interaction_output;
bool success = true;
for (const auto& policy : _validation_policies)
{
const auto check_result = policy->check();
interaction_output += (check_result.commentary + "\n\n");
if (!check_result.satisfied)
{
success = false;
break;
}
}
interaction_output.pop_back();
interaction_output.pop_back();
return {success, interaction_output};
}

42
controllers/controller.h Normal file
View File

@ -0,0 +1,42 @@
#ifndef CONTROLLER_H
#define CONTROLLER_H
#include <memory>
#include <string>
#include <list>
class Node;
class Actor;
class Policy;
class Controller
{
public:
struct Initializer
{
const std::list<std::string>& keywords;
const std::string& message;
};
explicit Controller(Initializer&& initializer);
virtual ~Controller() = 0;
virtual std::string interact(std::shared_ptr<Actor> actor) = 0;
virtual bool validateInput(const std::string& input_word) const final;
virtual void setValidationPolicies(const std::list<std::shared_ptr<Policy>>& policies) final;
struct ValidationResult
{
bool success = false;
std::string validation_output;
};
protected:
virtual ValidationResult validatePolicies() const final;
std::list<std::string> _keywords;
std::string _interaction_message;
std::list<std::shared_ptr<Policy>> _validation_policies;
};
#endif // CONTROLLER_H

View File

@ -0,0 +1,33 @@
#include "itemcontroller.h"
#include "item.h"
#include "actor.h"
#include "policy.h"
ItemController::ItemController(Initializer &&initializer) :
Controller(std::move(initializer))
{}
ItemController::~ItemController()
{}
std::string ItemController::interact(std::shared_ptr<Actor> actor)
{
std::string interaction_output;
const auto validation_result = validatePolicies();
interaction_output += validation_result.validation_output;
if (validation_result.success)
{
actor->giveItem(_item);
interaction_output += _interaction_message;
}
return interaction_output;
}
void ItemController::setDependentItem(const std::shared_ptr<Item> &item)
{
_item = item;
}

View File

@ -0,0 +1,21 @@
#ifndef ITEMCONTROLLER_H
#define ITEMCONTROLLER_H
#include "controller.h"
class Item;
class ItemController : public Controller
{
public:
explicit ItemController(Controller::Initializer&& initializer);
virtual ~ItemController() override;
virtual std::string interact(std::shared_ptr<Actor> actor) override;
void setDependentItem(const std::shared_ptr<Item>& item);
private:
std::shared_ptr<Item> _item;
};
#endif // ITEMCONTROLLER_H

View File

@ -0,0 +1,34 @@
#include "locationcontroller.h"
#include "location.h"
#include "policy.h"
#include "actor.h"
LocationController::LocationController(Initializer &&initializer) :
Controller(std::move(initializer))
{}
LocationController::~LocationController()
{}
std::string LocationController::interact(std::shared_ptr<Actor> actor)
{
std::string interaction_output;
const auto validation_result = validatePolicies();
interaction_output += validation_result.validation_output;
if (validation_result.success)
{
actor->moveToLocation(_location);
const std::string& node_interact_message = _location->interact();
interaction_output += (_interaction_message + "\n\n" + node_interact_message);
}
return interaction_output;
}
void LocationController::setDependentLocation(const std::shared_ptr<Location> &location)
{
_location = location;
}

View File

@ -0,0 +1,21 @@
#ifndef LOCATIONCONTROLLER_H
#define LOCATIONCONTROLLER_H
#include "controller.h"
class Location;
class LocationController : public Controller
{
public:
explicit LocationController(Controller::Initializer&& initializer);
virtual ~LocationController() override;
virtual std::string interact(std::shared_ptr<Actor> actor) override;
void setDependentLocation(const std::shared_ptr<Location>& location);
private:
std::shared_ptr<Location> _location;
};
#endif // LOCATIONCONTROLLER_H

21
entities/item.cpp Normal file
View File

@ -0,0 +1,21 @@
#include "item.h"
Item::Item(const std::string &label) :
_label(label),
_is_received(false)
{}
const std::string& Item::label() const
{
return _label;
}
bool Item::isReceived() const
{
return _is_received;
}
void Item::setReceived(bool received)
{
_is_received = received;
}

20
entities/item.h Normal file
View File

@ -0,0 +1,20 @@
#ifndef ITEM_H
#define ITEM_H
#include <string>
class Item
{
public:
explicit Item(const std::string& label);
const std::string& label() const;
bool isReceived() const;
void setReceived(bool received);
private:
std::string _label;
bool _is_received;
};
#endif // ITEM_H

24
entities/location.cpp Normal file
View File

@ -0,0 +1,24 @@
#include "location.h"
#include <algorithm>
Location::Location(Initializer &&initializer) :
_interaction_message(initializer.message),
_interactive_controllers(initializer.interactive_controllers),
_is_visited(false)
{}
const std::string& Location::interact()
{
_is_visited = true;
return _interaction_message;
}
const std::list<std::shared_ptr<Controller>>& Location::controllers()
{
return _interactive_controllers;
}
bool Location::isVisited() const
{
return _is_visited;
}

33
entities/location.h Normal file
View File

@ -0,0 +1,33 @@
#ifndef LOCATION_H
#define LOCATION_H
#include <list>
#include <string>
#include <memory>
class Controller;
class Location
{
public:
struct Initializer
{
const std::string& message;
const std::list<std::shared_ptr<Controller>>& interactive_controllers;
};
explicit Location(Initializer &&initializer);
virtual const std::string& interact();
const std::list<std::shared_ptr<Controller>>& controllers();
bool isVisited() const;
private:
std::string _interaction_message;
std::list<std::shared_ptr<Controller>> _interactive_controllers;
std::shared_ptr<Location> _current_user_location;
bool _is_visited;
};
#endif // LOCATION_H

7
levelbuilder.cpp Normal file
View File

@ -0,0 +1,7 @@
#include "levelbuilder.h"
LevelBuilder::LevelBuilder()
{}
LevelBuilder::~LevelBuilder()
{}

21
levelbuilder.h Normal file
View File

@ -0,0 +1,21 @@
#ifndef LEVELBUILDER_H
#define LEVELBUILDER_H
#include <memory>
class Controller;
class LevelBuilder
{
public:
explicit LevelBuilder();
virtual ~LevelBuilder() = 0;
virtual void init() = 0;
virtual void save() = 0;
virtual void load() = 0;
virtual const std::shared_ptr<Controller>& getStartingController() const = 0;
};
#endif // LEVELBUILDER_H

20
main.cpp Normal file
View File

@ -0,0 +1,20 @@
#include <iostream>
#include "controller.h"
#include "player.h"
#include "sandboxlevelbuilder.h"
int main()
{
std::unique_ptr<LevelBuilder> level_builder = std::make_unique<SandboxLevelBuilder>();
level_builder->init();
std::shared_ptr<Player> player = std::make_unique<Player>();
const auto& starting_controller = level_builder->getStartingController();
std::cout << starting_controller->interact(player) << "\n\n";
while (true)
{
player->commitAction();
}
}

View File

@ -0,0 +1,20 @@
#include "itemrequiredpolicy.h"
#include "item.h"
ItemRequiredPolicy::ItemRequiredPolicy(const std::string& satisfaction, const std::string& dissatisfaction) :
Policy(satisfaction, dissatisfaction)
{}
ItemRequiredPolicy::~ItemRequiredPolicy()
{}
Policy::CheckResult ItemRequiredPolicy::check() const
{
bool success = _item->isReceived();
return composeMessageFromResult(success);
}
void ItemRequiredPolicy::setRequiredItem(const std::shared_ptr<Item> &item)
{
_item = item;
}

View File

@ -0,0 +1,23 @@
#ifndef ITEMREQUIREDPOLICY_H
#define ITEMREQUIREDPOLICY_H
#include <memory>
#include "policy.h"
class Item;
class ItemRequiredPolicy : public Policy
{
public:
explicit ItemRequiredPolicy(const std::string& satisfaction, const std::string& dissatisfaction);
virtual ~ItemRequiredPolicy() override;
virtual Policy::CheckResult check() const override;
void setRequiredItem(const std::shared_ptr<Item>& item);
private:
std::shared_ptr<Item> _item;
};
#endif // ITEMREQUIREDPOLICY_H

View File

@ -0,0 +1,20 @@
#include "locationrequiredpolicy.h"
#include "location.h"
LocationRequiredPolicy::LocationRequiredPolicy(const std::string& satisfaction, const std::string& dissatisfaction) :
Policy(satisfaction, dissatisfaction)
{}
LocationRequiredPolicy::~LocationRequiredPolicy()
{}
Policy::CheckResult LocationRequiredPolicy::check() const
{
bool success = _location->isVisited();
return composeMessageFromResult(success);
}
void LocationRequiredPolicy::setRequiredLocation(const std::shared_ptr<Location> &location)
{
_location = location;
}

View File

@ -0,0 +1,23 @@
#ifndef LOCATIONREQUIREDPOLICY_H
#define LOCATIONREQUIREDPOLICY_H
#include <memory>
#include "policy.h"
class Location;
class LocationRequiredPolicy : public Policy
{
public:
explicit LocationRequiredPolicy(const std::string& satisfaction, const std::string& dissatisfaction);
virtual ~LocationRequiredPolicy() override;
virtual Policy::CheckResult check() const override;
void setRequiredLocation(const std::shared_ptr<Location>& location);
private:
std::shared_ptr<Location> _location;
};
#endif // LOCATIONREQUIREDPOLICY_H

16
policies/policy.cpp Normal file
View File

@ -0,0 +1,16 @@
#include "policy.h"
Policy::Policy(const std::string& satisfaction, const std::string& dissatisfaction) :
_commentary_on_satisfaction(satisfaction),
_commentary_on_dissatisfaction(dissatisfaction)
{}
Policy::~Policy()
{}
Policy::CheckResult Policy::composeMessageFromResult(bool result) const
{
return {result, (result)
? _commentary_on_satisfaction
: _commentary_on_dissatisfaction};
}

27
policies/policy.h Normal file
View File

@ -0,0 +1,27 @@
#ifndef POLICY_H
#define POLICY_H
#include <string>
class Policy
{
public:
explicit Policy(const std::string& satisfaction, const std::string& dissatisfaction);
virtual ~Policy() = 0;
struct CheckResult
{
bool satisfied = false;
std::string commentary;
};
virtual CheckResult check() const = 0;
protected:
virtual CheckResult composeMessageFromResult(bool result) const final;
std::string _commentary_on_satisfaction;
std::string _commentary_on_dissatisfaction;
};
#endif // POLICY_H

99
sandboxlevelbuilder.cpp Normal file
View File

@ -0,0 +1,99 @@
#include "sandboxlevelbuilder.h"
#include "location.h"
#include "item.h"
#include "locationcontroller.h"
#include "itemcontroller.h"
#include "itemrequiredpolicy.h"
#include <iostream>
SandboxLevelBuilder::SandboxLevelBuilder()
{}
SandboxLevelBuilder::~SandboxLevelBuilder()
{}
void SandboxLevelBuilder::init()
{
// START GAME TRIGGER
Controller::Initializer the_first_and_only_trigger_init = {{}, "Hello! This is a test run."};
std::shared_ptr<LocationController> the_first_and_only_trigger = std::make_shared<LocationController>(std::move(the_first_and_only_trigger_init));
// DOOR CONTROLLER
Controller::Initializer door_init = {{"door"}, "You successfully opened the door and entered the house."};
std::shared_ptr<LocationController> door_cont = std::make_shared<LocationController>(std::move(door_init));
// TABLE CONTROLLER
Controller::Initializer table_init = {{"table"}, "You approached the table."};
std::shared_ptr<LocationController> table_cont = std::make_shared<LocationController>(std::move(table_init));
// TENSHI CONTROLLER
Controller::Initializer tenshi_init = {{"tenshi", "card", "postcard"}, "You picked up cute postcard of tenshi eating corndog. Now you are happy."};
std::shared_ptr<ItemController> tenshi_cont = std::make_shared<ItemController>(std::move(tenshi_init));
// COUCH CONTROLLER
Controller::Initializer couch_init = {{"couch", "sofa"}, "You approached the coach."};
std::shared_ptr<LocationController> couch_cont = std::make_shared<LocationController>(std::move(couch_init));
// COACH FROM TABLE CONTROLLER
Controller::Initializer coach2_init = {{"coach", "sofa"}, "You slowly moved away from the table and approached the coach."};
std::shared_ptr<LocationController> coach2_cont = std::make_shared<LocationController>(std::move(coach2_init));
// PLEROMAN CONTROLLER
Controller::Initializer pleroman_init = {{"pleroman"}, "You talk to a pleroma user! What a happy and carefree creature. He even brew you some cofe!"};
std::shared_ptr<LocationController> pleroman_cont = std::make_shared<LocationController>(std::move(pleroman_init));
std::shared_ptr<ItemRequiredPolicy> need_tenshi_policy = std::make_shared<ItemRequiredPolicy>("You give him the postcard of Tenshi.", "He doesn't want to talk to you. Make him trust you!!");
pleroman_cont->setValidationPolicies({need_tenshi_policy});
// START LOCATION
auto&& init_msg = "You are now in a staring location. There is a door leading to a house. Typical text quest situation. To interact with something, type it as noun.";
Location::Initializer init = {init_msg, {door_cont}};
std::shared_ptr<Location> start = std::make_shared<Location>(std::move(init));
// ROOM LOCATION
auto&& room_msg = "This is an old room. You can see only a rusty table and a coach. Also there is a pleroma user standing still.";
Location::Initializer roomloc_init = {room_msg, {table_cont, couch_cont, pleroman_cont}};
std::shared_ptr<Location> room = std::make_shared<Location>(std::move(roomloc_init));
// TABLE LOCATION
auto&& table_msg = "Boring table. There is a flashy postcard on it.";
Location::Initializer tableloc_init = {table_msg, {coach2_cont, tenshi_cont, pleroman_cont}};
std::shared_ptr<Location> table = std::make_shared<Location>(std::move(tableloc_init));
// COUCH LOCATION
auto&& couch_msg = "Looks like the coach was comfy... several years ago. Now probably it only feeds roaches. Better not touch it.";
Location::Initializer couchloc_init = {couch_msg, {table_cont, pleroman_cont}};
std::shared_ptr<Location> couch = std::make_shared<Location>(std::move(couchloc_init));
// PLEROMAN LOCATION
auto&& pleroman_msg = ". . . \n\n From the conversation you find out the quest is still in a very raw test state, the engine isn't even finished... Alright, just terminate the game process.";
Location::Initializer pleromanloc_init = {pleroman_msg, {}};
std::shared_ptr<Location> pleroman = std::make_shared<Location>(std::move(pleromanloc_init));
std::shared_ptr<Item> tenshi = std::make_shared<Item>("Postcard of Tenshi eating corndog");
need_tenshi_policy->setRequiredItem(tenshi);
the_first_and_only_trigger->setDependentLocation(start);
door_cont->setDependentLocation(room);
table_cont->setDependentLocation(table);
couch_cont->setDependentLocation(couch);
coach2_cont->setDependentLocation(couch);
pleroman_cont->setDependentLocation(pleroman);
tenshi_cont->setDependentItem(tenshi);
_starting_controller = the_first_and_only_trigger;
}
void SandboxLevelBuilder::save()
{
std::cerr << "SandboxLevelBuilder::save : Not implemented!";
}
void SandboxLevelBuilder::load()
{
std::cerr << "SandboxLevelBuilder::load : Not implemented!";
}
const std::shared_ptr<Controller> &SandboxLevelBuilder::getStartingController() const
{
return _starting_controller;
}

22
sandboxlevelbuilder.h Normal file
View File

@ -0,0 +1,22 @@
#ifndef SANDBOXLEVELBUILDER_H
#define SANDBOXLEVELBUILDER_H
#include "levelbuilder.h"
class SandboxLevelBuilder : public LevelBuilder
{
public:
explicit SandboxLevelBuilder();
virtual ~SandboxLevelBuilder() override;
virtual void init() override;
virtual void save() override;
virtual void load() override;
virtual const std::shared_ptr<Controller>& getStartingController() const override;
private:
std::shared_ptr<Controller> _starting_controller;
};
#endif // SANDBOXLEVELBUILDER_H