/* -*- LPC -*- */
/*
* $Locker: trilogy $
* $Id: container.c,v 1.13 2001/03/18 17:32:23 tannah Exp trilogy $
* $Log: container.c,v $
* Revision 1.13 2001/03/18 17:32:23 tannah
* Changed all the %d/%d to <fraction>, the %p to <preposition>, the %I
* to <indirect:object> and the %D to <direct:object>
*
* Revision 1.12 2000/07/14 22:08:51 pinkfish
* Fix up to not use global variables from inherits
*
* Revision 1.11 2000/06/08 02:06:24 pinkfish
* Remove the old fill code.
*
* Revision 1.10 1999/11/18 10:04:34 pinkfish
* Add in stuff to control looking inside something else.
*
* Revision 1.9 1999/11/08 09:13:05 pinkfish
* Fix it up so you can see what is in it.
*
* Revision 1.8 1999/11/04 00:59:22 pinkfish
* Make it pay attenion to darkness levels.
*
* Revision 1.7 1999/07/20 07:53:48 wodan
* set_unlock_trap has been renamed set_lock_trap for some reason.
*
* Revision 1.6 1999/05/27 23:46:11 pinkfish
* Fix up to work propertly with the private variables in /std/basic/close_lock.c
* These people that assume things about object internals. Sheeze :)
*
* Revision 1.5 1998/10/30 08:34:49 pinkfish
* Fix up the name references.
*
* Revision 1.4 1998/03/12 08:07:15 pinkfish
* Added documentation.
*
* Revision 1.3 1998/03/05 06:03:35 pinkfish
* Fixed up the problems wirth picking up immovable signs.
*
* Revision 1.2 1998/02/11 00:34:06 presto
* Fixed placement of open/closed description
*
* Revision 1.1 1998/01/06 04:58:17 ceres
* Initial revision
*
*/
/**
* This is main container type object that players will use. For
* example, buckets and stuff would use this. A backpack would be
* a type of clothing and a potion bottle should be a vessel.
* @author Who knows, Pinkfish, Ember, Jeremy
* @see /obj/vessel.c
* @see /obj/clothing.c
*/
#include "move_failures.h"
#include "parse_command.h"
#include "potion_attrs.h"
/* Modified by Piecemaker 18/5/93 to add octarine descriptions. */
/* Modified by Jeremy Feb 96 to skip breakage in stationary containers
* and to add 'padded' property
*/
inherit "/std/container";
inherit "/std/basic/close_lock_container";
#define MAX_INVENT 40
nosave int full_weight, leak_rate, hb_count;
/* liquid/potion stuff */
mixed *misc_attrs; /* purely physical attributes ... all the 'inactive' parts */
nosave mixed *all_attrs; /* misc_attrs merged with active_attrs */
nosave mixed *active_attrs; /* this is the attrs due to the position in the potion space */
int volume, max_volume; /* total volume, and max volume for this container */
int water; /* the 'water' part of the volume ... the volume that is used in */
/* potion space activities. The volume that is not 'water' is */
/* considered 'inactive' in any potion reactions */
int *ps_coord; /* coordinate in the potion_space */
int ps_quantity; /* magic number describing quantity of active junk in this potion */
nosave mixed *potion_id, *potion_adjective;
nosave int volume_to_womble; /* kludge for the fraction stuff */
/** @ignore yes */
void set_volume_to_womble(int n) { volume_to_womble = n; }
/** @ignore yes */
int query_volume_to_womble() { return volume_to_womble; }
/**
* This method sets the weight of the container when it is full.
* @param i the new weight of the containe when full.
* @see query_full_weight()
* @see set_weight()
*/
void set_full_weight(int i) { full_weight = i; }
/**
* This method sets the leak rate of the container. The leak rate is how
* fast stuff leaks out of the container.
* @param i the new leak rate of the container
* @see query_leak_rate()
*/
void set_leak_rate(int i) { leak_rate = i; }
/**
* This method returns the full weight of the container.
* @see set_full_weight()
* @see query_weight()
*/
int query_full_weight() { return full_weight; }
/**
* This method returns the leak rate of the container
* @see set_leak_rate()
*/
int query_leak_rate() { return leak_rate; }
/**
* This method returns the current amount of liquid in the container.
* @return the current amount of liquid in the container
*/
int query_volume() { return volume; }
/**
* This method sets the current amount of liquid in the container. If
* the container has a leak rate, it starts to leak.
* @param i the new amount of liquid in the containe
* @see query_volume()
* @see set_leak_rate()
*/
void set_volume(int i) {
volume = i;
if (leak_rate) {
set_heart_beat(1);
}
} /* set_volume() */
/**
* This method returns the current maxium volume associated with this
* container.
* @return the current maximum volume
*/
int query_max_volume() { return max_volume; }
/*
void set_max_volume(int i) { max_volume = i; }
*/
/**
* This method returns the potion space co-ordinates of the liquid.
* @return the potion space co-ordinates
* @see query_ps_quantity()
*/
int *query_ps_coord() { return ps_coord; }
/**
* This method returns the quantity of liquid at the potion space.
* @return the quantity of liquid
* @see query_ps_coord()
* @see set_ps_quantity()
*/
int query_ps_quantity() { return ps_quantity; }
void set_ps_quantity(int n) { ps_quantity = n; }
int *query_all_attrs() { return all_attrs; }
int *query_misc_attrs() { return misc_attrs; }
int *query_active_attrs() { return active_attrs; }
/**
* This method sets the volume of water in the container.
* @param n the new volume of water
*/
void set_water_volume(int n) { water = n; if (leak_rate) set_heart_beat(1); }
/**
* This method returns the volume of water in the container.
* @see set_water_volume()
*/
int query_water_volume() { return water; }
/**
* This method sets the maximum weight of the container. This also sets
* the maximum volume of the container to 10 times its maximum weight.
* (If there is no current maximum volume).
* @param i the maxium weight of the container
* @see set_max_volume()
* @see add_weight()
*/
void set_max_weight(int i) {
if (!max_volume && i) {
max_volume = i*10;
}
::set_max_weight(i);
} /* set_max_weight() */
/**
* This method sets the maximum volume of the container. This also
* sets the maximum weight of the container to one tenth of the
* volume (if there is not current maximum weight).
* @param i the new maximum volume
* @see set_max_weight()
* @see add_volume()
*/
void set_max_volume(int i) {
if (!query_max_weight() && i) {
::set_max_weight(i/10);
}
max_volume = i;
} /* set_max_volume() */
/**
* This method returns the amount of the liquid you can actually empty
* from a container.
* @return the amount of liquid that can be emptied
*/
int empty_formula() {
/* formula to work out how close to empty someone can get casually */
int vol_lost;
vol_lost = 2 + volume * 95 / 100;
if (vol_lost > volume) vol_lost = volume;
return vol_lost;
} /* empty_formula() */
/** @ignore yes */
int cull_neutral_obs( mixed ob ) {
if ( ob->query_vect() ) {
return 1;
}
return 0;
} /* cull_neutral_obs() */
/**
* This method returns the vector of the contents of the container.
* This is based on the vectors of all the liquid with a vector set
* on them.
*/
int *contents_vect() {
object *inv;
int *v;
int ang, str, tot, i;
inv = all_inventory(this_object());
inv = filter_array(inv, "cull_neutral_obs", this_object());
if (sizeof(inv) == 0) return ({ 0, 0, 0 });
tot = ang = str = 0;
for (i = 0; i < sizeof(inv); i++) {
v = inv[i]->query_vect();
tot += v[0];
ang += v[1] * v[0];
str += v[2] * v[0];
}
return ({ ang / tot, str / tot, tot });
} /* contents_vect() */
/**
* This method will destroy all the liquid contents of the object.
* @return the number of object destroyed
*/
int dest_active_contents() {
object *inv;
int i;
inv = all_inventory(this_object());
inv = filter_array(inv, "cull_neutral_obs", this_object());
for (i = 0; i < sizeof(inv); i++) {
inv[i]->dest_me();
}
return sizeof(inv);
} /* dest_active_contents() */
/** @ignore yes */
int *squidge_vector(int *v, int meth_ang, int meth_mult) {
int ca, cb;
int da, cx, cy;
object trig;
"/obj/handlers/trig"->wibble_wobble();
trig = find_object("/obj/handlers/trig");
da = meth_ang - v[0];
ca = v[1] * trig->cos(da);
cb = v[1] * trig->sin(da);
ca = ca * meth_mult;
cb /= meth_mult;
ca /= 1000000;
cb /= 1000000;
cx = ca * trig->cos(meth_ang) + cb * trig->sin(meth_ang);
cy = ca * trig->sin(meth_ang) - cb * trig->cos(meth_ang);
return ({ cx / 1000000, cy / 1000000 });
}
void set_ps_coord_quantity(int *coord, int quantity);
/**
* This method adds a potion space vector with a particular
* quantity to the object.
* @param v the vector to add
* @param quant the quantity to add
*/
void add_ps_vect(int *v, int quant) {
object trig;
int ca, cb;
if (quant <= 0) return;
trig = find_object("/obj/handlers/trig");
/* ca = v[1] * trig->cos(v[0]) / 1000000;
cb = v[1] * trig->sin(v[0]) / 1000000; */
ca = v[0]; cb = v[1];
ca = (int)trig->pow1_5(ps_coord[0] * 10 * ps_quantity /(ca * quant)) * ca / 1000000;
cb = (int)trig->pow1_5(ps_coord[1] * 10 * ps_quantity /(cb * quant)) * cb / 1000000;
set_ps_coord_quantity( ({ ps_coord[0] + ca, ps_coord[1] + cb }),
quant + ps_quantity);
return;
}
/**
* This method returns a string for how transparent the liquid is
* based on the transparency value passed in.
* @return the transparency string()
* @param trans the transparency value
*/
string transparency_string(int trans)
/* return string describing transparency 'trans' */
{
switch (trans) {
case -10..9: return "opaque";
case 10..24: return "milky";
case 25..39: return "murky";
case 40..59: return "cloudy";
case 60..74: return "misty";
case 75..89: return "slightly misty";
case 90..110: return "clear";
/* if they've got the numbers stuffed up, they should _know_ about it :) */
default: return "paisley";
}
} /* transparency_string() */
/**
* This method returns a string for how consistent the liquid is
* based on the consistency value passed in.
* @return the consistency string()
* @param cons the consistency value
*/
string consistency_string(int cons)
/* return string describing consistency 'cons' */
{
switch (cons) {
case -10..9: return "watery liquid";
case 10..24: return "slightly viscous watery liquid";
case 25..39: return "runny syrup";
case 40..59: return "syrup";
case 60..74: return "jelly"; /* viscous liquid? */
case 75..89: return "paste";
case 90..110: return "solid";
/* see above comment in transparency */
default: return "non-Newtonian fluid";
}
} /* consistency_string() */
/**
* This method updates the values used for the find_match() parseing
* due to the liquids.
* @see /secure/simul_efun->find_match()
*/
void update_potion_parse()
{
int i;
string *exploded;
potion_adjective = query_adjectives() +
({ transparency_string(all_attrs[POTION_TRANSPARENCY]) });
potion_id = ({ query_name() }) + query_alias() +
({ consistency_string(all_attrs[POTION_CONSISTENCY]) });
for (i = 0; i < sizeof(all_attrs[POTION_NAMES]); i++) {
exploded = explode(all_attrs[POTION_NAMES][i][0], " ");
potion_id += ({ exploded[sizeof(exploded) - 1] });
if (sizeof(exploded) > 1) {
potion_adjective += exploded[0..sizeof(exploded) - 2];
}
}
for (i = 0; i < sizeof(all_attrs[POTION_COLOURS]); i++)
potion_adjective += explode(all_attrs[POTION_COLOURS][i][0], " ");
/* plurals? Lets forget them for now */
}
/**
* This method zaps all the liquid stuff in the container.
*/
void void_liquid()
{
volume = 0;
water = 0;
misc_attrs = allocate(POTION_ATTRS_SIZE);
misc_attrs[POTION_CONSISTENCY] = 0;
misc_attrs[POTION_TRANSPARENCY] = 100;
misc_attrs[POTION_NAMES] = ({ });
misc_attrs[POTION_COLOURS] = ({ });
misc_attrs[POTION_SMELLS] = ({ });
misc_attrs[POTION_FLAVOURS] = ({ });
ps_coord = (int *)POTION_SPACE_HANDLER->neutral_coordinate();
ps_quantity = 0;
/* Hmmm. I wonder if having these all the same array will cause problems */
active_attrs = all_attrs = misc_attrs;
update_potion_parse();
}
/** @ignore yes */
void create() {
do_setup++;
container::create();
close_lock_container::create();
set_can_export_inventory();
do_setup--;
void_liquid();
add_property("liquid", 1);
add_property("watertight", 1);
leak_rate = 1000;
if ( !do_setup )
this_object()->setup();
} /* create() */
/** @ignore yes */
void init() {
/* liquid::init(); */
(void)this_player()->add_command("drink", this_object());
(void)this_player()->add_command("splash", this_object(), "<direct:object> <preposition> <indirect:object>");
(void)this_player()->add_command("rub", this_object(), "<direct:object> <preposition> <indirect:object>");
(void)this_player()->add_command("apply", this_object(), "<direct:object> <preposition> <indirect:object>");
(void)this_player()->add_command("pour", this_object(), "<direct:object> <preposition> <indirect:object>");
(void)this_player()->add_command("taste", this_object());
(void)this_player()->add_command("smell", this_object());
this_player()->add_command("fill", this_object(), "<indirect:object> <preposition> <direct:object>");
this_player()->add_command("fill", this_object(), "<indirect:object> <fraction> up <preposition> <direct:object>");
this_player()->add_command("fill", this_object(), "<indirect:object> <fraction> full <preposition> <direct:object>");
(void)this_player()->add_command("empty", this_object());
close_lock_container::init();
} /* init() */
/* This may be stuffing up other containers...
int query_weight() {
if (!full_weight)
return ::query_weight();
return ::query_weight() + ((query_loc_weight()+(query_max_weight()*volume)/max_volume)
*full_weight)/query_max_weight();
} query_weight() */
/** @ignore yes */
int query_complete_weight() {
return ::query_complete_weight() + ( query_max_weight() * volume ) /
( max_volume + 1 );
} /* query_complete_weight() */
/**
* This method returns the current amount of weight left that can
* be filled on the container.
* @return the current amount of weight left
*/
int query_weight_left() {
if (!max_volume)
return query_max_weight() - query_loc_weight();
return query_max_weight() - query_loc_weight() - (query_max_weight()*volume)/max_volume;
} /* query_weight_left() */
/**
* This method returns the amount of volume left for liquids to be
* added into.
* @return the amount of volume left
* @see add_volume()
* @see transfer_liquid_to()
*/
int query_volume_left() {
if (!query_max_weight())
return max_volume - volume;
return max_volume - volume - (max_volume*query_loc_weight())/query_max_weight();
} /* query_volume_left() */
/** @ignore yes */
int add_weight( int n ) {
if ( query_weight_left() < n ) return 0;
if ( !( ::add_weight( n ) ) ) return 0;
if ( n >= 0 ) {
remove_call_out( "check_breakages" );
call_out( "check_breakages", 5 + random( 16 ) );
}
return 1;
#ifdef BREAK_NOW
obs = all_inventory();
for (i=0;i<sizeof(obs);i++)
if ((amt = obs[i]->query_property("fragile"))) {
if (query_loc_weight() <= amt || ((query_loc_weight() - amt)*100)/amt <= random(100))
obs[i] = 0;
} else
obs[i] = 0;
obs = obs - ({ 0 });
if (sizeof(obs)) {
say(this_player()->one_short()+" breaks "+
(sizeof(obs)>1?"some things":"one thing")+" in "+
query_multiple_short(({ this_object() }))+".\n");
write("You break "+query_multiple_short(obs)+" in "+
query_multiple_short(({ this_object() }))+".\n");
obs->dest_me();
}
return 1;
#endif
} /* add_weight() */
/**
* This method checks to see if any of the things contained in the
* container should be broken.
* @see /std/container->add_weight()
*/
void check_breakages() {
/* check loc_weight against fragility of every object and break some
* if necessary. If the container has the "padded" property, adjust
* the chance of breakage.
*/
object *obs, carrier;
int i, amt, wt;
// See if it's being carried by a living object
carrier = environment(this_object());
while (carrier && (!living(carrier))) {
carrier = environment(carrier);
}
if (!carrier)
return;
obs = all_inventory();
wt = query_loc_weight() - (int)query_property("padded");
for (i=0;i<sizeof(obs);i++) {
if ((amt = obs[i]->query_property("fragile"))) {
if (wt <= amt || ((wt - amt)*100)/amt <= random(100)) {
obs[i] = 0;
}
} else {
obs[i] = 0;
}
}
obs = obs - ({ 0 });
if (sizeof(obs) && environment(carrier)) {
tell_room(environment(carrier), carrier->the_short()+" breaks "+
(sizeof(obs)>1?"some things":"one thing")+" in "+
query_multiple_short(({ this_object() }))+".\n", ({ carrier }));
tell_object(carrier, "You break "+query_multiple_short(obs)+" in "+
query_multiple_short(({ this_object() }))+".\n");
obs->dest_me();
}
} /* check_breakages() */
/** @ignore yes */
varargs string pretty_short( object thing ) {
return short_status() + ::pretty_short( thing );
} /* pretty_short() */
/** @ignore yes */
varargs string pretty_plural( object thing ) {
return short_status() + ::pretty_plural( thing );
} /* pretty_plural() */
/**
* This method returns the name of the current liquid inside the container.
* @return the name of the current liquid
*/
string liquid_name()
{
string liq_name;
mixed *names, *colours;
string *med, *lo; /* groups of strings with hi/med/lo intensities */
int no_names, no_colours, i;
names = all_attrs[POTION_NAMES];
colours = all_attrs[POTION_COLOURS];
no_names = (sizeof(names) < 1 || names[0][1] < VERY_SMALL_AMOUNT);
no_colours = (sizeof(colours) < 1 || colours[0][1] < VERY_SMALL_AMOUNT);
if (no_names && no_colours) {
liq_name = "a colourless " +
transparency_string(all_attrs[POTION_TRANSPARENCY]) + " " +
consistency_string(all_attrs[POTION_CONSISTENCY]);
} else if (no_names) {
if (colours[0][1] < SMALL_AMOUNT) {
liq_name = "a faint " + colours[0][0];
} else {
liq_name = add_a(colours[0][0]);
}
liq_name += " " + transparency_string(all_attrs[POTION_TRANSPARENCY]) +
" " + consistency_string(all_attrs[POTION_CONSISTENCY]);
med = ({ });
i = 1;
while (i < sizeof(colours) && colours[i][1] >= SMALL_AMOUNT)
med += ({ colours[i++][0] });
lo = ({ });
while (i < sizeof(colours) && colours[i][1] >= VERY_SMALL_AMOUNT)
lo += ({ colours[i++][0] });
if (sizeof(med)) {
liq_name += " with swirls of " + query_multiple_short(med);
}
if (sizeof(lo)) {
if (sizeof(med)) liq_name += " and faint streaks of " + query_multiple_short(lo);
else liq_name += " with faint streaks of " + query_multiple_short(lo);
}
} else if (no_colours) {
i = 0;
med = ({ });
lo = ({ });
while (i < sizeof(names) && names[i][1] >= SMALL_AMOUNT)
med += ({ names[i++][0] });
while (i < sizeof(names) && names[i][1] >= VERY_SMALL_AMOUNT)
lo += ({ names[i++][0] });
if (sizeof(med) > 1) liq_name = "a mixture of " + query_multiple_short(med);
else if (sizeof(med) == 1) liq_name = med[0];
if (!sizeof(med) && sizeof(lo) > 1)
liq_name = "a diluted mixture of " + query_multiple_short(lo);
else if (!sizeof(med) && sizeof(lo) == 1)
liq_name = "diluted " + lo[0];
else if (sizeof(med) && sizeof(lo))
liq_name += "and small quantities of " + query_multiple_short(lo);
} else {
if (names[0][1] > colours[0][1] / 2)
/* arbitrary relationship ... names are 'twice' as visible as colours */
/* if the primary name is more visible than the primary colour, */
/* then we use this scenario: */
/* "chunky soup (a yellow cloudy syrup with swirls of green, orange */
/* and brown)" */
/* else we use the colour scenario: */
/* "a yellow cloudy syrup containing chunky soup with swirls of green, */
/* orange and brown" */
{
/* this little fragment copied directly from 'no_colours' above */
i = 0;
med = ({ });
lo = ({ });
while (i < sizeof(names) && names[i][1] >= SMALL_AMOUNT)
med += ({ names[i++][0] });
while (i < sizeof(names) && names[i][1] >= VERY_SMALL_AMOUNT)
lo += ({ names[i++][0] });
if (sizeof(med) > 1) liq_name = "a mixture of " + query_multiple_short(med);
else if (sizeof(med) == 1) liq_name = med[0];
if (!sizeof(med) && sizeof(lo) > 1)
liq_name = "a diluted mixture of " + query_multiple_short(lo);
else if (!sizeof(med) && sizeof(lo) == 1)
liq_name = "diluted " + lo[0];
else if (sizeof(med) && sizeof(lo))
liq_name += "and small quantities of " + query_multiple_short(lo);
/* this little fragment copied directly from 'no_names' above */
if (colours[0][1] < SMALL_AMOUNT) liq_name += " (a faint " + colours[0][0];
else liq_name += " (" + add_a(colours[0][0]);
liq_name += " " + transparency_string(all_attrs[POTION_TRANSPARENCY]) +
" " + consistency_string(all_attrs[POTION_CONSISTENCY]);
med = ({ });
i = 1;
while (i < sizeof(colours) && colours[i][1] >= SMALL_AMOUNT)
med += ({ colours[i++][0] });
lo = ({ });
while (i < sizeof(colours) && colours[i][1] >= VERY_SMALL_AMOUNT)
lo += ({ colours[i++][0] });
if (sizeof(med)) {
liq_name += " with swirls of " + query_multiple_short(med);
}
if (sizeof(lo)) {
if (sizeof(med)) liq_name += " and faint streaks of " + query_multiple_short(lo);
else liq_name += " with faint streaks of " + query_multiple_short(lo);
}
liq_name += ")";
} else { /* phew, coloured liquid containing names now */
/* this little fragment _almost_ directly copied from no_names above */
if (colours[0][1] < SMALL_AMOUNT) liq_name = "a faint " + colours[0][0];
else liq_name = add_a(colours[0][0]);
liq_name += " " + transparency_string(all_attrs[POTION_TRANSPARENCY]) +
" " + consistency_string(all_attrs[POTION_CONSISTENCY]);
med = ({ });
i = 0;
while (i < sizeof(names) && names[i][1] >= VERY_SMALL_AMOUNT)
med += ({ names[i++][0] });
liq_name += " containing " + query_multiple_short(med);
med = ({ });
i = 1;
while (i < sizeof(colours) && colours[i][1] >= SMALL_AMOUNT)
med += ({ colours[i++][0] });
lo = ({ });
while (i < sizeof(colours) && colours[i][1] >= VERY_SMALL_AMOUNT)
lo += ({ colours[i++][0] });
if (sizeof(med)) {
liq_name += " with swirls of " + query_multiple_short(med);
}
if (sizeof(lo)) {
if (sizeof(med)) liq_name += " and faint streaks of " + query_multiple_short(lo);
else liq_name += " with faint streaks of " + query_multiple_short(lo);
}
} /* yayayayaya. done! */
}
return liq_name;
}
/**
* This method returns the short description of the liquid.
* @return the short description of the liquid
* @see query_liquid_name()
*/
string query_liquid_short()
{
if (sizeof(all_attrs[POTION_NAMES]) && sizeof(all_attrs[POTION_COLOURS])) {
if (all_attrs[POTION_NAMES][0][1] > all_attrs[POTION_COLOURS][0][1] / 2) {
return all_attrs[POTION_NAMES][0][0];
}
}
return (sizeof(all_attrs[POTION_COLOURS]) ?
all_attrs[POTION_COLOURS][0][0] : "colourless") + " " +
transparency_string(all_attrs[POTION_TRANSPARENCY]) + " " +
consistency_string(all_attrs[POTION_CONSISTENCY]);
} /* query_liquid_short() */
/* ok modifyed back to using writes... */
/* ^^^ lies! all lies! */
/* Ok, Ok. Sulk */
/* Please ignore the above comments. They are wholely unjustified. */
/** @ignore yes */
string long(string str, int dark) {
string ret;
int bing;
ret = ::long(str, dark);
/* ret += calc_extra_look(); */
if (query_transparent() ||
!query_closed()) {
if ( ( dark == 2 ) || ( dark == -2 ) ) {
if (query_contents() != "") {
ret += "The "+ short( dark ) +" contains some items you cannot "
"make out.\n";
}
} else {
ret += query_contents( "The "+ short( dark ) +" contains:\n" );
}
}
/* what the hell is long_status, and why is it here? */
ret += long_status();
/* the long for the water inside of it */
if ((query_transparent() || !query_closed()) && volume) {
if ( ( dark == 2 ) || ( dark == -2 ) ) {
ret += "It has some liquid of some sort in it.\n";
} else {
bing = (volume*8 + max_volume/16)/max_volume;
if (bing <= 0) {
ret += "It is slightly wet from "+liquid_name()+".\n";
} else if (bing >= 8) {
ret += "It is full to the brim with " + liquid_name()+".\n";
} else {
ret += "It is " + ({ "an eighth", "a quarter",
"three eighths", "half", "five eighths", "three quarters",
"seven eighths" })[bing-1]+" full of "+liquid_name()+".\n";
}
}
}
return ret;
} /* long() */
/**
* This returns an adjective for how full the current object is with
* liquid. This is used in the parse command handling code.
* @return the fullness adjective
* @see query_max_volume()
*/
string *fullness_adjectives()
{
if (!max_volume) {
return ({ "totally", "empty" });
}
switch (100 * volume / max_volume) {
case 0..4: return ({ "totally", "empty" });
case 5..13: return ({ "empty" });
case 65..94: return ({ "full" });
case 95..100: return ({ "totally", "full" });
default: return ({ });
}
} /* fullness_adjectives() */
/* ok parse command stuff */
/** @@ignore yes */
string *parse_command_id_list() {
return potion_id + ::parse_command_id_list();
} /* parse_command_id_list() */
/* string *parse_command_plural_id_list() { return plurals; } */
/** @@ignore yes */
string *parse_command_adjectiv_id_list() {
return fullness_adjectives() + potion_adjective + ::parse_command_adjectiv_id_list();
} /* parse_command_adjectiv_id_list() */
/** @@ignore yes */
int sort_func(int *x, int *y)
{
if (x[1] < y[1]) return 1;
else return 0;
}
/** @@ignore yes */
mixed *mix_liq(mixed *arr1, mixed *arr2, int vol1, int vol2, int tot_vol)
{
int i, j; /* general indexes into arrays */
mixed *arr3;
arr3 = allocate(sizeof(arr1));
for (i = 0; i < sizeof(arr1); i++) {
arr3[i] = ({ arr1[i][0], arr1[i][1] * vol1 / tot_vol });
for (j = 0; j < sizeof(arr2); j++) {
if (arr2[j][0] == arr1[i][0]) {
arr3[i][1] += arr2[j][1] * vol2 / tot_vol;
arr2[j][1] += 100000; /* icky icky icky */
/* have to be able to restore this because (due to the magic of
arrays :( ) we are really working on the original */
break;
}
}
}
for (i = 0; i < sizeof(arr2); i++) {
if (arr2[i][1] >= 100000) {
arr2[i][1] -= 100000;
} else {
arr3 += ({ ({ arr2[i][0], arr2[i][1] * vol2 / tot_vol }) });
}
}
/* now lets sort it */
arr3 = sort_array(arr3, "sort_func", this_object());
/* now cull off 0's on the end */
for (i = sizeof(arr3) - 1; i >= 0; i--) {
if (arr3[i][1] > 0) break;
}
if (i < 0) arr3 = ({ });
else arr3 = arr3[0..i];
return arr3;
}
/** @@ignore yes */
mixed *merge_potions(mixed *potion1, mixed *potion2, int vol1, int vol2, int tot_vol)
{
mixed *result;
result = allocate(POTION_ATTRS_SIZE);
result[POTION_CONSISTENCY] =
(potion1[POTION_CONSISTENCY] * vol1 +
potion2[POTION_CONSISTENCY] * vol2) / tot_vol;
result[POTION_TRANSPARENCY] =
(potion1[POTION_TRANSPARENCY] * vol1 +
potion2[POTION_TRANSPARENCY] * vol2) / tot_vol;
result[POTION_NAMES] = mix_liq(potion1[POTION_NAMES], potion2[POTION_NAMES],
vol1, vol2, tot_vol);
result[POTION_COLOURS] = mix_liq(potion1[POTION_COLOURS], potion2[POTION_COLOURS],
vol1, vol2, tot_vol);
result[POTION_FLAVOURS] = mix_liq(potion1[POTION_FLAVOURS], potion2[POTION_FLAVOURS],
vol1, vol2, tot_vol);
result[POTION_SMELLS] = mix_liq(potion1[POTION_SMELLS], potion2[POTION_SMELLS],
vol1, vol2, tot_vol);
return result;
}
void set_misc_attrs(mixed *new_misc_attrs, int misc_vol)
{
misc_attrs = new_misc_attrs + ({ });
volume = water + misc_vol;
all_attrs = merge_potions(active_attrs, misc_attrs, water, volume - water, volume);
update_potion_parse();
if (leak_rate) set_heart_beat(1);
}
/**
* This method changes the concentration of the liquid to be a new
* and exciting concentration.
* @param potion the potion to change the concentration of
* @param new_conc the new concentration of the liquid
*/
mixed *change_concentration(mixed *potion, int new_conc)
{
mixed *newpotion;
int i;
newpotion = potion + ({ });
newpotion[POTION_CONSISTENCY] = newpotion[POTION_CONSISTENCY] * new_conc / 100;
newpotion[POTION_TRANSPARENCY] =
(100 - (100 - newpotion[POTION_TRANSPARENCY]) * new_conc / 100);
for (i = 0; i < sizeof(newpotion[POTION_NAMES]); i++) {
newpotion[POTION_NAMES][i][1] = newpotion[POTION_NAMES][i][1] * new_conc / 100;
}
for (i = 0; i < sizeof(newpotion[POTION_COLOURS]); i++) {
newpotion[POTION_COLOURS][i][1] = newpotion[POTION_COLOURS][i][1] * new_conc / 100;
}
for (i = 0; i < sizeof(newpotion[POTION_SMELLS]); i++) {
newpotion[POTION_SMELLS][i][1] = newpotion[POTION_SMELLS][i][1] * new_conc / 100;
}
for (i = 0; i < sizeof(newpotion[POTION_FLAVOURS]); i++) {
newpotion[POTION_FLAVOURS][i][1] = newpotion[POTION_FLAVOURS][i][1] * new_conc / 100;
}
return newpotion;
}
/**
* This method sets the quantity of the position space co-ordinate
* to be the new quantity.
* @param new_coord the new co-ordinate of the liquid
* @param new_quantity the new quantity of the liquid
*/
void set_ps_coord_quantity(int *new_coord, int new_quantity)
{
mixed *ps_attrs;
ps_attrs = (mixed *)POTION_SPACE_HANDLER->query_attrs_at(new_coord);
active_attrs = change_concentration(ps_attrs, new_quantity * 100 / water);
ps_quantity = new_quantity;
ps_coord = new_coord;
all_attrs = merge_potions(active_attrs, misc_attrs, water, volume - water, volume);
update_potion_parse();
(void)POTION_SPACE_HANDLER->potion_create(this_object(), new_coord, new_quantity);
}
void begin_config()
{
potion_id = allocate(9);
ps_coord = allocate(9);
}
void config(int vari, mixed cont)
{
potion_id[vari] = cont;
ps_coord[vari] = 1;
}
void end_config()
{
mixed *ps_attrs;
if (ps_coord[OC_VOL]) {
volume = potion_id[OC_VOL];
if (ps_coord[OC_MVOL]) water = volume - potion_id[OC_MVOL];
else water = potion_id[OC_WVOL];
} else {
water = potion_id[OC_WVOL];
volume = water + potion_id[OC_MVOL];
}
leak_rate = potion_id[OC_LEAKRATE];
if (leak_rate && volume) set_heart_beat(1);
if (ps_coord[OC_MAXVOL]) max_volume = potion_id[OC_MAXVOL];
else max_volume = volume;
ps_quantity = potion_id[OC_PSQUANT];
if (ps_coord[OC_MISCATTRS]) misc_attrs = potion_id[OC_MISCATTRS];
else misc_attrs = ({ 0, 100, ({ }), ({ }), ({ }), ({ }) });
if (ps_coord[OC_PSCOORD]) ps_coord = potion_id[OC_PSCOORD];
else ps_coord = ({ 0, 0 });
ps_attrs = (mixed *)POTION_SPACE_HANDLER->query_attrs_at(ps_coord);
active_attrs = change_concentration(ps_attrs, ps_quantity * 100 / water);
all_attrs = merge_potions(active_attrs, misc_attrs, water, volume - water, volume);
update_potion_parse();
(void)POTION_SPACE_HANDLER->potion_create(this_object(), ps_coord, ps_quantity);
}
/** @@ignore yes */
mixed stats() {
return container::stats() + close_lock_container::stats() + ({
({ "ps_quantity", query_ps_quantity() }),
({ "ps_coord", (pointerp(ps_coord) && sizeof(ps_coord) == 2) ?
"({ " + ps_coord[0] + ", " + ps_coord[1] + " })" :
sprintf("%O", ps_coord) }),
({ "volume", query_volume() + "" }),
({ "max volume", query_max_volume() }),
({ "water vol", query_water_volume() }),
({ "volume left", query_volume_left() }),
({ "weight left", query_weight_left() }),
({ "full_weight", query_full_weight(), }),
({ "leak_rate", query_leak_rate() + "" }),
});
}
/** @@ignore yes */
object query_parse_id(mixed *arr) {
volume_to_womble = 0;
return ::query_parse_id(arr);
} /* query_parse_id() */
/** @@ignore yes */
object query_frac_parse_id(mixed *arr) {
int i;
volume_to_womble = 0;
if (arr[P_THING] < 0) {
arr[P_THING]++;
if (arr[P_THING] != 0)
return 0;
volume_to_womble = volume*arr[P_TOP]/arr[P_BOT];
call_out("set_volume_to_womble", 0, 0);
arr[P_THING] = -1784628;
return this_object();
}
if (arr[P_THING] == 0)
if ((i=(arr[P_MAX_NUM]*arr[P_TOP])/arr[P_BOT]) > arr[P_CUR_NUM]++)
return this_object();
else
if (i+1 == arr[P_CUR_NUM]) {
volume_to_womble = volume*arr[P_TOP]/arr[P_BOT];
call_out("set_volume_to_womble", 0, 0);
return this_object();
}
else
return 0;
if ((i=(arr[P_THING]*arr[P_TOP])/arr[P_BOT]) > arr[P_CUR_NUM]++)
return this_object();
else
if (i+1 == arr[P_CUR_NUM]) {
volume_to_womble = volume*arr[P_TOP]/arr[P_BOT];
call_out("set_volume_to_womble", 0, 0);
return this_object();
}
return 0;
} /* query_frac_parse_id() */
/**
* This method removes some volume of liquid from the container.
* @see add_volume()
* @see query_volume()
*/
int remove_volume(int vol_lost)
{
int q_lost;
if (!volume) {
q_lost = ps_quantity;
water = 0;
ps_quantity = 0;
return q_lost;
}
q_lost = ps_quantity * vol_lost / volume;
water -= water * vol_lost / volume;
volume -= vol_lost;
ps_quantity -= q_lost;
return q_lost;
}
/** @ignore yes */
void heart_beat() {
int lost, off;
if (leak_rate == 0 || volume <= 0) {
set_heart_beat(0);
return;
}
if (hb_count--) return ;
hb_count = 10;
lost = leak_rate;
if (lost > volume)
lost = volume;
off = lost/100;
if (off > 10)
off = 10;
tell_room(environment(),
capitalize(query_liquid_short())+({ " drips slowly",
" drips",
" dribbles",
" trickles slowly",
" trickles",
" trickles rapidly",
" pours sluggishly",
" pours",
" streams",
" gushes",
" fountains", })[off]+" out of the "+
short(1)+".\n");
(void)remove_volume(lost);
if (!volume) {
set_heart_beat(0);
/* set_liquid_name(0); */
void_liquid();
}
} /* heart_beat() */
/**
* This method does the actual liquid transfer, as needed by the
* filling, emptying and pour operations.
* @param dest where the liquid is to go
* @param vol_misc the volume of non-water to move
* @param misc the attributes for the non-water
* @param vol_water the volume of water to move
* @param coord the co-ordinate of the liquid
* @param quantity the quantity of the potion space liquid
*/
void transfer_liquid_to(object dest, int vol_misc, mixed *misc,
int vol_water, int *coord, int quantity)
{
mixed *their_attrs;
int their_vol, their_water, their_quantity, new_quantity, new_misc_vol;
int *new_coord, *old_coord;
their_attrs = (mixed *)dest->query_misc_attrs();
their_vol = (int)dest->query_volume();
their_water = (int)dest->query_water_volume();
their_quantity = (int)dest->query_ps_quantity();
new_quantity = quantity + their_quantity;
if (!their_attrs) /* can't be a potion ... give up */
return ;
new_misc_vol = vol_misc + their_vol - their_water;
(void)dest->set_water_volume(their_water + vol_water);
if (new_misc_vol) {
their_attrs = merge_potions(misc_attrs, their_attrs,
vol_misc, their_vol - their_water,
new_misc_vol);
(void)dest->set_misc_attrs(their_attrs, new_misc_vol);
} else /* icck ... if we didn't do the set_misc_attrs, then their
volume is wrong, so we have to set it manually */
(void)dest->set_volume(their_water + vol_water);
old_coord = (int *)dest->query_ps_coord();
new_coord = allocate(2);
/* simple averaging ... */
if (pointerp(ps_coord) && new_quantity) {
new_coord[0] = (ps_coord[0] * quantity + old_coord[0] * their_quantity) /
new_quantity;
new_coord[1] = (ps_coord[1] * quantity + old_coord[1] * their_quantity) /
new_quantity;
dest->set_ps_coord_quantity(new_coord, new_quantity);
}
} /* transfer_liquid_to() */
/**
* This method returns true if the object is open and prints a message
* about the open status of the object.
* @return 1 if it is open, 0 if not
*/
int ensure_open()
{
if (query_locked()) {
write("The " + short(1) + " is locked.\n");
return 0;
}
if (query_closed()) /* has to be closed */
if (do_open()) {
write("You open the "+short(1)+".\n");
return 1;
} else {
write("You can't open the " + short(1) + ".\n");
return 0;
}
return 1;
} /* ensure_open() */
/** @ignore yes */
int do_pour(object *dest, string me, string him, string prep)
{
int amount_poured, volume_transferred, old_water, old_volume;
string liquid_desc;
if (sizeof(dest) > 1) {
write("Currently you can only pour into one object\n");
return 0;
}
if (!ensure_open()) return 0;
if (volume <= 0) {
write("The " + short(0) + " you are trying to pour out of is empty.\n");
return 0;
}
old_water = water;
old_volume = volume; /* so that when volume becomes 0 in this process */
liquid_desc = query_liquid_short();
if (volume_to_womble && volume_to_womble <= empty_formula())
volume_transferred = volume_to_womble;
else
volume_transferred = empty_formula();
amount_poured = remove_volume(volume_transferred);
if (volume_transferred > dest[0]->query_volume_left()) {
say(this_player()->short(0) + " attempts to pour from " + add_a(short(0))
+ " into " + add_a(dest[0]->short(0)) + " but ends up spilling "
+ liquid_desc + " all over the ground.\n");
write(capitalize(liquid_desc) + " spills on the floor as you try to pour "
+ "from the " + short(0) + " into the " + dest[0]->short(0) + ".\n");
amount_poured = (amount_poured * ((int)dest[0]->query_volume_left())) /
volume_transferred;
volume_transferred = (int)dest[0]->query_volume_left();
}
transfer_liquid_to(dest[0], volume_transferred * (old_volume - old_water) / old_volume,
misc_attrs, volume_transferred * old_water / old_volume, ps_coord, amount_poured);
this_player()->add_succeeded(dest[0]);
return 1;
}
/** @ignore yes */
int do_fill(object *to, mixed *args_b, mixed *args_a, mixed *args) {
int m, n, i, run_out, volume_needed, their_volume, their_max,
amount_poured, ok;
if (intp(args[1]) && intp(args[2])) {
m = args[0];
n = args[1];
if (m > n || m < 0 || n <= 0) {
notify_fail("Interesting fraction you have there!\n");
return 0;
}
} else {
m = 1;
n = 1;
}
if (query_locked()) {
notify_fail("The " + short(0) + " is locked!\n");
return 0;
}
if (query_closed()) {
if (do_open()) {
write("You open the " + short(0) + ".\n");
} else {
write("You cannot open the " + short(0) + ".\n");
return 0;
}
}
if (volume <= 0) {
write("The " + short(0) + " is bone dry!\n");
return 0;
}
run_out = 0;
for (i = 0; i < sizeof(to) && !run_out; i++) {
their_volume = (int)to[i]->query_volume();
their_max = (int)to[i]->query_max_volume();
if (their_max <= 0) {
write("The " + to[i]->short(0) +
" doesn't look like it can be filled!\n");
continue;
}
if (their_volume >= their_max) {
write("The " + to[i]->short(0) + " is full to the brim already.\n");
continue;
}
volume_needed = their_max * m / n;
if (their_volume >= volume_needed) {
write("The " + to[i]->short(0) + " is more than " + m + "/" + n +
" full already.\n");
continue;
}
ok++;
volume_needed -= their_volume;
if (volume_needed > empty_formula()) {
write("You drain the " + short(0) + " into the " + to[i]->short(0) +
" but it is not enough.\n");
volume_needed = empty_formula();
run_out = 1;
this_player()->add_succeeded(to[i]);
} else {
this_player()->add_succeeded(to[i]);
/*
write("You pour from the " + short(0) + " into the " +
to[i]->short(0) + ".\n");
*/
}
/*
say(this_player()->one_short() + " pours " + query_liquid_short() +
" from the " + short(0) + " into the " + to[i]->short(0) + ".\n");
*/
amount_poured = volume_needed * ps_quantity / volume;
transfer_liquid_to(to[i], volume_needed * (volume - water) / volume,
misc_attrs, volume_needed * water / volume, ps_coord, amount_poured);
amount_poured = remove_volume(volume_needed);
}
return ok;
} /* do_fill() */
/** @ignore yes */
int do_drink(object *dest, string me, string him, string prep)
{
int amount_drunk, amount_can_be_drunk;
if (sizeof(dest)) {
write("Drinking is a very simple operation - please don't complicate matters.\n");
return 0;
}
if (!ensure_open()) return 0;
if (volume <= 0) {
write("The " + short(0) + " is bone dry!\n");
return 0;
}
amount_can_be_drunk = (2000 - (int)this_player()->query_volume(2)) *
(int)this_player()->query_con() / 12;
/* should do some fudging to add +/- 5 mls or something */
/* possibly skill/stat dependant */
if (!volume_to_womble) volume_to_womble = empty_formula();
if (volume_to_womble > empty_formula()) volume_to_womble = empty_formula();
if (volume_to_womble > amount_can_be_drunk) {
write("You drink some of the liquid, but simply cannot fit it all in.\n");
volume_to_womble = amount_can_be_drunk;
}
amount_drunk = remove_volume(volume_to_womble);
(void)POTION_SPACE_HANDLER->potion_drunk(this_player(), ps_coord, amount_drunk);
this_player()->adjust_volume(2, volume_to_womble * 12 /
(int)this_player()->query_con());
switch ((this_player()->query_volume(2) + 100) / 200) {
case 5:
write("You feel mildly full of liquid.\n");
break;
case 6:
write("You feel very full of liquid.\n");
break;
case 7:
write("You feel pissed.\n");
break;
case 8:
write("You are awash with liquid.\n");
break;
case 9:
write("You are full to the brim with liquid.\n");
break;
case 10:
write("You feel you would burst if you drank any more.\n");
break;
}
return 1;
}
/** @ignore yes */
int do_empty(object *dest, string me, string him, string prep)
{
if (sizeof(dest)) {
write("Passing on to pour ... bad move.\n");
return do_pour(dest, me, him, prep);
}
/* this completely fails to work :( ^^^ */
if (!ensure_open()) { write("It aint open!\n"); return 0; }
if (volume == 0) {
write("The " + short(0) + " is already empty.\n");
return 0;
}
if (volume_to_womble && volume_to_womble <= empty_formula())
(void)remove_volume(volume_to_womble);
else
(void)remove_volume(empty_formula());
/* should check spillage */
return 1;
}
/** @ignore yes */
int do_splash(object *dest, string me, string him, string prep) {
/* note that spashing needs to be changed to make the amount that
actually gets to the targe be related to some skill ... */
int amount_splashed;
if (sizeof(dest) > 1) {
write("You can only splash one object at a time.\n");
return 0;
}
if (!sizeof(dest))
return 0;
if (!ensure_open()) return 0;
if (volume_to_womble && volume_to_womble <= empty_formula())
amount_splashed = remove_volume(volume_to_womble);
else
amount_splashed = remove_volume(empty_formula());
(void)POTION_SPACE_HANDLER->potion_touch(dest[0], ps_coord, amount_splashed);
(void)this_player()->add_succeeded(dest[0]);
return 1;
}
/** @ignore yes */
int do_rub(object *dest, string me, string him, string prep) {
int amount_rubbed;
if (sizeof(dest) > 1) {
write("You can only "+query_verb()+" on to one object at a time.\n");
return 0;
}
if (!sizeof(dest))
return 0;
if (environment(dest[0]) != this_player()) {
write("You can only "+query_verb()+" on to an object in your inventory.\n");
return 0;
}
if (!ensure_open()) return 0;
if (volume_to_womble && volume_to_womble <= empty_formula())
amount_rubbed = remove_volume(volume_to_womble);
else
amount_rubbed = remove_volume(empty_formula());
(void)POTION_SPACE_HANDLER->potion_touch(dest[0], ps_coord, amount_rubbed);
(void)this_player()->add_succeeded(dest[0]);
return 1;
}
/** @ignore yes */
void do_apply(object *dest, string me, string him, string prep ) {
do_rub( dest, me, him, prep );
}
#define TASTE_AMOUNT 5
/** @ignore yes */
int do_taste() {
int amount_tasted;
string desc;
mixed *group;
int i;
/* be kind to tasters! */
if (!ensure_open()) return 0;
if (volume < TASTE_AMOUNT) {
write("There is no liquid to taste.\n");
return 0;
}
desc = "The " + query_liquid_short();
if (!sizeof(all_attrs[POTION_FLAVOURS]) ||
all_attrs[POTION_FLAVOURS][0][1] < VERY_SMALL_AMOUNT)
desc += " has no discernible flavour";
else {
group = ({ });
for (i = 0; i < sizeof(all_attrs[POTION_FLAVOURS]) &&
all_attrs[POTION_FLAVOURS][i][1] >= SMALL_AMOUNT; i++)
group += all_attrs[POTION_FLAVOURS][i][0..0];
if (sizeof(group)) {
desc += " tastes of " + query_multiple_short(group);
if (i < sizeof(all_attrs[POTION_FLAVOURS]) &&
all_attrs[POTION_FLAVOURS][i][1] >= VERY_SMALL_AMOUNT)
desc += " with a faint hint of ";
} else desc += " tastes faintly of ";
group = ({ });
for (; i < sizeof(all_attrs[POTION_FLAVOURS]) &&
all_attrs[POTION_FLAVOURS][i][1] >= VERY_SMALL_AMOUNT; i++)
group += all_attrs[POTION_FLAVOURS][i][0..0];
if (sizeof(group)) desc += query_multiple_short(group);
}
write(desc + ".\n");
say(this_player()->one_short() + " takes a small sip from the " +
short(0) + ".\n");
amount_tasted = remove_volume(TASTE_AMOUNT);
(void)POTION_SPACE_HANDLER->potion_drunk(this_player(), ps_coord, TASTE_AMOUNT);
return 1;
}
/** @ignore yes */
int do_smell()
{
string desc;
string *group;
int i;
/* be kind to smellers! */
if (!ensure_open()) return 0;
if (volume < 1) {
write("There is no liquid to smell.\n");
return 0;
}
desc = "The " + query_liquid_short();
if (!sizeof(all_attrs[POTION_SMELLS]) ||
all_attrs[POTION_SMELLS][0][1] < VERY_SMALL_AMOUNT)
desc += " has no distinct aroma";
else {
group = ({ });
for (i = 0; i < sizeof(all_attrs[POTION_SMELLS]) &&
all_attrs[POTION_SMELLS][i][1] >= SMALL_AMOUNT; i++)
group += all_attrs[POTION_SMELLS][i][0..0];
if (sizeof(group)) {
desc += " smells of " + query_multiple_short(group);
if (i < sizeof(all_attrs[POTION_SMELLS]) &&
all_attrs[POTION_SMELLS][i][1] >= VERY_SMALL_AMOUNT)
desc += " with a faint hint of ";
} else desc += " smells faintly of ";
group = ({ });
for (; i < sizeof(all_attrs[POTION_SMELLS]) &&
all_attrs[POTION_SMELLS][i][1] >= VERY_SMALL_AMOUNT; i++)
group += all_attrs[POTION_SMELLS][i][0..0];
if (sizeof(group)) desc += query_multiple_short(group);
}
write(desc + ".\n");
say(this_player()->one_short() + " takes a whiff of the " +
short(0) + ".\n");
(void)POTION_SPACE_HANDLER->potion_smell(this_player(), ps_coord, ps_quantity * 100 / volume);
return 1;
}
/** @ignore yes */
mapping int_query_static_auto_load() {
mapping tmp;
tmp = ::int_query_static_auto_load();
return ([ "::" : tmp,
"leak rate" : leak_rate,
"full weight" : full_weight,
"trans" : query_transparent(),
"difficulty" : query_difficulty(),
"key" : query_key(),
"trap open func" : query_open_trap_func(),
"trap lock func" : query_lock_trap_func(),
"trap open ob" : query_open_trap_ob(),
"trap lock ob" : query_lock_trap_ob(),
"max volume" : max_volume,
]);
} /* int_query_static_auto_load() */
/** @ignore yes */
mapping query_dynamic_auto_load() {
if (!query_name() || query_name() == "object") {
return 0;
}
return ([
"::" : ::query_dynamic_auto_load(),
"locked" : query_locked(),
"stuck" : query_stuck(),
"closed" : query_closed(),
"volume" : volume,
"water" : water,
"misc attrs" : misc_attrs,
"ps coord" : ps_coord,
"ps quantity" : ps_quantity,
]);
} /* query_dynamic_auto_load() */
/** @ignore yes */
void init_dynamic_arg(mapping map) {
mixed *ps_attrs;
object money;
if (map["::"])
::init_dynamic_arg(map["::"]);
if (sizeof(map["money"])) {
money = clone_object("/obj/money");
money->set_money_array(map["money"]);
money->move(this_object());
}
if (map["locked"]) {
set_locked();
} else {
set_unlocked();
}
set_stuck(map["stuck"]);
if (map["closed"]) {
set_closed();
} else {
set_open();
}
volume = map["volume"];
set_water_volume(map["water"]);
if (volume == 0) {
void_liquid();
update_potion_parse();
return;
}
misc_attrs = map["misc attrs"];
ps_quantity = map["ps quantity"];
ps_coord = map["ps coord"];
ps_attrs = (mixed *)POTION_SPACE_HANDLER->query_attrs_at(ps_coord);
if(!water) water = 1;
active_attrs = change_concentration(ps_attrs, ps_quantity * 100 / water);
all_attrs = merge_potions(active_attrs, misc_attrs, water, volume - water, volume);
update_potion_parse();
} /* init_dynamic_arg() */
/** @ignore yes */
void init_static_arg(mapping args) {
if (args["::"]) {
::init_static_arg(args["::"]);
}
if (!undefinedp(args["leak rate"])) {
leak_rate = args["leak rate"];
}
if (!undefinedp(args["full weight"])) {
full_weight = args["full weight"];
}
if (!undefinedp(args["trans"])) {
if (args["trans"]) {
set_transparent();
} else {
set_opaque();
}
}
if (!undefinedp(args["difficulty"])) {
set_difficulty(args["difficulty"]);
}
if (!undefinedp(args["key"])) {
set_key(args["key"]);
}
if (!undefinedp(args["trap open func"])) {
set_open_trap(args["trap open ob"], args["trap open func"]);
}
if (!undefinedp(args["trap lock func"])) {
set_lock_trap(args["trap lock ob"], args["trap lock func"]);
}
if (!undefinedp(args["max volume"])) {
max_volume = args["max volume"];
}
} /* init_static_arg() */
/** @ignore yes
* Do it all the time for containers... They could have things in them.
* too hard to andle rhe special cases you know...
*/
mixed query_static_auto_load() {
if (!query_name() || query_name() == "object") return 0;
if (file_name(this_object())[0..13] == "/obj/container")
return int_query_static_auto_load();
return ([ ]);
} /* query_static_auto_load() */
/**
* This method stops the container being added when it is
* closed. It also handles the same flags as the liing
* object. We assume this is not the same
* as the default containers used
* by things like item rooms and such.
* @param ob the object being added
* @param flag the addition flag
* @see /std/basic/move.c
*/
int test_add(object ob, int flag) {
return !query_closed() && !flag;
} /* test_addd() */
/** @ignore yes */
int can_find_match_recurse_into(object looker) {
if (query_closed()) {
return 0;
}
return ::can_find_match_recurse_into(looker);
} /* can_find_match_recurse_into() */
/** @ignore yes */
int test_remove(object ob, int flag) { return !query_closed(); }
/** @ignore yes */
varargs int move(mixed dest, string messin, string messout) {
int result;
object from;
object to;
from = environment();
result = ::move(dest, messin, messout);
if (result == MOVE_OK) {
to = environment();
we_moved(from, to);
}
return result;
} /* move() */
/** @ignore yes */
void dest_me() {
close_lock_container::dest_me();
container::dest_me();
} /* dest_me() */