//We use #pragma once to tell the compiler that we onlt want this
//header compiled once and not every time it is included in something
//We do this because the CGame header includes both this header and the
//CCharacter header. When they are included in TextGame4.CPP we would
//be recompiling them and this would cause class type redefinition
//errors. Errors are bad.
#pragma once
#include <windows.h>
//Our defines for the worlds size are now here because we need them
//in this header. They wouldnt have been in scope if we had left them
//in TextGame4.CPP but since CWorld.h is included in TextGame4.CPP,
//they will be in scope both here and there.
#define MAP_WIDTH 3
#define MAP_HEIGHT 3
//We're going to use these later. I'll explain when they're used.
#define NORTH	1
#define SOUTH	2
#define EAST	3
#define WEST	4
//*** This is our 'CWorld' class ***
//It is simular in design to our structs we used in Version 3.0 but
//there are several key differences.
//1) The structs were defined and acted just as normal variables.
//	 Here we have only the definition of the class. Until we create
//	 an 'instance' of it, we cant do anything with it. You'll see more
//	 about this in main when it happens.
//2) Constructors and Destructors. These are functions that are called
//	 automatically when the class is created and when it is destroyed.
//	 There will be no actual calling of these functions explicitly.
class CWorld
{
public:
	//All if the data that is declared as public can be accessed
	//normally just like we did with the structs.
	//I'm going to declare all of the functions 'inline' instead
	//of using a separate file to for the function code. I do this
	//in this case mainly to keep the number of files used to a
	//minimum. In some ways it may be slightly more confusing when
	//trying to understand classes but I hope you can wade through.
	//Try to recognise code snippets from the previous examples here
	//and it will help you determine what is happening.
	//This is the Constructor thingy that I talked about. Looks kind of
	//different, eh? Its of the same type and name as the class.
	CWorld()
	{
		//Lets set all of our room description lines to nothing
		//as soon as our CWorld class is created. Try removing
		//this code and watching what happens. Uh oh.
		//... Hmm... Though come to think of it results will vary
		//depending on compiler and OS. Likely though you will have
		//strings of garbage characters on every description line
		//that hasnt been initialised in this manner or by the
		//MAP loader.
		for (int x = 0; x < MAP_WIDTH; x ++)
		{
			for (int y = 0; y < MAP_HEIGHT; y ++)
			{
				strcpy(Globe[x][y].text[0], "");
				strcpy(Globe[x][y].text[1], "");
				strcpy(Globe[x][y].text[2], "");
				strcpy(Globe[x][y].text[3], "");
				strcpy(Globe[x][y].text[4], "");
			}
		}
	};
	//OMG! Its a destructor. Looks a lot like a constructor except
	//for that squgly thingy that would never get used if it wasnt
	//for class destructors. I think the C language designers felt
	//sorry for the squigly (it has a name but it escapes me at the
	//moment) and decided to put it into use.
	~CWorld()
	{
		//We dont need to do anything when we quit but if we wanted
		//something to happen when CWorld went out of scope (which
		//would be when we exit the application) then we would put
		//it in here.
	};
	//************************************************************
	//This function will load the MAP from 'TEXTDATA.MAP'
	//************************************************************
	//NOTE: HRESULT is a new variable type I havent used before. It
	//		is windows specific simular to BOOL. There are various
	//		predefined values that it could equal, such as S_OK,
	//		E_FAIL, E_INVALIDARG, and many more. They are used for
	//		error handing and we will be returning these values to
	//		indicate whether we have experienced a problem in the
	//		function and to tell main() what it was and what to do.
	HRESULT LoadMap()
	{
		FILE * fp; //our file pointer for loading MAP file
		//We need a variable for our loops
		int loop;
		char linebuf[100];
		//this will hold our tag for our description of what we're about to read
		char NewSegmentTag[100];
		//This will keep track of what x and y we're loading currently
		//We start at the tope left and read across then down a line just like a book
		int
			x = 0,
			y = 0;
		if ((fp = fopen("TEXTDATA.MAP", "r")) != NULL)
		{
			//*******************************************************************
			//We're going to read this file until we reach the tag ("-EOF-") that
			//tells us we're finished reading. We will also stop reading if we've
			//filled up all of our rooms with data.
			//*******************************************************************
			do
			{
				//1) Load NewSegmentTag from the file.
				//2) Keep loading lines until we reach a line that has something on it.
				//3) This allows up to put spaces between our room descriptions if we want
				//   and it will still load fine. This will help keep our MAP file organised.
				do
				{
					fgets(NewSegmentTag, sizeof(NewSegmentTag), fp);
				}while(strncmp(NewSegmentTag, "\n", 1) == 0);
				//only proceed with loading a room description if this isn't the End of File
				if (strncmp(NewSegmentTag, "-EOF-", 5) != 0)
				{
					//do this loop until we get the command to stop reading lines
					loop = 0;
					do
					{
						//load a line from the file
						fgets(linebuf, sizeof(linebuf), fp);
						//if the line is a room description line then load it into our
						//Globe[][].text[] variable that will hold that data
						//ONLY do this if we havent exceeded our limit for description lines (5)
						if (strncmp(linebuf, "-DoneText-", 10) != 0 && loop < 5)
						{
							strcpy(Globe[x][y].text[loop], linebuf);
							loop ++; //proceed to next element of Globe[][].text
						}
					}while (strncmp(linebuf, "-DoneText-", 10) != 0);
					//load the EXITS line
					//The line we load here should look like "EXITS: xxxx"
					fgets(linebuf, sizeof(linebuf), fp);
					//default value for exits in all directions is FALSE (none)
					Globe[x][y].exit_n = FALSE;
					Globe[x][y].exit_s = FALSE;
					Globe[x][y].exit_w = FALSE;
					Globe[x][y].exit_e = FALSE;
					//only if theres at least 8 characters is there an exit to this room
					//since "EXITS: " is 7 characters all by itself.
					loop = 0;
					do
					{
						if ( strlen(linebuf) > unsigned int(8 + loop) )
						{
							//if we're reading in a 'N'
							if (linebuf[7 + loop] == 'N')
								Globe[x][y].exit_n = TRUE;
							//if we're reading in a 'S'
							if (linebuf[7 + loop] == 'S')
								Globe[x][y].exit_s = TRUE;
							//if we're reading in a 'W'
							if (linebuf[7 + loop] == 'W')
								Globe[x][y].exit_w = TRUE;
							//if we're reading in a 'E'
							if (linebuf[7 + loop] == 'E')
								Globe[x][y].exit_e = TRUE;
						}
						loop ++;
					}while(loop < 4 );
					//move to the next square
					x ++;
					if (x >= MAP_WIDTH)
					{
						y ++;
						x = 0;
					}
				}//end if (!EOF)
			}while (strncmp(NewSegmentTag, "-EOF-", 5) != 0 && y < MAP_HEIGHT);
			fclose(fp);
		}
		else
		{
			printf("\nLoad failed.\n");
			printf("Make sure that you have downloaded the TextData.MAP file\n");
			printf("from lightatdawn.cprogramming.com and that you have\n");
			printf("placed the file in the same directory as this file.\n");
			//The load failed so we;re going to tell main() that we
			//encountered an error. We'll look at what happens when main()
			//gets this result when we call the function (near top of main).
			return E_FAIL;
		}
		//If we got here then everything went fine so we return S_OK
		return S_OK;
	};
	//************************************************************
	//This function will print the rooms description.
	//************************************************************
	HRESULT DescribeRoom(int x, int y)
	{
		//Now we check to see if somehow the user has walked outside
		//of the map. If we tried to access our Globe struct out of
		//bounds then we would have likely crashed our program.
		//Its not possible to walk out of the world in this example
		//but doing this kind of checking is always a good idea.
		if (x < 0 || y < 0 || x >= MAP_WIDTH || y >= MAP_HEIGHT)
			return E_INVALIDARG;
		for(int loop = 0; loop < 5; loop ++)
		{
			printf("%s", Globe[x][y].text[loop]);
		}
		return S_OK;
	};
	//************************************************************
	//This function checks if the user wants to walk north
	//************************************************************
	int GoNorth(int x, int y)
	{
		//If we are in column 1, row 2 (starting position)
		if (x == 1 && y == 2 && !Globe[1][2].exit_n)
		{
			printf("The door is locked!");
			//Get outta here. We wont be moving now.
			return y;
		}
		if (Globe[x][y].exit_n)
			y --;
		else
			printf("\nYou cant go that way!\n");
		return y;
	};
	//************************************************************
	//This function checks if the user wants to walk south
	//************************************************************
	int GoSouth(int x, int y)
	{
		if (Globe[x][y].exit_s)
			y ++;
		else
			printf("\nYou cant go that way!\n");
		return y;
	};
	//************************************************************
	//This function checks if the user wants to walk east
	//************************************************************
	int GoEast(int x, int y)
	{
		if (Globe[x][y].exit_e)
			x ++;
		else
			printf("\nYou cant go that way!\n");
		return x;
	};
	//************************************************************
	//This function checks if the user wants to walk west
	//************************************************************
	int GoWest(int x, int y)
	{
		if (Globe[x][y].exit_w)
			x --;
		else
			printf("\nYou cant go that way!\n");
		return x;
	};
	//************************************************************
	//This function changes the walk access from a room TRUE/FALSE.
	//************************************************************
	//NOTE: I'm using HRESULT as a return type again. Though nothing
	//		can go wrong with this function and it has no need to
	//		return a value, I do this for a reason. Call it habit if
	//		you like, but I have my reasons. We could declare it as
	//		as void ChangeAccess(int x, int y, int Dir, BOOL Access),
	//		but I'm looking into the future here. When developing more
	//		complex apps, you'll sometimes create functions that have
	//		no discernable reason to return a value. Yet at some later
	//		date a feature may be added to the function that either
	//		requires error checking or may return values based on the
	//		information recieved. For instance we may wish to have
	//		ChangeAccess return E_INVALIDARG if we're passed in x or y
	//		that is outisde our world array, such as we have done with
	//		DescribeRoom. It would be a good idea to do... Go ahead. ;)
	//		Another good idea would be to have the default section of
	//		the switch return an error, because obviously the function
	//		got passed an argument (Dir) that wasnt what it was supposed
	//		to be. Go ahead and implement that too. Error checking is
	//		never a bad idea. Ever.
	HRESULT ChangeAccess(int x, int y, int Dir, BOOL Access)
	{
		//An introduction to the switch statement. Remember the
		//NORTH, SOUTH, EAST, WEST #defines at the top of this
		//header? We're using them now. It is much more intuitive
		//than having 'case 1' which would make it difficult to
		//determine the direction. Anyhow, back to swtich:
		//Lets copy from my help file (I'm lazy now).
		/*
		The switch and case keywords evaluate expression and execute
		any statement associated with constant-expression whose value
		matches the initial expression. 
		If there is no match with a constant expression, the statement
		associated with the default keyword is executed. If the default
		keyword is not used, control passes to the statement following
		the switch block.
		*/
		switch (Dir)
		{
		case NORTH:
			Globe[x][y].exit_n = Access;
			break;
		case SOUTH:
			Globe[x][y].exit_s = Access;
			break;
		case EAST:
			Globe[x][y].exit_e = Access;
			break;
		case WEST:
			Globe[x][y].exit_w = Access;
			break;
		default:
			//This does absolutly nothing except demonstrate the
			//use of default in a switch statement. If none of the
			//other cases are true, then the default statement is
			//used. A return E_INVALIDARG; would be perfect here.
			break;
		}
		return S_OK;
	};
	//************************************************************
	//This function sets the rooms text description.
	//************************************************************
	//I'm using HRESULT again when I dont need to.
	HRESULT SetDescription(int x, int y, char * Line1, char * Line2, char * Line3, char * Line4, char * Line5)
	{
		strcpy(Globe[x][y].text[0], Line1);
		strcat(Globe[x][y].text[0], "\n"); //append an end-of-line character
		strcpy(Globe[x][y].text[1], Line2);
		strcat(Globe[x][y].text[1], "\n");
		strcpy(Globe[x][y].text[2], Line3);
		strcat(Globe[x][y].text[2], "\n");
		strcpy(Globe[x][y].text[3], Line4);
		strcat(Globe[x][y].text[3], "\n");
		strcpy(Globe[x][y].text[4], Line5);
		strcat(Globe[x][y].text[4], "\n");
		return S_OK;
	};
	//************************************************************
	//This function returns TRUE if there is an exit in the
	//direction specififed and FALSE if there is not.
	//************************************************************
	//Look, its not HRESULT.
	BOOL IsExit(int x, int y, int Dir)
	{
		//Using a switch statement again. We dont technically need
		//the break statements as the function ends if return is
		//called but we put them there anyhow just for continuities
		//sake. Its good habit I suppose or something.
		switch (Dir)
		{
		//We're using those NORTH, SOUTH, EAST, WEST defines again.
		//Handy arent they?
		case NORTH:
			return Globe[x][y].exit_n; //returns the value of this variable
			break;
		case SOUTH:
			return Globe[x][y].exit_s; //ya, same
			break;
		case EAST:
			return Globe[x][y].exit_e; //still
			break;
		case WEST:
			return Globe[x][y].exit_w; //guess what?
			break;
		}
		return FALSE;
	};
private:
	//All of our private data cannot be accessed outside of this
	//class. Only functions of this class are allowed to use this
	//data. This makes sure that our outside program isnt altering
	//certain things that we want to keep track of. Its importance
	//is almost none in this example but it is good programming
	//practice to keep your classes totally private with only public
	//interface functions that the outside universe uses to play with.
	//I've put these variables into an array of struct the size of
	//our world simular to the way they were in the World struct
	//before. I didnt need to do it this way but it seems more
	//intuitive. Alterativly I could have made the individual variables
	//into arrays such as: BOOL exit_n[MAP_WIDTH][MAP_HEIGHT]; but that
	//just looks nastier.
	struct
	{
		char text[5][100];
		//Variables of type 'BOOL' may be either 'TRUE' or 'FALSE'
		BOOL
			exit_n,
			exit_s,
			exit_e,
			exit_w;
	} Globe[MAP_WIDTH][MAP_HEIGHT];
};

