/* game.c */
#include "os.h"
#include "config.h"
#include "db.h"
#include "externs.h"
#include "interface.h"
#include "match.h"
#ifdef MEM_CHECK
#include "mem_check.h"
#endif
/* declarations */
char dumpfile[200];
static int epoch = 0;
int depth = 0; /* excessive recursion prevention */
static int list_check (dbref thing, dbref player, int type, int end, char *str);
static int alias_list_check (dbref thing, const char *command, char *type);
static int quick_alias_check (dbref loc, const char *command, char *type);
static void do_poor(dbref player, char *arg1);
static void do_version(dbref player);
static void do_dolist(dbref player, char *inlist, char *command, dbref cause);
static void do_config(dbref player);
/*
* used to allocate storage for temporary stuff, cleared before command
* execution
*/
void do_dump (dbref player)
{
time_t tt;
tt = time ((time_t *) 0);
if (Wizard (player)) {
notify (player, "Dumping...");
fprintf (stderr, "** DUMP ** done by %s(#%d) at %s",
db[player].name, player, ctime (&tt));
fork_and_dump ();
} else {
notify (player, "Sorry, you are in a no dumping zone.");
}
}
/* print out stuff into error file */
void report (void)
{
fprintf (stderr, "****REPORT TRACE!****\n\tCommand:%s\tdepth:%d\n", ccom,
depth);
fflush (stderr);
if ((cplr > 0) && (cplr <= db_top))
fprintf (stderr, "\tPlayer #%d\n\tlocation #%d\n", cplr,
db[cplr].location);
fflush (stderr);
}
#ifdef DESTROY
static void do_purge (dbref player)
{
if (Wizard (player)) {
FIX;
notify (player, "Purge complete.");
} else
notify (player, "Sorry, you are a mortal.");
}
void dest_info (dbref thing, dbref tt)
{
if (thing == NOTHING && !Floating (tt)) {
if (db[tt].name) {
notify (db[tt].owner, tprintf ("You own a disconnected room, %s(#%d)",
db[tt].name, tt));
} else
fprintf (stderr, "ERROR: no name for room\n");
return;
}
switch (Typeof (thing)) {
case TYPE_ROOM: /* Tell all players room has gone away */
notify_except (db[thing].contents, 0,
"The floor disappears under your feet, you fall through NOTHINGness and then:");
break;
case TYPE_PLAYER: /* Show them where they arrived */
enter_room (thing, HOME);
break;
}
}
#endif /* DESTROY */
dbref speaker = NOTHING;
void notify (dbref player, const char *msg)
{
ATTR *d;
char tbuf1[BUFFER_LEN];
if ((player < 0) || (player >= db_top))
return;
if (depth++ > 7) {
depth--;
return;
}
switch (Typeof (player)) {
case TYPE_PLAYER:
raw_notify (player, msg);
break;
case TYPE_THING:
if (db[player].flags & THING_PUPPET &&
(db[player].location != db[db[player].owner].location ||
speaker == player)) {
sprintf (tbuf1, "%s> %s", db[player].name, msg);
raw_notify (db[player].owner, tbuf1);
}
d = atr_get (player, "LISTEN");
if (d) {
sprintf (tbuf1, "%s", uncompress (d->value));
if (wild_match (tbuf1, (char*)msg)) {
if (speaker != player)
did_it (speaker, player, 0, NULL, 0, NULL, "AHEAR", NOTHING);
else
did_it (speaker, player, 0, NULL, 0, NULL, "AMHEAR", NOTHING);
did_it (speaker, player, 0, NULL, 0, NULL, "AAHEAR", NOTHING);
/* also pass the message on
* Note: not telling player protects against two forms
* of recursion:
* player doesn't tell itself (as container) or as contents
* using teleport it is possible to create a recursive loop
* but this will be terminated when the depth variable exceeds 30
*/
if (!member (speaker, db[player].contents)) {
if ((Typeof (player) == TYPE_THING) &&
(db[player].flags & THING_PUPPET)) {
notify_except2 (db[player].contents, player,
db[player].owner, msg);
} else {
notify_except (db[player].contents, player, msg);
}
}
}
} else {
/* if there is no listen, check for ^ listen patterns */
/* these are like AHEAR - object cannot trigger itself */
if (speaker != player)
atr_comm_match (player, player, '^', ':', (char*)msg);
/* unlike normal @listen, don't pass the message on */
}
/* now check for multi listeners */
}
depth--;
}
void do_shutdown (dbref player)
{
if (Wizard (player)) {
raw_broadcast (0, "GAME: Shutdown by %s", db[player].name);
fprintf (stderr, "SHUTDOWN: by %s\n", unparse_object (player, player));
fflush (stderr);
/* This will create a file used to check if a restart should occur */
#ifdef AUTORESTART
system ("touch NORESTART");
#endif
shutdown_flag = 1;
} else {
notify (player, "Your delusions of grandeur have been duly noted.");
}
}
static void dump_database_internal (void)
{
char tmpfl[2048];
FILE *f;
sprintf (tmpfl, "%s.#%d#", dumpfile, epoch - 1);
#ifdef _MSC_VER
remove (tmpfl); /* nuke our predecessor */
#else
unlink (tmpfl); /* nuke our predecessor */
#endif
sprintf (tmpfl, "%s.#%d#", dumpfile, epoch);
#ifdef DBCOMP
if ((f = (FILE*)popen (tprintf ("gzip >%s", tmpfl), "w")) != NULL) {
db_write (f);
pclose (f);
#ifdef WIN32
#ifdef _MSC_VER
remove (dumpfile);
#else
unlink (dumpfile);
#endif
#endif
if (rename (tmpfl, dumpfile) < 0)
perror (tmpfl);
} else
perror (tmpfl);
#ifdef USE_MAILER
sprintf (tmpfl, "maildb.Z.#%d#", epoch - 1);
#ifdef _MSC_VER
remove (tmpfl);
#else
unlink (tmpfl);
#endif
sprintf (tmpfl, "maildb.Z.#%d#", epoch);
if (mdb_top > 0)
if ((f = (FILE*)popen (tprintf ("gzip >%s", tmpfl), "w")) != NULL) {
dump_mail (f);
pclose (f);
#ifdef WIN32
#ifdef _MSC_VER
remove ("maildb.Z");
#else
unlink ("maildb.Z");
#endif
#endif
if (rename (tmpfl, "maildb.Z") < 0)
perror (tmpfl);
} else
perror (tmpfl);
#endif
#else
if ((f = fopen (tmpfl, "wb")) != NULL) {
db_write (f);
fclose (f);
#ifdef WIN32
#ifdef _MSC_VER
remove (dumpfile);
#else
unlink (dumpfile);
#endif
#endif
if (rename (tmpfl, dumpfile) < 0)
perror (tmpfl);
} else
perror (tmpfl);
#ifdef USE_MAILER
sprintf (tmpfl, "maildb.#%d#", epoch - 1);
unlink (tmpfl);
sprintf (tmpfl, "maildb.#%d#", epoch);
if ((f = fopen (tmpfl, "wb")) != NULL) {
db_write (f);
fclose (f);
#ifdef WIN32
#ifdef _MSC_VER
remove ("maildb");
#else
unlink ("maildb");
#endif
#endif
if (rename (tmpfl, "maildb") < 0)
perror (tmpfl);
} else
perror (tmpfl);
#endif
#endif
}
void panic (const char *message)
{
char panicfile[2048];
FILE *f;
int i;
fprintf (stderr, "PANIC: %s\n", message);
report ();
/* turn off signals */
for (i = 0; i < NSIG; i++) {
signal (i, SIG_IGN);
}
/* shut down interface */
emergency_shutdown ();
/* dump panic file */
sprintf (panicfile, "%s.PANIC", dumpfile);
if ((f = fopen (panicfile, "wb")) == NULL) {
perror ("CANNOT OPEN PANIC FILE, YOU LOSE:");
WIN32CLEANUP
_exit (135);
} else {
fprintf (stderr, "DUMPING: %s\n", panicfile);
db_write (f);
fclose (f);
fprintf (stderr, "DUMPING: %s (done)\n", panicfile);
WIN32CLEANUP
_exit (136);
}
}
void dump_database (void)
{
epoch++;
fprintf (stderr, "DUMPING: %s.#%d#\n", dumpfile, epoch);
dump_database_internal ();
fprintf (stderr, "DUMPING: %s.#%d# (done)\n", dumpfile, epoch);
}
#ifndef WIN32
static int reaper (void)
{
int stat;
while (wait3 (&stat, WNOHANG, 0) > 0);
return 0;
}
#endif
void fork_and_dump (void)
{
#ifndef WIN32
int child;
#endif
epoch++;
fprintf (stderr, "CHECKPOINTING: %s.#%d#\n", dumpfile, epoch);
#ifndef WIN32
#ifndef NO_FORK
#ifdef USE_VFORK
raw_broadcast (0, "GAME: Dumping. The game will freeze for a few minutes.");
child = vfork ();
#else /* USE_VFORK */
child = fork ();
#endif /* USE_VFORK */
#else /* NO FORK */
raw_broadcast (0, "GAME: Dumping. The game will freeze for a few minutes.");
child = 0;
#endif /* NO_FORK */
if (child == 0) {
/* in the child */
#endif // WIN32
dump_database_internal ();
#ifndef WIN32
#ifndef NO_FORK
_exit (0); /* !!! */
#endif /* NO_FORK */
} else if (child < 0) {
perror ("fork_and_dump: fork()");
}
#endif // WIN32
}
static void do_restart (void)
{
dbref thing;
ATTR *s;
for (thing = 0; thing < db_top; thing++)
if (!(db[thing].flags & GOING) && (s = atr_get (thing, "STARTUP"))) {
char *r = safe_uncompress (s->value);
parse_que (thing, r, thing);
free (r);
}
}
int init_game (const char *infile, const char *outfile)
{
FILE *f;
int a;
depth = 0;
for (a = 0; a < 10; a++)
wptr[a] = NULL;
#ifdef DBCOMP
if ((f = (FILE*)popen (tprintf ("gzip -d < %s", infile), "r")) == NULL)
return -1;
#else
if ((f = fopen (infile, "rb")) == NULL)
return -1;
#endif
/* ok, read it in */
fprintf (stderr, "LOADING: %s\n", infile);
printf ("READING...\n");
fflush (stdout);
if (db_read (f) < 0) {
fprintf (stderr, "ERROR LOADING\n");
return -1;
}
printf ("READ\n");
fflush (stdout);
fprintf (stderr, "LOADING: %s (done)\n", infile);
/* everything ok */
#ifdef DBCOMP
pclose (f);
#else
fclose (f);
#endif
#ifdef USE_MAILER
/* read mail database */
#ifdef DBCOMP
if ((f = (FILE*)popen ("gzip -d <maildb.Z", "r")) == NULL)
mail_init ();
#else
if ((f = fopen ("maildb", "rb")) == NULL)
mail_init ();
#endif
/* okay, read it in */
else {
fprintf (stderr, "LOADING: maildb.Z\n");
printf ("READING...\n");
fflush (stdout);
load_mail (f);
printf ("READ\n");
fflush (stdout);
fprintf (stderr, "LOADING: maildb.Z (done)\n");
}
/* everything okay */
#ifdef DBCOMP
pclose (f);
#else
fclose (f);
#endif
#endif /* USE_MAILER */
#ifndef WIN32
/* initialize random number generator */
OS_SRAND (getpid ());
#endif
/* set up dumper */
strcpy (dumpfile, outfile);
init_timer ();
#ifndef WIN32
signal (SIGCHLD, (void *) reaper);
#endif
/* everything else ok restart all robots */
do_restart ();
return 0;
}
/*
* use this only in process_command
*/
#define Matched(string) { if(!string_prefix((string), command)) goto bad; }
/* the two versions of argument parsing */
static char *do_argtwo (dbref player, char *rest, dbref cause, char *buff)
{
exec (&rest, buff, player, cause, 0);
return (buff);
}
static char **do_argbee (dbref player, char *rest, dbref cause, char **arge,
char *buff)
{
int a;
char *p;
char tbuf1[BUFFER_LEN];
for (a = 1; a < MAX_ARG; a++) {
if (arge[a]) {
free ((char *) arge[a]);
#ifdef MEM_CHECK
del_check ("process_comm_args");
#endif
}
p = parse_up (&rest, ',');
if (p) {
strcpy ((arge[a] = (char *) malloc (strlen (p) + 1)), p);
#ifdef MEM_CHECK
add_check ("process_comm_args");
#endif
} else
arge[a] = NULL;
}
/* rest of delimiters are ,'s */
for (a = 1; a < MAX_ARG; a++)
if (arge[a]) {
strcpy (tbuf1, arge[a]);
p = tbuf1;
exec (&p, buff, player, cause, 0);
free ((char *) arge[a]);
strcpy ((arge[a] = (char *) malloc (strlen (buff) + 1)), buff);
}
return (arge);
}
#define arg2 do_argtwo(player,rest,cause,buff)
#define argv do_argbee(player,rest,cause,arge,buff)
void process_command (dbref player, char *command, dbref cause)
{
char *arg1;
int a;
char *q; /* utility */
char *p; /* utility */
char *r;
char buff[BUFFER_LEN], buff2[BUFFER_LEN], buff3[BUFFER_LEN];
char *arge[MAX_ARG]; /* pointers to arguments (null for empty) */
char unp[BUFFER_LEN]; /* unparsed command */
char oldarg1[BUFFER_LEN];
char *rest;
/* general form command arg0=arg1,arg2...arg10 */
int gagged = 0;
char temp[BUFFER_LEN]; /* utility */
int i; /* utility */
for (a = 0; a < MAX_ARG; a++)
arge[a] = NULL;
depth = 0;
if (command == 0) {
fprintf (stderr, "ERROR: No command!!!");
return;
}
/* just to have fun, let's reinit the random number gen (with the time) */
OS_SRAND ((int) time ((time_t *) 0));
if (God (player) && !God (cause))
return;
/* robustify player */
if ((player < 0) || (player >= db_top)) {
fprintf (stderr, "ERROR: bad player %d in process_command\n", player);
return;
}
gagged = IS (db[player].owner, TYPE_PLAYER, PLAYER_GAGGED);
/* Access the player */
Access (player);
if ((db[player].flags & GOING) ||
((Typeof (player) != TYPE_PLAYER) && (db[player].flags & HALT))) {
notify (db[player].owner,
tprintf ("Attempt to execute command by halted object #%d", player));
return;
}
/* The following check is removed due to a security hole it causes! */
/* if player is an exit or room execute command as owner */
/* if ((Typeof(player) == TYPE_ROOM) || (Typeof(player) == TYPE_EXIT))
player = db[player].owner; */
speaker = player;
#ifdef LOG_COMMANDS
fprintf (stderr, "COMMAND from %s(%d) in %s(%d): %s\n",
(player == NOTHING ? "NOTHING" : db[player].name), player,
(db[player].location == NOTHING ? "NOTHING"
: db[db[player].location].name), db[player].location, command);
#endif /* LOG_COMMANDS */
/* log all commands from suspect players */
if (Suspect (player)) {
fprintf (stderr, "SUSPECT %s(#%d) in %s(#%d): %s\n",
(player == NOTHING ? "NOTHING" : db[player].name), player,
(db[player].location == NOTHING ? "NOTHING"
: db[db[player].location].name), db[player].location, command);
}
/* eat leading whitespace */
while (*command && isspace ((int)*command))
command++;
/* eat extra white space */
q = p = command;
while (*p) {
/* scan over word */
while (*p && !isspace ((int)*p))
*q++ = *p++;
/* smash spaces */
while (*p && isspace ((int)*++p));
if (*p)
*q++ = ' '; /* add a space to separate next word */
}
/* terminate */
*q = '\0';
/* important home checking comes first! */
if (strcmp (command, "home") == 0) {
if (Typeof (player) == TYPE_EXIT || Typeof (player) == TYPE_ROOM)
return;
do_move (player, command, 0);
return;
}
if (!gagged && try_force (player, command))
return;
/* check for single-character commands */
if (*command == SAY_TOKEN && !gagged) {
do_say (player, command + 1, NULL);
} else if (*command == POSE_TOKEN && !gagged) {
do_pose (player, command + 1, NULL, 0);
} else if (*command == SEMI_POSE_TOKEN && !gagged) {
do_pose (player, command + 1, NULL, 1);
/* now check if command is an exact match for an exit in the room */
} else if (can_move (player, command)) {
if (Typeof (player) == TYPE_ROOM || Typeof (player) == TYPE_EXIT)
return;
do_move (player, command, 0);
} else {
strcpy (unp, command);
/* parse arguments */
/* find arg1 */
/* move over command word */
for (arg1 = command; *arg1 && !isspace ((int)*arg1); arg1++);
/* truncate command */
if (*arg1)
*arg1++ = '\0';
/* move over spaces */
while (*arg1 && isspace ((int)*arg1))
arg1++;
r = parse_up (&arg1, '='); /* first delimiter is ='s */
if (r) {
if (arge[0]) {
free ((char *) arge[0]);
#ifdef MEM_CHECK
del_check ("process_comm_args");
#endif
}
strcpy ((arge[0] = (char *) malloc (strlen (r) + 1)), r);
#ifdef MEM_CHECK
add_check ("process_comm_args");
#endif
}
rest = arg1; /* either arg2 or argv */
if (arge[0]) {
/* Let's unfutz the news/help commands, shall we? */
strcpy (oldarg1, arge[0]);
strcpy (buff3, arge[0]);
r = buff3;
exec (&r, buff2, player, cause, 0);
free ((char *) arge[0]);
strcpy ((arge[0] = (char *) malloc (strlen (r) + 1)), r);
} else {
oldarg1[0] = '\0';
}
arg1 = ((char *) arge[0]) ? (char *) buff2 : (char *) "";
if (!gagged && test_set (player, command, arg1, arg2)) {
/* let's free up all that nice memory, shall we? */
for (a = 0; a < MAX_ARG; a++) {
if (arge[a]) {
free ((char *) arge[a]);
#ifdef MEM_CHECK
del_check ("process_comm_args");
#endif
}
}
return;
}
switch (command[0]) {
case '@':
switch (command[1]) {
case 'a':
case 'A':
if (!string_compare (command, "@allhalt")) {
do_allhalt (player);
break;
}
switch (command[2]) {
#ifdef QUOTA
case 'l':
case 'L':
Matched ("@allquota");
do_allquota (player, arg1);
break;
#endif /* QUOTA */
case 't':
case 'T':
if (string_prefix ("@atrlock", command)) {
do_atrlock (player, arg1, arg2);
} else {
Matched ("@atrchown");
do_atrchown (player, arg1, arg2);
}
break;
default:
goto bad;
}
break;
case 'b':
case 'B':
Matched ("@boot");
do_boot (player, arg1);
break;
case 'c':
case 'C':
/* chown, create */
switch (command[2]) {
case 'h':
case 'H':
switch (command[3]) {
case 'o':
case 'O':
if (!string_compare (command, "@chownall")) {
do_chownall (player, arg1, arg2);
break;
} else {
if (gagged)
break;
Matched ("@chown");
do_chown (player, arg1, arg2);
break;
}
case 'z':
case 'Z':
if (!string_compare (command, "@chzoneall")) {
do_chzoneall (player, arg1, arg2);
break;
} else {
if (gagged)
break;
Matched ("@chzone");
do_chzone (player, arg1, arg2);
break;
}
}
break;
case 'o':
case 'O':
Matched ("@config");
do_config (player);
break;
case 'r':
case 'R':
if (gagged)
break;
Matched ("@create");
do_create (player, arg1, atol (arg2));
break;
case 'l':
case 'L':
if (gagged)
break;
Matched ("@clone");
do_clone (player, arg1);
break;
default:
goto bad;
}
break;
case 'd':
case 'D':
/* dbck, dig, or dump */
switch (command[2]) {
#ifdef DESTROY
case 'b':
case 'B':
Matched ("@dbck");
do_dbck (player);
break;
#endif
case 'E':
case 'e':
switch (command[3]) {
case 'c':
case 'C':
Matched ("@decompile");
do_decompile (player, arg1);
break;
#ifdef DESTROY
case 's':
case 'S':
Matched ("@destroy");
do_destroy (player, arg1, 0);
break;
#endif /* DESTROY */
default:
goto bad;
}
break;
case 'i':
case 'I':
if (gagged)
break;
Matched ("@dig");
do_dig (player, arg1, argv);
break;
case 'o':
case 'O':
switch (command[3]) {
#ifdef AT_DOING
case 'i':
case 'I':
if (gagged)
break;
if (Typeof (player) != TYPE_PLAYER)
break;
Matched ("@doing");
do_doing (player, arg1, arg2);
break;
#endif
case 'l':
case 'L':
Matched ("@dolist");
do_dolist (player, arg1, arg2, cause);
break;
}
break;
case 'u':
case 'U':
Matched ("@dump");
do_dump (player);
break;
default:
goto bad;
}
break;
case 'E':
case 'e':
switch (command[2]) {
case 'd':
case 'D':
if (gagged)
break;
Matched ("@edit");
do_edit (player, arg1, argv);
break;
case 'l':
case 'L':
if (gagged)
break;
Matched ("@elock");
do_lock (player, arg1, arg2, ENTERLOCK);
break;
case 'm':
case 'M':
if (gagged)
break;
Matched ("@emit");
do_emit (player, arg1, arg2);
break;
case 'n':
case 'N':
if (gagged)
break;
Matched ("@entrances");
do_entrances (player, arg1);
break;
case 'u':
case 'U':
if (gagged)
break;
Matched ("@eunlock");
do_unlock (player, arg1, ENTERLOCK);
break;
default:
goto bad;
}
break;
case 'F':
case 'f':
/* find, or force */
switch (command[2]) {
case 'i':
case 'I':
if (gagged)
break;
Matched ("@find");
do_find (player, arg1);
break;
case 'o':
case 'O':
if (gagged)
break;
Matched ("@force");
do_force (player, arg1, arg2);
break;
default:
goto bad;
}
break;
case 'g':
case 'G':
if (gagged)
break;
Matched ("@gedit");
do_gedit (player, arg1, argv);
break;
case 'h':
case 'H':
/* halt */
Matched ("@halt");
do_halt1 (player, arg1, arg2);
break;
case 'l':
case 'L':
/* lock or link */
switch (command[2]) {
case 'e':
case 'E':
if (gagged)
break;
Matched ("@lemit");
do_lemit (player, arg1, arg2);
break;
case 'i':
case 'I':
if (gagged)
break;
if (string_prefix ("@link", command)) {
do_link (player, arg1, arg2);
break;
} else {
Matched ("@listmotd");
do_motd (player, 3, "", "");
break;
}
case 'o':
case 'O':
if (gagged)
break;
if (string_prefix ("@login", command)) {
do_login (player, arg1);
break;
} else {
Matched ("@lock");
do_lock (player, arg1, arg2, BASICLOCK);
break;
}
default:
goto bad;
}
break;
case 'm':
case 'M':
/* @mail, @motd */
switch (command[2]) {
#ifdef USE_MAILER
case 'a':
case 'A':
if (gagged)
break;
Matched ("@mail");
do_mail (player, arg1, arg2);
break;
#endif
case 'o':
case 'O':
if (gagged)
break;
Matched ("@motd");
do_motd (player, 1, arg1, arg2);
break;
default:
goto bad;
}
break;
case 'n':
case 'N':
/* @name, @newpassword */
switch (command[2]) {
case 'a':
case 'A':
if (gagged)
break;
Matched ("@name");
do_name (player, arg1, arg2);
break;
case 'e':
case 'E':
if (strcmp (command, "@newpassword"))
goto bad;
do_newpassword (player, arg1, arg2);
break;
#ifdef DESTROY
case 'u':
if (gagged)
break;
Matched ("@nuke");
do_destroy (player, arg1, 1);
break;
#endif
default:
goto bad;
}
break;
case 'o':
case 'O':
/* @oemit, @open */
switch (command[2]) {
case 'e':
case 'E':
if (gagged)
break;
Matched ("@oemit");
do_oemit (player, arg1, arg2);
break;
case 'p':
case 'P':
if (gagged)
break;
Matched ("@open");
do_open (player, arg1, argv);
break;
default:
goto bad;
}
break;
case 'p':
case 'P':
switch (command[2]) {
case 'a':
case 'A':
Matched ("@password");
do_password (player, arg1, arg2);
break;
#ifdef WCREAT
case 'C':
case 'c':
Matched ("@pcreate");
do_pcreate (player, arg1, arg2);
break;
#endif
case 'E':
case 'e':
if (gagged)
break;
Matched ("@pemit");
do_pemit (player, arg1, arg2);
break;
case 'O':
case 'o':
switch (command[3]) {
case 'l':
case 'L':
Matched ("@poll");
do_poll (player, arg1, arg2);
break;
case 'o':
case 'O':
if (strcmp (command, "@poor"))
goto bad;
do_poor (player, arg1);
break;
default:
goto bad;
}
break;
case 'S':
case 's':
Matched ("@ps");
do_queue (player, arg1);
break;
#ifdef DESTROY
case 'u':
case 'U':
Matched ("@purge");
do_purge (player);
break;
#endif /* DESTROY */
default:
goto bad;
}
break;
#ifdef QUOTA
case 'q':
case 'Q':
Matched ("@quota");
do_quota (player, arg1, "");
break;
#endif /* QUOTA */
case 'r':
case 'R':
switch (command[2]) {
case 'e':
case 'E':
if (gagged)
break;
if (string_prefix ("@remit", command)) {
do_remit (player, arg1, arg2);
} else {
Matched ("@rejectmotd");
do_motd (player, 4, arg1, arg2);
}
break;
#ifdef ROYALTY_FLAG
case 'w':
case 'W':
if (string_prefix ("@rwall", command)) {
do_wizwall (player, arg1, arg2, 1, 1);
} else if (string_prefix ("@rwallpose", command)) {
do_wizwall (player, arg1, arg2, 1, 2);
} else if (string_prefix ("@rwallemit", command)) {
do_wizwall (player, arg1, arg2, 1, 3);
} else
goto bad;
break;
#endif
}
break;
case 's':
case 'S':
/* set, shutdown, success */
switch (command[2]) {
case 'e':
case 'E':
/* patched to add 'search' command */
switch (command[3]) {
case 'a':
case 'A':
Matched ("@search");
do_search (player, arg1, arg2);
break;
case 't':
case 'T':
if (gagged)
break;
Matched ("@set");
do_set (player, arg1, arg2);
break;
default:
goto bad;
}
break;
case 'h':
case 'H':
if (strcmp (command, "@shutdown"))
goto bad;
do_shutdown (player);
break;
case 't':
case 'T':
Matched ("@stats");
do_stats (player, arg1);
break;
case 'w':
case 'W':
switch (command[3]) {
case 'e':
case 'E':
Matched ("@sweep");
do_sweep (player, arg1);
break;
case 'i':
case 'I':
if (gagged)
break;
Matched ("@switch");
do_switch (player, arg1, argv, cause);
break;
default:
goto bad;
}
break;
#ifdef QUOTA
case 'q':
case 'Q':
Matched ("@squota");
do_quota (player, arg1, arg2);
break;
#endif /* QUOTA */
default:
goto bad;
}
break;
case 't':
case 'T':
switch (command[2]) {
case 'e':
case 'E':
if (gagged)
break;
Matched ("@teleport");
do_teleport (player, arg1, arg2);
break;
case 'r':
case 'R':
if (gagged)
break;
Matched ("@trigger");
do_trigger (player, arg1, argv);
break;
case 'O':
case 'o':
if (strcmp (command, "@toad"))
goto bad;
do_toad (player, arg1);
break;
default:
goto bad;
}
break;
case 'u':
case 'U':
switch (command[2]) {
case 'l':
case 'L':
if (gagged)
break;
Matched ("@ulock");
do_lock (player, arg1, arg2, USELOCK);
break;
case 'n':
case 'N':
switch (command[4]) {
case 'i':
case 'I':
if (gagged)
break;
Matched ("@unlink");
do_unlink (player, arg1);
break;
case 'o':
case 'O':
if (gagged)
break;
Matched ("@unlock");
do_unlock (player, arg1, BASICLOCK);
break;
default:
goto bad;
}
break;
case 's':
case 'S':
if (gagged)
break;
Matched ("@use-does");
sprintf (buff3, "%s/does", arg1);
do_trigger (player, buff3, argv);
break;
case 'u':
case 'U':
if (gagged)
break;
Matched ("@uunlock");
do_unlock (player, arg1, USELOCK);
break;
default:
goto bad;
}
break;
case 'v':
case 'V':
if (string_prefix ("@version", command)) {
do_version (player);
}
break;
case 'w':
case 'W':
switch (command[2]) {
case 'a':
case 'A':
if (string_prefix ("@wait", command)) {
wait_que (player, atoi (arg1), arg2, cause);
} else if (string_prefix ("@wall", command)) {
Matched ("@wall");
do_wall (player, arg1, arg2, 1);
} else if (string_prefix ("@wallpose", command)) {
do_wall (player, arg1, arg2, 2);
} else if (string_prefix ("@wallemit", command)) {
do_wall (player, arg1, arg2, 3);
} else
goto bad;
break;
#ifdef PLAYER_LOCATE
case 'h':
case 'H':
if (gagged)
break;
Matched ("@whereis");
do_whereis (player, arg1);
break;
#endif /* PLAYER_LOCATE */
case 'i':
case 'I':
if (string_prefix ("@wizwall", command)) {
do_wizwall (player, arg1, arg2, 0, 1);
} else if (string_prefix ("@wizmotd", command)) {
do_motd (player, 2, arg1, arg2);
} else if (string_prefix ("@wizpose", command)) {
do_wizwall (player, arg1, arg2, 0, 2);
} else if (string_prefix ("@wizemit", command)) {
do_wizwall (player, arg1, arg2, 0, 3);
} else
goto bad;
break;
default:
goto bad;
}
break;
case 'z':
case 'Z':
if (gagged)
break;
Matched ("@zemit");
do_zemit (player, arg1, arg2);
break;
default:
goto bad;
}
break;
case 'b':
case 'B':
Matched ("brief");
do_examine (player, arg1, 1);
break;
case 'd':
case 'D':
if (Typeof (player) == TYPE_ROOM || Typeof (player) == TYPE_EXIT)
break;
Matched ("drop");
do_drop (player, arg1);
break;
case 'e':
case 'E':
switch (command[1]) {
case 'X':
case 'x':
case '\0':
Matched ("examine");
do_examine (player, arg1, 0);
break;
case 'N':
case 'n':
if (Typeof (player) == TYPE_EXIT || Typeof (player) == TYPE_ROOM)
break;
Matched ("enter");
do_enter (player, arg1);
break;
default:
goto bad;
}
break;
case 'g':
case 'G':
/* get, give, go, or gripe */
switch (command[1]) {
case 'e':
case 'E':
if (gagged ||
Typeof (player) == TYPE_ROOM || Typeof (player) == TYPE_EXIT)
break;
Matched ("get");
do_get (player, arg1);
break;
case 'i':
case 'I':
if (gagged)
break;
Matched ("give");
do_give (player, arg1, arg2);
break;
case 'o':
case 'O':
if (Typeof (player) == TYPE_EXIT || Typeof (player) == TYPE_ROOM)
break;
Matched ("goto");
do_move (player, arg1, 0);
break;
case 'r':
case 'R':
if (gagged)
break;
Matched ("gripe");
do_gripe (player, arg1, arg2);
break;
default:
goto bad;
}
break;
case 'h':
case 'H':
Matched ("help");
do_help (player, oldarg1);
break;
case 'i':
case 'I':
Matched ("inventory");
do_inventory (player);
break;
case 'k':
case 'K':
if (gagged)
break;
Matched ("kill");
do_kill (player, arg1, atol (arg2), 0);
break;
case 'l':
case 'L':
switch (command[1]) {
case 'o':
case 'O':
case '\0': /* patch allow 'l' command to do a look */
Matched ("look");
do_look_at (player, arg1);
break;
case 'E':
case 'e':
if (Typeof (player) == TYPE_ROOM || Typeof (player) == TYPE_EXIT)
break;
Matched ("leave");
do_leave (player);
break;
default:
goto bad;
}
break;
case 'm':
case 'M':
if (Typeof (player) == TYPE_ROOM || Typeof (player) == TYPE_EXIT)
break;
Matched ("move");
do_move (player, arg1, 0);
break;
case 'n':
case 'N':
/* news */
if (string_compare (command, "news"))
goto bad;
do_news (player, oldarg1);
break;
case 'p':
case 'P':
if (gagged)
break;
Matched ("page");
do_page (player, arg1, arg2);
break;
case 'r':
case 'R':
Matched ("read"); /* undocumented alias for look at */
do_look_at (player, arg1);
break;
case 's':
case 'S':
/* say, "score" */
switch (command[1]) {
case 'a':
case 'A':
if (gagged)
break;
Matched ("say");
do_say (player, arg1, arg2);
break;
case 'c':
case 'C':
Matched ("score");
do_score (player);
break;
case 'l':
case 'L':
Matched ("slay");
do_kill (player, arg1, 0, 1);
break;
default:
goto bad;
}
break;
case 't':
case 'T':
switch (command[1]) {
case 'a':
case 'A':
if (gagged ||
Typeof (player) == TYPE_ROOM || Typeof (player) == TYPE_EXIT)
break;
Matched ("take");
do_get (player, arg1);
break;
case 'h':
case 'H':
if (Typeof (player) == TYPE_ROOM || Typeof (player) == TYPE_EXIT)
break;
Matched ("throw");
do_drop (player, arg1);
break;
default:
goto bad;
}
break;
case 'w':
case 'W':
if (gagged)
break;
Matched ("whisper");
do_whisper (player, arg1, arg2);
break;
case 'u':
case 'U':
if (gagged)
break;
Matched ("use");
do_use (player, arg1);
break;
default:
bad:
/* try matching enter aliases */
if ((i = alias_list_check (db[getloc (player)].contents, unp,
"EALIAS")) != -1) {
sprintf (temp, "#%d", i);
do_enter (player, temp);
return;
}
/* if that didn't work, try matching leave aliases */
if ((Typeof (db[player].location) != TYPE_ROOM) &&
(quick_alias_check (db[player].location, unp, "LALIAS"))) {
do_leave (player);
return;
}
/* try matching user defined functions before chopping */
a = 0;
if (!gagged) {
if (getloc (player) != NOTHING) {
a +=
list_check (db[getloc (player)].contents, player, '$', ':', unp);
if (getloc (player) != player)
a += atr_comm_match (getloc (player), player, '$', ':', unp);
}
if (getloc (player) != player)
a += list_check (db[player].contents, player, '$', ':', unp);
/* try matching commands on area zone object if nothing is matched */
if ((!a) && (getzone (db[player].location) != NOTHING))
a += atr_comm_match (getzone (db[player].location), player,
'$', ':', unp);
/* try matching commands on your zone object if nothing is matched */
if ((!a) && (getzone (player) != NOTHING) &&
(getzone (db[player].location) != getzone (player)))
a += atr_comm_match (getzone (player), player, '$', ':', unp);
#ifdef DO_GLOBALS
/* check global exits only if no other commands are matched */
if ((!a) && (getloc (player) != MASTER_ROOM)) {
if (global_exit (player, unp)) {
if ((Typeof (player) == TYPE_ROOM) ||
(Typeof (player) == TYPE_EXIT))
return;
else {
do_move (player, unp, 1);
return;
}
} else
/* global user-defined commands checked if all else fails. */
/* May match more than one command in the master room. */
a += list_check (db[MASTER_ROOM].contents, player, '$', ':', unp);
}
#endif
}
if (!a) {
notify (player, "Huh? (Type \"help\" for help.)");
#ifdef LOG_FAILED_COMMANDS
if (!controls (player, getloc (player)) {
fprintf (stderr, "HUH from %s(%d) in %s(%d)[%s]: %s %s\n",
db[player].name, player,
db[getloc (player)].name, getloc (player);
db[db[getloc (player)].owner].name,
command, reconstruct_message (arg1, arg2));}
#endif /* LOG_FAILED_COMMANDS */
}
break;}
}
for (a = 0; a < MAX_ARG; a++) {
if (arge[a]) {
free ((char *) arge[a]);
#ifdef MEM_CHECK
del_check ("process_comm_args");
#endif
arge[a] = NULL;
}
}
}
/* match a list of things */
static int list_check (dbref thing, dbref player, int type, int end, char *str) {
int match = 0;
while (thing != NOTHING) {
if (atr_comm_match (thing, player, type, end, str))
match = 1;
thing = db[thing].next;
}
return (match);
}
static int alias_list_check (dbref thing, const char *command, char *type) {
ATTR * a;
char alias[BUFFER_LEN];
while (thing != NOTHING) {
a = atr_get (thing, type);
if (a) {
strcpy (alias, uncompress (a->value));
if (!string_compare (alias, command))
return thing; /* matched an alias */
}
thing = db[thing].next;
}
return -1;
}
static int quick_alias_check (dbref loc, const char *command, char *type) {
ATTR * a;
char alias[BUFFER_LEN];
a = atr_get (loc, type);
if (a) {
strcpy (alias, uncompress (a->value));
return (!string_compare (alias, command));
} else
return 0;
}
int Hearer (dbref thing) {
ALIST * ptr;
if (((Typeof (thing) == TYPE_PLAYER) &&
(db[thing].flags & PLAYER_CONNECT)) ||
((Typeof (thing) == TYPE_THING) && (db[thing].flags & THING_PUPPET)))
return (1);
for (ptr = db[thing].list; ptr; ptr = AL_NEXT (ptr)) {
if (!AL_BAD (ptr) && !string_compare (AL_NAME (ptr), "LISTEN"))
return 1;
}
return (0);
}
int Commer (dbref thing) {
ALIST * ptr;
for (ptr = db[thing].list; ptr; ptr = AL_NEXT (ptr)) {
if (!AL_BAD (ptr)) {
if (*AL_STR (ptr) == '$')
return (1);
}
}
return (0);
}
int Listener (dbref thing) {
ALIST * ptr;
for (ptr = db[thing].list; ptr; ptr = AL_NEXT (ptr)) {
if (!AL_BAD (ptr)) {
if (*AL_STR (ptr) == '^')
return (1);
}
}
return (0);
}
static void do_poor (dbref player, char *arg1) {
int amt = atoi (arg1);
dbref a;
if (!God (player))
return;
for (a = 0; a < db_top; a++)
if (Typeof (a) == TYPE_PLAYER)
s_Pennies (a, amt);
}
static void do_version (dbref player) {
notify (player, tprintf ("The code running is %s", VERSION));
}
static void do_dolist (dbref player, char *inlist, char *command, dbref cause) {
char *list, *first, *rest, *fix1, *fix2;
char buff[BUFFER_LEN], tbuf1[BUFFER_LEN], tbuf2[BUFFER_LEN];
tbuf2[0] = tbuf1[0] = '\0';
strcpy (tbuf2, inlist);
strcpy (tbuf1, pronoun_substitute (cause, tbuf2, player));
list = tbuf1;
while (first = parse_up (&list, ' ')) {
fix1 = buff;
fix2 = command;
while (*fix2) {
rest = first;
while (*fix2 && (*fix2 != NUMBER_TOKEN))
*fix1++ = *fix2++;
if ((*fix2 == NUMBER_TOKEN) && (*(fix2 + 1) == NUMBER_TOKEN)) {
fix2++; fix2++;
while (rest && *rest)
*fix1++ = *rest++;
} else
*fix1++ = *fix2++;
}
*fix1 = '\0';
strcpy (tbuf2, pronoun_substitute (cause, buff, player));
parse_que (player, tbuf2, cause);
}
}
static void do_config (dbref player) {
notify (player, "----- MUSH CONFIGURATION -----");
#ifdef RESTRICTED_BUILDING
#ifdef FREE_OBJECTS
notify (player, "Players without a BUILDER bit can only create objects.");
#else
notify (player, "Players without a BUILDER bit cannot build anything.");
#endif
#endif
#ifdef QUOTA
notify (player, "Quota restrictions are in effect.");
#endif
#ifdef LOG_COMMANDS
notify (player, "All commands are being logged.");
#endif
#ifdef LOG_FAILED_COMMANDS
notify (player, "Commands which produce a " Huh ? " are being logged.");
#endif
#ifdef NO_FORK
notify (player, "Forking is disabled. Game will freeze during dumps.");
#endif
#ifdef USE_MAILER
notify (player, "The built-in MUSH mailing system is being used.");
#endif
#ifdef LOCKOUT
notify (player, "Site lockout is enabled.");
#endif
#ifdef WCREAT
notify (player, "Player registration is in effect.");
#endif
#ifdef DESTROY
notify (player, "Object recycling is enabled.");
#endif
#ifdef FLAGS_ON_EXAMINE
notify (player, "Expanded flag list is shown on examines.");
#endif
#ifdef FULL_INVIS
notify (player, "Dark players/objects show up as Someone/Something.");
#endif
#ifdef PLAYER_LOCATE
notify (player,
"The location of players not set UNFINDABLE can be found.");
#endif
#ifdef AT_DOING
notify (player, "Doing polls are enabled.");
#endif
#ifdef ROYALTY_FLAG
notify (player, "The ROYALTY flag is enabled.");
#endif
#ifdef INHERIT_FLAG
notify (player, "The INHERIT flag is enabled.");
#endif
#ifdef DO_GLOBALS
notify (player, tprintf ("The master room is #%d.", MASTER_ROOM));
#endif
#ifdef GUEST_RESTRICT
notify (player, tprintf ("The guest player is #%d.", GUEST_PLAYER));
#endif
#ifdef IDLE_TIMEOUT
notify (player,
tprintf ("The inactivity limit is %d minutes.", INACTIVITY_LIMIT));
#endif
notify (player, "----- BUILDING COSTS -----");
notify (player, tprintf ("Object creation....%d", OBJECT_COST));
notify (player, tprintf ("Room creation......%d", ROOM_COST));
notify (player, tprintf ("Exit creation......%d", EXIT_COST));
notify (player, tprintf ("Linking............%d", LINK_COST));
notify (player, tprintf ("Queue deposit......%d", QUEUE_COST));
notify (player, tprintf ("Quota per object...%d", QUOTA_COST));
notify (player, "----- COMMAND COSTS -----");
notify (player, tprintf ("@find..............%d", FIND_COST));
notify (player, tprintf ("page...............%d", PAGE_COST));
notify (player, tprintf ("kill base cost.....%d", KILL_BASE_COST));
notify (player, tprintf ("kill minimum cost..%d", KILL_MIN_COST));
notify (player, tprintf ("kill insurance.....%d", KILL_BONUS));
}
#undef Matched