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

444 lines
12 KiB
C

/* /daemon/emote.c
* From the Dead Souls Object Library
* A centralized soul handler
* Created by Descartes of Borg 961207
* Version: @(#) soul.c 1.11@(#)
* Last modified: 96/12/15
*/
#include <lib.h>
#include <pov.h>
#include <privs.h>
#include <save.h>
#include <daemons.h>
inherit LIB_DAEMON;
class emote {
string ErrorMessage;
mapping Rules;
}
class rule {
mixed array Message;
string array Adverbs;
}
private mapping Emotes = ([]);
private string array Adverbs = ({});
static private void validate() {
if(!this_player()) return 0;
if( !(master()->valid_apply(({ "ASSIST" }))) &&
!member_group(this_player(), "EMOTES") )
error("Illegal attempt to access SOUL_D: "+get_stack()+" "+identify(previous_object(-1)));
}
varargs int AddAdverbs(string array advs...) {
validate();
Adverbs = distinct_array(Adverbs + advs);
eventSave();
return 1;
}
varargs int AddRule(string verb, string rle, mixed array msg,
string array advs) {
class emote e = Emotes[verb];
class rule r;
validate();
if( !e ) {
return 0;
}
r = new(class rule);
r->Message = msg;
r->Adverbs = (advs || ({}));
e->Rules[rle] = r;
if( catch(parse_add_rule(verb, rle)) ) {
return 0;
}
eventSave();
return 1;
}
int AddVerb(string verb, string err) {
class emote e;
validate();
if( Emotes[verb] ) {
return 0;
}
else {
e = new(class emote);
}
e->ErrorMessage = err;
e->Rules = ([]);
Emotes[verb] = e;
eventSave();
return 1;
}
int RemoveRule(string emt, string rle) {
class emote e = Emotes[emt];
validate();
if( !e ) {
return 0;
}
map_delete(e->Rules, rle);
eventSave();
return 1;
}
int RemoveVerb(string verb) {
validate();
map_delete(Emotes, verb);
eventSave();
return 1;
}
string array GetAdverbs() {
return copy(Adverbs);
}
varargs mixed array GetChannelEmote(string emote, string parse, string args) {
class emote e = Emotes[emote];
mapping adverb = ([]);
class rule r;
if( !e ) {
return 0;
}
r = e->Rules[parse];
if( !r ) {
parse = replace_string(parse, "LIV", "LVS");
r = e->Rules[parse];
if( !r ) {
return 0;
}
}
if( args ) {
string array pool = r->Adverbs;
int any_adv = (member_array("*", pool) != -1);
if( member_array("-", pool) != -1 ) {
pool += Adverbs;
}
if( !any_adv && member_array(args, pool) == -1 ) {
string array matches = regexp(pool, "^" + args);
if( !sizeof(matches) ) {
return 0;
}
adverb = ([ "$adverb" : matches[0] ]);
}
else {
adverb = ([ "$adverb" : args ]);
}
}
return ({ r->Message, adverb });
}
string array GetEmotes() {
return keys(Emotes);
}
string GetErrorMessage(string verb) {
class emote e = Emotes[verb];
if( !e ) {
return 0;
}
return e->ErrorMessage;
}
string GetHelp(string arg) {
class emote e;
string array rls;
string str;
if( arg == "soul" ) {
str = "Your \"soul\" is a system of expressions you can use "
"to express how you are feeling. Though it does not really "
"cause anything to happen, other people, including NPC's, may "
"react to your emotions, especially when they are violent or "
"negative.\n\n"
"Some soul commands allow you to express an adverb to give some "
"sort of emphasis to the expression. Some commands are limited "
"to a certain set of adverbs, while most commands will allow you "
"to choose from the list of system wide adverbs given below. "
"You may always use your racial adverb in any expression "
"allowing an adverb. A racial adverb is simply a way of "
"emoting unique to your race, like \"smile gnomishly\".\n\n"
"For a list of soul commands, try <help feelings>.\n\n"
"The list of system adverbs are:\n";
str += format_page(sort_array(Adverbs, 1), 5);
return str;
}
e = Emotes[arg];
if( !e ) {
return 0;
}
rls = keys(e->Rules);
if( !sizeof(rls) ) {
return "This emote is not yet valid.";
}
else {
int w = member_array("", rls);
if( w > 0 ) {
if( w < sizeof(rls) -1 ) {
rls = ({ rls[w], rls[0..(w-1)]..., rls[(w+1)..]... });
}
else {
rls = ({ rls[w], rls[0..(w-1)]... });
}
}
}
if( rls[0] == "" ) {
str = "Syntax: <" + arg + ">\n";
}
else {
class rule r = e->Rules[rls[0]];
string array pool = r->Adverbs;
int all_advs = (member_array("-", r->Adverbs) != -1);
int anything = (member_array("*", r->Adverbs) != -1);
string rule = rls[0];
rule = replace_string(rule, "LIV", "SINGLE_LIVING");
rule = replace_string(rule, "LVS", "ONE_OR_MORE_LIVINGS");
if( anything ) {
rule = replace_string(rule, "STR", "PHRASE");
}
else if( all_advs ) {
pool = (pool - ({ "-", "*" })) + ({ "system adverbs" });
rule = replace_string(rule, "STR", "ADVERB");
}
str = "Syntax: <" + arg + " " + rule + ">\n";
if( !anything ) {
if( sizeof(pool) ) {
str += " Adverbs: " + item_list(pool);
}
}
str += "\n";
}
if( sizeof(rls) > 1 ) {
rls = rls[1..];
foreach(string rule in rls) {
class rule r = e->Rules[rule];
if( rule == "" ) {
str += " <" + arg + ">\n";
}
else {
string array pool = r->Adverbs;
int all_advs = (member_array("-", r->Adverbs) != -1);
int anything = (member_array("*", r->Adverbs) != -1);
rule = replace_string(rule, "LIV", "SINGLE_LIVING");
rule = replace_string(rule, "LVS", "ONE_OR_MORE_LIVINGS");
if( anything ) {
rule = replace_string(rule, "STR", "PHRASE");
}
else if( all_advs ) {
pool = (pool - ({ "-", "*" })) + ({ "system adverbs" });
rule = replace_string(rule, "STR", "ADVERB");
}
str += " <" + arg + " " + rule + ">";
if( !anything ) {
if( sizeof(pool) ) {
str += " Adverbs: " + item_list(pool);
}
}
str += "\n";
}
}
}
str += "\n";
str += capitalize(arg) + " is a soul command and affects nothing.\n";
str += "System adverbs are listed in <help soul>.\n";
str += "SINGLE_LIVING: You can target a single living thing\n"
"ONE_OR_MORE_LIVINGS: You can target multiple people using \"all\"\n"
"PHRASE: Any random phrase\n"
"ADVERB: Any adverb from the list of supported adverbs, or your "
"racial adverb.";
return str;
}
void SetErrorMessage(string verb, string msg) {
class emote e = Emotes[verb];
validate();
if( !e ) {
AddVerb(verb, msg);
}
else {
e->ErrorMessage = msg;
eventSave();
}
}
string GetRaceAdverb(mixed who) {
string res;
if( objectp(who) ) {
res = who->GetRace();
}
if( !res ) {
return "godly";
}
switch(res) {
case "gnome": return "gnomishly";
case "elf": return "elvenly";
case "half-elf": return "half-elvenly";
case "orc": return "orcishly";
case "half-orc": return "half-orcishly";
default: return res + "ly";
}
}
mapping GetRules(string emote) {
class emote e = Emotes[emote];
mapping m = ([]);
if( !e ) {
return 0;
}
foreach(string rle, class rule r in e->Rules) {
m[rle] = ({ r->Adverbs, r->Message });
}
if( !master()->valid_apply(({ PRIV_ASSIST }))
|| (this_player() && !member_group(this_player(), "EMOTES"))){
return copy(m);
}
return m;
}
int CanTarget(object who, string verb, object target, string rule) {
if( Emotes[verb] ) {
return 1;
}
else {
return 0;
}
}
mixed can_verb_rule(string verb, string rle) {
class emote e = Emotes[verb];
class rule r;
if( !e ) {
return 0;
}
r = e->Rules[rle];
if( !r ) {
return 0;
}
return 1;
}
varargs mixed do_verb_rule(string verb, string rle, mixed args...) {
object env = environment(this_player());
class emote e = Emotes[verb];
class rule r = e->Rules[rle];
string adv = 0;
switch( rle ) {
case "":
args = 0;
adv = 0;
break;
case "LIV": case "at LIV": case "with LIV": case "to LIV":
case "around LIV": case "on LIV":
case "OBJ": case "at OBJ": case "with OBJ": case "to OBJ":
case "LVS": case "at LVS": case "with LVS": case "to LVS":
case "around LVS": case "on LVS":
args = args[0];
adv = 0;
break;
case "STR": case "for STR": case "about STR":
adv = args[0];
args = 0;
break;
case "STR LIV": case "STR at LIV": case "STR with LIV":
case "STR around LIV": case "STR on LIV":
case "for STR LIV": case "for STR to LIV":
case "STR OBJ": case "STR at OBJ": case "STR with OBJ":
case "STR LVS": case "STR at LVS": case "STR with LVS":
case "STR around LVS": case "STR on LVS":
case "for STR LVS": case "for STR to LVS":
adv = args[0];
args = args[1];
break;
case "LIV STR": case "at LIV STR": case "LIV of STR": case "with LIV STR":
case "around LIV STR": case "on LIV STR":
case "LIV for STR": case "to LIV for STR":
case "OBJ STR": case "at OBJ STR": case "OBJ of STR": case "with OBJ STR":
case "LVS STR": case "at LVS STR": case "LVS of STR": case "with LVS STR":
case "around LVS STR": case "on LVS STR":
case "LVS for STR": case "to LVS for STR":
adv = args[1];
args = args[0];
break;
default:
this_player()->eventPrint("Unknown soul syntax.");
return 1;
}
if( arrayp(args) ) {
args = filter(args, (: objectp :));
}
if( adv ) {
string array pool = r->Adverbs + ({ GetRaceAdverb(this_player()) });
int any_adv = (member_array("*", pool) != -1);
if( member_array("-", pool) != -1 ) {
pool += Adverbs;
}
if( !any_adv && member_array(adv, pool) == -1 ) {
string array matches = regexp(pool, "^" + adv);
if( !sizeof(matches) ) {
this_player()->eventPrint("You cannot " + verb + " " + adv +
"!");
return 1;
}
adv = matches[0];
}
send_messages(r->Message[0], r->Message[1], this_player(), args, env,
([ "$adverb" : adv ]));
if( args ) {
args->eventReceiveEmote(this_player(), verb, adv);
}
}
else {
send_messages(r->Message[0], r->Message[1], this_player(), args, env);
if( args ) {
args->eventReceiveEmote(this_player(), verb);
}
}
return 1;
}
static void create() {
SetSaveFile(SAVE_SOUL);
daemon::create();
if(!file_exists(GetSaveFile()) &&
file_exists(old_savename(GetSaveFile()))){
cp(old_savename(GetSaveFile()), GetSaveFile());
}
SetNoClean(1);
parse_init();
foreach(string verb, class emote data in Emotes) {
foreach(string rle in keys(data->Rules)) {
parse_add_rule(verb, rle);
}
}
eventSave();
}