<html><!-- #BeginTemplate "/Templates/Body Text.dwt" -->
<head>
<title> Discworld Documentation </title>
</head>
<body bgcolor="#ffffff" TEXT="#000030" LINK="#4a529c" VLINK="#b57339">
<table width="75%" border="0">
<tr>
<td><font face="arial,helvetica"><img align=left src="http://discworld.imaginary.com/external//pics/dw4.gif"></font></td>
<td><font face="arial,helvetica">
<h2>Discworld Documentation:</h2>
<h2>LPC for Dummies</h2>
</font>
<p><font size="+1"><!-- #BeginEditable "Title" --><font size="+1"><b>Tutorial
Six - Putting It All Together - Advanced Objects</b></font><!-- #EndEditable --></font></p>
<p><i>N.B - This is a work in progress... a living document if you like.
If it appears to be dead when you view it, don't worry. It's most likely
just playing possum.</i></p>
<p>Comments on these chapters and tutorials can be e-mailed to <a href="mailto:drakkos@cableinet.co.uk">Drakkos.</a></p>
</td>
</tr>
</table>
<br>
<!-- #BeginEditable "Body" -->
<p>Woo, here it is. The final tutorial of this coding document. You've come a
long way already... you're just growing up so fast. <b>*sniffle* </b>
<p>In this final tutorial, we're going to take another look at objects and some
of the nifty things we can do with them. We've already seen how to code basic
weapons and clothes. We're now going to look at how to make our objects somewhat
more interesting and interactive. Sounds like fnu? Well, let's hope so!
<p><b>Objects Within Objects! </b>
<p>It's always nice to be able to carry objects nice and easily when wandering
from place to place. Backpack, satchels, and nice big pocketses are very useful
for this. The file that deals with most of the container code is /std/container,
but the file you inherit in most cases depends on what kind of container you
are creating. There are a number of containers in /obj/, allowing for all kinds
of storage objects to be created:
<p>
<div align="center">
<table width="75%" border="0">
<tr>
<td><b>"/obj/clothing"</b></td>
<td>/obj/clothing inherits /std/container as a part of its default setup.
You can use the add_pocket() method to add storage to your clothing. More
on this later.</td>
</tr>
<tr>
<td><b>"/obj/baggage"</b></td>
<td>This file would be used when you're creating items such as sacks and
chests.</td>
</tr>
<tr>
<td><b>"/obj/vessel"</b></td>
<td>This file should be inherited when creating containers designed to hold
liquids. Glasses, bottles, and so on should inherit this file.</td>
</tr>
<tr>
<td><b>"/obj/cont_save"</b></td>
<td>This files should be inherited when you want a baggage type container
to save its contents when objects are added or removed from it.</td>
</tr>
</table>
</div>
<p>
<p>Except for containers using /obj/clothing, we make our containers in exactly
the same way as we would any other object. We start off with a comment, an inherit,
and setup:
<blockquote>
<p><code>/* <br>
This is a container, For containing fings. <br>
Wrytten by Drakkos Thee Creator. <br>
20/10/2000 <br>
*/ </code></p>
<p><code>inherit "/obj/baggage"; </code></p>
<p><code>void setup() { <br>
set_name("bag"); <br>
set_short("little green bag"); <br>
set_long("This is a little green bag.\n"); <br>
add_adjective(({"little", "green"})); <br>
set_weight(5); <br>
set_max_weight(20); <br>
} </code></p>
</blockquote>
<p>Woo... isn't that easy? The only new information her is set_max_weight(). This
function simply determines how much inventory the object can hold... in this
case, twenty weight units. The weight of the container itself does not count
towards this, so you could put twenty weight units into the bag. The total weight
of the bag after that would be twenty units, plus the five units the bag weights
itself... giving a total weight of twenty-five units.
<p>Well... that was deceptively easy. Is that really all there is to it? Indeed
it is! At least, for baggage type containers. We need to do things slightly
differently for vessels and clothing. For clothing, we use the add_pocket method
instead. This takes two arguments, a string and an integer. The string is the
type of pocket (breast pocket, trouser pocket, etc), and the integer is the
maximum weight that pocket can hold. We've already seen how to create dungarees
in our third tutorial. We would simply add the line:
<blockquote>
<p><code>add_pocket("dungaree", 10); </code></p>
</blockquote>
<p>To our dungarees to give them a dungaree pocket that can hold ten units of
weight. Simple!
<p> For vessels, however, we also need to set a max_volume in addition to a max_weight.
This determines how much of a liquid the container can hold. For reference,
4000 units is roughly a litre of fluid. So if we have a vessel that has the
line:
<blockquote>
<p><code>set_max_volume(4000); </code></p>
</blockquote>
<p>It means that it can hold a litre of liquid before filling up. The vessel inheritable
deals with all the neato stuff like pouring vessels into other vessels and so
on. We're going to continue on with our baggage example, however, since that's
what we've started to code.
<p>It's very simple to make containers, as you can see. But there are a number
of nifty things you can do to make your containers more interesting. The functions
test_add and test_remove, for example, can be used to determine whether an object
may be added or removed from a container. The object you inherit will define
these as standard, but sometimes it is useful to redefine the function to allow
for specific behaviour.
<p>For example, since this is a bag for you only, let's make it so only you can
add or remove to it. Test_add() takes two arguments. The first in an object,
and is the reference to the item being added to the container. The second is
the move flag, but we don't need to worry about that at the moment. Test_add
will return a 1 if the object can be added, and a 0 if it cannot:
<blockquote>
<p> <code>int test_add(object ob, int flag) { <br>
if(this_player()->query_name() != "your_name_here")
{ <br>
return 0; <br>
} <br>
else { <br>
return ::test_add(ob, flag);
<br>
} <br>
}</code></p>
</blockquote>
<p> Remember that :: stuff from the theoretical part on inheritence? To recap,
it simply means 'execute the inherited function test_add'. In this case, we're
calling the inherited function and returning the return of that function. This
ensures that all the code dealing with objects moving into containers is executed
properly. In other words, we need to execute the inherited function, or we may
end up with a situation where we can put objects into the container regardless
of how much is already in it. We do something similar for test_remove, except
that test_remove takes three arguments. The first is the object, the second
is the move flag, and the third is the destination of the object:
<blockquote>
<p><code>int test_remove(object ob, int flag, mixed dest) { <br>
if(this_player()->query_name() != "your_name_here")
{ <br>
return 0; <br>
} <br>
else { <br>
return ::test_remove(ob, flag,
dest); <br>
} <br>
} </code></p>
</blockquote>
<p>So now we have a nice, safe, secure bag that only you can add or remove stuff
from. Neat? Indeed!
<p><b>Wear And Remove Functions!</b>
<p>Okay, so we've got a neat little bag now. But we need something else to outfit
ourselves with. We've already coded up some simple clothing for our NPC, but
now we're going to code up something for ourselves. Something nice and stylish...
something tasteful, but not conservative, that hints at impeccable taste and
a playful sense of fun. Hmm... what could possibly fit that bill? Oh, I know!
Let's code ourselves a pair of flourescent pink flares. You know you want to!
Right, so we start off with our comment, our inherit, and our setup. We're also
going to give our flares a couple of pockets, just because we can:
<blockquote>
<p><code>/* <br>
Flourescent Flared Trousers (Pink!) <br>
Wrytten by Drakkos Thee Creator <br>
21/10/2000 <br>
*/ </code></p>
<p><code>inherit "/obj/clothing"; </code></p>
<p><code>void setup() { <br>
set_name("trousers"); <br>
set_short("pair of flourescent pink flared trousers");
<br>
add_adjective(({"pair of", "flourescent", "pink",
"flared"})); <br>
set_long("This is a pair of extremely stylish, extremely
" <br>
"tasteful, flourescent pink
flared trousers.\n"); <br>
set_weight(10); <br>
set_value(0); <br>
set_type("trousers"); <br>
set_main_plural("pairs of flourescent pink flared
trousers"); <br>
add_plural("trousers"); <br>
setup_clothing(10000); <br>
add_pocket("left", 20); <br>
add_pocket("right", 20); <br>
} </code></p>
</blockquote>
<p>Now, that's all pretty straight forward. But they really are such stylish trousers.
It would be terrible if anyone but you could wear them. It would, wouldn't it?
Well, let's make it so anyone but us trying to wear them get a horrible, scary
message. We do this by using set_wear_remove_func(). This takes two arguments.
The first should be the filename of your trousers, the second should be a string
containing the name of the function to call:
<blockquote>
<p><code>set_wear_remove_func(base_name(this_object()), "do_wear_stuff"); </code></p>
</blockquote>
<p>base_name(this_object()) will simply return the base filename of your trousers
file. So if your trousers were stored in /w/your_name/clothing.c, then it would
return "/w/your_name/clothing". We use base_name() rather than the seemingly
more intuitive file_name, because file_name returns the name of the object,
*plus* the object reference of it, so you end up with something like '/w/your_name/clothing#2517552'.
Base_name simply disregards the object reference, so is what we want in this
case.
<p>Our function, do_wear_stuff(), takes one object argument. If the clothing is
being removed, then the argument will be 0. If it is being worn, then the argument
will be the object reference of the item. Confusing? Well, let's look at this
example:
<blockquote>
<p><code>void do_wear_stuff(object ob) { <br>
if(this_player()->query_name() != "your_name_here")
{ <br>
if(!ob) { <br>
tell_object(this_player(),
"You heave a sigh of relief as " <br>
"you
remove the ghastly garment.\n"); <br>
} <br>
else { <br>
tell_object(this_player(),
"Ye gods, are you really going "<br>
"to
wear those hideous things?!\n"); <br>
} <br>
} <br>
else { <br>
if(!ob) { <br>
tell_object(this_player(),
"Awww, why are you taking off your " <br>
"super-cool
slacks?\n"); <br>
} <br>
else { <br>
tell_object(this_player(),
"You feel Real Cool as you slip "<br>
"into
your fabulous flares!\n"); <br>
} <br>
} <br>
} </code></p>
</blockquote>
<p>Giving the trousers to my fashion concious helper, Draktest, he puts them on
and we see:
<blockquote>
<p><code>Ye gods, are you really going to wear those hideous things?! <br>
You wear a pair of flourescent pink flared trousers. </code></p>
</blockquote>
<p>'Lawks', says Draktest, and quickly wiggles out of them:
<blockquote>
<p><code>You heave a sigh of relief as you remove the ghastly garment. <br>
You remove a pair of flourescent pink flared trousers. </code></p>
</blockquote>
<p>Hehe! And now when *we* wear them:
<blockquote>
<p><code>You feel Real Cool as you slip into your fabulous flares! <br>
You wear a pair of flourescent pink flared trousers.</code></p>
</blockquote>
<p> And when, later on, we take them off:
<blockquote>
<p> <code>Awww, why are you taking off your super-cool slacks? <br>
You remove a pair of flourescent pink flared trousers. </code></p>
</blockquote>
<p>Whee! Now *no-one* will want to wear our trendy trousers. And who can blame
them? I mean, with a message like that, you'd be fooled into thinking you weren't
being fashionable! But, of course, as if! But... our flourescent trousers aren't
actually flourescent:
<blockquote>
<p><code>> bright <br>
The pair of flourescent pink flared trousers produces no light at all. </code></p>
</blockquote>
<p>They should be so flourescent that we can guide small aircraft down from the
skies! Well... maybe not *that* flourescent, but they should at least give out
some light. So let's add another line to our setup:
<blockquote>
<p><code>set_light(20); </code></p>
</blockquote>
<p>And voila:
<blockquote>
<p><code>> bright <br>
The pair of flourescent pink flared trousers produces a bit of light.</code>
</p>
</blockquote>
<p>Whee! Now we're fashionable, *and* conspicious in dark rooms! What else could
a fledgling creator possible want?
<p><b>Wield Functions and Attack Functions! </b>
<p>I'll tell you what else we want! We want a weapon! A mighty weapon, something
to strike fear into the hearts of all! What should we code for ourselves. Hmm...
a sword? No... everyone and their monkey has a sword. A mace? No... too heavy.
Hmm... oh, wait, I know! Let's code ourselves a nice big ruler to whack across
people's knuckles. I know that always used to strike terror into my heart at
school. But obviously, such a powerful weapon shouldn't fall into the hands
of those unready for the responsibility, so we're going to make it so only creators
can wield it. We'll start off with, again, comments, inherit, and setup:
<blockquote>
<p><code>/* <br>
Ruler Of Death +2 <br>
Wrytten by Drakkos Thee Creator <br>
21/10/2000 <br>
*/</code></p>
<p><code> inherit "/obj/weapon"; </code></p>
<p><code>void setup() { <br>
set_name("ruler"); <br>
set_short("wooden ruler"); <br>
add_adjective("wooden"); <br>
set_long("This is a thick, wooden ruler, with the
inches " <br>
"inked out in black.\n");<br>
set_weight(1); <br>
set_value(0); <br>
new_weapon(5000); <br>
add_attack("rap", 50, ({ 25, 10, 5 }), "blunt", "blunt",
0); <br>
add_attack_message("rap", "blunt", ({ <br>
0, <br>
({
"You rap $hcname$ smartly across the knuckles with your " <br>
"ruler.\n",
<br>
"$mcname$
raps you smartly across the knuckles with $mposs$ " <br>
"ruler.\n",
<br>
"$mcname$
raps $hcname$ smartly across the knuckles with "<br>
"$mposs$
ruler.\n"}) <br>
})); <br>
} </code></p>
</blockquote>
<p>Again, pretty familiar stuff. We've already seen how all these functions work
in our previous tutorials. New_weapon() looks new, but it's simply the condition
setup for a weapon object. What we're going to look at here are wield functions.
We're also going to see about that last argument of add_attack, the one we've
studiously left as 0 until now. The first thing we do is set our wield function.
Obviously a ruler as powerful as this must be kept in the hands of those responsible
enough to use it properly. Unfortunately, we can't find any of those people
just at the moment, so we'll have to limit it to just creators. The arguments
to the wield function are just the same as our set_wear_remove_function, but
in the opposite order. The function name comes first, followed by the object:
<blockquote>
<p><code>set_wield_func("test_creator", base_name(this_object() ) ); </code></p>
</blockquote>
<p>We then need a test_creator function in our object. Unlike the wear function,
however, this function will need to return a one or a zero. Zero indicates that
the weapon cannot be wielded, and one indicates that it can. We have to be very
careful when designing this function, however, since it gets called at unusual
times. It gets called when the item is first cloned, when someone tries to hold
it, when someone holding it dies, etc. So we must make sure we cater for all
these eventualities and return the correct value, otherwise Much Strangeness
will ensue. Like our function above, we pass in a single object argument. In
this case, it is the object attempting to wield the weapon:
<blockquote>
<p><code>int test_creator(object ob) { <br>
// In case the function is called when there's no
object to <br>
// be passed in. </code></p>
<p><code> if(!ob) { <br>
return 1; <br>
} <br>
<br>
// In case the object calling the function is a corpse
attempting to <br>
// rehold the weapon after death. <br>
</code></p>
<p><br>
<code> </code><code>if(ob->query_corpse()) {<br>
return 1; <br>
} <br>
</code></p>
<p><code> // And now the test creator bit itself. <br>
if(ob->query_creator()) { <br>
tell_object(ob, "You have
been deemed worthy, leetle " <br>
"creator!\n");
<br>
return 1; <br>
} <br>
else { <br>
tell_object(ob, "You have
been deemed unworthy, leetle " <br>
"player!\n");
<br>
return 0; <br>
} <br>
} </code> </p>
</blockquote>
<p>So now, creators can hold the ruler and Smite Their Foes with it, but any non
creators who try will simply be unable to do so. Neato! And now we've effectively
barred anyone but we happy creators from using our ruler of death, we can have
some fnu with it! See our add_attack function?
<blockquote>
<p><code>add_attack("rap", 50, ({ 25, 10, 5 }), "blunt", "blunt", 0); </code></p>
</blockquote>
<p>As we discussed previously, the last argument there is a function pointer that
is evaluated every time the function is called. We normally leave this as 0
because we have no function to evaluate. But let's change that a little bit,
and add a simple function to be called every time we attack with our ruler:
<blockquote>
<p><code>add_attack("rap", 50, ({ 5, 10, 5 }), "blunt", "blunt", "do_shame");
</code></p>
</blockquote>
<p>Now, every time we succeed with this attack, the function do_shame() is called.
This function has five arguments. The first is an integer and holds the damage
the attack would do. The second is the object being attacked, the third is the
object doing the attack. The fourth is a string containing the attack type,
and the last is a string containing the attack name:
<blockquote>
<p><code>void do_shame(int damage, object attack_ob, object attack_by, string
type, string name ) {<br>
tell_object(attack_ob, "Your knuckles %^BOLD%^sting!%^RESET%^\n");<br>
tell_object(attack_by, "You feel strangely satisfied
as " <br>
+ attack_ob->one_short() + " whimpers in pain!\n");
<br>
} </code></p>
</blockquote>
<p>A very simple example, simply printing some text on our poor leetle target's
screen, and some text on ours too. It is obviously possible to make this function
much more complicated, and do all sorts of clever things, limited only by your
imagination. But, let's see the nice message in all its glory: </p>
<blockquote>
<p><code>You rap Draktest smartly across the knuckles with your ruler. <br>
You feel strangely satisfied as Draktest whimpers in pain! </code></p>
</blockquote>
<p>Whee, fnu!
<p><b>Food And Eat Effects For Fnu And Profit! </b>
<p>We'll finish off our final tutorial with a brief look at food and eat effects.
We won't go into too much detail here, since the writing of effects and shadows
is something for a later date. But we will look at how to add existing effects
to food objects. Briefly, effects are little additions to the living that allow
for behaviour not specifically coded into players and NPCs. For example, a simple
effect may echo a message to the player it is placed on, and another message
to the room the player is in, every few seconds.A simple effect may change the
way the player looks to other people, adding an extra line to their description,
and so on. We will look at exactly what effects are at a later date.
<p>There already exist a wide range of effects in the mudlib... in /std/effects/
to be precise. These cover a whole range of functionality, from the useful,
to the bizzare. We'll start off nice and easy, by coding a leetle food item.
Much the same deal as the other items we've coded. Since we're not actually
going to be coding any new function in our object, however, we will code it
into a virtual object:
<blockquote>
<p><code>::Name::"sandwich" <br>
::Short::"monkey sandwich" <br>
::Adjective::({ "monkey" }) <br>
::Value::0 <br>
::weight::1 <br>
::Long::"This is a monkey sandwich. Made from real monkey. Mmm!\n" </code></p>
</blockquote>
<p>Easy as pie! Or, rather, easy as a monkey sandwich. Remember we have to save
our virtual object with a .food extension, tho'. But... well... monkey sandwiches
aren't exactly nice, are they? They're cruel to monkeys, for one thing. I like
monkeys. Do you like monkeys? I do... so I don't like seeing people eating them
on sandwiches. Plus, monkey meat doesn't keep to well, most likely, so it's
likely to become poisonous as soon as you've buttered the bread.
<p>We can easily make our monkey sandwich poisonous by adding an eat effect to
it:
<blockquote>
<p><code>::Eat Effects:: "/std/effects/ingested/poison", 600 </code></p>
</blockquote>
<p>The first argument there is the path to the effect, in this case, /std/effects/ingested/poision.
The second is the argument to the effect itself. We'll come back to that in
a later document, but for now it's sufficient to know that, in this case, 600
is the number of seconds the poison effect will be active for. And that's all!
Look, I'll even prove it to you:
<blockquote>
<p><code>> eat sandwich <br>
You suddenly don't feel very well. Maybe it was something you ate. <br>
You eat the monkey sandwich</code>. </p>
</blockquote>
<p>Woohoo! Later on, we'll look at how you can write your own hoopy effects too,
but for now we'll be happy with seeing how we can add these effects to food.
<p><b>Chapter Summary and Tutorial Conclusion </b>
<p>Wow! That's it! We've come to the end of this coding tutorial. I hope you found
it at least partially informative. If you've read through everything, you'll
find you've picked up a large number of skills that will be of benefit to you
as a creator. You know about data types, inheritence, functions, and control
flow of programs. You know about creating NPCs, itemss and rooms, and you also
know how to make these objects more interesting by adding neat little touches
to each. By now, you should feel comfortable in taking on whatever projects
you're assigned to. Congratulations... you should give yourself a hearty pat
on the back for getting this far. Kudos! And now, we must part company for now.
It's been fun writing these documents, even if it probably hasn't been fun reading
them. But if any of you (poor deluded fools) are hungry for more, then stay
tuned to the second coding tutorial, in which we cover some of the more advanced
topics in LPC. But, that's another day and another dollar, and you should wait
until you're fluent with what you've learned already before tackling anything
more advanced.
<ul>
<li><code>Container objects inherit inherit different files depending on what
kind of container is being created. </code></li>
<li><code>/obj/baggage is inherited when the container is a chest or sack type
of object. </code></li>
<li><code>/obj/vessel is inherited when the container is to hold liquids.</code></li>
<li><code>/obj/clothing is inherited if the container is to be wearable.</code></li>
<li><code>The function set_max_weight() determines how much can be stored in
a particular container. </code></li>
<li><code>The function set_max_volume() is used with vessels to determine how
much liquid they can hold. </code></li>
<li><code>The function add_pocket is used on clothing to add container pockets
to garments.</code></li>
<li><code>The function test_add() can be over-ridden in a container to change
the way the object deals with adding inventory. </code></li>
<li><code>The function test_remove() can be over-ridden to change an object's
behaviour with regards to removing inventory. </code></li>
<li><code>We can declare a function on clothing to be executed whenever someone
wears or removes the item. We use the set_wear_remove_function function to
do this. - We can make objects emit light using the set_light() function.</code></li>
<li><code>We can add a function to be called on a weapon whenever it is wielded
by using the set_wield_func() function. If our function returns 0, the weapon
cannot be wielded. If it returns 1, then it can. </code></li>
<li><code>We can add functions to weapon attacks by passing in the function
name as the last argument of add_attack().</code></li>
<li><code>We can add effects to be inflicted on a player when an item of food
is eaten by defining an eat effect. </code></li>
</ul>
<p><b>Support Files</b>
<blockquote>
<p> <code>/d/learning/newbie/introduction/examples/advanced_item_1.c <br>
/d/learning/newbie/introduction/examples/advanced_item_2.c <br>
/d/learning/newbie/introduction/examples/advanced_item_3.c<br>
/d/learning/newbie/introduction/examples/advanced_item_4.food </code></p>
</blockquote>
<!-- #EndEditable -->
<p>
<hr>
<center><font size="-1"><a href="/login.html">Discworld MUD</a>'s world wide web pages.<br>brought to you by<br>
<strong>Cut Me Own Throat Dibbler's <a href="/sausages.html">Sensational Sausages</a>; buy
one while they are hot.</strong> <br>
<hr>Lost? Try Discworld's <a href="/">home page</a>.</font></center><font size="-1"><i><a href="mailto:drakkos@cableinet.co.uk"><font size="-2">Mail Drakkos!</font></a></i>
</font>
</body>
<!-- #EndTemplate --></html>