#include #include #include #include #include "obj.h" #include "vars.h" #include "pline.h" #include "structs.h" #include "scrsyms.h" #include "display.h" #include "objtypes.h" #include "obj-map.h" #define OBJMAP(o) ((MAP *)(o->private)) typedef enum { AMT_UP = 1, AMT_DN, AMT_GATE } AMT; typedef struct map MAP; typedef struct automap AUTOMAP; struct automap { AUTOMAP *link; AUTOMAP *backlink; AMT t; int gatex; int gatey; OBJ *to; int odx; int ody; } ; struct map { char *label; int minx; int maxx; int miny; int maxy; char **map; AUTOMAP *autos; AUTOMAP *autoback; } ; static MAP *mapforobj(OBJ *o) { if (o->type != OBJ_MAP) panic("non-map where map needed"); return(o->private); } int map_blank(OBJ *o) { MAP *m; m = mapforobj(o); return(!m->map && !m->label); } const char *map_label(OBJ *o) { MAP *m; m = mapforobj(o); return(m->label); } void map_setlabel(OBJ *o, const char *newlabel) { MAP *m; m = mapforobj(o); free(m->label); m->label = newlabel ? strdup(newlabel) : 0; } #define FOO(x) int map_##x(OBJ *o) { MAP *m; m = mapforobj(o); return(m->x); } FOO(minx) FOO(miny) FOO(maxx) FOO(maxy) #undef FOO char map_charat(OBJ *o, int x, int y) { MAP *m; m = mapforobj(o); if ( !m->map || (x < m->minx) || (x > m->maxx) || !m->map[x-m->minx] || (y < m->miny) || (y > m->maxy) ) return(SYM_OOS); return(m->map[x-m->minx][y-m->miny]); } int map_setcharat(OBJ *o, int x, int y, char c) { MAP *m; int new; int i; int j; char *col; char oc; m = mapforobj(o); if (m->map == 0) { m->map = malloc(17*sizeof(char *)); for (i=0;i<17;i++) m->map[i] = 0; m->minx = x - 8; m->maxx = x + 8; m->miny = y - 5; m->maxy = y + 5; } if (x < m->minx) { new = x - 8; m->map = realloc(m->map,(m->maxx+1-new)*sizeof(char *)); bcopy(m->map,m->map+(m->minx-new),(m->maxx+1-m->minx)*sizeof(char *)); for (i=m->minx-new-1;i>=0;i--) m->map[i] = 0; m->minx = new; } else if (x > m->maxx) { new = x + 8; m->map = realloc(m->map,(new+1-m->minx)*sizeof(char *)); j = new - m->minx; for (i=m->maxx+1-m->minx;i<=j;i++) m->map[i] = 0; m->maxx = new; } if (y < m->miny) { new = y - 5; for (i=m->maxx-m->minx;i>=0;i--) { col = m->map[i]; if (col) { col = realloc(col,m->maxy+1-new); bcopy(col,col+(m->miny-new),m->maxy+1-m->miny); memset(col,SYM_OOS,m->miny-new); m->map[i] = col; } } m->miny = new; } if (y > m->maxy) { new = y + 5; for (i=m->maxx-m->minx;i>=0;i--) { col = m->map[i]; if (col) { col = realloc(col,new+1-m->miny); memset(col+(m->maxy+1-m->miny),SYM_OOS,new-m->maxy); m->map[i] = col; } } m->maxy = new; } col = m->map[x-m->minx]; if (! col) { col = malloc(m->maxy+1-m->miny); memset(col,SYM_OOS,m->maxy+1-m->miny); m->map[x-m->minx] = col; } oc = col[y-m->miny]; if ( (oc == c) || ( (col[y-m->miny] == SYM_TWALL) && ((c == SYM_HWALL) || (c == SYM_VWALL)) ) ) return(0); col[y-m->miny] = c; return(1); } static OBJ *get_blank_map(void) { INVOBJ *io; for (io=you->invent.inv;io;io=io->link) { if ((io->v[0]->type == OBJ_MAP) && map_blank(io->v[0])) { inventory_split_n(io,1,find_xwi(&you->invent)); return(io->v[0]); } } return(0); } static AUTOMAP *find_auto(OBJ *o, AMT kind, ...) { MAP *m; int x; int y; va_list argp; AUTOMAP **ap; AUTOMAP *a; m = mapforobj(o); if (kind == AMT_GATE) { va_start(argp,kind); x = va_arg(argp,int); y = va_arg(argp,int); va_end(argp); } ap = &m->autos; while ((a = *ap)) { if (a->to == 0) { *ap = a->link; free(a); continue; } if (a->t == kind) { switch (kind) { case AMT_UP: case AMT_DN: return(a); break; case AMT_GATE: if ((a->gatex == x) && (a->gatey == y)) return(a); break; } } ap = &a->link; } return(0); } static void setup_updn_autos(OBJ *o1, AMT d1, OBJ *o2, AMT d2, int odx, int ody) { AUTOMAP *a; MAP *m1; MAP *m2; m1 = mapforobj(o1); m2 = mapforobj(o2); a = malloc(sizeof(AUTOMAP)); a->t = d1; a->to = o2; a->odx = odx; a->ody = ody; a->link = m1->autos; m1->autos = a; a->backlink = m2->autoback; m2->autoback = a; a = malloc(sizeof(AUTOMAP)); a->t = d2; a->to = o1; a->odx = - odx; a->ody = - ody; a->link = m2->autos; m2->autos = a; a->backlink = m1->autoback; m1->autoback = a; } static void setup_gate_autos(OBJ *o1, int g1x, int g1y, OBJ *o2, int g2x, int g2y, int odx, int ody) { AUTOMAP *a; MAP *m1; MAP *m2; m1 = mapforobj(o1); m2 = mapforobj(o2); a = malloc(sizeof(AUTOMAP)); a->t = AMT_GATE; a->gatex = g1x; a->gatey = g1y; a->to = o2; a->odx = odx; a->ody = ody; a->link = m1->autos; m1->autos = a; a->backlink = m2->autoback; m2->autoback = a; a = malloc(sizeof(AUTOMAP)); a->t = AMT_GATE; a->gatex = g2x; a->gatey = g2y; a->to = o1; a->odx = - odx; a->ody = - ody; a->link = m2->autos; m2->autos = a; a->backlink = m1->autoback; m1->autoback = a; } static int map_auto_switch_updn(AMT out, AMT back, const char *tag) { AUTOMAP *a; OBJ *m; a = find_auto(map,out); if (a && !inv_present(&you->invent,a->to)) a = 0; if (! a) { m = get_blank_map(); if (! m) { pline("[Auto-switch failed - no blank map available]"); return(0); } setup_updn_autos(map,out,m,back,-mapox,-mapoy); map = m; mapox = 0; mapoy = 0; OBJMAP(m)->label = strdup(tag); pline("[Map auto-switched to a new map]"); return(1); } map = a->to; mapox += a->odx; mapoy += a->ody; pline("[Map auto-switched]"); return(1); } int map_auto_switch_gate(LOC *lc, const char *tag) { AUTOMAP *a; OBJ *m; a = find_auto(map,AMT_GATE,lc->x,lc->y); if (! a) { m = get_blank_map(); if (! m) { pline("[Map auto-switch failed - no blank map available]"); return(0); } setup_gate_autos(map,lc->x,lc->y,m,lc->to->x,lc->to->y,-mapox,-mapoy); map = m; mapox = 0; mapoy = 0; OBJMAP(m)->label = strdup(tag); pline("[Map auto-switched to a new map]"); return(1); } map = a->to; mapox += a->odx; mapoy += a->ody; pline("[Map auto-switched]"); return(1); } int map_auto_switch_up(const char *tag) { return(map_auto_switch_updn(AMT_UP,AMT_DN,tag)); } int map_auto_switch_dn(const char *tag) { return(map_auto_switch_updn(AMT_DN,AMT_UP,tag)); } OBJ *map_auto_link_up(OBJ *m, int *oxp, int *oyp) { AUTOMAP *a; a = find_auto(m,AMT_UP); if (! a) return(0); *oxp += a->odx; *oyp += a->ody; return(a->to); } OBJ *map_auto_link_dn(OBJ *m, int *oxp, int *oyp) { AUTOMAP *a; a = find_auto(m,AMT_DN); if (! a) return(0); *oxp += a->odx; *oyp += a->ody; return(a->to); } static void remove_autoback(OBJ *m, AUTOMAP *rem) { AUTOMAP **ap; AUTOMAP *a; ap = &OBJMAP(m)->autoback; while ((a = *ap)) { if (a == rem) { *ap = a->backlink; return; } ap = &a->backlink; } } void map_complete(OBJ *o, LEVEL *lv) { int x; int y; LOC *l; for (x=0;xcells[x][0]; for (y=0;ylabel = 0; m->minx = LEV_X; m->maxx = 0; m->miny = LEV_Y; m->maxy = 0; m->map = 0; m->autos = 0; m->autoback = 0; o->private = m; return(o); } static void old(OBJ *o) { MAP *m; int x; AUTOMAP *a; m = mapforobj(o); for (x=m->minx;x<=m->maxx;x++) free(m->map[x]); for (a=m->autoback;a;a=a->backlink) a->to = 0; while (m->autos) { a = m->autos; m->autos = a->link; remove_autoback(a->to,a); free(a); } free(m->map); free(m); } static void format(FILE *f, INVOBJ *io) { OBJ *o; MAP *m; if (io->dispn > 1) { fprintf(f,"%d blank maps",io->dispn); return; } o = io->v[0]; m = mapforobj(o); if (map_blank(o)) { fprintf(f,"a blank map"); } else { fprintf(f,"a map ("); if (m->label) fprintf(f,"label=%s",m->label); else fprintf(f,"no label"); if (m->map) { fprintf(f,", x=[%d..%d], y=[%d..%d])",m->minx,m->maxx,m->miny,m->maxy); } else { fprintf(f,", no content)"); } } if (o == map) fprintf(f," (in use)"); } static int identical(OBJ *o1, OBJ *o2) { return((o1!=map)&&(o2!=map)&&map_blank(o1)&&map_blank(o2)); } static int collapsible(OBJ *o1, OBJ *o2) { return(identical(o1,o2)); } static int identified(INVOBJ *io __attribute__((__unused__))) { return(1); } static INVOBJ *identify(INVOBJ *io) { return(io); } OBJOPS objops_map = { &new, &old, &format, 0, 0, &collapsible, &identical, &std_split, &identified, &identify };