Updated January 02 2007. Note: commands are
displayed in boldface, like this: ls -a
What's this FAQ about?
There are common issues and
questions that crop up for most new creators. This
document is intended to ease or at least shorten what can
be a steep learning curve.
1.1
My question isn't on here. Where can I get an answer?
There are five main ways to get
specific answers:
1) Ask your mud's administrator, or
other creators on your mud by using the cre
channel, like this:
cre does the
flux capacitor use verbs or add_actions?
To know what local channels are
available on your mud, type: lines
2) Your mud is probably on the intermud3
network. If your administrator has not
restricted intermud channels, you should be able to ask
questions on the Dead Souls intermud channel, with a command
like this:
ds hi! can
someone tell me what room Leo lives in?
3) If intermud is down, or nobody is
answering, or you have a bug to report, you can
also try emailing me, the author of this doc, at:
<my name here>@comcast.net
This is a long shot, as I prefer to answer things on
the forum, where more than just one person will
benefit. Note that I just might post your emailed
question on the forum, if I think that's appropriate.
4) If intermud is down, you can also log
into the Dead Souls demo mud at rugose.com
6666 This mud automatically promotes
users to creator status, allowing guests
to get a feel for what developing on Dead Souls is
like. You can try to log into that mud
and see if anyone is available to answer your
question. Intermud is disabled for new users there, though, so
you won't be able to use the ds line to ask questions.
- If someone doesn't know the answer right away, eventually
someone probably will.
- Sometimes people on intermud know the answer, but are busy and just
don't have the time to answer. On the forum, this is less the
case.
- Some questions have answers that are long, and intermud folks
may not want to spend the time on an elaborate answer to a
question
that they'll probably see someone else ask later. On a forum,
the responder can be reasonably sure that her help will be useful
not just to you, but to many others.
- You can post detailed error messages and logs, and the files(s)
that are giving you trouble. That way many eyes can analyze
your problem in depth.
- Once resolved, other people can later refer to that problem so
they don't have to ask the same question, or reinvent the wheel.
Important note about asking on <ds>:
Part of the reason this FAQ was
written is that people who ask questions on the
ds channel often do not realize that same question has
been asked many times before. If you ask something like
"how do I read the channel messages I missed?"
without first bothering to read this doc and others, you
just might get a response that's less friendly than you
might have expected. People on the channel really
want to help you, but if it seems like you're not
willing to put in the time to try to help yourself,
they might choose to ignore you until you gather some
clues on your own.
Something else to remember is
that we are not on your mud and we don't see what
you see. "Why won't my workroom update?" lacks enough
information to let anyone try to help, but "when i
try to update my workroom I get <error
message>" might.
Similarly, some things don't
have an answer that is suited to ds. "could
someone help me understand the score.c file?" or
"how do quests work?" have answers that are long and
complex, or are already covered in the
documentation available to you.
Some stuff just doesn't have an
answer that can be explained to you
unless you already have the experience you'd need to
know the answer. for example:
- How do I make a
stargate that has a dial for going to
different places?
- How do I make it
so a player can be on different planes of
existence, and what they see when they look around
depends on what plane they're on?
- How do I add limbs
so people can wear stuff like kneepads
on the knee only?
These three questions illustrate
things that are totally doable, but whose
explanation is so complex and full of judgment
calls that there is no way of satisfying the
question without making you magically understand
intermediate-level LPC coding. That doesn't mean they're bad
ideas, or even that hard to implement. It's
just that the questions can't be answered
until you read and understand the Creator's
Manual, and by that time, you'll know the answer on
your own.
Make sure you've read the docs,
then ask the question in a way that makes
it clear you aren't just a lazy person who wants
other people to do her work, but rather a hardworking
builder who has tried to fix something and needs
a specific answer to a specific question that isn't
already in the FAQ's or the docs.
Critiques are welcome, but they
should be constructive. "This combat
system is slow and stupid" is unhelpful and might be
taken as a hostile statement. Instead you
could phrase it in a way such as: "Combat is
slower than I expected. Why? I used to play on
LeetFooMud and it took less than a minute to kill
Tiamat." It's still a bit clueless, but it's a fair
question that can be answered on its own terms
without starting a flamestorm.
Finally, some things are only
lightly documented, or perhaps not at
all. Filling out the documentation is an ongoing
project, but as with much freeware out there, you
have to be willing to put in a little bit of time to
experiment. For example, you may not know what
the "importance to the class" section in the
class file format is, and you may not find the answer
in the docs. In such a case, you have to be
willing to experiment a little, and plug in different
numbers, to see what they do. I can't hold your hand
every step of the way. You have to trust your own
intelligence and enjoy the sense of adventure in
discovering things on your own.
Also, please refer to this Admin FAQ section
on how to ask questions in the most productive way.
The
ds channel is too spammy. It's distracting me.
Enable or disable a channel by
typing just its name. Like:
ds
All
I did was change one thing in a file, and now it won't update. Help!
You should make it a habit to
make backup copies of files before editing them. That way, if
you screw up the code, you can just copy the backup to the
original filename.
A convenient way to do this is
the bk command. See the debugging page for an example of its use.
If your file is in the /tmp
directory, it won't update. The lib uses /tmp for temporary
system files, and as a result, it is a security
feature that files in /tmp can't be loaded into memory.
If you are using Windows, you
need to be aware of the linefeed problem. unix text files
and DOS text files have different formatting. If you edit files in
Notepad, then try to update them, you may find that the file no
longer updates, no matter what you do. The difference is usually
invisible to you, so you can't tell why a file that looks
exactly the same as before now won't work.
Dead Souls expects
unix-formatted text, and if you feed it something else, the results
aren't likely to be to your satisfaction. Make sure you use
an editor that respects unix text. In Windows 2000, WordPad
seems to do a reasonable job of not completely screwing things. It
does, however, add carriage returns to your lines, so when
you look at them in ed, you'll see a bunch of "^M"'s all over the place.
Take a look at the third party downloads
page for some suggestions as to what to
use instead of the default Windows editors.
If you still have trouble, take
a look at the debugging page.
The
mud editor is confusing the heck out of me. It's too hard to use.
When
I log in, everything is screwed up, and I can't do anything!
This happens sometimes when you
log out while carrying an object with broken code. If for example,
you are wearing a vest, and then you edit the code for it, but it
doesn't work anymore, then you log out, what happens is the next time you
log in the mud will try to restore an item in your inventory that
throws an error, and your login gets stuck halfway.
If you find that when you log in
things are all screwed up for you, use the rescue login
feature. For me, this means I would login as cratylus_rescue instead of cratylus. My inventory will get wiped before my
playerfile is loaded, and I'll be able to log in with no
problems.
If this doesn't work, there's a
good chance that the room you're spawning in has a problem.
Try quitting and logging in again. If that works ok, then
it's very likely the room was at fault. See if there
are any messages in /log/runtime pointing to it.
Ok,
I'm a creator now. What am I supposed to do?
Ask your admin.
If you're like most other
creators, you have a creative vision you want to
implement and share with others. you want to create dragons, or
spaceships, perhaps dragons in spaceships. This makes you a
"builder".
As a builder, your job is to
learn how your mud works so you can get your neat
ideas turned into a virtual reality. As you might
have guessed, nobody is going to jack into your brain and
upload coding ability into you. You need to learn how
to move around, how the creation system works, and
yes, you'll need at least some passing acquaintance with
the stuff your mud is made of: files written in the LPC
language format.
The good news is that it's
nowhere near as hard to learn as C++. LPC is very
powerful, but it doesn't require you to be a master to get
simple things done.
Your first steps as a new creator
probably should go something like this:
1) Talk to your admin. Understand what
is expected of you, and what the rules of your
mud are.
2) Go to your workroom by typing: home. Read the helpful notes that are posted there for
you.
3) Read the Player's Handbook, cover to
cover. It isn't long, and you will need every bit
of information in there. This is not a
suggestion. You need to read the handbook.
4) Open the chest in your workroom, and
play around with the tools and toys in there.
Having read the handbook will help you deal with
any issues you have handling these items.
5) Type wiz to go to the Creator's Hall, and if
there are any posts on the board, read
them. To read the first post: read 1. To read the second, read 2, and so on. If you decide to write on the
board, remember that to exit "writing"
or "input" mode, you need to enter a dot on a line
all by itself, like this:
.
6) Once you get a feel for how to move
around, what playing here is like, and
how to do stuff, you can start exploring your creator
powers. To get a grasp of the very basics of
navigating through files and directories, type:
more
/doc/BASICS
Yes, you must include capital
letters. Dead Souls distinguishes between upper
and lower case letters in filenames.
To get a feel for what Dead Souls
LPC code looks like, wander about town and use the
about command to read code that compose the objects
there. For example:
goto
/domains/town/room/road
about here
about beggar
Or move around in your own home directory and check out the
defaults and templates there:
cd
/realms/<yourname>/area/npc
more fighter.c
To bring a copy of that fighter
to life:
clone fighter
To make him dance:
force fighter
to dance
To kill him:
zap fighter
To get rid of his corpse:
dest corpse
7) Once you're done having fun with your
godlike powers, it's time to start
learning how to make fun stuff of your own.
For a quick start in building,
you can start reading the Creator's
Manual at chapter 31, which is where the
QCS section begins:
read chapter
31 in manual
read chapter
32 in manual
and so on.
That's fine to start with, but
eventually you'll need to read the whole
Creator's Manual. If you don't, 90% of the
questions you ask about code could be fairly answered
with: "read the manual."
This
is weird...where is the online builder? How does new
stuff get compiled?
Dead Souls can be very strange
to people used to non-LPC muds. This is because
many other kinds of muds use a system where the mud
is written in C++, and to make changes, you need to
add C++ code to the source, recompile it, then reboot
the mud. In that kind of system, building
is done with tools where you fill in blanks
and code is generated for you. I presume that some C++
expertise is required for doing anything
unusual or fancy.
If you come from this kind of
environment, you may be in for a little
disorientation. On a Dead Souls mud, there is no need for
compiling code. You don't need to reboot the mud for
new stuff to be available.
You can add your new Orc God of
War to the game (after you code him, of
course) with two simple commands:
update
/realms/<you>/area/npc/grimmash.c
clone
/realms/<you>/area/npc/grimmash.c
You're now face to face with
him. This makes Dead Souls, like most LPC muds,
very flexible in what can be done, and very stable
in terms of needing few reboots. Reboots
typically are necessary only when someone
breaks important code, or to implement major
mud-wide changes.
So, just write your code, and
update it. It's that simple. There are two
main ways to do this. The easiest way is with the
QCS, or quick creation system. With the QCS,
you don't even need to look at code. You just issue a
few commands, and your new whatever is there. Check out an
example
of the QCS here.
To learn the QCS, read the
Creator's Manual starting on chapter 31.
The other way to create on-line
is with the ed command. The ed
editor is a powerful and flexible way of editing
files. Some people find it difficult at first, and
you might even be able to avoid it for a while
if you mostly just use QCS. However, you'll
eventually need to know a little about ed. For a tutorial, go
here.
For more detailed documentation,
type: help ed
I
explored around in /domains/Ylsrim and <XYZ> is broken
Ylsrim is kept in the
distribution as a kind of sentimental artifact. It's the
demo area that the original Dead Souls shipped with,
and although it's mostly been fixed up to work
with Dead Souls 2, things can behave unexpectedly.
There will be no new fixes to Ylsrim. Please
consider it a museum exhibit that stands as-is.
I
explored around in /domains/town and <XYZ> is broken
Please send me an email and let
me know, so I can fix it. Also let me know if
something in the default, campus, or examples domain is
hosed up.
What
are the known bugs and problems in Dead Souls?
Sometimes, when someone asks for help on the intermud
channels, I will ask them to post their broken file on http://lpmuds.net/forum/ to
troubleshoot.
Let me make a few things clear:
- I am not trying to steal your broken newbie code.
- I am not trying to drive up web site traffic.
- I am not trying to collect your personal data.
I've actually had more than one person get hostile
and defiant about posting on the forum, which I
find mind-boggling considering they were asking for help
in the first place.
The reason I ask is that, as good as I am with Dead
Souls and LPC, some things I can't figure out unless
I see:
1) The errors generated by the code.
2) The code that generates the error.
If I ask to see your file and you won't post it on the
forum, I might maybe accept it by email. On the other hand,
the point of the forum is for people to learn from each
other, including each other's mistakes. If you won't
allow your troubled code to be made public so
people can help you, I'll probably let you work it out
on your own.
Remember that I release 99% of my code for the
whole world to see, so I've got limited patience if you're
going to hoard your precious uber sword of wounding code.
Section 2: Code
What's
the QCS?
Please see the QCS example page for an explanation of this important Dead Souls system.
SetUnique
doesn't work.
SetUnique() is probably doing
something you don't expect. When an item is
loaded into memory, and it has an inventory, it first
checks each of those items for whether it's supposed to be
unique. If it is supposed to be unique,
then we look through the list of loaded
objects to see if there is one of these items already
cloned. If there is, then we don't clone a new one. What this means is that if I
kidnap Leo the archwizard and hold him in my
workroom, another one will not appear in the basement until
my Leo is dested.
Note, however, that this does
NOT mean that the mud will never have two Leos. I
can clone however many Leos I want. But as long as one
or more cloned Leos exist, the basement will not make
another. That's what SetUnique means.
Putting a negative number in the
value element of a given item in SetInventory
makes it get treated as a unique object.
Now, if the behavior you're
seeing is different from what I described, maybe
SetUnique is broken, and you should email me with what
you're seeing.
I
made a magic wand that disappears after 10 minutes. But
if a player logs out and log back in, they have another
10 minutes! How do I fix this?
What's happening is that you are
keeping track of how old the wand is,
perhaps with a variable named Age. But if the
player quits and logs back in, then the wand gets
cloned again, resetting all its values, including Age, to
the original.
The way to make the Age variable
survive logouts is with AddSave. If you
give your variable to AddSave as an argument, that
variable gets saved when the user quits, and when they log
back in, it is restored, preventing cheating.
See /obj/wed_ring.c for an
example.
Where
is it saved?
In the player's playerfile, along
with the values of all the objects they were carrying
when they quit. The file is in /secure/save/[ players |
creators ]/<first initial>/<name>.o
How
do I add or remove emotes?
That is an admin job. You admin
would use the addemote or removeemote commands.
How
can I tell what files something inherits?
Use the showtree command. To know
what files are inherited by your robe, for
example:
showtree
/domains/default/armor/robe
How
can I find the filename of something?
If it's in your environment: scan here If it's in your possession: scan me
The number sign (#) and numbers
at the end are that object's unique identifier.
What's
the largest integer usable by the mud?
2147483647
How
can I find out what functions exist in something?
Get its filename and use the
functions efun. For example:
It isn't really. Unless you're
coding a lib item, you should not be
inheriting LIB_OBJECT for "tangible things" anyway. You
should inherit LIB_ITEM.
The reason object::init() fails
is that LIB_OBJECT doesn't have an init() function
to call.
if(ob->GetFoo())
seems to break, but I don't know why
This function will error if ob
does not exist. Unless you are 100% positive ob will
exist (and really, even if so), it should look like this:
if(ob
&& ob->GetFoo())
Which means "if ob
exists, and it has a foo". This way, if there is no ob, the
check stops right there without getting hosed up on the
next step.
How
do I add color to my descriptions?
There are various markup tokens
you can use for this. They look like this:
write("%^BOLD%^GREEN%^ This
text would be in bold green letters %^RESET%^ and this would not.");
To make text blink, use this tag:
%^FLASH%^
The %^RESET% is important.
Without it, unpredictable things can happen.
To know what colors are
available, type: colors
You should probably avoid color
unless there is a compelling reason for its use. Many mud
admins discourage it because it can distract from the game and cause
uniformity issues: most mud admins feel their mud text should
look more or less the same everywhere.
How
do I turn the integer 42 into the string "forty-two"?
cardinal(42)
Can
I use !=NULL as a test?
In theory, I guess so, but I
doubt it'll work by default, and I'd discourage you from doing
anything so non-LPC-standard. Instead try something like one of
the following:
I
want to create and test a new command for the mud, but
I'm not admin so I can't put anything in the normal
command paths. What can I do?
Put your new command in your
homedir's cmd/ subdirectory. A sample command is
there already to serve as a template. When you
add a command, type:
update
/daemon/command
for it to show up in your path.
How
do skills work?
Skills are generally class-based,
meaning that they are specified in the class files
found in /secure/cfg/classes. Skills are only meaningful in
terms of library objects that understand them.
For example, a fighter's blade
attack is useful because player.c and combat.c make use of
this skill as a modifier.
But adding a basketweaving skill
to a class is not helpful unless there are library
objects (looms, perhaps, or straw) and verbs (weaving,
maybe?) that make use of that skill.
There are also race-based skills,
such as poison bite or breath attack.
These skills are specified in /secure/cfg/races.
How
do classes work?
Basically, having a class gives
you special skills. That's it. See the above section,
"How do skills work?"
How
do virtual rooms work?
Virtual rooms are rooms generated
on the fly by a virtual room server. You program
that server with the room descriptions, the number
of them, etc, and the virtual server can
make available a grid of rooms with your
descriptions.
This allows you to create, for
example, a vast desert, or a large jungle,
comprised of dozens, or hundreds, or thousands
of rooms without having to manually code
each and every single room.
Sefuns and efuns are functions
available to all objects on the mud. Any object may need to know
what time() it is, so rather than have a time() function in
every file that needs it, which could be many, there is a time()
function built into the game that any object can use. An
efun is built into the driver, so there is no LPC code
to look at. A sefun is a simulated efun, coded in LPC.
Sefuns are kept in /secure/sefun.
Lfuns are functions specific to
library objects. A shirt, for example, has functions that a
sword may not need, so the LIB_ARMOR and LIB_WEAPON
files contain their own functions, not shared by other files (it's
more complicated than this, but that's the idea). These
functions are library functions, or lfuns. Typically
they are found in the objects defined by the files in /lib.
For a lot more detail on efuns
and sefuns, see the admin FAQ.
Why
are there more sefun doc files than sefun files?
Sefun files, like
/secure/sefun/strings.c, often contain more than just one sefun.
Therefore, there will be more files documenting individual
functions than there are files containing sefuns.
I
edited a file but now the reload command is complaining.
There are two commonly used
commands for loading objects: update and reload.
When you want to load a file into
memory, you use update, for example: update
/domains/default/room/road
When you want to replace a cloned
object with a version that uses the latest code
in a file, you use reload, for example: reload my first red
sword
reload doesn't work on files.
update doesn't work on cloned
objects.
The reason there are two
commands, instead of one all-purpose one, is both historical and
functional. The reason "reload" exists is that I got sick of
having to dest a thing, update its file, then clone the thing
every time I wanted to test changes in its code. This
was annoyingly tedious, so I coded the reload() sefun and
reload command.
However, update works just fine,
and I wasn't about to try to fix something that
wasn't broken. It works, and LPC old timers are used to it.
Further, it has a function
sufficiently separate from reload that it stands as a
command on its own merits.
this_player()->GetName()
returns "A shadow" when the player is invis.
Use
this_player()->GetKeyName() instead.
Is
there a sefun for making a whole string uppercase?
upper_case("omgwtfroflmao")
What
is the difference between filter() and foreach()? How do I use them?
Both of these efuns can act on
the individual members of an array.
For example, if you wanted to
have an array named mystuff which contains the base filenames of
all objects in your inventory that inherit LIB_ARMOR:
using filter:
string
*mystuff = ({}); //This has to be a
global var object
*stuff = filter(filter(deep_inventory(this_player()),
(: inherits(LIB_ARMOR,$1) :) ), (: mystuff += ({ base_name($1) }) :) );
using foreach:
string
*mystuff = ({}); foreach(
object ob in deep_inventory(this_player())){ if(
inherits(LIB_ARMOR, ob) ) mystuff += ({ base_name(ob)}); }
There are arguments favoring the
use of either. I won't get into it. As far as I can tell, it's
really a question of preference. You can structure these
functions more elegantly than shown here, to best suit
you. But this is the idea.
member_array()
is returning exactly the wrong thing
It probably isn't. member_array()
seems somewhat counterintuitive at first, because it often
returns a 0 as a "hit".
What this function is doing is
checking to see whether the first argument is a member of the
array specified in the second argument, and then tells you
*which* element it is. for example:
Why does it return 0? Because
"foo" is element 0 of the array. If this_array == ({ "foo",
"bar", "baz" }), then this_array[0] is "foo". So
member_array("foo", this_array) would return 0.
If the first argument is not a
member of the array, member array returns -1. So that:
WRONG: if(member_array("polka
dancing", this_player()->GetSkills()) ) return 1; The first way says "If 'polka
dancing' has an element number that isn't -1, then it is a member, so let's
return 1"
The second way says "If 'polka
dancing' has an element number that isn't 0, then it is a member, so let's
return 1"
The problem with the second way
is that it is possible for "polka dancing" to be element 0 in that array,
and if it is, your code will incorrectly tell you that you can't polka
dance. But worse than this is that if you actually can't polka dance,
this second way will incorrectly tell you that you can. Given random
input, the second way would be wrong more than half the time.
I'm
trying to add two mappings together and the results are bizarre
Adding mappings together has to
be done just so in order for it to work the way one might
expect. What can happen in mapping arithmetic is that in the
process of trying to add the values of one mapping to
another, you can change the values of a mapping you didn't
intend to. The deal is a conflict between passing data by
reference or by value. To be sure that you don't
accidentally modify an innocent bystander, use the add_maps()
sefun. For example:
MyMap = add_maps(HisMap, HerMap);
or
MyMap = add_maps(MyMap, HerMap);
When
str = "abc", str[1] is 98, not "b". What gives?
What you're getting here is the
ASCII code of element 1. If you have to have that element
as a string, use the convert_ascii() sefun, like this:
convert_ascii(str[1])
You can instead use ranges, so
that:
str[0..0] == "a" str[1..1] == "b" str[1..2] == "bc"
If you use ranges, do not use the
convert_ascii() sefun.
How
do I make an array1 that is the same as array2 but without an element?
Two ways:
1) array1 = array2 - ({ element
});
2) array1 = filter(array2, (: $1
!= element :) );
How
do I pass arguments to a pointer in a functional?
With commas, like this:
(: eventKill, player :)
Your arguments will likely need
to be constants, tokens, and/or global variables.
What
does the tc() sefun do?
It's something I coded for myself
long ago, basically a personalized debug(). However,
people have been asking for that functionality for
themselves, so the debug() sefun now carries
this functionality. For more information, type:
man debug
How
can I find out how many items are in an array quickly?
sizeof(array)
My
SetRead isn't working
You may need an item for
each read. For example, SetRead( ([ ({"alpha", "bravo",
"charlie"}) : "Delta.", ]) )
May need something like this *above* it:
SetItems( ([ ({"alpha", "bravo",
"charlie"}) : "A thing you can read.", ]) )
My
SetEnters/SetSmells/SetListens isn't working
See above.
Can
I nest loops?
Can you? Probably. Should you?
Almost certainly not. For loops and while loops are
legal LPC, and you may even see them here or there in older
lib code. But they should be avoided because they
generate much more lag than the more efficient
foreach() and filter() efuns.
What
should I do or not do in my code?
1) Avoid using call_out() as much
as humanly possible. Use heart_beat() to time things
instead.
2) Don't code stuff that
replicates itself.
3) Don't code stuff that
circumvents security. For example, knowing that an admin is
logged on but invisible isn't much help to you
if he bans you for coding a tool to find him.
4) foreach() and filter() are
faster than for() loops, and harder to screw up.
5) switch() is faster and more
economical than if() for multiple evaluations.
6) Don't use callouts.
7) Don't use add_action for
something that already has a verb. There is no point in
making an add_action for "throw", for example. It's
just going to confuse players when your "throw" doesn't
behave the way "throw" does everywhere else on
the mud.
8) Callouts are bad, mkay?
9) Don't code delays by using
loops. This affects the whole mud. If an action is to be
delayed, use heart_beat().
How
much different or heavily modified is Dead Souls than stock LPC?
This is a difficult question to
answer on its own terms. It's roughly equivalent to:
Is Fedora different from stock
UNIX, or will my Solaris programs work on it?
This DVD movie is in NTSC format,
so my TV can handle it, right?
The terms used roughly
correspond to the same general thing, but the assumption
here is that there is a "stock" LPC, and you can
transplant code from one LP mud to another. Sometimes these transplants can
be done. Oftentimes not. This is because LPC has been
interpreted and implemented in many slightly different ways by
many slightly different versions of many different drivers. The
end product of the DVD is a movie playing on your TV, but how it
gets there is very different from how a videocassette does it, even
if it's the same movie and its signal is encoded in NTSC in both
cases.
If you have two LPmuds that use
different drivers, it can be much like the difference
between a DVD and a videotape. Sometimes, if the drivers are
related, the difference is smaller, like VHS versus Betamax, but
you'll still be embarking on a major project getting the movies
from one to play on the other.
The result is that a coder from
Discworld and a coder from Nightmare can roughly speak
the same language, and discuss solutions to their problems that
make sense. And each coder could probably visit the other
mud and work with a very small learning curve. But the code itself would
probably require substantial retooling to be interchanged.
Is
there a way to change the "default exit" room messages?
A lot of folks don't like having
default exits displayed at the
top. The muds they're used to display them at the bottom of the room
descriptions, and that's how they want their DS mud to look.
This is entirely doable, and not all that hard, really.
But it involves having some
understanding of LPC. The short
answer is "back up /lib/interactive.c, then modify
eventDescribeEnvironment() to suit your tastes."
However, failing to do this correctly will render you
unable to log into your mud, so I suggest you shelve
this idea until you are very comfortable with LPC.
This
dummy item is weird.
Dummy items *are* weird. They
exist because the parsing system requires objects
to act on. When you "look at painting", the parser doesn't take "painting"
as a string to match. Through a
magical mystical process deep in the MudOS driver, the
parser turns "painting" into an object to act on. It tries to find object in the
area that match this keyword, and if it finds
one, it sends that object a query about whether it can be
looked at. Depending on the response, the parser
continues on to determine what the verb (the command you
issued) thinks should happen to objects that can be
looked at, and tries to evaluate that event with the
object as its target. The process continues in a complex
dance of "may I? how so?" etc, until finally the
painting, the verb, the parser, and you come to an
agreement as to what the result of this looking should be. Crucial to this process is that
the painting actually *exist* as an object, so
it can be queried for various functions. Without a
"painting object" in the room, there's no parsing
that's going to happen with it. But what if this painting is
just part of the room description? You don't want
to add a painting to the inventory of a room just
so people can look at it. You want people to be able
to "look at painting", or "look at wall", or "look at
ceiling" without having to have all of these items
be part of the room's inventory. What a chore
that would be! This is where dummy items come
in. They are invisible objects that are set to
respond to the names they are assigned, such as
"ceiling", "wall", etc, handling the job of providing a
description when a person looks at the ceiling,
wall, etc. These kinds of dummy items are automatically
created when a room is loaded, based on what the
SetItems directive of the room contains. You'll also find dummy items for
special tasks, like a dummy button to
push in the town church.
Because of this specialized
role, dummy items are not intended to be
picked up or manipulated the way regular items are. If you
clone a dummy item, it's not going to behave
the way you want it to. A dummy item should only
ever be brought into existence by your code, not by
the clone command.
Clan
objects do nothing but screw things up.
Quite right! If you don't code a
clan object properly, it's extremely likely
to have little effect aside from screwing up a player's
savefile so badly that it needs to be destroyed. Why is this? Clan object code is
basically legacy guild code from Dead Souls
1.x. In the old versions of Dead Souls, guilds
were player-run institutions, operating basically
as clubs, with guild objects as a kind of
membership token. The version of LIB_GUILD that
came with Dead Souls 1.x was fatally buggy
in various ways. The most important way is that
even if you got it to work right, it did nothing
useful. There was no interaction with a guild or
player daemon, so if the guild leader quit, they
lost their guild leader status. Aside from
holding an object which designated them as a member
of a particular guild, LIB_GUILD provided no
advantage. I renamed it to LIB_CLAN,
because as a social-club object, that's a bit
closer to its role than "guild", which tended
to cause much confusion. Eventually there will be a
CLAN_D, and more sophisticated error handling to
prevent character file corruption. For now (version
2.0 of Dead Souls), just avoid using it.
My
NPC's stats are all hosed up.
Make sure you have SetLevel()
*after* SetRace() and SetClass(). Also make sure there's a working
::create() in your create function. Some examples are:
::create(); npc::create(); vendor::create();
And make sure your init()
function has an:
::init();
This
squirrel is taking *forever* to kill.
The mud is calculating its health
points based on level and race. If your squirrel has 340hp,
it'll seem unreasonably tough. Use SetMaxHealthPoints()
to cap its vitality to something like, say, 5.
Also, humans tend to be pretty
crappy at combat, unless they are of the fighter class.
Even a rat can be a challenge for a wimpy, weak
little level 1 human. Try using a dwarf or an orc to fight,
or make your character a fighter with: call
me->ChangeClass("fighter")
Even slips of paper and a bag of feathers. Anything at all
in your possession will make it super hard to fight.
An admin can change this so that encumbrance has no effect
at all. On ds2.1a15 and above, this is done with the command:
mudconfig encumbrance off
and a reboot.
My
room should not be entered/exited by just anyone. How do
I control this?
There are a couple of ways of
controlling entry to a room. Take a look at the "AddExit"
method in: /domains/town/room/valley.c
And also review the "CanReceive"
style in: /domains/town/room/wiz_hall.c
To prevent a room being exited
unless certain conditions are met, use CanRelease().
These strategies are not
discussed in detail in the Creators Manual, but the examples above should
provide ample information as to how to structure them.
Note that in general, objects
with a CanReceive() override should return ::CanReceive()
unless there is a good reason otherwise. It would
look like this:
int
CanReceive(object ob){
<if blah return 1> <if bleh
return 0> <etc and so
on>
return
::CanReceive(); }
Obviously the stuff between the
<> symbols is pseudocode and not LPC.
I
zapped a monster, but instead of being dead, now it's undead!
Take a look at the code for this
NPC. It probably has eventDie() overridden in a way
that does not return 1. This is not necessarily wrong. You may
*want* a monster that doesn't die like normal monsters do. But
if this behavior is unintended, that is probably the cause.
How does the format for race files work?
Race attributes are specified in
race files. They are found in
/secure/cfg/races
Here's a template with parameters
in parentheses for clarity:
RACE (race name here) SENSITIVITY (low light threshold):(bright light
threshold) LANGUAGE (self-explanatory) RESISTANCE (damage type):(how resistant we are
to the damage) STATS (name of the stat):(the average):(how
important. 1 is high) LIMB (limb name):(where it attaches):(how
important. 1 is high):(armor types) SKILL (skill name):(starting level):(how
important. 1 is high):(unused):(unused)
The unused fields in the skill
section are reserved for future implementation.
If the third field in the LIMB
line is 1, losing that limb will cause immediate death.
Special keywords can be appended
for particular functionality. These are:
FLYINGRACE (enables flying) LIMBLESSRACE (enables limbless travel) LIMBLESSCOMBATRACE (enables limbless combat) NONBITINGRACE (some races can't or won't bite) NOT_MEAT (specifies that when
it dies, a meat corpse shouldn't appear) SWIMMING_RACE (enables travel
in water) PLAYER_RACE
1 (enables the selection
of this race
for players)
Please note that while the
LIB_BODY object does specify a number of fingers, they
aren't items that can be severed, and their purpose
mostly is determining what kind of gloves you can wear.
NOT_MEAT is available in Dead Souls alpha 19 and above.
If NOT_MEAT is specified, then an npc of that race should
have SetBodyComposition() in its create() function.
For example, a rock golem should have:
SetBodyComposition("rock");
Please see /domains/default/npc/dummy.c for an example.
If an npc's race is NOT_MEAT, and it is not a robot,
and SetBodyComposition() is absent, it may not leave
any remains at all upon death, unless it has a composition
set by default in /lib/races.c
Dead Souls alpha libs have the following additional racial options:
MASS
An integer corresponding roughly
to weight on planet Earth, in pounds, multiplied by 10.
SIZE
/include/size_types.h
RESPIRATION_TYPE
/include/respiration_types.h
BODY_TYPE
/include/body_types.h
How
does the format for class files work?
Class files have only two types
of entry lines that Dead Souls
currently supports. The first is the name of the
class.
Every line after that is
presumed to be a skill specification line, in
the following format:
skill name:starting
level:importance to the class (1 is highest)
What
do Properties do?
Properties are a way to provide
flexibility in the lib. Objects usually work by
having variables that are modified by functions.
This allows a player to have, for example, a SpellBook
variable which contains the spells she knows,
and this variable in turn is affected by "spell
learning" functions, etc.
Suppose, however, that I want to
set a variable in a player, but that
variable does not exist. This is tricky indeed,
because it would involve a modification to one or
more library objects, and reloading them...possibly
requiring re-logins or (very rarely) even rebooting
the mud.
Instead you can use properties
as a quick and dirty way to get that
functionality without rewriting lib objects. For
example, if you do something like this:
SetProperty() and
SetProperties() are just convenient ways to create and
modify custom variables in objects and players on the fly.
Strictly speaking this is not good coding practice.
Anything useful enough to make into a Property is useful
enough to do in another way. However, it is available to you
as another implement in your coders' toolbox.
How
do I add a prehensile limb to a player or NPC?
See the Creator's Manual for
details on adding, desting, and removing limbs.
If a creature lacks a prehensile limb, they can't do
things like get objects, wear clothes, wield weapons, etc.
How
do I make a room occasionally display messages?
Use SetAction. There is a
well-commented example of this in
/domains/town/room/shore.c .
My
functional isn't working!
Functionals are a kind of
reference to a function. They won't work everywhere. For the
most part they serve as a pointer, and are used the way a variable
would be used. If the place you put the functional wouldn't make
sense for a variable, it wouldn't make sense for the functional
either. For example,
SetLong( (: ShowLong :) );
makes sense, because what's
happening is that instead of a string, your argument is a
function that returns a
string.
However, something like this
wouldn't work,
if( Cabbages == Kings ) (:
eventTalk :);
because you're treating a
functional as if it were a function. It isn't. In a case like this,
your line should look like this:
if( Cabbages == Kings )
eventTalk();
I've
read the Creator's Manual but I still don't understand mappings and
arrays.
Yeah, they can be tricky to get
a handle on. Let's suppose you're going to set up a nautical
commerce system, where you have to keep track of ships and their data. You
store ship data in a daemon, which is an object that stays loaded in
memory to manage information, but doesn't actually exist as a cloned item
in the game. We'll call it SHIPPING_D.
So, SHIPPING_D needs to keep
track of how many ships there are. I would do this with an array,
not a mapping, because it is a simple list, like this:
string *ship_list = ({ "Caine",
"Bounty" });
That way, when SHIPPING_D gets
queried for a list of all known ships, it can just return that
simple list. If you needed to add a ship, you'd have the daemon
perform this operation:
ship_list += ({ "Pequod" });
To remove a ship:
ship_list -= ({ "Caine" });
Suppose, however, that not only
do you need to keep track of ship names, but also their
captains, crew complement, etc. You could try to use an array for this, but it
would be very unwieldy. This is because to pick out specific elements,
you need to use a number. For example, if the ship_list array is ({
"Caine", "Bounty", "Pequod" }) then ship_list[0] is "Caine" and
ship_list[2] is "Pequod". If you were to try having an
array for each ship that contained complex information,
you'd have stuff like this:
There are a couple of problems
with this. First, the ship_list array is going to be a bit of a
mess. Second, you'll have to address the ship's data elements by their
array index number. For example, to know the Caine's crew complement,
you'll need to do something like this:
foreach(string *ship_data in
ship_list){ if(ship_data[0] == "Caine")
return ship_data[2]; }
The first step is to check each
element in ship_list to know if its first element is
"Caine", then return its third element, which is 117. Not only is this
inelegant and overcomplicated, it is not guaranteed to work.
Careless manipulation of your subarrays can result in elements being out
of order, with potentially disastrous results on your code.
It's just not a wise way to go about this. This is where
mappings come in. Rather than the mess above, we'd do it like this:
It looks more complicated, but
in fact it's a major simplification of your data and its access. Now
you have a sure-fire way to query a specific ship and its specific
data elements without a shadow of doubt as to what you'll get back.
Now if you want to know the name
of the Caine's captain, it looks like this:
return
AllShips["Caine"]["captain"];
Basically this is a mapping
inside a mapping. The mapping called Caine contains the element
"captain". Because the mapping Caine is an element in the mapping AllShips,
you access an element in it in the way shown above.
In a less complicated example,
mappings might be used, for example to store information
about, say, fish:
To remove a mapping element, use
the map_delete efun:
map_delete( FishTypes, "carp" );
Why are call_outs so bad?
Garfield@M*U*D
<ds> I'm wondering.. Why are call_outs so bad?
Cratylus <ds> ya good
question
Cratylus <ds> in themselves
they arent. One call_out more or less wont make the angels cry
Garfield@M*U*D
<ds> From what I can tell, they shouldn't be too bad if not
implemented poorly.
Cratylus <ds> the problem
is that if your creators get the idea call_outs are ok, you'll be
swamped with them
Garfield@M*U*D
<ds> Right. You want 10s of them, not 100s.
Cratylus <ds> and they, for
reasons i cant explain to you because it's driver related, are
expensive to run
Garfield@M*U*D
<ds> Can't explain because you're not familiar with the driver?
Cratylus <ds> right
Garfield@M*U*D
<ds> Right. Fair 'nuff.
Cratylus <ds> but i can
vouch for the truth of the proposition
Cratylus <ds> limbs used to
decompose, each with a call_out of its own
Cratylus <ds> if you
released the rage virus into the menagerie, your mud would eventually
crawl to a stop
<ds>
Garfield@M*U*D hehs.
Garfield@M*U*D
<ds> What amount of call_outs are we talking here? Hundreds?
Thousands?
Cratylus <ds> fewer than
200 as i recall
Cratylus <ds> but the
memory is hazy
Garfield@M*U*D
<ds> Hrm. Ick.
Garfield@M*U*D
<ds> I might peek at how they work.
Cratylus <ds> it also
redlined the processor
Garfield@M*U*D
<ds> Right.
Cratylus <ds> lucky for me
i have a 4-way box
Fine.
How am I supposed to create timed events, then?
There is a built in timing
system that uses the heart_beat() efun. To enable it, use
set_heart_beat() on the object that is to have a timed effect.
set_heart_beat(1) gives the object about one heart_beat per second.
set_heart_beat(60) gives it a heart_beat about once a minute.
Whenever the object has a
heart_beat happen, the function heart_beat() is called in it. So,
for example, an NPC might have a heart_beat function like this:
If the NPC's create() function
contains a set_heart_beat(10) then it will say "Hi!" every ten
seconds.
Another way to control it would
be to have a counter. You would define a global integer
variable by putting in in the body of the NPC's file before any
functions are defined. For example:
int counter = 0;
somewhere before the create()
function. Then your heart_beat function might look like this:
If the NPC's heart_beat is set
to 1, then the NPC will make his greeting about every ten
seconds. If its heart_beat is set to ten, then it'll take a minute and
forty seconds per greeting. Note that at the end of the if()
check, the counter is reset to 0 if the action is triggered.
I
need a list of all the functions available.
If you read the section on efuns
and sefuns, you have an idea of what they are. They are
documented in /doc/sefun and /doc/efun , and doing a list of
the dirs and subdirs there will give you a "list" of them.
The documentation on individual sefuns and efuns is generally
available through the man command, for example: man sscanf
If you're looking for
lists of library functions, such as SetClass in LIB_WEAPON,
your best bet is the help command, like this:
help library
objects weapon
help library
objects creator
That will list the functions in
the library object you specify. As of this writing,
the documentation on lfuns is not yet as thorough as the
documentation on efuns and sefuns, but this documentation is an
ongoing project whose output should eventually improve.
How
do I make an object you can [ jump on | climb | etc ] ?
Look for an example, and copy
it. Take a look at the code in the newbie mansion ladder
for climb code. Take a look at
/domains/Ylsrim/room/bank_roof.c for an example of something you can jump from. Other actions
will have similar examples. The sample domains are there for you
to explore and find examples of what you want to do.
Where
is the list of available skills? How do I add skills?
Please read the Administrator's
Guidebook chapter entitled "Understanding the Lib",
and skip to section named "Section IV: Skills".
Where
is the list of available classes? How do I add a class?
Type: ls
/secure/cfg/classes
To add a class, copy one of
those files and call it whatever the class should be. For
example:
cd
/secure/cfg/classes cp thief farmer
The modify the new file to suit
you. When you're done, use admintool to add the class to the class daemon. Type help admintool for information on that command.
Obviously, you'll need to be an
admin or assistant admin for this to work.
There is no list of languages.
It doesn't work that way. There is no centralized language
database, daemon, or anything like that. Languages are
basically like a skill: only useful to the extent that lib objects make
use of them.
A player might be able to
understand Tamarian, but if nobody else in the lib does, it
isn't much use. If no written material is in Tamarian besides, then the
player's language ability is a waste.
On the other hand, if a player
wants to be able to understand orcs, all she has to
do is find a language teacher that can instruct her in that
tongue. After enough lessons, she will be at 100% fluency, and
if she encounters written or spoken information in Tangetto,
she'll be able to understand all of it.
To know what languages you
understand, and to what extent, use the command:
language
To make yourself fluent in
English, type:
anglicize me
To make yourself fluent in all
languages, type:
polyglottize me
Obviously these commands are
available only to creators.
When
I try to call Bozo->SetLanguage("Clownish", 50), it sets it to 100%
Bozo is probably a newbie. If
Bozo's player level is at or below what is defined as newbie in
/secure/include/config.h, then he understands all languages at 100%. Raise his
level above that, and you should see his proficiency in that language
drop to what you specified.
How
do I update an .h file?
You don't, really. That's a
header file, which contains code to be included by a .c file. Only a
.c file gets loaded into memory, so to "update" an .h file, you
update the .c file that includes it. In the case of a global include,
like daemons.h, you would update the master object (also called the
master daemon) thusly:
update
/secure/daemon/master
I
want to put an object in a room that doesn't show up in the inventory but
it can be manipulated.
Typically the job of "being
invisible but examinable" is something done by dummy items. In FAQ
2.39 you read about how dummy
items work and how they let you have things in
rooms that are looked at, but not taken.
Suppose, however, that you want
to have a sittable bench in the long description, but you don't want
it to show up in the room's inventory. Or a chest that can be opened and
closed, but again, not part of the room's inventory list?
You can't just make the item
invisible, because then "look at bench" will return "There is no bench
here." The solution is to *inherit* a dummy item, and and give it
benchy functionality by also inheriting the things a sittable object needs.
For example:
#include <lib.h> inherit LIB_DUMMY; inherit LIB_SIT; inherit LIB_SURFACE; static void create() { dummy::create(); surface::create(); SetKeyName("bench"); SetId("bench"); SetAdjectives("wooden"); SetShort("a wooden bench"); SetLong("This is a typical
wooden bench, the sort you might "+ "see in a park. It appears
designed for sitting on."); SetMaxSitters(3); SetInvis(1); } mixed CanGet(object ob) { return
"The bench does not budge.";}
You can then add this file to
your room's inventory, and now you'll have a bench that
doesn't show up in the room's inventory, but can be
examined and used. In the case of a chest or a wardrobe, you'd want
to inherit LIB_DUMMY and LIB_STORAGE. There are some
key rules to keep in mind when doing this:
Always inherit LIB_DUMMY first.
Always invoke dummy::create()
before other ::creates()'s.
Make sure you have CanGet()
return an error string.
Make sure the item is
SetInvis(1).
What
is pass by reference? What is pass by value?
This is a slippery concept to
grasp for many folks. It has to do with the way that a
variable is handled, when it interacts with a function.
When you pass by value, you send
to the function the value that is held by the
variable. When you pass by reference, you send to the function a pointer to
the variable, not the value that it contains. This is critically
important to what happens to the variable when the function is
done doing its work. Let's take a look at a sample function:
This
is your typical simple function.
It wants to be fed some input at the
top, then it will digest it in the middle,
and then it will poop out whatever the
result of its digestion is. That's the return,
down at the bottom.
This one wants to be fed an
integer. When you put the integer into its feeding
funnel at the top, that integer will be stored
in the function's local variable "B". B will stand
for that integer.
The function then adds the
integer 1 to B. B is now whatever you put into the
function plus one.
This new value is what is now
returned, when the function completes.
Pretty straightforward. Let's
look at actually sending data to this function.
At the top of this illustration you see a variable called "A". A is of the type "integer", and
it contains the value 42. We're going to feed A to
SimpleFunction. We will "pass by value".
What is happening is that
whatever it is that A contains as a value, we are sending to our
function. We therefore are feeding the integer 42 to SimpleFunction.
SimpleFunction does its thing. B
is now equal to 42. Then we add 1 to it. Now B is equal to
43.
We are done. The function poops
out 43 as the return value. B is a local variable, so when
the function ends, its value resets and it is null. At the end
of this process: return value == 43, A == 42, B == NULL
We will now
send data again, but this
time, we will "pass by reference". This is slightly different. In
the previous example, we passed the value of A to SimpleFunction.
Instead, we will now pass a
reference to A to the
function. For all
practical purposes we are not sending 42.We are sending the variable A
itself.
The implications are
important.
When we feed A to SimpleFunction, B no longer means "a local
variable named B". B becomes a pointer to A. This means that even though
the function, as written, reads B = B + 1, when you pass by
reference you are actually performing the operation on the referenced
variable itself, so what it's actually doing is A = A +1. At the end of
this process: return value == 43, A == 43, B == NULL
You can see why it is vitally
important to grasp this concept. If you perform a pass by
reference operation, you will get the exact same return, or output, from the
function as if you had passed by value. However, you will have
modified the variable you passed to the function. If that's what you want
to do, great. But if you do it by accident, woe is you.
Note that in ds2.1a16 and above, you can use the "ref" keyword
to force a simple variable to pass by reference. For an example,
see /domains/default/obj/pass_example.c
ZOMG
pass by reference is terrible! How do I avoid it?
Fortunately, simple LPC
datatypes do not pass by reference as default behavior. Strings and
integers pass by value, so you don't have to worry
about accidentally mangling that data.
However, objects, mappings,
functions, and arrays all pass by reference. If you are not
careful in handling those datatypes, you can end up with some
extremely puzzling outcomes. When manipulating complex datatypes,
it is useful to use the copy() sefun, if you don't want to
modify the original variable. for example:
This function takes a string
array as an argument, and returns an array that is like
the input array, but without its first element. By using the
copy() sefun, we manipulated the an array identical to
InputArray in value, while leaving InputArray itself alone. If
instead of:
string *LocalArray =
copy(InputArray);
we had used:
string *LocalArray = InputArray;
Then the return value would have
been the same, but whatever the array was that we
passed to this function as an argument has been modified.
What
does the :: operator do?
Detah <ds> does anyone have
time to explain 1 line of code to me please. specifically score.c L15
daemon::create()
Cratylus
<ds> hmm
Cratylus
<ds> the :: is the "scope resolution operator"
Cratylus
<ds> that line says "in the file i inherited called daemon, run
the create function"
Detah <ds> so to understand
that line, I need to go to daemon.c and read the create() fun there?
Cratylus
<ds> yep
Detah <ds> ty
Cratylus
<ds> np
I
know this file is fine. I
copied it from another file that works,
but it won't update. This is driving me insane.
There are few circumstances under
which a properly-coded file will not update:
1) Files placed in /tmp will not
update.
2) Verbs placed outside the /verb
dir will not update.
3) Dead Souls does not handle
files with spaces in the name.
4) If the file you copied from
has a relative include (such as #include "./customdefs.h" ) and you copy that to a different
directory, the relative include will make the update fail if you don't
have the header file where it expects it.
5) If the file has a
SetInventory() that contains broken files or broken filenames or files that do not exist, the
update will probably fail in some way.
6) Files in directories that
aren't readable to you won't update.
7) .h files do not update.
8) Dead Souls is case-sensitive.
My_New_Room.c is a different file from my_new_room.c .
What
is SetEncounter supposed to do?
When objects meet in the same
environment, they call SetEncounter() in themselves to see if anything
interesting should occur, based on the other items in the
environment.
In the case of an NPC,
SetEncounter(50) means "if a living thing comes into the room, and its
charisma is lower than 50, kill it".
To make it always aggressive,
you'd set that to an appropriately high number.
Alternately you can put a
function pointer in there, to make a more sophisticated condition for
attack, or perhaps something other than combat.
See /domains/town/npc/orc.c for
an example.
I keep getting
"This should be edited by hand. Change cancelled."
The QCS is carefully designed and
calibrated to prevent you from
creating broken objects or damaging working ones. Even so, it is
possible to make very inconvenient mistakes with it.
One of the most common ways for a newbie to shoot himself in the
foot is by altering their workroom in a way he doesn't understand,
then being unable to restore it to its original state.
The workroom therefore has a feature that prevents it from being
modified with the QCS. If you go to your workroom and type more here , you will see that
SetNoModify(1) is in the file. This
makes the QCS refuse to make changes to the file.
To make changes to your workroom, either use the mud's line editor,
or use the following command while standing in your workroom: modify here setnomodify 0
By setting SetNoModify(0), you enable QCS to make changes to the room.
Note that asking for help fixing a workroom you screwed up
is an excellent way to brand yourself a Hopeless Newbie.
zOMGLOLERZ I
did what said but no my workrom really IS broke!!1!
In the inevitable case of someone damaging their workroom despite
my warnings and safeguards, your homedir contains a default
backup workroom file. To restore your workroom to its original,
working form, type:
cd mv workroom.c workroom.fukt1 cp workroom.bak workroom.c update workroom.c home
I can't find
the SetQuatloos() lfun anywhere!
One of the reasons people want a "list of all functions" is that
tracking down where a given function is defined can be a real pain.
For users of Dead Souls 2.1.1 and below, the only real option is
to do the following:
cd <directory to be searched> grep SetQuatloos *
This will search the files in your current directory and list to
you the files that contain your search string...in this case,
SetQuatloos.
Users of 2.1a15 and above have more options available to them. They
can use recursive grep:
cd /lib grep -r SetQuatloos *
This allows you to search not just your current directory, but all
subdirectories as well.
Neater still is the findfun command:
findfun SetQuatloos
This is more precise than grep. "grep" will tell you where the string
exists, but this includes places where it is called. "findfun" will tell
you where in /lib the function is defined,
which means that it tells you
which files contain the code that SetQuatloos() uses.
For more information on finding and analyzing library functions, see: help findfun help showfuns
What does "This
room needs a corresponding SetItem to make a SetEnter" mean?
For a player to "enter porthole", the room must have a "porthole" to
"enter".
That means that there must be an AddItem or a SetItems element called
"porthole"
in the room...else the SetEnter won't work. The rule of thumb is, if
you can't look at the enter, you can't enter it. In this case, if you
can't "look at porthole" you can safely assume you won't be able to
create an enter by that name. Either add the item manually by editing
(using AddItem or SetItem) or use QCS ( modify here items ). Please
see the QCS example page for how adding
items with QCS works.
Section 3: Intermud and channel stuff
How
do I know what other muds are online on intermud?
Type: mudlist
To see online Dead Souls
muds type: mudlist -m dead
Hey,
LeetFooMud is online! How can I tell if Biff is logged on?
To see who's logged on: rwho leetfoomud To tell Biff hello: tellbiff@leetfoomud
hello To see if Biff is listening to <ds>: list ds@leetfoomud To check out Biff's personal
info: finger
biff@leetfoomud
That's
weird...mudlist says LeetFooMud is there but I'm not getting anything
back.
The mudlist command reports on
data retrieved the last time the intermud daemon received an
update. This means that if LeetFooMud dropped off, say, 10
minutes ago, or if your own intermud connection is down, your
intermud commands are falling into the void.
To see if your intermud
connection is up, type: wiz This takes you to the Creator's
Hall, where a sign indicates your mud's intermud connection
status. This
sign may be up to
15 minutes out of date.
You can also test your mud's
intermud connection with the ping command, like this:
ping dead souls
ping frontiers
I
heard there are intermud channels that talk between other muds, not
just Dead Souls muds. How can I use them?
Ask your admin. Those channels
may not be open for use on your mud.
If you talk on <intercre>, be polite, and use the same rules of common sense and intelligent
questioning that you need to follow for <ds>. <intercre> is for code and technical questions ONLY. Do not ever spam it or use it for
chatting.
I strongly discourage you from
talking on <intergossip>. I assure you nothing good will come
of it. This warning only applies to the old intermud.org
router, known as *gjs. The intermud channel on the new
*yatmim router is much friendlier to newbies.
How
do I emote on a channel?
Add the word "emote" to the channel command.
For example:
creemote
compels your silence.
gets seen on the channel as: <cre>
Cratylus compels your
silence.
You can also add a colon to the
message, like this:
cre :compels
your silence.
How
do I see what I missed on a channel?
To see the recent messages, use
hist. For example:
hist ds
To see older stuff, look in
/log/chan
I
am sick and tired of the *gjs intermud network going down. Please fix
it.
If you really want just to chat,
then use <dchat>, since that's what it's there for.
Ask your admin for how to do this. I'd rather you expose <dchat> to your boredom than <ds>.
You can also try out <intergossip>.
Ask your admin
for details on that, as well. Be warned that <intergossip>
can be expected to contain extremely coarse language and
attitudes. You're really much better off not going there.
Alternately, there's a <ds_test> channel which is intended specifically for spammy
channel tests and such.
I'll
spam if I want to. You're not the boss of me.
It's true, I can't do much if
you're determined to be a jerk. If you consistently abuse
channels, your admin may be asked to limit your channel
access. In extreme cases, your mud may find itself banned
from the channel in question. I can only appeal to your sense
of fair play. Spamming hurts people who have
nothing to do with whatever you're pissed off about. Please
don't make whatever your problem is with someone a
headache for everyone.
This guy keeps hassling me on an
intermud channel
Sometimes people just can't leave
well enough alone, and they spam. Some people just
don't have anything to say that you want to hear. For
such situation, use the earmuff command. For
example:
earmuff
tatianna
And you will not receive channel
messages from that person. The reverse command
is unmuff. Earmuffing is also good when
someone from a non-European-language mud sends
well-meaning but garbled, escape-code filled
gibberish. If she doesn't understand your
English language requests to stop spamming, you
can just earmuff her.
What's the deal
with channel rules and banning and whatnot?
Basically, if you spam, or try to use the intermud router
commercially, or try to use it to hack or hurt other people,
or use hate speech, you're going to run into problems of
some sort. If I happen to be the one catching it, you're
liable to be banned for it on the spot, though I usually
make numerous warnings to a mud before taking the
drastic step of banning them from a channel.
Note that another vector for channel banning is abusing
a channel by not respecting the channel topic and customs. If
you insist on swearing and/or being hostile on <ds> (a channel
for friendly Dead Souls talk) or <dchat> (a channel for
friendly general chat) despite being warned, you may
find that you aren't able to use those channels.
On the other hand, being crude and obnoxious on
<intergossip> is entirely acceptable, within the
limits of router rule 5 (no commercial advertising,
hate speech, etc).
Some people have found it unpleasant that I enforce the
router rules. I understand that they are people who
are arguing their point from a good faith belief in the
righteousness of their position. However, the reality is
that one guy runs the router, and enforcement is up to
that one guy, and that's me.
The point of the router is to have a productive environment
where muds can communicate and conduct their business,
promoting the health and growth of new LP muds. If I
have to seem like a fascist in order for that to be
so, then so be it. But being a fascist is not the point.
I'm
fighting the beggar with my staff and he's kicking my ass
For one thing, you're a creator. Quit goofing around. If you want to
fight monsters and stuff, create a test player
character.
Next, you're probably still a Level 1 character. This makes you a
wimp. Raise your level with this command:
call
me->SetLevel(20)
Now get the medical tricorder from your workroom's chest and
raise your stats. Give yourself 100 strength. Why not?
If you're carrying a chest, table, chair, and
everything else you've
come across, you will be unable to do much during
combat. Try to wield a weapon, hold a couple of shopping bags
and boxes, and see how well you do against a pissed off
real-life enemy. You won't last long. So either drop all the
crap you're lugging around, or put it in a backpack
and wear the pack.
Put the staff in your robe and quit using it as a weapon.
It's a creating tool. Not only is it a poor weapon,
by default you lack double-handed weapon
skills, making you really crappy at using a really
crappy weapon. No wonder the orcs were beating you
like an animal. Get a carving knife from the
mansion. Or an orcslayer. Or hell, just use the zap
command and stop wasting time. You should have
characters for this.
Someone
amputated all my limbs and I can't do anything!
If your body
gets damaged you can restore yourself to your normal
physical status by typing:
heal
me
How
do I change my class?
Again
with the pretending to be a
player. Seriously, you need a
test player char so that if you screw something up, you don't
screw *yourself* up.
But, if
you're determined:
call
me->ChangeClass("thief")
Your
stats and levels will probably be all weird and hosed up.
Just raise your player level, that will probably fix it.
People
are talking to me in gibberish, even though it
says they're speaking English.
If your race
is not human, your default language is not English,
therefore someone
speaking in English would not be understood by you. As a creator, you
can avoid players' tedious language learning process and simply
type:
call
me->SetLanguage("English",100)
Obviously this will work for other languages too.
What's
this about Biff "unknowingly" telling me something?
If you are
invis and a player or someone on another mud tells to you, they
get an error message about you not being around. So, they told to
you, but do not know you actually got the message, since you
don't seem logged on.
How
do I find the location of a verb or command?
Use the which
command. For example:
which
zap
which
update
If 'which'
doesn't find it, the command is probably built into some object
you inherit, like the command shell or the hooks for the
chat daemon. Or it may be an add_action bound to a nearby
object. To see what commands objects or inherited files might
be providing you, type:
localcmds
Where
are the "exa" and "n" commands?
When you type some commands,
like exa, n, or i, what happens is that your command
shell recognizes them as aliases, and turns the
alias into the appropriate command. An alias is like a nickname, or
shorter word, for a command or series of
commands. To see the aliases you currently have, type: alias
To make a new alias: alias ml
mudlist
To make an alias that replaces a
specific command while permitting you to supply
arguments to it: alias ig
intergossip $*
To remove an alias: alias ig
After modifying aliases,
make sure to type: save How
do I get something to happen to a random person in a room? You can
pick a
random winner (or victim) for your action by using the
get_random_living() sefun. For
details on its usage:
man
get_random_living
You may also
find the get_livings() sefun useful.
My
wandering monster escaped from my workroom! How can I
find him?
If its name is jabberwock, try:
findobj
jabberwock
You can also probably just:
goto jabberwock
I
ran findobj on something but it says no environment. Where is it?
Right where
it says. Some objects create a "master copy" of themselves when they are
cloned. This copy remains loaded in memory even if that cloned
object goes away. You can distinguish between cloned objects and
master copies by the number sign and number at the end of cloned
objects. The master copy has no instance number. It is simply loaded
code, and does not "exist" in a way accessible to your player object on the
mud.
Sometimes a
cloned object will lose its environment. This is usually caused by an
error and is not a good thing. Dead Souls runs a "reaper"
daemon that periodically searches memory for cloned objects that
lack an environment, and they are destroyed.
How
do I update everything in a directory?
You really
shouldn't. There are very few cases I can think of where
updating an entire directory is something an average creator needs
to do. How often do you edit multiple files at once
without individually updating them? Good coding
practice is to update the one file you just worked on to know if it works
at all.
I also
discourage it because when you do this, you lag the mud considerably.
I/O is the most resource intensive kind of operation, and updating
is on its own quite resource intensive. Updating a directory
with dozens of files in it will cause a noticeable hiccup in the rest
of the mud.
If you are
determined to do this, though, the
command is :
update
/path/to/dir/*
I
don't like getting colors on my screen. How do I stop it?
Type: terminal
unknown
then type: save
Um...I
want colors back now please
Type: terminal
ansi
then type: save
I
can type 'n' and move north, but 'north' doesn't work.
Technically,
you can't 'n' either. When you type 'n', what it happening
is that your preset alias turns that 'n' into the
command line 'go
north'.
Because you do not have an alias 'north' that expands to 'go
north',
'north' doesn't
take you anywhere. But go
north
will.
Why
is there a bunch of stuff in ROOMS_FURNACE?
The QCS is
designed to attempt the graceful handling of unusual
events. Sloppy code, non-working objects, etc. Part of
this design is avoiding a situation where an
object's destruction affects your local environment
(and this happens a bit more often than you might
think).
To avoid some types of unpleasantness, QCS doesn't try to
immediately destruct objects when replacing them. Instead, they
are moved, along with whatever problems they might
have, to ROOMS_FURNACE. That is a room where things
go to be destructed quietly. Every second or so,
the contents of that room are destroyed, and their
bits recycled.
A few other items in the lib use the furnace, notably the
recycling bins and the reload command.
How
do I change
my screen and terminal settings?
help
terminal
help
screen
screen
79 24
ZOMG
this is the best mudlib evar how can I evar thank you?
No need,
citizen. Merely doing my job.
Just let me
know what bugs you find, and how I can make the lib
better.
Dude
this mudlib sux0rz @ss. What a waste of my time.
I'm sure Dead Souls has lots of
things that you don't like, but I can't fix them if I
don't know what they are. Email me so that I can understand
the lameness, and so others can benefit for your
suggestions.
I'm
seeing a filename but I can't read it.
If you try command and you get
something like:
/secure/foo/bar: No such
reference.
It means you don't have read
access to that file or directory. I've someone
make a stink about how a file they can't read
shouldn't be visible to them or some such thing. However, I
think he was just being difficult. Some files you
can't read, even though you have access to the
directory they're in. That's the story.
Is
there a command to go back to your previous directory without
having to type it all out again?
The shell has a few handy
builtins.
To go up a directory: cd ..
To go to your home dir: cd ~
To go to your area directory cd ~/area
To go to the /domains dir: cd ^
To go to /domains/default: cd ^default
To go to the directory you were
in before the current one: cd ~-
When
I'm in combat, I keep getting messages about not being able
to fight while carrying stuff, but I only have X, Y, and Z on me.
I was carrying some dishes to the
kitchen a while back, and it occurred to me that even if I had
a sword, if someone jumped out and started fighting me, the
first thing I'd have to do is drop anything I'm not wielding,
or get my butt kicked.
The more I thought about it, the
more it made sense to set up an encumbrance system that
prevented proper fighting ability so long as you're carrying anything
that isn't worn or wielded, no matter how heavy.
If you don't like this behavior,
talk to your admin abour changing the encumbrance define in
/secure/include/config.h .
QCS is a way to use simple
commands to manipulate complex files. Sometimes the
conversion between simple and complex causes unusual
compromises and outcomes.
When you create a new room, what
QCS does is look at the room you're
currently in. Let's say you're standing in
/realms/you/area/room/test1.c. And you issue the command
create room
east test2
In this case, "test2" is
considered a "relative path", which means that you didn't
provide QCS with *exactly* where you want the file to be. You told
QCS to figure out where to put that file. When QCS has to guess where a
new room goes, it simply assumes that the room
goes in the same directory as the current room. So, in this
case, you're going to make a file with this path:
/realms/you/area/room/test2.c
Suppose that this is not where
you want the new room to be. you want it to go
into /realms/you/testrooms/. In this case, you need to tell
QCS the "full path", like this:
create room
east /realms/you/testrooms/test2
When you create non-room
objects, also known as tangible items, QCS guesses in a
slightly different way. If you provide a relative name,
then QCS looks at your current working directory (cwd).
Based on the type of item, QCS looks for a directory with
the appropriate name. For example, if your cwd is
/realms/you/foo, and the type of object is a weapon, then QCS
looks for a directory named "/realms/you/foo/weap/". If it
exists, it puts your new file there. Otherwise it tries to
put it in "/realms/you/weap/". And if that doesn't work, it'll
default to your home area weapon directory, which is
"/realms/you/area/weap/".
If you've been granted domain
admin status, and you are using QCS to work on your
new domain, it's therefore very important that your cwd be
in the right place in the domain directory for it to work.
Otherwise, your new stuff may wind up in your default area dir,
and you could go nuts trying to find it.
Of course, you can avoid all
ambiguity by simply using a full path, like:
How
do I make a blank room, instead of copying the current one?
You'll always copy the old room, that's just how QCS works.
But you can quickly change it to a blank room by
entering the new room and issuing this command:
copy
/obj/room
How do I create an area?
You have a default area directory in your homedir. By
default, your QCS creations get put in there. However, if
your area is ever going to be put into play, it
could be inconvenient to move it into the /domains
directory, because every file reference will have to be
changed.
If your admins use unix and perl, this is trivial. If not, it's
a real obstacle.
Therefore, if you're going to work on an area that will
someday be open to the public, it's a good idea to
start in the /domains dir. Your admin will need to
create the appropriate directories. For example,
if the domain is to be FunkyTown, you'll need
/domains/FunkyTown, /domains/FunkyTown/room, and so on.
You will also need to have your admin make you a domain
admin of FunkyTown with the domainadmin command. This
will permit you to use QCS there.
That's the technical part of getting started with an area.
The hard part is that you need to know what
you're doing, you have to have a creative vision, and
the language skills to make it evocative, immersive,
and worth playing in. That's up to you...I
can't help you with that.
How do I make a quest? Think of a quest in terms of the
result. The result of a quest is a player
receiving quest points and a quest title. This means that pretty much
anything can be a quest. If you've coded a
rock to provide quest points and a quest title
when it is picked up, well, there's your
Rock Quest. However, you usually want to make things a
bit more challenging.
A quest can be as boring as
"pick up the red rock" or it can be a challenging
metaphysical inquiry into the nature of consciousness. If quest
points and a quest title are at the end of a series of
actions, then that series of actions is a quest. What those actions
should be are entirely up to your imagination. Review the
orcslayer quest in the Player's Handbook for an example.
You did read the Player's Handbook, right? Take a look at Leo the
Archwizard's code for an example of the mechanics of solving a quest.
Where's
Leo?
Read the
Player's Handbook already, please.
Where
are the vehicles and mounts?
There are none yet. After 2.1 is
released, I'll be able to concentrate on adding
new systems like that. For now, it's just bugfixes and
vital functionality I'm working on. However, 2.1
should be released Real Soon Now.
I'm
having trouble adding meals to my barkeep with QCS.
Cratylus <ds> ok here's the
deal
<ds>
Daelas@Moraelinost scrunches on the edge of his seat.
Cratylus <ds> menu items
can have more than one id
<ds>
Daelas@Moraelinost nods solemnly.
Cratylus <ds> "ale","first
class ale","beer"
Daelas@Moraelinost
<ds> with you so far.
Cratylus <ds> when you:
modify barkeep menuitems
Cratylus <ds> it asks you
for the id's
Daelas@Moraelinost
<ds> I didn't get that.
Cratylus <ds> when you're
done entering id's, you hit a period
Daelas@Moraelinost
<ds> is it SetMenuItems or menuitmes.
Cratylus <ds> then you
enter the filename to the item sold
I
heard DS has stargates. Where's an example?
The following rooms have
stargates:
/domains/Ylsrim/room/tower.c
/domains/default/room/stargate_lab.c
For info on valid gates, type: stargate
I
created a vendor, but he isn't responding to the "list" command.
The list command isn't part of
the vendor object. It's part of LIB_SHOP, which is a room
that acts as a sort of front-end for the vendor. The commands list, show, price, and appraise are not in the vendor, but in the
shop. To get the appropriate responses from the vendor, you would use
the following syntax:
list: ask vendor to browse show: ask vendor to show
<item> price: ask vendor to price
<item> appraise: ask vendor to
appraise <item>
I
gave room with a default smell but I cannot get any other smells in
there, such
as 'smell object' for example
SetSmell, like
SetListen, is in the form of a mapping. When using the QCS, the
correct formatting is automatically made for you. If coding by hand, take
a look at /domains/town/room/riverbank.c for what it looks like.
Note that for each Smell or Listen, you need a corresponding SetItems
element.
How do I make a
weapon more powerful?
Modify SetClass(). SetClass(20), for example, will make the weapon's
raw damage (before adjusting for armor, the opponent's skills,
magical protection, etc) be 20. So on a sleeping, naked, unenchanted
target, the weapon (assuming the wielder is adept) would take
away 20 health points on a successful strike.
As you can see, there are many modifiers on a weapon's effectiveness,
including the target's susceptibility to that kind of weapon. There
is no written-down formula for the exact amount of damage. You'll
need to make test weapons and test npc's and determine for yourself
the appropriate balance.
A convenient way to do this is in the arena. Type:
goto /domains/default/room/arena
There you'll see a training dummy and an npc you can use to
test your weapons and armor. The dummy talks whenever he is
hit, and describes the kind and extent and location of the
damage he has received. For a demonstration, type:
force fighter to kill dummy
You can make a weapon cause a certain amount of damage regardless
of protection by adding the appropriate code in in eventStrike().
Please see chapter 29 of the Creator's Manual for details and examples.
My NPC refuses
to wield his weapon!
There are a number of reasons this might be. If it is a two-handed
weapon, and he is already wielding something in one hand, that
would cause a failure. If the NPC is wearing a shield, and you
don't specify which hand to wield in, the NPC might default to
trying to wield on the shield hand, and that would fail.
To troubleshoot the problem, have the NPC wield specific things on
specific limbs to see if that works. For example,
force orc wield a sword in left hand force orc wield my first sword in
right hand