#include "copyright.h" #include <stdio.h> #include <ctype.h> #include <sys/param.h> #include "db.h" static int include_all = 0; /* include everything unless specified */ static int keep_players = 0; /* keep all players */ static int safe_below = 1; /* Keep everything <= safe_below */ static int safe_above = 2e9; /* Keep everything >= safe_above */ static int reachable = 0; /* Only keep rooms reachable from #0 */ static int norecycle = 0; /* Exclude things in recycling center */ static int inbuild = 0; /* True when in main nuild_trans loop */ static int recycling_center = 0;/* Room number home("Recycler") */ # define REACH_FLAG 0x40000000 # define REACHABLE(X) (db[X].flags & REACH_FLAG) # define SET_REACHABLE(X) (db[X].flags |= REACH_FLAG) static dbref included[NCARGS+1]; static dbref excluded[NCARGS+1]; static dbref *trans; /* translation vector */ #define DEFAULT_LOCATION (0) #define DEFAULT_OWNER (1) static int isok(dbref); /* returns 1 if object is specifically excluded */ static int is_excluded(dbref x) { int i; if(x == NOTHING) return 0; /* Don't exclude nothing */ /* check that it isn't excluded */ for(i = 0; excluded[i] != NOTHING; i++) { if(excluded[i] == x) return 1; /* always exclude specifics */ if(excluded[i] == db[x].owner) return 1; } return (0); } /* returns 1 if it is not excluded */ static int not_excluded(dbref x) { int i; if(x == NOTHING) return 1; /* Don't exclude nothing */ /* check that it isn't excluded */ for(i = 0; excluded[i] != NOTHING; i++) { if(excluded[i] == x) return 0; /* always exclude specifics */ if(excluded[i] == db[x].owner) return 0; } /* if it's an exit, check that its destination is ok */ if(Typeof(x) == TYPE_EXIT && db[x].location >= 0) { return isok(db[x].location); } else { return 1; } } /* returns 1 if it should be included in translation vector */ static int isok(dbref x) { int i; if(x == DEFAULT_OWNER || x == DEFAULT_LOCATION) return 1; if(x == NOTHING) return 1; for(i = 0; included[i] != NOTHING; i++) { if(included[i] == x) return 1; /* always get specific ones */ if(reachable && Typeof(x) == TYPE_ROOM && !REACHABLE(x)) { # ifdef DEBUG if (inbuild) fprintf (stderr, "Excluding %s(%dR), not reachable\n", db[x].name, x); # endif return 0; } if(norecycle && db[x].location == recycling_center) return 0; if(included[i] == db[x].owner || (x <= safe_below || x >= safe_above) || keep_players && Typeof(x) == TYPE_PLAYER) { return not_excluded(x); } } /* not in the list, can only get it if include_all is on */ /* or it's owned by DEFAULT_OWNER */ return (include_all && not_excluded(x)); } static void build_trans(void) { dbref i; dbref val; if((trans = (dbref *) malloc(sizeof(dbref) * db_top)) == 0) { abort(); } inbuild++; val = 0; for(i = 0; i < db_top; i++) { if(isok(i)) { trans[i] = val++; } else { trans[i] = NOTHING; } } inbuild--; } static dbref translate(dbref x) { if(x == NOTHING || x == HOME) { return(x); } else { return(trans[x]); } } /* TRUE_BOOLEXP means throw this argument out */ /* even on OR; it's effectively a null boolexp */ /* NOTE: this doesn't free anything, it just munges it up */ static struct boolexp *translate_boolexp(struct boolexp *exp) { struct boolexp *s1; struct boolexp *s2; if(exp == TRUE_BOOLEXP) { return TRUE_BOOLEXP; } else { switch(exp->type) { case BOOLEXP_NOT: s1 = translate_boolexp(exp->sub1); if(s1 == TRUE_BOOLEXP) { return TRUE_BOOLEXP; } else { exp->sub1 = s1; return exp; } /* break; */ case BOOLEXP_AND: case BOOLEXP_OR: s1 = translate_boolexp(exp->sub1); s2 = translate_boolexp(exp->sub2); if(s1 == TRUE_BOOLEXP && s2 == TRUE_BOOLEXP) { /* nothing left */ return TRUE_BOOLEXP; } else if(s1 == TRUE_BOOLEXP && s2 != TRUE_BOOLEXP) { /* s2 is all that is left */ return s2; } else if(s1 != TRUE_BOOLEXP && s2 == TRUE_BOOLEXP) { /* s1 is all that is left */ return s1; } else { exp->sub1 = s1; exp->sub2 = s2; return exp; } /* break; */ case BOOLEXP_CONST: exp->thing = translate(exp->thing); if(exp->thing == NOTHING) { return TRUE_BOOLEXP; } else { return exp; } /* break; */ default: abort(); /* bad boolexp type, we lose */ return TRUE_BOOLEXP; } } } static int ok(dbref x) { if(x == NOTHING || x == HOME) { return 1; } else { return trans[x] != NOTHING; } } static void check_bad_exits(dbref x) { dbref e; if(Typeof(x) == TYPE_ROOM && !isok(x)) { /* mark all exits as excluded */ DOLIST(e, db[x].exits) { trans[e] = NOTHING; } } } static void check_owner(dbref x) { if(ok(x) && !ok(db[x].owner)) { db[x].owner = DEFAULT_OWNER; } } static void check_location(dbref x) { dbref loc; dbref newloc; if(ok(x) && (Typeof(x) == TYPE_THING || Typeof(x) == TYPE_PLAYER) && !ok(loc = db[x].location)) { /* move it to home or DEFAULT_LOCATION */ if(ok(db[x].exits)) { newloc = db[x].exits; /* home */ } else { newloc = DEFAULT_LOCATION; } db[loc].contents = remove_first(db[loc].contents, x); PUSH(x, db[newloc].contents); db[x].location = newloc; } } static void check_next(dbref x) { dbref next; if(ok(x)) { while(!ok(next = db[x].next)) db[x].next = db[next].next; } } static void check_contents(dbref x) { dbref c; if(ok(x)) { while(!ok(c = db[x].contents)) db[x].contents = db[c].next; } } /* also updates home */ /* MUST BE CALLED AFTER check_owner! */ static void check_exits(dbref x) { dbref e; if(ok(x) && !ok(e = db[x].exits)) { switch(Typeof(x)) { case TYPE_ROOM: while(!ok(e = db[x].exits)) db[x].exits = db[e].next; break; case TYPE_PLAYER: case TYPE_THING: if(ok(db[db[x].owner].exits)) { /* set it to owner's home */ db[x].exits = db[db[x].owner].exits; /* home */ } else { /* set it to DEFAULT_LOCATION */ db[x].exits = DEFAULT_LOCATION; /* home */ } break; } } } static void do_write(void) { dbref i; dbref kludge; /* this is braindamaged */ /* we have to rebuild the translation map */ /* because part of it may have gotten nuked in check_bad_exits */ for(i = 0, kludge = 0; i < db_top; i++) { if(trans[i] != NOTHING) trans[i] = kludge++; } for(i = 0; i < db_top; i++) { if(ok(i)) { /* translate all object pointers */ db[i].location = translate(db[i].location); db[i].contents = translate(db[i].contents); db[i].exits = translate(db[i].exits); db[i].next = translate(db[i].next); db[i].key = translate_boolexp(db[i].key); db[i].owner = translate(db[i].owner); /* write it out */ printf("#%d\n", translate(i)); db_write_object(stdout, i); } } puts("***END OF DUMP***"); } int reach_lvl = 0; make_reachable (dbref x) { dbref e, r; int i; if (Typeof(x) != TYPE_ROOM || is_excluded(x)) return; reach_lvl++; SET_REACHABLE(x); #ifdef DEBUG for (i=0; i<reach_lvl; i++ ) fputc (' ', stderr); fprintf (stderr, "Set %s(%dR) reachable.\n", db[x].name, x); #endif DOLIST(e, db[x].exits) { r = db[e].location; if (r < 0) continue; if (is_excluded(r)) continue; if (is_excluded(e)) continue; if (!REACHABLE(r)) make_reachable(r); } reach_lvl--; } void main(int argc, char **argv) { dbref i; int top_in; int top_ex; char *arg0; top_in = 0; top_ex = 0; /* Load database */ if(db_read(stdin) < 0) { fputs("Database load failed!\n", stderr); exit(1); } fputs("Done loading database...\n", stderr); /* now parse args */ arg0 = *argv; for (argv++, argc--; argc > 0; argv++, argc--) { if (isdigit (**argv) || **argv == '-' && isdigit ((*argv)[1])) { i = atol(*argv); } else if (**argv == '+' && isdigit ((*argv)[1])) { i = atol(*argv+1); } else if (**argv == 'b' && isdigit ((*argv)[1])) { safe_below = atol(*argv+1); fprintf (stderr, "Including all objects %d and below\n", safe_below); } else if (**argv == 'a' && isdigit ((*argv)[1])) { safe_above = atol(*argv+1); fprintf (stderr, "Including all objects %d and above\n", safe_above); } else if (!strcmp(*argv, "all")) { include_all = 1; } else if (!strcmp(*argv, "reachable")) { reachable = 1; } else if (!strcmp(*argv, "players")) { keep_players = 1; } else if (!strcmp(*argv, "norecycle")) { norecycle = 1; } else if (**argv == '-' && (i = lookup_player (*argv+1)) != 0) { fprintf (stderr, "Excluding player %s(%d)\n", db[i].name, i); i = -i; } else if (**argv != '-' && (i = lookup_player (*argv)) != NOTHING) { fprintf (stderr, "Including player %s(%d)\n", db[i].name, i); } else { fprintf(stderr, "%s: bogus argument %s\n", arg0, *argv); continue; } if(i < 0) { excluded[top_ex++] = -i; } else { included[top_in++] = i; } } /* Terminate */ included[top_in++] = NOTHING; excluded[top_ex++] = NOTHING; /* Check for reachability from DEFAULT_LOCATION */ if (reachable) { make_reachable (DEFAULT_LOCATION); fputs ("Done marking reachability...\n", stderr); } /* Find recycler */ if (norecycle && ((i = lookup_player (RECYCLER)) != NOTHING)) { recycling_center = db[i].exits; if (recycling_center == DEFAULT_LOCATION) norecycle = 0; else { fprintf (stderr, "Excluding all players in %s(%d)\n", db[recycling_center].name, recycling_center); } } /* Build translation table */ build_trans(); fputs("Done building translation table...\n", stderr); /* Scan everything */ for(i = 0; i < db_top; i++) check_bad_exits(i); fputs("Done checking bad exits...\n", stderr); for(i = 0; i < db_top; i++) check_owner(i); fputs("Done checking owners...\n", stderr); for(i = 0; i < db_top; i++) check_location(i); fputs("Done checking locations...\n", stderr); for(i = 0; i < db_top; i++) check_next(i); fputs("Done checking next pointers...\n", stderr); for(i = 0; i < db_top; i++) check_contents(i); fputs("Done checking contents...\n", stderr); for(i = 0; i < db_top; i++) check_exits(i); fputs("Done checking homes and exits...\n", stderr); do_write(); fputs("Done.\n", stderr); exit(0); }