/* -*- LPC -*- */
/*
* $Locker: $
* $Id: ho_ld.c,v 1.12 2002/08/16 00:11:52 presto Exp $
* $Log: ho_ld.c,v $
* Revision 1.12 2002/08/16 00:11:52 presto
* Changed to allow you to switch from one hand to the other, or between
* one hand and two hands without unholding first
*
* Revision 1.11 2002/08/03 19:25:36 ceres
* New combat system version
*
* Revision 1.9 2001/03/13 05:04:22 pinkfish
* Fix up holding if you are already holding one of the items.
*
* Revision 1.8 2001/03/09 01:50:43 pinkfish
* Fix up some problems in hold.
*
* Revision 1.7 2001/03/07 22:02:49 pinkfish
* *** empty log message ***
*
* Revision 1.6 2001/03/07 21:59:30 terano
* Forcibly unlocked by pinkfish
*
* Revision 1.5 2000/03/10 23:27:18 gruper
* I *hope* I fixed an index out of bounds bug,
* but who knows - maybe I broke it even worse :)
*
* Revision 1.4 1999/07/07 23:24:52 pinkfish
* Fix up some problems with hold that caused it not to work with things
* that fiddled with the number of limbs available.
*
* Revision 1.3 1999/06/04 00:59:35 pinkfish
* Fix up hold to unhold from multiple hands.
*
* Revision 1.2 1998/10/08 09:52:49 pinkfish
* Fixed up to work correctly with things that do not wish to be unheld.
*
* Revision 1.1 1998/01/06 05:28:43 ceres
* Initial revision
*
*/
/* Command to hold weapons. This _should_ be fairly simple, however it is */
/* complicated by dealing with 1. a variable number of limbs and 2. printing */
/* out all the appropriate holding/unholding/failing/suceeding messages. */
inherit "/cmds/base";
#define TP this_player()
int cmd(object * obs,
string str)
{
int num_limbs; // this players limb count
int avail; // limbs available
int old_avail; // old limbs available, used for sanity checking
int reqd; // limbs required
int i; // general counter
int pos; // which limb position
int success; // did we succeed
int *used; // limbs used by set_hold or set_unhold
int *already_used; // limbs used by already held weapons
int *limbs_used; // limb positions used by already held objects
object ob;
object weapon;
object *using; // limbs currently in use
object *fails; // weapons we failed to hold
object *unfails; // weapons we failed to unhold
object *holds; // weapons we sucessfully held
object *unholds; // weapons we successfully unheld
object *already; // weapons already held
object *no_change; // objects that we are already holding the way
// we requested
string *limbs; // limb names;
string *hhands; // hands we successfully held weapons in
string *uhands; // hands we successfully unheld weapons from
// calc how many hands will be needed
limbs = TP->query_limbs();
num_limbs = sizeof(limbs);
avail = TP->query_free_limbs();
no_change = ({ });
already = filter(obs, (: $1->query_holder() :));
if (sizeof(already) > 0) {
using = this_player()->query_holding();
foreach (ob in already) {
limbs_used = find_member(ob, using);
if (str) {
if (sizeof(limbs_used) == 1 &&
member_array(str, limbs) == limbs_used[0])
{
no_change += ({ ob });
}
else already -= ({ ob });
}
else if (sizeof(limbs_used) != ob->query_no_limbs())
already -= ({ ob });
}
if (sizeof(obs) == sizeof(no_change)) {
add_failed_mess("You are already holding " +
query_multiple_short(obs) +
" in your " + str + ".\n");
return -1;
}
else if (sizeof(obs) == sizeof(already)) {
return notify_fail("You are already holding " +
query_multiple_short(obs) + ".\n");
} else {
obs -= already;
if (sizeof(already) > 0)
write(sprintf("You are already holding %s, you instead try to "
"hold %s.\n", query_multiple_short(already),
query_multiple_short(obs)));
already_used = map(already, (: $1->query_my_limb() :));
}
} else {
already_used = ({ });
}
fails = holds = unholds = hhands = uhands = unfails = ({ });
// deal with specific hands first
if (str && obs[0]) {
pos = member_array(str, limbs);
if (pos == -1) {
if (!sizeof(limbs)) {
return
notify_fail("You seem to have a singular lack of limbs.\n");
}
return notify_fail("Incorrect limb type, must be one of " +
query_multiple_short(limbs) + ".\n");
}
using = TP->query_holding();
// clear the appropriate hand
if (sizeof(unfails) == 0 && using[pos]) {
used = TP->set_unhold(using[pos]);
if (sizeof(used) == 0) {
/* This means we cannot hold the object for sure. */
unfails += ({ using[pos] });
uhands += ({ limbs[pos] });
} else {
for (i = 0; i < sizeof(used) && i < sizeof(limbs); i++) {
uhands += ({ limbs[used[i]] });
}
unholds += ({ using[pos] });
}
}
// Put it down if we are already holding it in another hand
if ((i = member_array(obs[0], using - unholds)) != -1) {
used = TP->set_unhold(obs[0]);
if (sizeof(used) == 0) {
/* This means we cannot hold the object for sure. */
unfails += ({ obs[0] });
uhands += ({ limbs[i] });
} else {
for (i = 0; i < sizeof(used) && i < sizeof(limbs); i++) {
uhands += ({ limbs[used[i]] });
}
unholds += ({ obs[0] });
}
}
if (sizeof(unfails) == 0) {
// hold in the appropriate hand
used = TP->set_hold(obs[0], pos, 1);
if (sizeof(used) == 0) {
fails += ({ obs[0] });
} else {
for (i = 0; i < sizeof(used) && i < sizeof(limbs); i++) {
hhands += ({ limbs[used[i]] });
}
holds += ({ obs[0] });
success = 1;
}
}
} else { // now deal with normal holding
foreach(ob in obs) {
reqd += ob->query_no_limbs();
}
if (reqd > num_limbs) {
add_failed_mess("You do not have enough limbs to hold $I.\n", obs);
return 0;
}
old_avail = -1;
// if necessary put down items until the required hands are available
// No need for a while, if it canont be done. It cannot be done.
// If nothign was able to be put down after one sweep through, we are
// out of luck.
while ((avail < reqd) && (avail < num_limbs)) {
if ((reqd > num_limbs - sizeof(unfails)) || (old_avail == avail)) {
if (sizeof(unfails)) {
add_failed_mess
("You do not have enough limbs to hold $I, since " +
query_multiple_short(unfails) + " failed " "to unhold.\n",
obs);
} else {
add_failed_mess
("Not able to free up enough limbs to hold $I.\n", obs);
}
return 0;
}
old_avail = avail;
using = TP->query_holding();
for (i = 0; i < sizeof(using); i++) {
weapon = using[i];
if (weapon && member_array(i, already_used) == -1) {
used = TP->set_unhold(weapon);
if (sizeof(used)) {
for (i = 0; i < sizeof(used) && used[i] < sizeof(limbs);
i++) {
uhands += ({ limbs[used[i]] });
}
unholds += ({ weapon });
avail = TP->query_free_limbs();
break;
} else {
if (member_array(weapon, unfails) == -1) {
unfails += ({ weapon });
}
uhands += ({ limbs[i] });
}
}
}
}
if (!sizeof(unfails)) {
// now try holding the new items
foreach(ob in obs) {
using = TP->query_holding();
pos = 0;
if (!ob->query_no_limbs() || avail < ob->query_no_limbs()) {
fails += ({ ob });
break;
}
// hold the new items
while ((using[pos]) && (pos < num_limbs)) {
pos++;
}
used = TP->set_hold(ob, pos, ob->query_no_limbs());
if (used == ({ })) {
fails += ({ ob });
} else {
for (i = 0; i < sizeof(used) && i < sizeof(limbs); i++) {
hhands += ({ limbs[used[i]] });
}
holds += ({ ob });
success = 1;
avail = TP->query_free_limbs();
}
}
}
}
// printout all the different sodding message types
if (sizeof(unfails)) {
tell_object(TP,
"You fail to put down " + query_multiple_short(unfails) +
" from your " + query_multiple_short(uhands) + ".\n");
say(TP->one_short() + " fails to put down " +
query_multiple_short(unholds) + " from " + TP->query_possessive() +
" " + query_multiple_short(uhands) + ".\n");
}
if (sizeof(unholds)) {
tell_object(TP, "You put down " + query_multiple_short(unholds) +
" from your " + query_multiple_short(uhands) + ".\n");
say(TP->one_short() + " puts down " + query_multiple_short(unholds) +
" from " + TP->query_possessive() + " " +
query_multiple_short(uhands) + ".\n");
}
if (sizeof(holds)) {
tell_object(TP,
"You hold " + query_multiple_short(holds) + " in your " +
query_multiple_short(hhands) + ".\n");
say(TP->one_short() + " holds " + query_multiple_short(holds) + " in " +
TP->query_possessive() + " " + query_multiple_short(hhands) +
".\n");
}
// don't print the failed to hold messages if we managed to hold stuff.
if (!success && sizeof(fails)) {
tell_object(TP,
"You fail to hold " + query_multiple_short(fails) + ".\n");
say(TP->one_short() + " fails to hold " + query_multiple_short(fails) +
".\n");
}
return 1;
} /* cmd() */
mixed *query_patterns()
{
return ({ "<indirect:object:me>", (: cmd($1, 0) :),
"<indirect:object:me> in [my] {" +
implode(this_player()->query_limbs(), "|") + "}",
(: cmd($1, implode($4[1..], " ")) :) });
} /* query_patterns() */