#pragma save_binary /* mudlib: Basis file: /bin/daemon/emoted.c author: Truilkan created: 1992/09/25 modified by Truilkan to run on tmi-2 on 1992/11/09 */ // Use the /t suffix if you want to edit the targeted version of the emotion. // To enter something in any of the fields, just add something on the line after // the header for it. For example, any lines entered between the .me line, and // the .others line will be the message displayed to the user of the command. // For reference, the replaceable parameters are: // $N = name of user $n = name of target // $S = subjective of user $O = objective of user $P = possessive of user // $s = '' '' target $o = '' '' target $p = '' '' target // $M = modifier (only appears if user ends command with " .") // $m = modifier (always appears unless user types own modifier or " .") // $V = verb (defaults to command name. can be set with .verb) // $G = possessive of user (either $N's or 'your' depending) // $g = possessive of target ('' $n's '') // $Q = preceding possessive (i.e. hers, his, its, hirs, yours) for user // $q = '' for target // For $S, $O, $P, $s, $o, $p: // subjective = (he, she, it, sie), objective = (him, her, it, hir), // possessive = (his, her, its, hir) // Mobydick added a lower_case() so that "kiss Psyche" would work as // well as "kiss psyche" does. // Pallando fixed lower_case() for the case someone just types "kiss" #include <config.h> #include <daemons.h> #include <emoted.h> inherit "/std/save.c"; mapping temotes, emotes; mixed * copy_array(mixed *array) { if (!pointerp(array)) return 0; else return array[0..(sizeof(array) - 1)]; } int query_prevent_shadow() { return 1; } void create() { temotes = ([]); emotes = ([]); set_persistent(1); // cause create()/remove() to load/save data seteuid(getuid()); save::create(); // restore the datafile } string * query_keys() { return uniq_array(keys(temotes) + keys(emotes)); } string * query_emotes() { return keys(emotes); } string * query_temotes() { return keys(temotes); } string to_string(mapping entry) { string result, *fields, val; int x; result = 0; if (mapp(entry)) { result = ""; fields = FIELDS; for (x = 0; x < sizeof(fields); x++) { if (entry && !undefinedp(val = entry[x])) { result += (fields[x] + "\n"); result += (val + "\n"); } } result += ".end\n"; } return result; } mapping to_mapping(string body) { int i, size, x, start; string *lines, *fields, *stop_fields; mapping new_entry; if (!body) { return 0; } lines = explode(body, "\n"); size = sizeof(lines); new_entry = ([]); fields = FIELDS; stop_fields = STOP_FIELDS; for (x = 0; x < sizeof(fields); x++) { i = member_array(fields[x], lines) + 1; if (!i) { continue; } if ((i < size) && ((member_array(lines[i], stop_fields) == -1))) { new_entry[x] = ""; start = i; for (;(i < size)&&(member_array(lines[i],stop_fields) == -1);i++) { if (i != start) { new_entry[x] += "\n" + lines[i]; } else { new_entry[x] += lines[i]; } } } } return new_entry; } // return a processed map to its original form mapping unprocess(mapping entry) { string *words, line, field; mapping new_entry; int *idx, j, k; if (!entry) { return 0; } idx = keys(entry); new_entry = allocate_mapping(sizeof(entry)); for (j = 0; j < sizeof(idx); j++) { if ((idx[j] == e_verb) || (idx[j] == e_verb2)) { new_entry[idx[j]] = entry[idx[j]]; } else { words = entry[idx[j]]; line = ""; for (k = 0; k < sizeof(words); k++) { field = words[k]; if (field[0] == 'X') { field = field[1..(strlen(field) - 1)]; } else { field = "$" + field; } line += field; } new_entry[idx[j]] = line; } } return new_entry; } // query an emote without a target string query_emote(string verb) { return to_string(unprocess(emotes[verb])); } // query an emote with a target string query_temote(string verb) { return to_string(unprocess(temotes[verb])); } // process: convert the map into a form that may be parsed more efficiently mapping process(mapping entry) { string *words, line; int *idx; int j; if (!entry) { return 0; } idx = keys(entry); for (j = 0; j < sizeof(idx); j++) { if ((idx[j] != e_verb) && (idx[j] != e_verb2)) { line = entry[idx[j]]; words = explode(line, "$"); if (line[0] != '$') { words[0] = "X" + words[0]; } entry[idx[j]] = words; } } return entry; } // add a temote void add_temote(string verb, string body) { if (!body) { return; } temotes[verb] = process(to_mapping(body)); } // add an emote void add_emote(string verb, string body) { mapping entry; if (!body) { return; } entry = to_mapping(body); if (undefinedp(entry[e_target])) { emotes[verb] = process(entry); } else { add_temote(verb, body); } } void delete_emote(string verb) { map_delete(emotes, verb); } void delete_temote(string verb) { map_delete(temotes, verb); } string apostrophed(string name) { int len; len = strlen(name); if (name[len - 1] == 's') { return name + "'"; } else { return name + "'s"; } } string cap_it(string str, int do_cap) { if (do_cap) { return capitalize(str); } else { return str; } } // make the substitutions for the various $variables string substitute(string verb, string verb2, int kind, string rest, string *words, string *modifier, object me, object target) { string name, pronoun, mo, remainder, temp; string plural, plural2; int j, forced, do_cap; for (j = 0; j < sizeof(words); j++) { forced = 0; if (!j) { do_cap = 1; } else if (words[j][0] == 'c') { words[j] = words[j][1..(strlen(words[j]) - 1)]; do_cap = 1; } else { do_cap = 0; } remainder = words[j][1..(strlen(words[j]) - 1)]; switch (words[j][0]) { case 'X' : // empty replacement (necessary) words[j] = remainder; break; case 'V' : if (kind == e_me) { words[j] = cap_it(verb, do_cap) + remainder; } else { if (!plural) { plural = pluralize_verb(verb); } words[j] = cap_it(plural, do_cap) + remainder; } break; case 'W' : if (kind == e_me) { words[j] = cap_it(verb2, do_cap) + remainder; } else { if (!plural2) { plural2 = pluralize_verb(verb2); } words[j] = cap_it(plural2, do_cap) + remainder; } break; case 'N' : // my name if (kind == e_me) { name = "you"; } else { name = (string)me->query("cap_name"); } words[j] = cap_it(name, do_cap) + remainder; break; case 'n' : // name of the target if (target == me) { switch (kind) { case e_me : name = "yourself"; break; case e_others : case e_target : if (!mo) { mo = objective((string)me->query("gender")); } name = cap_it(mo, do_cap) + "self"; break; break; default : break; } } else { if (target) { if (kind == e_target) { name = "you"; } else { name = (string)target->query("cap_name"); } } else { name = ""; } } words[j] = cap_it(name, do_cap) + remainder; break; case 'Q' : if (kind == e_me) { pronoun = "yours"; } else { pronoun = ppossessive((string)me->query("gender")); } words[j] = cap_it(pronoun, do_cap) + remainder; break; case 'q' : if (kind == e_target) { pronoun = ppossessive((string)target->query("gender")); } else { pronoun = "yours"; } words[j] = cap_it(pronoun, do_cap) + remainder; break; case 'G' : if (kind == e_me) { pronoun = "your"; } else { pronoun = apostrophed((string)me->query("cap_name")); } words[j] = cap_it(pronoun, do_cap) + remainder; break; case 'g' : if ((kind == e_target) || ((kind == e_me) && (me == target))) { pronoun = "your"; } else if (target == me) { pronoun = possessive((string)target->query("gender")); } else { pronoun = apostrophed((string)target->query("cap_name")); } words[j] = cap_it(pronoun, do_cap) + remainder; break; case 'm' : forced = 1; case 'M' : // replace with extra text or default temp = remainder; if ((!forced && (rest == ".")) || (forced && !rest)) { if (pointerp(modifier)) { rest = substitute(verb, verb2, kind, "", modifier, 0, me, target); } } if (!rest || (rest == ".")) { int rlen; rest = ""; rlen = strlen(temp); if (rlen && (temp[0] == ' ')) { temp = temp[1..(rlen - 1)]; } } words[j] = cap_it(rest, do_cap) + temp; break; case 'S' : // subjective pronoun for me if (kind == e_me) { pronoun = "you"; } else { pronoun = subjective((string)me->query("gender")); } words[j] = cap_it(pronoun, do_cap) + remainder; break; case 's' : // subjective pronoun for target if (kind == e_target) { pronoun = "you"; } else { pronoun = subjective((string)target->query("gender")); } words[j] = cap_it(pronoun, do_cap) + remainder; break; case 'P' : // possessive pronoun for me if (kind == e_me) { pronoun = "your"; } else { pronoun = possessive((string)me->query("gender")); } words[j] = cap_it(pronoun, do_cap) + remainder; break; case 'p' : // possessive pronoun for target if (kind == e_target) { pronoun = "your"; } else { pronoun = possessive((string)target->query("gender")); } words[j] = cap_it(pronoun, do_cap) + remainder; break; case 'O' : // objective pronoun for me if (kind == e_me) { pronoun = (target == me) ? "yourself" : "you"; } else { pronoun = objective((string)me->query("gender")); } words[j] = cap_it(pronoun, do_cap) + remainder; break; case 'o' : // objective pronoun for target if (kind == e_target) { pronoun = "you"; } else { if ((kind == e_me) && (target == me)) { pronoun = "yourself"; } else { pronoun = objective((string)target->query("gender")); } } words[j] = cap_it(pronoun, do_cap) + remainder; break; default : // words[j] unchanged break; } } return implode(words, ""); } string punctuate(string result) { int len, ch, ch2; if ((len = strlen(result)) < 3) { return result; } ch = result[len - 1]; ch2 = result[len - 2]; if ((ch == '.') && (ch2 == ' ')) { return result[0 .. (len - 3)] + "."; } if (ch == ' ') { result = result[0..(len - 2)]; ch = result[len - 2]; } if ((ch != '.') && (ch != '!') && (ch != '?')) { return result + "."; } else { return result; } } varargs void do_emote(string verb, string verb2, string rest, mapping entry, object me, object target, int test, int same_super) { string result, *mods, *words, *values, *def; mods = copy_array(entry[e_modifier]); def = entry[e_me]; if (!def) { if (target) { def = ({"N ", "V ", "M at ", "n"}); } else { def = ({"N ", "V ", "M"}); } } if (def[0] != "X*empty") { result = substitute(verb, verb2, e_me, rest, copy_array(def), mods, me, target); result = punctuate(result); if (target && !same_super) { result = "*" + result; } if (test) { write("me:\n" + result + "\n"); } else { write(result + "\n"); } } if (target && (target != me)) { mods = copy_array(entry[e_modifier]); if (!(values = entry[e_target])) { values = entry[e_others]; if (!values) { values = def; } } if (values && (values[0] != "X*empty")) { result = substitute(verb, verb2, e_target, rest, copy_array(values), mods, me, target); result = punctuate(result); if (target && !same_super) { result = "*" + result; } if (test) { write("target:\n" + result + "\n"); } else { tell_object(target, result + "\n"); } } } if (!target || same_super) { mods = copy_array(entry[e_modifier]); if (!(values = entry[e_others])) { values = def; } if (values) { result = substitute(verb, verb2, e_others, rest, copy_array(values), mods, me, target); result = punctuate(result); if (test) { write("others:\n" + result + "\n"); } else { // say(result + "\n", target); // Leto: there is no target here....weird.. if (!target) say(result+"\n"); else say(result+"\n", target); } } } } varargs int parse(string command, string rest, int test) { string head, tail, verb, verb2; object target, me; mapping entry, tentry; int same_super; entry = emotes[command]; tentry = temotes[command]; same_super = 0; if (!rest) { rest = (string)this_player()->getenv(command); } if (!mapp(entry) && !mapp(tentry)) { // not a recognized emote return 0; } me = this_player(); if (rest && (sscanf(rest, "%s %s", head, tail) != 2)) { head = rest; tail = 0; } if(head) head = lower_case(head); if (rest) { if (mapp(tentry)) { seteuid(getuid(this_player())); if(head) target = find_player(head); if(!target) target = present(head, environment(me)); seteuid(getuid(this_object())); if (target && me) { same_super = (environment(target) == environment(me)); } if (target && (wizardp(me) || same_super)) { rest = tail; if (!rest) rest = (string)this_player()->getenv(command); } else { target = 0; } } } if (target && living(target)) { if (!(verb = tentry[e_verb])) { verb = command; } verb2 = tentry[e_verb2]; do_emote(verb, verb2, rest, tentry, me, target, test, same_super); } else { if (!entry) { return 0; } if (!(verb = entry[e_verb])) { verb = command; } verb2 = entry[e_verb2]; do_emote(verb, verb2, rest, entry, me, target, test, same_super); } return 1; } varargs string return_emote(string verb, string verb2, string rest, mapping entry, object me, object target, int test, int same_super) { string result, *mods, *words, *values, *def; mods = copy_array(entry[e_modifier]); def = entry[e_me]; if (!def) { if (target) def = ({"N ", "V ", "M at ", "n"}); else def = ({"N ", "V ", "M"}); } if (def[0] != "X*empty") { result = substitute(verb, verb2, e_me, rest, copy_array(def), mods, me, target); result = punctuate(result); if (target && !same_super) result = "*" + result; if (test) write("me:\n" + result + "\n"); } if (target && (target != me)) { mods = copy_array(entry[e_modifier]); if (!(values = entry[e_target])) { values = entry[e_others]; if (!values) values = def; } if (values && (values[0] != "X*empty")) { result = substitute(verb, verb2, e_target, rest, copy_array(values), mods, me, target); result = punctuate(result); if (target && !same_super) result = "*" + result; if (test) write("target:\n" + result + "\n"); } } if (!target || same_super) { mods = copy_array(entry[e_modifier]); if (!(values = entry[e_others])) values = def; if (values) { result = substitute(verb, verb2, e_others, rest, copy_array(values), mods, me, target); result = punctuate(result); if (test) write("others:\n" + result + "\n"); } } return result; } varargs string return_parse(string command, string rest, int test) { string head, tail, verb, verb2; object target, me; mapping entry, tentry; int same_super; entry = emotes[command]; tentry = temotes[command]; same_super = 0; if (!rest) rest = (string)this_player()->getenv(command); if (!mapp(entry) && !mapp(tentry)) // not a recognized emote return 0; me = this_player(); if (rest && (sscanf(rest, "%s %s", head, tail) != 2)) { head = rest; tail = 0; } if (head) head = lower_case(head); if (rest) { if (mapp(tentry)) { seteuid(getuid(this_player())); if (head) target = find_player(head); if (!target) target = present(head, environment(me)); seteuid(getuid(this_object())); if (target) { same_super = 1; rest = tail; if (!rest) rest = (string)this_player()->getenv(command); } } } if (target && living(target)) { if (!(verb = tentry[e_verb])) verb = command; verb2 = tentry[e_verb2]; return return_emote(verb,verb2,rest,tentry,me,target,test,same_super); } else { if (!entry) return 0; if (!(verb = entry[e_verb])) verb = command; verb2 = entry[e_verb2]; return return_emote(verb,verb2,rest,entry,me,target,test,same_super); } }