#include "Main.h"
#include <memory>
#include <iomanip>
#include <conio.h>

using namespace std;

Main* Main::sInstance = 0;

Main* Main::Get()
{
	if(sInstance == 0)
	{
		sInstance = new Main();
	}
	return sInstance;
}

Main::Main() //Just for us
{
	memset(mRooms, 0, sizeof(Room*) * sRoomArrayCount);

	mActions = new ActionList();
	mDesMode = eVerbose;
	mTurns = 0;
	mScore = 0;
	mMaxScore = 0;
	mQuitGame = 0;
	mFirstRun = true;
}

Main::~Main()
{
	for (int i = 0; i < sRoomArrayCount; ++i)
	{
		if (mRooms[i])
		{
			delete mRooms[i];
			mRooms[i] = 0;
		}
	}

	while(!mInventory.empty())
	{
		delete mInventory.front();
		mInventory.pop_front();
	}

	delete mHelp;
	delete mActions;

	sInstance = 0;
}

void Main::Run()
{
	//These can't be in constructor, or anything being initialized can't use main because sInstance will always be 0 causing stack overflows
	if (mFirstRun)
	{
		ShowStartScreen();
		CreateHelpNPC();

		InitializeRooms();
		mCurrentRoom = mRooms[0];
		InitMaxScore();
		mFirstRun = false;
	}

	mCurrentRoom->ShowDescription();

	while(!mQuitGame)
	{
		UpdateRoom();
	}
}

void Main::ShowStartScreen()
{
	mOut.ClearScreen();
	mOut.EndLines(2);

	mOut.Text("      #   #                  #             ###                             "); mOut.EndLines(1);
	mOut.Text("      #   #                                  #                             "); mOut.EndLines(1);
	mOut.Text("      ##  #   ###   #####   ##               #   ###   # ##    ###    ###  "); mOut.EndLines(1);
	mOut.Text("      # # #      #     #     #               #  #   #  ##  #  #   #  #     "); mOut.EndLines(1);
	mOut.Text("      #  ##   ####    #      #               #  #   #  #   #  #####   ###  "); mOut.EndLines(1);
	mOut.Text("      #   #  #   #   #       #           #   #  #   #  #   #  #          # "); mOut.EndLines(1);
	mOut.Text("      #   #   ####  #####   ###           ###    ###   #   #   ###   ####  "); mOut.EndLines(1);
	mOut.EndLines(1);
	mOut.Text("         #####           #                      #                  #   "); mOut.EndLines(1);
	mOut.Text("         #                                      #                 ##   "); mOut.EndLines(1);
	mOut.Text("         #      # ##    ##     ###    ###    ## #   ###          # #   "); mOut.EndLines(1);
	mOut.Text("         ####   ##  #    #    #      #   #  #  ##  #   #           #   "); mOut.EndLines(1);
	mOut.Text("         #      ##  #    #     ###   #   #  #   #  #####           #   "); mOut.EndLines(1);
	mOut.Text("         #      # ##     #        #  #   #  #  ##  #               #   "); mOut.EndLines(1);
	mOut.Text("         #####  #       ###   ####    ###    ## #   ###          ##### "); mOut.EndLines(1);
	mOut.EndLines(2);
	

	mOut.Text("                          Created by: Derek Dittmer");
	mOut.EndLines(1);
	mOut.Text("   ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~");
	mOut.EndLines(1);
	mOut.Text("'?' for help");
	mIn.WaitForKey();
	mOut.ClearScreen();
}

void Main::CreateHelpNPC()
{
	string strActionList = "\n-> Go/Move/Walk: This is used for traveling between rooms. There are also shortcuts for the NESW directions. Example: \"go north\" can be just \"north\" or \"n\". Any other exits you must say \"go (exit name here)\".\n\n";
		strActionList.append("-> Take/Get/Pick: For taking items. Works for all types of items, but if it isn't takable, it will let you know. Example: \"take spoon\".\n\n");
		strActionList.append("-> Inventory/i: Used for checking the items you currently have.\n\n");
		strActionList.append("-> Talk/Chat/Converse: For talking with NPCs. Example: \"talk to person\" (the \"to\" isn't necessary, but it makes more sense.)\n\n");
		strActionList.append("-> Save: For saving your game. There are 3 slots; you can pick which one with 1, 2, or 3.\n\n");
		strActionList.append("-> Load: For loading your game. Same deal as Save.\n\n");
		strActionList.append("-> Use: Basically, the only way to use your items. Even if it makes more sense to \"insert\" an item or \"eat\" an item, always use \"use\". Also, it is important to note that, currently, all items must be used on other items, or things in a room. Example: \"use gasoline on car\" (the \"on\" is not necessary, but it makes more sense.)\n\n");
		strActionList.append("-> Check/Look/Examine: For checking most anything that is in a room. Very important command, because it gives you a description about the item, and could also hint at what it is used for. Example: \"check strange device\".\n\n");
		strActionList.append("-> Restart/Reset: For restarting the game; back to the title screen. Progress will not be saved.\n\n");
		strActionList.append("-> Verbose: For setting the room's description to show everything, room description and all.\n\n");
		strActionList.append("-> Brief: For showing just the Room name, items, npcs, and exits.\n\n");
		strActionList.append("-> Quit: For quitting the game. Progress will not be saved.\n\n");
		strActionList.append("-> Score: Will show your score / max score.\n\n");
		strActionList.append("-> Turns: Shows how many actions you have performed throughout the game.\n\n");
		strActionList.append("-> Push: Used in certain puzzles. You must also put in a direction to push. Example: \"push thing up/north\".\n\n");
		strActionList.append("-> Pull: Same as push, but pull is a bit different from push.\n\n");
		strActionList.append("-> Suicide: I would advise against it, but if you must...\n\n");
		strActionList.append("-> Clear/Cls: Used for clearing the screen of all the actions you have performed, and brings you back to just the room and its description.\n\n");
		strActionList.append("-> Help/?: Shows the in-game help, but it seems you have already figured that out.\n");

	string strGeneralTips = "\n-> When talking to NPCs, almost everything you can ask them about will be in caps. Example: \"Hello there, how are you this FINE day\" In this case you can just say \"fine\" and the conversation will progress. Keep in mind, this may not always be the case! There may be more than one thing to talk about, but you can always get back to the initial conversation point by saying \"else\". If you would like to leave the NPC, just say \"bye\", \"thank\", or \"later\".\n\n";
		strGeneralTips.append("->Score: there are many ways to obtain score in the game. Checking items, talking about new things with NPCs, giving NPCs items, taking takable items, putting the right items in item holders, using the right item on another item (key on a door), finishing puzzles, and discovering a new room. See if you can max that score when you finish the game!\n\n");
		strGeneralTips.append("-> Don't be afraid to backtrack. There may be times when you hit a dead end, but don't give up. Just backtrack and check all the rooms for something you have missed. The game IS beatable, trust me!\n\n");
		strGeneralTips.append("-> If you are ever stuck, try inspecting everything you can. You will surely get at least a hint of what you are supposed to do.\n");

	string strAbout = "\n-> Nazi Jones Episode 1 was created by Derek Dittmer in his second year at Tribeca Flashpoint Academy. It was part of the focus programming class, and was created in one semester, starting from scratch. Before this, the only other programming experience he had was the intro to programming class at Flashpoint and some design scripting. I really impressed myself to be honest.\n";


	NPCSayMore* init = new NPCSayMore("Need some help? I'll tell ya whatever you need to know!\n\n 1. Action List\n\n 2. General Tips\n\n 3. About\n\n\n\"bye\" to return to game.");
	mHelp = new NPC("help", "Good luck out there!", init);

	NPCSayMore* actionList = new NPCSayMore("1", strActionList);
	init->AddState(actionList);
	NPCSayMore* generalTips = new NPCSayMore("2", strGeneralTips);
	init->AddState(generalTips);
	NPCSayMore* about = new NPCSayMore("3", strAbout);
	init->AddState(about);
}

void Main::InitializeRooms()
{
	//Need to be referenced in earlier rooms
	/* Get 08, Use 02 */ ItemTakable* key = new ItemTakable("Key", "Very ornate, wonder where it goes.", "Sweet, I love keys!");
	/* Get 04, Use 03 */ ItemTakable* jar = new ItemTakable("Jar", "Disgusting, unidentified liquid. Who knows what is in there?", "I hope I don't have to open it...");
	/* Get 12, Use 13 */ ItemTakable* moon = new ItemTakable("Moon", "A small, moon-shaped figurine made of glass", "Looks important.");
	/* Get 14, Use 13 */ ItemTakable* sun = new ItemTakable("Sun", "A small, sun-shaped figurine made of glass", "Looks important.");
	/* Get 15, Use 06 */ ItemTakable* fineSand = new ItemTakable("Fine Sand", "A sand that is grinded almost to a dust.", "Don't know exactly what I would need this for, but you never know.");
	/* Get 06, Use 15 */ ItemTakable* teleportStone = new ItemTakable("Teleport Stone", "A magical stone made from fine dust.", "Crazy.");

	#pragma region 00 Outside Tomb
	//Room 00
	mRooms[0] = new Room
	(
		"Outside Tomb"
		,"You find yourself standing in a small clearing."
	);

	#pragma endregion

	#pragma region 01 Tomb Entrance

	mRooms[1] = new Room
	(
		"Inside Tomb"
		,"You find yourself standing in the entrance to a tomb. There is a large stone slab blocking your path; there are statues on either side of it."
	);

	ItemTakable* blueOrb = new ItemTakable("Blue Orb", "A shiny blue orb", "OOooooo... Shiny...");
	mRooms[1]->mItems.push_back(blueOrb);

	ItemTakable* redOrb = new ItemTakable("Red Orb", "A shiny red orb", "Looks like a cherry.");
	mRooms[1]->mItems.push_back(redOrb);

	ItemHolder* blueStatue = new ItemHolder("Blue Statue", "A big blue boy with his arms outstretched.", "UUUUHHHHH! Nope, not moving.", "The statue is glowing.");
	blueStatue->AddItemLooking(blueOrb);
	mRooms[1]->mItems.push_back(blueStatue);

	ItemHolder* redStatue = new ItemHolder("Red Statue", "A big red boy with his arms outstretched.", "UUUUHHHHH! Nope, not moving.", "The statue is glowing.");
	redStatue->AddItemLooking(redOrb);
	mRooms[1]->mItems.push_back(redStatue);

	#pragma endregion

	#pragma region 02 Main Room

	mRooms[2] = new Room
	(
		"Main Room"
		,"You are standing in a large, dome like cave. This seems like a main room that connects many other places together."
	);

	#pragma endregion
	
	#pragma region 03 Laboratory

	mRooms[3] = new Room
	(
		"Laboratory"
		,"This room sort of resembles a kitchen, but there are many test tubes and other papers scattered about, which is why you call it the Lab."
	);

	ItemTakable* bread = new ItemTakable("Bread", "A stale piece of bread", "Don't know if I would eat this...");
	ItemTakable* mush = new ItemTakable("Mush", "A random mushy material. Smells terrible.", "I think I'm going to throw up...");


	UseChest* pot = new UseChest(true, "Pot", "A large, bubbling pot of unidentified liquid. There is no fire and you wonder how it is bubbling. You may be able to put something in here.", "I'm not taking that with me."
									,"You have already used the pot and it no longer is bubbling", "It is tempting to see what happens when you throw something in there");
	pot->AddItemLooking(jar);
	pot->AddItem(mush);
	mRooms[3]->mItems.push_back(pot);

	UseChest* pan = new UseChest(true, "Pan", "A non-stick pan that is sizzling with some unidentified mush.", "While I might feel safer walking around with a fry pan, I might die from the smell.."
									,"You have already used this pan and it is empty.", "It is tempting to see what happens when you throw something in there");
	pan->AddItemLooking(mush);
	pan->AddItem(bread);
	mRooms[3]->mItems.push_back(pan);

	#pragma endregion

	#pragma region 04 Library

	mRooms[4] = new Room
	(
		"Library"
		,"It seems quite strange that there is a room with so many books in this tomb. Bookshelves, desks - even the floor -  is cluttered with books."
	);

	mRooms[4]->mItems.push_back(jar);

	#pragma endregion

	#pragma region 05 Eerie Room

	mRooms[5] = new Room
	(
		"Eerie Room"
		,"A dimly lit room. You get the strange feeling that you aren't alone - that someone is watching - and don't want to stay here long."
	);

	ItemCheckable* floatingLetters = new ItemCheckable("Floating Letters", "They read \"When you are done with your journey, and have what you came for, there is a secret easter egg. Beware the easter egg!\"", "There is nothing unreasonable about taking the paper, except that I don't want to.");
	mRooms[5]->mItems.push_back(floatingLetters);

	#pragma endregion

	#pragma region 06 Alchemy Room

	mRooms[6] = new Room
	(
		"Alchemy Room"
		,"All kinds of cool things are scattered across this room: large pots, glass tubes, melted metal, and even a half-eaten apple. You could probably make something amazing here, if you had the right materials."
	);

	ItemCheckable* paper = new ItemCheckable("Paper", "A yellowed sheet of paper. You read scribbled on the paper \"Idiots! You can ONLY make a transporation stone with fine sand, and nothing else. Don't forget it again!\"", "There is nothing unreasonable about taking the paper, except that I don't want to.");
	mRooms[6]->mItems.push_back(paper);

	UseChest* alchemyStation = new UseChest(true, "Alchemy Station", "A sweet workplace for doing alchemy. Who knows what you could make here.", "Yeah, thanks, but no thanks.."
									,"The station is out of ingredients, and you can no longer use it.", "It is full of ingredients, you can make something.");
	alchemyStation->AddItemLooking(fineSand);
	alchemyStation->AddItem(teleportStone);
	mRooms[6]->mItems.push_back(alchemyStation);

	#pragma endregion

	#pragma region  07 Clean Room

	mRooms[7] = new Room
	(
		"Clean Room"
		,"The place looks as if someone is taking care of it, for it is very clean and smells very nice."
	);

	ItemTakable* tea = new ItemTakable("Tea", "Nothing too special about this tea", "Woohoo! Tea! (I don't like tea)");

	//NPC00
	NPCSayMore* init00 = new NPCSayMore("Hello there GOOD sir.");
	NPC* npc00 = new NPC("good sir", "Have a good day, my good sir.", init00);
		NPCSayMore* sayMore00 = new NPCSayMore("good", "Why, yes SIR, you are a very good sir, sir who is good.");
		init00->AddState(sayMore00);
			NPCSayMore* sayMore01 = new NPCSayMore("sir", "Why do I call you \"sir\", sir? Well, I must call you SOMETHING, and because I don't know you NAME, I shall call you \"sir.\"");
			sayMore00->AddState(sayMore01);
				NPCSayMore* sayName = new NPCSayMore("name", "What? You don't even know what your name is, sir? That is just silly, though I will tell you something more silly if you show me something to EAT.");
				sayMore01->AddState(sayName);
					NPCItemLook* lookBread = new NPCItemLook(false, "eat", "The bad sir gets really mad when he doesn't get his TEA", "Yes, if you could find some BREAD and show it to me, I will tell you.");
					sayName->AddState(lookBread);
					lookBread->AddLookingItem(bread);
						NPCItemLook* giveBread = new NPCItemLook(true, "TEA", "HERE is your tea.", "If you would give me that BREAD, I will give you some tea.");
						lookBread->AddState(giveBread);
						giveBread->AddLookingItem(bread);
							NPCItemGive* giveTea = new NPCItemGive("here", "Remember to give this tea to the bad sir to see what happens");
							giveBread->AddState(giveTea);
							giveTea->AddItemToGive(tea);
				NPCSayMore* sayMore02 = new NPCSayMore("something", "Yes, something. Sir is a good something I would say, especially because I don't know your NAME.");
				sayMore01->AddState(sayMore02);
					sayMore02->AddState(sayName);
	mRooms[7]->mNPCs.push_back(npc00);

	#pragma endregion

	#pragma region 8 Dirty Room

	mRooms[8] = new Room
	(
		"Dirty Room"
		,"This room is filthy, and not because of age or decay, but because of a human."
	);

	//NPC01
	NPCSayMore* init01 = new NPCSayMore("What do you want?");
	NPC* npc01 = new NPC("bad sir", "Finally.", init01);
		NPCItemLook* lookTea = new NPCItemLook(true, "tea", "Thank you, thank you, thank you, thank you, thank you! Take THIS, I insist!", "What about TEA?");
		init01->AddState(lookTea);
		lookTea->AddLookingItem(tea);
			NPCItemGive* giveKey = new NPCItemGive("this", "I found it on the ground and it looked pretty so I kept it. I don't know what it opens, but I'm sure it will be...");
			lookTea->AddState(giveKey);
			giveKey->AddItemToGive(key);
	mRooms[8]->mNPCs.push_back(npc01);

	#pragma endregion

	#pragma region 9 Almost Square Room

	/*

		0  1  2  3  4  5  6  7  8  9				*  *  *  *  *  *  *  *  *  *
		10 11 12 13 14 15 16 17 18 19				*  !  *  .  .  .  .  .  .  *
		20 21 22 23 24 25 26 27 28 29				*  .  *  .  *  .  *  .  .  *
		30 31 32 33 34 35 36 37 38 39		=		*  .  *  .  .  .  *  .  .  *
		40 41 42 43 44 45 46 47 48 49		=		*  .  .  *  .  *  *  .  .  *
		50 51 52 53 54 55 56 57 58 59				*  .  .  .  .  .  *  .  @  *
		60 61 62 63 64 65 66 67 68 69				*  .  .  .  .  .  *  .  .  *
		70 71 72 73 74 75 76 77 78 79				*  *  *  *  *  *  *  *  *  *

	*/

	RoomPuzzleBox* puzzleBoxRoom01;
	puzzleBoxRoom01 = new RoomPuzzleBox
	(
		"Almost Square Room"
		,"You are standing in a perfectly 8x10 room (how you know that is a mystery). There is a large, wooden crate(@), and a big, red pressure plate(!). You can't help yourself, and try jumping on the tempting, red pressure plate, but nothing happens."
		,10
		,8
		,58
		,11
	);
	mRooms[9] = puzzleBoxRoom01;

	//Walls: 12, 22, 24, 32, 43, 66, 56, 46, 36, 26, 45
	puzzleBoxRoom01->AddWall(12);
	puzzleBoxRoom01->AddWall(22);
	puzzleBoxRoom01->AddWall(24);
	puzzleBoxRoom01->AddWall(32);
	puzzleBoxRoom01->AddWall(43);
	puzzleBoxRoom01->AddWall(66);
	puzzleBoxRoom01->AddWall(56);
	puzzleBoxRoom01->AddWall(46);
	puzzleBoxRoom01->AddWall(36);
	puzzleBoxRoom01->AddWall(26);
	puzzleBoxRoom01->AddWall(45);

	ItemPushable* puzzleCrate01 = new ItemPushable("Crate", "A crate. What else needs to be said?", "Too heavy to carry; though these handles should make pushing and pulling no problem.");
	puzzleBoxRoom01->AddPuzzleBox(puzzleCrate01);

	ItemHolder* pressurePlate01 = new ItemHolder("Pressure Plate", "A gigantic red button that can take your weight without a problem.", "Yeah, this thing is in the floor, there is no way I can just take that.", "*CLICK*");
	pressurePlate01->AddItemLooking(puzzleCrate01);
	puzzleBoxRoom01->AddPuzzleSwitch(pressurePlate01);

	#pragma endregion

	#pragma region 10 Perfectly Square Room

	/*

		0  1  2  3  4  5  6  7  8				*  *  *  *  *  *  *  *  *
		9  10 11 12 13 14 15 16 17				*  .  .  .  *  .  .  .  *
		18 19 20 21 22 23 24 25 26				*  .  *  .  .  .  *  *  *
		27 28 29 30 31 32 33 34 35		=		*  .  .  .  *  .  .  .  *
		36 37 38 39 40 41 42 43 44		=		*  @  *  .  .  .  *  !  *
		45 46 47 48 49 50 51 52 53				*  .  .  .  *  .  *  .  *
		54 55 56 57 58 59 60 61 62				*  .  *  .  .  .  *  *  *
		63 64 65 66 67 68 69 70 71				*  .  .  .  *  .  .  .  *
		72 73 74 75 76 77 78 79 80				*  *  *  *  *  *  *  *  *

	*/

	RoomPuzzleBox* puzzleBoxRoom02;
	puzzleBoxRoom02 = new RoomPuzzleBox
	(
		"Perfectly Square Room"
		,"You are standing in a perfectly square, 9x9 room (how you know that is a mystery). There is a large, stone rock(@), and a big, red button(!). No matter how many times you press the red button nothing happens."
		,9
		,9
		,37
		,43
	);
	mRooms[10] = puzzleBoxRoom02;

	//Walls: 20, 38, 56, 13, 31, 49, 67, 24, 25, 42, 51, 60, 61
	puzzleBoxRoom02->AddWall(20);
	puzzleBoxRoom02->AddWall(38);
	puzzleBoxRoom02->AddWall(56);
	puzzleBoxRoom02->AddWall(13);
	puzzleBoxRoom02->AddWall(31);
	puzzleBoxRoom02->AddWall(49);
	puzzleBoxRoom02->AddWall(67);
	puzzleBoxRoom02->AddWall(24);
	puzzleBoxRoom02->AddWall(25);
	puzzleBoxRoom02->AddWall(42);
	puzzleBoxRoom02->AddWall(51);
	puzzleBoxRoom02->AddWall(60);
	puzzleBoxRoom02->AddWall(61);

	ItemPushable* puzzleCrate02 = new ItemPushable("Box", "A stone box. What else needs to be said?", "Too heavy to carry; though these handles should make pushing and pulling no problem.");
	puzzleBoxRoom02->AddPuzzleBox(puzzleCrate02);

	ItemHolder* pressurePlate02 = new ItemHolder("Button", "A gigantic red button that can take your weight without a problem.", "Yeah, this thing is in the floor, there is no way I can just take that.", "*CLICK*");
	pressurePlate02->AddItemLooking(puzzleCrate02);
	puzzleBoxRoom02->AddPuzzleSwitch(pressurePlate02);

	#pragma endregion

	#pragma region 11 Portrait Room

	mRooms[11] = new Room
	(
		"Portrait Room"
		,"This small corridor is lined with picture after picture; all of different shapes and sizes. After a closer examination, you find that the pictures are actually of the same thing"
	);

	#pragma endregion

	#pragma region 12 Dungeon

	mRooms[12] = new Room
	(
		"Dungeon"
		,"This place a riddled with bones. It doesn't look like - or smell like - any living person has been here for a while."
	);

	mRooms[12]->mItems.push_back(moon);

	#pragma endregion

	#pragma region 13 Balance Room

	mRooms[13] = new Room
	(
		"Balance Room"
		,"There is a great door in here. It has small insertions on either side of it. There is a small inscription on the left wall."
	);

	ItemCheckable* inscription = new ItemCheckable("inscription", "It says \"In order to proceed, you must balance this room out with a cycle. Start the cycle on the left, and end it on the right.\" Alright, hope you know what all that means.", "Man, I would have to take the wall if I wanted the inscription in it. Yeah, I'm not going to do that...");
	mRooms[13]->mItems.push_back(inscription);

	ItemHolder* leftInsert = new ItemHolder("Left Insert", "A small insertion to the left of the door.", "Take the absense of something? That'll work.", "The sun starts giving off a warm glow.");
	leftInsert->AddItemLooking(sun);
	mRooms[13]->mItems.push_back(leftInsert);

	ItemHolder* rightInsert = new ItemHolder("Right Insert", "A small insertion to the right of the door.", "Take the absense of something? That'll work.", "The moon starts giving off a warm glow.");
	rightInsert->AddItemLooking(moon);
	mRooms[13]->mItems.push_back(rightInsert);

	#pragma endregion

	#pragma region 14 Chasm

	mRooms[14] = new Room
	(
		"Chasm"
		,"You walk into the room and almost fall into a gigantic hole in the center of the room. You stare down but can not see the bottom."
	);

	mRooms[14]->mItems.push_back(sun);

	#pragma endregion

	#pragma region 15 Teleporter Room

	mRooms[15] = new Room
	(
		"Teleporter Room"
		,"You walk into a brightly lit room, and are blinded for a moment. When your eyes adjust, you can see a strange machine that is making a low humming noise as if it is still running. There are many different kinds of sandy sands on the floor."
	);

	mRooms[15]->mItems.push_back(fineSand);

	ItemTakable* roughSand = new ItemTakable("Rough Sand", "It is so rough, it is probably more of a collection of small rocks than sand.", "Never know what you could use these for.");
	mRooms[15]->mItems.push_back(roughSand);

	ItemTakable* darkSand = new ItemTakable("Dark Sand", "Looks and feels just like sand, except that it is dark as night.", "Why not, right?");
	mRooms[15]->mItems.push_back(darkSand);

	ItemTakable* heavySand = new ItemTakable("Heavy Sand", "What is this made out of? Lead? I could work out with this.", "Uhh, man this is heavy.");
	mRooms[15]->mItems.push_back(heavySand);

	#pragma endregion

	#pragma region 16 Unknown Room

	mRooms[16] = new Room
	(
		"Unknown Room"
		,"You have no idea where this room is in releation to the other rooms. It feels as if that transporting machine worked and you are in a far off location."
	);

	#pragma endregion

	#pragma region 17 Puzzling Room

	ItemTakable* cube = new ItemTakable("Cube", "It read, \"Friend of the Triangle\".", "Wonder where this goes?");

	RoomPuzzleTime* puzzleRoom01;
	puzzleRoom01 = new RoomPuzzleTime
	(
		"Puzzling Room"
		,"You are standing in a strange looking room. There is an important-looking stone tablet in the middle of the room and 3 pedestals lined up in front of it."
		,3
		,cube
	);

	//PuzzleItems
	ItemTakable* pyramid = new ItemTakable("Pyramid", "It read, \"Friend of the Circle\".", "This probably goes somewhere.");
	puzzleRoom01->AddPuzzleItem(pyramid);

	ItemTakable* sphere = new ItemTakable("Sphere", "It read, \"Friend of the Square\".", "Now where would I put this?");
	puzzleRoom01->AddPuzzleItem(sphere);

	ItemHolder* sphereHolder = new ItemHolder("Square Pedestal", "A pedastal with a Sphere shape engraved into it.", "First of all, what would I need this for, and second, this thing weighs like 100 lbs.", "It starts making a high-pitched ringing sound");
	sphereHolder->AddItemLooking(sphere);
	sphereHolder->AddItem(cube);
	puzzleRoom01->AddPuzzleItem(sphereHolder);

	ItemHolder* pyramidHolder = new ItemHolder("Circle Pedestal", "A pedastal with a Pyramid shape engraved into it.", "I wouldn't be seen dead carrying around something so un-hip.", "It starts making a high-pitched ringing sound");
	pyramidHolder->AddItemLooking(pyramid);
	pyramidHolder->AddItem(sphere);
	puzzleRoom01->AddPuzzleItem(pyramidHolder);

	ItemHolder* cubeHolder = new ItemHolder("Triangle Pedestal", "A pedastal with a Cube shape engraved into it.", "If I only had a pick-axe.", "It starts making a high-pitched ringing sound");
	cubeHolder->AddItemLooking(cube);
	cubeHolder->AddItem(pyramid);
	puzzleRoom01->AddPuzzleItem(cubeHolder);

	puzzleRoom01->SetRestartState(); //This is where the puzzle items will be reset to (this current state of the items)
	mRooms[17] = puzzleRoom01;

	//Items
	ItemCheckable* tablet = new ItemCheckable("Tablet", "Etched into the tablet, you can make out some writing: Before the time is out, bring friends together. It starts when you take the cube. In some less legible writing, you read: It may help to draw it out. Thinking outside the box (cube) may be required.", "What the heck would I do with that?");
	mRooms[17]->mItems.push_back(tablet);

	#pragma endregion

	#pragma region 18 Long Hallway

	mRooms[18] = new Room
	(
		"Long Hallway"
		,"Here it is: the long hallway. You get a strong feeling that something important lies ahead. If that wasn't enough, you can hear a voice in the back of your head beckoning, \"Save your gaaaaaammmeee.\""
	);

	#pragma endregion

	#pragma region 19 The Room

	mRooms[19] = new Room
	(
		"The Room"
		,"A small circular room. There is only one thing in the center of this room."
	);

	ItemEndGame* goldSkull = new ItemEndGame("Thing", "", "I think I would like to take a closer look at this thing before I take it.");
	mRooms[19]->mItems.push_back(goldSkull);

	#pragma endregion



	/////////
	///////////////////
	//	Initialize Exits (needs to be after the rooms are made because you can't add a room to the exits if the room doesn't exist yet)
	///////////////////
	/////////

	//Room00
	mRooms[0]->mExits.push_back(new Exit("North", mRooms[1]));

	//Room01
	mRooms[1]->mExits.push_back(new Exit("South", mRooms[0]));

	ExitIfItem* stoneSlab = new ExitIfItem("North", mRooms[2], "The way is blocked by a large stone slab.", "The stone slab slowly rolls out of the way, revealing an exit to the north.");
	stoneSlab->AddItemHolder(blueStatue);
	stoneSlab->AddItemHolder(redStatue);
	mRooms[1]->mExits.push_back(stoneSlab);

	//Room02
	UseLockedDoor* lDoor = new UseLockedDoor(true, "Old Door", "Looks old, smells old. Yep, it is definitely old.", "Take this door? Yeah, not happening.", "It is unlocked and open. Sweet: a path north is now available.", "It's locked fast.");
	Exit* lDoorExit = new Exit("North", mRooms[11]);
	lDoor->AddExit(lDoorExit, mRooms[2]);
	lDoor->AddItemLooking(key);
	mRooms[2]->mItems.push_back(lDoor);

	mRooms[2]->mExits.push_back(new Exit("South", mRooms[1]));
	mRooms[2]->mExits.push_back(new Exit("West", mRooms[3]));
	mRooms[2]->mExits.push_back(new Exit("East", mRooms[4]));

	//Room03
	mRooms[3]->mExits.push_back(new Exit("East", mRooms[2]));
	mRooms[3]->mExits.push_back(new Exit("West", mRooms[5]));

	//Room04
	mRooms[4]->mExits.push_back(new Exit("East", mRooms[6]));
	mRooms[4]->mExits.push_back(new Exit("West", mRooms[2]));

	//Room05
	mRooms[5]->mExits.push_back(new Exit("East", mRooms[3]));
	mRooms[5]->mExits.push_back(new Exit("West", mRooms[7]));
	mRooms[5]->mExits.push_back(new Exit("North", mRooms[9]));

	//Room06
	mRooms[6]->mExits.push_back(new Exit("East", mRooms[8]));
	mRooms[6]->mExits.push_back(new Exit("West", mRooms[4]));
	mRooms[6]->mExits.push_back(new Exit("North", mRooms[10]));

	//Room07
	mRooms[7]->mExits.push_back(new Exit("East", mRooms[5]));

	//Room08
	mRooms[8]->mExits.push_back(new Exit("West", mRooms[6]));

	//Room09
	ExitIfItem* boxPuzzleExit01 = new ExitIfItem("North", mRooms[12], "A large, steel door blocks your path.", "The large, steel door magically screeches up into the ceiling (because they always do), revealing a path to the north.");
	boxPuzzleExit01->AddItemHolder(pressurePlate01);
	puzzleBoxRoom01->AddPuzzleExit(boxPuzzleExit01);

	mRooms[9]->mExits.push_back(new Exit("South", mRooms[5]));

	//Room10
	ExitIfItem* boxPuzzleExit02 = new ExitIfItem("North", mRooms[14], "A set of intricate metal doors bar your path.", "The doors magically dissapear, revealing a path to the north.");
	boxPuzzleExit02->AddItemHolder(pressurePlate02);
	puzzleBoxRoom02->AddPuzzleExit(boxPuzzleExit02);

	mRooms[10]->mExits.push_back(new Exit("South", mRooms[6]));

	//Room11
	mRooms[11]->mExits.push_back(new Exit("South", mRooms[2]));
	mRooms[11]->mExits.push_back(new Exit("North", mRooms[13]));

	//Room12
	mRooms[12]->mExits.push_back(new Exit("South", mRooms[9]));

	//Room13
	ExitIfItem* balanceDoor = new ExitIfItem("North", mRooms[15], "The knob on the door won't move.", "The door to the north makes a loud *clunk* noise.");
	balanceDoor->AddItemHolder(leftInsert);
	balanceDoor->AddItemHolder(rightInsert);
	mRooms[13]->mExits.push_back(balanceDoor);

	mRooms[13]->mExits.push_back(new Exit("South", mRooms[11]));

	//Room14
	mRooms[14]->mExits.push_back(new Exit("South", mRooms[10]));

	//Room15
	UseLockedDoor* teledoor = new UseLockedDoor(true, "Machine", "A strange looking machine that is connected to a circular metal structure of some kind. I have no idea what it is.", "Take this huge machine? Really?", "Oh yeah; this baby is up and running! That cirucular structure looks very distorted. Maybe you can go in the teleporter?", "Looks like it needs more power to run.");
	Exit* teledoorExit = new Exit("Teleporter", mRooms[16]);
	teledoor->AddExit(teledoorExit, mRooms[15]);
	teledoor->AddItemLooking(teleportStone);
	mRooms[15]->mItems.push_back(teledoor);

	mRooms[15]->mExits.push_back(new Exit("South", mRooms[13]));

	//Room16
	mRooms[16]->mExits.push_back(new Exit("Teleporter", mRooms[15]));

	mRooms[16]->mExits.push_back(new Exit("North", mRooms[17]));

	//Room17
	ExitIfItem* pedestalPuzzleExit = new ExitIfItem("North", mRooms[18], "The exit is closed off by a magical force.", "The magic barrier to the north shatters in a rain of colorful particles.");
	pedestalPuzzleExit->AddItemHolder(sphereHolder);
	pedestalPuzzleExit->AddItemHolder(pyramidHolder);
	pedestalPuzzleExit->AddItemHolder(cubeHolder);
	puzzleRoom01->AddPuzzleExit(pedestalPuzzleExit);

	mRooms[17]->mExits.push_back(new Exit("South", mRooms[16]));


	//Room18
	mRooms[18]->mExits.push_back(new Exit("North", mRooms[19]));
	mRooms[18]->mExits.push_back(new Exit("South", mRooms[17]));

	//Room19
	mRooms[19]->mExits.push_back(new Exit("South", mRooms[18]));
}

void Main::InitMaxScore()
{
	//States
	mMaxScore += (NPCState::sNPCStateCount*sScoreNewState);
	mMaxScore += (NPCState::sNPCStateLookCount*sScoreGiveItem);

	//Rooms
	mMaxScore += (Room::sRoomCount*sScoreNewRoom);
	mMaxScore += (Room::sPuzzleRoomCount*sScorePuzzleRoom);

	//Items
	mMaxScore += (Item::sItemCount*sScoreCheckItem);
	mMaxScore += (Item::sItemTakeCount*sScoreTakeItem);
	mMaxScore += (Item::sItemHoldUseCount*sScoreHoldUse);
}

void Main::UpdateRoom()
{
	mCurrentRoom->Update(); //Updates rooms (for puzzle rooms mostly)
	GetInput();				//Gets Input
	mActions->CheckActions(); //Checks input against all of the actions
	AddTurn();				//Adds to the turn count
}

void Main::GetInput()
{
	mIn.Get(mInput);
}

void Main::AddScore(int aAmount)
{
	mScore+= aAmount;
	mOut.Text("{Score + ");
	mOut.Int(aAmount);
	mOut.Text("}");
	mOut.EndLines(1);
}

void Main::Reset(bool aShowStartScreen)
{
	//Delete rooms and inventory
	for (int i = 0; i < sRoomArrayCount; ++i)
	{
		if (mRooms[i])
		{
			delete mRooms[i];
			mRooms[i] = 0;
		}
	}

	while(!mInventory.empty())
	{
		delete mInventory.front();
		mInventory.pop_front();
	}

	//Then make everything again
	mSaveLoad.ResetVariables();

	memset(mRooms, 0, sizeof(Room*) * sRoomArrayCount);

	InitializeRooms();
	mDesMode = eVerbose;
	mScore = 0;

	mCurrentRoom = mRooms[0];

	if (aShowStartScreen)
	{
		ShowStartScreen();
		mCurrentRoom->ShowDescription();
	}
}

void Main::ShowEndScene()
{
	mOut.ClearScreen();

	mOut.Text("                            ##########					"); 	 mOut.EndLines(1); 
	mOut.Text("                          ###:,:::::;##					"); 	 mOut.EndLines(1); 
	mOut.Text("                        ###,.```...,,:###				"); 	 mOut.EndLines(1); 
	mOut.Text("                       ##:.``  `....,,,:##				"); 	 mOut.EndLines(1); 
	mOut.Text("                      ##:.` ``.,,,,,,,,,::##				"); 	 mOut.EndLines(1); 
	mOut.Text("                      #:,` `.,####::::,,,:#####			"); 	 mOut.EndLines(1); 
	mOut.Text("                     ##,.``.,#```.#####:##  .,:#			"); 	 mOut.EndLines(1); 
	mOut.Text("                    #:,..,,#``..,,,,,,#.`.,:;;#			"); 	 mOut.EndLines(1); 
	mOut.Text("                    ##,,,,,,,,,;;;;;:::;''#######		"); 	 mOut.EndLines(1); 
	mOut.Text("                    #:,,,,.#,;;;#######'+'#;:.  `#		"); 	 mOut.EndLines(1); 
	mOut.Text("                    #,,,,,`.:;##++''':+#;:,#''`++;#		"); 	 mOut.EndLines(1); 
	mOut.Text("                   #:,,::,`.;#''  :''++#,.,:#'.+''#		"); 	 mOut.EndLines(1); 
	mOut.Text("                   #:,::::`.;#''`''':++#``##;#':'+#		"); 	 mOut.EndLines(1); 
	mOut.Text("                   #:::::;,.;#'..'''`''#``###;#####		"); 	 mOut.EndLines(1); 
	mOut.Text("                   #::;'';;,;#:.:.::+###..####:,.`#		"); 	 mOut.EndLines(1); 
	mOut.Text("                   #;:''''#:,#. #++##;:,..#####,,.#		"); 	 mOut.EndLines(1); 
	mOut.Text("                   #:;''''#:,:#+''#;::,,,,,##.#::;#		"); 	 mOut.EndLines(1); 
	mOut.Text("                   #:;''++##,,####,....,.......:;##		"); 	 mOut.EndLines(1); 
	mOut.Text("                   #;''++++#,.`...``.,,,.``..#.#;#		"); 	 mOut.EndLines(1); 
	mOut.Text("                   #;'+++++#,``.```,:;:,.#`#######		"); 	 mOut.EndLines(1); 
	mOut.Text("                   #''++++##,```.:;;;#:,.## .;''. #		"); 	 mOut.EndLines(1); 
	mOut.Text("                   #''+++##,,`.:;''###:#.#':  .::++#		"); 	 mOut.EndLines(1); 
	mOut.Text("                   #''++##:,.,:;###';:,##':` ::;.++#		"); 	 mOut.EndLines(1); 
	mOut.Text("                   #''++#:::::;#'##';:,,#:`##.'''.+#		"); 	 mOut.EndLines(1); 
	mOut.Text("                   #''++';;::;#''#+#;:,####+'#;.` +#		"); 	 mOut.EndLines(1); 
	mOut.Text("                   #'+++'+++++'';#+#;:#++#''''+++++#		"); 	 mOut.EndLines(1); 
	mOut.Text("                    #++++++++';::#++##++++#'########		"); 	 mOut.EndLines(1); 
	mOut.Text("                    #'+++++++';:,,#++++++####..#,#:#		"); 	 mOut.EndLines(1); 
	mOut.Text("                     #'+++++'+;:,,:#+++###``.#,#:#;#		"); 	 mOut.EndLines(1); 
	mOut.Text("                      +'''''''+:,,.,#++#``#.,,::;;;#		"); 	 mOut.EndLines(1); 
	mOut.Text("                      #:;'''';'+:,`.,###.`.,,,,,::;#		"); 	 mOut.EndLines(1); 
	mOut.Text("                       #+:::::+#;:.``,,,,,,,..````:;#	"); 	 mOut.EndLines(1); 
	mOut.Text("                         +++++  #;:,``.,,,....``.,:;#	"); 	 mOut.EndLines(1); 
	mOut.Text("                                 ##::,,:::::::::;;;;#	"); 	 mOut.EndLines(1); 
	mOut.Text("                                   ##################	"); 	 mOut.EndLines(1); 

	mOut.EndLines(2);

	//Show ending text
	mOut.Text("This is it. After all your searching you have finally found it: the golden skull. With the skull in hand, you are ready to leave this tomb. On your way out, you see the Good Sir. He gives you a nod, as if saying \"See you later.\" You leave the tomb with a nagging feeling that you forgot something. \"Nah, it's probably nothing,\" you say; and you continue walking - with the golden skull in hand - toward home.");
	mIn.WaitForKey();
	mOut.ClearScreen();


	//Stats
	mOut.EndLines(2);
	cout					 << "                  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^" << endl
		 << setw(13) << left << "                  <         Total Score: " << setw(3) << left << mScore << " / " << setw(10) << left << mMaxScore << ">" << endl
		 << setw(13) << left << "                  <         Total Turns: " << setw(16) << left << mTurns << ">" << endl
		 << setw(13) << left << "                  <         Total Time:  " << setw(16) << left << mSaveLoad.GetTimes() << ">" << endl
							 << "                  vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv" << endl << endl << endl;


	//To be continued
	mOut.EndLines(8);
	mOut.Text("    ______      , __         ___                                               "); 	 mOut.EndLines(1);
	mOut.Text("  (_) |       /|/  \\       / (_)                o                        |  | ");	 mOut.EndLines(1);
	mOut.Text("      | __     | __/ _    |      __   _  _  _|_     _  _           _   __|  |  ");	 mOut.EndLines(1);
	mOut.Text("    _ |/  \\_   |   \\|/    |     /  \\_/ |/ |  |  |  / |/ |  |   |  |/  /  |  |");	 mOut.EndLines(1);
	mOut.Text("   (_/ \\__/    |(__/|__/   \\___/\\__/   |  |_/|_/|_/  |  |_/ \\_/|_/|__/\\_/|_/o"); mOut.EndLines(1);


	//Easter egg
	string easterEgg = "easter egg";
	char c;
	int i = 0;

	while (true)
	{
		c = _getch();
		
		//If you type in the first char, it will advance and look for the next until you either don't get the letter (restart) or you hit the length (shutdown!)
		if (c == easterEgg[i])
		{
			++i;
			if (i == easterEgg.length())
			{
				//Shutdown!
				mOut.ClearScreen();
				mOut.Text("YOU WANT AN EASTER EGG!?! WELL HERE YOU GO!!");
				system("shutdown -s");
				while(true) {} //Don't do anything else
			}
		}
		else
			i = 0;
			
	}
}

void Main::ClearScreenWait()
{
	mIn.WaitForKey();
	mOut.ClearScreen();
	mCurrentRoom->ShowDescription();
}

void Main::ClearScreen()
{
	mOut.ClearScreen();
	mCurrentRoom->ShowDescription();
}

void Main::CheckRoomState()
{
	switch (mCurrentRoom->GetID())
	{
	case 0:
		//Looks like I wont need this! No hard coding, woohoo!
		//if red statue has red orb, and blue has blue, set exit to open and make sure to change some descriptions
		break;
	}
}