Commit 63d64450 authored by Stuart John Watson's avatar Stuart John Watson

Merge branch 'TilesAttemptB' into 'master'

Tiles attempt b

See merge request !3
parents 18167f2f e1d5cdfb
[submodule "src/lodepng"]
path = src/lodepng
url = https://github.com/lvandeve/lodepng.git
......@@ -14,10 +14,13 @@ add_executable(IdleCrawler
src/dungeon/dungeon.cpp
src/dungeon/rectangle.cpp
src/dungeon/space.cpp
src/dungeon/dungeonGenerator.cpp
src/dungeon/loader.cpp
src/entity/entity.cpp
src/entity/vision/vision.cpp
src/entity/vision/alive/alive.cpp
src/entity/vision/alive/mob/basicSolver.cpp
src/entity/vision/alive/mob/randomMove.cpp
src/entity/vision/alive/hero/hero.cpp
src/entity/vision/alive/hero/basicSolverHero.cpp)
src/entity/vision/alive/hero/basicSolverHero.cpp
src/lodepng/lodepng.cpp)
......@@ -16,6 +16,16 @@
### Build Instructions
After cloning the repository
```bash
git clone http://gitlab.sucs.org/rjames93/IdleCrawl.git
```
To build the project you will need to initialise the submodules that we use to provide functionality that we didn't feel was necessary to re implement for this project you can do this as follows
```bash
git submodule init
git submodule update
```
#### Requirements
- cmake
- X11
......@@ -32,7 +42,7 @@ cd build
cmake ../
make
make -j
```
......
#include "space.h"
#include "types.h"
#include <string>
#include <iostream>
#include <random>
#include <tuple>
#include <libconfig.h++>
#include "../configReader.h"
#include "types.h"
#include "space.h"
//Initilize statics
libconfig::Config cfg;
int _ = loadConfig(std::string("config.cfg"),&cfg);
const std::string VERSION = fromConfig(&cfg,"version",std::string(""));
const float Dungeon::ROOM_CHANCE = fromConfig(&cfg,"generator.pRoom",0.5f);
const int Dungeon::CORRI_MIN_LENGTH = fromConfig(&cfg,"generator.corridor.minLength",10);
const int Dungeon::CORRI_MAX_LENGTH = fromConfig(&cfg,"generator.corridor.maxLength",20);
const int Dungeon::CORRI_MIN_WIDTH = fromConfig(&cfg,"generator.corridor.minWidth",3);
const int Dungeon::COORI_MAX_WIDTH = fromConfig(&cfg,"generator.corridor.maxWidth",5);
const int Dungeon::ROOM_MIN_SIZE = fromConfig(&cfg,"generator.room.minSize",7);
const int Dungeon::ROOM_MAX_SIZE = fromConfig(&cfg,"generator.room.maxSize",19);
const int Dungeon::PLACE_TRIES = fromConfig(&cfg,"generator.nPlacetries",1000);
const int Dungeon::CONNECTION_TRIES = fromConfig(&cfg,"generator.connector.nTries",200);
const int Dungeon::CONNECTION_LENGTH= fromConfig(&cfg,"generator.connector.maxLength",10);
Dungeon::Dungeon(int _width,int _height,int seed) : Space(_width,_height){
generator = std::default_random_engine(seed);
}
std::tuple<int,int> Dungeon::upStairPosition(){
int x,y;
......@@ -36,6 +13,7 @@ std::tuple<int,int> Dungeon::upStairPosition(){
}
}
}
std::cerr << "Warning: No upstairs found";
return std::make_tuple(-1,-1);
}
......@@ -48,222 +26,6 @@ std::tuple<int,int> Dungeon::downStairPosition(){
}
}
}
std::cerr << "Warning: No downstairs found";
return std::make_tuple(-1,-1);
}
void Dungeon::populate(){
Space::populate();
//Chance we put a room instead of a corridor down
std::uniform_real_distribution<float> roomChance(0.0,1.0);
//Distribution for the length of our corridors
std::uniform_int_distribution<int> corriLength(Dungeon::CORRI_MIN_LENGTH,Dungeon::CORRI_MAX_LENGTH);
//Distribution for the width of our corridors
std::uniform_int_distribution<int> corriWidth(Dungeon::CORRI_MIN_WIDTH,Dungeon::COORI_MAX_WIDTH);
//Distribution for the size of our rooms (used for width and height sepertally)
std::uniform_int_distribution<int> roomSize(Dungeon::ROOM_MIN_SIZE,Dungeon::ROOM_MAX_SIZE);
/*/Chance we later knock down a joining wall for a door to increase conectivity
std::uniform_int_distribution<int> mergeDoor(1,20);*/
//Place a room in the center of the dungeon
Rectangle room = Rectangle(roomSize(generator),roomSize(generator));
room.populate();
insertSpace(room,getWidth()/2,getHeight()/2,MIDDLE_CENTER);
//Now keep trying to
for (int tries=0;tries<Dungeon::PLACE_TRIES;tries++){
//Locate a wall we can remove
std::tuple<int,int,LOCATION> removing = findWallToRemove();
int atX = std::get<0>(removing);
int atY = std::get<1>(removing);
LOCATION dir = std::get<2>(removing);
int roomWidth;
int roomHeight;
//Make a room or corridor to go there
if (roomChance(generator) < Dungeon::ROOM_CHANCE){
roomWidth = roomSize(generator);
roomHeight = roomSize(generator);
} else if (dir == TOP_CENTER || dir == BOTTOM_CENTER){
roomWidth = corriWidth(generator);
roomHeight = corriLength(generator);
} else if (dir == MIDDLE_LEFT || dir == MIDDLE_RIGHT){
roomWidth = corriLength(generator);
roomHeight = corriWidth(generator);
} else {
break;
}
//Put that corridor there if we can
Rectangle nRoom = Rectangle(roomWidth,roomHeight);
nRoom.populate();
if (not insertSpace(nRoom,atX,atY,dir)){
setTile(atX,atY,DOOR);
}
}
//Next up we are going to try and tunnel from 1 room/coridor to another to make more links
for (int tries=0;tries<Dungeon::CONNECTION_TRIES;tries++){
std::tuple<int,int,LOCATION> removing = findWallToRemove();
int atX = std::get<0>(removing);
int atY = std::get<1>(removing);
LOCATION dir = std::get<2>(removing);
//std::cerr << atX << atY << dir << std::endl;
if (dir == MIDDLE_CENTER){
break;
}
int chgX = 0;
int chgY = 0;
switch (dir){
case TOP_CENTER:
chgY = 1;
break;
case BOTTOM_CENTER:
chgY = -1;
break;
case MIDDLE_LEFT:
chgX = 1;
break;
case MIDDLE_RIGHT:
chgX = -1;
break;
}
int dist = 0;
int x=atX+chgX;
int y=atY+chgY;
int making = true;
while (dist<Dungeon::CONNECTION_LENGTH){
if (x == 0 || x == width-1 || y == 0 || y == height-1){
making = false;
break;
}
if (getTile(x,y) == WALL){
making = (getTile(x+chgX,y+chgY) == FLOOR);
break;
}
if (getTile(x,y) == FLOOR){
making = false;
break;
}
dist++;
x+=chgX;
y+=chgY;
}
if (!making || dist == Dungeon::CONNECTION_LENGTH){
continue;
}
Rectangle conn(abs(atX-x)+2*abs(chgY)+1,abs(atY-y)+2*abs(chgX)+1);
conn.populate();
if (insertSpace(conn,atX,atY,dir)){
//This shouldn't fail but maybe we didn't check something *shrug*
continue;
}
// Now add some fecking mobs to the game.
//Put the doors in
setTile(atX,atY,DOOR);
setTile(x,y,DOOR);
}
//Select stairs up and stairs down
int upX,upY,downX,downY;
int c = 0 ;
for(int x=1;x<width-1;x++){
for(int y=1;y<height-1;y++){
if (getTile(x-1,y-1) != FLOOR || getTile(x,y-1) != FLOOR || getTile(x+1,y-1) != FLOOR ||
getTile(x-1,y ) != FLOOR || getTile(x,y ) != FLOOR || getTile(x+1,y ) != FLOOR ||
getTile(x-1,y+1) != FLOOR || getTile(x,y+1) != FLOOR || getTile(x+1,y+1) != FLOOR
){
continue;
}
c++;
switch(c){
case 1:
upX=x;
upY=y;
break;
case 2:
downX=x;
downY=y;
break;
default:
std::uniform_int_distribution<int> dist(1,c);
switch(dist(generator)){
case 1:
upX=x;
upY=y;
break;
case 2:
upX=x;
upY=y;
break;
}
break;
}
}
}
setTile(upX,upY,STAIRS_UP);
setTile(downX,downY,STAIRS_DOWN);
// Now to place the Hero class on the STAIRS_UP block as if he just came down.
}
std::tuple<int,int,LOCATION> Dungeon::findWallToRemove(){
int c = 0;
int rX;
int rY;
LOCATION rD = MIDDLE_CENTER;
for(int x=1;x<width-1;x++){
for(int y=1;y<height-1;y++){
if (getTile(x,y) != WALL) {
continue;
}
TILE_TYPES up = getTile(x,y-1);
TILE_TYPES down = getTile(x,y+1);
TILE_TYPES left = getTile(x-1,y);
TILE_TYPES right = getTile(x+1,y);
LOCATION dir = MIDDLE_CENTER;
if (up == UNSET && down == FLOOR){
dir = BOTTOM_CENTER;
} else if (down == UNSET && up == FLOOR) {
dir = TOP_CENTER;
} else if (left == UNSET && right == FLOOR) {
dir = MIDDLE_RIGHT;
} else if (right == UNSET && left == FLOOR) {
dir = MIDDLE_LEFT;
} else {
continue;
}
std::uniform_int_distribution<int> dist(0,c++);
if (!dist(generator)){
rX = x;
rY = y;
rD = dir;
}
}
}
return std::make_tuple(rX,rY,rD);
}
#include <iostream>
#include <random>
#include <tuple>
#include <libconfig.h++>
#include "../configReader.h"
#include "types.h"
#include "space.h"
//Initilize statics
libconfig::Config cfg;
int _ = loadConfig(std::string("config.cfg"),&cfg);
const std::string VERSION = fromConfig(&cfg,"version",std::string(""));
const float DungeonGenerator::ROOM_CHANCE = fromConfig(&cfg,"generator.pRoom",0.5f);
const int DungeonGenerator::CORRI_MIN_LENGTH = fromConfig(&cfg,"generator.corridor.minLength",10);
const int DungeonGenerator::CORRI_MAX_LENGTH = fromConfig(&cfg,"generator.corridor.maxLength",20);
const int DungeonGenerator::CORRI_MIN_WIDTH = fromConfig(&cfg,"generator.corridor.minWidth",3);
const int DungeonGenerator::COORI_MAX_WIDTH = fromConfig(&cfg,"generator.corridor.maxWidth",5);
const int DungeonGenerator::ROOM_MIN_SIZE = fromConfig(&cfg,"generator.room.minSize",7);
const int DungeonGenerator::ROOM_MAX_SIZE = fromConfig(&cfg,"generator.room.maxSize",19);
const int DungeonGenerator::PLACE_TRIES = fromConfig(&cfg,"generator.nPlacetries",1000);
const int DungeonGenerator::CONNECTION_TRIES = fromConfig(&cfg,"generator.connector.nTries",200);
const int DungeonGenerator::CONNECTION_LENGTH= fromConfig(&cfg,"generator.connector.maxLength",10);
DungeonGenerator::DungeonGenerator(int _width,int _height,int seed) : Dungeon(_width,_height){
generator = std::default_random_engine(seed);
}
void DungeonGenerator::populate(){
Space::populate();
//Chance we put a room instead of a corridor down
std::uniform_real_distribution<float> roomChance(0.0,1.0);
//Distribution for the length of our corridors
std::uniform_int_distribution<int> corriLength(DungeonGenerator::CORRI_MIN_LENGTH,DungeonGenerator::CORRI_MAX_LENGTH);
//Distribution for the width of our corridors
std::uniform_int_distribution<int> corriWidth(DungeonGenerator::CORRI_MIN_WIDTH,DungeonGenerator::COORI_MAX_WIDTH);
//Distribution for the size of our rooms (used for width and height sepertally)
std::uniform_int_distribution<int> roomSize(DungeonGenerator::ROOM_MIN_SIZE,DungeonGenerator::ROOM_MAX_SIZE);
/*/Chance we later knock down a joining wall for a door to increase conectivity
std::uniform_int_distribution<int> mergeDoor(1,20);*/
//Place a room in the center of the DungeonGenerator
Rectangle room = Rectangle(roomSize(generator),roomSize(generator));
room.populate();
insertSpace(room,getWidth()/2,getHeight()/2,MIDDLE_CENTER);
//Now keep trying to
for (int tries=0;tries<DungeonGenerator::PLACE_TRIES;tries++){
//Locate a wall we can remove
std::tuple<int,int,LOCATION> removing = findWallToRemove();
int atX = std::get<0>(removing);
int atY = std::get<1>(removing);
LOCATION dir = std::get<2>(removing);
int roomWidth;
int roomHeight;
//Make a room or corridor to go there
if (roomChance(generator) < DungeonGenerator::ROOM_CHANCE){
roomWidth = roomSize(generator);
roomHeight = roomSize(generator);
} else if (dir == TOP_CENTER || dir == BOTTOM_CENTER){
roomWidth = corriWidth(generator);
roomHeight = corriLength(generator);
} else if (dir == MIDDLE_LEFT || dir == MIDDLE_RIGHT){
roomWidth = corriLength(generator);
roomHeight = corriWidth(generator);
} else {
break;
}
//Put that corridor there if we can
Rectangle nRoom = Rectangle(roomWidth,roomHeight);
nRoom.populate();
if (not insertSpace(nRoom,atX,atY,dir)){
setTile(atX,atY,DOOR);
}
}
//Next up we are going to try and tunnel from 1 room/coridor to another to make more links
for (int tries=0;tries<DungeonGenerator::CONNECTION_TRIES;tries++){
std::tuple<int,int,LOCATION> removing = findWallToRemove();
int atX = std::get<0>(removing);
int atY = std::get<1>(removing);
LOCATION dir = std::get<2>(removing);
//std::cerr << atX << atY << dir << std::endl;
if (dir == MIDDLE_CENTER){
break;
}
int chgX = 0;
int chgY = 0;
switch (dir){
case TOP_CENTER:
chgY = 1;
break;
case BOTTOM_CENTER:
chgY = -1;
break;
case MIDDLE_LEFT:
chgX = 1;
break;
case MIDDLE_RIGHT:
chgX = -1;
break;
}
int dist = 0;
int x=atX+chgX;
int y=atY+chgY;
int making = true;
while (dist<DungeonGenerator::CONNECTION_LENGTH){
if (x == 0 || x == width-1 || y == 0 || y == height-1){
making = false;
break;
}
if (getTile(x,y) == WALL){
making = (getTile(x+chgX,y+chgY) == FLOOR);
break;
}
if (getTile(x,y) == FLOOR){
making = false;
break;
}
dist++;
x+=chgX;
y+=chgY;
}
if (!making || dist == DungeonGenerator::CONNECTION_LENGTH){
continue;
}
Rectangle conn(abs(atX-x)+2*abs(chgY)+1,abs(atY-y)+2*abs(chgX)+1);
conn.populate();
if (insertSpace(conn,atX,atY,dir)){
//This shouldn't fail but maybe we didn't check something *shrug*
continue;
}
// Now add some fecking mobs to the game.
//Put the doors in
setTile(atX,atY,DOOR);
setTile(x,y,DOOR);
}
//Select stairs up and stairs down
int upX,upY,downX,downY;
int c = 0 ;
for(int x=1;x<width-1;x++){
for(int y=1;y<height-1;y++){
if (getTile(x-1,y-1) != FLOOR || getTile(x,y-1) != FLOOR || getTile(x+1,y-1) != FLOOR ||
getTile(x-1,y ) != FLOOR || getTile(x,y ) != FLOOR || getTile(x+1,y ) != FLOOR ||
getTile(x-1,y+1) != FLOOR || getTile(x,y+1) != FLOOR || getTile(x+1,y+1) != FLOOR
){
continue;
}
c++;
switch(c){
case 1:
upX=x;
upY=y;
break;
case 2:
downX=x;
downY=y;
break;
default:
std::uniform_int_distribution<int> dist(1,c);
switch(dist(generator)){
case 1:
upX=x;
upY=y;
break;
case 2:
upX=x;
upY=y;
break;
}
break;
}
}
}
setTile(upX,upY,STAIRS_UP);
setTile(downX,downY,STAIRS_DOWN);
// Now to place the Hero class on the STAIRS_UP block as if he just came down.
}
std::tuple<int,int,LOCATION> DungeonGenerator::findWallToRemove(){
int c = 0;
int rX;
int rY;
LOCATION rD = MIDDLE_CENTER;
for(int x=1;x<width-1;x++){
for(int y=1;y<height-1;y++){
if (getTile(x,y) != WALL) {
continue;
}
TILE_TYPES up = getTile(x,y-1);
TILE_TYPES down = getTile(x,y+1);
TILE_TYPES left = getTile(x-1,y);
TILE_TYPES right = getTile(x+1,y);
LOCATION dir = MIDDLE_CENTER;
if (up == UNSET && down == FLOOR){
dir = BOTTOM_CENTER;
} else if (down == UNSET && up == FLOOR) {
dir = TOP_CENTER;
} else if (left == UNSET && right == FLOOR) {
dir = MIDDLE_RIGHT;
} else if (right == UNSET && left == FLOOR) {
dir = MIDDLE_LEFT;
} else {
continue;
}
std::uniform_int_distribution<int> dist(0,c++);
if (!dist(generator)){
rX = x;
rY = y;
rD = dir;
}
}
}
return std::make_tuple(rX,rY,rD);
}
#include "space.h"
#include "types.h"
#include <string>
#include <fstream>
#include <streambuf>
#include <iostream>
Loader::Loader(int w,int h,std::string _filename): Dungeon(w,h){
filename = _filename.c_str();
}
TILE_TYPES TILE_REVERSE_LOOKUP(char c){
switch (c) {
case ' ': return UNSET;
case '#': return WALL;
case '.': return FLOOR;
case '+': return DOOR;
case '^': return STAIRS_UP;
case 'v': return STAIRS_DOWN;
case '~': return UNSEEN;
}
}
void Loader::populate(){
Space::populate();
std::ifstream f(filename);
int xAt = 0;
int yAt = 0;
char c = f.get();
while (!f.eof()){
if (c=='\n'){
yAt ++;
xAt = 0;
} else {
setTile(xAt,yAt,TILE_REVERSE_LOOKUP(c));
xAt++;
}
c = f.get();
}
}
......@@ -33,15 +33,20 @@ protected:
class Dungeon : public Space {
public:
Dungeon(int,int,int);
using Space::Space;
std::tuple<int,int> upStairPosition();
std::tuple<int,int> downStairPosition();
};
class DungeonGenerator : public Dungeon {
public:
DungeonGenerator(int,int,int);
void populate();
protected:
std::default_random_engine generator;
std::tuple<int,int,LOCATION> findWallToRemove();
public:
std::tuple<int,int> upStairPosition();
std::tuple<int,int> downStairPosition();
const static float ROOM_CHANCE;
const static int CORRI_MIN_LENGTH;
const static int CORRI_MAX_LENGTH;
......@@ -61,4 +66,12 @@ public:
};
class Loader : public Dungeon {
public:
Loader(int,int,std::string);
void populate();
protected:
const char* filename;
};
#endif
......@@ -11,7 +11,7 @@ enum TILE_TYPES {
STAIRS_DOWN,
UNSEEN
};
const char TILES_TYPES_MAP[]= {' ','#','.','+','^','v','+'};
const char TILES_TYPES_MAP[]= {' ','#','.','+','^','v','~'};
const int TILE_COLOUR_MAP[] = {0x607D8B,0x212121,0xFAFAFA,0x795548,0x4CAF50,0xFF9800,0x607D8B};
enum LOCATION {
......
......@@ -5,6 +5,7 @@
#include "hero.h"
BasicSolverHero::BasicSolverHero(Dungeon &_dungeon,int _x,int _y,int _viewDistance) : Hero(_dungeon,_x,_y,_viewDistance){
//std::cerr << &_dungeon << std::endl;
std::stack<std::tuple<int,int>> trail;
findSolution();
}
......@@ -25,6 +26,8 @@ void BasicSolverHero::findSolution(){
int doY = std::get<1>(pos);
int doN = tiles[doX*height+doY]+1;
//std::cerr << doX << "," << doY << "," << doN << std::endl;
if(dungeon.getTile(doX,doY) == STAIRS_DOWN){
trail.push(std::make_tuple(doX,doY));
break;
......
......@@ -168,3 +168,25 @@ void Vision::drawLevel(Display*& dpy,Window& w,GC& gc,int scale){
}
}
}
void Vision::drawTiles(Display *& dpy, Window &w, GC &gc,int scale,Pixmap *tiles){
Colormap colormap;
colormap = DefaultColormap(dpy, 0);
const int VIEW_DIAM = (viewDistance * 2) + 1;
for(int sx=0; sx < VIEW_DIAM; sx++){
for(int sy=0; sy < VIEW_DIAM; sy++){
int mapX = ( x + sx - viewDistance);
int mapY = ( y + sy - viewDistance);
if(mapX < 0 || mapY < 0 || mapX >= dungeon.getWidth() || mapY >= dungeon.getHeight() ){
continue;
}
std::cerr << "(" << mapX << "," << mapY << ")" << " - " << fov[ mapY * dungeon.getWidth() + mapX ] << std::endl;
TILE_TYPES t = fov[ mapY * dungeon.getWidth() + mapX ];
XCopyArea(dpy,tiles[t],w,gc,0,0,32,32,sx*32,sy*32);
}
}
}
......@@ -2,6 +2,7 @@
#define VISION_H
#include "../entity.h"
#include <X11/Xlib.h>
class Vision: public Entity { // This class is supposed to give the hero, mob, anything else that needs vision it's field of view. Therefore everything that needs to see or react to the environment needs to inherit from it.
public:
......@@ -9,6 +10,7 @@ class Vision: public Entity { // This class is supposed to give the hero, mob, a
char canSeeTile(int, int, int, int);
void updateFOW();
void drawLevel(Display*&,Window&,GC&,int);
void drawTiles(Display*&,Window&,GC&,int,Pixmap*);
protected:
TILE_TYPES *fov;
int viewDistance;
......
......@@ -9,6 +9,7 @@
#include <memory>
#include "../entity/vision/alive/mob/mob.h"
#include "../vroot.h"
#include "../lodepng/lodepng.h"
Game::Game(int _root):rootWindow(_root){
}
......@@ -18,103 +19,170 @@ Game::~Game(){
}
void Game::loop(){
// Start game loop
//Setup the display and window
Display *dpy = XOpenDisplay(NULL);
int blackColor = WhitePixel(dpy, DefaultScreen(dpy));