tmi2_fluffos_v2/
tmi2_fluffos_v2/bin/
tmi2_fluffos_v2/etc/
tmi2_fluffos_v2/fluffos-2.7-ds2.018/
tmi2_fluffos_v2/fluffos-2.7-ds2.018/ChangeLog.old/
tmi2_fluffos_v2/fluffos-2.7-ds2.018/Win32/
tmi2_fluffos_v2/fluffos-2.7-ds2.018/compat/
tmi2_fluffos_v2/fluffos-2.7-ds2.018/compat/simuls/
tmi2_fluffos_v2/fluffos-2.7-ds2.018/include/
tmi2_fluffos_v2/fluffos-2.7-ds2.018/testsuite/
tmi2_fluffos_v2/fluffos-2.7-ds2.018/testsuite/clone/
tmi2_fluffos_v2/fluffos-2.7-ds2.018/testsuite/command/
tmi2_fluffos_v2/fluffos-2.7-ds2.018/testsuite/data/
tmi2_fluffos_v2/fluffos-2.7-ds2.018/testsuite/etc/
tmi2_fluffos_v2/fluffos-2.7-ds2.018/testsuite/include/
tmi2_fluffos_v2/fluffos-2.7-ds2.018/testsuite/inherit/
tmi2_fluffos_v2/fluffos-2.7-ds2.018/testsuite/inherit/master/
tmi2_fluffos_v2/fluffos-2.7-ds2.018/testsuite/log/
tmi2_fluffos_v2/fluffos-2.7-ds2.018/testsuite/single/
tmi2_fluffos_v2/fluffos-2.7-ds2.018/testsuite/single/tests/compiler/
tmi2_fluffos_v2/fluffos-2.7-ds2.018/testsuite/single/tests/efuns/
tmi2_fluffos_v2/fluffos-2.7-ds2.018/testsuite/single/tests/operators/
tmi2_fluffos_v2/fluffos-2.7-ds2.018/testsuite/u/
tmi2_fluffos_v2/fluffos-2.7-ds2.018/tmp/
tmi2_fluffos_v2/fluffos-2.7-ds2.018/windows/
tmi2_fluffos_v2/lib/
tmi2_fluffos_v2/lib/adm/
tmi2_fluffos_v2/lib/adm/daemons/languages/
tmi2_fluffos_v2/lib/adm/daemons/network/I3/
tmi2_fluffos_v2/lib/adm/daemons/virtual/
tmi2_fluffos_v2/lib/adm/daemons/virtual/template/
tmi2_fluffos_v2/lib/adm/news/
tmi2_fluffos_v2/lib/adm/obj/
tmi2_fluffos_v2/lib/adm/obj/master/
tmi2_fluffos_v2/lib/adm/priv/
tmi2_fluffos_v2/lib/adm/shell/
tmi2_fluffos_v2/lib/adm/tmp/
tmi2_fluffos_v2/lib/cmds/
tmi2_fluffos_v2/lib/d/
tmi2_fluffos_v2/lib/d/Conf/
tmi2_fluffos_v2/lib/d/Conf/adm/
tmi2_fluffos_v2/lib/d/Conf/boards/
tmi2_fluffos_v2/lib/d/Conf/cmds/
tmi2_fluffos_v2/lib/d/Conf/data/
tmi2_fluffos_v2/lib/d/Conf/logs/
tmi2_fluffos_v2/lib/d/Conf/obj/
tmi2_fluffos_v2/lib/d/Conf/text/help/
tmi2_fluffos_v2/lib/d/Fooland/adm/
tmi2_fluffos_v2/lib/d/Fooland/data/
tmi2_fluffos_v2/lib/d/Fooland/data/attic/
tmi2_fluffos_v2/lib/d/Fooland/items/
tmi2_fluffos_v2/lib/d/TMI/
tmi2_fluffos_v2/lib/d/TMI/adm/
tmi2_fluffos_v2/lib/d/TMI/boards/
tmi2_fluffos_v2/lib/d/TMI/data/
tmi2_fluffos_v2/lib/d/TMI/rooms/
tmi2_fluffos_v2/lib/d/grid/
tmi2_fluffos_v2/lib/d/grid/adm/
tmi2_fluffos_v2/lib/d/grid/data/
tmi2_fluffos_v2/lib/d/std/
tmi2_fluffos_v2/lib/d/std/adm/
tmi2_fluffos_v2/lib/data/adm/
tmi2_fluffos_v2/lib/data/adm/daemons/
tmi2_fluffos_v2/lib/data/adm/daemons/doc_d/
tmi2_fluffos_v2/lib/data/adm/daemons/emoted/
tmi2_fluffos_v2/lib/data/adm/daemons/network/http/
tmi2_fluffos_v2/lib/data/adm/daemons/network/services/mail_q/
tmi2_fluffos_v2/lib/data/adm/daemons/network/smtp/
tmi2_fluffos_v2/lib/data/adm/daemons/news/archives/
tmi2_fluffos_v2/lib/data/attic/connection/
tmi2_fluffos_v2/lib/data/attic/user/
tmi2_fluffos_v2/lib/data/std/connection/b/
tmi2_fluffos_v2/lib/data/std/connection/l/
tmi2_fluffos_v2/lib/data/std/user/a/
tmi2_fluffos_v2/lib/data/std/user/b/
tmi2_fluffos_v2/lib/data/std/user/d/
tmi2_fluffos_v2/lib/data/std/user/f/
tmi2_fluffos_v2/lib/data/std/user/l/
tmi2_fluffos_v2/lib/data/std/user/x/
tmi2_fluffos_v2/lib/data/u/d/dm/working/doc_d/
tmi2_fluffos_v2/lib/data/u/l/leto/doc_d/
tmi2_fluffos_v2/lib/data/u/l/leto/smtp/
tmi2_fluffos_v2/lib/doc/
tmi2_fluffos_v2/lib/doc/driverdoc/applies/
tmi2_fluffos_v2/lib/doc/driverdoc/applies/interactive/
tmi2_fluffos_v2/lib/doc/driverdoc/concepts/
tmi2_fluffos_v2/lib/doc/driverdoc/driver/
tmi2_fluffos_v2/lib/doc/driverdoc/efuns/arrays/
tmi2_fluffos_v2/lib/doc/driverdoc/efuns/buffers/
tmi2_fluffos_v2/lib/doc/driverdoc/efuns/compile/
tmi2_fluffos_v2/lib/doc/driverdoc/efuns/ed/
tmi2_fluffos_v2/lib/doc/driverdoc/efuns/filesystem/
tmi2_fluffos_v2/lib/doc/driverdoc/efuns/floats/
tmi2_fluffos_v2/lib/doc/driverdoc/efuns/functions/
tmi2_fluffos_v2/lib/doc/driverdoc/efuns/general/
tmi2_fluffos_v2/lib/doc/driverdoc/efuns/mappings/
tmi2_fluffos_v2/lib/doc/driverdoc/efuns/numbers/
tmi2_fluffos_v2/lib/doc/driverdoc/efuns/parsing/
tmi2_fluffos_v2/lib/doc/driverdoc/lpc/constructs/
tmi2_fluffos_v2/lib/doc/driverdoc/lpc/preprocessor/
tmi2_fluffos_v2/lib/doc/driverdoc/lpc/types/
tmi2_fluffos_v2/lib/doc/driverdoc/platforms/
tmi2_fluffos_v2/lib/doc/mudlib/
tmi2_fluffos_v2/lib/ftp/
tmi2_fluffos_v2/lib/include/driver/
tmi2_fluffos_v2/lib/log/
tmi2_fluffos_v2/lib/log/driver/
tmi2_fluffos_v2/lib/obj/net/
tmi2_fluffos_v2/lib/obj/shells/
tmi2_fluffos_v2/lib/obj/tools/
tmi2_fluffos_v2/lib/std/adt/
tmi2_fluffos_v2/lib/std/board/
tmi2_fluffos_v2/lib/std/body/
tmi2_fluffos_v2/lib/std/fun/
tmi2_fluffos_v2/lib/std/living/
tmi2_fluffos_v2/lib/std/object/
tmi2_fluffos_v2/lib/std/shop/
tmi2_fluffos_v2/lib/std/socket/
tmi2_fluffos_v2/lib/std/user/
tmi2_fluffos_v2/lib/std/virtual/
tmi2_fluffos_v2/lib/student/
tmi2_fluffos_v2/lib/student/kalypso/
tmi2_fluffos_v2/lib/student/kalypso/armor/
tmi2_fluffos_v2/lib/student/kalypso/rooms/
tmi2_fluffos_v2/lib/student/kalypso/weapons/
tmi2_fluffos_v2/lib/u/l/leto/
tmi2_fluffos_v2/lib/u/l/leto/cmds/
tmi2_fluffos_v2/lib/www/errors/
tmi2_fluffos_v2/lib/www/gateways/
tmi2_fluffos_v2/lib/www/images/
tmi2_fluffos_v2/old/
tmi2_fluffos_v2/win32/
#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);
    }
}