#include "copyright.h" #include "config.h" #include <stdio.h> #include <ctype.h> #include <signal.h> #include <sys/wait.h> #include <sys/types.h> #include <sys/times.h> #include "db.h" #include "params.h" #include "interface.h" #include "match.h" #include "externs.h" #include "mush.h" /* declarations */ static char *dumpfile = 0, buf[BUFFER_LEN]; static int alarm_PANIC = 0; static int last_dump = 0; #ifdef HAVE_DRAND48 void srand48(long); #endif #ifdef MUSH dbref speaker = NOTHING; #endif /* funct (player, a, b, line) */ /* where the command line is "command a = b" */ #ifdef MUSH typedef struct { char *name; void (*function)(dbref, char *, char *, char *); int flag1, flag2, flag3; } game_command; #else typedef struct { char *name; void (*function)(dbref, char *, char *, char *); int flag; } game_command; #endif void time_keeper(void); void fork_and_dump(void); void dump_database(void); void clear_args(char *one, char *two, char *three); /* more hacks, let them dump a lachesis file... */ static int dump_lachesis = 0; void do_dump(__DO_PROTO) { if(Wizard(player)) { /* more hacks to dump a lachesis db */ if (arg2 && !strcmp(arg2, "lachesis")) { dump_lachesis = 1; notify(player, player, "Switching to Lachesis format."); } if (*arg1 #ifdef GOD_PRIV && God(player) #endif /* GOD_PRIV */ ) { strcpy(dumpfile, arg1); sprintf(buf, "Dumping to file %s...", arg1); notify(player, player, buf); } last_dump = 0; notify(player, player, "Dumped the DB to disk."); } else notify(player, player, "Sorry, you are in a no dumping zone."); } void do_shutdown(__DO_PROTO) { descriptor_data *d; if(FLAGS(player) & #ifdef GOD_PRIV GOD) #else /* !GOD_PRIV */ WIZARD) #endif /* GOD_PRIV */ { sprintf (buf, "%s has issued a shutdown.", unparse_name(player)); for(d = descriptor_list; d; d = d->next) { queue_string(d, buf); queue_write(d, "\r\n", 2); } log_status("SHUTDOWN: by %s\n", unparse_object(player, player)); shutdown_flag = 1; } else { notify(player, player, "Your delusions of grandeur have been duly noted."); log_status("ILLEGAL SHUTDOWN: tried by %s\n", unparse_object(player, player)); } } int epoch = 0; static void dump_database_internal() { char tpfile[248]; FILE *f; descriptor_data *d; int i=0; sprintf(tpfile, "%s.#%d#", dumpfile, epoch - 1); (void) unlink(tpfile); /* nuke our predecessor */ sprintf(tpfile, "%s.#%d#", dumpfile, epoch); #ifdef USE_DBP if(o_db_sync) dbp_sync(); else dbp_flush(); dbp_lock(); #endif if((f = fopen(tpfile, "w")) != NULL) { dump_lachesis ? db_write_lachesis(f) : db_write(f); dump_lachesis = 0; fclose(f); if(rename(tpfile, dumpfile) < 0) perror(tpfile); } else perror(tpfile); #ifdef USE_DBP dbp_unlock(); #endif /* Write out the macros */ sprintf(tpfile, "%s.#%d#", MACRO_FILE, epoch - 1); unlink(tpfile); sprintf(tpfile, "%s.#%d#", MACRO_FILE, epoch); if((f = fopen(tpfile, "w")) != NULL) { macrodump(macrotop, f); fclose(f); if (rename(tpfile, MACRO_FILE) < 0) perror(tpfile); } else perror(tpfile); } void panic(char *message) { char panicfile[2048]; FILE *f; int i; log_status("PANIC: %s\n", message); fprintf(stderr, "PANIC: %s\n", message); /* turn off signals */ for(i = 0; i < NSIG; i++) signal(i, SIG_IGN); /* shut down interface */ close_sockets(); #ifdef USE_DBP dbp_disable(); #endif /* dump panic file */ sprintf(panicfile, "%s.PANIC", dumpfile); if((f = fopen(panicfile, "w")) == NULL) { perror("CANNOT OPEN PANIC FILE, YOU LOSE"); #ifdef NOCOREDUMP _exit(135); #else /* !NOCOREDUMP */ signal(SIGIOT, SIG_DFL); abort(); #endif /* NOCOREDUMP */ } else { #ifndef USE_DBP log_status("DUMPING: %s\n", panicfile); fprintf(stderr, "DUMPING: %s\n", panicfile); dump_lachesis ? db_write_lachesis(f) : db_write(f); dump_lachesis = 0; fclose(f); log_status("DUMPING: %s (done)\n", panicfile); fprintf(stderr, "DUMPING: %s (done)\n", panicfile); #else fclose(f); unlink(panicfile); #endif /* USE_DBP */ #ifdef NOCOREDUMP _exit(136); #else /* !NOCOREDUMP */ signal(SIGIOT, SIG_DFL); abort(); #endif /* NOCOREDUMP */ } } void dump_database() { epoch++; log_status("DUMPING: %s.#%d#\n", dumpfile, epoch); dump_database_internal(); log_status("DUMPING: %s.#%d# (done)\n", dumpfile, epoch); } void time_keeper() { static int last_rwho = 0; static int last_setup = 0; static int current_time = 0; char uid[20]; descriptor_data *d; if (!last_setup) { last_setup = 1; last_dump = time((long *)NULL); last_rwho = time((long *)NULL); autostart_frames(); } current_time = time((long *)NULL); run_frames(); if ((current_time - last_dump) > DUMP_INTERVAL || alarm_PANIC == 1) { alarm_PANIC = 0; fork_and_dump(); } if(o_rwho) { if ((current_time - last_rwho) > RWHO_INTERVAL) { rwhocli_pingalive(); /* Active user profile */ profile_users(); for(d = descriptor_list; d; d = d->next) { if (d->connected && (d->player != NOTHING)) { sprintf(uid, "%d", d->player); rwhocli_userlogin(uid, unparse_name(d->player), d->connected_at); } } last_rwho = time((long *)NULL); } } } void fork_and_dump() { int child; epoch++; last_dump = time((long *)NULL); log_status("CHECKPOINTING: %s.#%d#\n", dumpfile, epoch); #ifdef NOFORK dump_database_internal(); #else if(o_notify_wiz) { notify_wizards("Doing a forked DB dump. Delays should be minimal."); } #ifdef USE_VFORK child = vfork(); #else /* USE_VFORK */ child = fork(); #endif /* USE_VFORK */ if(child == 0) { #ifdef USE_DBP dbp_disable(); #endif close(0); /* get that file descriptor back */ dump_database_internal(); _exit(0); /* !!! */ } #ifdef USE_DBP else if (child > 0) { /* flush the cache to disk */ dbp_sync(); } #endif else if(child < 0) perror("fork_and_dump: fork()"); #endif } static RETSIGTYPE reaper() { #ifdef HAVE_UNION_WAIT union wait stat; #else int stat; #endif #ifdef HAVE_WAIT3 while (wait3(&stat, WNOHANG, NULL) > 0); #else wait(&stat); #endif #ifdef AIX370 /* RESET the signal handler for AIX370 */ /* This may not be the best place to put this. */ signal(SIGCHLD, reaper); /* test modification by WOZ Jul 3 18:48 PDT 1991 */ #endif return ; } int init_game(char *infile, 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); } if((f = fopen(infile, "r")) == NULL) return -1; /* ok, read it in */ log_status("LOADING: %s\n", infile); fprintf(stderr, "LOADING: %s\n", infile); if(db_read(f) < 0) return -1; log_status("LOADING: %s (done)\n", infile); fprintf(stderr, "LOADING: %s (done)\n", infile); fclose(f); /* everything ok */ /* initialize random number generator */ srandom(getpid()); #ifdef USE_DBP fprintf(stderr, "Calling dbp_enable()\n"); if (dbp_enable(infile)) { fprintf(stderr, "Error in enable.\n"); exit(2); } #endif #ifdef HAVE_DRAND48 srand48(getpid()); #endif /* set up dumper */ if(dumpfile) free(dumpfile); dumpfile = dup_string(outfile); signal(SIGCHLD, reaper); return 0; } #ifdef MUSH game_command command_array[] = { {"@aahear", do_mush_prop_set, 2, 0, 0}, {"@aclone", do_mush_prop_set, 2, 0, 0}, {"@aconnect", do_mush_prop_set, 2, 0, 0}, {"@action", do_action, 1, 0, 0}, {"@adeath", do_mush_prop_set, 2, 0, 0}, {"@adescribe", do_mush_prop_set, 2, 0, 0}, {"@adisconnect", do_mush_prop_set, 2, 0, 0}, {"@adrop", do_mush_prop_set, 2, 0, 0}, {"@aefail", do_mush_prop_set, 2, 0, 0}, {"@aenter", do_mush_prop_set, 2, 0, 0}, {"@afailure", do_mush_prop_set, 2, 0, 0}, {"@ahear", do_mush_prop_set, 2, 0, 0}, {"@aleave", do_mush_prop_set, 2, 0, 0}, {"@amhear", do_mush_prop_set, 2, 0, 0}, {"@amove", do_mush_prop_set, 2, 0, 0}, {"@apayment", do_mush_prop_set, 2, 0, 0}, {"@asuccess", do_mush_prop_set, 2, 0, 0}, {"@atport", do_mush_prop_set, 2, 0, 0}, {"@attach", do_attach, 1, 1, 0}, {"@ause", do_mush_prop_set, 2, 0, 0}, {"@away", do_mush_prop_set, 2, 0, 0}, {"@backlinks", do_backlinks, 1, 0, 0}, {"@backlocks", do_backlocks, 1, 0, 0}, {"@boot", do_boot, 1, 0, 0}, {"@charges", do_mush_prop_set, 2, 0, 0}, {"@chown", do_chown, 1, 1, 0}, {"@comment", do_mush_prop_set, 2, 0, 0}, {"@contents", do_contents, 1, 1, 0}, {"@cost", do_mush_prop_set, 2, 0, 0}, {"@create", do_create, 1, 1, 0}, {"@death", do_mush_prop_set, 2, 0, 0}, {"@describe", do_describe, 1, 0, 0}, {"@destroy", do_recycle, 1, 0, 0}, {"@dig", do_dig, 1, 1, 0}, {"@drop", do_drop_message, 1, 0, 0}, {"@dump", do_dump, 0, 0, 0}, {"@ealias", do_mush_prop_set, 2, 0, 0}, {"@earthquake", do_earthquake, 0, 0, 0}, {"@edit", do_edit, 0, 0, 0}, {"@efail", do_mush_prop_set, 2, 0, 0}, {"@enter", do_mush_prop_set, 2, 0, 0}, {"@examine", do_at_examine, 1, 0, 0}, {"@exits", do_exits, 1, 0, 0}, {"@fail", do_fail, 1, 0, 0}, {"@filter", do_mush_prop_set, 2, 0, 0}, {"@find", do_find, 1, 0, 0}, {"@flags", do_list_flags, 0, 0, 0}, #ifdef USE_DBP {"@flush", do_db_flush, 0, 0, 0}, #endif {"@force", do_force, 1, 1, 0}, {"@go", do_go, 1, 0, 0}, {"@haven", do_mush_prop_set, 2, 0, 0}, {"@idescribe", do_mush_prop_set, 2, 0, 0}, {"@idle", do_mush_prop_set, 2, 0, 0}, {"@infilter", do_mush_prop_set, 2, 0, 0}, {"@inprefix", do_mush_prop_set, 2, 0, 0}, {"@kill", do_pidkill, 0, 0, 0}, {"@lalias", do_mush_prop_set, 2, 0, 0}, {"@leave", do_mush_prop_set, 2, 0, 0}, {"@link", do_link, 1, 1, 0}, {"@list", do_mlist, 0, 0, 0}, {"@logins", do_login, 0, 0, 0}, {"@move", do_mush_prop_set, 2, 0, 0}, {"@mset", do_mset, 1, 0, 0}, {"@name", do_name, 1, 0, 0}, {"@newpassword", do_newpassword, 0, 0, 0}, {"@odeath", do_mush_prop_set, 2, 0, 0}, {"@odescribe", do_mush_prop_set, 2, 0, 0}, {"@odrop", do_odrop, 1, 0, 0}, {"@oefail", do_mush_prop_set, 2, 0, 0}, {"@oenter", do_mush_prop_set, 2, 0, 0}, {"@ofail", do_ofail, 1, 0, 0}, {"@oleave", do_mush_prop_set, 2, 0, 0}, {"@omove", do_mush_prop_set, 2, 0, 0}, {"@opayment", do_mush_prop_set, 2, 0, 0}, {"@open", do_open, 1, 1, 0}, {"@osuccess", do_osuccess, 1, 0, 0}, {"@otport", do_mush_prop_set, 2, 0, 0}, {"@ouse", do_mush_prop_set, 2, 0, 0}, {"@owned", do_owned, 1, 1, 0}, {"@oxenter", do_mush_prop_set, 2, 0, 0}, {"@oxleave", do_mush_prop_set, 2, 0, 0}, {"@oxtport", do_mush_prop_set, 2, 0, 0}, {"@parameter", do_parameter_set, 0, 0, 0}, {"@password", do_password, 0, 0, 0}, {"@payment", do_mush_prop_set, 2, 0, 0}, {"@pcreate", do_pcreate, 0, 0, 0}, {"@permissions", do_perms, 1, 1, 0}, {"@prefix", do_mush_prop_set, 2, 0, 0}, {"@program", do_program, 0, 0, 0}, {"@properties", do_properties, 1, 1, 0}, {"@ps", do_ps, 0, 0, 0}, {"@queue", do_mush_prop_set, 2, 0, 0}, {"@recycle", do_recycle, 1, 0, 0}, {"@reset", do_reset, 0, 0, 0}, {"@rquota", do_mush_prop_set, 2, 0, 0}, {"@runout", do_mush_prop_set, 2, 0, 0}, {"@semaphore", do_mush_prop_set, 2, 0, 0}, {"@set", do_set, 1, 0, 0}, {"@sex", do_mush_prop_set, 2, 0, 0}, {"@shutdown", do_shutdown, 0, 0, 0}, {"@startup", do_mush_prop_set, 2, 0, 0}, {"@stats", do_stats, 1, 0, 0}, {"@success", do_success, 1, 0, 0}, {"@suid", do_player_setuid, 1, 0, 0}, #ifdef USE_DBP {"@synchronize", do_db_sync, 0, 0, 0}, #endif #ifdef HOWARD {"@sys", do_load, 0, 0, 0}, #endif {"@teleport", do_teleport, 1, 1, 0}, {"@toad", do_toad, 0, 0, 0}, {"@tport", do_mush_prop_set, 2, 0, 0}, {"@trace", do_trace, 0, 0, 0}, {"@trimdb", do_trimdb, 0, 0, 0}, {"@uncompile", do_uncompile, 0, 0, 0}, {"@unlink", do_unlink, 1, 0, 0}, {"@use", do_mush_prop_set, 2, 0, 0}, {"@version", do_version, 0, 0, 0}, {"@wall", do_wall, 0, 0, 1}, {"drop", do_drop, 1, 0, 0}, {"examine", do_examine, 1, 1, 0}, #ifdef HOWARD {"fortune", do_fortune, 0, 0, 0}, #endif {"get", do_get, 1, 0, 0}, {"give", do_give, 1, 1, 0}, {"goto", do_move, 0, 1, 0}, #ifndef HOWARD {"gripe", do_gripe, 0, 0, 1}, #endif {"help", do_help, 0}, {"inventory", do_inventory, 0, 0, 0}, {"kill", do_kill, 1, 1, 0}, {"look", do_look_at, 1, 0, 0}, {"man", do_man, 0, 0, 0}, {"move", do_move, 0, 0, 1}, {"news", do_news, 0, 0, 0}, {"page", do_page, 1, 1, 0}, {"pose", do_pose, 0, 0, 1}, {"put", do_drop, 1, 0, 0}, {"read", do_look_at, 1, 0, 0}, {"rob", do_rob, 1, 1, 0}, {"say", do_say, 0, 0, 1}, {"score", do_score, 0, 0, 0}, {"take", do_get, 1, 0, 0}, {"throw", do_drop, 1, 0, 0}, {"whisper", do_whisper, 1, 1, 0}, {"xprops", do_xqueue, 0, 0, 0}, {"zprops", do_prop_load, 1, 1, 0} }; #else game_command command_array[] = { {"@action", do_action, 0}, {"@attach", do_attach, 1}, {"@backlinks", do_backlinks, 1}, {"@backlocks", do_backlocks, 1}, {"@boot", do_boot, 1}, {"@chown", do_chown, 1}, {"@contents", do_contents, 1}, {"@create", do_create, 1}, {"@describe", do_describe, 0}, {"@dig", do_dig, 1}, {"@drop", do_drop_message, 1}, {"@dump", do_dump, 0}, {"@earthquake", do_earthquake, 0}, {"@edit", do_edit, 0}, {"@examine", do_at_examine, 1}, {"@exits", do_exits, 1}, {"@fail", do_fail, 0}, {"@find", do_find, 1}, {"@flags", do_list_flags, 0}, {"@force", do_force, 1}, {"@go", do_go, 1}, {"@kill", do_pidkill, 0}, {"@link", do_link, 1}, {"@list", do_mlist, 0}, {"@lock", do_lock, 0}, {"@logins", do_login, 0}, {"@name", do_name, 0}, {"@newpassword", do_newpassword, 0}, {"@odrop", do_odrop, 0}, {"@ofail", do_ofail, 0}, {"@open", do_open, 1}, {"@osuccess", do_osuccess, 0}, {"@owned", do_owned, 1}, {"@parameter", do_parameter_set, 0}, {"@password", do_password, 0}, {"@pcreate", do_pcreate, 0}, {"@permissions", do_perms, 1}, {"@program", do_program, 0}, {"@properties", do_properties, 1}, {"@ps", do_ps, 0}, {"@recycle", do_recycle, 1}, {"@reset", do_reset, 0}, {"@set", do_set, 0}, {"@shutdown", do_shutdown, 0}, {"@stats", do_stats, 1}, {"@stuid", do_player_setuid, 1}, {"@success", do_success, 0}, {"@sys", do_load, 0}, {"@teleport", do_teleport, 1}, {"@toad", do_toad, 1}, {"@trace", do_trace, 0}, {"@trimdb", do_trimdb, 0}, {"@uncompile", do_uncompile, 0}, {"@unlink", do_unlink, 1}, {"@unlock", do_unlock, 1}, {"@user", do_player_setuid, 1}, {"@version", do_version, 0}, {"@wall", do_wall, 1}, {"drop", do_drop, 1}, {"examine", do_examine, 1}, {"fortune", do_fortune, 0}, {"get", do_get, 1}, {"give", do_give, 1}, {"goto", do_move, 1}, {"gripe", do_gripe, 1}, {"help", do_help, 0}, {"inventory", do_inventory, 0}, {"kill", do_kill, 1}, {"look", do_look_at, 1}, {"man", do_man, 0}, {"move", do_move, 1}, {"news", do_news, 0}, {"page", do_page, 1}, {"pose", do_pose, 1}, {"put", do_drop, 1}, {"read", do_look_at, 1}, {"rob", do_rob, 1}, {"say", do_say, 1}, {"score", do_score, 0}, {"take", do_get, 1}, {"throw", do_drop, 1}, {"whisper", do_whisper, 1} }; #endif void process_command(dbref player, char *command, dbref cause) { char *arg1, *arg2, *full_command, *p; char *m1, *m2, *mfull; char pbuf[BUFSIZ], xbuf[BUFSIZ]; char hold1[BUFFER_LEN], hold2[BUFFER_LEN], hold3[BUFFER_LEN]; char mush_buffer[BUFSIZ +3]; int command_num, i, count, flag=1; frame *fr; if (!command) abort(); if(player < 0 || player >= db_top) { log_status("process_command: bad player %d\n", player); return; } if(o_log_commands) { if (!(FLAGS(player) & INTERACTIVE)) log_command("%s(%ld) in %s(%ld):%s %s\n", NAME(player), player, NAME(DBFETCH(player)->location), DBFETCH(player)->location, (FLAGS(player) & INTERACTIVE) ? " [interactive]" : " ", command); } #ifdef MUSH /* Halted objects can't execute commands */ if ((Typeof(player) != TYPE_PLAYER) && Halted(player)) { notify(OWNER(player), OWNER(player), tprintf("Attempt to execute command by halted object #%ld", player)); return; } /* Check for Verbose objects and notify */ if (Typeof(player) != TYPE_PLAYER && Verbose(player)) notify_nolisten(OWNER(player), tprintf("%s(#%ld)] %s", unparse_name(player), player, command)); /* Make sure the location of the object is good */ if (!GoodObject(Location(player))) notify(OWNER(player), OWNER(player), tprintf("Invalid location on command execution: %s(#%d)", unparse_name(player), player)); #endif /* Only players can go Interactive. */ if (FLAGS(player) & INTERACTIVE) { if(Typeof(player) != TYPE_PLAYER) { notify(OWNER(player), OWNER(player), tprintf("%s is interactive!", NAME(player))); log_status("%s(%ld) is INTERACTIVE\n", NAME(player), player); FLAGS(player) &= ~INTERACTIVE; DBDIRTY(player); } else interactive(player, command); return; } #ifdef MUSH speaker = player; /* MUSH listeners */ strcpy(mush_buffer, command); #endif /* eat leading whitespace */ while(*command && isspace(*command)) command++; /* check for single-character commands */ if ((*command == SAY_TOKEN) || (*command == SAY_TOKEN_TWO)) { sprintf(pbuf, "say %s", command + 1); command = pbuf; } else if ((*command == POSE_TOKEN) || (*command == POSE_TOKEN_TWO)) { sprintf(pbuf, "pose %s", command + 1); command = pbuf; } #ifdef MUSH else if (*command == '&') { sprintf(pbuf, "@mset %s", command + 1); command = pbuf; } #endif if ((can_move(player, command)) && ((*command != '!') || (!Wizard(player)))) { /* command is an exact match for an exit */ if (*command == '!') command++; do_move(player, "", "", command); *match_args = 0; } else { if (*command == '!') command++; if (*command == '.') *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 */ for(arg1 = command; *arg1 && !isspace(*arg1); arg1++); /* truncate command */ if(*arg1) *arg1++ = '\0'; /* 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++; for (command_num = 0; (command_num < sizeof(command_array) / sizeof(game_command)) && (stringn_compare(command, command_array[command_num].name, strlen(command)) > 0); command_num++); if ((command_num < sizeof(command_array) / sizeof(game_command)) && (!stringn_compare(command, command_array[command_num].name, strlen(command))) && (((command_num + 1 >= sizeof(command_array) / sizeof(game_command)) || (stringn_compare(command, command_array[command_num + 1].name, strlen(command)))))) { #ifdef MUSH if(command_array[command_num].flag1 == 1) { strcpy(hold1, arg1); m1 = exec(cause, hold1, player, EV_STRIP | EV_FCHECK); } else m1 = dup_it(arg1); if(command_array[command_num].flag2) { strcpy(hold2, arg2); m2 = exec(cause, hold2, player, EV_STRIP | EV_FCHECK); } else m2 = dup_it(arg2); if(command_array[command_num].flag3) { strcpy(hold3, full_command); mfull = exec(cause, hold3, player, EV_STRIP | EV_FCHECK); } else mfull = dup_it(full_command); if(command_array[command_num].flag1 == 2) (*command_array[command_num].function)(player, m1, m2, command_array[command_num].name); else (*command_array[command_num].function)(player, m1, m2, mfull); clear_args(m1, m2, mfull); return; #else (*command_array[command_num].function)(player, arg1, arg2, full_command); return; #endif } #ifdef MUSH /* Hook into the MUSH command parser */ if(mush_parse(player, mush_buffer, cause)) return; #endif /* MUSH */ if(o_muffail) { i = DBFETCH(GLOBAL_ENVIRONMENT)->exits; DOLIST (i, i) { if (!strcmp(DBFETCH(i)->name, "do_fail") && (FLAGS(i) & WIZARD)) { for (count = 0; count < DBFETCH(i)->sp.exit.ndest; count++) { if (Typeof(DBFETCH(i)->sp.exit.dest[count]) == TYPE_PROGRAM) { fr = new_frame(player, DBFETCH(i)->sp.exit.dest[count], i, DBFETCH(player)->location, 1); run_frame(fr, 1); if (fr && (fr->status != STATUS_SLEEP)) free_frame(fr); flag = 0; } } } } } if(flag) notify(player, player, "Huh? (Type \"help\" for help.)"); if (o_log_huhs) { if(!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); } } } #ifdef MUSH void clear_args(char *one, char *two, char *three) { if(one) free(one); if(two) free(two); if(three) free(three); } #endif void do_list_commands(__DO_PROTO) { int i; char buff[BUFFER_LEN]; char *bp; bp = buff; safe_str("Builtins:", buff, &bp); for (i = 0; i < sizeof(command_array) / sizeof(game_command); i++) { safe_chr(' ', buff, &bp); safe_str(command_array[i].name, buff, &bp); } *bp = '\0'; notify(player, player, buff); }