#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);
}