Soren Rogiers

Game developer

King's Assassin


King's Assassin is a text based game made for an assigment during my studies Digital Art and Entertainment.
Made in C++ and the data is stored in Json files.

The story is set in a kingdom far away somewhere in the middle ages. The game starts where you wake up in your cell and can't remember anything that happened.

It's entirely up to you to figure out clues, find objects to open doors, battle monsters to progress the game. Most objects can be examined to find clues or hints.

Code snippets below - full source on Github

Code snippets


									
//*******************
//JSON ENTITY MANAGER
//******************* 
#include "stdafx.h"

#include "JsonEntityManager.h"
#include "JsonEntity.h"
#include "Item.h"
#include "Room.h"
#include "EntryPoint.h"
#include "LivingEntity.h"
#include "Objects.h"
#include "Weapon.h"
#include "Armor.h"

JsonEntityManager::JsonEntityManager() {}

JsonEntityManager::~JsonEntityManager()
{
	for (auto& entity : m_Data)
	{
		delete entity.second;
	}
}

template 
void JsonEntityManager::LoadJson(std::string filename)
{
	JsonBox::Value v;
	v.loadFromFile(filename);

	JsonBox::Object o = v.getObject();
	for (auto entity : o)
	{
		std::string key = entity.first;
		m_Data[key] = dynamic_cast(new T(key, entity.second, this));
	}
}

template 
T* JsonEntityManager::GetEntity(std::string id)
{
	// The id prefix should match to the type T, so take the
	// first characters of the id up to the length of the
	// prefix and compare the two
	if (id.substr(0, EntityToString().size()) == EntityToString())
		return dynamic_cast(m_Data.at(id));
	else
		return nullptr;
}

template <> std::string EntityToString() { return "item"; }
template <> std::string EntityToString() { return "weapon"; }
template <> std::string EntityToString() { return "armor"; }
template <> std::string EntityToString() { return "object"; }
template <> std::string EntityToString() { return "livingentity"; }
template <> std::string EntityToString() { return "room"; }
template <> std::string EntityToString() { return "entrypoint"; }

template void JsonEntityManager::LoadJson(std::string);
template void JsonEntityManager::LoadJson(std::string);
template void JsonEntityManager::LoadJson(std::string);
template void JsonEntityManager::LoadJson(std::string);
template void JsonEntityManager::LoadJson(std::string);
template void JsonEntityManager::LoadJson(std::string);
template void JsonEntityManager::LoadJson(std::string);

template Item* JsonEntityManager::GetEntity(std::string);
template Weapon* JsonEntityManager::GetEntity(std::string);
template Armor* JsonEntityManager::GetEntity(std::string);
template Objects* JsonEntityManager::GetEntity(std::string);
template LivingEntity* JsonEntityManager::GetEntity(std::string);
template Room* JsonEntityManager::GetEntity(std::string);
template EntryPoint* JsonEntityManager::GetEntity(std::string);

//**********
//INVENTORY
//**********
#include "stdafx.h"
#include "Inventory.h"
#include "Item.h"
#include "JsonBox.h"

#include 
#include 
#include 
#include 
#include "Weapon.h"
#include "Armor.h"

Inventory::Inventory(JsonBox::Value& v, JsonEntityManager* mgr)
{
	JsonBox::Object o = v.getObject();
	Load(o["items"], mgr);
	Load(o["weapons"], mgr);
	Load(o["armor"], mgr);

}

Inventory::Inventory()
{

}


Inventory::~Inventory()
{
	m_Items.clear();
}
//Add takes a pointer to an item and a quantity and checks to see if the inventory
//already contains an item with the same id as the given item pointer
//if it does it increases the quantity of the item otherwise the inventory doesn't contain
//the item yet and creates a pair
void Inventory::Add(Item* item, int count)
{
	for(auto& it : this->m_Items)
	{
		if(it.first->m_ID == item->m_ID)
		{
			it.second += count;
			return;
		}
	}
	this->m_Items.push_back(std::make_pair(item, count));
}

//Remove: in order to remove an item from a list we need to use the erase function
//and this takes an iterator
void Inventory::Remove(Item* item, int count)
{
	for(auto it = this->m_Items.begin(); it != this->m_Items.end();++it)
	{
		if((*it).first->m_ID == item->m_ID)
		{
			(*it).second -= count;

			if ((*it).second < 1) 
				this->m_Items.erase(it);

			return;
		}
	}
}

//This count returns the quantity of the item that the inventory contains by finding the first pair
//whose ID's match
int Inventory::Count(Item* item)
{
	for(auto it : this->m_Items)
	{
		if(it.first->m_ID == item->m_ID)
		{
			return it.second;
		}
	}
	return 0;
}

std::vector Inventory::FilterEdibleItems()
{
	std::vector edibleItems;
	for(auto it : m_Items)
	{
		if(it.first->m_IsEdible == 1)
		{
			edibleItems.push_back(it.first);
		}
	}
	return edibleItems;
}

//This count function uses the GetItemByIndex function to find a pointer of type T* to the n item, which is then
//converted to an Item* pointer before being sent to the first count function.
template 
int Inventory::Count(unsigned int index)
{
	return Count(GetItemByIndex(index));
}

//The GetItemByIndex function returns a T* pointer to the x'th element in the item list that is of the same type as T
//std::list doesn't have an element access unlike a vector which does.
template 
T* Inventory::GetItemByIndex(unsigned int index)
{
	unsigned int i = 0;
	auto it = m_Items.begin();
	for(;it != m_Items.end();++it)
	{
		if((*it).first->m_ID.substr(0,EntityToString().size()) != EntityToString())
		{
			continue;
		}

		if (i++ == index)
			break;
	}

	if (it != this->m_Items.end())
	{
		return dynamic_cast((*it).first);
	}
	else
	{
		return nullptr;
	}
}

template 
int Inventory::Print(bool labeled)
{
	unsigned int i = 1;

	for(auto it : this->m_Items)
	{
		if (it.first->m_ID.substr(0, EntityToString().size()) != EntityToString())
			continue;

		if(labeled)
		{
			std::cout << i++ << ": ";
		}

		std::cout << it.first->m_Name << " (" << it.second << ") - ";
		std::cout << it.first->m_Description << std::endl;
	}
	return this->m_Items.size();
}

template 
void Inventory::Load(JsonBox::Value& v, JsonEntityManager* mgr)
{
	for(auto item : v.getArray())
	{
		std::string itemID = item.getArray()[0].getString();
		int quantity = item.getArray()[1].getInteger();
		m_Items.push_back(std::make_pair(mgr->GetEntity(itemID), quantity));
	}
}

template 
JsonBox::Array Inventory::ToJsonArray()
{
	JsonBox::Array jsonArray;
	for(auto item : this->m_Items)
	{
		if (item.first->m_ID.substr(0, EntityToString().size()) != EntityToString())
			continue;

		JsonBox::Array pair;
		pair.push_back(JsonBox::Value(item.first->m_ID));
		pair.push_back(JsonBox::Value(item.second));

		jsonArray.push_back(JsonBox::Value(pair));
	}

	return jsonArray;
}

void Inventory::Clear()
{
	m_Items.clear();
}

void Inventory::MergeInventories(Inventory* inventory)
{
	if (inventory == this)
		return;

	for(auto it : inventory->m_Items)
	{
		this->Add(it.first, it.second);
	}
	
}

int Inventory::Print(bool label)
{
	unsigned int i = 0;
	if(m_Items.empty())
	{
		std::cout << "Nothing to be found." << std::endl;
	} else
	{
		i += Print(label);
		i += Print(label);
		i += Print(label);
	}

	return i;
}

JsonBox::Object Inventory::GetJson()
{
	JsonBox::Object jsonObject;

	jsonObject["items"] = JsonBox::Value(ToJsonArray());
	jsonObject["weapons"] = JsonBox::Value(ToJsonArray());
	jsonObject["armor"] = JsonBox::Value(ToJsonArray());

	return jsonObject;
}

bool Inventory::CheckForWinningItem()
{
	for(auto it : m_Items)
	{
		if (it.first->m_Name == "Magical letter")
			return true;
	}

	return false;
}

template void Inventory::Load(JsonBox::Value&, JsonEntityManager*);
template void Inventory::Load(JsonBox::Value&, JsonEntityManager*);
template void Inventory::Load(JsonBox::Value&, JsonEntityManager*);

template JsonBox::Array Inventory::ToJsonArray();
template JsonBox::Array Inventory::ToJsonArray();
template JsonBox::Array Inventory::ToJsonArray();

template int Inventory::Count(unsigned int);
template int Inventory::Count(unsigned int);
template int Inventory::Count(unsigned int);

template Item* Inventory::GetItemByIndex(unsigned int);
template Weapon* Inventory::GetItemByIndex(unsigned int);
template Armor* Inventory::GetItemByIndex(unsigned int);

template int Inventory::Print(bool);
template int Inventory::Print(bool);
template int Inventory::Print(bool);

//*******************
//GAME EVENT HANDLER
//*******************
void GameEventHandler::Examine(Room* pRoom, const std::string objectString)
{
	std::string examinedObject;

	for (size_t i = 0; im_ObjectsInRoom.size(); ++i)
	{
		std::string upperCaseObject = pRoom->m_ObjectsInRoom[i]->m_Name;
		std::for_each(upperCaseObject.begin(), upperCaseObject.end(), [](char &s) {s = toupper(s); });

		if (upperCaseObject == objectString)
		{
			examinedObject = pRoom->m_ObjectsInRoom[i]->m_Description;
		}
	}

	for (size_t i = 0; im_EntryPoints.size(); ++i)
	{
		std::string upperCaseEntry = pRoom->m_EntryPoints[i]->m_Name;
		std::for_each(upperCaseEntry.begin(), upperCaseEntry.end(), [](char &s) {s = toupper(s); });

		if (upperCaseEntry == objectString)
		{
			if(pRoom->m_EntryPoints[i]->m_FlipDescription)
			{
				examinedObject = pRoom->m_EntryPoints[i]->m_Description2;
			}
			else
			{
				examinedObject = pRoom->m_EntryPoints[i]->m_Description;
			}
		}
	}
	if (examinedObject == "")
	{
		std::cout << "The object your looking for is not here." << std::endl;
	} else
	{
		std::cout << examinedObject << std::endl;
	}
}

//Opens the door if the door is unlocked or if the player has the required key and go through it
void GameEventHandler::Open(Room* pRoom, Player& player, const std::string objectString) const
{
	bool IsDoorFound = false;

	for (size_t i = 0; im_EntryPoints.size(); ++i)
	{
		std::string upperCaseEntrypoint = pRoom->m_EntryPoints[i]->m_Name;
		std::for_each(upperCaseEntrypoint.begin(), upperCaseEntrypoint.end(), [](char &s) {s = toupper(s); });

		if (upperCaseEntrypoint == objectString)
		{
			IsDoorFound = true;
			EntryPoint* entry = pRoom->m_EntryPoints.at(i);
			entry->m_FlipDescription = !entry->m_FlipDescription;
			int flag = player.Traverse(entry);
			SetConsoleTextAttribute(m_hConsole, 14);

			switch (flag)
			{
			default:
			case 0:
				std::cout << "The " << entry->m_Name << " is locked." << std::endl;
				break;
			case 1:
				std::cout << "You unlock the " << entry->m_Name << " and go through it." << std::endl;
				break;
			case 2:
				std::cout << "You go through the " << entry->m_Name << "." << std::endl;
				break;
			}
			SetConsoleTextAttribute(m_hConsole, 7);
		}
	}

	if(!IsDoorFound)
		std::cout << "The door you're looking for is not here." << std::endl;

}

void GameEventHandler::Look(Room* pRoom) const
{
	std::cout << "You look around and see: " << std::endl;
	SetConsoleTextAttribute(m_hConsole, 14);
	std::for_each(pRoom->m_ObjectsInRoom.begin(), pRoom->m_ObjectsInRoom.end(), [](const Objects* object) {std::cout << "* " << object->m_Name << std::endl; });
	std::for_each(pRoom->m_EntryPoints.begin(), pRoom->m_EntryPoints.end(), [](const EntryPoint* entry) {std::cout << "* " << entry->m_Name << std::endl; });
	SetConsoleTextAttribute(m_hConsole, 7);
}
								
							


									
{
  "livingentity_rat": {
    "name": "Rat",
    "hp": 3,
    "friendly": "0",
    "text": "The rat screeches",
    "attackpower": 3,
    "dodgechance": 0.015625,
    "agility": 3,
    "currentweapon": "weapon_rat_claw"
  },
  "livingentity_spear_goblin": {
    "name": "Spear Goblin",
    "hp": 4,
    "friendly": "0",
    "text": "",
    "attackpower": 4,
    "dodgechance": 0.015625,
    "agility": 2,
    "currentweapon": "weapon_goblin_spear"
  },
  "livingentity_dual_wielding_goblin": {
    "name": "Dual wielding Goblin",
    "hp": 4,
    "friendly": "0",
    "text": "",
    "attackpower": 4,
    "dodgechance": 0.015625,
    "agility": 5,
    "currentweapon": "weapon_goblin_dagger"
  },
  "livingentity_brawler_goblin": {
    "name": "Strong brawler goblin",
    "hp": 8,
    "friendly": "0",
    "text": "",
    "attackpower": 5,
    "dodgechance": 0.015625,
    "agility": 4,
    "currentweapon": "weapon_goblin_hammer"
  },
  "livingentity_rune_guardian": {
    "name": "Rune Guardian",
    "hp": 10,
    "friendly": "0",
    "text": "",
    "attackpower": 7,
    "dodgechance": 0.015625,
    "agility": 4,
    "currentweapon": "weapon_runed_sword"
  },
  "livingentity_goblin_assassin": {
    "name": "Goblin assasin",
    "hp": 5,
    "friendly": "0",
    "text": "",
    "attackpower": 10,
    "dodgechance": 0.015625,
    "agility": 10,
    "currentweapon": "weapon_goblin_dagger"
  },
   "livingentity_Kings_assassin": {
    "name": "King's assasin",
    "hp": 10,
    "friendly": "0",
    "text": "",
    "attackpower": 12,
    "dodgechance": 0.015625,
    "agility": 12,
    "currentweapon": "weapon_Assassins_blade"
  },
}
									
							

Screenshots


Go back