//
//
//
//////////////////////////////////////////////////////////////////////////////////////
// 
// 3600 grids, 60 ew, 60 ns = 3600 total.  Each assigned location
// so grid x1 y37, would be first x-block(50ns) 37 blocks to the east.
// y37 = 1850  starting variable
// x1  = 0     starting variable
//
//////////////////////////////////////////////////////////////////////////////////////
// Personal-note, when world-map editing, all grids have to be loaded, which means loading
// every single grid, this is so when the map-saves, it saves everything, not just a small chunk
// of the massive map, which would = bad if it were to happen that way.
// Editor on live-port will be disabled when we have builders and a dev-port for building
// the new/improved world on.  Though on the dev-port, we will probobly just keep the map always loaded
// so that we do not have to worry about constantly loading/closing, the worldmap.
//
//
// Additions: Adding GRID_DEBUGGING, to aid in logging of the grid system during testing phases.
//            Fixed localtime glitch
//            Added x/y stored ranges to the grid-data, for ease of grid locations.
//

// comment out if you don't want to debug
#define GRID_DEBUGGING 1

// step 0, assigning grid_list
Lexi::List<grid_data *>grid_list;

// global counter for memory checks
int grid_max;

//////////////////////////////////////////////////////////////////////////////////////
// the grid structure simply keeps track of a location array, when a segment of the
// map is loaded, it gets put into the grid, and then when moving/looking a local
// variable on the player points to the location of the x/y within the grid.
// 
// This method keeps memory to an extreme minimum.
// destroyed world/restore timers do not exist, plainly they will be set to a list
class grid_data {
	public:
		grid_data() { extern int grid_max; extern time_t current_time; last_used = &current_time; grid_max++;
			#ifdef GRID_DEBUGGING
			extern void log_string(const char *, ...);
			log_string("[WORLDMAP]: new grid_data created.  grid_max now: %d.", grid_max);
			#endif
		}
		~grid_data() { extern int grid_max;  grid_max--; 
			#ifdef GRID_DEBUGGING
			extern void log_string(const char *, ...);
			log_string("[WORLDMAP]: deleted grid_data.  grid_max now: %d.", grid_max);
			#endif
		}
	private:
		short location[50][50];			// a 50x50 array containing map information
		short grid_x;				// northsouth
		short grid_y;				// eastwest

		// Insanity check here
		short low_x_range;
		short high_x_range;
		short low_y_range;
		short high_y_range;


		// last used when?
		time_t last_used;			// last time the system used it.
							// we will compare, and close after
							// 1 hour of non-use.
							// non popular zones will close every hour
							// while popular ones will remain opened.
	public:
		short get_location(short x, short y) { return location[x][y];}			// gets the map-type
		void set_location(short x, short y, short type) { location[x][y] = type; }	// sets the map-type
		short get_x() { return grid_x; 	}						// gets the overall-x location
		short get_y() { return grid_y; }						// gets the overall-y location
		void set_x(int x) { grid_x = x; }						// sets the overall-x location
		void set_y(int y) { grid_y = y; }						// sets the overall-y location
		void set_x_range(int low, int high) { low_x_range = low; high_x_range = high; } // sets the low/high ranges for x
		void set_y_range(int low, int high) { low_y_range = low; high_y_range = high; } // sets the low/high ranges for y
		void get_x_range(int &low, int &high) { low = &low_x_range; high = &high_x_range; } // get the ranges
		void get_y_range(int &low, int &high) { low = &low_y_range; high = &high_y_range; } // get the ranges
		time_t &get_time() { return last_used; }					// returns last time the grid was accessed(roughly)
		void set_time() { extern time_t current_time; last_used = &current_time; }	// sets the time the grid was used.
};


//////////////////////////////////////////////////////////////////////////////////////
// lets see if our grid is loaded!
bool grid_loaded(short x, short y) {
	// grid matching and correction
	// this is done so that our variables of +1/-1 work correctly.
	if(x > MAX_GRID)	x = 0;
	if(y > MAX_GRID)	y = 0;

	if(x < 0)		x = MAX_GRID;
	if(y < 0)		y = MAX_GRID;

	FOREACH(Lexi::List<grid_data *>, grid_list, grid_iter) {
		grid_data *g = (*grid_iter);
		if(g->get_x() == x && g->get_y() == y)
			return true;
	}

	// no grid found, we aren't loaded, return false.
	return false;
}

//////////////////////////////////////////////////////////////////////////////////////
// remove a grid!
void close_grid(grid_data *g) {
	if(InList(grid_list, g))		// are we in the list
		grid_list.remove_one(g);	// remove us from it
	#ifdef GRID_DEBUGGING
	// why do we log it?  And why do we display memory free'd, well, this is 
	// allowing us to not only debug it, but keep track of the more frequented zones
	// for opening/closing, plus we want to keep track of the memory allocation, which is
	// why we made the grids, so its good to know.
	log_string("[WORLDMAP]: Grid X%d : Y%d has been closed.  Memory free'd (%s)", g->get_x(), g->get_y(), size_conversion(sizeof(g)))
	#endif
	delete g;				// delete the grid
	g = NULL;				// null the variable.
}

//////////////////////////////////////////////////////////////////////////////////////
// close the grid
void check_close(grid_data *g) {
	// hour not the same and the minute value matches.
	if(localtime(&g->get_time())->tm_hour != localtime(&current_time)->tm_hour
	&& localtime(&g->get_time())->tm_min > localtime(&g->get_time())->tm_min+1) {

		close_grid(g);	// kill our grid
		return;
	}

	// greater then 10 minutes, we close it out.
	if(localtime(&g->get_time())->tm_min+10 < localtime(&current_time)->tm_min) {
		close_grid(g);
		return;
	}

	return;
}

//////////////////////////////////////////////////////////////////////////////////////
// our updater, find the last time someone was within a grid.
// set it, and check to see if it is time to close an open grid.
// set this every 30 minutes or so.
Updater(grid_update) {
	if(grid_list.empty())
		return;
	#ifdef GRID_DEBUGGING
		log_string("[WORLDMAP]: Before: grid_update: grid_list contains %d grid(s).  Approx mem used %s!", grid_list.size, (sizeof(grid_data *) * grid_list.size) );
	#endif

	FOREACH(Lexi::List<grid_data *>, grid_list, g_iter) {
		grid_data *g = (*g_iter);
		FOREACH(Lexi::List<CHAR_DATA *>, wild_list, w_iter) {
			CHAR_DATA *c = (*w_iter);

			// we are in the grid!  Set our time!
			if(c->grid_x == g->get_x() && c->grid_y == g->get_y()) {
				g->set_time();
			}
		}
		// check to see if we have to close our grid
		check_close(g);	
	}

	#ifdef GRID_DEBUGGING
		log_string("[WORLDMAP]: After: grid_update: grid_list contains %d grid(s).  Approx mem used %s!", grid_list.size, (sizeof(grid_data *) * grid_list.size) );
	#endif
	return;
}

//////////////////////////////////////////////////////////////////////////////////////
// we grab our grid-data, this is helpful
grid_data *get_grid(short x, short y) {
	if(grid_list.empty()) return NULL;
	FOREACH(Lexi::List<grid_data *>, grid_list, g_iter) {
		grid_data *g = (*g_iter);
		if(g->get_x() == x && g->get_y() == y)
			return g;
	}
	return NULL;	
}

//////////////////////////////////////////////////////////////////////////////////////
// What grid are we within.  Greatly helpful, fast to process too.
// this will give us our grid-data, so we can pull any bits of information we need from
// that as required.
//
// This will most likely be-used in the draw_map code, as the worldmap can see into other
// ranges, and we will need the official grid-data's.
grid_data *within_range(short real_x, short real_y) {
	FOREACH(Lexi::List<grid_data *>, grid_list, g_iter) {
		grid_data *g = (*g_iter);
		int low_x, high_x;
		int low_y, high_y;

		// lets grab our ranges.  carefully!
		g->get_x_range(&low_x, &high_x);
		g->get_y_range(&low_y, &high_y);

		// lets find out if we are within the ranges.
		if(real_x >= low_x && real_x < high_x)		// we are within the x-range
			if(real_y >= low_y && real_y < high_y)	// we are within the y-range
				return g;

	}

	//////////////////////////////////////////////////////////
	// obviously, the grid wasn't found above, this is a problem
	// so to correct that, we know what grid we have to load
	// so we load it.  Plain, simple.
	int f_x = find_grid_x(real_x);
	int f_y = find_grid_y(real_y);
	grid_data * g = load_grid(f_x, f_y);

	// lets return g, even if g is null, we return here, hopefully save face.
	return g;
}

//////////////////////////////////////////////////////////////////////////////////////
// Find out what the 'IN_X'/'IN_Y' values should be.
// This function is used when players are 'sent' to the worldmap.
void set_in_grid(CHAR_DATA *ch) {
	grid_data *g = within_range(ch->coordinates[COORD_X], ch->coordinates[COORD_Y]);

	// assume not on the map.
	if(!g)
		return;
	int x_low, x_high;
	int y_low, y_high;

	// lets get our value's
	g->get_x_range(&x_low, &x_high);
	g->get_y_range(&y_low, &y_high);

	int special_x = x_low;
	int special_y = y_low;
	int real_x = 0;
	int real_y = 0;

	//////////////////////////////////////////////////////////////////////
	// Logic: 0-49 = possible locations, special_* is set to low-rating
	// we sift through, if the special_x match's the coord_x, then we've
	// found the right * location within the block.
	// here we go
	for(x = 0; x < 50; x++) {
		if(special_x == ch->coordinates[COORD_X]) {
			real_x = x;
			break;
		}
		special_x++;		
	}

	for(y = 0; y < 50; y++) {
		if(special_y == ch->coordinates[COORD_Y]) {
			real_y = x;
			break;
		}
		special_y++;		
	}

	// set the in_x/in_y variables
	ch->coordinates[IN_X] = real_x;
	ch->coordinates[IN_Y] = real_y;
	return;
}


//////////////////////////////////////////////////////////////////////////////////////
// LOCATING THE ACTUAL GRID: Since the world-map code is now broken into grids, but
// our pre-existing linkage to the map doesn't know the grids, we have to be-able to
// work with them, what means, we have to find the existing grids based on the x/y
// value's, here we accomplish that, and attain our grids location
//////////////////////////////////////////////////////////////////////////////////////


//////////////////////////////////////////////////////////////////////////////////////
// here we find out what the x-grid number will be
short find_grid_x(short real_x) {
	return real_x/50;	// short won't keep the remainder
}

//////////////////////////////////////////////////////////////////////////////////////
// here we find out what the y-grid number will be
short find_grid_y(short real_y) {
	return real_y/50;	// short won't keep the remainder
}

//////////////////////////////////////////////////////////////////////////////////////
// the math on this is easy, the grid is 50x50, the map is 3000x3000 (thats 3600 grids)
// we find our start location for x (up/down) and our y location (right/left).
// so, grid 2 37 would load at 100 1850 on the map.
// Based on the example above, ranges would be.
// 100->150 ud
// 1850->1900 lr
// however, we do not want to overlap our loaded tiles, so, to stop this from occuring
// we actualy only load to count -1., so 149, and 1899.  technically its still valid :)
//
// The loading proceedure is fast, and simple. while it keeps track of the x/y variables, it
// ultimatly creates a 'internal' set of x/y so that we do not break the overall location
// within the grid.  Crazy eh?
//
// If your math works properly with your grid alignment, you won't break any bounds
// within the reading of the x/y location.  if you think your not going to balance
// out properly, add gdImageSX or gdImageSY checks within the loops, to ensure that
// you do not exceed bounds, but we feel it isn't needed.
//
grid_data *load_grid(short x, short y) {
	int start_x = x * MAX_GRID_X;
	int start_y = y * MAX_GRID_Y;
	int end_x = start_x +50;			// easy math :P stops at 49 thanks to alligators ;)
	int end_y = start_y +50;			// easy math ;)
	FILE *jpgin = NULL;
	grid_data *g = NULL;

	// largest part on the memory is opening the file.
	// but even then, its not enough to hiccup on a modern computer.
        if((jpgin = fopen( WORLDMAP_FILE, "r" ) ) != NULL) {
		gdImagePtr im = gdImageCreateFromPng( jpgin );

		// our map-loading code goes here, with the ranges inputted.
		g = new grid_data();
		g->set_time();

		// what is the overall grid x/y location (10x,37y)...
		g->set_x(x);
		g->set_y(y);

		// what ranges is this grid responsible for!?
		g->set_x_range(start_x, end_x);
		g->set_y_range(start_y, end_y);

		// on-to map loading.
		int internal_y = 0;	// internal variable
		// we use set_location within the for-loop that will ensure here.
	        for( short yx = start_y; yx < end_x; ++yx )   {      
			int_internal_x = 0;
			for( short xy = start_x; xy < end_x; ++xy )      {  
				internal_x++;
				int pixel = gdImageGetPixel( im, xy, yx );         
				short terr = get_sector_colour( im, pixel );         
				g->set_location(internal_x,internal_y,terr);
			}   
			internal_y++;
		}
		// done like this because stranger things have happened!
		if(!InList(grid_list, g))
			grid_list.push_front(g);
		else
			log_string("[WORLDMAP]: Grid X%d : Y%d already in the list!  ODD!", g->get_x(), g->get_y());
		fclose(jpgin);   
		jpgin = NULL;
		gdImageDestroy( im );				// ensure the data is destroyed
		#ifdef GRID_DEBUGGING
		log_string("[WORLDMAP]: Grid X%d : Y%d has been opened.  Memory Allocated (%s)", g->get_x(), g->get_y(), size_conversion(sizeof(g)))
		#endif
	}

	// Here we deal with a safety issue, so that we do not have any overall problems, we try
	// and ensuer that our maps are purged often if not being used, and when we load a new
	// grid, we assume that people are wandering on the map, causing the rapid opening/closing
	// of grids.  if we have over <GRID_SAFETY> open, then we check and see if nobody is in
	// the grids, and then close them if nobody is in them.
	if(grid_max > GRID_SAFETY) {
		FOREACH(Lexi::List<grid_data *>, grid_list, grid_iter) {
			grid_data *g = (*grid_iter);
			if(localtime(&g->get_time())->tm_min+10 > localtime(&current_time)->tm_min
			|| (localtime(&g->get_time())->tm_hour < localtime(&current_time)->tm_hour
			&& localtime(&g->get_time())->tm_min < local_time(&current_time)->tm_min)) {
				bool found = false;
				FOREACH(Lexi::List<CHAR_DATA *>, wild_list, w_iter) {
					CHAR_DATA *w = (*w_iter);
					if(w->coordinates[GRID_X] == g->get_x() && w->coordinates[GRID_Y] == get_y())
						found = true;
				}

				// was there someone within the grid?  If not, lets close it!
				// even if the last-used time is out, we don't want to obscure
				// the map, so we protect ourselves, and ensure there are no outstanding issue's
				if(!found) {	
					#ifdef GRID_DEBUGGING
					log_string("[WORLDMAP]: Grid X%d : Y%d exceeding grid safety.  Will close!", g->get_x(), g->get_y()))
					#endif
					close_grid(g);
				}
			}
		}
	}

	return g;
}


//////////////////////////////////////////////////////////////////////////////////////
// movement: check coordinates for grid-loading changes.
// here we go doing the hard stuff.  We find out if the grid is loaded
// if it isn't, we load it, since we are changing coordinates, we need
// to ensure that everything is good.

// set our global coordinates.
coordinates[COORD_X] = temp_x;
coordinates[COORD_Y] = temp_Y;

// change our in_x variable appropriatly.
switch(direction) {
	case DIR_NORTH:
		coordinates[IN_X]--; break;
	case DIR_SOUTH:
		coordinates[IN_X]++; break;
	case DIR_EAST:
		coordinates[IN_Y]++; break;
	case DIR_WEST:
		coordinates[IN_Y]--; break;
	case DIR_NORTHEAST:
		coordinates[IN_X]--; 
		coordinates[IN_Y]++; break;
	case DIR_SOUTHWEST:
		coordinates[IN_X]++; 
		coordinates[IN_Y]--; break;
	case DIR_NORTHWEST:
		coordinates[IN_X]--; 
		coordinates[IN_Y]--; break;
	case DIR_SOUTHEAST:
		coordinates[IN_X]++; 
		coordinates[IN_Y]++; break;
}

// Now we've changed our IN_X/IN_Y variables, lets see if
// we are changing grids? or atleast close enough to load a new grid.
// manage our local x/y coordinates
if(coordinates[IN_X] == MAX_GRID_X-1) {
	if(!grid_loaded(coordinates[GRID_X+1], coordinates[GRID_Y]))
		load_grid(coordinates[GRID_X+1], coordinates[GRID_Y]);
}
if(coordinates[IN_Y] == MAX_GRID_Y-1) {
	if(!grid_loaded(coordinates[GRID_X], coordinates[GRID_Y+1]))
		load_grid(coordinates[GRID_X], coordinates[GRID_Y+1);
}
if(coordinates[IN_X] == 0) {
	if(!grid_loaded(coordinates[GRID_X-1], coordinates[GRID_Y]))
		load_grid(coordinates[GRID_X-1], coordinates[GRID_Y]));
}
if(coordinates[IN_Y] == 0) {
	if(!grid_loaded(coordinates[GRID_X], coordinates[GRID_Y-1]))
		load_grid(coordinates[GRID_X], coordinates[GRID_Y-1));
}

// we change our standing within the world based on these coordinates
// that we have manipulated, and ensure all is well.
// world wrapping!
// this will be changed to a switch statement so we can change more values
// easily without any major issue's.  such as the characters IN_X/IN_Y variables
// as they change when moving grid-to-grid.  Entirely based on the direction
// are we moving off-the-grid!
if(coordinates[IN_X] > 49 || coordinates[IN_X] < 0
|| coordinates[IN_Y] > 49 || coordinates[IN_Y] < 0) {
	// Okay, we're exceeding the value's, so we have to correct these
	// because this is how we do it.  So we do our grid-manipulation
	// to the best of our ability, change our coordinates, and re-align
	// our variables to match appropriatly.
	switch(direction) {
		case DIR_NORTH: 
				coordinates[GRID_X]--;
				coordinates[IN_X] = 0;	
				break;
		case DIR_SOUTH: 
				coordinates[GRID_X]++;
				coordinates[IN_X] = 49;	break;
		case DIR_EAST:  coordinates[GRID_Y]++;
				coordinates[IN_Y] = 0;	
				break;
		case DIR_WEST:  coordinates[GRID_Y]--; 
				coordinates[IN_Y] = 49;	
				break;
		case DIR_NORTHEAST: 
				coordinates[GRID_X]--;	coordinates[GRID_Y]++;
				coordinates[IN_X] = 0; coordinates[IN_Y] = 0;	
				break;
		case DIR_NORTHWEST: 
				coordinates[GRID_X]--;	coordinates[GRID_Y]--;
				coordinates[IN_X] = 0; coordinates[IN_Y] = 49;	
				break;
		case DIR_SOUTHEAST: 
				coordinates[GRID_X]++;	coordinates[GRID_Y]++; 
				coordinates[IN_X] = 49; coordinates[IN_Y] = 0; 	
				break;
		case DIR_SOUTHWEST: 
				coordinates[GRID_X] +=1;	coordinates[GRID_Y] -=1; 
				coordinates[IN_X] = 0; coordinates[IN_Y] = 49;	
				break;
	
	}
}

// world wrapping correction, ensuer we are in the right place
// and not in an non-existant location.
if(coordinates[GRID_X] > MAX_GRID-1) 	coordinates[GRID_X] = 0; 
if(coordinates[GRID_Y] > MAX_GRID-1)	coordinates[GRID_Y] = 0;
if(coordinates[GRID_X] < 0)		coordinates[GRID_X] = MAX_GRID-1;
if(coordinates[GRID_Y] < 0)		coordinates[GRID_Y] = MAX_GRID-1;

// everytime we move, we find our grid, there shouldn't be too many grids open
// at any given time, so this should process really fast.
// if it becomes an issue, then we'll just have to adjust to a minute management
// of grids, so after minutes of non-use they close, apposed to hours.
grid_data *g = get_grid(coordinates[GRID_X], coordinates[GRID_Y]);
if(g) // we hope this isn't ever null
	g->set_time();
else {
	log_string("Character {{%s} moved in a NULL grid, safety required", IS_NPC(this) ? short_descr : name);
	if(IS_NPC(this))
		extract_char(this, true);		// NPC not needed, extract.
	else
		extract_char(this, false);		// returns to their hometown safely!

	// just notify them with whats happened.
	Sendf("You have been returned to your hometown mystically, maybe this was a good thing.!\n\r");
}


//////////////////////////////////////////////////////////////////////////////////////
// Give our immortals the ability to view our loaded grids and alittle bit of information
// about them, this will help with understanding of the overall grid-mapping magic
// that has been performed here today.
COMMAND(cmd_gridlist) {
	BUFFER *output = new_buf();
	char arg[MIL];

	argument = one_argument(argument, arg);
	if(arg[0] == '\0' || !str_cmp(arg, "list")) {
		int cnt = 0;
		FOREACH(Lexi::List<grid_data *>, grid_list, grid_iter) {
			grid_data *g = (*grid_iter);
			BufPrintf(output, "[%d]Grid: X%d Y%d: Last used: %s: Memory Used: %s.\n\r", cnt, g->get_x(), g->get_y(), grab_time_log(g->get_time(), size_conversion(sizeof(g)));
			cnt++;
		}
	
		BufPrintf("%d grids with memory allocated.", grid_max);
		page_to_char(buf_string(output), ch);
		free_buf(output);
	}

	// close the selected grid, if nobody is in the grid.
	if(!str_cmp(arg, "remove") || !str_cmp(arg, "delete") || !str_cmp(arg, "close")) {
		if(!is_number(argument)) {
			ch->Sendf("Syntax: gridlist close <number>\n\r");
			return;
		}
		int cnt = 0;
		FOREACH(Lexi::List<grid_data *>, grid_list, grid_iter) {
			grid_data *g = (*grid_iter);
			if(cnt == atoi(argument)) {
				FOREACH(Lexi::List<CHAR_DATA *>, wild_list, wild_iter) {
					CHAR_DATA *c = (*wild_iter);
					if(g->get_x() == c->coordinates[GRID_X] && g->get_y() == c->coordinates[GRID_Y]) {
						ch->Sendf(You cannot delete that grid, it is in use!"\n\r");
						return;
					}
				}
				// close the grid
				close_grid(g);
				ch->Sendf("You have closed a worldmap grid.\n\r");
				return
			}
			cnt++;
		}		
		return;
	}

	ch->Sendf("Syntax: gridlist list\n\r");
	ch->Sendf("Syntax: gridlist close <number>\n\r");

	return;
}


//////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////
// display changes, based on x/y range
short coordinates[7];	// to replace x/y and cord variable in char_data.
#define COORD_X 0	// global coords		-- used to show the exact location on the worldmap
#define COORD_Y 1	// global coords		-- used to show the exact location on the worldmap
#define GRID_X  2	// what x-grid			-- our x-grid location
#define GRID_Y  3	// what y-grid			-- our y-grid location
#define IN_X    4	// what x location within grid	-- within the grid, what x location are we.
#define IN_Y    5	// what y location within grid	-- within the grid, what y location are we

#define GRID_SAFETY  5  // how many grids can be open before we start to freak out and try to close them!
#define MAX_GRID    60	// how many grids there are(60x60)
#define MAX_GRID_X  50  // max X per grid (this ties into the MAX_GRID value)
#define MAX_GRID_Y  50  // max Y per grid (this ties into the MAX_GRID value)

//////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////


//////////////////////////////////////////////////////////////////////////////////////
// We want to find out the size in KB, so we go the round-about way to determining the
// size, and returning it. under 1024, we return bytes, over, we return kb, and so on.
// this function is going to be used in many locations for memory management.
const char *size_conversion(size_t size) {
	int math_controller = 1024;
	int new_size = size/math_controller;	// in KB! (solong as size was over 1024, thi will return a kb)

	if(size <1024) {
		String str = "" << size << " bytes.";
		return str.c_str();
	}

	// over 1024 in originaly size!?
	if(size >=1024) {
		// whoah, whoah whoa!  We are in the megabytes (don't think we need to go anyhigher)
		if(new_size >= 1024) {
			String s = "" << new_size/1024 << " megabytes.";
			return s.c_str();
		}
		// not a megabyte, not a byte, must be a kilobyte!
		String str = "" << new_size << " kilobytes.";
		return str.c_str();
	}

	// if we ever reach this, I'll eat your hat!
	return "Unknown size.... SCARY!";

}

//////////////////////////////////////////////////////////////////////////////////////
// Modified looking (test)
int orig_grid_x = ch->coordinates[GRID_X];
int orig_grid_y = ch->coordinates[GRID_Y];
int curr_grid_x = orig_grid_x;
int curr_grid_y = orig_grid_y;

grid *gd = get_grid(orig_grid_x, orig_grid_y);

for(start_x = ch->coordinates[IN_X]-10; start_x < ch->coordinates[IN_X]+10; start_x++) {

	// modify our grid locations as required
	if(start_x <0)
		curr_grid_y--;
	if(start_x>49)
		curr_grid_x++;

	// now we loop through our Y variable, and get our location
	for(start_y = ch->coordinates[IN_Y]-7; start_y < ch->coordinates[IN_Y]+7; start_y++) {
		if(start_y>49)
			curr_grid_y++;
		if(start_y <0)
			curr_grid_y--;

		// make sure the grids are loaded that are required to be loaded.
		if(curr_grid_x == MAX_GRID_X-1) {
			if(!grid_loaded(curr_grid_x+1, curr_grid_y))
				load_grid(curr_grid_x+1, curr_grid_y);
		}
		if(curr_grid_y == MAX_GRID_Y-1) {
			if(!grid_loaded(curr_grid_x, curr_grid_y+1))
				load_grid(curr_grid_x, curr_grid_y+1);
		}
		if(curr_grid_x == 0) {
			if(!grid_loaded(curr_grid_x-1, curr_grid_y))
				load_grid(curr_grid_x-1, curr_grid_y);
		}
		if(curr_grid_y == 0) {
			if(!grid_loaded(curr_grid_x, curr_grid_y-1))
				load_grid(curr_grid_x, curr_grid_y-1);
		}

		// we draw our room (simple pleasures)
		// start_x and and start_y will be manipulated in draw_room based on curr_grid vs orig_grid.
		// if the grid's aren't the same, it will change based on how far beyond the limits.
		// so -7 translates into 43, where as 57 turns into 6, simple mathmatics to display the appropriate
		// information.
		//
		// gd is used to get the location and return its drawing point.
		// if the orig_grid's dont' match the curr_grid, we switch to the appropriate grid
		// but so-long as the orig_grid is the curr grid, we don't have to lookup the grid
		// location, saving memory and cpu usage everytime we look. <-- important!
		//
		// this looks like it could verywell work, so-long as the modifications are made to
		// draw_room that check the grids, and start_x/y variables and switch them around as
		// required.
		draw_room(ch, gd, orig_grid_x, orig_grid_y, curr_grid_x, curr_grid_y, start_x, start_y);


	}

}