#include "copyright.h" #include <stdio.h> #include <ctype.h> #include <sys/param.h> #include "db.h" #include "config.h" #ifndef MUDNAME #define MUDNAME "Islandia" #endif 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); char *OIF_ID (int); void OIFboolexp (FILE *, struct boolexp *); char *ofix (const char *); /* 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; } #ifdef RECYCLER if (norecycle && db[x].location == recycling_center) return 0; #endif if (included[i] == db[x].owner || (x <= safe_below || x >= safe_above) || keep_players && Typeof (x) == TYPE_PLAYER) { return not_excluded (x); } } #if 0 /* This is an UnterMUD converter. UnterMUDs don't have carried exits, so DROP such. Notez Bien: relies on the new source field. */ if (Typeof (i) == TYPE_EXIT && db[i].source == NOTHING) return 0; #endif /* 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; } /* This is an UnterMUD converter. UnterMUDs don't have carried exits, so DROP such. Notez Bien: relies on the new source field. */ if (Typeof (x) == TYPE_EXIT && db[x].source == NOTHING) return 0; /* Put here to avoid things getting renumbered. */ #ifdef TYPE_GARBAGE if (Typeof (x) == TYPE_GARBAGE) return 0; #endif 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; } } } void exitsources () { dbref i; dbref e; /* Make sure all sources have something recognizable. */ for (i = 0; i < db_top; i++) db[i].source = NOTHING; for (i = 0; i < db_top; i++) { if (Typeof (i) == TYPE_ROOM) { DOLIST (e, db[i].exits) { db[e].source = i; } } } } char buf[BUFSIZ]; static void do_OIF_write (void) { dbref i; dbref kludge; for (i = 0, kludge = 0; i < db_top; i++) { if (trans[i] != NOTHING) trans[i] = kludge++; } printf ("object sysobj\nint _objcnt=%d\nint newsarticle=0\nstr nam=The System Object (all mighty data point)\nobj _syslimbo=0\nlst own=wizard\nlst _wizards=wizard\nendobj\n", db_top - 1); strcpy (buf, "wizard"); rot_init (buf); rot_encode ("potrzebie", buf); printf ("object wizard\nflg _wz=\nflg _pl=\nstr nam=UnterWiz\nobj home=0@%s\nstr pass=%s\nobj loc=0\nlst own=wizard\nendobj\n", MUDNAME, buf); for (i = 0; i < db_top; i++) if (ok (i)) { printf ("object %s\n", OIF_ID (i)); printf ("str nam=%s\n", db[i].name); if (db[i].description) printf ("str desc=%s\n", db[i].description); if (db[i].contents) { printf ("lst con="); for (kludge = db[i].contents; kludge != NOTHING; kludge = db[kludge].next) if (Typeof (kludge) != TYPE_PLAYER) printf ("%s;", OIF_ID (kludge)); printf ("\n"); } if (db[i].key && !(Typeof (i) == TYPE_EXIT && db[i].location == NOTHING)) { printf ("boo lok="); OIFboolexp (stdout, translate_boolexp (db[i].key)); } else if (Typeof (i) == TYPE_EXIT && db[i].location == NOTHING) printf ("boo lok=F\n"); /* People can't walk through unlinked exits. */ else printf ("boo lok=T\n"); if (db[i].fail_message) printf ("str fail=%s\n", db[i].fail_message); if (db[i].ofail) printf ("str ofail=%s\n", ofix (db[i].ofail)); if (db[i].succ_message) printf ("str succ=%s\n", db[i].succ_message); if (db[i].osuccess) printf ("str osucc=%s\n", ofix (db[i].osuccess)); printf ("lst own=%s\n", OIF_ID (db[i].owner)); if (db[i].flags & LINK_OK) printf ("boo lnk=T\n"); if (db[i].flags & DARK) printf ("flg dark=\n"); switch (Typeof (i)) { case TYPE_PLAYER: printf ("flg _pl=\n"); if (Wizard (i)) printf ("flg _wz=\n"); printf ("obj loc=%s\n", OIF_ID (db[i].location)); printf ("obj home=%d@%s\n", translate (db[i].exits), MUDNAME); if (Genderof (i) == GENDER_MALE) { printf ("str subv=he\n"); printf ("str objv=him\n"); printf ("str posv=his\n"); } else if (Genderof (i) == GENDER_FEMALE) { printf ("str subv=she\n"); printf ("str objv=her\n"); printf ("str posv=her\n"); } else if (Genderof (i) == GENDER_NEUTER) { printf ("str subv=it\n"); printf ("str objv=it\n"); printf ("str posv=its\n"); } else { printf ("str subv=%s\n", db[i].name); printf ("str objv=%s\n", db[i].name); printf ("str posv=%s's\n", db[i].name); } OIF_ID (i); if (db[i].password) { rot_init (buf); rot_encode (db[i].password, buf); } else { buf[0] = 0; } printf ("str pass=%s\n", buf); break; case TYPE_THING: printf ("obj loc=%s\n", OIF_ID (db[i].location)); printf ("obj home=%d@%s\n", translate (db[i].exits), MUDNAME); if (db[i].flags & STICKY) printf ("cmd drop=tel $me home;_echo Dropped.\n"); break; case TYPE_ROOM: printf ("flg _rm=\n"); if (translate (db[i].location) != NOTHING) printf ("obj drpto=%s\n", OIF_ID (db[i].location)); printf ("lst xit="); for (kludge = db[i].exits; kludge != NOTHING; kludge = db[kludge].next) printf ("%s;", OIF_ID (kludge)); printf ("\n"); printf ("lst ply="); for (kludge = db[i].contents; kludge != NOTHING; kludge = db[kludge].next) if (Typeof (kludge) == TYPE_PLAYER) printf ("%s;", OIF_ID (kludge)); printf ("\n"); break; case TYPE_EXIT: /* Unlinked exit? Make it actually linked to home. */ if (db[i].location == NOTHING) printf ("obj dst=home\n"); else printf ("obj dst=%s\n", OIF_ID (db[i].location)); /* Yes, this is NEW. */ printf ("obj loc=%s\n", OIF_ID (db[i].source)); break; default: /* Do something sensible for stuff we don't understand. */ fprintf (stderr, "Can't handle type %d\n", Typeof (i)); abort (); /*NOTREACHED*/} printf ("endobj\n"); } } char *OIF_ID (dbref i) { if (i == HOME) sprintf (buf, "home"); else if (Typeof (i) == TYPE_PLAYER || Typeof (i) == TYPE_THING) sprintf (buf, "%d@%s", translate (i), MUDNAME); else sprintf (buf, "%d", translate (i)); return (buf); } int reach_lvl = 0; void make_reachable (dbref x) { dbref e, r; #ifdef DEBUG int i; #endif 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); } /* Gives all exits sources -- this becomes important later on. */ exitsources (); #ifdef RECYCLER /* 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); } } #endif /* 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(); */ do_OIF_write (); fputs ("Done.\n", stderr); exit (0); } static void OIFbool_subexp (FILE * f, struct boolexp *b) { switch (b->type) { case BOOLEXP_AND: putc ('(', f); OIFbool_subexp (f, b->sub1); putc (AND_TOKEN, f); OIFbool_subexp (f, b->sub2); putc (')', f); break; case BOOLEXP_OR: putc ('(', f); OIFbool_subexp (f, b->sub1); putc (OR_TOKEN, f); OIFbool_subexp (f, b->sub2); putc (')', f); break; case BOOLEXP_NOT: putc ('(', f); putc (NOT_TOKEN, f); OIFbool_subexp (f, b->sub1); putc (')', f); break; case BOOLEXP_CONST: fprintf (f, "%s", OIF_ID (b->thing)); break; default: break; } } void OIFboolexp (FILE * f, struct boolexp *b) { if (b != TRUE_BOOLEXP) { OIFbool_subexp (f, b); } putc ('\n', f); } char *ofix (const char *ins) { char foo[BUFSIZ]; char *bar, *baz; strcpy (foo, ins); strcpy (buf, ""); bar = foo; while ((baz = (char *) index (bar, '%')) != NULL) { *baz++ = '\0'; strcat (buf, bar); switch (*baz) { case 's': strcat (buf, "$subv"); break; case 'o': strcat (buf, "$objv"); break; case 'p': strcat (buf, "$posv"); break; case 'n': strcat (buf, "$nam"); } bar = baz + 1; } strcat (buf, bar); return (buf); }