/* /lib/command.c * from the Dead Souls Object Library * handles commands of living objects * created by Descartes of Borg 950323 * Version: @(#) command.c 1.2@(#) * Last modified: 96/12/07 */ #include <lib.h> #include <daemons.h> #include "include/command.h" #define OLD_STYLE_PLURALS 1 int Paused = 0; private static int Forced = 0; private static int StillTrying = 0; private static int ParseRecurse = 0; private static string CommandFail; private static string *SearchPath; private static int last_cmd_time = 0; private static int cmd_count = 1; private string *localcmds = ({}); private string parsed_command = ""; private static string *QueuedCommands = ({}); static string current_command = ""; static string original_command = ""; static int Charmode = 0; static string Charbuffer = ""; int direct_force_liv_str(){ return 1; } int direct_force_liv_to_str(){ return 1; } /* *************** /lib/command.c driver applies *************** */ static void create(){ SetCommandFail(0); SearchPath = ({ DIR_PLAYER_CMDS, DIR_SECURE_PLAYER_CMDS, DIR_CLAN_CMDS, DIR_COMMON_CMDS, DIR_SECURE_COMMON_CMDS }); } static string process_input(string args){ string verb, real_verb, tmpalias, orig; object env = environment(this_object()); string *talks = ({ "emote", "tell", "reply", "say", "whisper", "yell", "shout", "speak" }); string *filecmds = ({ "ced", "clone", "goto", "rehash", "reset", "showtree", "bk", "cat", "cp", "diff", "ed", "grep", "head", "indent", "longcat", "more", "mv", "rm", "sed", "showfuns", "source", "tail", "update", "cd", "ls", "mkdir", "rmdir" }); string *specialcmds = ({ "modify", "mudconfig", "describe" }); string *exempts = talks + filecmds + specialcmds; exempts += this_object()->GetChannels(); exempts += SOUL_D->GetEmotes(); orig = args; localcmds = ({}); filter(commands(), (: localcmds += ({ $1[0] }) :)); if(sizeof(args)){ string *tmpargs = explode(args, " "); if(sizeof(tmpargs)) verb = tmpargs[0]; else verb = ""; } if(verb && tmpalias = this_object()->GetAlias(verb)){ real_verb = explode(tmpalias, " ")[0]; } if(verb && tmpalias = this_object()->GetXverb(verb[0..0])){ real_verb = explode(tmpalias, " ")[0]; } if(!real_verb) real_verb = verb; if(Paused && (member_array(real_verb, exempts) == -1)){ this_object()->eventPrint("You are paused."); return ""; } if(!archp(this_object()) && MAX_COMMANDS_PER_SECOND){ if(last_cmd_time == time()) cmd_count++; else { last_cmd_time = time(); cmd_count = 1; } if(cmd_count > MAX_COMMANDS_PER_SECOND){ this_object()->eventPrint("You have exceeded the " + MAX_COMMANDS_PER_SECOND + " commands per second limit."); return ""; } } if(this_object()->GetSleeping() > 0){ if(verb != "wake"){ this_object()->eventPrint("You are asleep."); return ""; } } if(OLD_STYLE_PLURALS && args && (member_array(real_verb, exempts) == -1 || (member_array(verb, exempts) != -1 && !strsrch(trim(args),"to ")))){ int numba, i, tmp_num; string tmp_ret; string *line = explode(args," "); for(i = 1; i < sizeof(line); i++){ string element; if(!line[i]) error("String handling error in old style plural parser."); element = line[i]; exempts = sort_array(exempts, 1); if(sscanf(element,"%d.%d",numba,tmp_num) != 2 && sscanf(element,"%d.%s",numba,tmp_ret) == 2 && (member_array(real_verb, exempts) == -1)){ args = replace_string(args, numba + ".", numba + ordinal(numba) + " "); continue; } if(numba = atoi(element)){ int j; object o1; string e1, e2, tmp_thing = ""; e1 = numba+ordinal(numba); j = member_array(element, line); while(j > 0){ string old_tmp = tmp_thing; j--; e2 = line[j]; if(sizeof(tmp_thing)) tmp_thing = e2 + " " + tmp_thing; else tmp_thing = e2; if(member_array(tmp_thing, exempts) != -1) break; o1 = present(tmp_thing); if(!o1){ o1 = present(old_tmp); if(o1){ tmp_ret = e1 + " " + old_tmp; args=replace_string(args,old_tmp+" "+numba,tmp_ret); } } } }//end single number check } } parsed_command = args; if(member_array(verb, localcmds) != -1){ current_command = orig; } else { current_command = parsed_command; parsed_command = ""; } return current_command; } /* *************** /lib/command.c command lfuns *************** */ static int cmdAll(string args){ object old_agent, env; mixed err; string verb, file; if(grepp(parsed_command," ")){ sscanf(parsed_command,"%s %s", verb, args); parsed_command = ""; } if(!verb) verb = query_verb(); if(!this_object()->GetCharmode()){ if(!args) this_object()->Push(verb); else this_object()->Push(verb+" "+args); } else { this_object()->Push(this_object()->GetTempbuffer()); } old_agent = this_agent(this_object()); env = environment(); if(BARE_EXITS && env){ localcmds = ({}); filter(commands(), (: localcmds += ({ $1[0] }) :)); if(member_array(verb,CMD_D->GetCommands()) == -1 && member_array(verb,keys(VERBS_D->GetVerbs())) == -1 && member_array(verb,localcmds) == -1 ){ string dir; if(args) dir = verb + " " + args; else dir = verb; if(member_array(dir, (env->GetExits() || ({}))) != -1) verb = "go "+verb; if(member_array(dir, (env->GetEnters() || ({}))) != -1) verb = "enter "+verb; } } if(COMMAND_MATCHING && sizeof(match_command(verb))){ verb = match_command(verb); } if(query_custom_command(verb) && query_custom_command(verb) != "" && !creatorp(this_player()) ){ this_player()->eventPrint("How clever of you. Or lucky. In any case, this command is unavailable to you."); return 1; } if( !(file = (query_custom_command(verb) )) || query_custom_command(verb) == ""){ if( !(file = CMD_D->GetCommand(verb, GetSearchPath())) ){ string cmd; int dbg; if( verb && args ) cmd = verb + " " + args; else if(verb) cmd = verb; else if(args) cmd = args; if( this_object()->GetProperty("parse debug") ) dbg = 1; else if( this_object()->GetProperty("debug") ) dbg = 1; else dbg = 0; if( (err = parse_sentence(cmd, dbg)) == 1 ){ this_agent(old_agent || 1); return 1; } if( err ){ if( err == -1 ){ if( !(err = VERBS_D->GetErrorMessage(verb)) && !(err = SOUL_D->GetErrorMessage(verb)) ){ err = "Such a command exists, but no default " "syntax is known."; } } if( intp(err) ) /* MudOS bug */ err = "What?"; SetCommandFail(err); } message("error", GetCommandFail(), this_object()); this_agent(old_agent || 1); return 1; } } if( (err = call_other(file, "cmd", args)) != 1 ){ string cmd; if( err ) SetCommandFail(err); if( !args || args == "" ) cmd = verb; else cmd = verb + " " + args; if( (err = parse_sentence(cmd)) == 1 ){ this_agent(old_agent || 1); return 1; } if( !err ) err = GetCommandFail(); message("error", err, this_object()); this_agent(old_agent || 1); return 1; } this_agent(old_agent || 1); return 1; } int cmdDebugAll(string args){ object old_agent; mixed err; string verb, file; old_agent = this_agent(this_object()); verb = query_verb(); if( !(file = CMD_D->GetCommand(verb, GetSearchPath())) ){ string cmd; if( args ) cmd = verb + " " + args; else cmd = verb; if( (err = parse_sentence(cmd, 3)) == 1 ){ this_agent(old_agent || 1); return 1; } if( err ) SetCommandFail(err); message("error", GetCommandFail(), this_object()); this_agent(old_agent || 1); return 1; } if( (err = call_other(file, "cmd", args)) != 1 ){ string cmd; if( err ) SetCommandFail(err); if( !args || args == "" ) cmd = verb; else cmd = verb + " " + args; if( (err = parse_sentence(cmd, 3)) == 1 ){ this_agent(old_agent || 1); return 1; } if( !err ) err = GetCommandFail(); message("error", err, this_object()); this_agent(old_agent || 1); return 1; } this_agent(old_agent || 1); return 1; } /* *************** /lib/command.c lfuns *************** */ int Setup(){ enable_commands(); add_action( (: cmdAll :), "", 1); } int eventForce(string cmd){ string err; int res; #if 0 if(this_player() && interactive(this_object()) && this_player() != this_object()){ string forcer = this_player()->GetKeyName(); string forcee = this_object()->GetKeyName(); log_file("adm/force", timestamp()+" "+forcer+" forced "+forcee+" to "+cmd+"\n"); } #endif if(!cmd) return 0; cmd = process_input(cmd); if(!cmd) return 0; Forced = 1; err = catch(res = command(cmd)); Forced = 0; if(err){ error(err); } return res; } int eventForceQueuedCommand(string cmd){ tell_object(this_object(),"%^RED%^Executing queued command: %^RESET%^"+cmd); eventForce(cmd); } int eventExecuteQueuedCommands(){ int i = 0; foreach(string tmp in QueuedCommands){ i++; //tmp = process_input(tmp); call_out("eventForceQueuedCommand", i, tmp); QueuedCommands -= ({ tmp }); } } int eventQueueCommand(string line){ if(!line || !sizeof(line) || !stringp(line)) return 0; if(!this_player()) return 0; if(interactive(this_object())){ if(this_player() && this_player() != this_object()) return 0; } if(line != "") QueuedCommands += ({ line }); return 1; } int DoneTrying(){ return StillTrying = 0; } //Here we determine if the string corresponds unambiguously //to a limb possessed by the command issuer. int LimbCertain(string str){ object env = environment(this_player()); if(!env) env = this_player(); if(!str){ return 0; } foreach(mixed envs in ({ env, this_player() })){ if(present(str, env)){ return 0; } } if(member_array(str, this_player()->GetLimbs()) != -1){ return 1; } return 0; } varargs int eventRetryCommand(string lastcmd, int errtype, mixed args){ string virb, wrd, prep, rest,ret; string *tmp_arr = ({}); string *prep_arr = MASTER_D->parse_command_prepos_list(); object tmpob; mixed err; int i; string tmpret, act, direct, indirect, odirect, oindirect; mixed direct2, indirect2; if(previous_object() != master()) return 0; if(StillTrying){ StillTrying = 0; original_command = 0; return 1; } StillTrying = 1; if(!original_command || !sizeof(original_command)) original_command = lastcmd; tmpret = (lastcmd || ""); foreach(string foo in prep_arr){ if(grepp(tmpret," "+foo+" ")){ tmpret = replace_string(tmpret," "+foo+" "," PREPO "); } } tmpret = implode(explode(tmpret," ")," "); i = sscanf(tmpret,"%s %s PREPO %s",act, direct, indirect); if(i != 3) i = sscanf(tmpret,"%s %s PREPO PREPO %s",act, direct, indirect); if(i != 3) i = sscanf(tmpret,"%s %s %s",act, direct, indirect); if(i != 3) i = sscanf(tmpret,"%s %s",act, direct); odirect = direct; oindirect = indirect; //read is a special case. takes a str as first arh sometimes. if(act == "read" && !grepp(tmpret, " in a ")){ tmpret = replace_string(lastcmd, " in ", " in a "); } else if(i > 1 ){ object ob1, ob2; string tmpstr, s1, s2, article1, article2; if(StillTrying){ tmpstr = remove_article(direct); if(args && sizeof(args) && answers_to(tmpstr, args[0]) && present(args[0])) ob1 = args[0]; else ob1 = to_object(tmpstr, this_object()); } if(StillTrying && indirect){ tmpstr = remove_article(indirect); if(args && sizeof(args) && answers_to(tmpstr, args[0]) && present(args[0])) ob2 = args[0]; else ob2 = to_object(tmpstr, this_object()); } if(ob1) direct = ob1->GetUniqueId(); else direct = remove_article(direct); if(ob2) indirect = ob2->GetUniqueId(); else indirect = remove_article(indirect); if(!ob1 && direct && grepp(direct," ")){ if(sscanf(direct,"%s %s",s1, s2) == 2 && !ordinalp(s1,1)){ direct2 = "a "+direct; } } else if(!ob1 && direct){ if(first(direct,2) == "a " || first(direct,3) == "an "){ direct2 = direct; } else direct2 = "a "+direct; } if(!ob2 && indirect && grepp(indirect," ")){ if(sscanf(indirect,"%s %s",s1, s2) == 2 && !ordinalp(s1,1)){ if(!LimbCertain(indirect)) indirect2 = "a "+indirect; } } else if(!ob2 && indirect){ if(first(indirect,2) == "a " || first(indirect,3) == "an "){ if(!LimbCertain(indirect)) indirect2 = indirect; } else if(!LimbCertain(indirect)) indirect2 = "a "+indirect; } if(direct && !direct2) direct2 = direct; if(indirect && !indirect2) indirect2 = indirect; tmpret = replace_string(lastcmd, odirect, direct2); if(indirect2 && oindirect) tmpret = replace_string(tmpret, oindirect, indirect2); } ret = tmpret; err = parse_sentence(ret); StillTrying = 0; original_command = 0; if( !stringp(err) && err > -1 ){ return 1; } write("It seems you'll have to be more specific."); return 1; } /* ********** /lib/command.c data manipulation functions ********** */ string *AddSearchPath(mixed val){ if(stringp(val)){ if(!strsrch(val,"/secure/cmds/admins") || !strsrch(val,"/cmds/admins")){ if(!master()->valid_apply(({ "SECURE", "ASSIST", "LIB_CONNECT" })) ){ tell_creators("Security violation in progress: "+identify(previous_object(-1)) + ", "+get_stack()); error("Illegal attempt to modify path data: "+identify(previous_object(-1)) + ", "+get_stack()); } } val = ({ val }); } else if(!pointerp(val)) error("Bad argument 1 to AddSearchPath()\n"); return (SearchPath = distinct_array(SearchPath + val)); } string *RemoveSearchPath(mixed val){ if(stringp(val)) val = ({ val }); else if(!pointerp(val)) error("Bad argument 1 to RemoveSearchPath()\n"); return (SearchPath -= val); } string *GetSearchPath(){ return SearchPath; } int GetForced(){ return Forced; } int GetClient(){ return 0; } string GetCurrentCommand(){ if(!this_player()) return ""; if(this_player() != this_object()) return ""; return current_command; } int SetPlayerPaused(int i){ if( base_name(previous_object()) != LIB_CONNECT && (!this_player() || !archp(this_player())) ){ error("Illegal attempt to pause a player: "+get_stack()+" "+identify(previous_object(-1))); log_file("adm/pause",timestamp()+" Illegal attempt to access SetPlayerPaused on "+identify(this_object())+" by "+identify(previous_object(-1))+"\n"); } Paused = i; return Paused; } int GetPlayerPaused(){ return Paused; } string SetCommandFail(string str){ if( !str || str == "" ){ if(!creatorp(this_object())) CommandFail = "Try \"help commands\" for a list of some commands."; if(creatorp(this_object())) CommandFail = "Try \"help creator commands\" for a list of some creator commands."; return CommandFail; } else return (CommandFail = str); } string GetCommandFail(){ return CommandFail; }