/* game.c */
#include <ctype.h>
#include <fcntl.h>
#include <string.h>
#ifdef XENIX
#include <sys/signal.h>
#else
#include <signal.h>
#include <sys/wait.h>
#endif /* xenix */
#include <sys/time.h>
#include <sys/types.h>
#include "config.h"
#include "db.h"
#include "externs.h"
#include "interface.h"
#include "match.h"
#ifdef MEM_CHECK
#include "mem_check.h"
#endif
#ifdef USE_NALLOC
#include "nalloc.h"
NALLOC *glurp;
#endif
/* declarations */
char dumpfile[200];
static int epoch = 0;
int reserved;
int depth = 0; /* excessive recursion prevention */
extern dbref cplr;
extern char ccom[];
void fork_and_dump();
void dump_database();
extern void exec();
/*
* used to allocate storage for temporary stuff, cleared before command
* execution
*/
void do_dump(player)
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()
{
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
void do_purge(player)
dbref player;
{
if (Wizard(player)) {
FIX;
notify(player, "Purge complete.");
} else
notify(player, "Sorry, you are a mortal.");
}
void dest_info(thing, tt)
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(player, msg)
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, 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, '^', ':', msg);
/* unlike normal @listen, don't pass the message on */
}
/* now check for multi listeners */
}
depth--;
}
void do_shutdown(player)
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.");
}
}
#ifdef XENIX
/* rename hack!!! */
rename(s1, s2)
char *s1;
char *s2;
{
char buff[300];
sprintf(buff, "mv %s %s", s1, s2);
system(buff);
}
#endif
static void dump_database_internal()
{
char tmpfl[2048];
FILE *f;
extern int unlink();
sprintf(tmpfl, "%s.#%d#", dumpfile, epoch - 1);
unlink(tmpfl); /* nuke our predecessor */
sprintf(tmpfl, "%s.#%d#", dumpfile, epoch);
#ifdef DBCOMP
if ((f = popen(tprintf("compress >%s", tmpfl), "w")) != NULL) {
db_write(f);
pclose(f);
if (rename(tmpfl, dumpfile) < 0)
perror(tmpfl);
} else
perror(tmpfl);
#ifdef USE_MAILER
sprintf(tmpfl, "maildb.Z.#%d#", epoch - 1);
unlink(tmpfl);
sprintf(tmpfl, "maildb.Z.#%d#", epoch);
if (mdb_top > 0)
if ((f = popen(tprintf("compress >%s", tmpfl), "w")) != NULL) {
dump_mail(f);
pclose(f);
if (rename(tmpfl, "maildb.Z") < 0)
perror(tmpfl);
} else
perror(tmpfl);
#endif
#else
if ((f = fopen(tmpfl, "w")) != NULL) {
db_write(f);
fclose(f);
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, "w")) != NULL) {
db_write(f);
fclose(f);
if (rename(tmpfl, "maildb") < 0)
perror(tmpfl);
} else
perror(tmpfl);
#endif
#endif
}
void panic(message)
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, "w")) == NULL) {
perror("CANNOT OPEN PANIC FILE, YOU LOSE:");
_exit(135);
} else {
fprintf(stderr, "DUMPING: %s\n", panicfile);
db_write(f);
fclose(f);
fprintf(stderr, "DUMPING: %s (done)\n", panicfile);
_exit(136);
}
}
void dump_database()
{
epoch++;
fprintf(stderr, "DUMPING: %s.#%d#\n", dumpfile, epoch);
dump_database_internal();
fprintf(stderr, "DUMPING: %s.#%d# (done)\n", dumpfile, epoch);
}
static int reaper()
{
#ifdef XENIX
int status;
wait(&status);
#else
union wait my_stat;
while (wait3(&my_stat, WNOHANG, 0) > 0) ;
#endif
return 0;
}
void fork_and_dump()
{
int child;
epoch++;
fprintf(stderr, "CHECKPOINTING: %s.#%d#\n", dumpfile, epoch);
#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 */
close(reserved); /* get that file descriptor back */
#ifdef CONCENTRATOR
#ifndef XENIX
signal(SIGCHLD, SIG_DFL);
#else
signal(SIGCLD, SIG_DFL);
#endif /* XENIX */
#endif /* CONCENTRATOR */
dump_database_internal();
#ifndef NO_FORK
_exit(0); /* !!! */
#else /* NO FORK */
reserved = open("/dev/null", O_RDWR);
#ifdef CONCENTRATOR
#ifndef XENIX
signal(SIGCHLD, (void *) reaper);
#else
signal(SIGCLD, (void *) reaper);
#endif /* XENIX */
#endif /* CONCENTRATOR */
#endif /* NO_FORK */
} else if (child < 0) {
perror("fork_and_dump: fork()");
}
}
void do_restart()
{
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(infile, outfile)
const char *infile;
const char *outfile;
{
FILE *f;
int a;
extern void init_timer();
depth = 0;
#ifdef USE_NALLOC
glurp = na_open(sizeof(char));
#endif
for (a = 0; a < 10; a++)
wptr[a] = NULL;
#ifdef DBCOMP
if ((f = popen(tprintf("uncompress < %s", infile), "r")) == NULL)
return -1;
#else
if ((f = fopen(infile, "r")) == 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 = popen("uncompress <maildb.Z", "r")) == NULL)
mail_init();
#else
if ((f = fopen("maildb", "r")) == 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 */
/* initialize random number generator */
srandom(getpid());
/* set up dumper */
strcpy(dumpfile, outfile);
init_timer();
#ifndef XENIX
signal(SIGCHLD, (void *)reaper);
#else /* xenix */
signal(SIGCLD, (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 */
char *do_argtwo(player, rest, cause, buff)
dbref player;
char *rest;
dbref cause;
char *buff;
{
exec(&rest, buff, player, cause, 0);
return (buff);
}
char **do_argbee(player, rest, cause, arge, buff)
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]) {
#ifdef USE_NALLOC
na_unalloc(glurp, arge[a]);
#else
free((char *) arge[a]);
#endif
#ifdef MEM_CHECK
del_check("process_comm_args");
#endif
}
p = parse_up(&rest, ',');
if(p) {
#ifdef USE_NALLOC
strcpy((arge[a] = (char *) na_ualloc(glurp, strlen(p)+1)), p);
#else
strcpy((arge[a] = (char *)malloc(strlen(p)+1)), p);
#endif
#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);
#ifdef USE_NALLOC
na_unalloc(glurp, arge[a]);
strcpy((arge[a] = (char *) na_ualloc(glurp, strlen(buff) + 1)), buff);
#else
free((char *)arge[a]);
strcpy((arge[a] = (char *)malloc(strlen(buff)+1)), buff);
#endif
}
return (arge);
}
#define arg2 do_argtwo(player,rest,cause,buff)
#define argv do_argbee(player,rest,cause,arge,buff)
void process_command(player, command, cause)
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 */
void do_poor(), do_version(), do_dolist(), do_config();
extern void wait_que();
#ifdef USE_NALLOC
na_clear(glurp);
#endif
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) */
srandom((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(*command))
command++;
/* eat extra white space */
q = p = command;
while (*p) {
/* scan over word */
while (*p && !isspace(*p))
*q++ = *p++;
/* smash spaces */
while (*p && isspace(*++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);
} else {
strcpy(unp, command);
/* parse arguments */
/* find arg1 */
/* move over command word */
for (arg1 = command; *arg1 && !isspace(*arg1); arg1++) ;
/* truncate command */
if (*arg1)
*arg1++ = '\0';
/* move over spaces */
while (*arg1 && isspace(*arg1))
arg1++;
r = parse_up(&arg1, '='); /* first delimiter is ='s */
if(r) {
if(arge[0]) {
#ifdef USE_NALLOC
na_unalloc(glurp, arge[0]);
#else
free((char *)arge[0]);
#endif
#ifdef MEM_CHECK
del_check("process_comm_args");
#endif
}
#ifdef USE_NALLOC
strcpy((arge[0] = (char *) na_ualloc(glurp, strlen(r)+1)), r);
#else
strcpy((arge[0] = (char *)malloc(strlen(r)+1)), r);
#endif
#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);
#ifdef USE_NALLOC
na_unalloc(glurp, arge[0]);
strcpy((arge[0] = (char *) na_ualloc(glurp, strlen(r) + 1)), r);
#else
free((char *)arge[0]);
strcpy((arge[0] = (char *)malloc(strlen(r)+1)), r);
#endif
} 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]) {
#ifdef USE_NALLOC
na_unalloc(glurp, arge[a]);
#else
free((char *) arge[a]);
#endif
#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);
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);
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]) {
#ifdef USE_NALLOC
na_unalloc(glurp, (char *) arge[a]);
#else
free((char *) arge[a]);
#endif
#ifdef MEM_CHECK
del_check("process_comm_args");
#endif
arge[a] = NULL;
}
}
}
/* match a list of things */
int list_check(thing, player, type, end, str)
dbref thing, player;
char type, 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);
}
int alias_list_check(thing, command, type)
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;
}
int quick_alias_check(loc, command, type)
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(thing)
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(thing)
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(thing)
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);
}
void do_poor(player, arg1)
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);
}
void do_version(player)
dbref player;
{
notify(player,tprintf("The code running is %s",VERSION));
}
void do_dolist(player, inlist, command, cause)
dbref player, cause;
char *inlist, *command;
{
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);
}
}
void do_config(player)
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 CONCENTRATOR
notify(player, "Concentrator is enabled.");
#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