/* Do not remove the headers from this file! see /USAGE for more info. */
#include <mudlib.h>
#include <security.h>
inherit M_MESSAGES;
inherit M_COMPLETE;
inherit M_ACCESS;
inherit M_GRAMMAR;
private mapping emotes=([]);
private string* adverbs=({});
#define SAVE_FILE "/data/daemons/soul"
#define CMD_ADD_EMOTE "/cmds/wiz/addemote"
#define CMD_REMOVE_EMOTE "/cmds/wiz/rmemote"
#define CMD_MOVE_EMOTE "/cmds/wiz/mvemote"
void
create() {
string verb, rule;
mapping value;
mixed ignore;
unguarded(1, (: restore_object, SAVE_FILE, 1 :));
parse_init();
foreach (verb, value in emotes) {
if (value[0]) {
value[""] = value[0];
map_delete(value, 0);
}
if (value[1]) {
value["STR"] = value[1];
map_delete(value, 1);
}
foreach (rule, ignore in value) {
catch(parse_add_rule(verb, rule));
}
}
if (!adverbs)
adverbs = ({});
}
string stat_me()
{
return "Number of feelings: " + sizeof(emotes) + "\n";
}
int
add_emote(string verb, mixed rule, string array parts)
{
/*
if( base_name( previous_object()) != CMD_ADD_EMOTE )
error("Illegal call to add_emote()\n");
*/
// try this first b/c it will error if rule is illegal
parse_add_rule(verb, rule);
if (!emotes[verb])
emotes[verb] = ([]);
if (sizeof(parts) > 1)
emotes[verb][rule] = parts;
else
emotes[verb][rule] = parts[0];
unguarded(1, (: save_object, SAVE_FILE :));
return 1;
}
int
remove_emote(string verb, string rule)
{
if ( base_name(previous_object())!=CMD_REMOVE_EMOTE )
error("Illegal call to remove_emote()\n");
if (!emotes[verb]) return 0;
if (sizeof( rule )) {
if (!emotes[verb][rule]) return 0;
map_delete(emotes[verb], rule);
} else {
map_delete(emotes, verb);
}
parse_remove(verb);
parse_refresh();
unguarded(1, (: save_object, SAVE_FILE :));
return 1;
}
int
move_emote(string verb, string dest)
{
if (base_name(previous_object())!=CMD_MOVE_EMOTE)
error("Illegal call to move_emote()\n");
if ( (!emotes[verb]) || (!dest)) return 0;
emotes[dest]=emotes[verb];
foreach (string rule, string soul in emotes[verb])
{
parse_add_rule(dest, rule);
}
map_delete(emotes, verb);
unguarded(1, (: save_object, SAVE_FILE :));
return 1;
}
mixed
query_emote(string em) {
return emotes[em];
}
private string get_completion(string);
#define IMUD_CHANNELT_DUMMY "/obj/mudlib/ichannelt"
mixed * internal_get_soul(string verb, string rule, mixed *args,
int add_imud_msg)
{
mapping rules;
mixed soul;
int i, j, num;
object *who, *imud_who;
string token;
mixed * result;
rules = emotes[verb];
if (!rules) return 0;
soul = rules[rule];
if (!soul) return 0;
// minus the verb's real name; we don't want to process the real names
// of any of the objects
num = (sizeof(args) - 1)/2;
for (i = 0; i < num; i++) {
if (stringp(args[i]) && strlen(args[i]) && args[i][<1] == '*'
&& member_array(' ', args[i]) == -1) {
args[i] = get_completion(args[i][0..<2]);
if (!args[i])
return 0;
break;
}
}
if (soul[0] == '=') soul = rules[soul[1..]];
if (stringp(soul)) {
if (soul[<1] != '\n') soul += "\n";
} else {
soul = map_array(soul, (: $1[<1] == '\n' ? $1 : $1 + "\n" :));
}
who = ({ this_body() });
if ( add_imud_msg )
imud_who = ({ new( IMUD_CHANNELT_DUMMY, this_body(), 3 ) });
if (strsrch(rule, "LIV") != -1)
{
i = 0;
foreach (token in explode(rule, " ")) {
if (token == "LIV") {
who += ({ args[i] });
if ( add_imud_msg )
imud_who += ({ new( IMUD_CHANNELT_DUMMY, args[i], 2 ) });
args[i..i] = ({});
} else
if (token[0] >= 'A' && token[0] <= 'Z')
i++;
}
}
if ( add_imud_msg )
result = ({ who, allocate( sizeof( who )+1 ),
allocate( sizeof( imud_who )+1) });
else
result = ({ who, allocate(sizeof(who) + 1) });
for ( j = 0; j < add_imud_msg+1; j++ )
{
object *w;
w = ( j ? imud_who : who );
//RABUG(sprintf("%O", w));
for (i = 0; i < sizeof(w); i++) {
string tmp;
if (stringp(soul))
tmp = soul;
else {
if (i && i + 1 < sizeof(soul))
tmp = soul[i + 1];
else
tmp = soul[0];
}
//RABUG(sprintf("i: %d, tmp: %s, soul: %O", i, tmp, soul));
//RABUG(sprintf("w[i]: %O, w: %O, args: %O", w[i], w, args));
result[1+j][i] = compose_message(w[i], tmp, w, args...);
}
//### tmp fix
result[1+j][<1] =
compose_message(0, stringp(soul) ? soul : soul[1], w, args...);
}
return result;
}
varargs mixed *
get_soul(string verb, string rule, mixed *args)
{
return internal_get_soul(verb, rule, args, 0);
}
varargs mixed *
get_imud_soul(string verb, string rule, mixed args...)
{
return internal_get_soul(verb, rule, args, 1);
}
mixed
list_emotes()
{
return keys( emotes );
}
string *
emote_apropos(string str) {
int num_verbs, num_rules;
int i, j;
string *verbs, *rules;
mapping rules_for_verb;
mixed data;
string *found;
found = ({});
verbs = keys(emotes);
num_verbs = sizeof(verbs);
for (i=0; i<num_verbs; i++) {
rules_for_verb = emotes[verbs[i]];
rules = keys(rules_for_verb);
num_rules = sizeof(rules);
for (j=0; j<num_rules; j++) {
data = rules_for_verb[rules[j]];
if (arrayp(data)) {
if (strsrch(lower_case(data[0]), lower_case(str)) != -1 ||
strsrch(lower_case(data[1]), lower_case(str)) != -1)
found += ({ verbs[i] + " " + rules[j] });
}
else {
if (strsrch(lower_case(data), lower_case(str)) != -1)
found += ({ verbs[i] + " " + rules[j] });
}
}
}
return found;
}
private string get_completion(string s)
{
string * completions;
completions = complete(s, adverbs);
switch(sizeof(completions))
{
case 0:
write("Can't find a match for '" + s + "*'.\n");
return 0;
case 1:
return completions[0];
default:
write("Can't find a unique match.\nFound: " + implode(completions, ", ") + "\n");
return 0;
}
}
/*
** Interface with parsing functions. We use the "wild" card functions
** so that we don't have to support a gazillion can/do type actions.
*/
int livings_are_remote() { return 1; }
mixed can_verb_wrd(string verb, string wrd)
{
return member_array(wrd, adverbs) != -1 || member_array('*', wrd) != -1;
}
mixed can_verb_rule(string verb, string rule)
{
if (!emotes[verb]) return;
return !undefinedp(emotes[verb][rule]);
}
mixed direct_verb_rule(string verb, string rule)
{
return !undefinedp(emotes[verb][rule]);
}
mixed indirect_verb_rule(string verb, string rule)
{
return !undefinedp(emotes[verb][rule]);
}
void do_verb_rule(string verb, string rule, mixed args...)
{
mixed soul;
// RABUG(sprintf("do_verb_rule: (args: %O)", args));
soul = get_soul(verb, rule, args);
if (!soul) return;
if ( sizeof(soul[0]) == 2 &&
!immediately_accessible(soul[0][1]))
{
soul[1][0] = "*" + soul[1][0];
soul[1][1] = "*" + soul[1][1];
inform(soul[0], soul[1], 0);
}
else
{
inform(soul[0], soul[1], environment(this_body()));
}
return;
}
mixed *parse_soul(string str) {
mixed result;
mixed soul;
result = parse_my_rules(this_body(), str, 0);
if (!result) return 0;
if( intp(result) || stringp(result)) return 0;
soul = get_soul(result[0], result[1], result[2..]);
if (!soul) return 0;
return soul;
}
mixed *parse_imud_soul(string str) {
object temp;
string user;
string tmp;
mixed result;
mixed soul;
int i;
// This bit of the code can only handle one person,
// could make it handle more, but its not worth it while the IMUD stuff
// only handles two people
i = strsrch( str, "@" );
// if ( i > -1 )
if(sscanf(str,"%s@%s",user,tmp)==2)
{
string array muds=IMUD_D->query_up_muds();
string array words=explode(tmp," ");
string array matches;
string array previous_matches=muds;
string emote;
int j=sizeof(words);
/* The soul is all of the user except for the last word. */
emote=implode(explode(user," ")[0..<2]," ");
/* Assume that the last word of user, is the actual users name
* this has problems if there are cases where the users name includes
* a space, but we will deal with that later.*/
user=explode(user," ")[<1];
tmp="";
for(i=0;i<j;i++) {
tmp += " " + words[i];
if(tmp[0]==' ')
tmp=tmp[1..];
matches=find_best_match_or_complete(tmp,muds);
/* If there are multiple matches, add the next word first and see
* if that narrows the possibilities down. */
if(sizeof(previous_matches&matches)>1) {
previous_matches&=matches;
continue;
}
/* We know that there is either 1 or no matches now. Check for none
* first. The fact that we are at this point means that the previous
* iteration had more than one match, but this one doesn't. It's
* ambiguous */
if(!sizeof(matches)) {
write("Vague mud name. could be: " +
implode(previous_matches,", ") + "\n");
return;
}
/* We have narrowed things down to one successful match. Nothing more
* needs to be done. Just use it. */
}
tmp=sprintf("%s@%s",user,matches[0]);
temp = new( IMUD_CHANNELT_DUMMY, tmp );
if ( temp )
{
str = replace_string( sprintf("%s %s",emote,tmp), tmp, "wibblewibble"+tmp );
}
}
result = parse_my_rules(this_body(), str, 0 );
if (!result || intp(result) || stringp(result))
{
if ( temp ) temp->remove();
return 0;
}
soul = get_imud_soul(result...);
if (!soul)
return 0;
return soul;
}
void set_adverbs(string* mods)
{
if(!arrayp(mods)) error("bad arg type");
adverbs = mods;
unguarded(1, (: save_object, SAVE_FILE :));
}
string* get_adverbs(){
return adverbs;
}
void add_adverb(string adverb)
{
if(!stringp(adverb)) error("bad arg type");
adverbs += ({adverb});
unguarded(1, (: save_object, SAVE_FILE :));
}
void remove_adverb(string adverb)
{
adverbs -= ({adverb});
unguarded(1, (: save_object, SAVE_FILE :));
}