! Copyright by Rick Dague, [email protected]
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; }
];