/** * New holding code! * Because the old stuff wasn't OO enough for me. * @author Pinkfish * @changes See the RCS log, but this change is made by Terano * * This has the controlling code for holding/wielding objects */ /** * This stuff is setup by other parts of /std/living, and can't be * changed. */ nosave mixed *_using; nosave mixed *_weapons; //This is somewhat strangely named, it is actually an int that is 1 on //success and 0 on fail. #define START_VALUE "1" /** * We have to keep the interfaces the same so has to not break things */ int *set_hold(object ob, int location, int limbs); int *set_unhold(object ob); private int sub_hold(object ob, int pos, int first); /** * @ignore */ void create() { _weapons = ({ }); } /** * This method returns the an array of the names of the limbs * on the living object. * @return an array of limbs */ string *query_limbs() { //Be type safe! string race_ob; string *limbs; race_ob = this_object()->query_race_ob(); if (!race_ob) { _using = ({ }); return ({ }); } limbs = race_ob->query_limbs(); if (!_using) { _using = allocate(sizeof(limbs)); } return limbs; } string* query_using_array() { return copy(_using); } /* query_using_array() */ /** * This method returns the current holding array of the living object. * This has one element in the array for each object and a 0 is in the * array if that limb is not holding anything. The positions correspond * to the positions returned by the query_limbs() function. * @return an array of held objects * @see query_holding() * @see query_free_limbs() * @see query_weapons() */ object *query_holding() { if (!arrayp(_using)) { //Generate a using array query_limbs(); } _using = map(_using, (: $1 ? (environment($1) == this_object()? $1 : 0) : 0 :)); return copy(_using); } /* query_holding() */ /** * This method returns the list of limbs the object is being held in. * @param ob the object to check the limbs for * @return the limbs it is held in */ string* query_holding_limbs(object ob) { string* ret; int i; object* holding; string* limbs; ret = ({ }); holding = query_holding(); limbs = query_limbs(); for (i = 0; i < sizeof(holding); i++) { if (holding[i] == ob) { ret += ({ limbs[i] }); } } return ret; } /** * This method returns the number of free limbs on the living object. * A free limb! Yes, have a couple of free legs, beat the rush! * Buy now! * @return the number of free limbs * @see query_holding() * @see query_limbs() */ int query_free_limbs() { if (!arrayp(_using)) { query_limbs(); } return sizeof(filter(_using, (: !$1 || environment($1) != this_object() :))); } /** * This method returns the currently held weapons on the living object. * This is an array of held items which are weapons and can be used * in combat. * @return the array of held weapons * @see query_holding() */ object *query_weapons() { // I don't quite understand the bit after the || // Also, it runtimes if $1 is 0 --Presto // return filter(_weapons, (: $1 || environment($1) != this_object() :)); return filter(_weapons, (: $1 :)); } /** * This method sets the object as unheld. It will attempt to remove * the object from a held limb. * <p> * The return array contains the index of the limbs from which the * item was removed, if the array is 0 size then no items were * removed. * @param ob the object to unhold * @return a array of limb numbers * @see set_hold() * @see query_limbs() */ int *set_unhold(object ob) { int *pos; if (!objectp(ob)) { return ({ }); } if (member_array(ob, _using) == -1) { return ({ }); } if (!ob->set_holder(0)) { return ({ }); } pos = find_member(ob, _using); if (ob->query_weapon()) { _weapons = filter(_weapons, (: $1 != $(ob) :)); } if (ob->query_armour()) { this_object()->remove_armour(ob); } _using = map(_using, (: $1 == $(ob) ? 0 : $1 :)); this_object()->do_burden_call(); return pos; } /** * This method sets the object as held. It will attempt to hold it starting * at the given position in the limbs array. * <p> * The return array contains the index of the limbs from which the * item was added, if the array is 0 size then no items were * added. * @param ob the object to hold * @param pos the position in the limb array to start holding at * @param limbs the number of limbs to be used (1 or 2 usually). leave as * zero for default. * @return a array of limb numbers * @see set_unhold() * @see query_limbs() * * Editors Note: I have changed set_hold so that it no longer * automatically unholds objects. I am moving that functionality to the * hold command. If you want your objects to be in a specific limb, * you have to free it up yourself using set_unhold. * If you don't care which limbs, you just have to free up enough limbs * to hold it. */ int *set_hold(object ob, int pos, int limbs) { int limb_count; int *free = ({ }); int *used = ({ }); int total = 0; int temp = 0; int ok; int failed; if (environment(ob) != this_object()) { debug_printf("Bad environment"); return ({ }); } limb_count = sizeof(this_player()->query_limbs()); if (!arrayp(_using)) { query_limbs(); } /** * Find out if we have enough free arms.. if not scream and die. * I want to do it this way, because the hold command should * be responsable for freeing limbs.. not us. */ //We are trying any and all limbs. if (pos == -1) { total = ob->query_no_limbs(); if (total > this_object()->query_free_limbs()) { debug_printf("Too many limbs"); return ({ }); } //Find out which limbs are free free = find_member(0, _using); if (!sizeof (free)) { return ({ }); } // Start with the first one and do the normal hold attempts. pos = free[0]; } //It wants a specific position - is it free? if (objectp(_using[pos]) && environment(_using[pos]) == this_object()) { //Nope! Remember, only you can make sure your limbs are free before //using them! return ({ }); } //Set the first one that they asked for, guess the rest ourselves. ok = sub_hold(ob, pos, 1); if (ok) { used += ({ pos }); } else { return ({ }); } //Initialise our 'guessing' variables. //Get all free limbs and note the used limb. if(limbs) total = limbs - 1; else total = ob->query_no_limbs() - 1; free = find_member(0, _using); temp = 0; while (temp < total && temp < sizeof(free)) { //Oops, we've run out of limbs! if (temp > limb_count) { set_unhold(ob); return ({ }); } sub_hold(ob, free[temp], 0); if (ok) { used += ({ free[temp] }); temp++; } else { failed = 1; } } if (failed) { set_unhold(ob); return ({ }); } else { this_object()->do_burden_call(); return used; } } /** * Does a lot of the grunt work in holding, does all the validation * for each limb for starters. More stuff might come later! * Tannah - you can mask this if you want. * Terano. */ private int sub_hold(object ob, int pos, int first) { int success; // Must be in our inventory to hold it. if (environment(ob) != this_object()) { return 0; } //If failed_mess = 1 [note that this means that we haven't failed yet] //and if we haven't held it yet. [If failed mess is one and there is no //holder, we haven't tried yet.] if (first) { success = ob->set_holder(this_object(), pos); if (!success) { return 0; } } _using[pos] = ob; if (ob->query_weapon()) { if (member_array(ob, _weapons) == -1) { _weapons += ({ ob }); } } return 1; }