/* IMPORTANT!
You may non-commercially make modifications to this program and
non-commercially distribute modified copies anywhere and to anyone,
provided you follow these basic guidelines.

Replace 'Foo Bar' in the below line '#define EDITNOTES "Edited by Foo Bar"'
with your name(s).

I recommend separate compiles for each calculator.
*/



// Insert your name(s) here
#define EDITNOTES "Edited by Foo Bar"
#define EDITNOTES2 ""



/* Note: Each scenario file has a 16-byte random "code" used to identify it.
The code for the default scenario is {49854, 918, 50773, 19788, 18976, 37979, 34958, 46238}.
This would be important if you intend to build AI for the default scenario only.
*/

/* C Source File
Created 4/8/2004; 9:17:37 PM
Original Author: William Jacobs

CivEdit, version 1.03
Now open source!

Changes from version 1.02:
-compiled with TIGCC v0.95 beta 17

Short-term requirements:
[none]

Long-term requirements:
[none]
*/

#define COMMENT_PROGRAM_NAME   "CivEdit"
#define COMMENT_VERSION_STRING "1.03"
#define COMMENT_VERSION_NUMBER 1,0,3,0

#include <tigcclib.h>         // Include All Header Files

#define UPCHAR 23
#define DOWNCHAR 24
#define _2nd 4096

enum ORDERS {none, buildcity, buildcanal, mineforgold, buildroads, board};
enum TYPES {gro, wat, air, ha, bom, bmr};

struct PLAYER
{
	//struct TRANSPORT *transport;
	struct UNIT *unit;
	struct CITY *city;
	// gpt is gold per turn per city
	// active is whether a unit is available vis-a-vis technology
	unsigned char cities, /*transports,*/ researching, *researched, *active, gpt, rbonus5, pbonus5, bridge;
	// apos is the positions of the activated units
	// showhp is whether the bars are movement points by default
	char *apos, xc, yc, xo, yo, handicap, curcity, showhp;
	// researchp40 is 40 times the portion of the technology researched (out of 200, 250, 300, or 350)
	short researchp40, units, curunit,
	// Range for gold is 0 - 30,000
			gold;
};

// w and h are actually 1 less than the width and height respectively
struct MAP
{
	char name[20];
	struct TILE *tile;
	unsigned char w, h;
};

/*struct KEYS
{
	short up, down, left, right, let[26], diamond;
};*/

struct NUMS
{
	char scen, map, game, autosave, **player, infos, techs;
	short turnnum, maxturn;
	unsigned short code[8], goldoverflow;
};

// 23 bytes
// Range for total number of technologies is 0 - 63
struct TECH
{
	// No longer in draw width than 57, excluding leading pixel
	char id[17];
	unsigned char prereq[3],
	// prod5 must not exceed 19
								prod5:5, sci5:5, gold:7, age:6, bridge:1;
};

// 16 bytes
/*struct TRANSPORT
{
	short transport[8];
};*/

// Limit 300 units per player
// 9 bytes
struct UNIT
{
	// uindex means unit index (i.e. Warriors, etc.)
	unsigned short uindex:10, hp10:12,
	// tindex means transporter index, attacked is whether the unit attacked
	// this turn
								tindex:9;
	/* Valid orders:
	   0 = - = idle
	   1 = B = Building a city
	   2 = C = building a Canal
	   3 = M = Mining
	   4 = R = building Roads
	   5 = T = in a Transport unit
	   
	   Old 1 = A = Assisting production*/
	unsigned char x, y, orders:7, attacked:1,
	// percent means percantage of task completed x 2
								percent2, m2;
};

// Map is 50x50, 1 byte
struct TILE
{
	unsigned char water1:1, river1:1, road1:1, mine1:1, water2:1, river2:1, road2:1, mine2:1;
};

// Maximum of 127 unit types, 28 bytes
struct UNITTYPE
{
	// No longer in draw width than 57, excluding leading pixel; id must not be a null string
	char id[17];
	unsigned char turns10;
	// vsha5 means percentage of attack that can be used versus high air ÷ 5
	/* buildmult10 is a multiplier for the building speed x 10 - engineers = 2x
	   and settlers / builders = 1x */
	// tech = prerequisite, br means blast radius
	// limit: 99
	unsigned char d:7,
	// limit: 99
			m:7,
	// limit: 99
			a:7,
			vsha5:5, vsa5:5, buildmult10:7, assist5:6, canals:1, tech:6, br:4,
	// cau means consumed after use
	// Range for cost10 is 1 - 99
			cost10:7, mines:7,
	// trans means how many units it can transport
	// Range for trans is 0 - 9
			trans:7, /*bribe:1,*/ cau:1, type:3;
};

// 13 bytes
struct OLDCITY
{
	unsigned char x, y, building;
	// percent is the portion of the production that is complete
	float percent;
};

// 5 bytes
struct CITY
{
	unsigned char x, y, building;
	// percent is the portion of the production that is complete x 1000
	short percent1600;
};

struct SORTS
{
	// csort[0] is the cheapest unit
	// asort[0] is the unit earliest in the alphabet
	// tsort[0] is the technology earliest in the alphabet
	unsigned char *csort, *asort; //, *tsort;
};

struct FOCUS
{
	char xc, yc, xo, yo;
};

unsigned long rects[100];
unsigned char *sprites;
short let[26];

/*void debugchar(char a)
{
	char inf[30];
	FontSetSys(F_8x10);
	sprintf(inf, "%c", a);
	ClrScr();
	DrawStr(0, 0, inf, A_NORMAL);
	ngetchx();
}

void debugint(short a)
{
	char inf[30];
	FontSetSys(F_8x10);
	sprintf(inf, "%d", a);
	ClrScr();
	DrawStr(0, 0, inf, A_NORMAL);
	ngetchx();
}*/

/*void debugint2(short a)
{
	char inf[30];
	FontSetSys(F_6x8);
	sprintf(inf, "%d", a);
	DrawStr(40, 35, inf, A_NORMAL);
}*/

/*void debugfloat(float a)
{
	char inf[30];
	FontSetSys(F_8x10);
	sprintf(inf, "%f", a);
	ClrScr();
	DrawStr(0, 0, inf, A_NORMAL);
	ngetchx();
}

void debuglong(long int a)
{
	char inf[30];
	FontSetSys(F_8x10);
	sprintf(inf, "%ld", a);
	ClrScr();
	DrawStr(0, 0, inf, A_NORMAL);
	ngetchx();
}*/

void error(unsigned char a)
{
	char message[27] = "Error reading ";
	switch(a)
	{
		/*case 1:
			strcpy(message, "Grayscale initialization error");
			break;
		Not necessary due to GrayOnThrow function	
		*/
		case 1:
			strcpy(message + 6, "saving game");
			break;
		case 2:
			strcat(message, "map data");
			break;
		case 3:
			strcat(message, "scenario data");
			break;
		case 4:
			strcpy(message + 6, "loading saved game");
			break;
		case 5:
			strcpy(message, "Timer initialization error");
			break;
		case 6:
			strcpy(message, "Insufficient memory for operation");
			break;
		case 7:
			strcpy(message + 6, "saving scenario");
			break;
		default:
			strcpy(message + 6, "saving map");
	};
	DlgMessage("Terminal Error", message, BT_NONE, BT_OK);
}

void DrawStrXor(unsigned char x, char y, const char *s)
{
	DrawStr(x, y, s, A_XOR);
}

void DrawStrXor1(char y, const char *s)
{
	DrawStrXor(1, y, s);
}

void DrawStrXor100(char y, const char *s)
{
	DrawStrXor(100, y, s);
}

void DrawCharXor(unsigned char x, char y, char s)
{
	DrawChar(x, y, s, A_XOR);
}

void DrawLineXor(unsigned char x1, char y1, unsigned char x2, char y2)
{
	DrawLine(x1, y1, x2, y2, A_XOR);
}

void drawrect(unsigned char x1, char y1, unsigned char x2, char y2)
{
	SCR_RECT rect;
	rect = (SCR_RECT){{x1, y1, x2, y2}};
	ScrRectFill(&rect, &rect, A_XOR);
}

void drawrect100159(unsigned char y1, unsigned char y2)
{
	drawrect(100, y1, 159, y1 + y2);
}

void setfont4x6()
{
	FontSetSys(F_4x6);
}

void setfont6x8()
{
	FontSetSys(F_6x8);
}

void centertext(const char *s, char y)
{
	DrawStrXor(80 - (DrawStrWidth(s, FontGetSys()) >> 1), y, s);
}

void tryfree(void *ptr)
{
	if (ptr)
	{
		free(ptr);
	}
}

char keyletter(short k)
{
	char a;
	short *b;
	if (isalpha(k))
	{
		return(tolower(k));
	}
	else if (k == 149)
	{
		// EE
		return('k');
	}
	else
	{
		b = let;
		for(a = 0; a <= 25; a++)
		{
			if (k == *(b++))
			{
				return(a + 'a');
			}
		}
		return(0);
	}
}

// freadc means perform FREAD and Compare the result to n
// Returns whether there was a problem in reading
char freadc(void *ptr, unsigned short size, unsigned short n, FILE *input)
{
	return(fread(ptr, size, n, input) != n);
}

char fread1(void *ptr, unsigned short n, FILE *input)
{
	return(freadc(ptr, 1, n, input));
}

char fwritec(void *ptr, unsigned short size, unsigned short n, FILE *input)
{
	return(fwrite(ptr, size, n, input) != n);
}

char fwrite1(void *ptr, unsigned short n, FILE *input)
{
	return(fwritec(ptr, 1, n, input));
}

static inline char savescen(char fileindex, struct TECH *tech, struct UNITTYPE *info, char *scenname, struct NUMS *nums, struct SORTS *sorts, char allowbigchanges)
{
	FILE *output;
	char a, fname[11];
	sprintf(fname, "main\\scen%d", fileindex);
	if (!(output = fopen(fname, "wb")))
	{
		return(0);
	}
	if (allowbigchanges)
	{
		for(a = 0; a <= 7; a++)
		{
			nums->code[a] = ((rand() >= KEY_DIAMOND) << 15) + rand();
		}
	}
	if (fwrite1(scenname, 21, output))
	{
		return(0);
	}
	if (fwritec(&(nums->code), 2, 8, output))
	{
		return(0);
	}
	if (fwrite1(&(nums->infos), 1, output))
	{
		return(0);
	}
	if (fwritec(info, sizeof(struct UNITTYPE), nums->infos, output))
	{
		return(0);
	}
	if (fwrite1(sprites, (nums->infos + 6) << 3, output))
	{
		return(0);
	}
	if (fwrite1(sorts->csort, nums->infos, output))
	{
		return(0);
	}
	if (fwrite1(sorts->asort, nums->infos, output))
	{
		return(0);
	}
	if (fwrite1(&(nums->techs), 1, output))
	{
		return(0);
	}
	if (fwritec(tech, sizeof(struct TECH), nums->techs, output))
	{
		return(0);
	}
	fputc(0, output);
	fputs("CIV", output);
	fputc(0, output);
	fputc(OTH_TAG, output);
	return(!fclose(output));
}

char loadscen(char fileindex, struct TECH **tech, struct UNITTYPE **info, char *scenname, struct NUMS *nums, struct SORTS *sorts)
{
	FILE *input;
	char fname[11];
	short a;
	sprintf(fname, "main\\scen%d", fileindex);
	if (!(input = fopen(fname, "rb")))
	{
		return(0);
	}
	if (fread1(scenname, 21, input))
	{
		return(0);
	}
	if (freadc(&(nums->code), 2, 8, input))
	{
		return(0);
	}
	if (fread1(&(nums->infos), 1, input))
	{
		return(0);
	}
	tryfree(*info);
	*info = (struct UNITTYPE *)malloc_throw(nums->infos * sizeof(struct UNITTYPE));
	a = (nums->infos + 6) << 3;
	tryfree(sprites);
	sprites = (unsigned char *)malloc_throw(a);
	tryfree(sorts->csort);
	sorts->csort = (unsigned char *)malloc_throw(nums->infos);
	tryfree(sorts->asort);
	sorts->asort = (unsigned char *)malloc_throw(nums->infos);
	if (freadc(*info, sizeof(struct UNITTYPE), nums->infos, input))
	{
		return(0);
	}
	if (fread1(sprites, a, input))
	{
		return(0);
	}
	a = nums->infos;
	if (fread1(sorts->csort, a, input))
	{
		return(0);
	}
	if (fread1(sorts->asort, a, input))
	{
		return(0);
	}
	if (fread1(&(nums->techs), 1, input))
	{
		return(0);
	}
	a = nums->techs;
	tryfree(*tech);
	*tech = (struct TECH *)malloc_throw(a * sizeof(struct TECH));
	//tryfree(sorts->tsort);
	//sorts->tsort = (unsigned char *)malloc_throw(a);
	if (freadc(*tech, sizeof(struct TECH), a, input))
	{
		return(0);
	}
	/*if (fread1(sorts->tsort, a, input) != a)
	{
		return(0);
	}*/
	return(!fclose(input));
	/*ClrScr();
	DrawStr(0, 0, (*info)[0].id, A_NORMAL);
	ngetchx();*/
}

char dirkeys2(short k)
{
	if (k == KEY_LEFT)
	{
		return(1);
	}
	else if (k == KEY_UP)
	{
		return(2);
	}
	else if (k == KEY_RIGHT)
	{
		return(3);
	}
	else if (k == KEY_DOWN)
	{
		return(4);
	}
	else
	{
		return(0);
	}
}

void bigmessage(const char *s)
{
	char *a, b[107], *c, y;
	strcpy(c = b, s);
	FontSetSys(F_8x10);
	ClrScr();
	y = 2;
	while ((a = strchr(c, '^')))
	{
		*a = 0;
		centertext(c, y);
		y += 11;
		c = a + 1;
	}
	centertext(c, y);
}

short grayngetchx()
{
	pokeIO(0x600005,0b10111);
	return(ngetchx());
}

short nograyngetchx()
{
	idle();
	return(ngetchx());
}

void etc()
{
	setfont4x6();
	DrawStrXor(39, 91, "Press ENTER to continue");
	while (nograyngetchx() != 13);
}

void highlight3(char a)
{
	drawrect(0, a * 9 + 1, 159, a * 9 + 9);
}

// Returns -1 for no selection (meaning go back one screen), else the selection
char askwhichdata(char datatype, char addempty)
{
	char a, b[10], c, e, y, s[29], fname[14] = "main\\";
	short d;
	//struct NUMS nums;
	struct MAP map;
	FILE *input;
	ClrScr();
	setfont6x8();
	y = -7;
	c = -1;
	switch(datatype)
	{
		case 0:
			sprintf(fname + 5, "civgame0");
			break;
		case 1:
			sprintf(fname + 5, "scen0");
			break;
		default:
			sprintf(fname + 5, "map0");
	};
	for(a = 0; a <= 9; a++)
	{
		y += 9;
		b[a] = 0;
		if ((input = fopen(fname, "rb")))
		{
			switch(datatype)
			{
				case 0:
					// Load game
					//if (fread(&d, 2, 1, input) && fread(&nums, sizeof(struct NUMS), 1, input) && fread(&e, 1, 1, input) && fread(s, 1, 11, input) == 11)
					if (!fseek(input, sizeof(struct NUMS) + 2, SEEK_SET) && fread(s, 1, 11, input) == 11)
					{
						strcat(s, " vs ");
						b[a] = (fread(s + strlen(s), 1, 11, input) == 11);
					}
					break;
				case 1:
					// Load scenario
					b[a] = (fread(s, 1, 21, input) == 21);
					break;
				default:
					// Load map
					if ((b[a] = fread(&map, sizeof(struct MAP), 1, input)))
					{
						strcpy(s, map.name);
					}
			};
			fclose(input);
		}
		if (!b[a] && addempty)
		{
			strcpy(s, "(empty)");
			b[a] = 1;
		}
		if (b[a])
		{
			DrawStrXor(13, y, s);
			DrawCharXor(1, y, a + '0');
			if (c == -1)
			{
				c = a;
			}
		}
		fname[strlen(fname) - 1]++;
	}
	/*if (!b[3])
	{
		exit(0);
	}*/
	if (c > -1)
	{
		setfont4x6();
		DrawStrXor(1, 94, "Use \x17\x18 to move, ENTER to select");
		setfont6x8();
		highlight3(c);
		do
		{
			a = c;
			d = nograyngetchx();
			e = dirkeys2(d);
			if (e)
			{
				if (e >= 3)
				{
					y = 1;
				}
				else if (e)
				{
					y = 9;
				}
				for(a = (c + y) % 10; a != c; a = (a + y) % 10)
				{
					if (b[a])
					{
						break;
					}
				}
			}
			if (a != c) //&& a >= 0 && a <= 9)
			{
				highlight3(c);
				highlight3(c = a);
			}
		}
		while (d != 13 && d != 264);
		if (d == 13)
		{
			return(c);
		}
		else
		{
			return(-1);
		}
	}
	else
	{
		strcpy(s, "There are no");
		if (!datatype)
		{
			strcat(s, " saved^games.");
		}
		else
		{
			if (datatype == 1)
			{
				strcat(s, "^scenario files.");
			}
			else
			{
				strcat(s, " map^files.");
			}
		}
		bigmessage(s);
		etc();
		return(-1);
	}
}

void highlight(char a)
{
	switch(a)
	{
		case 0:
			drawrect(55, 54, 105, 64);
			break;
		case 1:
			drawrect(70, 69, 90, 79);
			break;
		default:
			drawrect(67, 84, 93, 94);
	}
}

// Returns -2 for back, -1 for new, 0 - 9 for load
/*char newload(char datatype, struct KEYS *keys)
{
	char a, s[16];
	short k;
	do
	{
		FontSetSys(F_8x10);
		ClrScr();
		switch(datatype)
		{
			//case 0:
			//	strcpy(s, "Game");
			//	break;
			case 1:
				strcpy(s, "Scenario");
				break;
			default:
				strcpy(s, "Map");
		};
		strcat(s, " Editor");
		centertext(s, 8);
		setfont6x8();
		DrawStrXor(71, 40, "New");
		DrawStrXor(68, 60, "Load");
		drawrect(70, 38, 90, 48);
		a = 1;
		do
		{
			k = ngetchx();
			if ((k == KEY_UP && !a) || (k == KEY_DOWN && a))
			{
				a = !a;
				drawrect(70, 38, 90, 48);
				drawrect(67, 58, 93, 68);
			}
		}
		while (k != 13 && k != 264);
		if (!a && k == 13)
		{
			a = askwhichdata(datatype, keys, 0) + 2;
			if (a == 1)
			{
				k = 0;
			}
		}
	}
	while (k != 13 && k != 264);
	if (k != 264)
	{
		return(a - 2);
	}
	else
	{
		return(-2);
	}
}*/

// updown = 0: returns 0 for ESC, 1 for ENTER
// updown = 1: returns k
short getstr(char *s, char x, char y, char maxchars, unsigned char maxwidth, char updown)
{
	short k;
	char a, b, f, h;
	b = h = strlen(s);
	setfont6x8();
	if (b != maxchars || maxchars > 16)
	{
		DrawLineXor(x + 6 * h + 1, y + 7, x + 6 * h + 5, y + 7);
	}
	do
	{
		f = 0;
		k = nograyngetchx();
		if (k == 257)
		{
			// backspace
			if (h)
			{
				f = s[a = --h];
				s[h] = 0;
			}
		}
		else if (k == 263)
		{
			// Clear
			DrawStrXor(x, y, s);
			s[h = 0] = 0;
		}
		else if (h < maxchars)
		{
			if ((f = keyletter(k)) || (((k == ' ' && maxchars != 10) || k == 173) && h))
			{
				if (!f)
				{
					f = ' ';
				}
				else if (isalpha(k))
				{
					// This accomidates uppercase letters
					f = k;
				}
				a = h;
				sprintf(s + h++, "%c", f);
				if (DrawStrWidth(s, F_4x6) > maxwidth)
				{
					s[--h] = 0;
					f = 0;
				}
			}
		}
		if (f)
		{
			DrawCharXor(x + 6 * a, y, f);
		}
		if (b != h)
		{
			if (b != maxchars || maxchars > 16)
			{
				DrawLineXor(x + 6 * b + 1, y + 7, x + 6 * b + 5, y + 7);
			}
			if (h != maxchars || maxchars > 16)
			{
				DrawLineXor(x + 6 * h + 1, y + 7, x + 6 * h + 5, y + 7);
			}
			b = h;
		}
	}
	while (((!updown && k != 13) || (updown && k != KEY_UP && k != KEY_DOWN)) && k != 264);
	if (h != maxchars && maxchars <= 16)
	{
		DrawLineXor(x + 6 * h + 1, y + 7, x + 6 * h + 5, y + 7);
	}
	if (updown)
	{
		return(k);
	}
	else
	{
		return(k == 13);
	}
}

void revrect(unsigned char x1, unsigned char y1, unsigned char x2, unsigned char y2)
{
	SCR_RECT rect;
	rect = (SCR_RECT){{x1, y1, x2, y2}};
	ScrRectFill(&rect, &rect, A_REVERSE);
}

void rectoutline(short x1, short y1, short x2, short y2, short attribute)
{
	DrawLine(x1, y1, x2, y1, attribute);
	DrawLine(x2, ++y1, x2, y2, attribute);
	DrawLine(x1 + 1, y2, x2 - 1, y2, attribute);
	DrawLine(x1, y1, x1, y2, attribute);
}

void clearleft()
{
	revrect(0, 0, 98, 99);
}

void editsprite(unsigned char *sprite)
{
	char a, b, x, y, ox, oy;
	unsigned char newsprite[8];
	short k;
	clearleft();
	for(a = 14; a <= 86; a += 9)
	{
		for(b = 4; b <= 76; b += 9)
		{
			DrawLine(a, 4, a, 76, A_NORMAL);
			DrawLine(14, b, 86, b, A_NORMAL);
		}
	}
	setfont6x8();
	DrawStrXor1(80, "F1: Save Changes");
	DrawStrXor1(90, "F2: Exit");
	for(a = 0; a <= 7; a++)
	{
		newsprite[a] = sprite[a];
		for(b = 0; b <= 7; b++)
		{
			if ((newsprite[a] >> (7 - b)) % 2)
			{
				drawrect(9 * b + 16, 9 * a + 6, 9 * b + 21, 9 * a + 11);
			}
		}
	}
	Sprite8(86, 91, 8, newsprite, LCD_MEM, SPRT_OR);
	ox = oy = x = y = 3;
	//drawrect(9 * x + 18, 9 * y + 8, 9 * x + 19, 9 * y + 9);
	rectoutline(9 * x + 15, 9 * y + 5, 9 * x + 22, 9 * y + 12, A_XOR);
	do
	{
		ox = x;
		oy = y;
		k = nograyngetchx();
		a = dirkeys2(k);
		if (a == 1)
		{
			x = (x + 7) % 8;
		}
		else if (a == 3)
		{
			x = (x + 1) % 8;
		}
		else if (a == 2)
		{
			y = (y + 7) % 8;
		}
		else if (a)
		{
			y = (y + 1) % 8;
		}
		else if (k == 13)
		{
			if ((newsprite[y] >> (7 - x)) % 2)
			{
				newsprite[y] -= (1 << (7 - x));
			}
			else
			{
				newsprite[y] += (1 << (7 - x));
			}
			drawrect(9 * x + 16, 9 * y + 6, 9 * x + 21, 9 * y + 11);
			DrawPix(86 + x, 91 + y, A_XOR);
		}
		else if (k == 263)
		{
			// Clear
			for(a = 0; a <= 7; a++)
			{
				newsprite[a] = 0;
				for(b = 0; b <= 7; b++)
				{
					revrect(9 * b + 16, 9 * a + 6, 9 * b + 21, 9 * a + 11);
				}
			}
			revrect(86, 91, 93, 98);
		}
		if (ox != x || oy != y)
		{
			/*drawrect(9 * ox + 18, 9 * oy + 8, 9 * ox + 19, 9 * oy + 9);
			drawrect(9 * x + 18, 9 * y + 8, 9 * x + 19, 9 * y + 13);*/
			rectoutline(9 * ox + 15, 9 * oy + 5, 9 * ox + 22, 9 * oy + 12, A_XOR);
			rectoutline(9 * x + 15, 9 * y + 5, 9 * x + 22, 9 * y + 12, A_XOR);
		}
	}
	while (k != 268 && k != 269);
	if (k == 268)
	{
		for(a = 0; a <= 7; a++)
		{
			sprite[a] = newsprite[a];
		}
	}
}

// drawfs means "Draw F's", as in F keys
void drawfs()
{
	setfont4x6();
	DrawStrXor(0, 88, "F1: Info");
	DrawStrXor(42, 88, "F2: Technologies");
	DrawStrXor(0, 94, "F3: Units");
	DrawStrXor(42, 94, "F4: Sprites");
}

void spriteselect(struct UNITTYPE *info, struct NUMS *nums, char a)
{
	if (a < nums->infos)
	{
		DrawStrXor(0, 82, info[a].id);
	}
	else
	{
		switch(a)
		{
			case 84:
				DrawStrXor(0, 82, "Water");
				break;
			case 85:
				DrawStrXor(0, 82, "Unoccupied City");
				break;
			case 86:
				DrawStrXor(0, 82, "Occupied City");
				break;
			case 87:
				DrawStrXor(0, 82, "Roads");
				break;
			case 88:
				DrawStrXor(0, 82, "Rivers");
				break;
			case 89:
				DrawStrXor(0, 82, "Mines");
		};
	}
	rectoutline(9 * (a % 10) + 4, 9 * (a / 10), 9 * (a % 10) + 13, 9 * (a / 10) + 9, A_XOR);
}

// Returns (1 for dir, 2 for 2nd + dir, 3 for diamond + dir) + 3 if down
char dirkeys(short k)
{
	char a, b;
	a = dirkeys2(k);
	if (a == 2)
	{
		return(1);
	}
	else if (a == 4)
	{
		return(4);
	}
	else
	{
		b = dirkeys2(k - _2nd);
		if (a == 1 || b == 1 || b == 2)
		{
			return(2);
		}
		else if (a || b)
		{
			return(5);
		}
		else
		{
			a = dirkeys2(k - KEY_DIAMOND);
			if (a == 1 || a == 2)
			{
				return(3);
			}
			else if (a)
			{
				return(6);
			}
			else
			{
				return(0);
			}
		}
	}
}

void sprintfd(char *s, short a)
{
	sprintf(s, "%d", a);
}

// Returns the next non-unit benefit of the technology, using values as in infotbar
char nexttechbenefit(char curbenefit, struct TECH *tech)
{
	if (tech->gold && curbenefit < 0)
	{
		return(0);
	}
	else if (tech->prod5 && curbenefit < 1)
	{
		return(1);
	}
	else if (tech->sci5 && curbenefit < 2)
	{
		return(2);
	}
	else if (tech->bridge && curbenefit < 3)
	{
		return(3);
	}
	else
	{
		return(4);
	}
}

void drawinfobox(unsigned char selected, unsigned char start, unsigned char end, char istechnology)
{
	char y;
	if (selected != 255)
	{
		if (istechnology)
		{
			if (end <= 14 || selected <= 7 || selected == start)
			{
				y = selected;
			}
			else //if (selected + 7 >= end)
			{
				y = max(14 + selected - end, 7);
			}
			/*else
			{
				y = 7;
			}*/
			y = 6 * y + 8;
		}
		else
		{
			y = 28;
		}
	}
	else
	{
		y = 0;
	}
	drawrect100159(y, 6);
}

static inline void swordshield(unsigned char x, char y)
{
	Sprite8(x, y, 7, (unsigned char[]){0x40,0x40,0x40,0x40,0xE0,0x40,0x40}, LCD_MEM, SPRT_OR);
	Sprite8(x + 20, y, 7, (unsigned char[]){0xF8,0xF8,0xF8,0xF8,0xF8,0x70,0x20}, LCD_MEM, SPRT_OR);
}

unsigned char max1(unsigned char a)
{
	return(max(a, 1));
}

void addtype(char *s, struct UNITTYPE *curinfo)
{
	switch(curinfo->type)
	{
		case gro:
			strcat(s, "Ground");
			break;
		case wat:
			strcat(s, "Water");
			break;
		case air:
			strcat(s, "Air");
			break;
		case ha:
			strcat(s, "High Air");
			break;
		case bom:
			strcat(s, "Bomb");
			break;
		//case bmr:
		default:
			strcat(s, "Bomber");
	};
}

// gives information about a technology or unit
// istechnology indicates whether the information is regarding a technological advance rather than a unit
void infotbar(struct TECH *tech, struct UNITTYPE *info, struct NUMS *nums, struct SORTS *sorts, char istechnology, char index)
{
	// cat means category
	// if istechnology = 1, then selected is the line number of the current selection
	// end is the last line of display, whereas end2 is the greatest value selected can assume
	// start is the lowest value selected can assume
	unsigned char e, h, start, selected, prevselected, end, end2, cat1, cat2, recalc, redraw;
	char a, b, d, f, y, s[18];
	short c, k;
	struct UNITTYPE *curinfo;
	struct TECH *curtech, *curtech2;
	recalc = redraw = 1;
	do
	{
		if (recalc)
		{
			// istechnology = 1 is assumed
			cat1 = start = 0;
			curtech = tech + index;
			for(a = -1; a <= 3; cat1++)
			{
				a = nexttechbenefit(a, curtech);
			}
			for(a = 0; a < nums->infos; a++)
			{
				if (info[a].tech == index)
				{
					cat1++;
					if (!start)
					{
						start = cat1;
					}
				}
			}
			for(cat2 = 0; cat2 <= 2; cat2++)
			{
				if (curtech->prereq[cat2] == 255)
				{
					break;
				}
			}
			cat1--;
			// 3 = 4 - 1
			c = 3;
			for(a = 0; a < nums->techs; a++)
			{
				for(b = 0; b <= 2; b++)
				{
					e = tech[a].prereq[b];
					//curtech2 = tech + a;
					if (e == index)
					{
						c++;
					}
					else if (e == 255)
					{
						break;
					}
				}
			}
			end2 = end = max1(cat1) + max1(cat2) + max(c, 4);
			if (c < 4)
			{
				if (cat2)
				{
					//end2 = max1(cat1) + cat2 + 3;
					end2 -= 2;
				}
				else
				{
					//end2 = cat1 + 2;
					end2 -= 4;
				}
			}
			if (!start)
			{
				start = 3 + max1(cat1);
				if (!cat2)
				{
					if (c)
					{
						start += 2;
					}
					else
					{
						start = 255;
					}
				}
			}
			selected = start;
			prevselected = 255;
			recalc = 0;
		}
		if (redraw)
		{
			a = ((end > 14 && max(selected, 7) != max(prevselected, 7) && min(end, selected + 7) != min(end, prevselected + 7)) || !istechnology || prevselected == 255);
			if (a)
			{
				revrect(100, 0, 159, 99);
				setfont4x6();
			}
			if (istechnology)
			{
				if (a)
				{
					a = b = 0;
					f = 1;
					if (selected <= 7 || end <= 14 || selected == start)
					{
						c = -3;
						y = 9;
						d = 14;
					}
					else
					{
						c = min(selected + 7, end) - 16;
						if (c + 2 <= max1(cat1))
						{
							if (c >= 0)
							{
								for(d = -1; d <= 3 && c >= 0; f++)
								{
									d = nexttechbenefit(d, curtech);
									c--;
								}
								if (c >= 0)
								{
									f += ++c;
									for(d = 0; c >= 0; d++)
									{
										if (info[sorts->asort[d]].tech == index)
										{
											c--;
										}
									}
									c = d + 4;
								}
								else
								{
									c = d;
								}
							}
						}	
						else
						{
							c -= max1(cat1);
							if (c < max1(cat2))
							{
								b = 1;
							}
							else
							{
								f = (c -= (max1(cat2) + 1));
								if (c >= 0)
								{
									for(d = 0; d < nums->techs; d++)
									{
										//curtech2 = tech + sorts->tsort[d];
										for(b = 0; b <= 2; b++)
										{
											e = tech[d].prereq[b];
											if (e == 255)
											{
												break;
											}
											else if (e == index)
											{
												if (!c--)
												{
													c = d;
													d = 126;
													break;
												}
											}
										}
									}
								}
								/*else
								{
									f = 0;
								}*/
								b = 2;
							}
						}
						DrawCharXor(100, 9, UPCHAR);
						d = 13;
						y = 15;
					}
					DrawStrXor100(1, curtech->id);
					DrawLineXor(100, 7, 159, 7);
					if (end <= 14)
					{
						d = end;
					}
					else if (selected + 7 < end)
					{
						DrawCharXor(100, 93, DOWNCHAR);
						d--;
					}
					/*sprintf(s, "%d  ", selected);
					DrawStr(0, 91, s, A_REPLACE);
					sprintf(s, "%d  ", f);
					DrawStr(22, 91, s, A_REPLACE);*/
					do
					{
						switch(b)
						{
							case 0:
								if (c >= -1)
								{
									if (cat1)
									{
										if (c <= 3)
										{
											c = nexttechbenefit(c, curtech);
										}
										if (c > 3)
										{
											do
											{
												curinfo = info + sorts->asort[++c - 5];
											}
											while (curinfo->tech != index);
											strcpy(s, curinfo->id);
										}
										else
										{
											switch(c)
											{
												case 0:
													sprintf(s, "Revenue +%d", curtech->gold);
													break;
												case 1:
													sprintf(s, "Production +%d%%", 5 * curtech->prod5);
													break;
												case 2:
													sprintf(s, "Science +%d%%", 5 * curtech->sci5);
													break;
												default:
													strcpy(s, "Bridge Building");
											};
										}
										/*if (f++ < cat1)
										{
											strcat(s, ",");
										}
										else*/
									}
									else
									{
										strcpy(s, "(none)");
										f = 0;
										/*b = 1;
										c = -1;*/
									}
									if (f++ >= cat1)
									{
										b = 1;
										c = -1;
									}
								}
								else
								{
									if (c == -3)
									{
										strcpy(s, "Type: ");
										switch(curtech->age)
										{
											case 0:
												strcat(s, "Ancient");
												break;
											case 1:
												strcat(s, "Basic");
												break;
											case 2:
												strcat(s, "Industrial");
												break;
											default:
												strcat(s, "Modern");
										};
									}
									else
									{
										*s = 0;
										DrawStrXor(115, y, "Benefits:");
									}
									c++;
								}
								break;
							case 1:
								if (c >= 0)
								{
									if ((f = cat2))
									{
										strcpy(s, tech[curtech->prereq[c]].id);
										/*if ((f = (c + 1 < cat2)))
										{
											strcat(s, ",");
										}
										else if (!(f = (c + 1 < cat2)))
										{
											b = 2;
											c = -2;
										}*/
									}
									else
									{
										strcpy(s, "(none)");
										/*b = 2;
										c = -2;*/
									}
									if (!(f = (c + 1 < cat2)))
									{
										b = 2;
										c = -2;
									}
								}
								else
								{
									strcpy(s, "   Prerequisites:");
								}
								c++;
								break;
							default:
								*s = 0;
								if (c >= 0)
								{
									do
									{
										curtech2 = tech + c;
										for(e = 0; e <= 2; e++)
										{
											h = curtech2->prereq[e];
											if (h == 255)
											{
												break;
											}
											else if (h == index)
											{
												strcpy(s, curtech2->id);
												break;
											}
										}
										c++;
									}
									while (c < nums->techs && !*s);
									if (!*s)
									{
										strcpy(s, "(none)");
									}
									if (++f + max1(cat1) + max1(cat2) + 3 >= end)
									{
										c = -1;
									}
									/*else if (++f + max1(cat1) + max1(cat2) + 4 < end)
									{
										strcat(s, ",");
									}*/
								}
								else
								{
									DrawStrXor(117, y, "Allows:");
									c++;
								}
						};
						if (c >= 1 || (!b && !c))
						{
							strcat(s, ",");
						}
						DrawStrXor100(y, s);
						y += 6;
					}
					while (++a <= d); //&& a + selected <= end);
				}
				else
				{
					drawinfobox(prevselected, start, end, istechnology);
				}
				prevselected = selected;
			}
			else
			{
				curinfo = info + index;
				sprintfd(s, curinfo->a);
				DrawStrXor100(1, curinfo->id);
				DrawLineXor(100, 7, 159, 7);
				swordshield(105, 9);
				setfont6x8();
				DrawStrXor(108, 9, s);
				sprintfd(s, curinfo->d);
				DrawStrXor(130, 9, s);
				Sprite8(147, 9, 8, sprites + ((index + 6) << 3), LCD_MEM, SPRT_OR);
				setfont4x6();
				sprintf(s, "Moves: %d", curinfo->m);
				DrawStrXor100(17, s);
				DrawStrXor(108, 23, "Prerequisite:");
				if (curinfo->tech != 63)
				{
					DrawStrXor100(29, tech[curinfo->tech].id);
					selected = 0;
				}
				else
				{
					DrawStrXor100(29, "(none)");
					selected = 255;
				}
				strcpy(s, "Type: ");
				switch(curinfo->type)
				{
					case gro:
						strcat(s, "Ground");
						break;
					case wat:
						strcat(s, "Water");
						break;
					case air:
						strcat(s, "Air");
						break;
					case ha:
						strcat(s, "High Air");
						break;
					case bom:
						strcat(s, "Bomb");
						break;
					//case bmr:
					default:
						strcat(s, "Bomber");
				};
				DrawStrXor100(y = 35, s);
				if (curinfo->trans)
				{
					sprintf(s, "Transports: %d", curinfo->trans);
					DrawStrXor100(y += 6, s);
				}
				if (curinfo->br)
				{
					sprintf(s, "Blast Radius: %d", curinfo->br);
					DrawStrXor100(y += 6, s);
				}
				if (curinfo->buildmult10)
				{
					sprintf(s, "Build Speed: %d.%d", curinfo->buildmult10 / 10, curinfo->buildmult10 % 10);
					DrawStrXor100(y += 6, s);
				}
				if (curinfo->canals)
				{
					DrawStrXor100(y += 6, "Can Build Canals");
				}
				if (curinfo->mines)
				{
					sprintf(s, "Mines: %d gold", curinfo->mines);
					DrawStrXor100(y += 6, s);
				}
				if (curinfo->assist5)
				{
					sprintf(s, "Assists City: %d%%", curinfo->assist5 * 5);
					DrawStrXor100(y += 6, s);
				}
				//if (!curinfo->bribe)
				//{
					if (curinfo->a)
					{
						sprintf(s, "Vs. Air: %d%%", curinfo->vsa5 * 5);
						DrawStrXor100(y += 6, s);
						sprintf(s + 4, "High Air: %d%%", curinfo->vsha5 * 5);
						DrawStrXor100(y += 6, s);
					}
				/*}
				else
				{
					DrawStrXor100(y += 6, "Can Bribe");
				}*/
				if (curinfo->cau)
				{
					DrawStrXor100(y += 6, "Dstroyd After Use");
				}
				sprintf(s, "Takes: %d.%d turns", curinfo->turns10 / 10, curinfo->turns10 % 10);
				DrawStrXor100(y + 6, s);
				if (y <= 83)
				{
					sprintf(s, "Costs: %d gold", 10 * curinfo->cost10);
					DrawStrXor100(y + 12, s);
				}
			}
			drawinfobox(selected, start, end, istechnology);
			redraw = 0;
		}
		if ((a = dirkeys(k = nograyngetchx())))
		{
			if (selected != 255 && istechnology)
			{
				if (a >= 4)
				{
					switch(a)
					{
						case 4:
							a = 2;
							break;
						case 5:
							a = 11;
							break;
						//case 6:
						default:
							a = 127;
					};
					for(a--; a; a--)
					{
						if (selected == end2)
						{
							break;
						}
						else
						{
							b = (selected != cat1 + 1);
							if (b && selected != max1(cat1) + cat2 + 2)
							{
								selected++;
							}
							else if (b || cat2)
							{
								selected += 2;
							}
							else
							{
								selected += 4;
							}
						}
						redraw = 1;
					}
				}
				else
				{
					switch(a)
					{
						case 2:
							a = 10;
							break;
						// The following line must not read "default:"
						case 3:
						//default:
							a = 127;
					};
					for(d = 1; d <= a; d++)
					{
						if (selected == start)
						{
							break;
						}
						else
						{
							b = (selected != max1(cat1) + max1(cat2) + 4);
							if (selected != max1(cat1) + 3 && b)
							{
								selected--;
							}
							else if (b || cat2)
							{
								selected -= 2;
							}
							else
							{
								selected -= 4;
							}
						}
						redraw = 1;
					}
				}
			}
		}
		else if (k == 13)
		{
			if (selected != 255)
			{
				if (istechnology)
				{
					b = selected - (max1(cat1) + 3);
					if (selected <= cat1 + 1)
					{
						b = selected - start + 1;
						for(a = 0; b; a++)
						{
							c = sorts->asort[a];
							if (info[c].tech == index)
							{
								b--;
							}
						}
						index = c;
						istechnology = 0;
					}
					//else if (selected <= max(cat1, 1) + cat2 + 3)
					else if (b < cat2)
					{
						index = curtech->prereq[b];
					}
					else
					{
						b -= max(cat2, 1);
						for(a = 0; b; a++)
						{
							//curtech2 = tech + sorts->tsort[a];
							for(c = 0; c <= 2; c++)
							{
								e = tech[a].prereq[c];
								if (e == index)
								{
									b--;
								}
								else if (e == 255)
								{
									break;
								}
							}
						}
						index = a - 1;
					}
					redraw = 1;
				}
				else
				{
					index = curinfo->tech;
					redraw = istechnology = 1;
				}
				recalc = istechnology;
			}
		}
		else if (k == '+' || k == '-')
		{
			if ((recalc = istechnology))
			{
				a = index;
				if (k == '+')
				{
					index++;
				}
				else
				{
					index += nums->techs - 1;
				}
				index %= nums->techs;
			}
			else
			{
				for(a = 0; sorts->asort[a] != index; a++);
				if (k == '+')
				{
					a++;
				}
				else
				{
					a += nums->infos - 1;
				}
				index = sorts->asort[a % nums->infos];
			}
			redraw = 1;
		}
		else if ((a = keyletter(k)))
		{
			/*if ((recalc = istechnology))
			{
				b = nums->techs;
				g = sorts->tsort;
			}
			else
			{
				b = nums->infos;
				g = sorts->asort;
			}
			for(a = 0; g[a] != index; a++);*/
			if ((recalc = istechnology))
			{
				c = nums->techs;
			}
			else
			{
				c = nums->infos;
			}
			if (k == '+' || k == '-')
			{
				if (istechnology)
				{
					a = index;
					if (k == '+')
					{
						index++;
					}
					else
					{
						index += c - 1;
					}
					index %= c;
				}
				else
				{
					for(a = 0; sorts->asort[a] != index; a++);
					if (k == '+')
					{
						a++;
					}
					else
					{
						a += c - 1;
					}
					index = sorts->asort[a % c];
				}
			}
			else
			{
				b = 0;
				do
				{
					if (istechnology)
					{
						d = *(tech[index = b].id);
					}
					else
					{
						d = *(info[index = sorts->asort[b]].id);
					}
					b++;
				}
				while (a > tolower(d) && b < c);
			}
			redraw = 1;
		}
	}
	while (k != 264 && k != 4361);
	drawinfobox(selected, start, end, istechnology);
}

/*void copyinfo(struct UNITTYPE *info1, struct UNITTYPE *info2)
{
	strcpy(info1->id, info2->id);
	info1->turns10 = info2->turns10;
	info1->d = info2->d;
	info1->m = info2->m;
	info1->a = info2->a;
	info1->vsha5 = info2->vsha5;
	info1->buildmult10 = info2->buildmult10;
	info1->assist5 = info2->assist5;
	info1->canals = info2->canals;
	info1->tech = info2->tech;
	info1->br = info2->br;
	info1->cost10 = info2->cost10;
	info1->vsa5 = info2->vsa5;
	info1->mines = info2->mines;
	info1->trans = info2->trans;
	//info1->bribe = info2->bribe;
	info1->cau = info2->cau;
	info1->type = info2->type;
}

void copytech(struct TECH *tech1, struct TECH *tech2)
{
	char a;
	strcpy(tech1->id, tech2->id);
	for(a = 0; a <= 2; a++)
	{
		tech1->prereq[a] = tech2->prereq[a];
	}
	tech1->prod5 = tech2->prod5;
	tech1->sci5 = tech2->sci5;
	tech1->gold = tech2->gold;
	tech1->age = tech2->age;
	tech1->bridge = tech2->bridge;
}*/

// h and w are actually 1 less than the height and width of the rectangle, respectively
void setxyhw(char *x, char *y, char *h, char *w)
{
	char a;
	*h = 6;
	*w = 4;
	*y = 6 * (a = *y) + 10;
	switch(a)
	{
		case 0:
			*x = 0;
			*y = 1;
			*h = 8;
			*w = 98;
			break;
		case 1:
			if (*x == 6)
			{
				*x = 84;
				*y = 11;
				*h = *w = 9;
			}
			else
			{
				if (*x < 2)
				{
					*x = *x * 6 + 9;
				}
				else if (*x < 4)
				{
					*x = *x * 6 + 20;
				}
				else
				{
					*x = *x * 6 + 43;
				}
				*y = 11;
				*h = 8;
				*w = 6;
			}
			break;
		case 2:
			*x = 29;
			*w = 58;
			break;
		case 3:
			*x = 21;
			*w = 26;
			break;
		case 4:
			*x = 63 + ((*x) << 2) + ((*x == 2) << 1);
			break;
		case 5:
			if (*x != 2)
			{
				*x = 22 + ((*x) << 2);
			}
			else
			{
				*x = 83;
			}
			break;
		case 6:
			if (!*x)
			{
				*x = 27;
				*w = 11;
			}
			else
			{
				*x = 79 + 6 * *x;
				*w = 4;
			}
			break;
		case 7:
			if (*x <= 1)
			{
				*x = 24 + ((*x) << 2);
			}
			else
			{
				*x = 74 + ((*x) << 2);
			}
			break;
		case 8:
			*x = 45;
			break;
		case 9:
			*x = 26 + ((*x) << 2);
			break;
		case 10:
			*x = 42 + ((*x) << 2);
			break;
		case 11:
			*x = 72;
			*w = 11;
			break;
		case 12:
			*x = 37;
			*y = 83;
			*w = 24;
			*h = 8;
			break;
		default:
			*x = 32;
			*y = 91;
			*w = 35;
			*h = 8;
	};
}

char dmod(char olddigit, short k)
{
	if (isdigit(k))
	{
		return(k - '0');
	}
	if (k == '+')
	{
		return((olddigit + 1) % 10);
	}
	else
	{
		return((olddigit + 9) % 10);
	}
}

// Performs a case insensitive comparison between a and b
// Returns -1 if a < b, 0 if a = b, 1 else
char inscomp(const char *a, const char *b)
{
	short c;
	char d;
	c = 0;
	for(d = 0; !c; d++)
	{
		if (!a[d])
		{
			if (b[d])
			{
				return(-1);
			}
			else
			{
				return(0);
			}
		}
		else if (!b[d])
		{
			return(1);
		}
		c = tolower(a[d]) - tolower(b[d]);
	}
	return((c > 0) - (c < 0));
}

// Returns 1 for done, 0 for cancel
static inline char editunit(struct UNITTYPE *info, struct UNITTYPE *curinfo, char *sprite, struct TECH *tech, struct NUMS *nums, char allowbigchanges)
{
	// xs means x screen
	char a, b, x, y, ox, oy, digit, olddigit, redraw, xs, ys, h, w, s[25];
	short k;
	struct UNITTYPE newinfo;
	memcpy(&newinfo, curinfo, sizeof(struct UNITTYPE));
	redraw = 1;
	do
	{
		if (redraw)
		{
			setfont6x8();
			clearleft();
			DrawStrXor(2, 2, newinfo.id);
			swordshield(6, 12);
			sprintf(s, "%02d", newinfo.a);
			DrawStrXor(9, 12, s);
			sprintf(s, "%02d", newinfo.d);
			DrawStrXor(32, 12, s);
			sprintf(s, "MP:%02d", newinfo.m);
			DrawStrXor(49, 12, s);
			rectoutline(83, 10, 94, 21, A_NORMAL);
			Sprite8(85, 12, 8, sprite, LCD_MEM, SPRT_OR);
			setfont4x6();
			if (newinfo.tech != 63)
			{
				sprintf(s, "Prereq: %s", tech[newinfo.tech].id);
			}
			else
			{
				strcpy(s, "Prereq: (none)");
			}
			DrawStrXor1(23, s);
			strcpy(s, "Type: ");
			addtype(s, curinfo);
			DrawStrXor1(29, s);
			sprintf(s, "Turns to Produce: %02d.%d", newinfo.turns10 / 10, newinfo.turns10 % 10);
			DrawStrXor1(35, s);
			sprintf(s, "Costs: %03d", newinfo.cost10 * 10);
			DrawStrXor1(41, s);
			sprintf(s, "Transports: %d", newinfo.trans);
			DrawStrXor(42, 41, s);
			if (newinfo.canals)
			{
				strcpy(s, "Canals: Yes");
			}
			else
			{
				strcpy(s, "Canals: No");
			}
			DrawStrXor1(47, s);
			sprintf(s, "Build Speed: %d.%d", newinfo.buildmult10 / 10, newinfo.buildmult10 % 10);
			DrawStrXor(42, 47, s);
			sprintf(s, "Mines: %02d", newinfo.mines);
			DrawStrXor1(53, s);
			sprintf(s, "Assists City: %03d%%", newinfo.assist5 * 5);
			DrawStrXor(42, 53, s);
			sprintf(s, "Blast Radius: %d", newinfo.br);
			DrawStrXor1(59, s);
			sprintf(s, "Vs. Air: %03d%%", newinfo.vsa5 * 5);
			DrawStrXor1(65, s);
			sprintf(s, "Vs. High Air: %03d%%", newinfo.vsha5 * 5);
			DrawStrXor1(71, s);
			strcpy(s, "Destroyed After Use: ");
			if (newinfo.cau)
			{
				strcat(s, "Yes");
			}
			else
			{
				strcat(s, "No");
			}
			DrawStrXor1(77, s);
			setfont6x8();
			DrawStrXor(37, 84, "Done");
			DrawStrXor(32, 92, "Cancel");
			y = ys = 0;
			drawrect(0, 1, 98, 9);
			redraw = 0;
		}
		ox = xs = x;
		oy = ys = y;
		setxyhw(&xs, &ys, &h, &w);
		if (!y && allowbigchanges)
		{
			k = getstr(newinfo.id, 2, 2, 16, 58, 1);
		}
		else
		{
			k = nograyngetchx();
		}
		a = dirkeys2(k);
		if (a == 2)
		{
			if (y)
			{
				y--;
			}
			else
			{
				y = 13;
			}
			switch(y)
			{
				case 1:
					x = 2;
					break;
				case 4: case 8: case 9: case 10:
					x = 0;
					break;
				case 5: case 7:
					x = ((x != 0) << 1);
					break;
				case 6:
					x = (x != 0);
			};
		}
		else if (a == 4)
		{
			if (y < 13)
			{
				y++;
			}
			else
			{
				y = 0;
			}
			switch(y)
			{
				case 1: case 4: case 9: case 10:
					x = 0;
					break;
				case 5:
					x = 2;
					break;
				case 6:
					x = (x >= 2);
					break;
				case 7:
					x = ((x != 0) << 1);
			};
		}
		else if (a == 1)
		{
			if (x)
			{
				x--;
			}
		}
		else if (a)
		{
			switch(y)
			{
				case 1:
					a = 6;
					break;
				case 4: case 5: case 6: case 9: case 10:
					a = 2;
					break;
				case 7:
					a = 4;
					break;
				//case 0: case 2: case 3: case 11: case 12: case 13:
				default:
					a = 0;
			};
			if (x < a)
			{
				x++;
			}
		}
		else if (k == '+' || k == '-' || (isdigit(k) && y != 2) || (k == 13 && (y == 3 || y == 6 || y == 11)))
		{
			FontSetSys(y == 1);
			olddigit = digit = 0;
			switch(y)
			{
				case 1:
					if (x <= 5 && (x <= 1 || allowbigchanges))
					{
						if (x <= 3 || newinfo.type != bom)
						{
							switch(x)
							{
								case 0: case 1:
									b = newinfo.a;
									break;
								case 2: case 3:
									b = newinfo.d;
									break;
								default:
									b = newinfo.m;
							};
							switch(x)
							{
								case 0: case 2: case 4:
									olddigit = b / 10;
									b = 10 * (digit = dmod(olddigit, k)) + b % 10;
									break;
								default:
									olddigit = b % 10;
									b = 10 * (b / 10) + (digit = dmod(olddigit, k));
							};
							switch(x)
							{
								case 0: case 1:
									newinfo.a = b;
									break;
								case 2: case 3:
									newinfo.d = b;
									break;
								default:
									newinfo.m = b;
							};
						}	
					}
					break;
				case 2:
					if (nums->techs && allowbigchanges)
					{
						if (newinfo.tech != 63)
						{
							DrawStrXor(29, 23, tech[newinfo.tech].id);
							if (k == '+')
							{
								if (++newinfo.tech == nums->techs)
								{
									newinfo.tech = 63;
								}
							}
							else if (newinfo.tech)
							{
								newinfo.tech--;
							}
							else
							{
								newinfo.tech = 63;
							}
						}
						else
						{
							DrawStrXor(29, 23, "(none)");
							if (k == '+')
							{
								newinfo.tech = 0;
							}
							else
							{
								newinfo.tech = nums->techs - 1;
							}
						}
						if (newinfo.tech != 63)
						{
							DrawStrXor(29, 23, tech[newinfo.tech].id);
						}
						else
						{
							DrawStrXor(29, 23, "(none)");
						}
					}
					break;
				case 3:
					if (!isdigit(k) && allowbigchanges)
					{
						*s = 0;
						addtype(s, &newinfo);
						DrawStrXor(21, 29, s);
						if (k != '-')
						{
							newinfo.type = (newinfo.type + 1) % 6;
						}
						else
						{
							newinfo.type = (newinfo.type + 5) % 6;
						}
						*s = 0;
						addtype(s, &newinfo);
						DrawStrXor(21, 29, s);
						if (newinfo.type == bom)
						{
							newinfo.m = newinfo.trans = 0;
							DrawStr(83, 41, "0", A_REPLACE);
							setfont6x8();
							DrawStr(67, 12, "00", A_REPLACE);
						}
					}
					break;
				case 4:
					switch(x)
					{
						case 0:
							olddigit = newinfo.turns10 / 100;
							digit = dmod(olddigit, k);
							if (digit > 2 || (digit == 2 && newinfo.turns10 % 100 >= 50))
							{
								digit = 2;
								newinfo.turns10 = 249;
								DrawStr(67, 35, "4.9", A_REPLACE);
								DrawLineXor(67, 35, 67, 39);
							}
							else if (!(newinfo.turns10 = 100 * (unsigned char)digit + (newinfo.turns10 % 100)))
							{
								DrawChar(73, 35, '1', A_REPLACE);
								newinfo.turns10 = 1;
							}
							break;
						case 1:
							olddigit = (newinfo.turns10 % 100) / 10;
							if ((digit = dmod(olddigit, k)) >= 5 && newinfo.turns10 >= 200)
							{
								digit = 4;
							}
							if (!(newinfo.turns10 += 10 * (digit - olddigit)))
							{
								DrawChar(73, 35, '1', A_REPLACE);
								newinfo.turns10 = 1;
							}
							break;
						default:
							olddigit = (newinfo.turns10) % 10;
							digit = dmod(olddigit, k);
							if (!(newinfo.turns10 += digit - olddigit))
							{
								newinfo.turns10 = digit = 1;
							}
					};
					break;
				case 5:
					switch(x)
					{
						case 0:
							olddigit = newinfo.cost10 / 10;
							digit = dmod(olddigit, k);
							if (!(newinfo.cost10 = digit * 10 + newinfo.cost10 % 10))
							{
								DrawChar(26, 41, '1', A_REPLACE);
								DrawLineXor(26, 41, 26, 45);
								newinfo.cost10 = 1;
							}
							break;
						case 1:
							olddigit = newinfo.cost10 % 10;
							digit = dmod(olddigit, k);
							if (!(newinfo.cost10 += digit - olddigit))
							{
								digit = 1;
								newinfo.cost10 = 1;
							}
							break;
						default:
							if (newinfo.type != bom && allowbigchanges)
							{
								olddigit = newinfo.trans;
								newinfo.trans = digit = dmod(olddigit, k);
							}
					};
					break;
				case 6:
					if (allowbigchanges)
					{
						if (!x)
						{
							if (!isdigit(k))
							{
								olddigit = newinfo.canals + 10;
								digit = (newinfo.canals = !newinfo.canals) + 10;
								if (!newinfo.buildmult10 && newinfo.canals)
								{
									newinfo.buildmult10 = 10;
									DrawStr(85, 47, "1.0", A_REPLACE);
								}
							}
							break;
						}
						else
						{
							switch(x)
							{
								case 1:
									olddigit = newinfo.buildmult10 / 10;
									digit = dmod(olddigit, k);
									newinfo.buildmult10 = 10 * digit + (newinfo.buildmult10 % 10);
									break;
								default:
									olddigit = newinfo.buildmult10 % 10;
									digit = dmod(olddigit, k);
									newinfo.buildmult10 = 10 * (newinfo.buildmult10 / 10) + digit;
							};
							if (!newinfo.buildmult10)
							{
								newinfo.canals = 0;
								DrawStr(27, 47, "No ", A_REPLACE);
							}
						}
					}
					break;
				case 7:
					if (x >= 2 || allowbigchanges)
					{
						switch(x)
						{
							case 0:
								olddigit = newinfo.mines / 10;
								digit = dmod(olddigit, k);
								newinfo.mines = 10 * digit + (newinfo.mines % 10);
								break;
							// The following line must not read "default:"
							case 1:
								olddigit = newinfo.mines % 10;
								digit = dmod(olddigit, k);
								newinfo.mines = 10 * (newinfo.mines / 10) + digit;
								break;
							case 2:
								olddigit = newinfo.assist5 / 20;
								digit = min(dmod(olddigit, k), 2);
								newinfo.assist5 = 20 * digit + newinfo.assist5 % 20;
								break;
							case 3:
								olddigit = ((newinfo.assist5 % 20) >> 1);
								digit = dmod(olddigit, k);
								newinfo.assist5 += ((digit - olddigit) << 1);
								break;
							case 4:
								digit = olddigit = 5 * (newinfo.assist5 % 2);
								if (k == '+' || k == '-')
								{
									digit = 5 - olddigit;
								}
								else if (k == '0' || k == '5')
								{
									digit = k - '0';
								}
								newinfo.assist5 += (digit - olddigit) / 5;
								break;
						};
					}
					break;
				case 8:
					//if (x)
					//{
						olddigit = newinfo.br;
						newinfo.br = digit = dmod(olddigit, k);
					/*}
					else
					{
						olddigit = newinfo.bribe + 10;
						if (!isdigit(k))
						{
							digit = (newinfo.bribe = !newinfo.bribe) + 10;
						}
					}*/
					break;
				case 9: case 10:
					if (y == 9)
					{
						b = newinfo.vsa5;
					}
					else
					{
						b = newinfo.vsha5;
					}
					switch(x)
					{
						case 0:
							olddigit = b / 20;
							if (k == '+' || (isdigit(k) && k != '0'))
							{
								b = 20;
								digit = 1;
								if (y == 9)
								{
									DrawStr(30, 65, "00", A_REPLACE);
									DrawLineXor(30, 65, 30, 69);
								}
								else
								{
									DrawStr(46, 71, "00", A_REPLACE);
									DrawLineXor(46, 71, 46, 75);
								}
							}
							else //if (k == '-' || k == '0')
							{
								digit = 0;
								b %= 20;
							}
							break;
						case 1:
							if (b != 20)
							{
								olddigit = (b >> 1);
								digit = dmod(olddigit, k);
								b = (digit << 1) + b % 2;
							}
							else
							{
								digit = olddigit = 0;
							}
							break;
						default:
							digit = olddigit = 5 * (b % 2);
							if (b < 20)
							{
								if (k == '+' || k == '-')
								{
									digit = 5 - olddigit;
								}
								else if (k == '0' || k == '5')
								{
									digit = k - '0';
								}
								b += (digit - olddigit) / 5;
							}
							break;
					};
					if (y == 9)
					{
						newinfo.vsa5 = b;
					}
					else
					{
						newinfo.vsha5 = b;
					}
					break;
				case 11:
					if (!isdigit(k))
					{
						olddigit = newinfo.cau + 10;
						digit = (newinfo.cau = !newinfo.cau) + 10;
					}
					break;
			};
			if (digit != olddigit)
			{
				if (olddigit < 10)
				{
					DrawCharXor(xs, ys + 1, olddigit + '0');
					DrawCharXor(xs, ys + 1, digit + '0');
				}
				else
				{
					DrawStrXor(xs, ys + 1, "Yes");
					DrawStrXor(xs, ys + 1, "No");
				}
			}
		}
		else if (k == 13)
		{
			if (y == 12)
			{
				if (!*(newinfo.id))
				{
					y = 0;
				}
				else
				{
					for(a = 0; a < nums->infos; a++)
					{
						if (!inscomp(newinfo.id, info[a].id) && curinfo != info + a)
						{
							y = 0;
							break;
						}
					}
				}
			}
			else if (y == 1 && x == 6)
			{
				editsprite(sprite);
				redraw = 1;
			}
		}
		else if (k == 264)
		{
			y = 12;
		}
		else if (y == 2 && allowbigchanges)
		{
			setfont4x6();
			if (k == 257 || k == 263)
			{
				// Backspace and Clear
				if (newinfo.tech != 63)
				{
					DrawStrXor(29, 23, tech[newinfo.tech].id);
					DrawStrXor(29, 23, "(none)");
					newinfo.tech = 63;
				}
			}
			else if ((a = keyletter(k)))
			{
				if (nums->techs)
				{
					if (newinfo.tech != 63)
					{
						DrawStrXor(29, 23, tech[newinfo.tech].id);
					}
					else
					{
						DrawStrXor(29, 23, "(none)");
					}
					newinfo.tech = 0;
					while (a > tolower(*(tech[newinfo.tech++].id)) && newinfo.tech < nums->techs);
					DrawStrXor(29, 23, tech[--newinfo.tech].id);
				}
			}
		}
		if (x != ox || y != oy)
		{
			drawrect(xs, ys, xs + w, ys + h);
			xs = x;
			ys = y;
			setxyhw(&xs, &ys, &h, &w);
			drawrect(xs, ys, xs + w, ys + h);
		}
	}
	while (k != 13 || y < 12);
	if (y == 12)
	{
		memcpy(curinfo, &newinfo, sizeof(struct UNITTYPE));
	}
	return(y == 12);
}

void addage(char *s, struct TECH *tech)
{
	switch(tech->age)
	{
		case 0:
			strcat(s, "Ancient");
			break;
		case 1:
			strcat(s, "Basic");
			break;
		case 2:
			strcat(s, "Industrial");
			break;
		default:
			strcat(s, "Modern");
			break;
	}
}

// Returns 1 for done, 0 for cancel
static inline char edittech(struct TECH *curtech, struct TECH *tech, struct NUMS *nums)
{
	// xs means x screen
	char d, f, g, x, y, ox, oy, xs, ys, w, digit, olddigit, redraw, s[17];
	unsigned char a, c, e;
	short b;
	short k;
	struct TECH newtech;
	memcpy(&newtech, curtech, sizeof(struct TECH));
	redraw = 1;
	do
	{
		if (redraw)
		{
			clearleft();
			setfont6x8();
			DrawStrXor(2, 1, newtech.id);
			for(a = 0; a <= 2; a++)
			{
				if (newtech.prereq[a] != 255)
				{
					DrawStrXor1(15 + (a << 3), tech[newtech.prereq[a]].id);
				}
				else
				{
					DrawStrXor1(15 + (a << 3), "(none)");
				}
			}
			strcpy(s, "Age: ");
			addage(s, &newtech);
			DrawStrXor1(42, s);
			sprintf(s, "Production: +%02d%%", 5 * newtech.prod5);
			DrawStrXor1(50, s);
			sprintf(s, "Science: +%02d%%", 5 * newtech.sci5);
			DrawStrXor1(58, s);
			sprintf(s, "Revenue: +%02d", newtech.gold);
			DrawStrXor1(66, s);
			strcpy(s, "Bridges: ");
			if (newtech.bridge)
			{
				strcat(s, "Yes");
			}
			else
			{
				strcat(s, "No");
			}
			DrawStrXor1(74, s);
			DrawStrXor(37, 83, "Done");
			DrawStrXor(32, 92, "Cancel");
			setfont4x6();
			DrawStrXor(26, 9, "Prerequisites:");
			drawrect(xs = redraw = 0, ys = 0, w = 98, 8);
			y = -1;
		}
		ox = x;
		oy = y;
		setfont6x8();
		if (y == -1)
		{
			k = getstr(newtech.id, 2, 1, 16, 58, 1);
		}
		else
		{
			k = nograyngetchx();
		}
		if (k == KEY_UP)
		{
			x = 0;
			y = ((y + 11) % 11) - 1;
		}
		else if (k == KEY_DOWN)
		{
			x = 0;
			y = ((y + 2) % 11) - 1;
		}
		else if (k == KEY_LEFT)
		{
			if (x)
			{
				x--;
			}
		}
		else if (k == KEY_RIGHT)
		{
			if (y >= 4 && y <= 6 && !x)
			{
				x = 1;
			}
		}
		else if (k == 264)
		{
			y = 8;
		}
		else
		{
			if (k != '+' && k != '-')
			{
				f = keyletter(k);
			}
			else
			{
				f = 0;
			}
			if (k == '+' || k == '-' || (isdigit(k) && y >= 4 && y <= 6) || (k == 13 && (y == 3 || y == 7)) || ((f || k == 257 || k == 263) && y <= 2))
			{
				digit = olddigit = 0;
				switch(y)
				{
					case 0: case 1: case 2:
						if (nums->techs)
						{
							a = newtech.prereq[y];
							if (k != 257 && k != 263)
							{
								if (k == '+')
								{
									b = 1;
									c = 0;
								}
								else
								{
									b = -1;
									c = nums->techs - 1;
								}
								if ((g = (!f && a != 255)))
								{
									c = a;
								}
								else
								{
									e = 255;
								}
								do
								{
									do
									{
										if (g)
										{
											if ((!c && k != '+') || (c + 1 == nums->techs && k == '+'))
											{
												c = 255;
												break;
											}
											c += b;
										}
										else
										{
											g = 1;
										}
										for(d = 0; d <= 2; d++)
										{
											if (d != y && newtech.prereq[d] == c)
											{
												break;
											}
										}
										if (d == 3 && tech + c != curtech)
										{
											break;
										}
									}
									while (c != a);
									g = 0;
									if (f && c != 255)
									{
										if (f <= tolower(*(tech[c].id)))
										{
											e = c;
											g = 1;
										}
									}
								}
								while (g);
								if (f && e != 255)
								{
									c = e;
								}
							}
							else
							{
								c = 255;
							}
							
							if (c != a)
							{
								if (c > a)
								{
									d = 1;
								}
								else
								{
									d = -1;
								}
								do
								{
									a = newtech.prereq[y];
									if (a != 255)
									{
										DrawStrXor1((y << 3) + 15, tech[a].id);
									}
									else
									{
										DrawStrXor1((y << 3) + 15, "(none)");
									}
									if ((e = (y + d >= 0 && y + d <= 2)))
									{
										b = c - newtech.prereq[y + d];
										e = (((b > 0) ^ (d == -1)) && b);
									}
									if (e)
									{
										newtech.prereq[y] = newtech.prereq[y + d];
									}
									else
									{
										newtech.prereq[y] = c;
									}
									if (newtech.prereq[y] != 255)
									{
										DrawStrXor1((y << 3) + 15, tech[newtech.prereq[y]].id);
									}
									else
									{
										DrawStrXor1((y << 3) + 15, "(none)");
									}
									if (e)
									{
										y += d;
									}
								}
								while (e);
							}
						}
						break;
					case 3:
						*s = 0;
						addage(s, &newtech);
						DrawStrXor(31, 42, s);
						if (k != '-')
						{
							newtech.age = (newtech.age + 1) % 4;
						}
						else
						{
							newtech.age = (newtech.age + 3) % 4;
						}
						*s = 0;
						addage(s, &newtech);
						DrawStrXor(31, 42, s);
						break;
					case 4:
						if (x)
						{
							digit = olddigit = 5 * (newtech.prod5 % 2);
							if (k == '0' || k == '5')
							{
								digit = k - '0';
							}
							else if (k == '+' || k == '-')
							{
								digit = 5 - olddigit;
							}
							newtech.prod5 += ((digit - olddigit) / 5);
						}
						else
						{
							olddigit = newtech.prod5 / 2;
							digit = dmod(olddigit, k);
							newtech.prod5 += ((digit - olddigit) << 1);
						}
						break;
					case 5:
						if (x)
						{
							digit = olddigit = 5 * (newtech.sci5 % 2);
							if (k == '0' || k == '5')
							{
								digit = k - '0';
							}
							else if (k == '+' || k == '-')
							{
								digit = 5 - olddigit;
							}
							newtech.sci5 += ((digit - olddigit) / 5);
						}
						else
						{
							olddigit = newtech.sci5 / 2;
							digit = dmod(olddigit, k);
							newtech.sci5 += ((digit - olddigit) << 1);
						}
						break;
					case 6:
						if (x)
						{
							olddigit = newtech.gold % 10;
							digit = dmod(olddigit, k);
							newtech.gold += (digit - olddigit);
						}
						else
						{
							olddigit = newtech.gold / 10;
							digit = dmod(olddigit, k);
							newtech.gold += (10 * (digit - olddigit));
						}
						break;
					case 7:
						newtech.bridge = !newtech.bridge;
						DrawStrXor(55, 74, "Yes");
						DrawStrXor(55, 74, "No");
						break;
				};
				if (olddigit != digit)
				{
					DrawCharXor(xs, ys + 1, olddigit + '0');
					DrawCharXor(xs, ys + 1, digit + '0');
				}
			}
			else if (k == 13 && y == 8)
			{
				if (!*(newtech.id))
				{
					y = -1;
				}
				else
				{
					for(a = 0; a < nums->techs; a++)
					{
						if (!inscomp(newtech.id, tech[a].id) && curtech != tech + a)
						{
							y = -1;
							break;
						}
					}
				}
			}
		}
		if (x != ox || y != oy)
		{
			drawrect(xs, ys, xs + w, ys + 8);
			switch(y)
			{
				case -1:
					xs = 0;
					ys = 0;
					w = 98;
					break;
				case 3:
					xs = 31;
					ys = 41;
					w = 60;
					break;
				case 4:
					xs = 79 + 6 * x;
					ys = 49;
					w = 6;
					break;
				case 5: case 6:
					xs = 61 + 6 * x;
					ys = 17 + (y << 3);
					w = 6;
					break;
				case 7:
					xs = 55;
					ys = 73;
					w = 18;
					break;
				case 8:
					xs = 37;
					ys = 82;
					w = 24;
					break;
				case 9:
					xs = 32;
					ys = 91;
					w = 35;
					break;
				//case 0: case 1: case 2:
				default:
					xs = 0;
					ys = 14 + (y << 3);
					w = 98;
			};
			drawrect(xs, ys, xs + w, ys + 8);
		}
	}
	while (k != 13 || y < 8);
	if (y == 8)
	{
		memcpy(curtech, &newtech, sizeof(struct TECH));
	}
	return(y == 8);
}

char f1f2()
{
	short k;
	do
	{
		k = nograyngetchx();
	}
	while (k != 268 && k != 269);
	return(k == 268);
}

void trydeleteinfo(struct NUMS *nums, struct UNITTYPE **info, struct SORTS *sorts, char index)
{
	short a;
	char b;
	clearleft();
	setfont6x8();
	DrawStrXor1(1, "Confirm deleting");
	DrawStrXor1(10, (*info)[index].id);
	DrawStrXor1(33, "F1: Confirm");
	DrawStrXor1(42, "F2: Cancel");
	if (f1f2())
	{
		nums->infos--;
		for(b = index; b < nums->infos; b++)
		{
			memcpy(*info + b, *info + b + 1, sizeof(struct UNITTYPE));
		}
		*info = (struct UNITTYPE *)realloc_throw(*info, nums->infos * sizeof(struct UNITTYPE));
		for(b = 0; sorts->asort[b] != index; b++);
		while(b < nums->infos)
		{
			sorts->asort[b] = sorts->asort[b + 1];
			b++;
		}
		for(b = 0; b < nums->infos; b++)
		{
			if (sorts->asort[b] > index)
			{
				sorts->asort[b]--;
			}
		}
		sorts->asort = (unsigned char *)realloc_throw(sorts->asort, nums->infos);
		for(b = 0; sorts->csort[b] != index; b++);
		while(b < nums->infos)
		{
			sorts->csort[b] = sorts->csort[b + 1];
			b++;
		}
		for(b = 0; b < nums->infos; b++)
		{
			if (sorts->csort[b] > index)
			{
				sorts->csort[b]--;
			}
		}
		sorts->csort = (unsigned char *)realloc_throw(sorts->csort, nums->infos);
		for(a = (index + 6) << 3; a < (nums->infos + 6) << 3; a += 8)
		{
			memcpy(sprites + a, sprites + a + 8, 8);
		}
		sprites = (unsigned char *)realloc_throw(sprites, (nums->infos + 6) << 3);
	}
}

void highlight2(char a)
{
	switch(a)
	{
		case 0:
			drawrect(31, 38, 129, 48);
			break;
		case 1:
			drawrect(67, 58, 93, 68);
			break;
		default:
			drawrect(19, 78, 141, 88);
	};
}

void copysprites()
{
	sprites = (unsigned char *)malloc_throw(48);
	memcpy(sprites, (unsigned char[]){0xFF,0xFF,0x57,0xAF,0xFF,0xFF,0xD5,0xEB,0x7C,0x54,0x7C,0x54,0x7C,0x54,0x7C,0x00,0xF8,0xA8,0xF8,0xAB,0xFB,0xAA,0xFA,0x02,0x20,0x20,0x20,0x20,0x20,0xFF,0x20,0x20,0x02,0x14,0xA9,0x46,0x02,0x04,0x08,0x04,0x00,0x18,0x3C,0x7E,0x7E,0x7E,0x7E,0x00}, 48);
}

void highlight6(char a)
{
	switch(a)
	{
		case 0:
			drawrect(70, 38, 90, 48);
			break;
		case 1:
			drawrect(67, 58, 93, 68);
			break;
		default:
			drawrect(61, 78, 99, 88);
	};
}

char editscen()
{
	// viewmode: 0 = technologies, 1 = units, 2 = sprites
	char c, d, f, g, h, s[107], viewmode, start, prevstart, end, selected, prevselected, scenname[21], allowbigchanges;
	unsigned char e, *pre, newsprite[8];
	short a, b, k;
	unsigned short code2[8];
	struct SORTS sorts;
	struct NUMS nums;
	struct TECH *tech, *curtech, newtech;
	struct UNITTYPE *info, newinfo, *newinfo2;
	FILE *input;
	sorts.csort = sorts.asort = NULL;
	sprites = NULL;
	info = NULL;
	tech = NULL;
	/*do
	{*/
		b = -1;
		do
		{
			FontSetSys(F_8x10);
			ClrScr();
			centertext("Scenario Editor", 8);
			setfont6x8();
			DrawStrXor(71, 40, "New");
			DrawStrXor(68, 60, "Load");
			DrawStrXor(62, 80, "Update");
			highlight6(a = 0);
			do
			{
				c = a;
				k = nograyngetchx();
				if (k == KEY_UP)
				{
					a = (a + 2) % 3;
				}
				else if (k == KEY_DOWN)
				{
					a = (a + 1) % 3;
				}
				if (c != a)
				{
					highlight6(c);
					highlight6(a);
				}
			}
			while (k != 13 && k != 264);
			if (a && k == 13)
			{
				b = askwhichdata(1, 0);
				if (b == -1)
				{
					k = 0;
				}
			}
		}
		while (k != 13 && k != 264);
		if (b >= 0)
		{
			if (!loadscen(b, &tech, &info, scenname, &nums, &sorts))
			{
				error(3);
				return(0);
			}
			allowbigchanges = 2 - a;
		}
		else if (k != 264)
		{
			*scenname = 0;
			/*FontSetSys(F_8x10);
			ClrScr();
			centertext("Enter scenario name:", 20);
			do
			{
				if (!getstr(scenname, 50, 20, keys, 0))
				{
					b = 1;
				}
			}
			while (!b && !*scenname);
			if (!b)
			{*/
				nums.infos = 0;
				nums.techs = 0;
				copysprites();
			//}
			allowbigchanges = 1;
		}
		else
		{
			return(1);
		}
	/*}
	while (b);*/
	ClrScr();
	DrawLineXor(99, 0, 99, 99);
	viewmode = !allowbigchanges;
	a = 0;
	do
	{
		if (viewmode <= 1)
		{
			// Technologies and units
			prevstart = 127;
			if (viewmode)
			{
				end = nums.infos;
			}
			else
			{
				end = nums.techs;
			}
			start = selected = 0;
			do
			{
				if (start != prevstart)
				{
					clearleft();
					setfont6x8();
					if (start + 7 + !start < end)
					{
						DrawCharXor(1, 76, DOWNCHAR);
						c = 7;
					}
					else
					{
						c = 8;
					}
					if (start)
					{
						DrawCharXor(1, 4, UPCHAR);
					}
					else if (viewmode)
					{
						DrawStrXor1(4, "(new unit)");
					}
					else
					{
						DrawStrXor1(4, "(new technology)");
					}
					c = min(c, end + (start != 0) - start);
					for(a = 1; a <= c; a++)
					{
						b = a + start - ((start != 0) + 1);
						if (viewmode)
						{
							DrawStrXor1(a * 9 + 4, info[sorts.asort[b]].id);
						}
						else
						{
							DrawStrXor1(a * 9 + 4, tech[b].id);
						}
					}
					drawfs();
				}
				else if (prevselected != selected)
				{
					a = 9 * (prevselected + (start != 0));
					drawrect(0, a + 3, 98, a + 11);
				}
				if (prevselected != selected || prevstart != start)
				{
					a = 9 * (selected + (start != 0));
					drawrect(0, a + 3, 98, a + 11);
				}
				prevselected = selected;
				prevstart = start;
				a = dirkeys(k = nograyngetchx());
				if (a >= 4)
				{
					switch(a)
					{
						case 4:
							a = 2;
							break;
						case 5:
							a = 8;
							break;
						default:
							a = 127;
					};
					for(a--; a; a--)
					{
						if (selected + start == end)
						{
							break;
						}
						else if (selected == 6 + !start && selected + start + 1 != end)
						{
							if (!start++)
							{
								start++;
								selected--;
							}
						}
						else
						{
							selected++;
						}
					}
				}
				else if (a)
				{
					switch(a)
					{
						case 2:
							a = 7;
							break;
						// The following line must not be "default:"
						case 3:
							a = 127;
					};
					for(b = 1; b <= a; b++)
					{
						if (!selected && !start)
						{
							break;
						}
						else
						{
							if (!selected)
							{
								if (start != 2)
								{
									start--;
								}
								else
								{
									start = 0;
									selected = 1;
								}
							}
							else
							{
								selected--;
							}
						}
					}
				}
				else if ((a = keyletter(k)))
				{
					for(start = 1; start < end; start++)
					{
						if (viewmode)
						{
							b = *(info[sorts.asort[start - 1]].id);
						}
						else
						{
							b = *(tech[start - 1].id);
						}
						if (tolower(b) >= a)
						{
							break;
						}
					}
					if (end <= 8)
					{
						selected = start;
						start = 0;
					}
					else if ((selected = max(start + 7 - end, 0)))
					{
						start = end - 7;
					}
					if (start + selected > end)
					{
						start = end - selected;
					}
					else if (start == 1)
					{
						start = 0;
						selected = 1;
					}
				}
				else if (k == 268)
				{
					if (selected || start)
					{
						a = 9 * (selected + (start != 0)) + 3;
						drawrect(0, a, 98, a + 8);
						if (viewmode)
						{
							infotbar(tech, info, &nums, &sorts, 0, sorts.asort[start + selected - 1]);
						}
						else
						{
							infotbar(tech, info, &nums, &sorts, 1, start + selected - 1);
						}
						drawrect(0, a, 98, a + 8);
					}
				}
				else if (k >= 269 && k <= 271)
				{
					a = k - 269;
					if (a != viewmode && (a || allowbigchanges))
					{
						viewmode = a;
						a = k = 0;
					}
				}
				else if (k == 257)
				{
					// Backspace
					if ((selected || start) && allowbigchanges)
					{
						if (viewmode)
						{
							trydeleteinfo(&nums, &info, &sorts, sorts.asort[start + selected - 1]);
						}
						else
						{
							clearleft();
							setfont6x8();
							DrawStrXor1(1, "Confirm deleting");
							DrawStrXor1(10, tech[a = start + selected - 1].id);
							DrawStrXor1(33, "F1: Confirm");
							DrawStrXor1(42, "F2: Cancel");
							if (f1f2())
							{
								for(b = a; b + 1 < nums.techs; b++)
								{
									memcpy(tech + b, tech + b + 1, sizeof(struct TECH));
								}
								tech = (struct TECH *)realloc_throw(tech, --nums.techs * sizeof(struct TECH));
								for(b = 0; b < nums.techs; b++)
								{
									pre = tech[b].prereq;
									for(c = 0; c <= 2; c++)
									{
										if (pre[c] == 255)
										{
											break;
										}
										else if (pre[c] == a)
										{
											for(c++; c <= 2; c++)
											{
												if (pre[c] == 255)
												{
													break;
												}
												else
												{
													pre[c - 1] = pre[c] - 1;
												}
											}
											pre[c - 1] = 255;
										}
										else if (pre[c] > a)
										{
											pre[c]--;
										}
									}
								}
								newinfo2 = info;
								for(b = 0; b < nums.infos; b++)
								{
									if (info[b].tech == a)
									{
										info[b].tech = 63;
									}
									else if (info[b].tech > a && info[b].tech != 63)
									{
										info[b].tech--;
									}
								}
							}
						}
						k = 0;
					}
				}
				else if (k == 13)
				{
					if (start || selected || allowbigchanges)
					{
						if (viewmode)
						{
							if (start || selected)
							{
								a = sorts.asort[d = start + selected - 1];
								if ((b = editunit(info, newinfo2 = info + a, sprites + ((a + 6) << 3), tech, &nums, allowbigchanges)))
								{
									for(c = d; c + 1 < nums.infos; c++)
									{
										sorts.asort[c] = sorts.asort[c + 1];
									}
									for(c = 0; sorts.csort[c] != a; c++);
									while(c + 1 < nums.infos)
									{
										sorts.csort[c] = sorts.csort[c + 1];
										c++;
									}
								}
							}
							else if (nums.infos < 84)
							{
								newinfo.type = newinfo.d = newinfo.m = newinfo.a = newinfo.vsha5 = newinfo.buildmult10 = newinfo.assist5 = newinfo.canals = newinfo.br = newinfo.vsa5 = newinfo.mines = newinfo.trans = newinfo.cau = *(newinfo.id) = 0;
								newinfo.tech = 63;
								newinfo.cost10 = 10;
								newinfo.turns10 = 50;
								for(a = 0; a <= 7; a++)
								{
									newsprite[a] = 0;
								}
								if ((b = editunit(info, &newinfo, newsprite, tech, &nums, allowbigchanges)))
								{
									a = nums.infos;
									info = (struct UNITTYPE *)realloc_throw(info, ++nums.infos * sizeof(struct UNITTYPE));
									memcpy(newinfo2 = info + a, &newinfo, sizeof(struct UNITTYPE));
									sprites = (unsigned char *)realloc_throw(sprites, (a + 7) << 3);
									memcpy(sprites + ((a + 6) << 3), newsprite, 8);
									/*for(c = 0; c <= 7; c++)
									{
										sprites[c + ((a + 6) << 3)] = newsprite[c];
									}*/
									sorts.asort = (unsigned char *)realloc_throw(sorts.asort, nums.infos);
									sorts.csort = (unsigned char *)realloc_throw(sorts.csort, nums.infos);
								}
							}
							else
							{
								clearleft();
								setfont6x8();
								DrawStrXor1(1, "Unit limit");
								DrawStrXor1(10, "reached. You");
								DrawStrXor1(19, "can't add any");
								DrawStrXor1(28, "more.");
								setfont4x6();
								DrawStrXor(9, 91, "Press ENTER to continue");
								b = 0;
								while (nograyngetchx() != 13);
							}
							if (b)
							{
								for(c = 0; c + 1 < nums.infos && inscomp(newinfo2->id, info[sorts.asort[c]].id) >= 0; c++);
								for(b = nums.infos - 2; b >= c; b--)
								{
									sorts.asort[b + 1] = sorts.asort[b];
								}
								sorts.asort[c] = a;
								for(c = 0; c + 1 < nums.infos && newinfo2->cost10 >= info[sorts.csort[c]].cost10; c++);
								for(b = nums.infos - 2; b >= c; b--)
								{
									sorts.csort[b + 1] = sorts.csort[b];
								}
								sorts.csort[c] = a;
							}
						}
						else
						{
							if (start || selected)
							{
								a = start + selected - 1;
								if ((b = edittech(tech + a, tech, &nums)))
								{
									memcpy(&newtech, tech + a, sizeof(struct TECH));
								}
							}
							else if (nums.techs < 63)
							{
								*(newtech.id) = newtech.age = newtech.prod5 = newtech.sci5 = newtech.gold = newtech.bridge = 0;
								for(b = 0; b <= 2; b++)
								{
									newtech.prereq[b] = 255;
								}
								if ((b = edittech(&newtech, tech, &nums)))
								{
									a = nums.techs++;
									tech = (struct TECH *)realloc_throw(tech, nums.techs * sizeof(struct TECH));
								}
							}
							else
							{
								clearleft();
								setfont6x8();
								DrawStrXor1(1, "Technology limit");
								DrawStrXor1(10, "reached. You");
								DrawStrXor1(19, "can't add any");
								DrawStrXor1(28, "more.");
								setfont4x6();
								DrawStrXor(9, 91, "Press ENTER to continue");
								b = 0;
								while (nograyngetchx() != 13);
							}
							if (b)
							{
								for(b = !a; b < nums.techs; b++)
								{
									if (a != b && inscomp(newtech.id, tech[b].id) < 0)
									{
										break;
									}
								}
								if (b < a)
								{
									for(c = a - 1; c >= b; c--)
									{
										memcpy(tech + c + 1, tech + c, sizeof(struct TECH));
									}
								}
								else
								{
									b--;
									for(c = a; c < b; c++)
									{
										memcpy(tech + c, tech + c + 1, sizeof(struct TECH));
									}
								}
								memcpy(tech + b, &newtech, sizeof(struct TECH));
								for(d = 0; d < nums.techs; d++)
								{
									pre = tech[d].prereq;
									for(c = 0; c <= 2; c++)
									{
										e = pre[c];
										if (e == 255)
										{
											break;
										}
										else if (e == a)
										{
											pre[c] = b;
											for(f = c - 1; f >= 0; f--)
											{
												if (pre[f] > b)
												{
													pre[f + 1] = pre[f];
													pre[f] = b;
												}
												else
												{
													break;
												}
											}
											for(f = c + 1; f <= 2; f++)
											{
												if (pre[f] <= b)
												{
													pre[f - 1] = pre[f] - 1;
													pre[f] = b;
													c = f;
												}
											}
										}
										else if ((e > min(a, b) && e < max(a, b)) || e == b)
										{
											if (b < a)
											{
												pre[c]++;
											}
											else
											{
												pre[c]--;
											}
										}
									}
								}
								for(d = 0; d < nums.infos; d++)
								{
									e = info[d].tech;
									if (e == a)
									{
										info[d].tech = b;
									}
									else if ((e > min(a, b) && e < max(a, b)) || e == b)
									{
										if (b < a)
										{
											info[d].tech++;
										}
										else
										{
											info[d].tech--;
										}
									}
								}
							}
						}
						k = 0;
					}
				}
			}
			while (k && k != 264);
		}
		else
		{
			// Sprites
			clearleft();
			for(b = 0; b < nums.infos; b++)
			{
				Sprite8(9 * (b % 10) + 5, 9 * (b / 10) + 1, 8, sprites + ((b + 6) << 3), LCD_MEM, SPRT_OR);
			}
			for(b = 84; b <= 89; b++)
			{
				Sprite8(9 * (b % 10) + 5, 9 * (b / 10) + 1, 8, sprites + ((b - 84) << 3), LCD_MEM, SPRT_OR);
			}
			drawfs();
			spriteselect(info, &nums, a);
			do
			{
				b = a;
				k = nograyngetchx();
				c = dirkeys2(k);
				if (c == 1)
				{
					if (a % 10)
					{
						a--;
					}
					else
					{
						a += 9;
					}
				}
				else if (c == 3)
				{
					if (a % 10 < 9)
					{
						a++;
					}
					else
					{
						a -= 9;
					}
				}
				else if (c == 2)
				{
					if (a >= 10)
					{
						a -= 10;
					}
					else
					{
						a += 80;
					}
				}
				else if (c)
				{
					if (a < 80)
					{
						a += 10;
					}
					else
					{
						a -= 80;
					}
				}
				else if (k == 13)
				{
					if (a < 84)
					{
						if (a < nums.infos)
						{
							editsprite(sprites + ((a + 6) << 3));
							k = 0;
						}
					}
					else
					{
						editsprite(sprites + ((a - 84) << 3));
						k = 0;
					}
				}
				else if (k == 268)
				{
					if (a < nums.infos)
					{
						spriteselect(info, &nums, a);
						infotbar(tech, info, &nums, &sorts, 0, a);
						spriteselect(info, &nums, a);
					}
				}
				else if (k == 269 || k == 270)
				{
					if (k != 269 || allowbigchanges)
					{
						viewmode = k - 269;
						k = 0;
					}
				}
				else if (allowbigchanges)
				{
					if (k == 257)
					{
						// Backspace
						if (a < nums.infos)
						{
							trydeleteinfo(&nums, &info, &sorts, a);
							k = 0;
						}
					}
					else if (k == '+' || k == '-')
					{
						if (k == '+')
						{
							c = 1;
						}
						else
						{
							c = -1;
						}
						if (a + c >= 0 && a + c < nums.infos)
						{
							memcpy(&newinfo, info + a, sizeof(struct UNITTYPE));
							memcpy(info + a, info + a + c, sizeof(struct UNITTYPE));
							memcpy(info + a + c, &newinfo, sizeof(struct UNITTYPE));
							for(b = 0; b < nums.infos; b++)
							{
								if (sorts.asort[b] == a)
								{
									sorts.asort[b] = a + c;
								}
								else if (sorts.asort[b] == a + c)
								{
									sorts.asort[b] = a;
								}
								if (sorts.csort[b] == a)
								{
									sorts.csort[b] = a + c;
								}
								else if (sorts.csort[b] == a + c)
								{
									sorts.csort[b] = a;
								}
							}
							k = (a + min(c, 0) + 6) << 3;
							memcpy(newsprite, sprites + k, 8);
							memcpy(sprites + k, sprites + k + 8, 8);
							memcpy(sprites + k + 8, newsprite, 8);
							/*for(b = k; b <= k + 7; b++)
							{
								e = sprites[b];
								sprites[b] = sprites[b + 8];
								sprites[b + 8] = e;
							}*/
							a += c;
							k = 0;
						}
					}
				}
				if (a != b && k && k != 264)
				{
					spriteselect(info, &nums, b);
					spriteselect(info, &nums, a);
				}
			}
			while (k && k != 264);
		}
		if (k == 264)
		{
			a = h = 0;
			do
			{
				FontSetSys(F_8x10);
				ClrScr();
				centertext("Scenario Menu", 8);
				setfont6x8();
				DrawStrXor(32, 40, "Continue Editing");
				DrawStrXor(68, 60, "Save");
				DrawStrXor(20, 80, "Exit Scenario Editor");
				highlight2(a);
				do
				{
					b = a;
					k = nograyngetchx();
					if (k == KEY_UP)
					{
						a = (a + 2) % 3;
					}
					else if (k == KEY_DOWN)
					{
						a = (a + 1) % 3;
					}
					else if (k == 13)
					{
						switch(a)
						{
							case 0:
								k = 13;
								break;
							case 1:
								k = 0;
								e = 1;
								curtech = tech;
								for(c = 0; c < nums.techs; c++)
								{
									if (!curtech->prod5 && !curtech->sci5 && !curtech->gold && !curtech->bridge)
									{
										for(d = 0; d < nums.techs; d++)
										{
											if (c != d)
											{
												pre = tech[d].prereq;
												for(f = 0; f <= 2; f++)
												{
													if (pre[f] == 255)
													{
														break;
													}
													else if (pre[f] == c)
													{
														d = 126;
														break;
													}
												}
											}
										}
										if (d != 127)
										{
											for(d = 0; d < nums.infos; d++)
											{
												if (info[d].tech == c)
												{
													d = 126;
												}
											}
											if (d != 127)
											{
												sprintf(s, "Cannot save^scenario file for^the following^reason:^technology^\"%s\"^has no benefit.", tech[c].id);
												ClrScr();
												bigmessage(s);
												etc();
												e = 0;
												break;
											}
										}
									}
									curtech++;
								}
								if (e)
								{
									pre = (unsigned char *)malloc_throw(nums.techs);
									for(f = 0; f < nums.techs; f++)
									{
										for(g = 0; g < nums.techs; g++)
										{
											pre[g] = 0;
										}
										pre[f] = 2;
										do
										{
											c = 0;
											for(d = 0; d < nums.techs; d++)
											{
												if (pre[d] == 2)
												{
													for(g = 0; g <= 2; g++)
													{
														e = tech[d].prereq[g];
														if (e == 255)
														{
															break;
														}
														else if (e == f)
														{
															c = 1;
															f = d = 126;
															sprintf(s, "Cannot save^scenario file for^the following^reason:^technology^\"%s\"^is its own^prerequisite.", tech[c].id);
															ClrScr();
															bigmessage(s);
															etc();
															break;
														}
														else if (pre[e] != 1)
														{
															c = 1;
															pre[e] = 2;
														}
													}
													pre[d] = 1;
												}
											}
										}
										while (c);
									}
									tryfree(pre);
									if (f != 127)
									{
										FontSetSys(F_8x10);
										ClrScr();
										centertext("Enter scenario name:", 20);
										setfont6x8();
										DrawStrXor(2, 50, scenname);
										do
										{
											c = getstr(scenname, 2, 50, 20, 255, 0);
										}
										while (c && !*scenname);
										if (c)
										{
											c = askwhichdata(1, 1);
											if (c != -1)
											{
												sprintf(s, "main\\scen%d", c);
												d = 1;
												if ((input = fopen(s, "rb")))
												{
													if (!allowbigchanges)
													{
														if (!fseek(input, 21, SEEK_SET))
														{
															if (!freadc(code2, 2, 8, input))
															{
																/*for(d = 0; d <= 7; d++)
																{
																	if (nums.code[d] != code2[d])
																	{
																		break;
																	}
																}*/
																d = memcmp(nums.code, code2, 16);
															}
															else
															{
																error(3);
																return(0);
															}
														}
														else
														{
															error(3);
															return(0);
														}
													}
													fclose(input);
													if (d)
													{
														bigmessage("Really overwrite^existing scenario?^This will make all^saved games that^use it unplayable.");
														d = 61;
													}
													else
													{
														bigmessage("Really update^existing scenario?");
														d = 28;
													}
													DrawStrXor1(d, "F1: Yes");
													DrawStrXor1(d + 11, "F2: No");
													d = f1f2();
												}
												else
												{
													d = 1;
												}
												if (d)
												{
													if (!savescen(c, tech, info, scenname, &nums, &sorts, allowbigchanges))
													{
														error(7);
														return(0);
													}
													a = 2;
													h = 1;
													ClrScr();
													bigmessage("Scenario has been^saved.");
													etc();
												}
											}
										}
									}
								}
								break;
							default:
								if (h)
								{
									k = 264;
									break;
								}
								ClrScr();
								bigmessage("Really abandon this^scenario file?");
								DrawStrXor1(28, "F1: Yes");
								DrawStrXor1(39, "F2: No");
								if (f1f2())
								{
									k = 264;
								}
								else
								{
									k = 0;
								}
						};
					}
					else if (k == 264)
					{
						k = 13;
					}
					if (a != b)
					{
						highlight2(b);
						highlight2(a);
					}
				}
				while (k && k != 13 && k != 264);
			}
			while (k != 13 && k != 264);
			if (k == 13)
			{
				ClrScr();
				DrawLineXor(99, 0, 99, 99);
			}
		}
	}
	while (k != 264);
	tryfree(tech);
	tryfree(info);
	tryfree(sprites);
	tryfree(sorts.asort);
	tryfree(sorts.csort);
	return(1);
}

char adj(char x, struct MAP *map)
{
	//char a;
	if (x < 0)
	{
		return(x + map->w + 1);
	}
	else if (x > map->w)
	{
		return(x - (map->w + 1));
	}
	else
	{
		return(x);
	}
	/*a = map->w + 1;
	return((char)((short)(x + a) % (short)a));*/
}

short mapindex(char x, char y, struct MAP *map)
{
	return(((short)y * (short)(map->w + 2 - (map->w % 2)) + (short)adj(x, map)) >> 1);
}

short tiles(struct MAP *map)
{
	return(mapindex(map->w, map->h, map) + 1);
}

// Returns 1 upon error, 0 else
char readandcopycities(FILE **input, char cities, struct CITY *city)
{
	char a;
	struct OLDCITY *oldcity, *oldcity2;
	oldcity2 = oldcity = (struct OLDCITY *)malloc_throw(cities * sizeof(struct OLDCITY));
	if (freadc(oldcity, sizeof(struct OLDCITY), cities, *input))
	{
		return(1);
	}
	for(a = 0; a < cities; a++)
	{
		city->x = oldcity2->x;
		city->y = oldcity2->y;
		city->building = oldcity2->building;
		city->percent1600 = (short)(oldcity2->percent * 1600.0);
		city++;
		oldcity2++;
	}
	tryfree(oldcity);
	return(0);
}

char loadmap(char fileindex, struct MAP *map, struct CITY **city, char *cities)
{
	FILE *input;
	char fname[10];
	short a, c;
	unsigned char b;
	sprintf(fname, "main\\map%d", fileindex);
	if (!(input = fopen(fname, "rb")))
	{
		return(0);
	}
	tryfree(map->tile);
	if (freadc(map, sizeof(struct MAP), 1, input))
	{
		return(0);
	}
	// This is performed here to ensure that there are at least 16 more bytes
	if (fread1(&b, 1, input))
	{
		return(0);
	}
	if (b != 255)
	{
		c = 100;
		if (fseek(input, -1, SEEK_CUR))
		{
			return(0);
		}
	}
	else if (freadc(&c, 2, 1, input))
	{
		return(0);
	}
	a = tiles(map);
	map->tile = (struct TILE *)malloc_throw(a * sizeof(struct TILE));
	if (freadc(map->tile, sizeof(struct TILE), a, input))
	{
		return(0);
	}
	for(a = 0; a <= 1; a++)
	{
		if (fread1(cities + a, 1, input))
		{
			return(0);
		}
		tryfree(city[a]);
		city[a] = (struct CITY *)malloc_throw(cities[a] * sizeof(struct CITY));
		if (c > 100)
		{
			if (freadc(city[a], sizeof(struct CITY), cities[a], input))
			{
				return(0);
			}
		}
		else if (readandcopycities(&input, cities[a], city[a]))
		{
			return(0);
		}
	}
	return(!fclose(input));
}

char savemap(char fileindex, struct MAP *map, struct CITY **city, char *cities)
{
	FILE *output;
	char fname[10];
	short a;
	unsigned char c;
	sprintf(fname, "main\\map%d", fileindex);
	if (!(output = fopen(fname, "wb")))
	{
		return(0);
	}
	if (fwritec(map, sizeof(struct MAP), 1, output))
	{
		return(0);
	}
	// This is performed here to ensure that there are at least 16 more bytes
	c = 255;
	if (fwrite1(&c, 1, output))
	{
		return(0);
	}
	a = 103;
	if (fwritec(&a, 2, 1, output))
	{
		return(0);
	}
	if (fwritec(map->tile, sizeof(struct TILE), tiles(map), output))
	{
		return(0);
	}
	for(a = 0; a <= 1; a++)
	{
		if (fwrite1(cities + a, 1, output))
		{
			return(0);
		}
		if (fwritec(city[a], sizeof(struct CITY), cities[a], output))
		{
			return(0);
		}
	}
	fputc(0, output);
	fputs("CIV", output);
	fputc(0, output);
	fputc(OTH_TAG, output);
	return(!fclose(output));
}

// Centers the viewscreen at the specified coordinates
void centerscreen(struct FOCUS *focus, struct MAP *map, char x, char y)
{
	focus->xc = adj(x - 5, map);
	//plyr[turn].xo = 5;  Irrelevant because xo always = 5
	// Note that this code may require revision if the scrolling system
	// is changed
	/*if (y < 5)
	{
		curplyr->yc = 0;
	}
	else if (y < map->h - 5)
	{
		curplyr->yc = y - 5;
	}
	else
	{
		curplyr->yc = map->h - 10;
	}*/
	focus->yo = y - (focus->yc = max(min(y - 5, map->h - 10), 0));
}

unsigned char getwater(struct MAP *map, short index, char odd)
{
	if (odd)
	{
		return(map->tile[index].water2);
	}
	else
	{
		return(map->tile[index].water1);
	}
}

unsigned char getriver(struct MAP *map, short index, char odd)
{
	if (odd)
	{
		return(map->tile[index].river2);
	}
	else
	{
		return(map->tile[index].river1);
	}
}

unsigned char getroad(struct MAP *map, short index, char odd)
{
	if (odd)
	{
		return(map->tile[index].road2);
	}
	else
	{
		return(map->tile[index].road1);
	}
}

unsigned char getmine(struct MAP *map, short index, char odd)
{
	if (odd)
	{
		return(map->tile[index].mine2);
	}
	else
	{
		return(map->tile[index].mine1);
	}
}

// Returns whether there was a change
/*char setwater(struct MAP *map, short index, char odd, char value)
{
	if (odd)
	{
		map->tile[index].water2 = value;
	}
	else
	{
		map->tile[index].water1 = value;
	}
}

char setriver(struct MAP *map, short index, char odd, char value)
{
	if (odd)
	{
		map->tile[index].river2 = value;
	}
	else
	{
		map->tile[index].river1 = value;
	}
}

char setroad(struct MAP *map, short index, char odd, char value)
{
	if (odd)
	{
		map->tile[index].road2 = value;
	}
	else
	{
		map->tile[index].road1 = value;
	}
}

char setmine(struct MAP *map, short index, char odd, char value)
{
	if (odd)
	{
		map->tile[index].mine2 = value;
	}
	else
	{
		map->tile[index].mine1 = value;
	}
}*/

void spacedetails(struct FOCUS *focus, struct MAP *map)
{
	short a;
	char b;
	GraySetAMSPlane(DARK_PLANE);
	a = mapindex(b = adj(focus->xc + focus->xo, map), focus->yc + focus->yo, map);
	b %= 2;
	if (getwater(map, a, b))
	{
		Sprite8(101, 0, 8, sprites, GrayGetPlane(DARK_PLANE), SPRT_OR);
	}
	else
	{
		if (getriver(map, a, b))
		{
			Sprite8(110, 0, 8, sprites + 32, GrayGetPlane(DARK_PLANE), SPRT_OR);
		}
		if (getmine(map, a, b))
		{
			Sprite8(119, 0, 8, sprites + 40, GrayGetPlane(DARK_PLANE), SPRT_OR);
		}
		if (getroad(map, a, b))
		{
			Sprite8(128, 0, 8, sprites + 24, GrayGetPlane(DARK_PLANE), SPRT_OR);
		}
	}
}

static inline void spaceoutline(char x, char y, short attribute)
{
	x *= 9;
	y *= 9;
	rectoutline(x, y, x + 9, y + 9, attribute);
}

/*void copycity(struct CITY *city1, struct CITY *city2)
{
	city1->x = city2->x;
	city1->y = city2->y;
	city1->building = city2->building;
	city1->percent = city2->percent;
}*/

void setdarkplane()
{
	GraySetAMSPlane(DARK_PLANE);
}

void setlightplane()
{
	GraySetAMSPlane(LIGHT_PLANE);
}

void highlight4(char x)
{
	drawrect(52 + (x << 3) + 24 * (x >= 2), 39, 59 + (x << 3) + 24 * (x >= 2) + (x % 2), 49);
}

// Returns 1 for back, 0 else
char changemapsize(struct MAP *map)
{
	char a, x, ox, digit, olddigit, s[9];
	unsigned char *p, h, w;
	short k;
	h = map->h;
	w = map->w;
	FontSetSys(F_8x10);
	ClrScr();
	centertext("Enter Map Size:", 8);
	sprintf(s, "%02d x %02d", w + 1, h + 1);
	centertext(s, 40);
	highlight4(x = 0);
	do
	{
		ox = x;
		k = nograyngetchx();
		if (k == KEY_LEFT)
		{
			if (x)
			{
				x--;
			}
		}
		else if (k == KEY_RIGHT)
		{
			if (x < 3)
			{
				x++;
			}
		}
		else if (k == '+' || k == '-' || isdigit(k))
		{
			if (x < 2)
			{
				p = &w;
			}
			else
			{
				p = &h;
			}
			if (x % 2)
			{
				olddigit = (*p + 1) % 10;
				digit = dmod(olddigit, k);
				if (*p < 19 && !digit)
				{
					digit = 1;
				}
				*p += (digit - olddigit);
			}
			else
			{
				olddigit = (*p + 1) / 10;
				digit = max(dmod(olddigit, k), 1);
				if (digit == 1 && *p % 10 == 9)
				{
					*p = 10;
					DrawChar(60 + 20 * x, 40, '1', A_REPLACE);
				}
				else
				{
					*p += (digit - olddigit) * 10;
				}
			}
			if (olddigit != digit)
			{
				DrawCharXor(a = 52 + (x << 3) + 24 * (x >= 2), 40, olddigit + '0');
				DrawCharXor(a, 40, digit + '0');
			}
		}
		if (x != ox)
		{
			highlight4(ox);
			highlight4(x);
		}
	}
	while (k != 13 && k != 264);
	if (k == 13)
	{
		map->h = h;
		map->w = w;
	}
	return(k == 264);
}

void highlight5(char a)
{
	switch(a)
	{
		case 0:
			drawrect(31, 33, 129, 43);
			break;
		case 1:
			drawrect(67, 48, 93, 58);
			break;
		case 2:
			drawrect(46, 63, 114, 73);
			break;
		default:
			drawrect(34, 78, 126, 88);
	};
}

static inline void cleartile(char x, char y, struct MAP *map)
{
	struct TILE *curtile;
	curtile = map->tile + mapindex(x, y, map);
	if (x % 2)
	{
		curtile->water2 = curtile->river2 = curtile->mine2 = curtile->road2 = 0;
	}
	else
	{
		curtile->water1 = curtile->river1 = curtile->mine1 = curtile->road1 = 0;
	}
}

char editmap()
{
	// fi means focus index
	char b, d, e, f[3], g, h, j, s[75], x, y, ox, oy, fi, redraw, redrawtbar, drawsize, cities[2], disp[121];
	struct MAP map, oldmap;
	struct CITY *city[2], *curcity, tempcity;
	struct TILE *curtile;
	struct FOCUS focus;
	short a, c, i, k;
	FILE *input;
	map.tile = NULL;
	*city = city[1] = NULL;
	focus.xo = 5;
	map.w = map.h = 19;
	b = -1;
	do
	{
		FontSetSys(F_8x10);
		ClrScr();
		centertext("Map Editor", 8);
		setfont6x8();
		DrawStrXor(71, 40, "New");
		DrawStrXor(68, 60, "Load");
		highlight6(a = 0);
		do
		{
			k = nograyngetchx();
			if ((k == KEY_UP && a) || (k == KEY_DOWN && !a))
			{
				a = !a;
				highlight6(0);
				highlight6(1);
			}
		}
		while (k != 13 && k != 264);
		if (k == 13)
		{
			if (a)
			{
				b = askwhichdata(2, 0);
				if (b == -1)
				{
					k = 0;
				}
			}
			else if (changemapsize(&map))
			{
				k = 0;
			}
		}
	}
	while (k != 13 && k != 264);
	if (b >= 0)
	{
		if (!loadmap(b, &map, city, cities))
		{
			error(2);
			return(0);
		}
		centerscreen(&focus, &map, (*city)->x, (*city)->y);
	}
	else if (k != 264)
	{
		city[0] = city[1] = NULL;
		cities[0] = cities[1] = focus.yc = *(map.name) = 0;
		a = tiles(&map);
		curtile = map.tile = (struct TILE *)malloc_throw(a * sizeof(struct TILE));
		for(c = 0; c < a; c++)
		{
			curtile->river1 = curtile->river2 = curtile->mine1 = curtile->mine2 = curtile->road1 = curtile->road2 = curtile->water1 = curtile->water2 = 0;
			curtile++;
		}
		focus.yo = 5;
		focus.xc = map.w - 4;
	}
	else
	{
		return(1);
	}
	copysprites();
	redraw = redrawtbar = 1;
	drawsize = 0;
	setdarkplane();
	ClrScr();
	setlightplane();
	ClrScr();
	do
	{
		if (redraw)
		{
			if (!GrayCheckRunning())
			{
				GrayOnThrow();
			}
			for(a = 0; a <= 120; a++)
			{
				disp[a] = 127;
			}
			for(a = 0; a <= 1; a++)
			{
				curcity = city[a];
				for(b = 0; b < cities[a]; b++)
				{
					x = adj(curcity->x - focus.xc, &map);
					y = curcity->y - focus.yc;
					if (x >= 0 && x <= 10 && y >= 0 && y <= 10)
					{
						disp[11 * y + x] = 50 * a + b;
					}
					curcity++;
				}
			}
			fi = 11 * focus.yo + focus.xo;
			setdarkplane();
			if (!redrawtbar)
			{
				revrect(100, 0, 159, 8);
				revrect(0, 0, 99, 99);
				setlightplane();
				revrect(100, 0, 159, 8);
				revrect(0, 0, 99, 99);
			}
			else
			{
				ClrScr();
				setlightplane();
				ClrScr();
			}
			for(a = 0; a <= 54; a += 27)
			{
				Sprite32(a, 0, 100, rects, GrayGetPlane(LIGHT_PLANE), SPRT_OR);
			}
			Sprite32(72, 0, 100, rects, GrayGetPlane(LIGHT_PLANE), SPRT_OR);
			drawrect(9 * focus.xo + 1, 9 * focus.yo + 1, 9 * focus.xo + 8, 9 * focus.yo + 8);
			spaceoutline(focus.xo, focus.yo, A_REVERSE);
			for(y = a = 0; y <= 10; y++)
			{
				for(x = 0; x <= 10; x++)
				{
					if ((h = (disp[a] == 127)))
					{
						d = 0;
						b = focus.xc + x;
						c = mapindex(b, focus.yc + y, &map);
						if (getwater(&map, c, b = adj(b, &map) % 2))
						{
							f[d++] = 0;
						}
						else
						{
							if (getroad(&map, c, b))
							{
								f[d++] = 3;
							}
							if (getriver(&map, c, b))
							{
								f[d++] = 4;
							}
							if (getmine(&map, c, b))
							{
								f[d++] = 5;
							}
						}
						b = c = 1;
					}
					else
					{
						*f = 1;
						b = !(disp[a] / 50);
						d = (a == fi);
						c = (b || d);
						b = (b && d);
						d = 1;
					}
					for(g = b; g <= c; g++)
					{
						for(e = 0; e < d; e++)
						{
							GraySetAMSPlane(g);
							// SPRT_XOR is 0, SPRT_OR is 1
							Sprite8(9 * x + 1, 9 * y + 1, 8, sprites + (f[e] << 3), GrayGetPlane(g), h);
						}
					}
					a++;
				}
			}
			if (focus.xc + 10 >= map.w || !focus.xc)
			{
				if (focus.xc)
				{
					a = 9 * (map.w - focus.xc + 1);
				}
				else
				{
					a = 0;
				}
				setdarkplane();
				DrawLineXor(a, 0, a, 99);
				// This accounts for overlap with the selected space
				setlightplane();
				DrawLine(a, 0, a, 99, A_NORMAL);
				if (!focus.xc && map.w == 10)
				{
					setdarkplane();
					DrawLineXor(99, 0, 99, 99);
					// This accounts for overlap with the selected space
					setlightplane();
					DrawLine(99, 0, 99, 99, A_NORMAL);
				}
			}
			if (!focus.yc)
			{
				setdarkplane();
				DrawLine(0, 0, 99, 0, A_NORMAL);
				setlightplane();
				DrawLine(0, 0, 99, 0, A_NORMAL);
			}
			if (focus.yc + 10 == map.h)
			{
				setdarkplane();
				DrawLine(0, 99, 99, 99, A_NORMAL);
				setlightplane();
				DrawLine(0, 99, 99, 99, A_NORMAL);
			}
			spacedetails(&focus, &map);
			if ((a = disp[fi]) != 127)
			{
				sprintfd(s, (a % 50) + 1);
				setfont6x8();
				for(b = 0; b <= !(a / 50); b++)
				{
					GraySetAMSPlane(b);
					Sprite8(139, 1, 8, sprites + 8, GrayGetPlane(b), SPRT_OR);
					DrawStrXor(147, 1, s);
				}
			}
			setfont4x6();
			setdarkplane();
			sprintf(s, "(%d,%d)    ", adj(focus.xc + focus.xo, &map) + 1, focus.yc + focus.yo + 1);
			DrawStr(100, 94, s, A_REPLACE);
			redraw = 0;
		}
		if (redrawtbar)
		{
			setdarkplane();
			setfont6x8();
			DrawStrXor100(10, "F1:Water");
			DrawStrXor100(18, "F2:Land");
			DrawStrXor100(26, "F3:Mine");
			DrawStrXor100(34, "F4:River");
			DrawStrXor100(42, "F5:Roads");
			setfont4x6();
			DrawStrXor100(53, "X: Black City");
			DrawStrXor100(59, "Y: Gray City");
			DrawStrXor100(65, "\x15: Delete City");
			DrawStrXor100(71, "ESC: Menu");
			DrawStrXor100(77, "+/-:Change City#");
			DrawStrXor100(86, "1 2 3 : Draw Size");
			drawrect(100 + 6 * drawsize, 85, 104 + 6 * drawsize, 91);
			redrawtbar = 0;
		}
		ox = x = adj(focus.xc + focus.xo, &map);
		oy = y = focus.yc + focus.yo;
		k = grayngetchx();
		if ((a = dirkeys2(k)) == 2)
		{
			y--;
		}
		else if (a == 4)
		{
			y++;
		}
		else if (a == 1)
		{
			x--;
		}
		else if (a)
		{
			x++;
		}
		//else if (k == KEY_UP + _2nd)
		else if ((a = dirkeys2(k - _2nd)) == 2)
		{
			y -= 11;
		}
		else if (a == 4)
		{
			y += 11;
		}
		else if (a == 1)
		{
			x -= 11;
		}
		else if (a)
		{
			x += 11;
		}
		else if (k == KEY_DIAMOND + KEY_UP)
		{
			y = 0;
		}
		else if (k == KEY_DIAMOND + KEY_DOWN)
		{
			y = map.h;
		}
		else if (k >= 268 && k <= 272)
		{
			d = max(y - drawsize, 0);
			e = min(y + drawsize, map.h);
			g = h = 0;
			if (k >= 270)
			{
				for(a = d; a <= e; a++)
				{
					for(b = -drawsize; b <= drawsize; b++)
					{
						h++;
						c = mapindex(d = adj(x + b, &map), a, &map);
						d %= 2;
						switch(k)
						{
							case 270:
								if (getmine(&map, c, d))
								{
									g++;
								}
								break;
							case 271:
								if (getriver(&map, c, d))
								{
									g++;
								}
								break;
							default:
								if (getroad(&map, c, d))
								{
									g++;
								}
						};
					}
				}
				g = ((g << 1) <= h);
			}
			for(a = max(y - drawsize, 0); a <= min(y + drawsize, map.h); a++)
			{
				for(b = -drawsize; b <= drawsize; b++)
				{
					curtile = map.tile + mapindex(c = adj(x + b, &map), a, &map);
					c %= 2;
					switch(k)
					{
						case 268:
							if (disp[11 * (a - focus.yc) + focus.xo + b] == 127)
							{
								if (c)
								{
									if (!curtile->water2)
									{
										curtile->water2 = redraw = 1;
										curtile->river2 = curtile->mine2 = curtile->road2 = 0;
									}
								}
								else if (!curtile->water1)
								{
									curtile->water1 = redraw = 1;
									curtile->river1 = curtile->mine1 = curtile->road1 = 0;
								}
							}
							break;
						case 269:
							if (c)
							{
								if (curtile->water2)
								{
									curtile->water2 = 0;
									redraw = 1;
								}
							}
							else
							{
								if (curtile->water1)
								{
									curtile->water1 = 0;
									redraw = 1;
								}
							}
							break;
						case 270:
							if (c)
							{
								if (curtile->water2)
								{
									curtile->water2 = 0;
									redraw = 1;
								}
								if (curtile->mine2 != g)
								{
									curtile->mine2 = g;
									redraw = 1;
								}
							}
							else
							{
								if (curtile->water1)
								{
									curtile->water1 = 0;
									redraw = 1;
								}
								if (curtile->mine1 != g)
								{
									curtile->mine1 = g;
									redraw = 1;
								}
							}
							break;
						case 271:
							if (c)
							{
								if (curtile->water2)
								{
									curtile->water2 = 0;
									redraw = 1;
								}
								if (curtile->river2 != g)
								{
									curtile->river2 = g;
									redraw = 1;
								}
							}
							else
							{
								if (curtile->water1)
								{
									curtile->water1 = 0;
									redraw = 1;
								}
								if (curtile->river1 != g)
								{
									curtile->river1 = g;
									redraw = 1;
								}
							}
							break;
						default:
							if (c)
							{
								if (curtile->water2)
								{
									curtile->water2 = 0;
									redraw = 1;
								}
								if (curtile->road2 != g)
								{
									curtile->road2 = g;
									redraw = 1;
								}
							}
							else
							{
								if (curtile->water1)
								{
									curtile->water1 = 0;
									redraw = 1;
								}
								if (curtile->road1 != g)
								{
									curtile->road1 = g;
									redraw = 1;
								}
							}
					};
				}
			}
		}
		else if (k >= '1' && k <= '3')
		{
			drawrect(100 + 6 * drawsize, 85, 104 + 6 * drawsize, 91);
			drawsize = k - '1';
			drawrect(100 + 6 * drawsize, 85, 104 + 6 * drawsize, 91);
		}
		else if (k == 'x' || k == 'y')
		{
			if (disp[fi] / 50 + 'x' != k)
			{
				if (cities[k -= 'x'] != 50)
				{
					if (disp[fi] != 127)
					{
						curcity = city[!k];
						for(a = disp[fi] % 50; a + 1 < cities[!k]; a++)
						{
							memcpy(curcity + a, curcity + a + 1, sizeof(struct CITY));
						}
						city[!k] = (struct CITY *)realloc_throw(curcity, --cities[!k] * sizeof(struct CITY));
					}
					else
					{
						curtile = map.tile + mapindex(adj(x, &map), y, &map);
						if (x % 2)
						{
							curtile->water2 = 0;
						}
						else
						{
							curtile->water1 = 0;
						}
					}
					city[k] = (struct CITY *)realloc_throw(city[k], ++cities[k] * sizeof(struct CITY));
					curcity = city[k] + cities[k] - 1;
					curcity->x = x;
					curcity->y = y;
					curcity->building = 255;
					curcity->percent1600 = 0;
					redraw = 1;
				}
				else
				{
					setlightplane();
					revrect(100, 0, 159, 99);
					setdarkplane();
					revrect(100, 0, 159, 99);
					setfont6x8();
					DrawStrXor100(2, "This");
					DrawStrXor100(9, "action");
					DrawStrXor100(17, "would");
					DrawStrXor100(25, "exceed");
					DrawStrXor100(33, "the city");
					DrawStrXor100(41, "limit of");
					DrawStrXor100(49, "50.");
					DrawStrXor100(61, "F1:OK");
					while (grayngetchx() != 268);
					revrect(100, 0, 159, 99);
					spacedetails(&focus, &map);
					redrawtbar = 1;
				}
			}
		}
		else if (k == 264)
		{
			a = h = 0;
			redraw = redrawtbar = 1;
			do
			{
				GrayOff();
				FontSetSys(F_8x10);
				ClrScr();
				centertext("Map Menu", 8);
				setfont6x8();
				DrawStrXor(32, 35, "Continue Editing");
				DrawStrXor(68, 50, "Save");
				DrawStrXor(47, 65, "Change Size");
				DrawStrXor(35, 80, "Exit Map Editor");
				highlight5(a);
				do
				{
					b = a;
					k = nograyngetchx();
					if (k == KEY_UP)
					{
						a = (a + 3) % 4;
					}
					else if (k == KEY_DOWN)
					{
						a = (a + 1) % 4;
					}
					else if (k == 13)
					{
						switch(a)
						{
							case 0:
								k = 13;
								break;
							case 1:
								if (!*cities || !cities[1])
								{
									strcpy(s, "Cannot save^map file for the^following reason:^");
									if (!*cities)
									{
										strcat(s, "black");
									}
									else
									{
										strcat(s, "gray");
									}
									strcat(s, " has no^starting city.");
									ClrScr();
									bigmessage(s);
									etc();
								}
								else
								{
									FontSetSys(F_8x10);
									ClrScr();
									centertext("Enter map name:", 20);
									setfont6x8();
									DrawStrXor(2, 50, map.name);
									do
									{
										c = getstr(map.name, 2, 50, 19, 255, 0);
									}
									while (c && !*(map.name));
									if (c)
									{
										c = askwhichdata(2, 1);
										if (c != -1)
										{
											sprintf(s, "main\\map%d", c);
											if ((input = fopen(s, "rb")))
											{
												fclose(input);
												bigmessage("Really overwrite^existing map?");
												DrawStrXor1(28, "F1: Yes");
												DrawStrXor1(39, "F2: No");
												d = f1f2();
											}
											else
											{
												d = 1;
											}
											if (d)
											{
												if (!savemap(c, &map, city, cities))
												{
													error(8);
													return(0);
												}
												a = 3;
												h = 1;
												ClrScr();
												bigmessage("Map has been saved.");
												etc();
											}
										}
									}
								}
								k = 0;
								break;
							case 2:
								oldmap.h = map.h;
								oldmap.w = map.w;
								changemapsize(&map);
								if (oldmap.h != map.h || oldmap.w != map.w)
								{
									oldmap.tile = map.tile = (struct TILE *)realloc_throw(map.tile, max(tiles(&map), tiles(&oldmap)) * sizeof(struct TILE));
									if (oldmap.w != map.w)
									{
										if (map.w < oldmap.w)
										{
											g = 1;
											c = 0;
											k = min(oldmap.h, map.h);
											j = min(oldmap.w, map.w);
										}
										else
										{
											g = -1;
											c = min(oldmap.h, map.h) + 1;
											k = 1;
											j = 0;
										}
										do
										{
											c += g;
											if (g == 1)
											{
												d = -1;
											}
											else
											{
												d = min(oldmap.w, map.w) + 1;
											}
											do
											{
												d += g;
												i = mapindex(d, c, &oldmap);
												curtile = map.tile + mapindex(d, c, &map);
												if (d % 2)
												{
													curtile->water2 = getwater(&oldmap, i, 1);
													curtile->river2 = getriver(&oldmap, i, 1);
													curtile->mine2 = getmine(&oldmap, i, 1);
													curtile->road2 = getroad(&oldmap, i, 1);
												}
												else
												{
													curtile->water1 = getwater(&oldmap, i, 0);
													curtile->river1 = getriver(&oldmap, i, 0);
													curtile->mine1 = getmine(&oldmap, i, 0);
													curtile->road1 = getroad(&oldmap, i, 0);
												}
											}
											while (d != j);
										}
										while (c != k);
									}
									map.tile = (struct TILE *)realloc_throw(map.tile, tiles(&map) * sizeof(struct TILE));
									for(c = 0; c <= map.h; c++)
									{
										for(d = oldmap.w + 1; d <= map.w; d++)
										{
											cleartile(d, c, &map);
										}
									}
									for(c = oldmap.h + 1; c <= map.h; c++)
									{
										for(d = 0; d <= min(oldmap.w, map.w); d++)
										{
											cleartile(d, c, &map);
										}
									}
									for(c = 0; c <= 1; c++)
									{
										curcity = city[c];
										for(d = 0; d < cities[c]; d++)
										{
											if (curcity->x > map.w || curcity->y > map.h)
											{
												for(a = d; a + 1 < cities[c]; a++)
												{
													memcpy(curcity + a, curcity + a + 1, sizeof(struct CITY));
												}
												city[c] = (struct CITY *)realloc_throw(curcity, --cities[c] * sizeof(struct CITY));
												d--;
											}
											curcity++;
										}
									}
									/*focus.yc = 0;
									focus.yo = 5;
									focus.xc = map.w - 4;*/
									x = min(adj(focus.xc + focus.xo, &oldmap), map.w);
									y = min(focus.yc + focus.yo, map.h);
									centerscreen(&focus, &map, x, y);
									redraw = 1;
									k = 13;
								}
								else
								{
									k = 0;
								}
								break;
							default:
								if (h)
								{
									k = 264;
									break;
								}
								ClrScr();
								bigmessage("Really abandon this^map file?");
								DrawStrXor1(28, "F1: Yes");
								DrawStrXor1(39, "F2: No");
								if (f1f2())
								{
									k = 264;
								}
								else
								{
									k = 0;
								}
						};
					}
					else if (k == 264)
					{
						k = 13;
					}
					if (a != b)
					{
						highlight5(b);
						highlight5(a);
					}
				}
				while (k && k != 13 && k != 264);
			}
			while (k != 13 && k != 264);
		}
		else if (disp[fi] != 127)
		{
			curcity = city[b = disp[fi] / 50];
			if (k == 257)
			{
				// Backspace
				curcity += a;
				for(a = disp[fi] % 50; a + 1 < cities[b]; a++)
				{
					memcpy(curcity, curcity + 1, sizeof(struct CITY));
				}
				city[b] = (struct CITY *)realloc_throw(city[b], --cities[b] * sizeof(struct CITY));
				redraw = 1;
			}
			else
			{
				a = disp[fi] % 50;
				if ((k == '+' && a + 1 < cities[b]) || (k == '-' && a))
				{
					a = disp[fi] % 50;
					if (k == '+')
					{
						b = 1;
					}
					else
					{
						b = -1;
					}
					memcpy(&tempcity, curcity + a, sizeof(struct CITY));
					memcpy(curcity + a, curcity + a + b, sizeof(struct CITY));
					memcpy(curcity + a + b, &tempcity, sizeof(struct CITY));
					sprintfd(s, ((a += b) + 1) % 50);
					if (a % 50 < 9)
					{
						strcat(s, " ");
					}
					setfont6x8();
					disp[fi] += b;
					for(b = 0; b <= !(disp[fi] / 50); b++)
					{
						GraySetAMSPlane(b);
						DrawStr(147, 1, s, A_REPLACE);
					}
				}
			}
		}
		if (!redraw)
		{
			y = min(max(y, 0), map.h);
			if ((redraw = (x != ox || y != oy)))
			{
				centerscreen(&focus, &map, x, y);
			}
		}
	}
	while (k != 264);
	tryfree(map.tile);
	tryfree(*city);
	tryfree(city[1]);
	tryfree(sprites);
	return(1);
}

void freeplyr(struct PLAYER *plyr)
{
	char a;
	for(a = 0; a <= 1; a++)
	{
		tryfree(plyr->unit);
		tryfree(plyr->city);
		tryfree(plyr->active);
		tryfree(plyr->researched);
		tryfree(plyr->apos);
		plyr++;
	}
}

char loadgame(struct PLAYER *plyr, char *turn, struct MAP *map, struct NUMS *nums, char *scenname)
{
	FILE *input;
	char fname[14], b, c, d;
	short a;
	struct PLAYER *curplyr;
	c = nums->game;
	sprintf(fname, "main\\civgame%d", c);
	if (!(input = fopen(fname, "rb")))
	{
		return(0);
	}
	freeplyr(plyr);
	for(a = 0; a <= 1; a++)
	{
		tryfree(nums->player[a]);
	}
	tryfree(nums->player);
	tryfree(map->tile);
	if (freadc(&a, 2, 1, input))
	{
		return(0);
	}
	if (freadc(nums, sizeof(struct NUMS), 1, input))
	{
		return(0);
	}
	// The players' names are read here for easy access in the askwhichdata function
	nums->game = c;
	nums->player = (char **)malloc_throw(sizeof(char *) << 1);
	for(d = 0; d <= 1; d++)
	{
		if (fread1(nums->player[d] = (char *)malloc_throw(11), 11, input))
		{
			return(0);
		}
	}
	if (fread1(turn, 1, input))
	{
		return(0);
	}
	if (freadc(plyr, sizeof(struct PLAYER), 2, input))
	{
		return(0);
	}
	if (fread1(scenname, 21, input))
	{
		return(0);
	}
	for(d = 0; d <= 1; d++)
	{
		plyr->active = (unsigned char *)malloc_throw(nums->infos);
		plyr->researched = (unsigned char *)malloc_throw(nums->techs);
		plyr->unit = (struct UNIT *)malloc_throw(plyr->units * sizeof(struct UNIT));
		if (freadc(plyr->unit, sizeof(struct UNIT), plyr->units, input))
		{
			return(0);
		}
		plyr->city = (struct CITY *)malloc_throw(plyr->cities * sizeof(struct CITY));
		if (a > 100)
		{
			if (freadc(plyr->city, sizeof(struct CITY), plyr->cities, input))
			{
				return(0);
			}
		}
		else if (readandcopycities(&input, plyr->cities, plyr->city))
		{
			return(0);
		}
		if (fread1(plyr->researched, nums->techs, input))
		{
			return(0);
		}
		if (fread1(plyr->active, nums->infos, input))
		{
			return(0);
		}
		if (fread1(&b, 1, input))
		{
			return(0);
		}
		plyr->apos = (char *)malloc_throw(b);
		if (fread1(plyr->apos, b, input))
		{
			return(0);
		}
		plyr++;
	}
	if (freadc(map, sizeof(struct MAP), 1, input))
	{
		return(0);
	}
	a = tiles(map);
	map->tile = (struct TILE *)malloc_throw(a * sizeof(struct TILE));
	if (freadc(map->tile, sizeof(struct TILE), a, input))
	{
		return(0);
	}
	if (fread1(&b, 1, input))
	{
		return(0);
	}
	if (fclose(input))
	{
		return(0);
	}
	return(1);
}

static inline char aposend(struct PLAYER *curplyr)
{
	char end;
	for(end = 0; curplyr->apos[end] != 127; end++);
	return(end + 1);
}

char savegame(struct PLAYER *plyr, char turn, struct MAP *map, struct NUMS *nums, char *scenname)
{
	FILE *output;
	char fname[14], b;
	short a;
	struct PLAYER *curplyr;
	sprintf(fname, "main\\civgame%d", nums->game);
	//unlink(fname);
	if (!(output = fopen(fname, "wb")))
	{
		return(0);
	}
	a = 104;
	if (fwritec(&a, 2, 1, output))
	{
		return(0);
	}
	if (fwritec(nums, sizeof(struct NUMS), 1, output))
	{
		return(0);
	}
	// The players' names are written here for easy access in the askwhichdata function
	for(a = 0; a <= 1; a++)
	{
		if (fwritec(nums->player[a], 1, 11, output))
		{
			return(0);
		}
	}
	if (fwritec(&turn, 1, 1, output))
	{
		return(0);
	}
	if (fwritec(plyr, sizeof(struct PLAYER), 2, output))
	{
		return(0);
	}
	if (fwritec(scenname, 1, 21, output))
	{
		return(0);
	}
	for(a = 0; a <= 1; a++)
	{
		b = aposend(plyr);
		if (fwritec(plyr->unit, sizeof(struct UNIT), plyr->units, output))
		{
			return(0);
		}
		if (fwritec(plyr->city, sizeof(struct CITY), plyr->cities, output))
		{
			return(0);
		}
		if (fwritec(plyr->researched, 1, nums->techs, output))
		{
			return(0);
		}
		if (fwritec(plyr->active, 1, nums->infos, output))
		{
			return(0);
		}
		if (fwritec(&b, 1, 1, output))
		{
			return(0);
		}
		if (fwritec(plyr->apos, 1, b, output))
		{
			return(0);
		}
		plyr++;
	}
	a = tiles(map);
	// b is whether the previous save was from edit mode as opposed to play mode
	b = 1;
	if (fwritec(map, sizeof(struct MAP), 1, output))
	{
		return(0);
	}
	if (fwritec(map->tile, sizeof(struct TILE), a, output))
	{
		return(0);
	}
	if (fwritec(&b, 1, 1, output))
	{
		return(0);
	}
	fputc(0, output);
	fputs("CIV", output);
	fputc(0, output);
	fputc(OTH_TAG, output);
	return(!fclose(output));
}

void emptyfull(char a)
{
	FILE *input;
	char b[14];
	sprintf(b, "main\\civgame%d", a);
	revrect(81, 36, 119, 43);
	if ((input = fopen(b, "rb")))
	{
		fclose(input);
		DrawStrXor(79, 36, "(full)");
	}
	else
	{
		DrawStrXor(79, 36, "(empty)");
	}
}

char editgame()
{
	char x, y, ox, oy, xs, ys, w, s[18], digit, olddigit, turn, scenname[21];
	short a, k;
	struct PLAYER plyr[2], *curplyr;
	struct MAP map;
	struct NUMS nums;
	nums.game = askwhichdata(0, 0);
	if (nums.game == -1)
	{
		return(1);
	}
	map.tile = NULL;
	nums.player = (char **)malloc_throw(sizeof(char *) << 1);
	curplyr = plyr;
	for(a = 0; a <= 1; a++)
	{
		nums.player[a] = (char *)malloc_throw(11);
		curplyr->active = curplyr->apos = curplyr->researched = NULL;
		curplyr->unit = NULL;
		curplyr->city = NULL;
		curplyr++;
	}
	if (!loadgame(plyr, &turn, &map, &nums, scenname))
	{
		error(4);
		return(0);
	}
	sprintf(s, "Turn Limit: %04d", nums.maxturn);
	setfont4x6();
	ClrScr();
	DrawStrXor1(11, "(set turn limit to 0 to eliminate limit)");
	DrawStrXor1(28, "(a positive handicap makes it easier for black)");
	DrawStrXor1(94, "Use \x15\x16\x17\x18 to move, +- or 0-9 to change");
	setfont6x8();
	DrawStrXor1(2, s);
	sprintf(s, "Handicap: %d", plyr->handicap);
	DrawStrXor1(19, s);
	sprintf(s, "Save File: %d", nums.game);
	DrawStrXor1(36, s);
	emptyfull(nums.game);
	centertext("Player Names:", 47);
	sprintf(s, "Black: %s", *(nums.player));
	DrawStrXor1(56, s);
	sprintf(s, "Gray: %s", nums.player[1]);
	DrawStrXor1(65, s);
	centertext("Save", 76);
	centertext("Cancel", 85);
	x = y = 0;
	drawrect(xs = 73, ys = 1, 79, 9);
	w = 6;
	do
	{
		ox = x;
		oy = y;
		if (y != 3 && y != 4)
		{
			k = nograyngetchx();
		}
		else
		{
			k = getstr(nums.player[y - 3], 61 - 6 * y, 9 * y + 29, 10, (y << 1) + 50, 1);
		}
		if (k == KEY_UP)
		{
			x = 0;
			y = (y + 6) % 7;
		}
		else if (k == KEY_DOWN)
		{
			x = 0;
			y = (y + 1) % 7;
		}
		else if (k == KEY_LEFT)
		{
			if (x)
			{
				x--;
			}
		}
		else if (k == KEY_RIGHT)
		{
			if (!y && x < 3)
			{
				x++;
			}
		}
		else if (k == '+' || k == '-' || isdigit(k))
		{
			digit = olddigit = 0;
			switch(y)
			{
				case 0:
					olddigit = (nums.maxturn / (short)pow(10.0, (float)(3 - x))) % 10;
					digit = dmod(olddigit, k);
					a = nums.maxturn;
					nums.maxturn += (digit - olddigit) * (short)pow(10.0, (float)(3 - x));
					if (nums.maxturn < nums.turnnum)
					{
						sprintf(s, "%04d", a);
						DrawStrXor(73, 2, s);
						digit = olddigit = 0;
						if (nums.maxturn < (nums.turnnum >> 1))
						{
							nums.maxturn = 0;
						}
						else
						{
							nums.maxturn = nums.turnnum;
						}
						sprintf(s, "%04d", nums.maxturn);
						DrawStrXor(73, 2, s);
					}
					break;
				case 1:
					a = plyr->handicap;
					if (isdigit(k))
					{
						plyr->handicap = k - '0';
					}
					else if (k == '-')
					{
						plyr->handicap = max(plyr->handicap - 1, -5);
					}
					else
					{
						plyr->handicap = min(plyr->handicap + 1, 5);
					}
					if (a != plyr->handicap)
					{
						sprintfd(s, a);
						DrawStrXor(61, 19, s);
						sprintfd(s, plyr->handicap);
						DrawStrXor(61, 19, s);
					}
					break;
				case 2:
					olddigit = nums.game;
					nums.game = digit = dmod(olddigit, k);
					emptyfull(nums.game);
			};
			if (digit != olddigit)
			{
				DrawCharXor(xs, ys + 1, olddigit + '0');
				DrawCharXor(xs, ys + 1, digit + '0');
			}
		}
		else if (k == 264)
		{
			y = 5;
		}
		if (x != ox || y != oy)
		{
			drawrect(xs, ys, xs + w, ys + 8);
			w = 6;
			switch(y)
			{
				case 0:
					xs = 73 + 6 * x;
					ys = 1;
					break;
				case 1:
					xs = 61;
					ys = 18;
					w = 12;
					break;
				case 2:
					xs = 67;
					ys = 35;
					break;
				case 3:
					xs = 43;
					ys = 55;
					w = 60;
					break;
				case 4:
					xs = 37;
					ys = 64;
					w = 60;
					break;
				case 5:
					xs = 68;
					ys = 75;
					w = 24;
					break;
				default:
					xs = 62;
					ys = 84;
					w = 35;
			};
			drawrect(xs, ys, xs + w, ys + 8);
		}
	}
	while (k != 13 || y < 5);
	if (k == 13 && y == 5)
	{
		savegame(plyr, turn, &map, &nums, scenname);
	}
	tryfree(map.tile);
	for(a = 0; a <= 1; a++)
	{
		tryfree(nums.player[a]);
	}
	tryfree(nums.player);
	freeplyr(plyr);
	return(1);
}

// Main Function
void _main(void)
{
	char a, b, letters[] = "=(),/|789*=456- 123t+0.xyz";
	short k;
	NeedStack(7000);
	for(a = 0; a <= 25; a++)
	{
		let[a] = letters[a];
	}
	let[15] = KEY_STO;
	a = 0;
	do
	{
		rects[a] = 0xFFFFFFF0;
		for(a++; a % 9 && a <= 98; a++)
		{
			rects[a] = 0x80402010;
		}
	}
	while (a <= 99);
	OSInitKeyInitDelay(250);
	OSInitBetweenKeyDelay(40);
	randomize();
	
	do
	{
		FontSetSys(F_8x10);
		ClrScr();
		centertext("Civ89 Editor", 4);
		setfont6x8();
		centertext("v1.03", 17);
		centertext("Scenario", 56);
		centertext("Map", 71);
		centertext("Game", 86);
		setfont4x6();
		centertext(EDITNOTES, 33);
		centertext(EDITNOTES2, 40);
		highlight(a = b = 0);
		do
		{
			k = nograyngetchx();
			if (k == KEY_UP)
			{
				b = (b + 2) % 3;
			}
			else if (k == KEY_DOWN)
			{
				b = (b + 1) % 3;
			}
			if (a != b)
			{
				highlight(a);
				highlight(a = b);
			}
		}
		while (k != 13 && k != 264);
		if (k == 13)
		{
			switch(a)
			{
				case 0:
					a = editscen();
					break;
				case 1:
					a = editmap();
					break;
				default:
					a = editgame();
			};
		}
	}
	while (a && k != 264);
}
