! --------------------------------------------------------------------
!
! RECEPTACLES
! ===========
! (containers with defined capacities)
! for use with INFORM 6.x, (c) 1999 Graham Nelson
! Version 1.0 (2002-July-06)
!
! Written & copyright (c) 2002, 2006 by Peer Schaefer.
!
! The distribution of this file for free or for profit is allowed, as
! long as this copyright notice and the disclaimer (see below) remain
! intact. You may distribute modified versions of this file under the
! same terms, as long as you place a notice on top of the file that it
! is modified by you, and provide your name and the date of the
! modifications. The unmodified or modified version distributed by you
! must be (re)distributable, modifyable and usable under the same terms
! as this version.
!
! You may use this library unaltered or in a modified version freely
! for your own games, commercial or not. It would be nice if you give
! me some credit or provide the sourcecode, but that is not legally
! required.
!
! NO WARRANTY, NO LIABILITY. PROVIDED FREE OF CHARGE "AS IS". USE ON
! YOUR OWN RISK!
!
! Bug reports, comments and suggestions to:
[email protected]
!
! The latest version should be available at:
!
http://www.wolldingwacht.de/if/recept.html
!
! --------------------------------------------------------------------
!
!
! REFERENCE
! =========
! This library contribution implements a new class of objects called
! "receptacles". Receptacles are containers (or supporters) that are
! aware of weight, volume and size. Every time the player tries to put
! an object into such a receptacle the receptacle checks whether its
! remaining storage-capacity is sufficient or not.
!
! To define its weight, volume and size every object in the game can
! (but hasn't to) provide the properties
! - weight
! - volume
! - size ("size" represents the maximum length on any axis, e.g.
! the length of an arrow or of a staff. It's obvious that
! the volume of a quiver is "used up" when you store many
! arrows in it, but the length of the quiver is not "used
! up" by the length of the stored arrows: it only
! indicates whether an arrow is too long for the quiver
! or not.)
!
! Each of these three properties can be a numerical value or a
! routine that returns a numerical value. If one of these properties
! is missing or has the value 0 (zero), the respective dimension of
! the object is 0 (that means that the object has no or only
! neglectable weight, volume or size).
!
! Please notice: Weight, volume and size are measured in abstract
! "units" (plain numbers). Whether one "unit" of e.g.
! weight is a grain, a british pound, a kilogram, an
! US-ton or 1 sun-mass is completely up to you and
! your program.
!
! To create a container which automatically checks weight, volume and
! size use the new "receptacle"-class. Containers of this class can
! provide three new properties:
! - capacity_weight
! - capacity_volume
! - capacity_size
! Each of these three properties can be a numerical value or a routine
! that returns a numerical value. If one of these properties is missing
! or has the value INFINITE_CAPACITY (a predefined constant), the
! respective capacity of the receptacle is infinite.
!
! Of course containers/receptacles can also provide weight, volume and
! size (since they are not only containers/receptacles but also objects
! that can be stored inside other containers/receptacles).
!
! For clarification:
! * The player can store multiple objects in a receptacle, as long as
! their total-weight does not exceed the capacity_weight of the
! receptacle.
! * The player can store multiple objects in a receptacle, as long as
! their total-volume does not exceed the capacity_volume of the
! receptacle.
! * In other words: capacity_weight and capacity_volume are "used up"
! by objects stored inside the receptacle.
! * capacity_size is a different story: it's not "used up" but
! checked seperately for each object.
!
! As a little extra a receptacle can also provide the new property
! capacity_number. That property can be a number or a routine that
! returns a number. It indicates how many objects (maximum) can be
! stored inside that receptacle. Any objects beyond this maximum are
! rejected.
!
!
! Some technical details:
! -----------------------
! * Calculating the weight of a container (or supporter) is a
! recursive process: The weights of all (immediate) child-objects
! are added to the weight of the container itself; the total-
! weights of these child-objects are calculated by adding up the
! weights of THEIR child-objects; and so forth.
! * If the weight of an object is provided as a routine, this routine
! should return the TOTAL weight of the object (including the
! weight of all child-objects inside, grand-child-objects etc).
! The weights of child-objects are NOT added automatically in this
! case. That gives you more flexibility in the creation of special
! containers (e.g. magical bags that weigh less than their
! contents).
! * Volume and size of childrens are NOT added to the objects
! volume/size (assuming that standard-containers are not flexible
! and have fixed proportions). To override this you can provide
! your own VOLUME and SIZE properties, which calculate volume resp.
! size at run-time (see example below).
! * It's totaly legal to create a container whose volume_capacity is
! greater than it's volume (it's pretty inplausible, but this way
! you can create magical bags, black holes and other weird things).
!
!
! DEBUGGING VERBS:
! ----------------
! When compiled in debug-mode recept.h provides three meta-verbs:
! $weigh OBJECT - prints the weight of the object
! $measure OBJECT - prints all dimensions of an object
! $capacity OBJECT - prints the capacities of a receptacle
!
!
!
! EXAMPLE 1:
! ----------
! Receptacle box "box" with name "box",
! volume 10, ! The box itself has a volume of 10
! capacity_volume 9, ! And it can store a volume of 9
! has container;
!
! Object stone "stone" with name "stone",
! volume 2; ! This stone has a volume of 2
!
! The lines above create a box with a volume of 10 and a capacity of 9,
! and a stone with a volume of 2. The player can put up to 4 stones in
! the box (with a total volume of 4x2=8). A fifth stone can't be stored
! in the box, since the capacity of the box is 9 and the total volume
! of 5 stones would be 10.
!
!
! EXAMPLE 2:
! ----------
! The following example creates a wooden box and a steel box:
!
! Receptacle wooden_box "wooden box"
! with name "wooden" "box",
! volume 10, ! The box itself has a volume of 10
! ! units
! capacity_volume 9, ! And it can store objects up to a
! ! volume of 9 units
! has container;
!
! Receptacle steel_box "steel box"
! with name "steel" "box",
! volume 8, ! The box itself has a volume of 8
! ! units
! capacity_volume 7, ! And it can store objects up to a
! ! volume of 7 units
! has container;
!
! You can put the steel box into the wooden box (volume 8 fits in
! capacity 9) but not the wooden box into the steel box (volume 10
! doesn't fit in capacity 7). If you put something with a volume of 2
! or greater into the wooden box, you can't put the steel box into
! it because that would require a free volume of 8 or more.
!
!
! EXAMPLE 3:
! ----------
! Volume and size of childrens are NOT added to the objects volume or
! size (assuming that containers are not flexible and have fixed
! proportions), so if you want to create a flexible bag whose volume
! grows if objects are stored inside, you should code an appropriate
! routine as the volume property:
!
! Receptacle -> bag "flexible bag"
! with name "flexible" "bag",
! capacity_volume 20,
! capacity_size 5,
! volume [ v i;
! v = 1; ! Minimal volume.
! objectloop (i in bag) ! Add volumes of all
! v = v + VolumeOf (i); ! immediate childs.
! return v;
! ],
! size [ s i;
! s = 1; ! Minimal size when empty.
! objectloop (i in bag) ! Find the largest child:
! if (SizeOf (i) > s) s = SizeOf (i);
! return s; ! (The size of the largest
! ], ! immediate child determines
! has container; ! the size of the bag.)
!
!
! EXAMPLE 4:
! ----------
! The weights of childrens are added automatically to the objects
! weight. You can override this by providing an own weight-routine.
! The following example creates a wonder-bag, whose total-weight is
! only half the total-weight of it's contents:
!
! Receptacle -> wonder_bag "wonder bag"
! with name "wonder" "magic" "bag",
! capacity_volume 100,
! weight [ w i;
! w = 1; ! Base weight of bag is 1
! objectloop (i in wonder_bag)
! w = w + WeightOf (i); ! Add up weights...
! return (w/2); ! ...and return 50%
! ],
! has container;
!
!
! CONTACT:
! --------
! Bug reports, suggestions, questions, comments and congratulations to:
!
[email protected]
! (or, if that fails, to:
[email protected])
System_file; ! to avoid a warning for not using the
! __DUMMY_RECEPT class
Class __DUMMY_RECEPT ! Defines the seven new properties without
with ! using up any program-space or
weight 0, ! runtime-memory
size 0,
volume 0,
capacity_weight 0,
capacity_size 0,
capacity_volume 0,
capacity_number 0;
Constant INFINITE_CAPACITY -1; ! (-1) symbolizes an infinite capacity
! --------------------------------------------------------
! The following functions calculate the weight, volume and size
! of any given object.
[ WeightOf obj w i;
if (obj provides weight)
{
if (metaclass(obj.weight) == Routine)
return indirect (obj.weight);
w = obj.weight;
} else w = 0;
if ((obj has container) || (obj has supporter))
objectloop (i in obj)
w = w + WeightOf (i); ! Add weight of child-
! objects
return w;
];
[ SizeOf obj;
if (obj provides size)
{
if (metaclass(obj.size) == Routine)
return indirect (obj.size);
return obj.size;
};
return 0;
];
[ VolumeOf obj;
if (obj provides volume)
{
if (metaclass(obj.volume) == Routine)
return indirect (obj.volume);
return obj.volume;
};
return 0;
];
! --------------------------------------------------------
! The following functions calculate the capacity of any given
! container or supporter.
[ CapacityWeightOf obj;
if (obj provides capacity_weight)
{
if (metaclass(obj.capacity_weight) == Routine)
return indirect (obj.capacity_weight);
return obj.capacity_weight;
}
return INFINITE_CAPACITY; ! Unlimited weight capacity
];
[ CapacityVolumeOf obj;
if (obj provides capacity_volume)
{
if (metaclass(obj.capacity_volume) == Routine)
return indirect (obj.capacity_volume);
return obj.capacity_volume;
}
return INFINITE_CAPACITY; ! Unlimited volume capacity
];
[ CapacitySizeOf obj;
if (obj provides capacity_size)
{
if (metaclass(obj.capacity_size) == Routine)
return indirect (obj.capacity_size);
return obj.capacity_size;
}
return INFINITE_CAPACITY; ! Unlimited size capacity
];
[ CapacityNumberOf obj;
if (obj provides capacity_number)
{
if (metaclass(obj.capacity_number) == Routine)
return indirect (obj.capacity_number);
return obj.capacity_number;
}
return INFINITE_CAPACITY; ! Unlimited number of objects
];
! --------------------------------------------------------
Class Receptacle
with
before [ s i;
Receive:
! Check weight:
if ( CapacityWeightOf (self) ~= INFINITE_CAPACITY )
! not unlimited
! capacity
{
if ( WeightOf(noun) > CapacityWeightOf (self) )
print_ret (The) noun, " is too heavy for ", (the) self, ".";
s = 0;
objectloop (i in self) ! calculate the
s = s + WeightOf(i); ! weight of all
! contents
if ( (s + WeightOf(noun)) > CapacityWeightOf (self) )
print_ret (The) self, " has reached it's capacity.";
};
! Check volume:
if ( CapacityVolumeOf (self) ~= INFINITE_CAPACITY )
! not unlimited
! capacity
{
if ( VolumeOf(noun) > CapacityVolumeOf (self) )
print_ret (The) noun, " does not fit into ", (the) self, ".";
s = 0;
objectloop (i in self) ! calculate the
s = s + VolumeOf(i); ! volume of all
! contents
if ( (s + VolumeOf(noun)) > CapacityVolumeOf (self) )
print_ret (The) self, " has reached it's capacity.";
};
! Check size:
if ( CapacitySizeOf (self) ~= INFINITE_CAPACITY )
! not unlimited
! capacity
{
if ( SizeOf(noun) > CapacitySizeOf (self) )
print_ret (The) noun, " is too large for ", (the) self, ".";
};
! Check number:
if ( CapacityNumberOf (self) ~= INFINITE_CAPACITY )
! not unlimited
! capacity
{
s = 0;
objectloop (i in self)
s++;
if ( (s+1) > CapacityNumberOf (self) )
print_ret (The) self, " contains too many objects.";
};
rfalse;
];
#ifdef DEBUG;
Verb meta '$weigh' * noun -> MetaWeigh;
Verb meta '$measure' * noun -> MetaMeasure;
Verb meta '$capacity' * noun -> MetaCapacity;
[ MetaWeighSub;
print_ret (The) noun, " weighs ",
WeightOf (noun), " units.";
];
[ MetaMeasureSub;
print (The) noun, ":^";
print "Weight: ", WeightOf(noun), " units^";
print "Size: ", SizeOf(noun), " units^";
print "Volume: ", VolumeOf(noun), " units^";
rtrue;
];
[ MetaCapacitySub;
print (The) noun, ":^";
print "Capacity (weight): ";
if (CapacityWeightOf(noun) == INFINITE_CAPACITY)
print "infinite^";
else
print CapacityWeightOf(noun), " units^";
print "Capacity (size): ";
if (CapacitySizeOf(noun) == INFINITE_CAPACITY)
print "infinite^";
else
print CapacitySizeOf(noun), " units^";
print "Capacity (volume): ";
if (CapacityVolumeOf(noun) == INFINITE_CAPACITY)
print "infinite^";
else
print CapacityVolumeOf(noun), " units^";
print "Capacity (number of objects): ";
if (CapacityNumberOf(noun) == INFINITE_CAPACITY)
print "infinite^";
else
print CapacityNumberOf(noun), "^";
rtrue;
];
#endif;
! End