mud/lib/lib/command.c
2020-09-06 05:43:07 -07:00

533 lines
17 KiB
C

/* /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", "read", "title", "register" });
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; }