Large diffs are not rendered by default.

@@ -7,10 +7,11 @@ math(EXPR BITNESS "8*${CMAKE_SIZEOF_VOID_P}")

add_executable(snowdevice
${CMAKE_SOURCE_DIR}/src/start.cpp
)
src/input.cpp src/include/input.h src/engine.cpp src/include/engine.h src/player.cpp src/include/player.h src/Inventory.cpp src/include/Inventory.h src/position.cpp src/include/position.h)
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -static -mwindows -m64")
target_include_directories(snowdevice
PUBLIC ${CMAKE_SOURCE_DIR}/extern/BearLibTerminal/Include/C
${CMAKE_SOURCE_DIR}/src/include
)
target_link_libraries(snowdevice
${CMAKE_SOURCE_DIR}/extern/BearLibTerminal/Windows64/BearLibTerminal.lib
Binary file not shown.
@@ -0,0 +1,41 @@
cmake_minimum_required(VERSION 2.6)
project(PCGBSPDungeonGen)

set(CMAKE_INSTALL_PREFIX "${CMAKE_BINARY_DIR/DIST}")
set(CMAKE_CXX_FLAGS "-std=c++11 -static-libstdc++ ${CMAKE_CXX_FLAGS}")

# Project Options/Settings

set(PCG_DUNGEONGEN_VERSION_MAJOR 0)
set(PCG_DUNGEONGEN_VERSION_MINOR 1)

option(BUILD_DEMO
"Build the demos/examples"
ON
)

if (BUILD_DEMO)
add_subdirectory(source_demo)
endif (BUILD_DEMO)


# Dependencies
# -


# Sources and Building

include_directories(
"${PROJECT_SOURCE_DIR}/include"
)

file(GLOB SourceFiles
"source/*.cpp"
)

add_library(PCG_BSPDungeonGen STATIC ${SourceFiles})


# Installation
install(TARGETS PCG_BSPDungeonGen DESTINATION lib)
install(DIRECTORY ${PROJECT_SOURCE_DIR}/include/PCG-BSPDungeonGen DESTINATION include)
@@ -0,0 +1,21 @@
The MIT License (MIT)

Copyright (c) 2014 George Koutsikos

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
@@ -0,0 +1,15 @@
#ifndef PCG_CORRIDOR_H
#define PCG_CORRIDOR_H


#include "Vec2.h"
#include <vector>


typedef std::vector<Vec2> Path;

// Simplistic grid-based pathfinding
Path FindPath(Vec2 begin, Vec2 end);


#endif
@@ -0,0 +1,74 @@
#ifndef PCG_DUNGEON_H
#define PCG_DUNGEON_H


#include <vector>
#include <queue>
#include <map>
#include <algorithm>
#include <random>
#include <string>

#include "AABB.h"
#include "Node.h"


typedef AABB Room;
typedef std::vector<Vec2> Path;
typedef std::vector<unsigned int> GridLine;
typedef std::vector<std::vector<unsigned int> > Grid;


/*! Class representing a randomly generated dungeon
*/
class Dungeon {
public:
Dungeon(std::string seed, int width, int height);

~Dungeon();

enum TILE_TYPE {
Empty = 0, Floor = 1, Corridor = 2, Entrance = 3, Exit = 4, Door = 5, Treasure = 6, Monster = 7, Trap = 8
};
private:
int mWidth;
int mHeight;
int mUnitSquare;
std::mt19937 mRandGen;
std::uniform_real_distribution<float> mUniDistr;
std::seed_seq mSeedSeq;
std::string mSeedString;
std::vector<Room> mRooms;
std::vector<Path> mCorridors;
std::vector<Vec2> mTreasures;
std::vector<Vec2> mMonsters;
std::vector<Vec2> mTraps;
Vec2 mEntrance;
Vec2 mExit;
Grid mGrid;
Node<AABB> mRootNode;
public:
void Generate(void);

Grid GetGrid(void);

private:
void ClearGrid();

void SplitSpace(Node<AABB> *node);

void FindRoomsDigCorridors();

void PlaceEntranceAndExit();

void BakeFloor();

void PlaceDoors();

void PlaceTreasureAndMonsters();

void BakeDetails();
};


#endif
@@ -0,0 +1,98 @@
-- ************************************* --
-- BSP Based Dungeon Generation --
-- ************************************* --

-- Instructions:
--
-- Open a command line app and run
-- premake4 one_of_these__gmake__vs2010__xcode__codeblocks

_ACTION = _ACTION or 'gmake'

-- _ _
-- | | (_)
-- ___ _ __ | |_ _ ___ _ __ ___
-- / _ \| '_ \| __| |/ _ \| '_ \/ __|
-- | (_) | |_) | |_| | (_) | | | \__ \
-- \___/| .__/ \__|_|\___/|_| |_|___/
-- | |
-- |_|

-- No options for now...


-- _ _ _
-- | | | | (_)
-- ___ ___ | |_ _| |_ _ ___ _ __ ___
-- / __|/ _ \| | | | | __| |/ _ \| '_ \/ __|
-- \__ \ (_) | | |_| | |_| | (_) | | | \__ \
-- |___/\___/|_|\__,_|\__|_|\___/|_| |_|___/


solution "PCG-BSPDungeonGen"
configurations { "Debug", "Release" }
location "./build"
targetdir "./build"


project "PCG-BSPDungeonGenLib"
kind "SharedLib"
language "C++"
location "./build/library"

includedirs {
path.getabsolute("./include/")
}

files {
"source/AABB.cpp",
"source/Node.cpp",
"source/Corridor.cpp",
"source/Dungeon.cpp"
} -- .cpp files

configuration "Debug"
defines { "DEBUG" }
flags { "Symbols" }

configuration "Release"
defines { "NDEBUG" }
flags { "Optimize" }

configuration { "windows", "codelite" }
buildoptions { "-std=c++11" }

configuration { "linux", "gmake" }
buildoptions { "-std=c++11" }


project "PCG-BSPDungeonGenDemo"
kind "ConsoleApp"
language "C++"
location "./build/demo"

includedirs {
path.getabsolute("./include/")
}

files {
"source_demo/Main.cpp"
} -- .cpp files

links {
"PCG-BSPDungeonGenLib"
}

configuration "Debug"
defines { "DEBUG" }
flags { "Symbols" }

configuration "Release"
defines { "NDEBUG" }
flags { "Optimize" }

configuration { "windows", "codelite" }
buildoptions { "-std=c++11" }

configuration { "linux", "gmake" }
buildoptions { "-std=c++11" }
@@ -0,0 +1,50 @@
#include "PCG-BSPDungeonGen\Corridor.h"


#include <cmath>


/*! Function that returns a list of points
* for each neighbouring grid cell of the
* function's center parameter
*/
std::vector<Vec2> GetNeighbours(Vec2 &center) {
std::vector<Vec2> neighbours;
neighbours.push_back(Vec2(center.x + 1, center.y));
neighbours.push_back(Vec2(center.x - 1, center.y));
neighbours.push_back(Vec2(center.x, center.y + 1));
neighbours.push_back(Vec2(center.x, center.y - 1));
return neighbours;
}


// Simplistic grid-based pathfinding
Path FindPath(Vec2 begin, Vec2 end) {

// Create needed variables and init
// with the starting point.
Path result;
result.push_back(begin);
Vec2 current = begin;

do {
// Get neighbours
Path neighbours = GetNeighbours(current);
// Find nearest
int nearestIndex;
int nearestRange = 1000;
for (int i = 0; i < 4; ++i) {
if ((std::abs(neighbours[i].x - end.x) + std::abs(neighbours[i].y - end.y)) < nearestRange) {
nearestRange = (std::abs(neighbours[i].x - end.x) + std::abs(neighbours[i].y - end.y));
nearestIndex = i;
}
}
// save up and continue...
current = neighbours[nearestIndex];
result.push_back(current);
} while (current != end); //... until we reach the end point

return result;
}


@@ -0,0 +1,289 @@
#include "PCG-BSPDungeonGen\Dungeon.h"


#include <iostream>
#include <cmath>

#include "PCG-BSPDungeonGen\Corridor.h"


#define RAND_GEN_PERCENTAGE (float)mUniDistr(mRandGen)


// Constructors
Dungeon::Dungeon(std::string seed, int width, int height) : mWidth(width), mHeight(height),
mRootNode(nullptr, AABB(0, 0, width, height)) {
// init grid
mGrid = std::vector<std::vector<unsigned int> >(mHeight, std::vector<unsigned int>(mWidth, TILE_TYPE::Empty));

mSeedString = seed;
mSeedSeq = std::seed_seq(mSeedString.begin(), mSeedString.end());
mRandGen = std::mt19937(mSeedSeq);
mUniDistr = std::uniform_real_distribution<float>(0.0f, 1.0f);
}


Dungeon::~Dungeon() { }


#define DEBUG 1

// Public Methods
void Dungeon::Generate() {
// Clean-up if already generated
mRootNode = Node<AABB>(nullptr, AABB(0, 0, mWidth, mHeight));
mRooms.clear();
mCorridors.clear();
mTreasures.clear();
mMonsters.clear();
mTraps.clear();
ClearGrid();

// Generate dungeon parts
SplitSpace(&mRootNode);
FindRoomsDigCorridors();
BakeFloor();
PlaceEntranceAndExit();
PlaceDoors();
PlaceTreasureAndMonsters();
BakeDetails();

std::cout << "Dungeon Generation complete!" << std::endl;

#ifdef DEBUG
for (int i = 0; i < mGrid.size(); i++) {
for (int j = 0; j < mGrid[i].size(); j++) {
std::cout << mGrid[i][j];
}
std::cout << std::endl;
}
#endif
}


Grid Dungeon::GetGrid(void) {
return mGrid;
}


// Private Methods
void Dungeon::ClearGrid() {
mGrid.clear();
mGrid = std::vector<std::vector<unsigned int> >(mHeight, std::vector<unsigned int>(mWidth, TILE_TYPE::Empty));
}


void Dungeon::SplitSpace(Node <AABB> *node) {

// Choose how and where to split
float ratio = (float) node->GetData().getWidth() / node->GetData().getHeight();
bool splitVertical = true;
if (ratio < 1.0f)
splitVertical = false;


float split = RAND_GEN_PERCENTAGE;
do {
split = RAND_GEN_PERCENTAGE;
} while (split < 0.4f || split > 0.6f);


// Create and calculate the 2 subspaces
// of the splitted one.
AABB subspaceA, subspaceB;

if (splitVertical) {
int splitX = node->GetData().X() + (int) (split * node->GetData().getWidth());
subspaceA = AABB(node->GetData().X(), node->GetData().Y(),
(int) (split * node->GetData().getWidth()), node->GetData().getHeight());
subspaceB = AABB(splitX, node->GetData().Y(),
(int) ((1 - split) * node->GetData().getWidth()), node->GetData().getHeight());
} else {
int splitY = node->GetData().Y() + (int) (split * node->GetData().getHeight());
subspaceA = AABB(node->GetData().X(), node->GetData().Y(),
node->GetData().getWidth(), (int) (split * node->GetData().getHeight()));
subspaceB = AABB(node->GetData().X(), splitY,
node->GetData().getWidth(), (int) ((1 - split) * node->GetData().getHeight()));
}

#ifdef DEBUG
std::cout << "Splitting [" << node->GetData().X() << ", " << node->GetData().Y() << ", " <<
node->GetData().getWidth() << ", " << node->GetData().getHeight() << "] into:" << std::endl;
std::cout << "Space A: [" << subspaceA.X() << ", " << subspaceA.Y() << ", " << subspaceA.getWidth() << ", " <<
subspaceA.getHeight() << "]" << std::endl;
std::cout << "Space B: [" << subspaceB.X() << ", " << subspaceB.Y() << ", " << subspaceB.getWidth() << ", " <<
subspaceB.getHeight() << "]" << std::endl;
std::cout << std::endl;
#endif

// Add subspaces to the current node
node->MakeLeftChild(subspaceA);
node->MakeRightChild(subspaceB);

// Decide if we need to split more
// and continue recursion.
if (subspaceA.getWidth() > 7 && subspaceA.getHeight() > 6)
SplitSpace(node->GetLeftChild());
if (subspaceB.getWidth() > 7 && subspaceB.getHeight() > 6)
SplitSpace(node->GetRightChild());

} // method ends here


void Dungeon::FindRoomsDigCorridors() {
Node<AABB>::NodeIterator it(&mRootNode);

// Iterate over bsp-tree and add Rooms that
// adhere to the minimum size required
while (it.Next() != false) {
if (it.IsLeaf() == true && it.GetData().getWidth() > 3 && it.GetData().getHeight() > 3) {
mRooms.push_back(AABB(it.GetData().X() + 1, it.GetData().Y() + 1, it.GetData().getWidth() - 2,
it.GetData().getHeight() - 2));
#ifdef DEBUG
std::cout << "Added [" << it.GetData().X() << ", " << it.GetData().Y() << ", " << it.GetData().getWidth() <<
", " << it.GetData().getHeight() << "]" << std::endl;
#endif
}
}

it.Reset();

// Re-iterate over bsp-tree and create
// corridors using pathfind function (grid-based)
while (it.Next() != false) {
if (!it.IsLeaf()) {
Path corridor = FindPath(it.GetNode()->GetLeftChild()->GetData().getCenter(),
it.GetNode()->GetRightChild()->GetData().getCenter());
mCorridors.push_back(corridor);

#ifdef DEBUG
std::cout << "Corridor points from [" << it.GetNode()->GetLeftChild()->GetData().getCenter().x << ", " <<
it.GetNode()->GetLeftChild()->GetData().getCenter().y << "]" << std::endl;
std::cout << " to [" << it.GetNode()->GetRightChild()->GetData().getCenter().x << ", " <<
it.GetNode()->GetRightChild()->GetData().getCenter().y << "]" << std::endl;
for (Path::iterator itP = corridor.begin(); itP != corridor.end(); itP++) {
std::cout << itP->x << ", " << itP->y << std::endl;
}
std::cout << std::endl;
#endif
}
}

} // method ends here


void Dungeon::PlaceEntranceAndExit() {

int i, j; // i is the index of the room with the entrance
// j is the index of the room with the exit
i = j = 0;

// There are N rooms, choose if entrance will be in one
// of the rooms of the first half (0 to N/2) or on the
// second (N/2 to N). Exit will be on the other.
if (RAND_GEN_PERCENTAGE > 0.5f) {
i = floorf(RAND_GEN_PERCENTAGE * (mRooms.size() / 2.0f));
j = floorf((mRooms.size() / 2.0f) + RAND_GEN_PERCENTAGE * (mRooms.size() / 2.0f));
} else {
j = floorf(RAND_GEN_PERCENTAGE * (mRooms.size() / 2.0f));
i = floorf((mRooms.size() / 2.0f) + RAND_GEN_PERCENTAGE * (mRooms.size() / 2.0f));
}

// Set the center of the rooms as entrance and exit
mEntrance = mRooms[i].getCenter();
mExit = mRooms[j].getCenter();

#ifdef DEBUG
std::cout << "Entrance: [" << mEntrance.x << ", " << mEntrance.y << "]" << std::endl;
std::cout << "Exit: [" << mExit.x << ", " << mExit.y << "]" << std::endl;
#endif

} // method ends here



void Dungeon::BakeFloor() {
std::cout << std::endl << "Baking data on mGrid..." << std::endl;

// Fill rooms on the grid with the proper id (floor=1)
for (std::vector<Room>::iterator it = mRooms.begin(); it != mRooms.end(); ++it) {
for (int i = it->Y(); i < it->Y() + it->getHeight(); i++) {
for (int j = it->X(); j < it->X() + it->getWidth(); j++) {
mGrid[i][j] = TILE_TYPE::Floor;
}
}
}

// Fill corridors on the grid with the proper id (corridor=2)
for (std::vector<Path>::iterator it = mCorridors.begin(); it != mCorridors.end(); ++it) {
for (Path::iterator pathIt = it->begin(); pathIt != it->end(); ++pathIt) {
if (mGrid[pathIt->y][pathIt->x] != 1)
mGrid[pathIt->y][pathIt->x] = TILE_TYPE::Corridor;
}
}

} // method ends here



void Dungeon::PlaceDoors() {
// Detects corridor-room crossings and
// places doors (door=5)
// *fix* weird door placement sometimes
for (int i = 1; i < mGrid.size() - 1; i++) {
for (int j = 1; j < mGrid[i].size() - 1; j++) {
if (mGrid[i][j] == 2 &&
(mGrid[i + 1][j] == 1 || mGrid[i - 1][j] == 1 || mGrid[i][j + 1] == 1 || mGrid[i][j - 1] == 1) &&
(mGrid[i + 1][j] != 5 && mGrid[i - 1][j] != 5 && mGrid[i][j + 1] != 5 && mGrid[i][j - 1] != 5) &&
((mGrid[i + 1][j] == 0 && mGrid[i - 1][j] == 0) || (mGrid[i][j + 1] == 0 && mGrid[i][j - 1] == 0))) {
mGrid[i][j] = TILE_TYPE::Door;
}
}
}
}


void Dungeon::PlaceTreasureAndMonsters() {
// Iterate rooms and place treasure, monsters and traps
for (std::vector<Room>::iterator it = mRooms.begin(); it != mRooms.end(); ++it) {
int scale = (int) ((float) it->getVolume() / 8.0f);
// Monsters
for (int i = 0; i < scale; i++)
mMonsters.push_back(Vec2(it->X() + (int) (it->getWidth() * RAND_GEN_PERCENTAGE),
it->Y() + (int) (it->getHeight() * RAND_GEN_PERCENTAGE)));
// Treasures
if (scale > 3) {
mTreasures.push_back(Vec2(it->X() + (int) (it->getWidth() * RAND_GEN_PERCENTAGE),
it->Y() + (int) (it->getHeight() * RAND_GEN_PERCENTAGE)));
mTreasures.push_back(Vec2(it->X() + (int) (it->getWidth() * RAND_GEN_PERCENTAGE),
it->Y() + (int) (it->getHeight() * RAND_GEN_PERCENTAGE)));
} else if (scale >= 1)
mTreasures.push_back(Vec2(it->X() + (int) (it->getWidth() * RAND_GEN_PERCENTAGE),
it->Y() + (int) (it->getHeight() * RAND_GEN_PERCENTAGE)));
// Traps
if (RAND_GEN_PERCENTAGE > 0.35f)
mTraps.push_back(Vec2(it->X() + (int) (it->getWidth() * RAND_GEN_PERCENTAGE),
it->Y() + (int) (it->getHeight() * RAND_GEN_PERCENTAGE)));
}
}


void Dungeon::BakeDetails() {
// Write the details of the dungeon to its grid.
// Details = Entrance/Exit, Monsters, Treasure and Traps

// Entrance and exit...
mGrid[mEntrance.y][mEntrance.x] = TILE_TYPE::Entrance;
mGrid[mExit.y][mExit.x] = TILE_TYPE::Exit;
// Monsters...
for (std::vector<Vec2>::iterator it = mMonsters.begin(); it != mMonsters.end(); ++it)
mGrid[it->y][it->x] = TILE_TYPE::Monster;
// Treasure...
for (std::vector<Vec2>::iterator it = mTreasures.begin(); it != mTreasures.end(); ++it)
mGrid[it->y][it->x] = TILE_TYPE::Treasure;
// Traps...
for (std::vector<Vec2>::iterator it = mTraps.begin(); it != mTraps.end(); ++it)
mGrid[it->y][it->x] = TILE_TYPE::Trap;
}


@@ -0,0 +1,6 @@
roguelike notes

* crawl thru megacity skyscraper ala dredd? pvp, fighting styles, slots for skills and augments
* roguelikes depend on augmentation and strategy
* DX and system shock both feature biomechanical augmentation as part of their character progression
* human vs augmented progression paths?
@@ -0,0 +1,70 @@
#include "PCG-BSPDungeonGen\AABB.h"


// Constructors
AABB::AABB() {
mPosition.x = 0;
mPosition.y = 0;
mSize.x = 0;
mSize.y = 0;
}

AABB::AABB(int x, int y, int w, int h) {
mPosition.x = x;
mPosition.y = y;
mSize.x = w;
mSize.y = h;
}

AABB::~AABB() { }


// Methods
int AABB::X() const {
return mPosition.x;
}


int AABB::Y() const {
return mPosition.y;
}


Vec2 AABB::getCenter() const {
return Vec2(mPosition.x + mSize.x / 2, mPosition.y + mSize.y / 2);
}


int AABB::getHeight() const {
return mSize.y;
}


int AABB::getVolume() const {
return mSize.x * mSize.y;
}


int AABB::getWidth() const {
return mSize.x;
}


void AABB::setPosition(int x, int y) {
mPosition.x = x;
mPosition.y = y;
}


void AABB::setSize(int w, int h) {
mSize.x = w;
mSize.y = h;
}


bool AABB::isInside(Vec2 &p) const {
return (p.x >= mPosition.x && p.x <= (mPosition.x + mSize.x) &&
p.y >= mPosition.y && p.y <= (mPosition.y + mSize.y));
}


@@ -0,0 +1,4 @@
//
// Created by Karl on 12/12/2015.
//

@@ -0,0 +1,122 @@
#include "PCG-BSPDungeonGen\Node.h"
#include "PCG-BSPDungeonGen\AABB.h"

// Constructors
template<typename T>
Node<T>::Node(Node <T> *parent, T data) {
mpParent = parent;
mpLeft = nullptr;
mpRight = nullptr;
mData = data;
}

template<typename T>
Node<T>::~Node() {
if (mpLeft != nullptr)
delete mpLeft;
if (mpRight != nullptr)
delete mpRight;
}


// Methods
template<typename T>
T Node<T>::GetData() const {
return mData;
}


template<typename T>
Node <T> *Node<T>::GetParent(void) const {
return mpParent;
}


template<typename T>
Node <T> *Node<T>::GetLeftChild(void) const {
return mpLeft;
}

template<typename T>
void Node<T>::MakeLeftChild(T data) {
mpLeft = new Node(this, data);
}


template<typename T>
Node <T> *Node<T>::GetRightChild(void) const {
return mpRight;
}

template<typename T>
void Node<T>::MakeRightChild(T data) {
mpRight = new Node(this, data);
}


// NodeIterator -- Public inner class
template<typename T>
Node<T>::NodeIterator::NodeIterator(Node *parent) {
mpRoot = parent;
mpCurrent = parent;
}


template<typename T>
bool Node<T>::NodeIterator::Next() {
if (mpCurrent->GetLeftChild() != 0 && mVisited.find(mpCurrent->GetLeftChild()) == mVisited.end()) {
//mpCurrent->SetLeftVisited();
mVisited.insert(mpCurrent->GetLeftChild());
mpCurrent = mpCurrent->GetLeftChild();
return true;
}

if (mpCurrent->GetRightChild() != 0 && mVisited.find(mpCurrent->GetRightChild()) == mVisited.end()) {
//mpCurrent->SetRightVisited();
mVisited.insert(mpCurrent->GetRightChild());
mpCurrent = mpCurrent->GetRightChild();
return true;
}

if (mpCurrent->GetParent() != 0) {
mpCurrent = mpCurrent->GetParent();
return true;
} else {
return false;
}
}


template<typename T>
T Node<T>::NodeIterator::GetData() const {
return mpCurrent->mData;
}


template<typename T>
Node <T> *Node<T>::NodeIterator::GetNode() const {
return mpCurrent;
}


template<typename T>
bool Node<T>::NodeIterator::IsLeaf() const {
if (mpCurrent->GetLeftChild() == 0 && mpCurrent->GetRightChild() == 0)
return true;
else
return false;
}


template<typename T>
void Node<T>::NodeIterator::Reset() {
mVisited.clear();
mpCurrent = mpRoot;
}


// explicit template instantiation
template
class Node<AABB>;


@@ -0,0 +1,44 @@
//
// Created by Karl on 12/12/2015.
//
#include "BearLibTerminal.h"
#include "engine.h"
#include "input.h"

int Engine::run() {
mainCharacter = Player(10, 10);
mainCharacter.render();
terminal_refresh();
while (terminal_read() != TK_CLOSE) {
input::checkForInputAndBlock();
terminal_clear();
printf("position is %d X %d Y\n", mainCharacter.playerPosition.posX(), mainCharacter.playerPosition.posY());
}
terminal_close();
return 0;
}

bool Engine::canMovePlayerTo(int x, int y) {
return true;
}

bool Engine::movePlayerTo(int newX, int newY) {
if (!canMovePlayerTo(newX, newY)) {
return false;
} else {
mainCharacter.playerPosition.setX(newX);
mainCharacter.playerPosition.setY(newY);
return true;
}
}

void Engine::movePlayerBy(int x, int y) {
mainCharacter.playerPosition.setX(mainCharacter.playerPosition.posX() + x);
mainCharacter.playerPosition.setY(mainCharacter.playerPosition.posY() + y);
mainCharacter.render();
terminal_refresh();
}

const Player Engine::getCurrentPlayer() {
return this->mainCharacter;
}
@@ -0,0 +1,35 @@
#ifndef PCG_AABB_H
#define PCG_AABB_H



#include "Vec2.h"


/*! Class for Axis-Aligned Bounding Box
* Instances of this class are used to represent
* a region in 2d space.
*/
class AABB {
public:
AABB();
AABB(int x, int y, int w, int h);
~AABB();
private:
Vec2 mPosition;
Vec2 mSize;
public:
int getWidth() const;
int getHeight() const;
int getVolume() const;
Vec2 getCenter() const;
int X() const;
int Y() const;
void setPosition(int x, int y);
void setSize(int w, int h);
bool isInside(Vec2 &p) const;
};



#endif
@@ -0,0 +1,14 @@
//
// Created by Karl on 12/12/2015.
//

#ifndef SNOWDEVICE_INVENTORY_H
#define SNOWDEVICE_INVENTORY_H


class Inventory {

};


#endif //SNOWDEVICE_INVENTORY_H
@@ -0,0 +1,46 @@
#ifndef PCG_NODE_H
#define PCG_NODE_H



#include <unordered_set>

template<typename T>
class Node {
public:
Node(Node<T>* parent, T data);
~Node();
private:
T mData;
Node* mpParent;
Node* mpLeft;
Node* mpRight;
public: // Public Methods
T GetData(void) const;
Node* GetParent(void) const;

void MakeLeftChild(T space);
Node* GetLeftChild(void) const;

void MakeRightChild(T space);
Node* GetRightChild(void) const;
public: // Public inner types
class NodeIterator {
public:
NodeIterator(Node* parent);
private:
std::unordered_set<Node*> mVisited;
Node* mpRoot;
Node* mpCurrent;
public:
bool Next();
T GetData() const;
Node* GetNode() const;
bool IsLeaf() const;
void Reset();
};
};



#endif
@@ -0,0 +1,41 @@
#ifndef PCG_VEC2_H
#define PCG_VEC2_H



/*! Struct representing a point or vector in 2d space.
*/
typedef struct _Vec2 {
/* Data */
int x;
int y;

/* Constructors and Operators */
_Vec2() {
x=0;
y=0;
}

_Vec2(int _x, int _y) {
x=_x;
y=_y;
}

_Vec2(const _Vec2& v) {
x=v.x;
y=v.y;
}

bool operator==(const _Vec2& rhs) const {
return (x == rhs.x && y == rhs.y);
}

bool operator!=(const _Vec2& rhs) const {
return (x != rhs.x || y != rhs.y);
}

} Vec2;



#endif
@@ -0,0 +1,32 @@
//
// Created by Karl on 12/12/2015.
//

#ifndef SNOWDEVICE_SD_ENGINE_H
#define SNOWDEVICE_SD_ENGINE_H


#include "player.h"

class Engine {
public:
static Engine &getInstance() {
static Engine instance_;
return instance_;
}

int run();

bool movePlayerTo(int, int);

bool canMovePlayerTo(int, int);

void movePlayerBy(int, int);

const Player getCurrentPlayer();

private:
Player mainCharacter;
};

#endif //SNOWDEVICE_SD_ENGINE_H
@@ -0,0 +1,17 @@
//
// Created by Karl on 12/12/2015.
//

#ifndef SNOWDEVICE_INPUT_H
#define SNOWDEVICE_INPUT_H


class input {
public:
static void checkForInputAndBlock();

static void parseInput(int suppliedKey);
};


#endif //SNOWDEVICE_INPUT_H
@@ -0,0 +1,25 @@
//
// Created by Karl on 12/12/2015.
//
#include "Inventory.h"
#include "position.h"

#ifndef SNOWDEVICE_PLAYER_H
#define SNOWDEVICE_PLAYER_H


struct Player {
char *playerGlyph;
public:
Player();

Player(int, int);

void render();

Position playerPosition;
Inventory playerInventory;
};


#endif //SNOWDEVICE_PLAYER_H
@@ -0,0 +1,33 @@
//
// Created by Karl on 12/12/2015.
//

#ifndef SNOWDEVICE_POSITION_H
#define SNOWDEVICE_POSITION_H


struct Position {
private:
int x;
int y;
int z;
public:
Position();

Position(int, int, int);

const int posX();

const int posY();

const int posZ();

void setX(int);

void setY(int);

void setZ(int);
};


#endif //SNOWDEVICE_POSITION_H
@@ -0,0 +1,34 @@
//
// Created by Karl on 12/12/2015.
//
#include <engine.h>
#include "BearLibTerminal.h"
#include "input.h"

void input::checkForInputAndBlock() {
int key = terminal_read();
parseInput(key);
return;
}

void input::parseInput(int suppliedKey) {
switch (suppliedKey) {
case TK_ESCAPE:
terminal_close();
break;
case TK_LEFT:
Engine::getInstance().movePlayerBy(-1, 0);
break;
case TK_RIGHT:
Engine::getInstance().movePlayerBy(1, 0);
break;
case TK_DOWN:
Engine::getInstance().movePlayerBy(0, 1);
break;
case TK_UP:
Engine::getInstance().movePlayerBy(0, -1);
break;
default:
break;
}
}
@@ -0,0 +1,19 @@
//
// Created by Karl on 12/12/2015.
//

#include "player.h"
#include "BearLibTerminal.h"

Player::Player(void) {
playerGlyph = (char *) "@";
playerPosition = Position();
}

Player::Player(int x, int y) {
playerPosition = Position(x, y, 0);
}

void Player::render() {
terminal_print(playerPosition.posX(), playerPosition.posY(), "@");
}
@@ -0,0 +1,39 @@
//
// Created by Karl on 12/12/2015.
//

#include "position.h"

const int Position::posX() {
return x;
}

const int Position::posY() {
return y;
}

const int Position::posZ() {
return z;
}

Position::Position() {
x = y = z = 0;
}

Position::Position(int suppliedX, int suppliedY, int suppliedZ) {
x = suppliedX;
y = suppliedY;
z = suppliedZ;
}

void Position::setX(int newX) {
x = newX;
}

void Position::setY(int newY) {
y = newY;
}

void Position::setZ(int newZ) {
z = newZ;
}
@@ -1,14 +1,17 @@
#include <BearLibTerminal.h>
#include <cstdio>
// Hide the console window

int main()
{
terminal_open();
terminal_print(1, 1, "Hello, world!");
terminal_refresh();
while (terminal_read() != TK_CLOSE);
terminal_close();
return 0;
#include "engine.h"

int main() {
terminal_open();
terminal_set
(
"input:"
"cursor-symbol = 0x1F,"
"cursor-blink-rate = 500,"
"precise-mouse = false,"
"mouse-cursor = true,"
"filter=[];"
);
Engine::getInstance().run();
return 0;
}