/* -*- LPC -*- */ /* * $Locker: presto $ * $Id: new_soul.c,v 1.30 2003/04/09 01:27:20 presto Exp presto $ */ /** * The soul handler for Discworld. Handles the soul definitions and * the mangling needed to print the output for the players. * * @author Pinkfish */ #include <player.h> #include <soul.h> #include <user_parser.h> #define SAVE_FILE "/save/soul" #define SOUL_DATA_DIR "/save/soul/data/" #define POS_SELF 0 #define POS_TARGET 1 #define POS_REST 2 #define PCACHE_MAX_SIZE 30 #define SCACHE_MAX_SIZE 100 #define CLEAN_UP_DELAY 300 /* * The soul driver itself... */ mixed soul_commands; mapping soul_command_names; nosave mapping pattern_cache; nosave mapping soul_cache; nosave string *pcache_order, *scache_order; nosave int scache_hits, scache_reads, pcache_hits, pcache_reads, cache_callout; void load_it(); void save_it(); void print_messages(string verb, mixed obs, string arg, string self, string rest, string target, string force, mapping position); protected void save_soul_command(string name, mixed *data); void create() { soul_commands = 0; soul_command_names = ([ ]); pattern_cache = ([ "" : NO_ARGUMENT ]); pcache_order = ({ }); scache_order = ({ }); soul_cache = ([ ]); seteuid("Room"); load_it(); } void clean_cache() { int i; for (i = 0; i < (sizeof(pcache_order) - PCACHE_MAX_SIZE); i++) { map_delete(pattern_cache, pcache_order[i]); } pcache_order = pcache_order[i..]; for (i = 0; i < (sizeof(scache_order) - SCACHE_MAX_SIZE); i++) { map_delete(soul_cache, scache_order[i]); } scache_order = scache_order[i..]; cache_callout = 0; } /** * Adds in a soul command. Only allows additions from * the soul compiler. * * @see /obj/handlers/soul_compiler.c * @param name the name of the soul command * @param data the data associated with the soul command */ void add_soul_command(string name, mixed data) { if (file_name(previous_object()) != SOUL_COMPILER) return; save_soul_command(name, data); map_delete(soul_cache, name); save_it(); } /** * Deletes the soul command. This is used to remove soul commands * that are no longer used. * * @param name the soul command name to delete */ void delete_soul_command(string name) { map_delete(soul_cache, name); map_delete(soul_command_names, name); unguarded((: rm, SOUL_DATA_DIR + name + ".os" :)); save_it(); } /** * The name of all the soul commands. * * @return an array containing the names of all the soul commands */ string *query_soul_commands() { return keys(soul_command_names); } /** * Used internally to get the soul command data. * * @param str the soul command to get data for * @return the soul command data * @see query_soul_command_stuff() */ protected mixed *query_soul_command_data(string str) { scache_reads++; /* This function will load in the rubbish from the disk. */ if (!soul_cache[str] && soul_command_names[str]) { string tmp; tmp = unguarded((: read_file, SOUL_DATA_DIR + str + ".os" :)); soul_cache[str] = restore_variable(tmp); if (!cache_callout && (sizeof(scache_order) > SCACHE_MAX_SIZE)) cache_callout = call_out("clean_cache", CLEAN_UP_DELAY); } else { scache_order -= ({ str }); scache_hits++; } scache_order += ({ str }); return soul_cache[str]; } /** * Returns the data associated with soul command. * Probably not very useful, but useful for debugging. * * @param str the soul command to get the data for * @return the data associated with the soul command */ mixed *query_soul_command_stuff(string str) { return query_soul_command_data(str) + ({ }); } /** * @ignore yes */ protected void save_soul_command(string name, mixed *data) { string str; str = save_variable(data); unguarded((: rm, SOUL_DATA_DIR + name + ".os" :)); unguarded((: write_file, SOUL_DATA_DIR + name + ".os", str :)); soul_command_names[name] = 1; } /** * Saves the current state of the soul object. */ void save_it() { unguarded((: save_object, SAVE_FILE :)); } /** * Loads the previous state of the soul object off the disc. */ void load_it() { string *names; int i; unguarded((: restore_object, SAVE_FILE :)); if (mapp(soul_commands)) { /* Ok, we convert it to the new format... */ soul_command_names = ([ ]); names = keys(soul_commands); for (i = 0; i < sizeof(names); i++) { reset_eval_cost(); save_soul_command(names[i], soul_commands[names[i]]); } soul_commands = 0; save_it(); } } private mixed create_pattern_cache(string pattern) { mixed *bing, ret; string s1, s2; bing = explode("#" + pattern, "<indirect:"); if (sizeof(bing) == 1) if (sscanf(bing[0], "%s<word>%s", s1, s2) || sscanf(bing[0], "%s<string>%s", s1, s2)) ret = ONLY_ARGUMENT; else ret = NO_ARGUMENT; else if (sscanf(bing[0], "%s<word>%s", s1, s2) || sscanf(bing[0], "%s<string>%s", s1, s2)) ret = ARGUMENT_FIRST; else if (sscanf(bing[1], "%s<word>%s", s1, s2) || sscanf(bing[1], "%s<string>%s", s1, s2)) ret = ARGUMENT_SECOND; else ret = ONLY_TARGET; return ret; } /** * This returns the arrays that are used by the pattern * matcher in the player object. Called from inside add_command interface. * * @param name the souul command name to find * @return 0 if no command found, otherwise an array of patterns * @see /global/new_parse->add_command() */ mixed *query_soul_command(string name) { mixed *data; mixed *ret; string pat; int i; if (!soul_command_names[name]) { return 0; } data = query_soul_command_data(name); if (!data) { return 0; } ret = ({ ({ ({ }), "", 0, this_object(), 0 }) }); for (i = 0; i < sizeof(data[PATTERNS]); i++) { pat = data[PATTERNS][i]; pcache_reads++; if (!pattern_cache[pat]) { pattern_cache[pat] = create_pattern_cache(pat); if (!cache_callout && sizeof(pcache_order) > PCACHE_MAX_SIZE) { cache_callout = call_out("clean_cache", CLEAN_UP_DELAY); } } else { pcache_hits++; pcache_order -= ({ pat }); } pcache_order += ({ pat }); ret += ({ ({ ((mixed *) PATTERN_OB->query_pattern(pat))[1], pat, 0, this_object(), 0 }) }); } return ret; } /** * The main soul handling bit. This is called by the add_command code * when a soul command is matched. * * @param verb the verb matched * @param obs the objects to do the soul command on * @param in_dir_match the name which was matched for the peoples names * @param args the values of the string and stuff * @param pattern the pattern which was matched. * @return 1 if the command succeeded, 0 if it failed */ int command_control(string verb, object * obs, string, string in_dir_match, string *args, string pattern) { int i; int j; string arg; mixed *stuff; object *wom; object *rem; mixed *data; if (!soul_command_names[verb]) { return 0; } if (pattern != "") { stuff = PATTERN_OB->query_pattern(pattern); for (i = 1; i < sizeof(stuff); i++) { switch (stuff[i]) { case INDIRECT_OBJECT: /* Ok, in here we check for remote and multiple soul earmuffs... */ i += 2; wom = obs; if (previous_object()->query_property("no soul")) { previous_object()->add_failed_mess(this_object(), "You cannot use directed souls.\n", ({ })); return 0; } // check for ignoring people if ((sizeof(obs) == 1) && !previous_object()->query_creator() && obs[0]->query_property("ignoring") && member_array((string) previous_object()->query_name(), (string *)obs[0]->query_property("ignoring")) != -1) { return 0; } /* prevent multiple souls to people with multiple-soul earmuffed or * creators who are invis */ if (sizeof(obs) > 1) { obs = filter(obs, (: !$1->check_earmuffs("multiple-soul") :)); if (!sizeof(obs)) { previous_object()->add_failed_mess(this_object(), "Everyone seems to have their multiple souls earmuffed. " "I'm depressed, are you depressed?\n", ({ })); return 0; } } /* * prevent remote souls to npcs, to people you cant see and to * people who are role-playing and not in your environment */ rem = filter(obs, (: (!interactive($1) && environment(previous_object(1)) != environment($1)) || //!$1->query_visible(previous_object(1)) || (interactive($1) && $1->query_role_playing() && environment($1) != environment(previous_object(1))) :)); obs -= rem; obs -= previous_object()->query_ignoring(obs); /* * people who are roleplaying cannot use remote souls or souls to * people they don't know. */ if(previous_object()->query_role_playing()) obs -= filter(obs, (: environment($1) != environment(previous_object(1)) || (interactive($1) && !previous_object(1)->is_friend($1->query_name())) :)); if (!sizeof(obs)) { return 0; } if (previous_object()->check_earmuffs("remote-soul")) { if (previous_object()->query_earmuffs() == PLAYER_ALLOW_FRIENDS_EARMUFF) { rem = filter(obs, (: environment(previous_object(1)) != environment($1) && !previous_object(1)->is_friend($1->query_name()) :)); } else { rem = filter(obs, (: environment(previous_object(1)) != environment($1) :)); } if (sizeof(rem) == sizeof(obs)) { previous_object()->add_failed_mess(this_object(), "You cannot do a remote soul when you have remote souls " "earmuffed.\n", ({ })); return 0; } obs = obs - rem; } else { obs = filter(obs, (: !$1->check_earmuffs("remote-soul") || (environment(previous_object(1)) == environment($1)) :)); if (!sizeof(obs)) { previous_object()->add_failed_mess(this_object(), "Remote soul earmuffs enabled for $I.\n", wom); return 0; } } j++; break; case STRING: case SINGLE_WORD: case SHORT_STRING: arg = args[j++]; break; case NUMBER: j++; break; case FRACTION: j += 2; break; case OPTIONAL: case OPTIONAL_SPACES: i++; break; case WORD_LIST: case WORD_LIST_SPACES: i++; if (pointerp(stuff[i]) && sizeof(stuff[i]) > 1) j++; break; } } } /* * Ok. We have this soul command. Lets find out what sort of * pattern we have */ if (!pattern_cache[pattern]) { return 0; } if (!previous_object()->query_creator()) { if ((int) previous_object()->adjust_sp(-SOUL_COST * (1 + sizeof(obs))) < 0) { previous_object()->add_failed_mess(this_object(), NO_POWER, ({ })); return 0; } } data = query_soul_command_data(verb); switch (pattern_cache[pattern]) { case NO_ARGUMENT: /* * This case. Means we try the no_argument thing first. Otherwise * we pick the first argument one and use that. */ if (data[SINGLE]) if (data[SINGLE][NO_ARGUMENTS]) { if (sizeof(data[SINGLE][NO_ARGUMENTS]) > POSITION_SINGLE) { print_messages(verb, 0, "", data[SINGLE][NO_ARGUMENTS][SELF], data[SINGLE][NO_ARGUMENTS][REST], 0, 0, data[SINGLE][NO_ARGUMENTS][POSITION_SINGLE]); } else { print_messages(verb, 0, "", data[SINGLE][NO_ARGUMENTS][SELF], data[SINGLE][NO_ARGUMENTS][REST], 0, 0, 0); } return 1; } else { if (!data[SINGLE][ARGUMENTS]) return 0; arg = data[SINGLE][ARGUMENTS][ARGS][0]; } else return 0; case ONLY_ARGUMENT: if (arg == "?") { /* Find a random arguement... */ j = 0; for (i = 0; i < sizeof(data[SINGLE][ARGUMENTS]); i += SMALL_ARG_SIZE) j += sizeof(data[SINGLE][ARGUMENTS][i + ARGS]); j = random(j); for (i = 0; i < sizeof(data[SINGLE][ARGUMENTS]); i += SMALL_ARG_SIZE) if (j < sizeof(data[SINGLE][ARGUMENTS][i + ARGS])) { if (data[SINGLE][ARGUMENTS][i + ARGS][j] == "#") { if (j > 0) j--; else { j++; if (j >= sizeof(data[SINGLE][ARGUMENTS][i + ARGS])) { j -= sizeof(data[SINGLE][ARGUMENTS][i + ARGS]); continue; } } } print_messages(verb, 0, data[SINGLE][ARGUMENTS][i + ARGS][j], data[SINGLE][ARGUMENTS][i + SELF], data[SINGLE][ARGUMENTS][i + REST], 0, 0, data[SINGLE][ARGUMENTS][i + POSITION_SINGLE]); return 1; } else { j -= sizeof(data[SINGLE][ARGUMENTS][i + ARGS]); } } /* Ok, now to find the argument... */ for (i = 0; i < sizeof(data[SINGLE][ARGUMENTS]); i += SMALL_ARG_SIZE) { if ((j = member_array(arg, data[SINGLE][ARGUMENTS][i + ARGS], 0, 1)) != -1) { /* Found... */ print_messages(verb, 0, data[SINGLE][ARGUMENTS][i + ARGS][j], data[SINGLE][ARGUMENTS][i + SELF], data[SINGLE][ARGUMENTS][i + REST], 0, 0, data[SINGLE][ARGUMENTS][i + POSITION_SINGLE]); return 1; } } /* No argument. SO we check for a wildcard */ for (i = 0; i < sizeof(data[SINGLE][ARGUMENTS]); i += SMALL_ARG_SIZE) if ((j = member_array("#", data[SINGLE][ARGUMENTS][i + ARGS], 0, 1)) != -1) { /* Found... */ print_messages(verb, 0, arg, data[SINGLE][ARGUMENTS][i + SELF], data[SINGLE][ARGUMENTS][i + REST], 0, 0, data[SINGLE][ARGUMENTS][i + POSITION_SINGLE]); return 1; } /* No argument found... */ previous_object()->add_failed_mess(this_object(), arg + " is not a valid argument to the soul " "command \"" + verb + "\".\n", ({ })); return 0; case ARGUMENT_FIRST: case ARGUMENT_SECOND: break; case ONLY_TARGET: if (data[TARGET][NO_ARGUMENTS]) { obs->event_soul_command(this_object(), verb, previous_object(), in_dir_match, 0); print_messages(verb, obs, "", data[TARGET][NO_ARGUMENTS][SELF], data[TARGET][NO_ARGUMENTS][REST], data[TARGET][NO_ARGUMENTS][TARGET], data[TARGET][NO_ARGUMENTS][FORCE], data[TARGET][NO_ARGUMENTS][POSITION]); return 1; } /* Ok. Now, we return 0 if there is no argument one */ if (!data[TARGET][ARGUMENTS]) { return 0; } arg = data[TARGET][ARGUMENTS][ARGS][0]; break; } if (arg == "?") { /* Find a random argument... */ j = 0; for (i = 0; i < sizeof(data[TARGET][ARGUMENTS]); i += ARG_SIZE) { j += sizeof(data[TARGET][ARGUMENTS][i + ARGS]); } j = random(j); for (i = 0; i < sizeof(data[TARGET][ARGUMENTS]); i += ARG_SIZE) { if (j < sizeof(data[TARGET][ARGUMENTS][i + ARGS])) { if (data[TARGET][ARGUMENTS][i + ARGS][j] == "#") { if (j > 0) { j--; } else { j++; if (j >= sizeof(data[TARGET][ARGUMENTS][i + ARGS])) { j -= sizeof(data[TARGET][ARGUMENTS][i + ARGS]); continue; } } } obs->event_soul_command(this_object(), verb, previous_object(), in_dir_match, arg); print_messages(verb, obs, data[TARGET][ARGUMENTS][i + ARGS][j], data[TARGET][ARGUMENTS][i + SELF], data[TARGET][ARGUMENTS][i + REST], data[TARGET][ARGUMENTS][i + TARGET], data[TARGET][ARGUMENTS][i + FORCE], data[TARGET][ARGUMENTS][i + POSITION]); return 1; } else { j -= sizeof(data[TARGET][ARGUMENTS][i + ARGS]); } } } for (i = 0; i < sizeof(data[TARGET][ARGUMENTS]); i += ARG_SIZE) { if ((j = member_array(arg, data[TARGET][ARGUMENTS][i + ARGS], 0, 1)) != -1) { /* Found... */ obs->event_soul_command(this_object(), verb, previous_object(), in_dir_match, arg); print_messages(verb, obs, data[TARGET][ARGUMENTS][i + ARGS][j], data[TARGET][ARGUMENTS][i + SELF], data[TARGET][ARGUMENTS][i + REST], data[TARGET][ARGUMENTS][i + TARGET], data[TARGET][ARGUMENTS][i + FORCE], data[TARGET][ARGUMENTS][i + POSITION]); return 1; } } /* No argument found. Check for wildcard */ for (i = 0; i < sizeof(data[TARGET][ARGUMENTS]); i += ARG_SIZE) { if ((j = member_array("#", data[TARGET][ARGUMENTS][i + ARGS], 0, 1)) != -1) { /* Found... */ obs->event_soul_command(this_object(), verb, previous_object(), in_dir_match, arg); print_messages(verb, obs, arg, data[TARGET][ARGUMENTS][i + SELF], data[TARGET][ARGUMENTS][i + REST], data[TARGET][ARGUMENTS][i + TARGET], data[TARGET][ARGUMENTS][i + FORCE], data[TARGET][ARGUMENTS][i + POSITION]); return 1; } } /* No argument found... */ return 0; } string get_name(object ob, int use_name, int type) { if(ob == previous_object()) return ob->query_objective() + "self"; if(userp(ob) && use_name && environment(ob) != environment(previous_object())) return "$mirror_short:" + file_name(ob) + "$"; return ob->one_short(use_name); } private string create_message(mixed targets, string args, string pattern, int type, string verb, string position, string actor_position, mixed me, int use_name) { string *bits; string *rabbit; string singular; string plural; int i; int word_break; if(arrayp(targets) && sizeof(targets) == 1) targets = targets[0]; //if (previous_object() == find_player("presto")) //tell_creator("presto", "pattern == %s, verb = %s, type == %d, use_name == %d\n", pattern, verb, type, use_name); if (stringp(verb) && type && (sizeof(explode(pattern, "$V$")) < 2)) { if (pointerp(targets) && sizeof(targets) > 0) { pattern = replace_string(pattern, pluralize(verb), "$V$1=" + pluralize(verb) + "," + verb + "$V$"); } else { pattern = replace_string(pattern, pluralize(verb), "$V$0=" + pluralize(verb) + "," + verb + "$V$"); } } if(pattern) { pattern = replace_string(pattern, "$V$", "VERBFROG"); bits = explode("%" + replace(pattern, ({ "$arg$", args })), "$"); } if (!me) { me = previous_object(); } //if (me == find_player("presto")) //tell_creator("presto", "%O\n", bits); for (i = 1; i < sizeof(bits); i += 2) { switch (bits[i]) { case "article": if (vowel(args[0])) { bits[i] = "an"; } else { bits[i] = "a"; } break; case "hcname": if (stringp(targets)) { bits[i] = targets; break; } if (objectp(targets)) { if ((targets == me)) { if (type) { bits[i] = (string) targets->query_objective() + "self"; } else { bits[i] = "yourself"; } } else { bits[i] = (string) get_name(targets, use_name, type); } break; } if(arrayp(targets)) { bits[i] = "$M$" + implode(map(targets, (: get_name :), use_name, type), "") + "$M$"; } break; case "mhcname": /* Stoopid stuff could be revised at some point, if done nicely. */ if (stringp(targets)) { bits[i] = targets + "'s"; /* This will look really stoopid. */ break; } if (objectp(targets)) { if ((targets == me)) if (type) bits[i] = (string) targets->query_possessive(); else bits[i] = "your"; else bits[i] = (string) targets->the_poss_short(); break; } /* This will look really stoopid. */ bits[i] = "$M$" + implode(map(targets, (: objectp($1) ? $1->the_poss_short($(use_name)) : $1 + "'s" :)), "") + "$M$"; break; case "hposs": if (objectp(targets)) bits[i] = (string) targets->query_possessive(); else bits[i] = "their"; break; case "hpronoun": if (objectp(targets)) bits[i] = (string) targets->query_pronoun(); else bits[i] = "they"; break; case "hobj": if (objectp(targets)) bits[i] = (string) targets->query_objective(); else bits[i] = "them"; break; case "mcname": if(stringp(me)) bits[i] = me; else if (me != previous_object()) { /* Must be from the help... */ bits[i] = (string) me->short(0, 0); } else if(userp(me) && use_name) { bits[i] = me->short(0, 0); } else bits[i] = me->the_short(); break; case "mposs": if (type && objectp(me)) { bits[i] = (string) me->query_possessive(); } else { bits[i] = "your"; } break; case "mpronoun": bits[i] = (string) me->query_pronoun(); break; case "mobj": if(objectp(me)) bits[i] = (string) me->query_objective(); else bits[i] = "you"; break; case "position": if (position) { rabbit = explode("%" + position, "$"); rabbit[0] = rabbit[0][1..]; /* Make sure the size is even... */ if ((sizeof(rabbit) % 2) == 1) { rabbit += ({ "" }); } bits = bits[0..i] + rabbit + bits[i + 1..]; } bits[i] = ""; break; case "aposition": if (actor_position) { rabbit = explode("%" + actor_position, "$"); rabbit[0] = rabbit[0][1..]; /* Make sure the size is even... */ if ((sizeof(rabbit) % 2) == 1) { rabbit += ({ "" }); } bits = bits[0..i] + rabbit + bits[i + 1..]; } bits[i] = ""; break; case "s": if (i == 0) break; word_break = strsrch(bits[i - 1], ' ', -1); if (word_break == -1) break; if (me == previous_object()) { /* Not from 'help' */ if (use_name) bits[i] = pluralize(bits[i - 1][word_break + 1 .. ]); else { if (pointerp(targets) && sizeof(targets) > 0) bits[i] = "$V$1="; else bits[i] = "$V$0="; bits[i] += pluralize(bits[i - 1][word_break + 1 .. ]) + "," + bits[i - 1][word_break + 1 .. ] + "$V$"; } bits[i - 1] = bits[i - 1][0 .. word_break]; } break; case "verb": if (i + 1 < sizeof(bits)) { if (sscanf(bits[i + 1], "%s,%s", singular, plural) == 2) { if (me == previous_object()) { if (use_name) bits[i] = singular; else { if (pointerp(targets) && sizeof(targets) > 0) bits[i] = "$V$1="; else bits[i] = "$V$0="; bits[i] += singular + "," + plural + "$V$"; } } else bits[i] = singular; bits = bits[0 .. i] + bits[i + 2 .. ]; } } break; case "dollar": bits[i] = "$"; break; } } pattern = implode(bits, "")[1..] + "\n"; pattern = replace_string(pattern, "VERBFROG", "$V$"); //if (me == find_player("presto")) tell_creator("presto", "pattern == %s\n", pattern); return pattern; } private string position_command(mixed bing) { if (stringp(bing)) { return bing; } if (mapp(bing)) { return bing["cmd"]; } return 0; } private void do_position_stuff(object ob, mapping position) { string cur_pos; string new_pos; /* Ok, the position stuff... */ if (position) { cur_pos = ob->query_position(); if (position[cur_pos]) { /* Ok, do it... */ new_pos = position_command(position[cur_pos]); } else if (position["default"]) { new_pos = position_command(position["default"]); } if (new_pos && new_pos != "ignore" && !ob->query_cannot_change_position() && ("/cmds/living/" + new_pos)->query_position_command()) { ("/cmds/living/" + new_pos)->position(ob, position["silent"]); } } } private string *position_string(object ob, mapping position, int) { string *str; string cur_pos; mixed new_pos; str = ({ 0, 0, 0 }); if (position) { cur_pos = ob->query_position(); if (position[cur_pos]) { new_pos = position[cur_pos]; } else if (position["default"]) { new_pos = position["default"]; } if (mapp(new_pos)) { return ({ new_pos["self"], new_pos["target"], new_pos["rest"] }); } if (new_pos && new_pos != "ignore" && !ob->query_cannot_change_position() && ("/cmds/living/" + new_pos)->query_position_command()) { str = ({ " making you " + new_pos + " " + ("/cmds/living/" + new_pos)->query_up_down(), " making $hobj$ " + new_pos + " " + ("/cmds/living/" + new_pos)->query_up_down(), " making $hobj$ " + new_pos + " " + ("/cmds/living/" + new_pos)->query_up_down() }); } } return str; } private string position_of(object ob, mapping position) { string tmp; tmp = ob->query_position(); if (position[tmp]) { tmp = position_command(position[tmp]); if (tmp) { return tmp; } } if (position["default"]) { tmp = position_command(position["default"]); if (tmp) { return tmp; } } return ""; } private string env_position_of(object ob, mapping position) { return file_name(ob->query_current_room()) + position_of(ob, position); } private void print_messages(string verb, mixed obs, string arg, string self, string rest, string target, string force, mapping position) { object *here, *targ; string *pos_stuff, *actor_pos_stuff; if(!obs) obs = ({ }); if(!position) position = ([ ]); switch(sizeof(obs)) { case 0: pos_stuff = position_string(previous_object(), position, 0); actor_pos_stuff = ({ "", "", ""}); // Change positions. do_position_stuff(previous_object(), position); break; case 1: pos_stuff = position_string(obs[0], position, 0); actor_pos_stuff = position_string(previous_object(), position["actor"], 0); // Change positions do_position_stuff(obs[0], position); if (position && position["actor"]) do_position_stuff(previous_object(), position["actor"]); break; default: actor_pos_stuff = position_string(previous_object(), position["actor"], 0); pos_stuff = ({ "", "", "" }); // Change positions. if (position && position["actor"]) do_position_stuff(previous_object(), position["actor"]); } here = filter(obs, (: environment(previous_object(1)) == environment($1) :)); targ = obs - here - ({ previous_object() }); //if (previous_object() == find_player("presto")) tell_creator("presto", "targ == %O, p_o == %O\n", targ, previous_object(1)->short()); if(!sizeof(obs) || sizeof(here)) previous_object()->remove_hide_invis("hiding"); // Souler. This is used if the souler isn't a target. if(member_array(previous_object(), obs) == -1) { previous_object()->event_soul(previous_object(), create_message(obs, arg, self, 0, 0, pos_stuff[POS_TARGET], actor_pos_stuff[POS_TARGET], 0, 1), ({ }), verb, arg, 0); } else { // Remove ourselves if this is a multiple soul, otherwise keep ourselves // in it. if(sizeof(obs) > 1) obs -= ({ previous_object() }); previous_object()->event_soul(previous_object(), create_message(obs, arg, self, 0, 0, pos_stuff[POS_SELF], actor_pos_stuff[POS_SELF], 0, 1), ({ }), verb, arg, 0); } // Convert arg to 3rd person. if(arg) arg = replace(arg, ({ "yourself", previous_object()->query_objective() + "self", "your", previous_object()->query_possessive() })); // Remote targets if(sizeof(targ)) { /* * This is so that souls to multiple remote targets will show up as * "Womble bings happily at you and Cabbage". */ target = replace(target, ({ " you.", " $hcname$.", " you ", " $hcname$ ", " you!", " $hcname$!", " your ", " $mhcname$ " })); targ->event_soul(previous_object(), create_message(obs, arg, target, 1, 0, pos_stuff[POS_SELF], actor_pos_stuff[POS_TARGET], 0, 1), ({ }), verb, arg, 0); } // Strip the souler. obs -= ({ previous_object() }); // Spectators and local targets (except the souler) if(!sizeof(obs) || sizeof(here)) { if(sizeof(here) > 1) here -= ({ previous_object() }); if(environment(previous_object())) event(environment(previous_object()), "soul", create_message(here, arg, rest, 1, 0, pos_stuff[POS_REST], actor_pos_stuff[POS_REST], 0, 0), ({ previous_object() }) + targ, verb, arg, sizeof(here)>=1?here[0]:0); } #ifdef DISABLED // Do soul forces. if(sizeof(obs) && stringp(force)) { force = replace(force, "$mcname$", previous_object()->query_name()); foreach(ob in obs) call_out("do_force", 2, ({ ob, force })); } #endif } /** * @ignore yes */ string add_start(string pat, string verb) { return verb + " " + pat; } /** * The list of soul comands in the look at soul function. * * @return the list of all the soul commands formated for the screen */ string help_list() { return "$P$Soul$P$The commands available in this soul currently number " + sizeof(soul_command_names) + ".\nHere is a nice list of them.\nGood luck!\n" + sprintf("%-#*s\n\n", (int) this_player()->query_cols(), implode(sort_array(keys(soul_command_names), 1), "\n")); } /** * Returns the help string for the soul ocmmand. Creates a nice helkp * message for the passed soul command. * * @param verb the soul command to get help on * @return the soul command help string */ string help_string(string verb) { string ret, arg; int i; mixed target; mixed *data; if (!soul_command_names[verb]) return 0; data = query_soul_command_data(verb); ret = sprintf("Allowed command patterns:\n%-#*s\n\n", (int) this_player()->query_cols(), implode(map_array(data[PATTERNS], "add_start", this_object(), verb), "\n")); if (data[SINGLE]) { if (data[SINGLE][NO_ARGUMENTS]) { ret += "Has a no arguments mode.\nSelf: " + create_message(0, "", data[SINGLE][NO_ARGUMENTS][SELF], 0, 0, 0, 0, this_player(), 0) + "Others: " + create_message(0, "", data[SINGLE][NO_ARGUMENTS][REST], 1, 0, 0, 0, this_player(), 0) + "\n"; } if (data[SINGLE][ARGUMENTS]) { for (i = 0; i < sizeof(data[SINGLE][ARGUMENTS]); i += SMALL_ARG_SIZE) { arg = data[SINGLE][ARGUMENTS][i + ARGS][0]; ret += sprintf("For the arguments: [%-=*s", (int) this_player()->query_cols() - 20, implode(data[SINGLE][ARGUMENTS][i + ARGS], ", ") + "]") + "\nSelf: " + create_message(0, arg, data[SINGLE][ARGUMENTS][i + SELF], 0, 0, 0, 0, this_player(), 0) + "Others: " + create_message(0, arg, data[SINGLE][ARGUMENTS][i + REST], 1, 0, 0, 0, this_player(), 0) + "\n"; } } } if (data[TARGET]) { target = query_multiple_short(({ "Womble", "Cabbage" })); if (data[TARGET][NO_ARGUMENTS]) { ret += "Has a no arguments, targeted mode.\nSelf: " + create_message(target, "", data[TARGET][NO_ARGUMENTS][SELF], 0, 0, 0, 0, this_player(), 0) + "Target: " + (data[TARGET][NO_ARGUMENTS][TARGET] ? create_message(target, "", data[TARGET][NO_ARGUMENTS][TARGET], 2, 0, 0, 0, this_player(), 0) : create_message(target, "", data[TARGET][NO_ARGUMENTS][REST], 1, 0, 0, 0,this_player(), 0)) + "Others: " + create_message(target, "", data[TARGET][NO_ARGUMENTS][REST], 1, 0, 0, 0, this_player(), 0) + "\n"; } if (data[TARGET][ARGUMENTS]) { for (i = 0; i < sizeof(data[TARGET][ARGUMENTS]); i += ARG_SIZE) { arg = data[TARGET][ARGUMENTS][i + ARGS][0]; ret += sprintf("For the arguments: [%-=*s", (int) this_player()->query_cols() - 20, implode(data[TARGET][ARGUMENTS][i + ARGS], ", ") + "]") + "\nSelf: " + create_message(target, arg, data[TARGET][ARGUMENTS][i + SELF], 0, 0, 0, 0, this_player(), 0) + "Target: " + (data[TARGET][ARGUMENTS][TARGET + i] ? create_message(target, arg, data[TARGET][ARGUMENTS][i + TARGET], 2, 0, 0, 0, this_player(), 0) : create_message(target, arg,data[TARGET][ARGUMENTS][i + REST], 1, 0, 0, 0,this_player(), 0)) + "Others: " + create_message(target, arg, data[TARGET][ARGUMENTS][i + REST], 1, 0, 0, 0, this_player(), 0); } } } return this_player()->convert_message(ret); } /** * Attempts to do the force on the player. * @param arr the args used to force */ void do_force(mixed *arr) { string cmd; cmd = explode(arr[1], " ")[0]; /* Only allow them to use soul commands on the force... */ if (soul_command_names[cmd] && !arr[0]->query_property("dead") && userp(arr[0])) arr[0]->eventForce(arr[1]); } int query_pcache_size() { return sizeof(keys(pattern_cache)); } int query_scache_size() { return sizeof(keys(soul_cache)); } mixed *stats() { return ({ ({ "souls read", scache_reads, }), ({ "soul cache hit percent", (scache_hits * 100) / scache_reads, }), ({ "souls in cache", sizeof(keys(soul_cache)), }), ({ "patterns read", pcache_reads, }), ({ "pattern cache hit percent", (pcache_hits * 100) / pcache_reads, }), ({ "patterns in cache", sizeof(keys(pattern_cache)) - 1, }), }); }