/* * add_command: * This handles all the cute multiple object parseing stuff. It is the * bit which handles the add_action like things done from all the objects * for things such as read and so on. */ static mapping commands, cur_objects; static mixed *suc_indir; string create_string(string pattern, mixed *args, int d, int e, string s1, string s2); void create() { commands = ([ ]); cur_objects = ([ ]); } mapping query_p_commands() { return commands; } mapping query_p_objects() { return cur_objects; } /* * this is called by the object the command is being passed on to find * whether or not it succeeded on the objects it was passed... and which * ones. This can be passed an object.. or an array of objects. * Share and enjoy. */ int add_succeeded(mixed ob) { int i; if (objectp(ob)) if (member_array(ob, suc_indir) == -1) suc_indir += ({ ob }); else return 1; else if (!pointerp(ob)) return 0; else for (i=0;i<sizeof(ob);i++) if (member_array(ob[i], suc_indir) == -1) suc_indir += ({ ob[i] }); return 1; } /* * this adds a clever command to the object. * Horror stuff, these clever commands, but they dfo a lot of the work * for you which is why they were added. * For an example look at /std/liquid */ int add_command(string command, object ob, mixed format) { int j; /* * Set up the format how we want it handled. You can put an array of * format strings to this function. */ if (!format) format = ({ "%D" }); if (stringp(format)) format = ({ format }); if (!pointerp(format)) return 0; /* check to see if the command exists in the command array */ if (commands[command]) { for (j=0;j<sizeof(format);j++) if (commands[command][format[j]]) { if (member_array(ob, commands[command][format[j]]) == -1) commands[command][format[j]] += ({ ob }); } else commands[command][format[j]] = ({ ob }); /* * put the object in the fast find object array. This is done for the * entering and exiting of objects from the players environment. */ if (cur_objects[ob]) cur_objects[ob] += ({ command }); else cur_objects[ob] = ({ command }); return 1; } /* New command not yet added. */ commands[command] = ([ ]); for (j=0;j<sizeof(format);j++) commands[command][format[j]] = ({ ob }); /* Add it to our fast find object list */ if (cur_objects[ob]) cur_objects[ob] += ({ command }); else cur_objects[ob] = ({ command }); return 1; } /* * This is the bit that handles object leaving the environment of the * player. */ int remove_object(mixed ob) { if (objectp(ob) && !cur_objects[ob]) return 0; /* called out for umm, eval reasons. */ call_out("remove_object2", 0, ob); return 1; } /* * The bit that does all the horrible work... */ int remove_object2(mixed ob) { string ind, *bing; int i, j; /* Handle arrays. */ if (pointerp(ob)) return sizeof(filter_array(ob, "remove_object2", this_object())); /* Check to see if our illustious object exists or not. */ if (!cur_objects[ob]) return 0; for (i=0;i<sizeof(cur_objects[ob]);i++) if (commands[(ind=cur_objects[ob][i])]) { /* * Go through all the formats one bye one. Deleteing both this object and * any dested ones it runs accross. */ bing = m_indices(commands[ind]); for (j=0;j<sizeof(bing);j++) if (!sizeof((commands[ind][bing[j]] -= ({ 0, ob })))) commands[ind] = m_delete(commands[ind], bing[j]); /* Check to see if after deleteion of formats if the entire command goes */ if (!m_sizeof(commands[ind])) commands = m_delete(commands, ind); } /* Delete the object from the object table */ cur_objects = m_delete(cur_objects, ob); return 1; } /* The dest event :) */ void event_dest_me(object ob) { /* * Don't call this out as otherwise we end up with a 0 which may mess up * the mapping a bit. */ if (!cur_objects[ob]) return ; remove_object2(ob); } /* * Handle leaving. Check to see if it is me leaving. If it is, then * remove all the objects from the inventory. */ void event_exit(object ob, string mess, object dest, object *ignore) { if (dest == this_object() || dest == environment()) return ; remove_object(ob); } void me_moveing(object from) { /* Use this so as to get the hidden objects as well. */ if (from) remove_object((object *)from->find_inv_match()); } /* This is the bit that is add_actioned and does the grunt work */ int parse_comm(string str) { int retval; mixed *dir, *indir; mixed *args, m; string s; string pattern; string verb, noti; string s1, s2, *bing; int j, q; int iI, iD; mixed *bity; /* First split out the verb from the rest of the string */ if (sscanf(str, "%s %s", verb, str) != 2) { verb = str; str = 0; } /* check to see if the command exists. */ if (!commands[verb]) return 0; /* Set the the succeeded indirect objects to be the empty set */ suc_indir = ({ }); notify_fail(capitalize(verb) + " what?\n"); /* * You need to have some arguments, these things only work with object * references... */ noti = ""; if (!str || str == "") return 0; /* Get the list of formats to check */ bing = m_indices(commands[verb]); for (q=0;q<sizeof(bing);q++) { /* Set the args to all null values */ args = ({ 0, 0, 0, 0, 0, }); /* * Split the pattern up to get the %D and %I positions and substitute them * for %s's in the format string. */ pattern = implode((dir = explode("&"+bing[q]+"&", "%D")), "%s"); pattern = implode((indir = explode(pattern, "%I")), "%s"); pattern = pattern[1..strlen(pattern)-2]; /* Do the parse_command check. */ if (!parse_command(str, environment(this_player()), pattern, args[0], args[1], args[2], args[3], args[4])) { noti += "Syntax: "+verb+" "+replace(bing[q], ({ "%p", "<prep>", "%I", "<object>", "%D", "<object>", "'", "" }))+"\n"; continue; } iI = iD = 0; /* * Figure out the postion of the %D and the %I in the string, and check to see * if the returned args actually match some objects, fail if they do not. */ if (sizeof(dir) > 1) dir = find_match((s=args[(iD=sizeof(explode(dir[0], "%"))-1)]), ({ this_object(), environment() })); else { noti += "Syntax: "+verb+" "+replace(bing[q], ({ "%p", "<prep>", "%I", "<object>", "%D", "<object>", "'", "" }))+"\n"; continue; /* direct object! */ } if (sizeof(indir) > 1) indir = find_match((s=args[(iI=sizeof(explode(indir[0], "%"))-1)]), ({ this_object(), environment() }) ); else indir = ({ }); /* Bity is the array of succeeded objects. */ bity = ({ }); for (j=0;j<sizeof(dir);j++) if (dir[j]->short()) /* Object must have a short to be worked on */ /* * Check to see if the object is in the list of objects with the command * added */ if (member_array(dir[j], commands[verb][bing[q]]) != -1) /* * Do the call checking for return value. You can return a string or * a array to do odd things. Look at query_multiple_short */ if ((m=(mixed)call_other(dir[j], "do_"+verb, indir, args[iD], args[iI], args))) if (stringp(m) || pointerp(m)) bity += ({ m }); else bity += ({ dir[j] }); /* * Did we suceed? Big question everyone is asking. * Print the fail message if we didn't. */ if (sizeof(bity) != sizeof(dir) || sizeof(suc_indir) != sizeof(indir)) { s1 = query_multiple_short(dir - bity); s2 = query_multiple_short(indir - suc_indir); s = create_string(pattern, args, iD, iI, s1, s2); write("You failed to "+verb+" "+s); retval++; } /* and continue... */ if (!sizeof(bity) || (sizeof(indir) && !sizeof(suc_indir))) continue; /* Print our nice success message */ s1 = query_multiple_short(bity); s2 = query_multiple_short(suc_indir); s = create_string(pattern, args, iD, iI, s1, s2); write("You "+verb+" "+s); say(this_player()->query_cap_name()+" "+verb+"s "+s); retval++; } if (noti != "") notify_fail(noti); return retval; } /* * This horrible bit passes the args and the mutiple shorts to give a * nice format string as a message. This is used to print both errors * and fails. */ string create_string(string pattern, mixed *args, int d, int e, string s1, string s2) { string *bits, s; int i; pattern = replace(pattern, ({ "'", "", "[", "", "]", "" })); bits = explode("*"+pattern, "%"); s = bits[0][1..10000]; if (s1 == "") s1 = "(no match)"; if (s2 == "") s2 = "(no match)"; for (i=0;i<sizeof(bits)-1;i++) if (i == d) s += s1+bits[i+1][1..100]; else if (i == e) s += s2+bits[i+1][1..100]; else s += args[i]+bits[i+1][1..100]; return s+".\n"; }