! Copyright by Rick Dague, bifurcate@geocities.com
constant ndead 101;
constant sdead 102;
constant nspass 103;
constant nsbreak 104;
constant edead 105;
constant wdead 106;
constant ewpass 107;
constant ewbreak 108;
constant endcmap 109;

global cmapi = 0;
global cmap_first = 0;

class corner(cmap_alloc)
with
	short_name [ i j;
		i = cmap_linest(cmapi); j = cmap->cmapi;
		if(i <= 100 && j <= 50) {
			print (string)cmap_ew-->(i - 51)," & ",(string)cmap_ns-->(j - 1);
		} else {
			if(i <= 100) print (string)cmap_ew-->(i - 51)," St.";
			else print (string)cmap_ns-->(j - 1)," Ave.";
		}
		rtrue;
	],
	before [ i;
	Go:
		i = cmap_cango(noun);
		if(i ~= 0) { cmapi = i; playerto(cmap_find()); rtrue; }
	],
	description [ ; print "On a city street. "; cmap_prexits(); ],
	cant_go [ ; cmap_prexits(); ],
	nxtcnr 0,
has;

[ cmap_find j i x st;
	if(j == 0) j = cmapi;
	x = cmap_first;
	for(i = 0: i <= j: ++i) {
		switch(cmap->i) {
		1 to 50,edead,wdead,ewpass:
			if(st == nsbreak) break;
			if(i == j) return x;
			x = x.nxtcnr;
		ewbreak: ;
		default: st = cmap->i;
		}
	}
	cmapi = j;
	cmap_err(0,"not a valid corner");
];

[ cmap_prexits dir dir1 ct;
	objectloop(dir in compass)
		if(cmap_cango(dir)) {
			if(++ct > 1) {
				if(ct == 2) print "Exits are "; else print ", ";
				print (directionname)dir1;
			}
			dir1 = dir;
		}
	if(ct == 1) print "An exit is "; else print " and ";
	print (directionname)dir1,".^";
];

[ cmap_err b s;
	if(b == 0) {
		print "error in cmap->",cmapi," == ",cmap->cmapi,": ",(string)s;
		new_line; quit;
	}
];

[ cmap_linest i x;
	do { x = (cmap->--i)&$7f;
	} until(50 < x && x <= nsbreak);
	return x;
];

[ cmap_cango dir x st i;
	x = cmap->cmapi;
	st = cmap_linest(cmapi);
	if(dir == n_obj) {
		if(st == ndead || x > nsbreak) rfalse;
		i = cmapi;
		do { if(i == 0) rfalse;
		} until(cmap->--i == x);
		if(cmap_linest(i) == nsbreak or sdead) rfalse;
	}
	if(dir == s_obj) {
		if(st == sdead || x > nsbreak) rfalse;
		i = cmapi;
		do { if(cmap->++i == endcmap) rfalse;
		} until(cmap->i == x);
		if(cmap_linest(i) == nsbreak or ndead) rfalse;
	}
	if(dir == e_obj) {
		i = cmapi + 1;
		if(x == edead || st > 100) rfalse;
		x = cmap->i;
		if(x == endcmap or wdead or ewbreak || (50 < x && x <= nsbreak))
			rfalse;
	}
	if(dir == w_obj) {
		i = cmapi - 1;
		if(x == wdead || st > 100 || cmap->i == st or edead or ewbreak)
			rfalse;
	}
	return i;
];

[ cmap_check x i st n s e w;
	cmapi = 0;
	cmap_err(51 <= cmap->0 && cmap->0 <= nsbreak,
		"cmap->0 must be an east-west number or ndead, sdead, nspass");
	for(cmapi = 0: : ++cmapi) {
		x = cmap->cmapi;
		cmap_err(1 <= x && x <= endcmap,"cmap value out of range");
		if(x == endcmap) break;
		if(51 <= x && x <= nsbreak) {
			st = x;
			for(i = cmapi + 1: cmap->i ~= endcmap: ++i)
				cmap_err(cmap->i ~= x,"duplicated east-west row");
		} else cmap_err(x <= 50 || st <= 100,"edead, wdead, ewpass and
				ewbreak can only be used with an east-west row");
	}
	for(cmapi = 0: : ++cmapi) {
		x = cmap->cmapi;
		if(x == endcmap) break;
		if(51 <= x && x <= nsbreak) st = x;
		else {
			if(x ~= ewbreak && st ~= nsbreak) {
				n = cmap_cango(n_obj); s = cmap_cango(s_obj);
				e = cmap_cango(e_obj); w = cmap_cango(w_obj);
				switch(x) {
				edead: cmap_err(w ~= 0,"need west exit");
				wdead: cmap_err(e ~= 0,"need east exit");
				ewpass: cmap_err(w ~= 0 && e ~= 0,"need both east and west exits");
				default:
					switch(st) {
					ndead: cmap_err(n ~= 0,"need north exit");
					sdead: cmap_err(s ~= 0,"need south exit");
					nspass: cmap_err(n ~= 0 && s ~= 0,"need both north and south exits");
					default: cmap_err((n ~= 0 || s ~= 0) && (e ~= 0 || w ~= 0),
						"need both (north or south) and (east or west) exits");
					}
				}
			}
		}
	}
	cmap_first = 0;
];

[ cmap_create i b x st top first;
	for(i = 0: : ++i) {
		switch(cmap->i) {
		endcmap: jump DONE;
		1 to 50,edead,wdead,ewpass:
			if(st == nsbreak) break;
			if(b ~= 0) { ++b; break; }
			x = corner.create();
			if(x == 0) { ++b; break; }
			jump INSERT;
		ewbreak: ;
		128 to 255:
			cmap->i = cmap->i - 128;
			x = cmap_first;
			cmap_first = cmap_first.nxtcnr;
.INSERT;	if(top ~= 0) top.nxtcnr = x; else first = x;
			top = x;
		default: st = x;
		}
	}
.DONE;
	if(b ~= 0) {
		print "error in cmap: need to set cmap_alloc to ",cmap_alloc + b;
		new_line; quit;
	}
	cmap_first = first;
];

[ cmap_static cnr i x;
	cmapi = i;
	x = cmap->i;
	cmap_err(x < 128,"a static already assigned");
	for(i = cmap_first: i ~= 0: i = i.nxtcnr)
		if(i == cnr) {
			print "error in cmap: ",(name)cnr," re static-ed";
			new_line; quit;
		}
	if(x < 51) cmap_err(cmap_linest(cmapi) ~= nsbreak,"not a valid corner");
	else cmap_err(x ~= ewbreak,"not a valid corner");
	cmap->cmapi = x + 128;
	cnr.nxtcnr = cmap_first;
	x = cnr;
	for(i = 0: i < cmapi: ++i)
		if(cmap->i >= 128) x = x.nxtcnr;
	if(x == cnr) cmap_first = x;
	else { cnr.nxtcnr = x.nxtcnr; x.nxtcnr = cnr; }
];
