/* /daemon/soul.c
* A central daemon to handle all soul commands issued via players
* created by Blitz@NM-IVD (last edited Oct/9/95)
*/
#include <soul.h>
inherit SOUL_ADVERBS;
private mapping Soul;
int GetEmoteHelp(string str);
class SoulRec {
mixed *var, *message;
object *target;
}
static void create() {
object ob;
adverbs::create();
if( !file_exists(SaveFile + ".o") ) {
Soul = ([ ]);
if( catch(ob = load_object(FallBackFile)) ) return;
if( ob ) Soul = ob->GetSoulCommands();
if( sizeof(Soul) ) save_object(SaveFile);
}
else restore_object(SaveFile);
}
static object GetLiving(string str) {
object ob;
if( !str || str == "" ) return 0;
if( ( !ob = present(str, environment(this_player())) ) ||
( hiddenp(ob) ) ||
( ob->GetInvis() ) ) return 0;
return ob;
}
varargs static string
Match(string action, string search, mixed extra) {
string *line = ({});
if( !sizeof(search) ) return 0;
if( !extra ) {
if( search == "." ) return "";
line = (Soul[action][ExtraAdverbs] || ({}) ) + GetAdverbs(search);
}
else if( arrayp(extra) ) line = extra;
if( !sizeof(line) ) return 0;
if( sizeof(line = regexp(line, "^"+search)) )
return line[0];
if( member_array("*", line) > -1 ) return search;
return 0;
}
private string MakeYourMessage(class SoulRec Emote) {
int i, flag, cnt;
object last_target, target;
mixed str, line;
string ret = "";
foreach(line in Emote->message) {
i = sizeof( str = line[0][0..] );
target = Emote->target[cnt];
while(i--) if( str[i][0] == '$' ) {
switch(str[i]) {
case "$N" : str[i] = (flag ? "" : "you"); flag = 1; break;
case "$A" : str[i] = (Emote->var[cnt][2] || ""); break;
case "$T" : if(target) {
if(last_target == target)
str[i] = objective(target);
else str[i] = (string)target->GetName();
last_target = target;
} else str[i] = 0;
break;
case "$TA" : if(target) {
if(last_target == target)
str[i] = possessive(target); else
str[i] = possessive_noun((string)target->GetName());
} else str[i] = 0;
break;
case "$TP" : str[i] = (target ? possessive(target) : ""); break;
case "$TO" : str[i] = (target ? objective(target) : ""); break;
case "$TR" : str[i] = (target ? reflexive(target) : ""); break;
case "$TN" : str[i] = (target ? nominative(target) : ""); break;
case "$NP" : str[i] = "your"; break;
case "$NO" : case "$NN" : str[i] = "you"; break;
case "$NR" : str[i] = "yourself"; break;
case "$X" : case "$*" : str[i] = (Emote->var[cnt][3] || "");
break;
}
}
ret += implode(filter(str, (: sizeof :)), " ");
if(Emote->var[cnt][4]) ret += (string)Emote->var[cnt][4];
cnt++;
}
return (capitalize(ret) + ".");
}
private string MakeTheirMessage(class SoulRec Emote, object who) {
int i, flag, cnt;
object last_target, target;
mixed str, line;
string ret = "";
foreach(line in Emote->message) {
i = sizeof( str = line[1][0..] );
target = Emote->target[cnt];
while(i--) if( str[i][0] == '$' ) {
switch(str[i]) {
case "$N" : line[1][i] = str[i] =
(flag ? "" : (string)this_player()->GetName());
flag = 1; break;
case "$A" : line[1][i] = str[i] = (Emote->var[cnt][2] || ""); break;
case "$T" : if(target) {
if(target == who) str[i] = "you"; else
if(last_target == target)
str[i] = objective(target);
else str[i] = (string)target->GetName();
last_target = target;
} else str[i] = "";
break;
case "$TA" : if(target) {
if(target == who) str[i] = "your"; else
if(last_target == target)
str[i] = possessive(target); else
str[i] = possessive_noun((string)target->GetName());
} else str[i] = "";
break;
case "$TN" : if(!target) str[i] = ""; else
if(target == who) str[i] = "you"; else
str[i] = nominative(target);
break;
case "$TO" : if(!target) str[i] = ""; else
if(target == who) str[i] = "you"; else
str[i] = objective(target);
break;
case "$TP" : if(!target) str[i] = ""; else
if(target == who) str[i] = "your"; else
str[i] = possessive(target);
break;
case "$NP" : line[1][i] = str[i] = possessive(this_player()); break;
case "$NO" : line[1][i] = str[i] = objective(this_player()); break;
case "$NR" : line[1][i] = str[i] = reflexive(this_player()); break;
case "$NN" : line[1][i] = str[i] = nominative(this_player()); break;
case "$TR" : if(!target) str[i] = ""; else
if(target == who) str[i] = "yourself"; else
str[i] = reflexive(target);
break;
case "$NA" : line[1][i] = str[1] =
possessive_noun((string)this_player()->GetName());
break;
case "$X" : case "$*" :
line[1][i] = str[i] = (Emote->var[cnt][3] || "");
break;
}
}
ret += implode(filter(str, (: sizeof :)), " ");
if(Emote->var[cnt][4]) ret += (string)Emote->var[cnt][4];
cnt++;
}
return (capitalize(ret) + ".");
}
static void DisplayMessages(class SoulRec Emote) {
object *obs, ob;
message("emote", MakeYourMessage(Emote), this_player() );
if( sizeof(obs = filter(distinct_array(Emote->target), (: $1 :))) )
foreach(ob in obs)
message("emote", MakeTheirMessage(Emote, ob), ob);
if( !obs ) obs = ({ });
message("emote", MakeTheirMessage(Emote, 0),
environment(this_player()), obs + ({ this_player() }) );
}
int do_cmd(string action, string arg) {
string *emotes, *var;
string feeling, tmp, tmp2;
mixed str;
int i, total;
class SoulRec Emote;
if(!Soul[action]) return 0;
if( !arg ) arg = "";
total = sizeof(emotes = explode(sprintf("%s %s", action, arg), " and "));
Emote = new(class SoulRec);
Emote->var = allocate(total);
Emote->target = Emote->var[0..];
Emote->message = Emote->var[0..];
foreach(feeling in emotes) {
if(sizeof(var = explode(feeling, " ")) > 4) {
var[3] = implode(var[3..], " ");
var = var[0..3] + ({ 0 });
} else var += allocate(5 - sizeof(var));
if(!Soul[ var[0] ]) {
message("emote", capitalize( var[0] )+" is not a valid feeling!",
this_player() );
return 1;
}
if( Soul[ var[0] ][DisableAnd] && (total>1) ) {
message("emote", capitalize(var[0])+" does not support "
"the 'and' option.",
this_player() );
return 1;
}
if( !sizeof(var[1]) ) {
if(!str = Soul[ var[0] ][NoArgs] || Soul[ var[0] ][NoTarget] ) {
message("emote", capitalize(var[0])+" whom?", this_player());
return 1;
}
}
else
if( !Emote->target[i] = GetLiving(var[1]) ) {
if( !Soul[ var[0] ][NoTarget] ) {
message("emote", capitalize(var[0]) + " whom? ", this_player());
return 1;
}
var[3] = sizeof(var[3]) ? (var[2]+" "+var[3]) : var[2];
var[2] = var[1];
var[1] = 0;
str = Soul[ var[0] ][NoTarget];
}
else str = Soul[ var[0] ][Targeted];
if( Emote->target[i] == this_player() ) {
message("emote", "That would be silly.", this_player());
return 1;
}
tmp2 = tmp = 0;
if(!arrayp(str) || (sizeof(str) != 2)) {
notify_fail("You cannot "+var[0]+" like that!\n");
return 0;
}
if( sizeof(var[2]) ) { /* check for adverb */
if( !(tmp = Match(var[0], var[2])) || /* one word match? */
(sizeof(var[3]) && /* >one word match? */
!tmp2 = Match(var[0], var[2]+" "+var[3])) )
{
var[3] = var[3] ? (var[2]+" "+var[3]) : var[2]; /* no match found */
var[2] = Soul[var[0]][ForceAdverb]; /* use forced */
} else { /* adverb if any */
var[2] = tmp || tmp2;
if(tmp2) var[3] = 0; /* since a adverb was matched using more */
} /* word, nullify extra var.. */
}
else var[2] = Soul[var[0]][ForceAdverb];
if( sizeof(var[3]) ) {
tmp = 0;
if( !Soul[ var[0] ][Locations] ) {
if(strsrch(str[1], "$*") == -1) {
notify_fail("You cannot "+var[0]+" like that!\n");
return 0;
}
} else {
if( Soul[var[0]][Preposition] &&
!strsrch(var[3], Soul[var[0]][Preposition]) )
var[3] = replace_string(var[3],
Soul[var[0]][Preposition] + " ", "");
if( !tmp = Match(var[0], var[3], Soul[var[0]][Locations]) ) {
message("emote", "You cannot "+var[0]+" like that!", this_player());
return 1;
}
if( Soul[var[0]][Preposition] )
var[3] = sprintf("%s %s", Soul[var[0]][Preposition], tmp);
else var[3] = tmp;
}
} else
if( strsrch(str[1], "$X") > -1 && Soul[var[0]][ForceLocation] )
var[3] = Soul[var[0]][ForceLocation];
if( (total > 1) && i < (total-1) )
var[4] = ( i == (total-2) ? " and " : ", " );
Emote->var[i] = var[0..]; /* copy(var) */
Emote->message[i] = ({ explode(str[0], " "), explode(str[1], " ") });
var = allocate(5);
i++;
}
DisplayMessages(Emote);
return 1;
}
int AddEmote(string verb, mixed m) {
if( !archp(this_player()) ) return 0;
if( !mapp(m) ) {
error("Bad argument 1 to AddEmote.\n");
return 0;
}
Soul[verb] = copy(m);
save_object(SaveFile);
return 1;
}
int RemoveEmote(string verb) {
if( !archp(this_player()) ) return 0;
if( !Soul[verb] ) return 0;
map_delete(Soul, verb);
save_object(SaveFile);
}
mixed GetEmote(string verb) {
if(!Soul[verb]) return 0;
return copy(Soul[verb]);
}
string GetHelp(string str) {
string ret, var, search;
mixed tmp, sarray;
mapping AdverbPool = ([ ]);
if( sscanf(str, "%s %s", var, search) ) str = var;
if( str == "feelings" ) sarray = keys(Soul);
else if( str == "adverbs" ) {
sarray = ({});
AdverbPool = GetAdverbPool();
tmp = keys(AdverbPool);
foreach(var in tmp) sarray += AdverbPool[var];
}
else return 0;
if( search )
if(!sizeof(sarray = regexp(sarray, "^"+search))) return 0;
sarray = sort_array(sarray, 1);
ret = "[ %^CYAN%^"+capitalize(str)+" listing. Matches found: "+sizeof(sarray)+"%^RESET%^ ]\n\n";
if( str == "feelings" )
ret += HelpPage;
ret += format_page(sarray, (str == "adverbs" ? 4 : 5));
if( str == "feelings" )
ret += "\nNote: \"help adverbs <search prefix>\" to see adverbs.\n";
return ret;
}