/* * This file includes various "convert to text form" functions. Since * they are debugging code, invalid values get printed in decimal * (usually into a static buffer) and returned rather than provoking * panics. */ #include #include #include #include #include #include #include #include "obj.h" #include "vars.h" #include "dice.h" #include "time.h" #include "util.h" #include "pline.h" #include "trail.h" #include "display.h" #include "structs.h" #include "signals.h" #include "montypes.h" #include "mon-@-you.h" #include "debug.h" #define TRACK_EXIT (-1) /* pseudo value used only here */ /* * Check that a LOC is a legitimate cell on a LEVEL. * * This is not possible to do with reasonable efficiency in fully * portable C; the only way I know of to do that is to scan every LOC * of the LEVEL and see if it equals the argument. * * This version depends on nonportable properties of pointer->integer * conversion. */ static int ok_loc_(LOC *l, LEVEL *lv) { return( ((unsigned long int)l >= (unsigned long int)&lv->cells[0][0]) && ((unsigned long int)l <= (unsigned long int)&lv->cells[LEV_X-1][LEV_Y-1]) ); } /* * See if the LOC is a valid location. The LEVEL is checked first; it * can be thought of as an `expected' level. */ static int ok_loc(LOC *l, LEVEL *lv) { int n; if (ok_loc_(l,lv)) return(1); for (n=0;ncells[x][0]; fprintf(o,"%d: %d \r",lno,x); for (y=0;yon != lv) { fprintf(f,"on wrong: (%d,%d,%d)\n",lv->levelno,x,y); l->on = lv; } if ((l->x != x) || (l->y != y)) { fprintf(f,"xy wrong: (%d,%d,%d) (%d,%d)\n",lv->levelno,x,y,l->x,l->y); l->x = x; l->y = y; } l ++; } } } fprintf(o,"Dumping levels...\r\n"); for (lno=0;lnolevelno); fprintf(f,"flags"); if (lv->flags & LVF_WRAPAROUND) fprintf(f," WRAPAROUND"); if (lv->flags & LVF_DRIFT) fprintf(f," DRIFT"); if (lv->flags & LVF_SEEN) fprintf(f," SEEN"); fprintf(f,"\n"); fprintf(f,"traps"); if (setjmp(bad)) { fprintf(f,""); } else { TRAP *t; TRAP tp; for (t=lv->traps;t;t=t->link) { tp = *t; fprintf(f,"%d/",(int)tp.type); if (tp.loc) { if (ok_loc(tp.loc,lv)) { if (tp.loc->on == lv) { fprintf(f,"(%d,%d)",tp.loc->x,tp.loc->y); } else { fprintf(f,"(%d,%d,%d)",tp.loc->on->levelno,tp.loc->x,tp.loc->y); } } else { fprintf(f,"(bad)"); } } else { fprintf(f,"(null)"); } } } fprintf(f,"\n"); if (setjmp(bad)) goto unexsig; if (lv->up) { if (ok_lev(lv->up)) { fprintf(f,"up %d\n",lv->up->levelno); } else { fprintf(f,"up bad\n"); } } else { fprintf(f,"up null\n"); } if (lv->down) { if (ok_lev(lv->down)) { fprintf(f,"down %d\n",lv->down->levelno); } else { fprintf(f,"down bad\n"); } } else { fprintf(f,"down null\n"); } for (x=0;xcells[x][0]; for (y=0;ytype) { case LOC_ROCK: fprintf(f,"R-"); break; case LOC_WALL: fprintf(f,"W"); if (0) { case LOC_SDOOR: fprintf(f,"S"); } if (0) { case LOC_DOOR: fprintf(f,"D"); } if (l->walldoor > 15) { fprintf(f,"(%x)",l->walldoor); } else { fprintf(f,"%x",l->walldoor); } break; case LOC_CAVE: switch (l->cavetype) { case LOC_JUSTCAVE: fprintf(f,"C-"); break; case LOC_STAIRS_U: fprintf(f,"C<"); break; case LOC_STAIRS_D: fprintf(f,"C>"); break; default: fprintf(f,"C(%d)",(int)l->cavetype); break; } break; case LOC_GATE: switch (l->gatetype) { case LOC_GATE_IN: fprintf(f,"Gi"); break; case LOC_GATE_OUT: fprintf(f,"Go"); break; default: fprintf(f,"G(%d)",(int)l->gatetype); break; } break; default: fprintf(f,"(%d)",(int)l->type); break; } if (l->flags & LF_FLAG) putc('F',f); if (l->flags & LF_FLAGB) putc('B',f); if (l->flags & LF_VISIBLE) putc('V',f); for (t=0;ttracks[t] == 0) { putc('0',f); } else if (ok_loc(l->tracks[t],lv)) { if (l->tracks[t]->on != l->on) { fprintf(f,"(%d,%d,%d)",l->tracks[t]->on->levelno,l->tracks[t]->x,l->tracks[t]->y); } else { fprintf(f,"(%d,%d)",l->tracks[t]->x,l->tracks[t]->y); } } else { fprintf(f,"(bad:%p)",(void *)l->tracks[t]); } } if (l->objs.inv) { fprintf(f,"o(%p)",(void *)l->objs.inv); /* XXX dump objects here */ } if (l->monst) { fprintf(f,"m(%p)",(void *)l->monst); } if (l->to) { if (ok_loc(l->to,l->to->on)) { fprintf(f,"t(%d,%d,%d)",l->to->on->levelno,l->to->x,l->to->y); } else { fprintf(f,"t(bad)"); } } l ++; } putc('\n',f); } if (lv->shops) { SHOP *sp; SHOP s; fprintf(f,"shops\n"); for (sp=lv->shops;sp;sp=sp->link) { fprintf(f,"%p",(void *)sp); if (setjmp(bad)) { fprintf(f,"\n"); continue; } else { s = *sp; } if (s.on == 0) { fprintf(f," on null"); } else if (s.on != lv) { fprintf(f," on %p (want %p)",(void *)s.on,(void *)lv); } else { fprintf(f," on correct"); } fprintf(f," shkname "); if (setjmp(bad)) { fprintf(f,""); } else { fprintf(f,"%s",s.shkname); } fprintf(f," type %d",s.type); switch (s.type) { case SHOP_TYPE_GENERAL: fprintf(f," [GENERAL]"); break; default: fprintf(f," (unknown)"); break; } fprintf(f," at (%d,%d) size (%d,%d) ([%d..%d] X [%d..%d]), door (%d,%d)\n",s.pos.x,s.pos.y,s.size.x,s.size.y,s.pos.x,s.pos.x+s.size.x-1,s.pos.y,s.pos.y+s.size.y-1,s.door.x,s.door.y); } } else { fprintf(f,"no shops\n"); } } fprintf(o,"Dumping monster types...\r\n"); fprintf(f,"Monster types:\n"); for (i=0;i"); else fprintf(f,"%s",mt->name); fprintf(f," letter %c",mt->letter); fprintf(f," probs"); for (j=0;jinfo->probs[j]); fprintf(f," new %p monctl %p\n",(void *)mt->info->new,(void *)mt->info->monctl); } fprintf(o,"Dumping monsters...\r\n"); fprintf(f,"Monsters:\n"); if (setjmp(bad)) { fprintf(f,"\n"); } else { for (m=mchain;m;m=m->link) { MONST M; static struct { int flag; const char *name; } mflags[] = { { MF_DEAD, "DEAD" }, { MF_ASLEEP, "ASLEEP" }, { MF_INVISIBLE, "INVISIBLE" }, { MF_SEE_INVISIBLE, "SEE_INVISIBLE" }, { MF_TELEPATHIC, "TELEPATHIC" }, { MF_SAWYOU, "SAWYOU" }, { MF_TRACKING, "TRACKING" }, { 0, 0 } }; int first; int flg; fprintf(f,"%p:",(void *)m); M = *m; fprintf(f," type "); for (i=0;i",(void *)M.type); } fprintf(f," sym %c hp %d",M.symbol,M.hp); fprintf(f," flags %x <",M.flags); first = 1; flg = M.flags; for (i=0;mflags[i].name;i++) { if (flg & mflags[i].flag) { fprintf(f,"%s%s",first?"":",",mflags[i].name); first = 0; flg &= ~mflags[i].flag; } } if (flg) fprintf(f,"%s%x",first?"":",",flg); fprintf(f,"> speed %g age %d you (%d,%d) private %p ops %p invent ",M.speed/(double)TIMESCALE,M.age,M.you.x,M.you.y,(void *)M.private,(void *)M.ops); fprintf(f,M.invent.inv?"%p loc ":"null loc ",(void *)M.invent.inv); /* XXX dump objects here */ if (M.loc) { if (ok_loc(M.loc,&Levels[0])) { fprintf(f,"%d,%d,%d",M.loc->on->levelno,M.loc->x,M.loc->y); } else { fprintf(f,"bad"); } } else { fprintf(f,"null"); } fprintf(f," lastloc "); if (M.lastloc) { if (ok_loc(M.lastloc,&Levels[0])) { fprintf(f,"%d,%d,%d",M.lastloc->on->levelno,M.lastloc->x,M.lastloc->y); } else { fprintf(f,"bad"); } } else { fprintf(f,"null"); } fprintf(f,"\n"); } fclose(f); } fprintf(o,"Dumping core...\r\n"); } abort(); } /* * Check that a monster is in a sane location; if not, bugcheck. */ void debug_checkm(MONST *m) { if (! ok_loc(m->loc,&Levels[0])) { debugsig(0); } } /* * Set various fatal signals to call the handler passed as argument. */ static void setdebugsigs(void (*how)(int)) { signal(SIGQUIT,how); signal(SIGILL,how); signal(SIGEMT,how); signal(SIGFPE,how); signal(SIGBUS,how); signal(SIGSEGV,how); signal(SIGSYS,how); signal(SIGPIPE,how); } /* * Catch various fatal signals with debugsig (see above). */ void debugcatch(void) { setdebugsigs(&debugsig); } /* * Return the text name of a LOC type. */ static const char *typename(LOC *lc) { static char buf[10]; switch (lc->type) { case LOC_ROCK: return("ROCK"); break; case LOC_WALL: return("WALL"); break; case LOC_SDOOR: return("SDOOR"); break; case LOC_CAVE: return("CAVE"); break; case LOC_GATE: return("GATE"); break; case LOC_DOOR: return("DOOR"); break; } sprintf(&buf[0],"%d",lc->type); return(&buf[0]); } /* * Return the text name of a LOC's subtype. */ static const char *subtype(LOC *lc) { static char buf[10]; switch (lc->type) { case LOC_WALL: case LOC_SDOOR: switch (lc->walldoor) { case LOC_UWALL: return("UWALL"); break; case LOC_HWALL: return("HWALL"); break; case LOC_VWALL: return("VWALL"); break; case LOC_TWALL: return("TWALL"); break; } sprintf(&buf[0],"%d",lc->walldoor); break; case LOC_CAVE: switch (lc->cavetype) { case LOC_JUSTCAVE: return("JUSTCAVE"); break; case LOC_STAIRS_U: return("STAIRS U"); break; case LOC_STAIRS_D: return("STAIRS D"); break; } sprintf(&buf[0],"%d",(int)lc->cavetype); break; case LOC_GATE: switch (lc->gatetype) { case LOC_GATE_IN: return("GATE IN"); break; case LOC_GATE_OUT: return("GATE OUT"); break; } sprintf(&buf[0],"%d",(int)lc->gatetype); break; case LOC_DOOR: switch (lc->walldoor) { case LOC_CHDOOR: return("CHDOOR"); break; case LOC_CVDOOR: return("CVDOOR"); break; case LOC_OHDOOR: return("OHDOOR"); break; case LOC_OVDOOR: return("OVDOOR"); break; } sprintf(&buf[0],"%d",lc->walldoor); break; default: sprintf(&buf[0],"(type%d)",(int)lc->type); break; } return(&buf[0]); } /* * Return (via a static buffer) a flag bits string for a LOC. This * does not cover all the flag bits, just the ones I think worth * mentioning in debugging output. */ static const char *flags(LOC *lc) { static char buf[256]; static struct { int bit; const char *name; } list[] = { { LF_SHOP, "SHOP" }, { LF_VAULT, "VAULT" }, { LF_VISIBLE, "VISIBLE" } }; char *cp; int bits; int i; cp = &buf[0]; bits = lc->flags; for (i=0;i= 0) return(lc->tracks[tracktype]); switch (tracktype) { case TRACK_EXIT: { LOC *best; int nb; LOC *lc2; int i; void maybesave(LOC *l) { if ( (nb == 0) || (l->exitdist < best->exitdist) ) { best = l; nb = 1; } else if (l->exitdist == best->exitdist) { nb ++; if (onein(nb)) best = l; } } if (lc->exitdist == 0) return(0); nb = 0; for (i=0;i<8;i++) { lc2 = movecell(lc,delta[i][0],delta[i][1],1); if ( (lc2->type == LOC_GATE) || (lc2->type == LOC_DOOR) || (lc2->type == LOC_SDOOR) || (lc2->type == LOC_CAVE) ) maybesave(lc2); } if ( ( (lc->type == LOC_GATE) || ( (lc->type == LOC_CAVE) && ( (lc->cavetype == LOC_STAIRS_U) || (lc->cavetype == LOC_STAIRS_D) ) ) ) && (lc2=lc->to) ) maybesave(lc2); return(nb?best:0); } break; } panic("bad tracktype %d in debug follow_track",tracktype); } /* * Dump out info on a monster. This is designed for in-game player use * from debugging code. */ static void dump_monster(MONST *m) { int lno; INVOBJ *io; const char *prompt; DLLS line(FILE *f) { switch (lno++) { case 1: fprintf(f,"%s (%c) HP=%d/%d heal=%d age=%d", m->type->name, m->symbol, m->hp, m->maxhp, m->heal, m->age ); break; case 2: fprintf(f," speed=%g created=%g you=(%d,%d)", m->speed/(double)TIMESCALE, m->created/(double)TIMESCALE, m->you.x, m->you.y ); break; case 3: fprintf(f," flags ="); if (m->flags & MF_DEAD) fprintf(f," DEAD"); if (m->flags & MF_ASLEEP) fprintf(f," ASLEEP"); if (m->flags & MF_INVISIBLE) fprintf(f," INVISIBLE"); if (m->flags & MF_SEE_INVISIBLE) fprintf(f," SEE_INVISIBLE"); if (m->flags & MF_TELEPATHIC) fprintf(f," TELEPATHIC"); if (m->flags & MF_SAWYOU) fprintf(f," SAWYOU"); if (m->flags & MF_TRACKING) fprintf(f," TRACKING"); break; default: if (! io) return(DL_L_DONE); format_inv_line(io,f); io = io->link; break; } return(DL_L_MORE); } if (! m) return; lno = 1; io = m->invent.inv; prompt = ""; display_list(&line,&prompt,&dl_justmore); } /* * This is an interactive look-around-the-dungeon debugging interface. * It lets the player inspect the entire dungeon, with time frozen. * * The interface can be seen in the code below following the getch(). */ void probe(void) { LOC *lc; LOC *trk; LEVEL *lastlevel; int ch; int x; int y; static int tracktype = TRACK_SMART; lastlevel = 0; lc = you->loc; while (1) { if (lc->on != lastlevel) { clear(); lvdisp(lc->on); lastlevel = lc->on; } mvprintw(LINES-2,0,"x %d y %d %s track ",lc->x,lc->y,trackname(tracktype)); trk = follow_track(lc,tracktype); if (! trk) { printw("null"); } else { if (lc->on == trk->on) { printw("(%d,%d)",trk->x,trk->y); } else { printw("(%d,%d) on %s",trk->x,trk->y,trk->on->shortname); } } if (tracktype >= 0) printw(" tracktime %g",lc->tracktime[tracktype]/(double)TIMESCALE); clrtoeol(); mvprintw(LINES-1,0,"type %s subtype %s flags %s", typename(lc),subtype(lc),flags(lc)); if (lc->objs.inv) printw(" (objs)"); clrtoeol(); move(lc->y,lc->x); refresh(); ch = getch(); if (dirkey(ch,&x,&y,0,0,0)) { lc = movecell(lc,x,y,1); } else { switch (ch) { case 'i': show_inventory(&lc->objs,"",&showinvent_all); lastlevel = 0; break; case 'f': if (lc->to) lc = lc->to; break; case 'm': dump_monster(lc->monst); lvdisp(lc->on); break; case 't': if (trk) lc = trk; break; case 'T': move(LINES-2,0); clrtoeol(); mvprintw(LINES-1,0,"Track xit, umb, or mart? "); clrtoeol(); refresh(); while (1) { switch (getch()) { case 'e': case 'E': tracktype = TRACK_EXIT; break; case 'd': case 'D': tracktype = TRACK_DUMB; break; case 's': case 'S': tracktype = TRACK_SMART; break; case '\33': break; default: continue; break; } break; } break; case 'W': if ( (lc->type == LOC_CAVE) || ( (lc->type == LOC_DOOR) && (lc->walldoor & LOC_DOOR_OPEN) ) ) { clear(); teleport_you(lc); return; } break; case '<': if ((lc->on->index > 0) && (lc->on->index < DUNGEON_LEVELS)) { lc = &levels[lc->on->index-1].cells[lc->x][lc->y]; } else { LEVEL *lv; int x; int y; LOC *lc2; lv = lc->on; for (x=0;xcells[x][y]; if ( (lc2->type == LOC_GATE) && (lc2->gatetype == LOC_GATE_OUT) ) { lc = &lc2->to->on->cells[lc->x][lc->y]; x = LEV_X; /* aka "break 2" */ y = LEV_Y; } } } } break; case '>': if ((lc->on->index >= 0) && (lc->on->index < DUNGEON_LEVELS-1)) { lc = &levels[lc->on->index+1].cells[lc->x][lc->y]; } else { LEVEL *lv; int x; int y; LOC *lc2; lv = lc->on; for (x=0;xcells[x][y]; if ( (lc2->type == LOC_GATE) && (lc2->gatetype == LOC_GATE_IN) ) { lc = &lc2->to->on->cells[lc->x][lc->y]; x = LEV_X; /* aka "break 2" */ y = LEV_Y; } } } } break; case '\33': clear(); return; break; } } } } /* * Compute and display the topology of the dungeon. * * This works on just the standard dungeon levels. It effectively * collapses all connected cells into a single point, with up and down * stairs being links between points. It then displays one line per * level, giving, for the points on that level, the number of cells in * that point and the links up (^) and down (v), with destinations * given in terms of per-level serial numbers for points. For * example, * * 12 1 0[312]:^0/0/0/0/1/0/0v1/0/0 * 13 2 1[21]:^0v0 0[326]:^0/0v0/0 * 14 1 0[346]:^1/0/0v0 * 15 1 0[296]:^0v0 * * says that level 13 (the 12 line - note the numbers are 0-origin, * whereas conventional level numbers are 1-origin) consists of a * single 312-LOC blob, level 14 consists of two blobs, one (#0) of * 326 LOCs and the other (#1) of 21 LOCs, level 15 a single 346-LOC * blob, and level 16 a single 296-LOC blob. Level 13 has seven * stairs up, six to level 12's blob 0 and 1 to blob 1; it has three * stairs down, two to level 14's blob 0 and one to its blob 1. On * level 14, blob 0 has two stairs up and two down; each of the four * leads to blob on the relevant level. Blob 1 has one stair each up * and down, leading to blob 0. (In this case, since levels 13 and 15 * consist of only a single blob, all stairs to either must lead to * blob 0.) Level 15 has three stairs up, two to blob 0 and one to * blob 1; it has only one stair down, leading to level 16 blob 0. We * can perhaps draw this fragment as * * Lv.13 Lv.14 Lv.15 Lv.16 * * 312 326 346 296 * <---+---------------+---------------+---------------+---> * <---+---------------+---------------+ * <---+ | * <---+ 21 | * <---+---------------+---------------+ * <---+ * | * <---+ * * As another example, in * * 13 1 0[294]:^0v3/0 * 14 4 3[108]:^0v1 2[14]:v1 1[14]:v1 0[130]:^0v1 * 15 3 2[11]: 1[315]:^3/2/1/0v2/1/0 0[7]:v0/0 * 16 3 2[42]:^1 1[33]:^1 0[225]:^1/0/0v0 * 17 2 1[125]:v0 0[220]:^0v0 * 18 1 0[325]:^1/0v0/0/0 * * we have a more complex sturcture. Level 14 is a single blob; it * has only one stair up and two down. The stairs down lead to level * 15 blobs 0 and 3. Level 15 has four blobs; blobs 0 and 3 are very * roughly equal in size (130 and 108 LOCs) and each one has a link up * to level 14 blob 0 and a link down to level 16 blob 1. It also has * two small (14-LOC) blobs, each of which has a link down only, to * level 16 blob 1. Level 16 has three blobs. Blob 2 has 11 LOCs and * has no stairs at all (it's a vault). Blob 1 has 315 LOCs and links * to everything above and below, one stairwell each. Blob 0 is small * (only 7 LOCs) and has two stairs, both down to blob 0 on level 17. * Level 17 has three blobs, with the bulk of the level (225 LOCs) in * blob 0, linked to blob 1 (one stair) and blob 0 (two stairs) above * and blob 0 (one stair) below; blobs 1 and 2 are small and have just * one stair, to blob 1 above. Etc. Drawing this (more compactly), * * Lv.14 Lv.15 Lv.16 Lv.17 Lv.18 Lv.19 * * * <---+-------+ 7-------+------220------+---> * | 130 +------225 325--> * | | | | * | +-------+-------+ 125------+---> * | | * 294 14------+-------33 * | 315 * | 14------+-------42 * | | * +------108------+ * * 11 * * (In these examples, the graph turns out to be not only planar but * easy to draw. Consider the last example and imagine if level 16's * blob 2 had stairs up to level 15 blob 3 and down to level 17 blob * 0; it would have been impossible to draw without rerouting lines or * reordering blobs, and slightly more complex cases can actually lead * to nonplanar graphs; consider * * 10 3 2[50]^0v2/1/0 1[50]^0v2/1/0 0[50]^0v2/1/0 * 11 3 2[50]^2/1/0v0 1[50]^2/1/0v0 0[50]^2/1/0v0 * * which is possible, if unlikely, and contains K(3,3), one of the two * basic nonplanar graphs, in the resulting graph.) * * The code that's #if 0 here appears to be some sort of attempt to * mechanically generate boxology, conceptually like the above * examples. Presumably it doesn't work. */ void structure(void) { __label__ throw_out; typedef struct part PART; typedef struct link LINK; struct part { PART *link; PART *levlink; LEVEL *lev; unsigned char id; unsigned int size; int xo; LINK *up; LINK *dn; } ; struct link { LINK *link; LINK *uplink; LINK *dnlink; PART *upp; LOC *uploc; PART *dnp; LOC *dnloc; } ; int x; int y; int z; LEVEL *lev; LOC *lc; unsigned char id[DUNGEON_LEVELS][LEV_X][LEV_Y]; unsigned char nid[DUNGEON_LEVELS]; unsigned char curid; PART *lparts[DUNGEON_LEVELS]; TRAIL *q; TRAIL **qt; TRAIL *t; PART *parts; PART *p; LINK *links; LINK *ln; PART *part0; #if 0 int z0; int z1; int i; int j; #endif int rock(LOC *l) { switch (l->type) { case LOC_ROCK: case LOC_WALL: return(1); break; default: return(0); break; } } void maybe_q_loc(LOC *l) { TRAIL *n; if ((l->flags & LF_FLAG) || rock(l)) return; n = newtrail(); *qt = n; n->link = 0; qt = &n->link; n->loc = l; l->flags |= LF_FLAG; id[z][l->x][l->y] = curid; p->size ++; } void all_neighbours(LOC *l, void (*fn)(LOC *)) { int dx; int dy; int x; int y; for (dx=-1;dx<=1;dx++) { x = l->x + dx; if (l->on->flags & LVF_WRAPAROUND) { if (x < 0) x += LEV_X; else if (x >= LEV_X) x -= LEV_X; } else { if ((x < 0) || (x >= LEV_X)) continue; } for (dy=-1;dy<=1;dy++) { y = l->y + dy; if (l->on->flags & LVF_WRAPAROUND) { if (y < 0) y += LEV_Y; else if (y >= LEV_Y) y -= LEV_Y; } else { if ((y < 0) || (y >= LEV_Y)) continue; } (*fn)(&l->on->cells[x][y]); } } } PART *part_for_loc(LOC *l) { PART *p; int i; if (! (l->flags & LF_FLAG)) panic("impossible stairs"); i = id[l->on->index][l->x][l->y]; for (p=parts;p;p=p->link) { if ((p->lev == l->on) && (p->id == i)) return(p); } panic("nonexistent part"); } void get(void) { if (getch() == 3) goto throw_out; } q = 0; qt = &q; parts = 0; links = 0; for (z=DUNGEON_LEVELS-1;z>=0;z--) { lev = &levels[z]; lparts[z] = 0; for (x=LEV_X-1;x>=0;x--) { for (y=LEV_Y-1;y>=0;y--) { lev->cells[x][y].flags &= ~LF_FLAG; } } nid[z] = 0; for (x=LEV_X-1;x>=0;x--) { for (y=LEV_Y-1;y>=0;y--) { lc = &lev->cells[x][y]; if (lc->flags & LF_FLAG) continue; if (rock(lc)) continue; curid = nid[z]++; p = malloc(sizeof(PART)); p->link = parts; parts = p; p->levlink = lparts[z]; lparts[z] = p; p->lev = lc->on; p->id = curid; p->size = 0; p->up = 0; p->dn = 0; maybe_q_loc(lc); while (q) { t = q; q = q->link; if (! q) qt = &q; lc = t->loc; freetrail(t); all_neighbours(lc,&maybe_q_loc); } } } } part0 = 0; for (z=DUNGEON_LEVELS-1;z>=0;z--) { lev = &levels[z]; for (x=LEV_X-1;x>=0;x--) { for (y=LEV_Y-1;y>=0;y--) { lc = &lev->cells[x][y]; if ((lc->type == LOC_CAVE) && (lc->cavetype == LOC_STAIRS_U)) { ln = malloc(sizeof(LINK)); ln->link = links; links = ln; ln->dnloc = lc; ln->uploc = lc->to; ln->dnp = part_for_loc(lc); if (lc->to) { ln->upp = part_for_loc(lc->to); } else { if (part0) panic("multiple part0s"); part0 = malloc(sizeof(PART)); part0->link = parts; parts = part0; part0->lev = 0; part0->id = 0; part0->size = 0; part0->up = 0; part0->dn = 0; ln->upp = part0; } ln->uplink = ln->dnp->up; ln->dnp->up = ln; ln->dnlink = ln->upp->dn; ln->upp->dn = ln; } } } } if (! part0) panic("no part0"); clear(); for (z=DUNGEON_LEVELS-1;z>=0;z--) { const char *pref; lev = &levels[z]; move(z,0); clrtoeol(); printw(" %d %d",z,nid[z]); for (p=lparts[z];p;p=p->levlink) { printw(" %d[%d]:",p->id,p->size); pref = "^"; for (ln=p->up;ln;ln=ln->uplink) { printw("%s%d",pref,ln->upp->id); pref = "/"; } pref = "v"; for (ln=p->dn;ln;ln=ln->dnlink) { printw("%s%d",pref,ln->dnp->id); pref = "/"; } } } move(LINES-1,0); get(); #if 0 for (z1=DUNGEON_LEVELS-1;z1>=0;) { if (nid[z1] == 1) { z1 --; continue; } i = 0; for (z0=z1;(z0>=0)&&(nid[z0]>1);z0--) i += nid[z0]; z0 ++; if (z1 > z0) { __label__ abort_enumeration; int n[z1+1-z0]; int bestordervec[i]; int bestcrossings; int ordervec[i]; int *orders[z1+1-z0]; PART *partvec0[i]; PART *partvec[i]; int px0[z1+1-z0]; int crossings(void) { int crosscount; int z; int i; PART **pv; PART *p; LINK *l; int i2; PART *p2; LINK *l2; int *o; crosscount = 0; for (z=z0;z0;i--) { p = pv[i]; for (l=p->dn;l;l=l->dnlink) { for (i2=i-1;i2>=0;i2--) { p2 = pv[i2]; for (l2=p2->dn;l2;l2=l2->dnlink) { if ( ( (p2->xo - p->xo) * (l2->dnp->xo - l->dnp->xo) ) < 0) crosscount ++; } } } } } return(crosscount); } void loadpartvec(int z) { int i; int x; x = px0[z]; for (i=n[z]-1;i>=0;i--) { (partvec[x+i]=partvec0[x+orders[z][i]])->xo = i; } } void enumerated(void) { int z; int i; for (z=z0;z<=z1;z++) loadpartvec(z-z0); i = crossings(); if ((bestcrossings < 0) || (i < bestcrossings)) { bestcrossings = i; bcopy(&ordervec,&bestordervec,sizeof(ordervec)); if (i == 0) goto abort_enumeration; } } void enumerate(int m, int *v, int next) { char taken[m]; void try(int x) { int i; if (x < 0) { if (next < 0) { enumerated(); } else { enumerate(n[next],orders[next],next-1); } return; } for (i=m-1;i>=0;i--) { if (! taken[i]) { taken[i] = 1; v[x] = i; try(x-1); taken[i] = 0; } } } bzero(&taken[0],m); try(m-1); } j = 0; for (z=z0;z<=z1;z++) { n[z-z0] = nid[z]; orders[z-z0] = &ordervec[j]; px0[z-z0] = j; for (p=lparts[z],i=0;p;p=p->levlink,i++) partvec0[j+i] = p; if (i != nid[z]) panic("count wrong"); j += i; } for (z=DUNGEON_LEVELS-1;z>=0;z--) { mvaddch(z,0,((z>=z0)&&(z<=z1))?'*':' '); } move(LINES-1,0); clrtoeol(); refresh(); get(); bestcrossings = -1; enumerate(n[z1-z0],orders[z1-z0],z1-z0-1); abort_enumeration:; j = 0; for (z=z0;z<=z1;z++) { orders[z-z0] = &bestordervec[j]; j += nid[z]; } for (z=z0;z<=z1;z++) loadpartvec(z-z0); for (z=z0;z<=z1;z++) { move(z,0); clrtoeol(); printw(" %d %d",z,nid[z]); for (i=0;iid,p->size); pref = "^"; for (ln=p->up;ln;ln=ln->uplink) { printw("%s%d",pref,ln->upp->id); pref = "/"; } pref = "v"; for (ln=p->dn;ln;ln=ln->dnlink) { printw("%s%d",pref,ln->dnp->id); pref = "/"; } } } move(LINES-1,0); clrtoeol(); for (z=z0;z<=z1;z++) { printw(" %d:",z); for (x=0;x %d",bestcrossings); clrtoeol(); get(); } z1 = z0 - 1; } #endif throw_out:; clear(); }