/* $Header: /cvsroot/fbmuck/fbmuck/src/game.c,v 1.37 2003/10/07 07:22:53 revar Exp $ */ #include "copyright.h" #include "config.h" #include <stdio.h> #include <ctype.h> #include <signal.h> #ifndef WIN32 #include <sys/wait.h> #endif #include "db.h" #include "props.h" #include "params.h" #include "tune.h" #include "interface.h" #include "match.h" #include "externs.h" #include "fbstrings.h" /* declarations */ static const char *dumpfile = 0; static int epoch = 0; time_t last_monolithic_time = 0; static int forked_dump_process_flag = 0; FILE *input_file; FILE *delta_infile; FILE *delta_outfile; char *in_filename = NULL; void fork_and_dump(void); void dump_database(void); void do_dump(dbref player, const char *newfile) { char buf[BUFFER_LEN]; if (Wizard(player)) { #ifndef DISKBASE if (global_dumper_pid != 0) { notify(player, "Sorry, there is already a dump currently in progress."); return; } #endif if (*newfile #ifdef GOD_PRIV && God(player) #endif /* GOD_PRIV */ ) { if (dumpfile) free((void *) dumpfile); dumpfile = alloc_string(newfile); snprintf(buf, sizeof(buf), "Dumping to file %s...", dumpfile); } else { snprintf(buf, sizeof(buf), "Dumping..."); } notify(player, buf); dump_db_now(); } else { notify(player, "Sorry, you are in a no dumping zone."); } } void do_delta(dbref player) { if (Wizard(player)) { #ifdef DELTADUMPS notify(player, "Dumping deltas..."); delta_dump_now(); #else notify(player, "Sorry, this server was compiled without DELTADUMPS."); #endif } else { notify(player, "Sorry, you are in a no dumping zone."); } } void do_shutdown(dbref player) { if (Wizard(player)) { log_status("SHUTDOWN: by %s\n", unparse_object(player, player)); shutdown_flag = 1; restart_flag = 0; } else { notify(player, "Your delusions of grandeur have been duly noted."); log_status("ILLEGAL SHUTDOWN: tried by %s\n", unparse_object(player, player)); } } void do_restart(dbref player) { if (Wizard(player)) { log_status("SHUTDOWN & RESTART: by %s\n", unparse_object(player, player)); shutdown_flag = 1; restart_flag = 1; } else { notify(player, "Your delusions of grandeur have been duly noted."); log_status("ILLEGAL RESTART: tried by %s\n", unparse_object(player, player)); } } #ifdef DISKBASE extern long propcache_hits; extern long propcache_misses; #endif static void dump_database_internal(void) { char tmpfile[2048]; FILE *f; snprintf(tmpfile, sizeof(tmpfile), "%s.#%d#", dumpfile, epoch - 1); (void) unlink(tmpfile); /* nuke our predecessor */ snprintf(tmpfile, sizeof(tmpfile), "%s.#%d#", dumpfile, epoch); if ((f = fopen(tmpfile, "wb")) != NULL) { db_write(f); fclose(f); #ifdef DISKBASE fclose(input_file); #endif #ifdef DELTADUMPS fclose(delta_outfile); fclose(delta_infile); #endif #ifdef WIN32 (void) unlink(dumpfile); /* Delete old file before rename */ #endif if (rename(tmpfile, dumpfile) < 0) perror(tmpfile); #ifdef DISKBASE free((void *) in_filename); in_filename = string_dup(dumpfile); if ((input_file = fopen(in_filename, "rb")) == NULL) perror(dumpfile); #endif #ifdef DELTADUMPS if ((delta_outfile = fopen(DELTAFILE_NAME, "wb")) == NULL) perror(DELTAFILE_NAME); if ((delta_infile = fopen(DELTAFILE_NAME, "rb")) == NULL) perror(DELTAFILE_NAME); #endif } else { perror(tmpfile); } /* Write out the macros */ snprintf(tmpfile, sizeof(tmpfile), "%s.#%d#", MACRO_FILE, epoch - 1); (void) unlink(tmpfile); snprintf(tmpfile, sizeof(tmpfile), "%s.#%d#", MACRO_FILE, epoch); if ((f = fopen(tmpfile, "w")) != NULL) { macrodump(macrotop, f); fclose(f); #ifdef WIN32 unlink(MACRO_FILE); #endif if (rename(tmpfile, MACRO_FILE) < 0) perror(tmpfile); } else { perror(tmpfile); } sync(); #ifdef DISKBASE /* Only show dumpdone mesg if not doing background saves. */ if (tp_dbdump_warning && tp_dumpdone_warning) wall_and_flush(tp_dumpdone_mesg); #endif #ifdef DISKBASE propcache_hits = 0L; propcache_misses = 1L; #endif } void panic(const char *message) { char panicfile[2048]; FILE *f; log_status("PANIC: %s\n", message); fprintf(stderr, "PANIC: %s\n", message); /* shut down interface */ if (!forked_dump_process_flag) { emergency_shutdown(); } /* dump panic file */ snprintf(panicfile, sizeof(panicfile), "%s.PANIC", dumpfile); if ((f = fopen(panicfile, "wb")) == NULL) { perror("CANNOT OPEN PANIC FILE, YOU LOSE"); sync(); #ifdef NOCOREDUMP exit(135); #else /* !NOCOREDUMP */ # ifdef SIGIOT signal(SIGIOT, SIG_DFL); # endif abort(); #endif /* NOCOREDUMP */ } else { log_status("DUMPING: %s\n", panicfile); fprintf(stderr, "DUMPING: %s\n", panicfile); db_write(f); fclose(f); log_status("DUMPING: %s (done)\n", panicfile); fprintf(stderr, "DUMPING: %s (done)\n", panicfile); (void) unlink(DELTAFILE_NAME); } /* Write out the macros */ snprintf(panicfile, sizeof(panicfile), "%s.PANIC", MACRO_FILE); if ((f = fopen(panicfile, "w")) != NULL) { macrodump(macrotop, f); fclose(f); } else { perror("CANNOT OPEN MACRO PANIC FILE, YOU LOSE"); sync(); #ifdef NOCOREDUMP exit(135); #else /* !NOCOREDUMP */ #ifdef SIGIOT signal(SIGIOT, SIG_DFL); #endif abort(); #endif /* NOCOREDUMP */ } sync(); #ifdef NOCOREDUMP exit(136); #else /* !NOCOREDUMP */ #ifdef SIGIOT signal(SIGIOT, SIG_DFL); #endif abort(); #endif /* NOCOREDUMP */ } void dump_database(void) { epoch++; log_status("DUMPING: %s.#%d#\n", dumpfile, epoch); dump_database_internal(); log_status("DUMPING: %s.#%d# (done)\n", dumpfile, epoch); } /* * Named "fork_and_dump()" mostly for historical reasons... */ void fork_and_dump(void) { epoch++; #ifndef DISKBASE if (global_dumper_pid != 0) { wall_wizards("## Dump already in progress. Skipping redundant scheduled dump."); return; } #endif last_monolithic_time = time(NULL); log_status("CHECKPOINTING: %s.#%d#\n", dumpfile, epoch); if (tp_dbdump_warning) wall_and_flush(tp_dumping_mesg); #ifdef DISKBASE dump_database_internal(); #else if ((global_dumper_pid=fork())==0) { forked_dump_process_flag = 1; set_dumper_signals(); dump_database_internal(); _exit(0); } #endif } #ifdef DELTADUMPS extern int deltas_count; int time_for_monolithic(void) { dbref i; int count = 0; long a, b; if (!last_monolithic_time) last_monolithic_time = time(NULL); if (time(NULL) - last_monolithic_time >= (tp_monolithic_interval - tp_dump_warntime) ) { return 1; } for (i = 0; i < db_top; i++) if (FLAGS(i) & (SAVED_DELTA | OBJECT_CHANGED)) count++; if (((count * 100) / db_top) > tp_max_delta_objs) { return 1; } fseek(delta_infile, 0L, 2); a = ftell(delta_infile); fseek(input_file, 0L, 2); b = ftell(input_file); if (a >= b) { return 1; } return 0; } #endif void dump_warning(void) { if (tp_dbdump_warning) { #ifdef DELTADUMPS if (time_for_monolithic()) { wall_and_flush(tp_dumpwarn_mesg); } else { if (tp_deltadump_warning) { wall_and_flush(tp_deltawarn_mesg); } } #else wall_and_flush(tp_dumpwarn_mesg); #endif } } #ifdef DELTADUMPS void dump_deltas(void) { if (time_for_monolithic()) { fork_and_dump(); deltas_count = 0; return; } epoch++; log_status("DELTADUMP: %s.#%d#\n", dumpfile, epoch); if (tp_deltadump_warning) wall_and_flush(tp_dumpdeltas_mesg); db_write_deltas(delta_outfile); if (tp_deltadump_warning && tp_dumpdone_warning) wall_and_flush(tp_dumpdone_mesg); #ifdef DISKBASE propcache_hits = 0L; propcache_misses = 1L; #endif } #endif extern short db_conversion_flag; int init_game(const char *infile, const char *outfile) { FILE *f; if ((f = fopen(MACRO_FILE, "r")) == NULL) log_status("INIT: Macro storage file %s is tweaked.\n", MACRO_FILE); else { macroload(f); fclose(f); } in_filename = (char *) string_dup(infile); if ((input_file = fopen(infile, "rb")) == NULL) return -1; #ifdef DELTADUMPS if ((delta_outfile = fopen(DELTAFILE_NAME, "wb")) == NULL) return -1; if ((delta_infile = fopen(DELTAFILE_NAME, "rb")) == NULL) return -1; #endif db_free(); init_primitives(); /* init muf compiler */ mesg_init(); /* init mpi interpreter */ SRANDOM(getpid()); /* init random number generator */ tune_load_parmsfile(NOTHING); /* load @tune parms from file */ /* ok, read the db in */ log_status("LOADING: %s\n", infile); fprintf(stderr, "LOADING: %s\n", infile); if (db_read(input_file) < 0) return -1; log_status("LOADING: %s (done)\n", infile); fprintf(stderr, "LOADING: %s (done)\n", infile); /* set up dumper */ if (dumpfile) free((void *) dumpfile); dumpfile = alloc_string(outfile); if (!db_conversion_flag) { /* initialize the _sys/startuptime property */ add_property((dbref) 0, "_sys/startuptime", NULL, (int) time((time_t *) NULL)); add_property((dbref) 0, "_sys/maxpennies", NULL, tp_max_pennies); add_property((dbref) 0, "_sys/dumpinterval", NULL, tp_dump_interval); add_property((dbref) 0, "_sys/max_connects", NULL, 0); } return 0; } void cleanup_game() { if (dumpfile) free((void *) dumpfile); free((void *) in_filename); } extern short wizonly_mode; void do_restrict(dbref player, const char *arg) { if (!Wizard(player)) { notify(player, "Permission Denied."); return; } if (!strcmp(arg, "on")) { wizonly_mode = 1; notify(player, "Login access is now restricted to wizards only."); } else if (!strcmp(arg, "off")) { wizonly_mode = 0; notify(player, "Login access is now unrestricted."); } else { notify_fmt(player, "Restricted connection mode is currently %s.", wizonly_mode ? "on" : "off" ); } } /* use this only in process_command */ #define Matched(string) { if(!string_prefix((string), command)) goto bad; } int force_level = 0; dbref force_prog = NOTHING; /* Set when a program is the source of FORCE */ void process_command(int descr, dbref player, char *command) { char *arg1; char *arg2; char *full_command; char *p; /* utility */ char pbuf[BUFFER_LEN]; char xbuf[BUFFER_LEN]; char ybuf[BUFFER_LEN]; struct timeval starttime; struct timeval endtime; double totaltime; if (command == 0) abort(); /* robustify player */ if (player < 0 || player >= db_top || (Typeof(player) != TYPE_PLAYER && Typeof(player) != TYPE_THING)) { log_status("process_command: bad player %d\n", player); return; } if ((tp_log_commands || Wizard(OWNER(player)))) { if (!(FLAGS(player) & (INTERACTIVE | READMODE))) { if (!*command) { return; } log_command("%s%s%s%s(%d) in %s(%d):%s %s\n", Wizard(OWNER(player)) ? "WIZ: " : "", (Typeof(player) != TYPE_PLAYER) ? NAME(player) : "", (Typeof(player) != TYPE_PLAYER) ? " owned by " : "", NAME(OWNER(player)), (int) player, NAME(DBFETCH(player)->location), (int) DBFETCH(player)->location, " ", command); } else { if (tp_log_interactive) { log_command("%s%s%s%s(%d) in %s(%d):%s %s\n", Wizard(OWNER(player)) ? "WIZ: " : "", (Typeof(player) != TYPE_PLAYER) ? NAME(player) : "", (Typeof(player) != TYPE_PLAYER) ? " owned by " : "", NAME(OWNER(player)), (int) player, NAME(DBFETCH(player)->location), (int) DBFETCH(player)->location, (FLAGS(player) & (READMODE)) ? " [READ] " : " [INTERP] ", command); } } } if (FLAGS(player) & INTERACTIVE) { interactive(descr, player, command); return; } /* eat leading whitespace */ while (*command && isspace(*command)) command++; /* Disable null command once past READ line */ if (!*command) return; /* check for single-character commands */ if (!tp_enable_prefix) { if (*command == SAY_TOKEN) { snprintf(pbuf, sizeof(pbuf), "say %s", command + 1); command = &pbuf[0]; } else if (*command == POSE_TOKEN) { snprintf(pbuf, sizeof(pbuf), "pose %s", command + 1); command = &pbuf[0]; } else if (*command == EXIT_DELIMITER) { snprintf(pbuf, sizeof(pbuf), "delimiter %s", command + 1); command = &pbuf[0]; } } /* profile how long command takes. */ gettimeofday(&starttime, NULL); /* if player is a wizard, and uses overide token to start line... */ /* ... then do NOT run actions, but run the command they specify. */ if (!(TrueWizard(OWNER(player)) && (*command == OVERIDE_TOKEN))) { if (can_move(descr, player, command, 0)) { do_move(descr, player, command, 0); /* command is exact match for exit */ *match_args = 0; *match_cmdname = 0; } else { if (tp_enable_prefix) { if (*command == SAY_TOKEN) { snprintf(pbuf, sizeof(pbuf), "say %s", command + 1); command = &pbuf[0]; } else if (*command == POSE_TOKEN) { snprintf(pbuf, sizeof(pbuf), "pose %s", command + 1); command = &pbuf[0]; } else if (*command == EXIT_DELIMITER) { snprintf(pbuf, sizeof(pbuf), "delimiter %s", command + 1); command = &pbuf[0]; } else { goto bad_pre_command; } if (can_move(descr, player, command, 0)) { do_move(descr, player, command, 0); /* command is exact match for exit */ *match_args = 0; *match_cmdname = 0; } else { goto bad_pre_command; } } else { goto bad_pre_command; } } } else { bad_pre_command: if (TrueWizard(OWNER(player)) && (*command == OVERIDE_TOKEN)) command++; full_command = strcpy(xbuf, command); for (; *full_command && !isspace(*full_command); full_command++) ; if (*full_command) full_command++; /* find arg1 -- move over command word */ command = strcpy(ybuf, command); for (arg1 = command; *arg1 && !isspace(*arg1); arg1++) ; /* truncate command */ if (*arg1) *arg1++ = '\0'; /* remember command for programs */ strcpy(match_cmdname, command); /* move over spaces */ while (*arg1 && isspace(*arg1)) arg1++; /* find end of arg1, start of arg2 */ for (arg2 = arg1; *arg2 && *arg2 != ARG_DELIMITER; arg2++) ; /* truncate arg1 */ for (p = arg2 - 1; p >= arg1 && isspace(*p); p--) *p = '\0'; /* go past delimiter if present */ if (*arg2) *arg2++ = '\0'; while (*arg2 && isspace(*arg2)) arg2++; strcpy(match_cmdname, command); strcpy(match_args, full_command); switch (command[0]) { case '@': switch (command[1]) { case 'a': case 'A': /* @action, @armageddon, @attach */ switch (command[2]) { case 'c': case 'C': Matched("@action"); do_action(descr, player, arg1, arg2); break; case 'r': case 'R': if (strcmp(command, "@armageddon")) goto bad; do_armageddon(player, full_command); break; case 't': case 'T': Matched("@attach"); do_attach(descr, player, arg1, arg2); break; default: goto bad; } break; case 'b': case 'B': /* @bless, @boot */ switch (command[2]) { case 'l': case 'L': Matched("@bless"); do_bless(descr, player, arg1, arg2); break; case 'o': case 'O': Matched("@boot"); do_boot(player, arg1); break; default: goto bad; } break; case 'c': case 'C': /* @chlock, @chown, @chown_lock, @clone, @conlock, @contents, @create, @credits */ switch (command[2]) { case 'h': case 'H': switch (command[3]) { case 'l': case 'L': Matched("@chlock"); do_chlock(descr, player, arg1, arg2); break; case 'o': case 'O': if(strlen(command) < 7) { Matched("@chown"); do_chown(descr, player, arg1, arg2); } else { Matched("@chown_lock"); do_chlock(descr, player, arg1, arg2); } break; default: goto bad; } break; case 'l': case 'L': Matched("@clone"); do_clone(descr, player, arg1); break; case 'o': case 'O': switch (command[4]) { case 'l': case 'L': Matched("@conlock"); do_conlock(descr, player, arg1, arg2); break; case 't': case 'T': Matched("@contents"); do_contents(descr, player, arg1, arg2); break; default: goto bad; } break; case 'r': case 'R': if (string_compare(command, "@credits")) { Matched("@create"); do_create(player, arg1, arg2); } else { do_credits(player); } break; default: goto bad; } break; case 'd': case 'D': /* @dbginfo, @delta, @describe, @dig, @dlt, @doing, @drop, @dump */ switch (command[2]) { case 'b': case 'B': Matched("@dbginfo"); do_serverdebug(descr, player, arg1, arg2); break; case 'e': case 'E': if(command[3] == 'l' || command[3] == 'L') { Matched("@delta"); do_delta(player); } else { Matched("@describe"); do_describe(descr, player, arg1, arg2); } break; case 'i': case 'I': Matched("@dig"); do_dig(descr, player, arg1, arg2); break; case 'l': case 'L': Matched("@dlt"); do_delta(player); break; case 'o': case 'O': Matched("@doing"); if (!tp_who_doing) goto bad; do_doing(descr, player, arg1, arg2); break; case 'r': case 'R': Matched("@drop"); do_drop_message(descr, player, arg1, arg2); break; case 'u': case 'U': Matched("@dump"); do_dump(player, full_command); break; default: goto bad; } break; case 'e': case 'E': /* @edit, @entrances, @examine */ switch (command[2]) { case 'd': case 'D': Matched("@edit"); do_edit(descr, player, arg1); break; case 'n': case 'N': Matched("@entrances"); do_entrances(descr, player, arg1, arg2); break; case 'x': case 'X': Matched("@examine"); sane_dump_object(player, arg1); break; default: goto bad; } break; case 'f': case 'F': /* @fail, @find, @flock, @force, @force_lock */ switch (command[2]) { case 'a': case 'A': Matched("@fail"); do_fail(descr, player, arg1, arg2); break; case 'i': case 'I': Matched("@find"); do_find(player, arg1, arg2); break; case 'l': case 'L': Matched("@flock"); do_flock(descr, player, arg1, arg2); break; case 'o': case 'O': if(strlen(command) < 7) { Matched("@force"); do_force(descr, player, arg1, arg2); } else { Matched("@force_lock"); do_flock(descr, player, arg1, arg2); } break; default: goto bad; } break; case 'i': case 'I': /* @idescribe */ Matched("@idescribe"); do_idescribe(descr, player, arg1, arg2); break; case 'k': case 'K': /* @kill */ Matched("@kill"); do_dequeue(descr, player, arg1); break; case 'l': case 'L': /* @link, @list, @lock */ switch (command[2]) { case 'i': case 'I': switch (command[3]) { case 'n': case 'N': Matched("@link"); do_link(descr, player, arg1, arg2); break; case 's': case 'S': Matched("@list"); match_and_list(descr, player, arg1, arg2); break; default: goto bad; } break; case 'o': case 'O': Matched("@lock"); do_lock(descr, player, arg1, arg2); break; default: goto bad; } break; case 'm': case 'M': /* @mcpedit, @mcpprogram, @memory, @mpitops, @muftops */ switch (command[2]) { case 'c': case 'C': if (string_prefix("@mcpedit", command)) { Matched("@mcpedit"); do_mcpedit(descr, player, arg1); break; } else { Matched("@mcpprogram"); do_mcpprogram(descr, player, arg1); break; } case 'e': case 'E': Matched("@memory"); do_memory(player); break; case 'p': case 'P': Matched("@mpitops"); do_mpi_topprofs(player, arg1); break; case 'u': case 'U': Matched("@muftops"); do_muf_topprofs(player, arg1); break; default: goto bad; } break; case 'n': case 'N': /* @name, @newpassword */ switch (command[2]) { case 'a': case 'A': Matched("@name"); do_name(descr, player, arg1, arg2); break; case 'e': case 'E': if (strcmp(command, "@newpassword")) goto bad; do_newpassword(player, arg1, arg2); break; default: goto bad; } break; case 'o': case 'O': /* @odrop, @oecho, @ofail, @open, @osuccess, @owned */ switch (command[2]) { case 'd': case 'D': Matched("@odrop"); do_odrop(descr, player, arg1, arg2); break; case 'e': case 'E': Matched("@oecho"); do_oecho(descr, player, arg1, arg2); break; case 'f': case 'F': Matched("@ofail"); do_ofail(descr, player, arg1, arg2); break; case 'p': case 'P': Matched("@open"); do_open(descr, player, arg1, arg2); break; case 's': case 'S': Matched("@osuccess"); do_osuccess(descr, player, arg1, arg2); break; case 'w': case 'W': Matched("@owned"); do_owned(player, arg1, arg2); break; default: goto bad; } break; case 'p': case 'P': /* @password, @pcreate, @pecho, @program, @propset, @ps */ switch (command[2]) { case 'a': case 'A': Matched("@password"); do_password(player, arg1, arg2); break; case 'c': case 'C': Matched("@pcreate"); do_pcreate(player, arg1, arg2); break; case 'e': case 'E': Matched("@pecho"); do_pecho(descr, player, arg1, arg2); break; case 'r': case 'R': if (string_prefix("@program", command)) { Matched("@program"); do_prog(descr, player, arg1); break; } else { Matched("@propset"); do_propset(descr, player, arg1, arg2); break; } case 's': case 'S': Matched("@ps"); list_events(player); break; default: goto bad; } break; case 'r': case 'R': /* @recycle, @relink, @restart, @restrict */ switch (command[3]) { case 'c': case 'C': Matched("@recycle"); do_recycle(descr, player, arg1); break; case 'l': case 'L': Matched("@relink"); do_relink(descr, player, arg1, arg2); break; case 's': case 'S': if (!strcmp(command, "@restart")) { do_restart(player); } else if (!strcmp(command, "@restrict")) { do_restrict(player, arg1); } else { goto bad; } break; default: goto bad; } break; case 's': case 'S': /* @sanity, @sanchange, @sanfix, @set, @shutdown, @stats, @success, @sweep */ switch (command[2]) { case 'a': case 'A': if (!strcmp(command, "@sanity")) { sanity(player); } else if (!strcmp(command, "@sanchange")) { sanechange(player, full_command); } else if (!strcmp(command, "@sanfix")) { sanfix(player); } else { goto bad; } break; case 'e': case 'E': Matched("@set"); do_set(descr, player, arg1, arg2); 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 'u': case 'U': Matched("@success"); do_success(descr, player, arg1, arg2); break; case 'w': case 'W': Matched("@sweep"); do_sweep(descr, player, arg1); break; default: goto bad; } break; case 't': case 'T': /* @teleport, @toad, @trace, @tune */ switch (command[2]) { case 'e': case 'E': Matched("@teleport"); do_teleport(descr, player, arg1, arg2); break; case 'o': case 'O': if (!strcmp(command, "@toad")) { do_toad(descr, player, arg1, arg2); } else if (!strcmp(command, "@tops")) { do_all_topprofs(player, arg1); } else { goto bad; } break; case 'r': case 'R': Matched("@trace"); do_trace(descr, player, arg1, atoi(arg2)); break; case 'u': case 'U': Matched("@tune"); do_tune(player, arg1, arg2); break; default: goto bad; } break; case 'u': case 'U': /* @unbless, @unlink, @unlock, @uncompile, @usage */ switch (command[2]) { case 'N': case 'n': if (string_prefix(command, "@unb")) { Matched("@unbless"); do_unbless(descr, player, arg1, arg2); } else if (string_prefix(command, "@unli")) { Matched("@unlink"); do_unlink(descr, player, arg1); } else if (string_prefix(command, "@unlo")) { Matched("@unlock"); do_unlock(descr, player, arg1); } else if (string_prefix(command, "@uncom")) { Matched("@uncompile"); do_uncompile(player); } else { goto bad; } break; case 'S': case 's': Matched("@usage"); do_usage(player); break; default: goto bad; break; } break; case 'v': case 'V': /* @version */ Matched("@version"); notify(player, VERSION); break; case 'w': case 'W': /* @wall */ if (strcmp(command, "@wall")) goto bad; do_wall(player, full_command); break; default: goto bad; } break; case 'd': case 'D': /* disembark, drop */ switch (command[1]) { case 'i': case 'I': Matched("disembark"); do_leave(descr, player); break; case 'r': case 'R': Matched("drop"); do_drop(descr, player, arg1, arg2); break; default: goto bad; } break; case 'e': case 'E': /* examine */ Matched("examine"); do_examine(descr, player, arg1, arg2); break; case 'g': case 'G': /* get, give, goto, gripe */ switch (command[1]) { case 'e': case 'E': Matched("get"); do_get(descr, player, arg1, arg2); break; case 'i': case 'I': Matched("give"); do_give(descr, player, arg1, atoi(arg2)); break; case 'o': case 'O': Matched("goto"); do_move(descr, player, arg1, 0); break; case 'r': case 'R': if (string_compare(command, "gripe")) goto bad; do_gripe(player, full_command); break; default: goto bad; } break; case 'h': case 'H': /* help */ Matched("help"); do_help(player, arg1, arg2); break; case 'i': case 'I': /* inventory, info */ if (string_compare(command, "info")) { Matched("inventory"); do_inventory(player); } else { Matched("info"); do_info(player, arg1, arg2); } break; case 'k': case 'K': /* kill */ Matched("kill"); do_kill(descr, player, arg1, atoi(arg2)); break; case 'l': case 'L': /* leave, look */ if (string_prefix("look", command)) { Matched("look"); do_look_at(descr, player, arg1, arg2); break; } else { Matched("leave"); do_leave(descr, player); break; } case 'm': case 'M': /* man, motd, move, mpi */ if (string_prefix(command, "move")) { do_move(descr, player, arg1, 0); break; } else if (!string_compare(command, "motd")) { do_motd(player, full_command); break; } else if (!string_compare(command, "mpi")) { do_mpihelp(player, arg1, arg2); break; } else { if (string_compare(command, "man")) goto bad; do_man(player, (!*arg1 && !*arg2 && arg1 != arg2) ? "=" : arg1, arg2); } break; case 'n': case 'N': /* news */ Matched("news"); do_news(player, arg1, arg2); break; case 'p': case 'P': /* page, pose, put */ switch (command[1]) { case 'a': case 'A': Matched("page"); do_page(player, arg1, arg2); break; case 'o': case 'O': Matched("pose"); do_pose(player, full_command); break; case 'u': case 'U': Matched("put"); do_drop(descr, player, arg1, arg2); break; default: goto bad; } break; case 'r': case 'R': /* read, rob */ switch (command[1]) { case 'e': case 'E': Matched("read"); /* undocumented alias for look */ do_look_at(descr, player, arg1, arg2); break; case 'o': case 'O': Matched("rob"); do_rob(descr, player, arg1); break; default: goto bad; } break; case 's': case 'S': /* say, score */ switch (command[1]) { case 'a': case 'A': Matched("say"); do_say(player, full_command); break; case 'c': case 'C': Matched("score"); do_score(player); break; default: goto bad; } break; case 't': case 'T': /* take, throw */ switch (command[1]) { case 'a': case 'A': Matched("take"); do_get(descr, player, arg1, arg2); break; case 'h': case 'H': Matched("throw"); do_drop(descr, player, arg1, arg2); break; default: goto bad; } break; case 'w': case 'W': /* whisper */ Matched("whisper"); do_whisper(descr, player, arg1, arg2); break; default: bad: notify(player, tp_huh_mesg); if (tp_log_failed_commands && !controls(player, DBFETCH(player)->location)) { log_status("HUH from %s(%d) in %s(%d)[%s]: %s %s\n", NAME(player), player, NAME(DBFETCH(player)->location), DBFETCH(player)->location, NAME(OWNER(DBFETCH(player)->location)), command, full_command); } break; } } /* calculate time command took. */ gettimeofday(&endtime, NULL); if (starttime.tv_usec > endtime.tv_usec) { endtime.tv_usec += 1000000; endtime.tv_sec -= 1; } endtime.tv_usec -= starttime.tv_usec; endtime.tv_sec -= starttime.tv_sec; totaltime = endtime.tv_sec + (endtime.tv_usec * 1.0e-6); if (totaltime > (tp_cmd_log_threshold_msec / 1000.0)) { log2file(LOG_CMD_TIMES, "%6.3fs, %.16s: %s%s%s%s(%d) in %s(%d):%s %s", totaltime, ctime((time_t *)&starttime.tv_sec), Wizard(OWNER(player)) ? "WIZ: " : "", (Typeof(player) != TYPE_PLAYER) ? NAME(player) : "", (Typeof(player) != TYPE_PLAYER) ? " owned by " : "", NAME(OWNER(player)), (int) player, NAME(DBFETCH(player)->location), (int) DBFETCH(player)->location, " ", command); } } #undef Matched