Updated May 2009. 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 to you on your
mud, type: lines
2) Your mud is probably on the
Intermud-3
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 dead-souls.net
8000
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
or:
chan block 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.
If you're using a relatively recent version of Dead Souls, you
can avoid some of the pain of the ed
line editor by enabling "CreWeb".
CreWeb is a web-based application that can run from the built-in
Dead Souls webserver, allowing you to edit and upload files
without having to mess with ed. For more information, type:
If you use a character-mode compliant telnet client, you might
also avail yorself of ced.
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. This
is also true for Praxis.
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?
I don't remember.
Why do you keep asking me to post my code?
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.
"help
modify" breaks.
This is typically the result of your columns screen
setting being very large. Type:
screen 80 24
There are no help files!
You probably downloaded the public domain version of
Dead Souls. This version is not recommended for newcomers
to Dead Souls...it is really for experts or for people
who have special needs like developing their own lib
or selling their software. For normal people who are just
interested in running a mud, the regular version is
the right choice. Download
and install the regular
distribution, instead.
Where are the help files for skills and stats?
Things like "strength" or "intelligence" or "knife
defense" are stats and skills that are used by the
mud in calculating things like combat effectiveness.
For the most part, they are self-explanatory..."strength"
is how strong you are, "magic attack" is how good you are
at, say, hurling fireballs.
For the most part these are not documented in the help
system because their use should be self-explanatory
and may not even exist from mud to mud. Please see the
other faq articles for more details:
Often what querents mean when they ask this question
is "exactly how does strength and knife attack interact
in the combat system with the opponent's dexterity,
armor and knife defense?"
The only answer to this question that I can give and
retain my sanity is "You're going to have to get familiar
with the lib, test different weapons and skill/stat
levels, and see for yourself."
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
Note that AddSave() is not responsible for the act of
saving data to the playerfile. AddSave() sets in the object
which variables should be saved. When the player quits
or the automatic save time is reached (about every 5 minutes),
the save_player() lfun in LIB_AUTOSAVE checks each carried
object for its AddSaves(), and saves that data in the
player object accordingly.
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?
On a 32-bit compiled driver: 2147483647 (Two point one billion)
On a 64-bit compiled driver: 9223372036854775807 (Nine point two
quintillion)
To know which you're on, type: eval
return MAX_INT
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)
There is no function to do the reverse.
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.
An apply is a function that is called by the
driver. Some
examples of applies are create() and reset(). Although you
can call many applies normally from within the mud, the
point of them is to have some common functions known to the
driver that it can call on objects. In the case of create(),
it is a function that the driver calls on any new object
loaded into memory (like main() in a C program). Many applies
are security oriented, and are called only in the master object,
such as valid_read() or valid_socket(). This is a way for the
driver to be assured that a trusted security object knows
it's ok to perform the pending "sensitive" operation.
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:
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?
Usually 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 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 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.
7) 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. They
don't like the obvious exits up top.
In the current version of Dead Souls this is no longer the default
behavior. Now obvious exits are displayed at the bottom, in a
more "natural" style closer to the way LPmuds have historically
done it.
Your admin can switch between this new way and the old way with
the command:
mudconfig nmexits [ yes | no ]
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.x 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")
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
There are also 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 three types
of
entry lines that Dead Souls
currently supports.
The first is the name of the
class.
PLAYER_CLASS is 1 if it's a class available to players. 0 if not.
Every line after that is
presumed to be
a skill specification line, in
the following
format:
skill name:importance to the class (1 is highest):starting level
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.
Type the following:
efuns lfuns sefuns
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:
static void create() {
base_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);
SetPreventGet("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_BASE_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).
In Dead Souls 2.5a21 and below,
inherit LIB_DUMMY, not
LIB_BASE_DUMMY, and use dummy::create(); rather than
base_dummy::create();
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
You said that what I want to do requires a daemon. I
am afraid.
Think of a daemon as a kind of server program inside the mud. It
just runs in the background, waiting to be called upon to perform
some action. What daemons are commonly used for is managing information.
If I told you that your project probably needs a daemon, it's probably
because you're planning on saving some kind of information across
reboots
that needs to be accessible to everyone. For example, if you're going
to implement a railroad, you probably want to keep track of which
train is where, what the different ticket prices are, etc. A daemon
would serve as a repository of that data, managing the information
and saving it in an object persistence file so it is preserved in
case of reboot.
There are many kinds of daemons. Some handle intermud connectivity,
some handle player information. They are nothing to be afraid of, they
are LPC objects with a job to do. Some of them are very large
and have complicated code because they have big, complicated jobs.
If, for example, you aim to play with the "master daemon", which
handles mud security, you should be very sure you know what you're
doing.
But by examining how other daemons do their thing, and by keeping
frequent backups, and by the process of patient, persistent trial-
and-error, you'll eventually ramp up to where your daemon code
does what you want.
LOL I tried to
show something to someone in the shop but the vendor gave an error.
This, and some other situations on the lib, are "bugs" that I plan
to leave in place on purpose.
The point is to illustrate an important aspect of parsing on Dead
Souls. The shops inherit LIB_SHOP, meaning that they have add_action()'s
that try to intercept some commands and feed them to the vendor in
a way the vendor finds meaningful...for example, rather than
"ask oana to show omni", you
can just "show omni" and Oana
gets the
right idea as to what to do.
If you then want to use the "show" verb, like "show omni to cratylus"
because you want me to see what you just bought, the shop will intercept
that "show" command before the verb gets processed, and Oana will
get involved. If you leave the room, though, the "show" verb is
no longer overridden by the shop's add_action() and you'll be
able to impress me with your purchase.
Why am I leaving this "broken" behavior in place? It's important for
new admins to understand this interaction between add_action()
parsing and verb parsing. It helps you understand how messy it can
be when 3 or 4 objects in the same room have add_action()'s with
the same trigger command, and it makes it more obvious why a lib-wide
verb handler makes so much sense.
2.74 My object
keeps failing with an eval cost too high error.
MudOS is a single-threaded program. Things have to happen one
after the other. You cannot, for example, simultaneously search
a large file for a string while the mud does something else.
While the string is being looked for, nothing else happens on
the mud until that operation completes.
What this means is that if someone has coded an object carelessly,
and it, for example, gets stuck in an enless search for a string,
then the mud could be hung indefinitely.
Fortunately, MudOS keeps track of how long a specific operation
has been running, and there is a threshold for aborting an
operation that has been hogging too much time. If your messed-up
string search goes on beyond that threshold, the mud will stop
it and return the eval cost too high error you've seen.
While this might seem, on the surface, presumptuous, it is actually
a very, very good thing. You do not need your mud lagging every
few seconds because someone's ill-conceived NPC is hogging the
thread. Nor do you need your creators able to bring your mud to
a screeching halt through casual carelessness.
However, sometimes you need to perform an operation that does
take a long time. For example, you might want a way to index
the files in your mud. With the DS distribution containing
thousands of files, and disk I/O being the slowest operation
a computer does, this would be made difficult.
The answer is to break up the execution of a single operation
into multiple operations via call_out(). A call_out will schedule
the call of a function in its own execution stack. If your
operation can be split up into multiple call_outs, then you
have a better chance of avoiding the eval cost runtime error.
For a specific example, see how the /secure/daemons/file.c
daemon does its nightly indexing of lib files.
Note that careless use of the call_out() efun in an attempt
to evade eval cost restrictions can cause your mud to
lag horribly. Use call_out() with extreme
caution.
Please explain
( foo ? bar : baz )
This is a spiffy and simple way to return a value based on
the truth of a tested statement.
Basically, ( foo ? bar :
baz ) means:
If foo is true, then the returned value of this statement
is bar. If it is not true, then the value of this statement
is baz.
For the purposes of the test, the integer 0 counts as "not true" while
a non-zero integer counts as "true". A defined variable of a non-integer
type will tend to count as "true".
This type of statement is sometimes referred to as a "ternary
conditional".
Where are
things like Town and race and starting money set for new players?
The place to start looking is /secure/lib/connect.c
Then review /lib/player.c for the "enter the game" and setup
functions called by connect.c
How do I make
my NPC respawn sooner than the reset interval?
To make a room check its inventory every 60 seconds and clone
Lars if he's missing from that room:
You can use this to restock containers as well. For an example
of an automatically restocking weapons rack, see
/domains/default/obj/rack.c
in Dead Souls 2.7a27 and above.
Note that if you use this method
for wandering monsters, your mud may
soon be swamped with them, because the room only checks whether
the object is in the room, not
whether it is in the mud.
My TalkResponse
NPC doesn't work, but it really really should!
This is most often caused by the NPC not understanding the language
that the player speaks. If the NPC's level is above MAX_NEWBIE_LEVEL,
he only understands the languages his race gives him. Therefore
your 10th level elf soothsayer hears your human's request for
a prophecy just fine...he just doesn't understand Common or English,
so he doesn't know what the human is actually saying.
To make an NPC understand all languages, add this to his create() apply:
SetPolyglot(1);
How do I load
an object?
Some LP libs use the command "load" to read an object's code into
memory. On Dead Souls, "load" is a verb used to do things like
put bullets in a gun.
The command to have the mud read an object's code into memory is
"update":
update /path/to/object
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.
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.
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.
or
cre: wants you to
shut up.
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/archive
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.
3.12 Hello?
Anyone here? Can someone answer a question for me?
It's usually better just to ask the question. If you just
ask the question, then someone who is idle that moment,
but comes back in a half hour, can see it, and answer it
if they can. However, if they come back after a half
hour and what they see is "can someone help me?", then
they my have less interest in seeing if you're still online
and still have a question.
Also, keep in mind that if someone says "yes, I'm here,"
now they are on the spot, and may feel obligated to
help you. Folks unsure whether they can help may be
reluctant to put themselves in a position where they
could look silly. If you just ask, and they *do* know,
they can respond.
So, just ask, and realize sometimes it takes a while
to get a response. If you can't wait around for an
answer and don't know when you'll be back online, then
post your question on the forum.
How come people
on IMC2 can't rwho me?
This is fixed in the current stable version.
How do I find someone on Intermud-3?
Type: i3locate joe
Section
4: Miscellanea
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->ChangeLevel(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. Also, provide help on the
intermud channels for those who ask. That's how
you can "give back."
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.
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 .
Your player object looks. This initiates a check of the
environment
for light. The room has ambient light. Things in the room may have
radiant light. Ambient light plus radiant light is added together.
This number is given to your player object. If the number is in your
vision range, you can see. Torches and flashlights work by having
radiant light set.
When I control
an NPC, sometimes my commands fail oddly.
NPC's are intentionally simpler creatures than players. When
a player's command fails, it's very important that she know why,
otherwise the game can lose its fun. NPC's are not entitled to
the same regard as players, and therefore their parsing and
error messages are more primitive, if they exist at all.
If, for example, you try to "force fighter to drop boot",
you may not only have nothing happen...it might actually
barf up a runtime error, on older versions of the lib.
This is because NPC's don't get the full luxury of "default
parsing" that players do. You can "drop boot", and if the lib
has default parsing enabled, you'll just drop the first
boot in your inventory. An NPC, however, may need to specify
"drop first boot". And if it doesn't get the command right,
that NPC may simply not receive a very helpful error message
as to why.
Perhaps someday the NPC's will march en masse into my workroom
and demand equal rights and back pay. Until that day, however,
please accept that they are just not meant to be as versatile
in-game avatars as proper player objects are.
How do I make
myself able to cast my new spell?
Normally players learn spells by learning them from an NPC
that teaches it, like Herkimer. However, if you want to
test new spells you've created, you can teach them to
yourself this way:
call me->eventLearnSpell("snowball")
However, this uses the normal player learning process,
and if you don't happen to have the requisite magic
skill levels, it may fail. To force yourself to know
a set of spells at specific levels, you'd use the
SetSpellBook() function, thusly:
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?
As of Dead Souls 2.4.1 mounts
work for getting around and
storing stuff.
You can see an example of a mount by cloning a mountable horse:
clone /domains/town/npc/horse befriend horse mount horse ride north dismount abandon horse
Mounted combat is slated for future releases.
As of 2.5a19, you can see
some basic sample vehicles in
/domains/default/vehicles
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
etc.
How do I add
colors to exits?
modify here obvious %^YELLOW%^east,
west%^RESET%^
To make all exit messages colored, your admin would
have to edit /lib/std/room.c and add the appropriate
tags to the obvious exits string.
How do i
refresh a room?
Go to the room and type: update
The new
room I created with QCS has SetItems I don't want
Type: modify here delete
SetItems
I'm trying to
set my NPC to have a strength of 30 but it won't work.
You have to place the SetStat() directive *below* SetRace(), because
otherwise his body's default race characteristics will clobber
your custom setting.