Texty: An Animated C++ Game

Texty is a windows console app written in C++ for an assignment. I wanted to explore how far I could take the console and also take a look into game engines. The overall gameplay is tenuous at best, but the look and feel go beyond what I had of thought a console application could produce.

The premise of the actual game play is to navigate a maze of rooms in which you have no orientation. Collect items, defeat monsters and solve riddles.

I don't believe there is actually an ending!@

When I wrote this I was pretty interested in decoupling my code, I was also reading stuff about data oriented design and trying to fight the OO approach. There's a decent amount of code so I'll only be showing the bits I find most interesting. The codebase is made up of an editor, a string library and the game itself. Though I will only show the game here.

The main is very clean, easy to read and simple. if only the rest of the application was too! It looks like this:


int main()
{
	Engine* e = Engine::Get();			//bit easier
	e->AddSystem(StateManager::Get());		//push subsystems to engines system list
	e->Init();					//init engine and all subsystems (only 1 subsystem left lol)
	e->ShowCursor(false);				//hide that ugly cursor

	IntroState* s = new IntroState();		//create first state.. statemanager will delete this
	StateManager::Get()->Push(*s);			//push state onto our states stack

	e->MainLoop();					//enter our main loop!
}
			

The game engine is based off this awesome book: www.gameprogrammingpatterns.com. It is sort of a frankenstein as it has an observer, singleton and statemanager in it, not to mention I may have bent some of the ideas to meet my goals, not great but learning is learning.

At engine init, we set up our window title, size, load our assets (which in itself is a pretty cool function!) The mainloop controls the framerate, as originally it had 1000s of frames per second. It also calls update on all the subsystems, which is where the main processing is done.



void Engine::Init()
	{
		HANDLE hndW = GetStdHandle(STD_OUTPUT_HANDLE);

		SMALL_RECT windowsz = { 0, 0, _wWidth - 1, _wHeight - 1 };	//make window size smaller than actual to hide scrollbar on side
		COORD buffsz = { _wWidth, _wHeight };

		//set window properties
		SetConsoleTitleA(_wTitle);
		SetConsoleWindowInfo(hndW, TRUE, &windowsz);
		SetConsoleScreenBufferSize(hndW, buffsz);

		bool errexit = false;
		if (!Assets::LoadMonstersFile("Monsters.txt"))	errexit = true;		//fill our main structs (monsters, items, riddles)
		if (!Assets::LoadItemsFile("Items.txt"))		errexit = true;	//if failed to load, free memory and exit
		if (!Assets::LoadRiddlesFile("Riddles.txt"))	errexit = true;
		if (errexit){
			printf_s("Failed to load asset files.");
			getchar();
			ProcessExit();
			exit(0);
		}

		//init all subsystems *down to only one* lol
		for (int i = 0; i < _nSystems; ++i)
			_systems[i]->Init();
	}

	void Engine::MainLoop()
	{
		int now = (int)time(0), lastframe = now, dt;

		while (!_wantExit){				//loop while we dont want to quit
			now = (int)time(0);
			dt = now - lastframe;
			lastframe = now;

			if (dt < _frameRate)			//if our framerate is too fast, wait for some time
				Sleep(_frameRate - dt);

			for (int i = 0; i < _nSystems; ++i)	//loop through subsystems and call their updates
				_systems[i]->Update();

			if (_wantExit)				//if something wants to exit then call destroy for all systems
				ProcessExit();
		}
	}

	void Engine::ShowCursor(bool show)
	{
		HANDLE hndW = GetStdHandle(STD_OUTPUT_HANDLE);
		CONSOLE_CURSOR_INFO cursorInfo;
		GetConsoleCursorInfo(hndW, &cursorInfo);
		cursorInfo.bVisible = show;
		SetConsoleCursorInfo(hndW, &cursorInfo);
	}

		

The file reader was designed to read a file in order to fill a struct without knowing the layout of the struct. This let me use the same filereader function for reading in all the different asset files which had different formats. It's also super enjoyable writing code like this.

Doing this introduced a pretty good understanding of structs and padding. I'm sure it's not the most efficient way of doing things but it sure was fun. The comments provide most of the insights.




//Example: format: "%s32%i%i" => struct unknown { char[32]; int; int } or "%i%c%p3"  => struct unknown { int; char;  }

#include "FileReader.h"
#include 
#include 

int FileReader::CountLines(const char* fname)	//assumes there is at least one valid line^^
{
	FILE* fp;
	int c, lines = 1;
	fopen_s(&fp, fname, "r");				//open file
	if (!fp) return 0;						//if couldnt open file return false
	while ((c = fgetc(fp)) != EOF)			//while getc isnt endoffile
		if (c == '\n')						//if char is a new line , count it
			++lines;
	fclose(fp);								//close file
	return lines;							//return count
}

int FileReader::Read(void*& strct, int size, const char* fmt, const char* fname)
{
	unsigned int numLines = CountLines(fname);		//read how many records we need to store
	if (!numLines) return 0;						//either no lines in file, or file couldnt be opened

	FILE* fp;
	fopen_s(&fp, fname, "r");						//open file (again)
	if (!fp) return 0;

	strct = operator new(numLines*size);

	char line[256] = { 0 }, buffer[256] = { 0 };			//some buffers to handle reading file
	char* fmtptr = (char*)fmt, *strctptr = (char*)strct;	//pointer to start of struct and start of formatting
	char* bufptr = nullptr, *lineptr = nullptr;

	while (fgets(line, sizeof(line), fp)) {			//while we get line
		lineptr = (char*)line;						//set lineptr to start of line
		while (*fmtptr){							//looop through our formatting, since we use this to copy in correct order
			bufptr = (char*)buffer;					//reset our buffer pointer
			if (*fmtptr == '%')						//move fmtptr to an interesting point
				++fmtptr;
			while (*lineptr && *lineptr != '\n' && *lineptr != '\t')	//copy data from line to buffer
				*bufptr++ = *lineptr++;
			*bufptr = 0, lineptr++;					//add null char
			switch (*fmtptr)						//switch formatting to handle different types of data
			{
			case 's':								//if its a string
			{
				int strlen = _getfmtstrlen(fmtptr);	//determine how much we need to offset
				strcpy_s(strctptr, strlen, buffer);	//copy buffer to struct
				strctptr += strlen;					//move structptr to pass the cstring variable within struct
				break;
			}
			case 'c':											//if its just a char
			{
				fmtptr++;										//must fmtptr++ for next iteration
				*(char*)strctptr = buffer[0];					//copy first char to struct
				strctptr += sizeof(char);						//move passed char
				break;
			}
			case 'i':											//if its an int
			{
				fmtptr++;										//must fmtptr++ for next iteration
				*(unsigned int*)strctptr = atoi(buffer);		//copy buffer to int
				strctptr += sizeof(unsigned int);				//move structptr past int
				break;
			}
			case 'p':											//if padding
			{
				fmtptr++;
				char c[2] = { *fmtptr++, 0 };					//padding shouldnt be more than 3 bytes
				strctptr += atoi(c);							//skip it some amount
				break;
			}
			}
		}
		fmtptr = (char*)fmt;									//next record, start over again
	}
	fclose(fp);
	return numLines;											//return how many records in struct
}

int FileReader::_countchar(char find, const char* str)	//counts char in a string - not used anymore
{
	char* cp = (char*)str;								//set pointer to start of string
	int counter = 0;
	while (*cp)											//while we have string
		if (*cp++ == find)								//if current pos == find
			++counter;									//increment counter
	return counter;
}

int FileReader::_getfmtstrlen(char* &fmtptr)
{
	char tmp[5] = { 0 };		//temp place to hold ints
	for (int i = 0; i < sizeof(tmp) && *fmtptr++ && *fmtptr != '\n' && *fmtptr != '\t' && *fmtptr != '%'; ++i)
		tmp[i] = *fmtptr;		//while its an int, copy it to our temp spot
	return atoi(tmp);			//return it as an int
}

		

One of the more complex areas is the rendering system. I faced several issues with getting to what I thought was an acceptable look, the first major hurdle was the collision system. Originally the objects would overlap each other before collision was detected, the other issue was knowing where they collided whether it was on the horizontally, diagonally or vertically. I created bounding boxes, where the bounding box stores an array of indexes related to the canvas's index, so if two items are drawn in the same spot on the canvas then they will collide here.

Only the first 16bits are used to store the index, and bits 17/18 are used to indicate where the bound is if its on the side for example, it only needs to reverse the x velocity, and if its ontop it only needs the y velocity.

Below the FillCanvas() is the man workhorse of the Renderer class. It's main purpose is to fill the screen buffer (canvas) with all the objects that need to be rendererd. Afterwards drawing to the screen is as simple as calling WriteConsoleOutput() with our screen buffer.

It was super dooper fun playing with bits



//***********RENDERER.CPP
	void Renderer::FillCanvas()
	{
		int ww = Engine::Get()->GetWindowWidth();		//width of window
		int iCanvas, iCurrent;
		int cW = _canvas->GetWidth();
		int cH = _canvas->GetHeight();
		RenderObject* cur = NULL;

		_canvas->Clear();	//way easier to just clear canvas instead of updating only those that need updating (moving objects make it tedious)

		for (auto current = _renderMap.begin(); current != _renderMap.end(); current++){	//for each object to be rendered
			cur = current->second;								//set pointer to current for easier typing
				if (cur->GetVX() || cur->GetVY()){					//if its moving then move it and check for collision against all other objects
					cur->Move();
					for (auto nxt = _renderMap.begin(); nxt != _renderMap.end(); nxt++){
						if (cur != nxt->second && cur->CheckCollision(nxt->second))
							break;						//collision occured, break out of loop
					}
				}
				if (cur->isDraw()){							//if its drawn then
				//loop through buffer and calc index -> copies buffer to _canvas so can draw all objects at once
				for (int y = 0; y < current->second->GetHeight() && y < cH; ++y){		//loop through buffer
					for (int x = 0; x < current->second->GetWidth() && x < cW; ++x){
						iCanvas = (x + cur->GetPosX()) + ww *(y + cur->GetPosY());	//index to array pos for canvas buffer
						iCurrent = x + cur->GetWidth()*y;				//index to array pos for objs buffer

						if (cur->GetCharAt(iCurrent)){					//only copy stuff if there is something there
							_canvas->WriteToBuffer(iCanvas, cur->GetCharAt(iCurrent), cur->GetColourAt(iCurrent));
						}
					}
				}
			}
		}
	}
//***********RENDEROBJECT.CPP
unsigned int unpack(unsigned int element)		//returns first two bytes as unsigned int
	{
		unsigned char c1 = element, c2 = element >> 8;
		return ((c2 << 8) + c1);
	}

	void RenderObject::CreateBoundingBox()
	{
		int count = 0, ind, n = _w*_h;		//todo maybe remove rundandcies
		for (int i = 0; i < n; ++i){
			if (_buffer[i].Char.AsciiChar != 0)
				++count;
		}
		_boundingBoxSz = count * 5;
		if (count){
			if (_boundingBox)
				delete[]_boundingBox;
			_boundingBox = new unsigned int[_boundingBoxSz];
			for (int i = 0; i < n; ++i){
				if (_buffer[(i / n) + _w*(i % n)].Char.AsciiChar != 0){
					ind = ((1 / n) + _window.Left) + 79 * ((i%n) + _window.Top);
					_boundingBox[i] = ind - 1;	//to left		vx
					_boundingBox[i] |= 1 << 17;

					_boundingBox[++i] = ind;	//to left		vx
					_boundingBox[i] |= 1 << 17;

					_boundingBox[++i] = ind + 1;	//to right		vx
					_boundingBox[i] |= 1 << 17;

					_boundingBox[++i] = ind - 79;	//above			vy
					_boundingBox[i] |= 1 << 16;

					_boundingBox[++i] = ind + 79;	//below			vy
					_boundingBox[i] |= 1 << 16;
				}
			}
		}
	}
	/*
	Loops through this objects boundery array and a given one, it then checks if they hit,
	then it reads the bit flags to change velocities (read bitflags above function)
	*/
	bool RenderObject::CheckCollision(RenderObject* nxt)
	{	//some checks
		if (!_boundingBox || !nxt->_boundingBox || !_solid || !nxt->isSolid() || !nxt->isDraw()) return false;
		bool colx = false, coly = false, col = false;
		unsigned int x;
		for (unsigned int i = 0; i < _boundingBoxSz; ++i){
			for (unsigned int j = 0; j < nxt->_boundingBoxSz; ++j){				//loop through both bounding boxes
				if (unpack(_boundingBox[i]) == unpack(nxt->_boundingBox[j])){	//if there is a match
					x = nxt->_boundingBox[j];
					if ((x >> 17) & 1 && !colx){			//vx flag and not changed vx yet
						_vx *= -1;							//reverse vx
						colx = true;
					}
					else if ((x >> 16) & 1 && !coly){		//vy flag and not changed vy yet
						_vy *= -1;							//reverse vy
						coly = true;
					}
				}
			}
			if (!col && (coly || colx)){	//only check col once col is true instead of coly and colx
				if (nxt->GetVX() || nxt->GetVY())nxt->Move();
				col = true;
			}
			coly = colx = false;
		}
		return col;
	}

		

Each renderObject is made up of:



RenderObject::RenderObject(int x, int y, int w, int h)
		:_vx(0),
		_vy(0),
		_solid(1),
		_x(-1),
		_y(-1),
		_draw(true),
		_boundingBoxSz(0)
	{
		_id = s_idGen++;		//get our unique instance id (for render map)
		_w = w;				//store our widths heights
		_h = h;
		_window.Top = y;		//setup our window ->window not really needed but i like to be able to draw without renderer
		_window.Left = x;
		_window.Right = x + w;
		_window.Bottom = y + h;
		_buffer = new CHAR_INFO[w*h];	//allocate enough size for our buffer
		Clear();			//clear garbage from object
	}

Due to the drawing being done with WriteConsoleOutput() which accepts an array of CHAR_INFO structs, for simplicity, my renderObjects all used the same buffer. This meant for each access, the actual position within the array had to be derived from the x position, y position and the width of buffer. The functions to note are: RenderObject::Write() which is the actual writing to the console, it is only a couple lines long.



	void RenderObject::Clear()		//clears buffer
	{
		for (int y = 0; y < _h; ++y){		//for all rows
			for (int x = 0; x < _w; ++x){	//for columns
				_buffer[x + _w*y].Char.AsciiChar = 0;	//set that to 0
				_buffer[x + _w*y].Attributes = 0;	//set colour to 0
			}
		}
	}

	void RenderObject::Fill(char c, unsigned int colour)	//fillls buffer with something (see above function)
	{
		for (int y = 0; y < _h; ++y){
			for (int x = 0; x < (_w); ++x){
				_buffer[x + _w*y].Char.AsciiChar = c;
				_buffer[x + _w*y].Attributes = colour;
			}
		}
	}

	void RenderObject::WriteToBuffer(int index, unsigned char c, unsigned int colour)
	{
		_buffer[index].Char.AsciiChar = c;
		_buffer[index].Attributes = colour;
	}

	void RenderObject::Write()	//writes the buffer to screen, bypass renderer
	{
		if (_draw){
			HANDLE hndW = GetStdHandle(STD_OUTPUT_HANDLE);
			WriteConsoleOutput(hndW, _buffer, { _w, _h }, { 0, 0 }, &_window);
		}
	}

	void RenderObject::Plot(const COORD& pt, unsigned char c, unsigned int colour) //copies point to buffer
	{
		int index = pt.X + _w*pt.Y;			//calcs index of point to our buffer
		_buffer[index].Char.AsciiChar = c;
		_buffer[index].Attributes = colour;
	}

	void RenderObject::DrawBox(const COORD& start, int w, int h, unsigned char c, unsigned int colour) //draws box
	{
		h = start.Y + h;
		w = start.X + w;
		for (int y = start.Y; y < h && y <= _window.Bottom; ++y){
			for (int x = start.X; x < w && x <= _window.Right; ++x){
				if (y == start.Y || x == start.X || x == w - 1 || y == h - 1)
					Plot({ x, y }, c, colour);
			}
		}
	}

Now that all the drawing and engine stuff is accounted for, the statemanager is as simple as pushing on a state and popping it off. Only the most recent state will be updated. For this game the ESC will pop a state, so to exit back to the main intro screen, it is only ever one button away.

The code for the initial gamestate is super simple for everything it does. The DrawPlay() looks a bit crazy but it is just an unrolled loop to make things simpler and faster. Essentially it's just moving pixles into the middle of the screen to form the word PLAY



#include "IntroState.h"
#include "GameState.h"
#include 

namespace Texty{
	IntroState::IntroState()
		:_play(false),
		_nextState(nullptr)
	{
		int ww = Engine::Get()->GetWindowWidth();
		int wh = Engine::Get()->GetWindowHeight();

		for (int i = 0; i < MAX_PLAYTHING; ++i){
			_plaything[i].CreateRenderObject(rand() % (ww - 10) + 5, rand() % (wh-10) + 5, 1, 1);		//create bunch of objects at random position
			_plaything[i].Plot({ 0, 0 }, CHAR_BLOCK, (i < 93 ? WHITE : rand() % COLOUR_MAX - 1 + 1));	//plot boxes, PLAY in white, extra in random colour
			_plaything[i].SetV((i % 2 ? 1 : -1), (i % 2 ? 1 : -1));					//set all to velocity with x,y
			_plaything[i].CreateBoundingBox();							//create bounding box so they collide
			_renderer.Insert(_plaything[i].GetId(), &_plaything[i]);				//insert them into renderer
		}
	}

	void IntroState::Update()
	{
		_renderer.Update();		//draw our objects
		if (_kbhit() != 0) {		//if keyboard hit, do something
			int c = _getch();
			if (c == 27){		//escape key
				StateManager::Get()->WantPop();	//pop state next chance we get - will exit game
			}
			else if (!_play){	//if its first keypress, do some pretty stuff
				DrawPLAY();	//pretty play word
				_play = true;	//next key hit will mean we play
			}
			else{			//second key hit push our gamestate on
				_play = false;
				for (int i = 0; i < MAX_PLAYTHING; ++i){	//setting up this state so when we return it looks nicer
					_plaything[i].SetV((i % 2 ? 1 : -1), (i % 2 ? 1 : -1));
				}
				_nextState = new GameState();			//create our new state
				StateManager::Get()->Push(*_nextState);		//push our new state onto stack
			}
		}
	}

	IntroState::~IntroState()
	{
	}

	/*
		prettiest function ever!
		loooks pretty bad but won't somebody please think about the performance!
		i think there are roughly 100(+-10) objects to loop through, it does it in 10 iterations!
	*/
	void IntroState::DrawPLAY()
	{
		static const int ALIGNX = Engine::Get()->GetWindowWidth() / 2 - 15;	//just so its only ever called once
		static const int ALIGNY = Engine::Get()->GetWindowHeight() / 2 - 10;

		//VERTICAL LINES ONLY
		for (int i = 0; i < 7; ++i){
			_plaything[i].MoveTo(ALIGNX, ALIGNY + i);				//P
			_plaything[i + 7].MoveTo(ALIGNX + 1, ALIGNY + i);		//P
			_plaything[i + 14].MoveTo(ALIGNX + 9, ALIGNY + i);		//L
			_plaything[i + 21].MoveTo(ALIGNX + 10, ALIGNY + i);		//L
			_plaything[i + 28].MoveTo(ALIGNX + 16, ALIGNY + i);		//A
			_plaything[i + 35].MoveTo(ALIGNX + 17, ALIGNY + i);		//A
			_plaything[i + 42].MimgoveTo(ALIGNX + 21, ALIGNY + i);		//A
			_plaything[i + 49].MoveTo(ALIGNX + 22, ALIGNY + i);		//A
			if (i < 4){
				_plaything[i + 56].MoveTo(ALIGNX + 5, ALIGNY + i);	//P
				_plaything[i + 60].MoveTo(ALIGNX + 6, ALIGNY + i);	//P
			}
			else{
				_plaything[i + 60].MoveTo(ALIGNX + 28, ALIGNY + i); //Y
				_plaything[i + 63].MoveTo(ALIGNX + 29, ALIGNY + i); //Y
			}
		}
		//horizontal lines
		for (int i = 0, j = 70; i < 3; ++i, ++j){
			_plaything[j].MoveTo(ALIGNX + i + 2, ALIGNY);				//P
			_plaything[j + 3].MoveTo(ALIGNX + i + 2, ALIGNY + 3);		//P
			_plaything[j + 6].MoveTo(ALIGNX + i + 11, ALIGNY + 6);		//L
			_plaything[j + 9].MoveTo(ALIGNX + i + 18, ALIGNY);			//A
			_plaything[j + 12].MoveTo(ALIGNX + i + 18, ALIGNY + 3);		//A
			_plaything[j + 15].MoveTo(ALIGNX + i + 25, ALIGNY + i);		//Y
			_plaything[j + 19].MoveTo(ALIGNX + 29 + i, ALIGNY + 3 - i);	//Y
		}
		_plaything[88].MoveTo(ALIGNX + 28, ALIGNY + 3);		//end of y
		_plaything[92].MoveTo(ALIGNX + 32, ALIGNY);
	}
}

Into the action! Intro scene combined with some gameplay

One of the main features of the game is the cool textbox. It draws the box and lines with functions from above. It features easy to use coloured text inspired by the Wolf:ET chat system although instead of using ^3 it uses _3_. An echo function is needed to show typed characters.

The animation of the doors is simply leveraging the draw system with MoveTo() as well as drawing after set frames.



  ///usage _currentGS->WriteToTextBox("_15_This room requires a _14_%s_15_ in order to be accessed.", Assets::s_items[_item].name);

  void TextBox::WriteToTextBox(const char* txt, ...)	//saves me using buffers && sprintf all over the place
	{
		//i would like to be able to change colour on the fly, _#_ where # represents colour code
		//so _12_THIS IS RED_13_THIS IS WHITE ==> THIS IS RED THIS IS WHITE
		char buffer[512] = { 0 };
		va_list va;
		va_start(va, txt);
		vsprintf_s(buffer, sizeof(buffer), txt, va);
		va_end(va);

		_output = buffer;

		if (_output.Length()){								//if there is text to write
			if (_currentLine > _textBox->GetHeight() - 4){	//if there are no more lines, then clear box and restart from line 1
				_currentLine = 1;
				ClearTextBox();
			}
			for (int x = _textBox->GetPosX() + 1, i = 0; i<_output.Length() && x < _textBox->GetWidth()-1; ++x, ++i){
				if (_output.CharAt(i) == '-' && _output.CharAt(i + 1) == 'n'){		//if newline then add a new line
					i += 2;
					++_currentLine;
					x = _textBox->GetPosX()+1;
				}
				if (_output.CharAt(i) == '_'){			//see if colour code in string
					_colour = _output.GetIntAt(i);		//set our colour
					if (_colour == -1)					//if it wasnt a colour code, set it back to default
						_colour = WHITE;
				}
				//if (_colour > WHITE && _colour <= 1)
				//	getchar();
				_textBox->WriteToBuffer(x + _textBox->GetWidth()*_currentLine, _output.CharAt(i), _colour);
			}
			_currentLine++;		//increment line
			//printf_s("%i", _colour);
			//getchar();
		}
	}

	void TextBox::ClearInputBox()	//only clear echo area - dont want what we type sticking in input area
	{
		const static int echoline = _textBox->GetHeight() - 2;
		if (_input.Length()){
			for (int x = _textBox->GetPosX() + 2, i = 0; x < _textBox->GetWidth()-1; ++x, ++i){
				_textBox->WriteToBuffer(x + _textBox->GetWidth()*echoline, (unsigned int)0, (unsigned int)0);
			}
		}
	}

	void TextBox::Echo()	//echo what keys we type so we can see what we read
	{
		const static int echoline = _textBox->GetHeight()-2;
		if (_input.Length()){
			for (int x = _textBox->GetPosX()+2, i = 0; x < _input.Length()+2; ++x, ++i){
				_textBox->WriteToBuffer(x + _textBox->GetWidth()*echoline, _input.CharAt(i), WHITE);
			}
		}
	}
}

  

An array is used to create the rooms, the array is randomly filled with locked rooms, monster rooms, riddle rooms and empty rooms. The riddle room consists of a random riddle where the correct answer grants a random reward. A monster room contains a random monster, some monsters are only defeatable with a good weapon equipped. A locked room requires a specific item, which may need to be farmed from riddles and Monsters , it is terribly flawed as you can go back and forth to gather lots of items quickly.

Here is part of the gamestate plus some of the room code. All items and riddles etc are loaded from .txt files on start up



  //	gamestate creation, how the rooms are created.

  for (int y = 0; y < ROOM_H; ++y){
			for (int x = 0; x < ROOM_W; ++x){
				if ((x || y) && !(rand() % 4))		//yukky but ensures first door isnt locked
					_rooms[x][y] = new LockedRoom(this, rand() % 3, rand() % 3, rand() % 3);
				else if (!(rand() % 2))
					_rooms[x][y] = new MonsterRoom(this, rand() % 3, rand() % 3, rand() % 3);
				else if (!(rand() % 2))
				_rooms[x][y] = new RiddleRoom(this, rand() % 3, rand() % 3, rand() % 3);
				else
					_rooms[x][y] = new EmptyRoom(this, rand() % 3, rand() % 3, rand() % 3);
			}
		}

    //RIDDLE ROOM_Hbool RiddleRoom::OnRoomEnter(int dir)
	{
		if (!_drawable)
			DrawDrawable(DARKGREEN, WHITE);
		_drawable->SetDraw(true);
#ifndef SKIPANIMATION
		HandleAnimation(dir);
#endif
		_iRiddle = rand() % Assets::GetNumRiddles();		//generate random riddle on each entry
		_currentGS->ClearTextBox();
		_currentGS->WriteToTextBox("_15_A Riddler appears to be holding something that you want...-nHe offers a riddle.");
		_currentGS->WriteToTextBox("_3_%s", Assets::s_riddles[_iRiddle].riddle);
		return true;
	}

	void RiddleRoom::ProcessInput(const myString::String& input)
	{
		int item = rand() % Assets::GetNumItems();
		if (input.Find(Assets::s_riddles[_iRiddle].answer) >= 0){
			_currentGS->WriteToTextBox("_15_A look of horror comes across the Riddler's face, you've beaten him!");
			_currentGS->WriteToTextBox("_15_The riddler reluctantly hands over his precious _14_%s_15_ to you!", Assets::s_items[item].name);
			_currentGS->InsertPlayerItem(Assets::s_items[item]);
			_passed = true;
		}
		else
			_currentGS->WriteToTextBox("_15_The Riddler laughs are how foolish you appear to be!");
	}

  //MONSTER ROOM_H
  void MonsterRoom::HandleAttack()
{
  if (_monster.GetHP() > 0){
    _currentGS->WriteToTextBox("_15_You attack the _12_%s_15_ with your whopping _12_%i_15_ attack power!",
      Assets::s_monsters[_monster.GetId()].name, _currentGS->GetPlayerAttack());

    if (!_currentGS->PlayerAttack(&_monster)){		//if monster isnt dead, it will attack back
      _currentGS->WriteToTextBox("_15_It looks like you've made a poor decision...");
      _currentGS->WriteToTextBox("_15_The _12_%s_15_ fights back, dealing a costly_12_ %i_15_ damage!",
        Assets::s_monsters[_monster.GetId()].name, _monster.GetAttack());
      _currentGS->HurtPlayer(_monster.GetAttack());	//attack player with monster
      if (_currentGS->GetPlayerHP() <= 0){			//if player died
        _currentGS->WriteToTextBox("You have died. Press any key to continue");
        StateManager::Get()->WantPop();				//quit time
      }
    }
    else{	//monster died
      int item = rand() % Assets::GetNumItems();				//generate random drop item
      _currentGS->InsertPlayerItem(Assets::s_items[item]);	//insert item to our inventory
      _currentGS->WriteToTextBox("_15_The _12_%s_15_ dies, and drops an awesome _14_%s",
        Assets::s_monsters[_monster.GetId()].name,
        Assets::s_items[item].name);
      _drawable->SetDraw(false);								//stop drawing the now dead monster
    }
    _currentGS->WriteToTextBox("_15_You have %iHP left.", _currentGS->GetPlayerHP());
  }
  else		//trying to attack dead monster
    _currentGS->WriteToTextBox("There is nothing else to attack");
}

}