INFO
Lesson 1 - the firts LPC lesson by Lars!
DESCRIPTION
There was to be more lessons than this first, but Lars never wrote
them. Read and enjoy this historic document. We've even kept the
typoes etc. :)
Lesson 1 (Introduction to LPC/Beginning Objects)
LPC is a small, object oriented type C language developed by Lars
Pensj| for LP-MUD, a Multi-User Dungeon environment under many UNIX
systems. Since the premise of this language is based on C, it
contains many of the syntactical qualities of C, but also maintains a
large set of functions capable of performing many actions inside the
game. The objective is to begin to look at LPC as a way of creating
objects, rather than specific items, so that new coders can begin to
experience the way LPC actually works. Rooms, weapons, monsters,
armor, and whatever creation you can think of, even yourself, are
objects. LPC allows you to create, modify, delete, and reproduce
these objects in almost any manner you choose. This tutorial will
guide you through some of the basic principles of LPC, and how to
begin to design objects of your own choosing. All objects will be
stored in .c files, using the 'ed' editor or some uploading method of
your choice.
Objects can be created easily, using some of the built-in functions
that LPC allows. Here are a few of them; your local LPC site might
have more available for you. From here on out, the functions listed
below are RESERVED functions, in that they serve a special purpose.
They should not be used in any manner except for what their purpose
entails.
NOTE: Always look in /doc/efun and /doc/lfun for a list of functions
to use (These are the functions for 2.4.5...They may or may not
be available for you to use.)
---------------- LIST OF FUNCTIONS FOR YOUR MUD -------------------
add_action add_money add_verb add_weight allocate
attacked_by call_other call_out can_put_and_get capitalize
cat catch catch_tell clear_bit clone_object
command create_wizard creator crypt ctime
destruct drop ed enable_commands environment
exit explode extra_look extract file_name
file_size find_living find_object find_player first_inventory
get heal_self heart_beat hit_player id
implode init input_to intp living
log_file long lower_case ls move_object
next_inventory notify_fail objectp parse_command people
pointerp present previous_object query_attack query_auto_load
query_gender_string query_idle query_info query_level
query_money query_name query_npc query_value query_verb
query_weight random remove_call_out reset restore_object
save_object say set_bit set_heart_beat set_light
set_living_name short shout show_stats sizeof
sscanf stop_fight stop_wielding stringp tell_object
tell_room test_bit this_object this_player time
transfer users write write_file
---------------------------------------------------------------------------
Let's take an object of any kind, and build it from the ground up. In
order to build something trivial, say, a small rose, we need to use
certain functions given to us by LPC.
To start, we will first need a description of the rose. Two of the
functions from the list above that we will need are short() and
long(). As a player of LP-MUD, you may recognize these as the verbose
and brief descriptions of an object. short() is the short description
of an object, and returns the string for that description, whereas the
long() is a more verbose description of the object, as is seen when
someone 'examines' it. So, back to our rose example, we might have in
our rose.c file:
short() { return "a small red rose"; }
long() { write("This small red rose is very beautiful.\n"); }
NOTE: Your idea of style for writing code might be different from
mine; it is simply a matter of taste. I usually put all of my
one-line LPC code on one line, but you are welcome to use your
own style.
The two functions above works as follows. Let's take short() for
starters. short() is a way of defining a function in LPC, where
'short' is the name of the function, and the information contained
between the { and the } is the action list for that function name.
short() is a RESERVED function, in that it serves a special purpose.
short() returns to the user a string that will contain a brief
description of the item. long(), on the other hand, uses write() to
tell users about the object. We write out information to the person
holding the object, and tell them something about the rose. In this
case, we write out that the rose is beautiful to look at. By using
write(), we can tell users various things. long() is another RESERVED
function, and is called whenever someone 'exa' or 'examine's the
object.
So now we see how to make the objects with description. But other
questions might pop up from this. How do we get the object, or drop
the object? Can we set a price on the object? What about its weight?
And how to we assign a name to an object? Let's finish off the object,
and take a look at what it does.
/* Check for a name of the object */
id(str) { return str == "rose"; }
/* The short description of the object */
short() { return "a small red rose"; }
/* The long description of the object */
long() { write("This small red rose is very beautiful.\n"); }
/* Make sure that the object can be picked up */
get() { return 1; }
/* Set a weight of 1 on the object */
query_weight() { return 1; }
/* Set a value of 10 coins on the object */
query_value() { return 10; }
With all of the above code, you have just created a small rose! To
complete our understanding of the code, we need to understand what
get(), id(str), query_value(), and query_weight() do. get(), as you
might guess, simply allows the item to be picked up. Without this
get() function, no one can pick up the object, unless they have some
object which allows them to do so (dicussion on that will continue
later.) So, since get() is a RESERVED function, we can note that by
returning 1 to the caller, as we do above, we are saying that yes,
someone can pick up this object. id(str) is another RESERVED
function, which serves to check if a string passed to id(str) is one
of the names of the function. When we say (return str == "rose") what
we are really doing is saying that if the string passed to id(str) is
"rose", then return 1, or true; otherwise, return 0, or false. It is
simply checking to see that the strings, when compared, are identical.
In LPC (as well as C), 0 is used to represent a false condition, while
1 (or any other non-zero value) is used to represent a true condition.
To add other strings to the comparison, separate them with the 'or'
sign (||). For example, this is also a valid setting for the id(str)
function:
/* Add a name to the object */
id(str) { return str == "rose" || str == "red rose"; }
If the caller of id(str) passes "rose" or "red rose", the function
will return 1 back to the user, or 0 otherwise. query_weight() and
query_value() are two functions which also return values to their
caller, for weight and value respectively. We set a weight on the
object so that someone carrying too much can't pick up more than
possible, and we set a value on the object so that they can sell it
for a certain amount of gold coins. In the example above, we have set
the value of the object to 10 coins, and the weight on the object to
1. Weights and values will vary according to both your personal
tastes, and specifications for your MUD.
Once this is saved in a file, we can then update the file, and clone
it, and it will appear in our inventory. Assuming that we are in the
proper directory, and the code is in a file called 'rose.c', we can do
the following:
> load rose
Ok.
> clone rose
Ok.
> i
a small red rose.
> exa rose
This small red rose is very beautiful.
> sell rose
You get 10 gold coins.
>
As you will notice, the ability to create objects has been made very
easy by the designers of LPC, and your usage of the RESERVED functions
will enhance the objects you create.
In order to spice up the rose we have created, we will append these two
functions onto the end of our rose.c file:
/* Set some initial actions for our object */
init() { add_action("smell_rose", "smell"); }
/* smell_rose() -- smell the rose. An assigned action from init() */
smell_rose(str)
{
if ((!str) || (str != "rose")) { return 0; }
write("You smell the sweet fragrance of the rose.\n");
return 1;
}
These lines will allow us the capability of actually 'smell'ing the
object. In that sense, we are now assigning 'actions' to the object.
This is an important point, in that everything in LPC revolves around
an action of some sort. A person cannot move, walk, talk, breathe, or
even exist if actions were not allowed. In the example above, we have
added a function called init(). init(), as you will find out in
future lessons, is one of the key functions in LPC. It will allow us
to define actions, and functions associated to those actions. In the
previous example, we have set up add_action("smell_rose", "smell").
"smell_rose" is the name of the function that will perform the write
to the user, and "smell" is the action. So, when we type in "smell"
in any sense, the add_action() will catch that word, and try to
perform some action in the smell_rose() function.
Within the smell_rose() function, we need to check for a couple of
things. First, we need to make sure that the string that is being
sent to the smell_rose() function is actually "rose". If it isn't,
then we want to return 0 back to the user, as this function is
useless.
NOTE: By setting up an add_action() function, we are saying that we
catch the word "smell", but we do not pass it to the associated
function. So, in other words, when we type in "smell rose",
only "rose" goes to smell_rose(). And likewise, if we type in
"smell rose", then " rose" goes to smell_rose().
> update rose
players/you/rose will be updated next reference.
> clone rose
Ok.
> smell rose
You smell the sweet fragrance of the rose.
> smell rose
What ?
> smell
What ?
>
From the example above, we notice that we must say "smell rose"
properly in order to get the function to work. We will deal with how
to handle improper typing on the users side later, but for now, we
will assume that the user holding the object will not add extra spaces
when typing in "smell rose".
There you have it! One complete object. Most objects from this point
will now become easier to develop, because we are no longer set to the
idea of some type of object, but rather an object in general. This
will become very clear in the next lesson, when we begin to talk about
objects as rooms, and how they will take shape.
EXAMPLES TO USE AND STUDY FOR LESSON ONE
-----------------------------------------------------------------------
Example #1 -- A small rose.
-----------------------------------------------------------------------
/*
// Rose -- A small rose example
// By Matt D. Robinson
*/
/* Check for a name of the object */
id(str) { return str == "rose" || str == "red rose"; }
/* The short description of the object */
short() { return "a small red rose"; }
/* The long description of the object */
long() { write("This small red rose is very beautiful.\n"); }
/* Make sure that the object can be picked up */
get() { return 1; }
/* Set a weight of 1 on the object */
query_weight() { return 1; }
/* Set a value of 10 coins on the object */
query_value() { return 10; }
/* Set some initial actions for our object */
init() { add_action("smell_rose", "smell"); }
/* smell_rose() -- smell the rose. An assigned action from init() */
smell_rose(str)
{
/*
// If the function obtains no string, or the string is not "rose",
// then we return 0, or a false condition, to the caller.
*/
if ((!str) || (str != "rose") || (str != "red rose"))
{
return 0;
}
write("You smell the sweet fragrance of the rose.\n");
return 1;
}
-----------------------------------------------------------------------
Example #2 -- A pair of cymbals.
-----------------------------------------------------------------------
/*
// Cymbals -- Items to clang together
// By Matt D. Robinson
*/
/* Check for a name of the object */
id(str) { return str == "cymbals"; }
/* The short description of the object */
short() { return "a pair of shiny cymbals"; }
/* The long description of the object */
long()
{
write("This is a pair of shiny cymbals. "+
"Try to 'clash' them together.\n");
}
/* Make sure that the object can be picked up */
get() { return 1; }
/* Set a weight of 2 on the object */
query_weight() { return 2; }
/* Set a value of 40 coins on the object */
query_value() { return 40; }
/* Set some initial actions for our object */
init() { add_action("clash_cymbals", "clash"); }
clash_cymbals(str)
{
/*
// If the function obtains no string, or the string is not
// "cymbals", then we return 0, or a false condition, to the
// caller.
*/
if ((!str) || (str != "cymbals"))
{
return 0;
}
write("You clash the cymbals together, making a lot of noise!\n");
/*
// This is another RESERVED function, say(), which will be
// discussed later (if you would like to figure out what it does,
// then look at /doc/efun/say.)
*/
say(this_player()->query_name() + " makes noise with cymbals!\n");
return 1;
}
-----------------------------------------------------------------------
Example #3 -- A drinking glass, more advanced, reset(arg) as well as
integers also explained in next lesson
-----------------------------------------------------------------------
/*
// Drinking Glass -- Drink some good liquid.
// By Matt D. Robinson
*/
/*
// Declare the integer drinks
*/
int drinks;
/* Change number on reset (IMPORTANT -- WILL BE COVERED IN LESSON 2) */
reset(arg)
{
if (arg) return;
drinks = 3;
return 1;
}
/* Check for a name of the object */
id(str) { return str == "glass" || str == "drinking glass"; }
/* The short description of the object */
short() { return "a drinking glass"; }
/* The long description of the object */
long()
{
write("This is a drinking glass. Perhaps you can 'drink +"+
"from glass'.\n");
}
/* Make sure that the object can be picked up */
get() { return 1; }
/* Set a weight of 2 on the object */
query_weight() { return 3; }
/* Set a value of 40 coins on the object */
query_value() { return 50; }
/* Set some initial actions for our object */
init() { add_action("drink_liquid", "drink"); }
drink_liquid(str)
{
/*
// If the function obtains no string, or the string is not
// "from glass", then we return 0, or a false condition, to the
// caller.
*/
if ((!str) || (str != "from glass"))
{
return 0;
}
/*
// Check to see that drinks is 0. If so, say the glass is empty.
*/
if (!drinks)
{
write("The glass looks empty.\n");
return 1;
}
/*
// Decrement the value of drinks by 1. (Using '--' syntax)
*/
drinks--;
write("You take a sip from the glass, and spin in delight.\n");
return 1;
}
-----------------------------------------------------------------------
Please refer to /doc/efun and /doc/lfun for more information about
functions mentioned in this documentation, or, ask your local LPC guru
for more help.
Help topics available:
You are guest number 272 since November 2019.
This file was last modified: June 2000.