Lpc, the stuff that dreams are made of
A great man once said "I am not a great man, I stand on the shoulders of
giants." Another man said that in the computer business we stand on
eachothers feet. I'd like to think that is not so and therefor I share some
of my experiences here.
Hacking
There is a hack for every problem, and you can quote me on that. However
there is a right and a wrong way to solve a problem. When the problem is
caused by the mudlib, the right way is of course to change the mudlib,
this may seem hopeless, but don't dispair, the archwizards are there to
make the changes for you. Arches often equals lazy though, so you better
have ample motivation for your change.
Security
Remember that anyone can call any functions that you haven't declared as
static. Also remember that static functions can't be called by any other
objects, not even your own or call_out:s. Also remember that arrays are
shared, that means that if you return an array from a function its contents
can be modifyed from another object. Lpmud is never more safe than it's
most unsafe object.
Wizards beware
Making good armours and weapons is probably the best way of ensuring that
players will visit your area, but beware, too good stuff will invariably
cause some sort of inflation in weapons and armours. You'll become
inpopular among the older and higher wizards. Your chanses of advancing
beyond wizardhood may reduce. If you still want to make a bunch of really
good weapons then make sure that they are _very_ hard to get and that your
area is inpeckable, variated and full of surprises. That way noone can
complain and you can motivate your good weapons.
Administrators beware
Some of your wizards _will_ ignore the warning above, so what the heck,
giv'em hell for it. There is of course another way to stop an evil trend:
Example, someone dreams up an 'autobow' command, and suddenly everybody
goes around bowing to everybody. As an administrator you can either
perish by this evil, useless and extremly utter command or you can make
your own generalized 'auto' command and put it in the playerobject. Now
all the novelty with autobow is lost and with any luck, the trend will die
all by itself. If not, well, nobody is perfect.
Things not to do
Don't do this, or you'll become very, very inpopular:
- throw(0);
It crashes most lpmuds.
- destruct(this_object()); or destruct(this_player()); in init()
It crashes some lpmuds.
- explode() with a user-typed second argument can crash the mud.
- Never do errors in auto_loading objects.
Players can loose their commands.
- Errors in exit() will stop people from leaving and that's not a
pretty sight.
- Don't trust find_call_out(), it can return -1 even if there are
pending call_outs.
- Never make super-monsters, you have no idea how usual it is that they
escape and kill players.
- Avoid putting \ at the end of strings in objects that use
save_object(). It won't be able to restore that string on many muds.
- In native mode, if an objects euid is zero it is not possible to
call_out to other objects if you don't make absolutely sure that the
other object is loaded first. It gives the error 'Illigal to load
object with euid zero'.
- Never trust the players not to do something, sooner or later they will
anyway.
- Be careful with call_outs if they multiply they stop the mud.
- Be careful with inherit, if you inherit an object that inherit your
object the mud stops in an eternal loop.
- Don't use the efuns ed() & shout() without a this_player()
- On some muds it's possible to catch() too long evaluation and then
continue as nothing has happened. This can of course cause an eternal
loop.
- In native mode it is possible to initialize variables like this:
int a=12;
or
int b=destruct(this_object());
Don't use the latter example, it crashes most muds.
- Watch out for too deep recursions, it can actually crash the driver.
- The preprocessor isn't bugfree either, division by zero or modulo by
zero in #if will crash most drivers.
- Don't make it possible to enter your workroom from the game, it's easy
to forget superweapons etc. in the workroom.
- Everybody loves to make wiztools, but think first, maybe your
particular wiztool is already made.
- explode() is not the inverse of implode(), rememeber that.
- Never remember players by their playerobject, always use
ob->query_real_name() and find_player() to remember the player as
the playerobject may change.
- Watch out with inherit, if your object inherit two objects which in
their turn inherit the same object. You will have two sets of some
variables.
- Remember that lpmud is singel-threaded, that mean that if you succseed
in keeping the cpu for yourself the mud will stop.
- Watch out when using say() and call_out(), call_out saves this_player
in all modern lpmuds, therefor say() will appear where this_player is
even he/she has wandered across the whole game during the delay.
- It is simpler to have one file per object, but it is much more
memory-efficient to clone standardobjects from rooms and configure
them.
- Busy wait. That is, don't do a loop to make a delay by counting to
one zillion, the mud will stop while you do that. Use call_out()
instead.
There are lots of other things you shouldn't do, but with any common sense
you won't make _every_ mistake in the book :) If you don't belive me, go
ahead, make a fool out of yourself.
Tips & trix
- Mappings are sorted, for all types but integers this is uninportant, as
they are sorted in a strange order. However, integers are sorted in
numerical order and it's much faster than sort_array()
- add_action() has a flag that makes it possible to catch all commands
beginning with a certain string. add_action("com","",1) is a special
case thogh, it catches _all_ commands typed by a player. Nifty, but
dangerous, beware.
- input_to() is another way of catching all the input from a player, but
if the command is prepended with a ! it will still be interpreted like
a normal command.
- implode(explode(" "+" "+"alpha beta"+" "," ")," ")=="alpha beta" Remember and use.
- Don't get carried away and make zillions of rooms without anything
interesting in them, mortals invariably find this boring.
- Try not to copy code, use inherit instead, that is much more
memory-efficient.
- Avoid too much calling between objects, it makes the code unreadable and slow.
If you want to split the code into lots of files, use inherit.
- Don't take any responsibily youself, always let some higher wizard check
your obejects so he can take part of the blame.
- enable_commands() changes this_player() to this_object() use with care.
- if simul_efun has defined an efun in a way you don't like, you can use
efun::function() instead.
Questions and answers about lpc.
Note that it would be impossible to give answers that would apply to every
mud in the world, but I think these applies to most.
Q: How do I make a weapon that hits harder against some types of monsters.
A: Here is an example of an weapon that has the upper hand on orcs.
int weapon_hit(object attacked)
{
if(attacked->query_race()=="orc")
{
write("Ziing!\n");
return 10; /* This number is added to the damage */
}else{
return ;
}
}
Q: Can I use ANSI codes to make objects look green?
A: Yes, you can, No you are not allowed to do it. Some muds will even filter out
your escape sequences.
Q: How do I know if an object is in the same room as my object?
A: if(environment()==environment(the_object)))
Q: How do I let another wizard read my files?
A: The only way that works on all muds is the directory /open. Everybody
can read and write there.
Q: How do I know the filenames to the rooms when I use goto?
A: You don't, you have to go there and check it out first.
Q: How do I change a character within a string?
A: You don't, you have to build a new string like this:
string char;
int pos;
new_string=old_string[0..pos-1]+char+old_string[pos+1,10000];
Note that char is a string, not an int or char or anything like that.
Q: How do I transform an ascii value to a character in a string?
A: In standard lpc there is no way of doing this but to have an array with
all the strings in and index it on the number, but some lpmuds have an
efun sprintf, and then you can do like this:
str=sprintf("%s",value);
See the efun chapter for further details.
Q: How do I make my monsters wander around without letting them leave my area?
A: The easiest way is to put a function in your monsters that identifies them,
let's say query_is_profezzorns_monster() and let this function return 1,
then you put the following code in all your rooms that leads out:
int no_way() { return 1; }
void init()
{
::init()
if(this_player()->query_is_profezzorns_monster())
{
/* Do this for every direction that leads out. */
add_action("no_way","south");
}
}
Some mudlibs has blocking function in their standarobjects and those
functions are probably better, however, this solution should work
almost everywhere.
Q: Why doesn't the driver tell _me_ about the error, it just winds up in
lpmud.log?
A: Somewhere on the way to the error this_player() was changed to a monster,
the most usual case is when enable_commands() is executed in the creation
of a monster.
Q: Are there any real manual or tutorial about lpc?
A: If you don't count this document, then the answer is no.
Q: Can I redefine an efun and still use the real efun?
A: Yes, here is an example of how explode _should_ work:
string extract(string a,int b,int c)
{
if(c>=b) if(b>-1) if(strlen(a)>c) return efun::extract(a,b,c);
return "";
}
string *explode(string a,string b)
{
string *c;
if(a==b) return ({"",""});
if(strlen(b)) if(my_extract(a,0,strlen(b)-1)==b)
return ({ "" })+explode(extract(a,strlen(b),strlen(a)-1),b);
if(c=efun::explode(a+b,b)) return c;
return ({});
}
Note that efun::explode() is used to call the efun explode.
Q: Is there a way of doing this or that?
A: Read the efun chapter before you ask.
Q: Why doesn't my object appear when I clone it? I can't find any errors
anywhere!
A: If you are programming under a native mud you probably forgot to define
move(), put this line in your program:
void move(object o) { move_object(this_object(),o); }
Q: Why isn't my question listed?
A: It's not asked often enough or I just forgot, ask me about it.
Q: How do I recognize a roomobject?
A: You don't, on most muds the only defenition of a room is that it is
accessable by players.
Q: How do I recognize a player?
A: Use interactive(ob), not query_ip_number().
Q: How do I recognize a monster?
A: Call query_npc(), many people use living(), but other objects than
monsters can be living.
Profezzorn (hubbe@lysator.liu.se)