Dead Souls Creator FAQ

Written by Cratylus @ Dead Souls

Updated October 2007.

Note: commands are displayed in boldface, like this: ls -a

What's this FAQ about?


There are common issues and questions that crop
up for most new creators. This document is intended to
ease or at least shorten what can be a steep learning
curve.


Section 1: Getting Started

1.1 My question isn't on here. Where can I get an answer?

1.2 The ds channel is too spammy. It's distracting me.

1.3 All I did was change one thing in a file, and now it won't update. Help!

1.4 The mud editor is confusing the heck out of me. It's too hard to use.

1.5 When I log in, everything is screwed up, and I can't do anything!

1.6 Ok, I'm a creator now. What am I supposed to do?

1.7 This is weird...where is the online builder? How does new stuff get compiled?

1.8 I explored around in /domains/Ylsrim and <XYZ> is broken

1.9 I explored around in /domains/town and <XYZ> is broken

1.10 What are the known bugs and problems in Dead Souls?

1.11 Why do you keep asking me to post my code?

1.12 "help modify" breaks.

1.13 There are no help files!

1.14 Where are the help files for skills and stats?


Section 2: Code

2.1 What's the QCS?

2.2 SetUnique doesn't work.

2.3 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?

2.4 Where is it saved?

2.5 How do I add or remove emotes?

2.6 How can I tell what files something inherits?


2.7 How can I find the filename of something?

2.8 What's the largest integer usable by the mud?

2.9 How can I find out what functions exist in something?

2.10 object::init() is broken!

2.11 if(ob->GetFoo()) seems to break, but I don't know why

2.12 How do I add color to my descriptions?

2.13 How do I turn the integer 42 into the string "forty-two"?

2.14 Can I use !=NULL as a test?

2.15 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?

2.16 How do skills work?

2.17 How do classes work?

2.18 How do virtual rooms work?

2.19 How are files organized in Dead Souls?

2.20 What are lfuns, sefuns and efuns?

2.21 Why are there more sefun doc files than sefun files?

2.22 I edited a file but now the reload command is complaining.

2.23 this_player()->GetName() returns "A shadow" when the player is invis.

2.24 Is there a sefun for making a whole string uppercase?

2.25 What is the difference between filter() and foreach()? How do I use them?

2.26 member_array() is returning exactly the wrong thing

2.27 I'm trying to add two mappings together and the results are bizarre

2.28 When str = "abc", str[1] is 98, not "b". What gives?

2.29 How do I make an array1 that is the same as array2 but without an element?

2.30 How do I pass arguments to a pointer in a functional?

2.31 What does the tc() sefun do?

2.32 How can I find out how many items are in an array quickly?

2.33 My SetRead isn't working

2.34 My SetEnters/SetSmells/SetListens isn't working

2.35 Can I nest loops?

2.36 What should I do or not do in my code?

2.37 How much different or heavily modified is Dead Souls than stock LPC?

2.38 Is there a way to change the "default exit" room messages?

2.39 This dummy item is not at all behaving like I expected.

2.40 Clan objects do nothing but screw things up.

2.41 My NPC's stats are all hosed up.

2.42 This squirrel is taking *forever* to kill.

2.43 My room should not be entered/exited by just anyone. How
do I control this?


2.44 I zapped a monster, but instead of being dead, now it's undead!

2.45 How does the format for race files work?

2.46 How does the format for class files work?

2.47 What do Properties do?

2.48 How do I add a prehensile limb to a player or NPC?

2.49 How do I make a room occasionally display messages?

2.50 My functional isn't working!

2.51 I've read the Creator's Manual but I still don't understand mappings and arrays.

2.52 Why are call_outs so bad?

2.53 Fine. How am I supposed to create timed events, then?

2.54 I need a list of all the functions available.

2.55 How do I make an object you can [ jump on | climb | etc ] ?

2.56 Where is the list of available skills? How do I add skills?

2.57 Where is the list of available classes? How do I add a class?


2.58 Where is the list of available races?

2.59 How do languages work? Is there a list of them?

2.60 When I try to call test->SetLanguage("Bozo", 50), it sets it to 100%

2.61 How do I update an .h file?

2.62 I want to put an object in a room that doesn't show up in the inventory
but it can be manipulated.


2.63 What is pass by reference? What is pass by value?

2.64 ZOMG pass by reference is terrible! How do I avoid it?

2.65 What does the :: operator do?

2.67 I know this file is fine. I copied it from another file that
works, but it won't update. This is driving me insane.


2.68 What is SetEncounter supposed to do?

2.69 I keep getting "This should be edited by hand.Change cancelled."

2.70 zOMGLOLERZ I did what said but no my workrom really IS broke!!1!


2.71 I can't find the SetQuatloos() lfun anywhere!

2.72 You said that what I want to do requires a daemon. I am afraid.

2.73 LOL I tried to show something to someone in the shop but the vendor gave an error.

2.74 My object keps failing with an eval cost too high error.


2.75 Please explain ( foo ? bar : baz )


Section 3: Intermud and channel stuff

3.1 How do I know what other muds are online on intermud?

3.2 Hey, LeetFooMud is online! How can I tell if Biff is logged on?

3.3 That's weird...mudlist says LeetFooMud is there but I'm not getting anything back.

3.4 I heard there are intermud channels that talk between other muds,
not just Dead Souls muds. How can I use them?

3.5 How do I emote on a channel?

3.6 How do I see what I missed on a channel?

3.7 I am sick and tired of the intermud network going down. Please fix it.

3.8 I just wanna chat. Is there a dschat channel?

3.9 I'll spam if I want to. You're not the boss of me.

3.10 This guy keeps hassling me on an intermud channel

3.11 What's the deal with channel rules and banning and whatnot?

3.12 Hello? Anyone here? Can someone answer a question for me?


3.13 How come people on IMC2 can't rwho me?


Section 4: Miscellanea

4.1 I'm fighting the beggar with my staff and he's kicking my ass

4.2 Someone amputated all my limbs and I can't do anything!

4.3 How do I change my class?

4.4 People are talking to me in gibberish, even though it says they're speaking English.

4.5 What's this about Biff "unknowingly" telling me something?

4.6 How do I find the location of a verb or command?

4.7 Where is the "exa" command? Where is the "n" command?

4.8 How do I get something to happen to a random person in a room?

4.9 My wandering monster escaped from my workroom! How can I find him?

4.10 I ran findobj on something but it says no environment. Where is it?

4.11 How do I update everything in a directory?

4.12 I don't like getting colors on my screen. How do I stop it?

4.13 Um...I want colors back now please

4.14 I can type 'n' and move north, but 'north' doesn't work.

4.15 Why is there a bunch of stuff in ROOMS_FURNACE?

4.16 How do I change my screen and terminal settings?

4.17 ZOMG this is the best mudlib evar how can I evar thank you?

4.18 Dude this mudlib sux0rz @ss. What a waste of my time.

4.19 I'm seeing a filename but I can't read it.

4.20 Is there a command to go back to your previous directory
without having to type it all out again?


4.21 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.


4.22 How do light sources work?

4.23 When I control an NPC, sometimes my commands fail oddly.


Section 5: Building

5.1 QCS is putting stuff where I don't want it.

5.2 How do I make a blank room, instead of copying the current one?

5.3 How do I build an area?

5.4 How do I make a quest?

5.5 Where's Leo?

5.6 Where are the vehicles and mounts?

5.7 I'm having trouble adding meals to my barkeep with QCS.

5.8 I heard DS has stargates. Where's an example?

5.9 I created a vendor, but he isn't responding to the "list" command.

5.10 I gave room with a default smell but I cannot get any other smells
in there,such as 'smell object' for example

5.11 How do I make a weapon more powerful?

5.12 My NPC refuses to wield his weapon.


5.13 How do I add colors to exits?

5.14 How do i refresh a room?

5.15 The new room I created with QCS has SetItems I don't want


5.16 I'm trying to set my fighter to have a strength of 50 but it won't work.



Section 1: Getting Started


1.1 My question isn't on here. Where can I get an answer?

There are five main ways to get specific answers:

1) Ask your mud's administrator, or other creators on
your mud by using the cre channel, like this:

cre does the flux capacitor use verbs or add_actions?

To know what local channels are available on your
mud, type: lines


2) Your mud is probably on the intermud3 network. If
your administrator has not restricted intermud channels,
you should be able to ask questions on the Dead Souls
intermud channel, with a command like this:

ds hi! can someone tell me what room Leo lives in?


3) If intermud is down, or nobody is answering, or
you have a bug to report, you can also try emailing
me, the author of this doc, at: <my name here>@comcast.net
This is a long shot, as I prefer to answer things on
the forum, where more than just one person will
benefit. Note that I just might post your emailed
question on the forum, if I think that's appropriate.


4) If intermud is down, you can also log into the
Dead Souls demo mud at rugose.com 6666
This mud automatically promotes users to
creator status, allowing guests to get a feel for
what developing on Dead Souls is like.
You can try to log into that mud and see if anyone
is available to answer your question. Intermud is disabled
for new users there, though, so you won't be able to use the ds line
to ask questions.


5) There is also the Dead Souls Forum at http://lpmuds.net/forum/
This is a really great place to ask for a few reasons:

- If someone doesn't know the answer right away, eventually
  someone probably will.
- Sometimes people on intermud know the answer, but are busy and just
  don't have the time to answer. On the forum, this is less the case.
- Some questions have answers that are long, and intermud folks
  may not want to spend the time on an elaborate answer to a question
  that they'll probably see someone else ask later. On a forum,
  the responder can be reasonably sure that her help will be useful
  not just to you, but to many others.
- You can post detailed error messages and logs, and the files(s)
  that are giving you trouble. That way many eyes can analyze
  your problem in depth.
- Once resolved, other people can later refer to that problem so
  they don't have to ask the same question, or reinvent the wheel.



Important note about asking on <ds>:

Part of the reason this FAQ was written is that
people who ask questions on the ds channel often do not
realize that same question has been asked many times
before. If you ask something like "how do I read the
channel messages I missed?" without first bothering to
read this doc and others, you just might get a response
that's less friendly than you might have expected.
People on the channel really want to help you,
but if it seems like you're not willing to put in the
time to try to help yourself, they might choose to
ignore you until you gather some clues on your own.

Something else to remember is that we are not
on your mud and we don't see what you see. "Why won't
my workroom update?" lacks enough information to let
anyone try to help, but "when i try to update my
workroom I get <error message>" might.

Similarly, some things don't have an answer
that is suited to ds. "could someone help me
understand the score.c file?" or "how do quests work?"
have answers that are long and complex, or are
already covered in the documentation available
to you.

Some stuff just doesn't have an answer
that can be explained to you unless you already
have the experience you'd need to know the answer.
for example:

- How do I make a stargate that has a dial for
going to different places?

- How do I make it so a player can be on different
planes of existence, and what they see when they
look around depends on what plane they're on?

- How do I add limbs so people can wear stuff
like kneepads on the knee only?

These three questions illustrate things that are
totally doable, but whose explanation is so
complex and full of judgment calls that there
is no way of satisfying the question without
making you magically understand intermediate-level
LPC coding.
That doesn't mean they're bad ideas, or
even that hard to implement. It's just that
the questions can't be answered until you read
and understand the Creator's Manual, and by that
time, you'll know the answer on your own.

Make sure you've read the docs, then ask
the question in a way that makes it clear you aren't
just a lazy person who wants other people to do her
work, but rather a hardworking builder who has
tried to fix something and needs a specific answer
to a specific question that isn't already in the
FAQ's or the docs.

Critiques are welcome, but they should
be constructive. "This combat system is slow and
stupid" is unhelpful and might be taken as a
hostile statement. Instead you could phrase it
in a way such as: "Combat is slower than I
expected. Why? I used to play on LeetFooMud and it
took less than a minute to kill Tiamat." It's still
a bit clueless, but it's a fair question that can
be answered on its own terms without starting
a flamestorm.

Finally, some things are only lightly
documented, or perhaps not at all. Filling out
the documentation is an ongoing project, but as
with much freeware out there, you have to be willing
to put in a little bit of time to experiment. For
example, you may not know what the "importance
to the class" section in the class file format is,
and you may not find the answer in the docs. In
such a case, you have to be willing to experiment a
little, and plug in different numbers, to see what
they do. I can't hold your hand every step of the
way. You have to trust your own intelligence and
enjoy the sense of adventure in discovering things
on your own.

Also, please refer to this Admin FAQ section
on how to ask questions in the most productive way.


The ds channel is too spammy. It's distracting me.

Enable or disable a channel by typing just its name. Like:

ds


All I did was change one thing in a file, and now it won't update. Help!

You should make it a habit to make backup copies of files
before editing them. That way, if you screw up the code, you can
just copy the backup to the original filename.

A convenient way to do this is the bk command. See
the debugging page for an example of its use.

If your file is in the /tmp directory, it won't update.
The lib uses /tmp for temporary system files, and as
a result, it is a security feature that files in /tmp can't
be loaded into memory.

If you are using Windows, you need to be aware of the
linefeed problem. unix text files and DOS text files have different
formatting. If you edit files in Notepad, then try to update them,
you may find that the file no longer updates, no matter what
you do. The difference is usually invisible to you, so you can't
tell why a file that looks exactly the same as before now won't
work.

Dead Souls expects unix-formatted text, and if you feed it
something else, the results aren't likely to be to your
satisfaction. Make sure you use an editor that respects unix
text. In Windows 2000, WordPad seems to do a reasonable job of not
completely screwing things. It does, however, add carriage
returns to your lines, so when you look at them in ed, you'll
see a bunch of "^M"'s all over the place.

Take a look at the third party downloads page for
some suggestions as to what to use instead of the default
Windows editors.

If you still have trouble, take a look at the debugging page.


The mud editor is confusing the heck out of me. It's too hard to use.

Check out the MUD Editor tutorial. It should ease the pain a little.


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?

Please see the Known Issues page.


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

This is fixed in Dead Souls 2.5a18 and above.


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:

http://dead-souls.net/ds-creator-faq.html#2.16
http://dead-souls.net/ds-creator-faq.html#2.56
http://dead-souls.net/ds-admin-faq.html#115

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?

2147483647


How can I find out what functions exist in something?

Get its filename and use the functions efun. For example:

eval return functions(load_object("/domains/town/obj/sign"))


object::init() is broken!

It isn't really. Unless you're coding a lib
item, you should not be inheriting LIB_OBJECT for
"tangible things" anyway. You should inherit LIB_ITEM.

The reason object::init() fails is that LIB_OBJECT
doesn't have an init() function to call.


if(ob->GetFoo()) seems to break, but I don't know why

This function will error if ob does not exist. Unless
you are 100% positive ob will exist (and really, even if so),
it should look like this:

if(ob && ob->GetFoo())

Which means "if ob exists, and it has a foo".
This way, if there is no ob, the check stops right there
without getting hosed up on the next step.


How do I add color to my descriptions?

There are various markup tokens you can use for this. They look like this:

write("%^BOLD%^GREEN%^ This text would be in bold green letters %^RESET%^ and this would not.");

To make text blink, use this tag: %^FLASH%^

The %^RESET% is important. Without it, unpredictable things can happen.

To know what colors are available, type: colors

You should probably avoid color unless there is a compelling
reason for its use. Many mud admins discourage it because it can
distract from the game and cause uniformity issues: most mud
admins feel their mud text should look more or less
the same everywhere.


How do I turn the integer 42 into the string "forty-two"?

cardinal(42)


Can I use !=NULL as a test?

In theory, I guess so, but I doubt it'll work by default, and I'd
discourage you from doing anything so non-LPC-standard.
Instead try something like one of the following:

if(variable)
if(sizeof(variable))
if(variable != "")


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.

For an example, take a look at

/domains/town/virtual/


How are files organized in Dead Souls?


See the admin FAQ.


What are lfuns, sefuns and efuns?


Sefuns and efuns are functions available to all objects on the
mud. Any object may need to know what time() it is, so rather
than have a time() function in every file that needs it, which
could be many, there is a time() function built into the
game that any object can use. An efun is built into the
driver, so there is no LPC code to look at. A sefun is a
simulated efun, coded in LPC. Sefuns are kept in /secure/sefun.

Lfuns are functions specific to library objects. A shirt,
for example, has functions that a sword may not need, so
the LIB_ARMOR and LIB_WEAPON files contain their own functions,
not shared by other files (it's more complicated than this,
but that's the idea). These functions are library
functions, or lfuns. Typically they are found in the objects
defined by the files in /lib.

For a lot more detail on efuns and sefuns, see the admin FAQ.


Why are there more sefun doc files than sefun files?

Sefun files, like /secure/sefun/strings.c, often contain
more than just one sefun. Therefore, there will be more
files documenting individual functions than there are
files containing sefuns.


I edited a file but now the reload command is complaining.

There are two commonly used commands for loading
objects: update and reload.

When you want to load a file into memory, you use
update, for example: update /domains/default/room/road

When you want to replace a cloned object with a
version that uses the latest code in a file, you
use reload, for example: reload my first red sword

reload doesn't work on files.

update doesn't work on cloned objects.

The reason there are two commands, instead of one all-purpose
one, is both historical and functional. The reason "reload"
exists is that I got sick of having to dest a thing, update
its file, then clone the thing every time I wanted to
test changes in its code. This was annoyingly tedious, so I
coded the reload() sefun and reload command.

However, update works just fine, and I wasn't about
to try to fix something that wasn't broken. It works, and
LPC old timers are used to it.

Further, it has a function sufficiently separate from
reload that it stands as a command on its own merits.


this_player()->GetName() returns "A shadow" when the player is invis.

Use this_player()->GetKeyName() instead.


Is there a sefun for making a whole string uppercase?

upper_case("omgwtfroflmao")


What is the difference between filter() and foreach()? How do I use them?

Both of these efuns can act on the individual members of an array.

For example, if you wanted to have an array named mystuff which
contains the base filenames of all objects in your inventory that
inherit LIB_ARMOR:

using filter:

string *mystuff = ({}); //This has to be a global var
object *stuff = filter(filter(deep_inventory(this_player()),
(: inherits(LIB_ARMOR,$1) :) ), (: mystuff += ({ base_name($1) }) :) );

using foreach:

string *mystuff = ({});
foreach( object ob in deep_inventory(this_player())){
if( inherits(LIB_ARMOR, ob) ) mystuff += ({ base_name(ob)});
}

There are arguments favoring the use of either. I won't get into
it. As far as I can tell, it's really a question of preference.
You can structure these functions more elegantly
than shown here, to best suit you. But this is the idea.


member_array() is returning exactly the wrong thing

It probably isn't. member_array() seems somewhat counterintuitive
at first, because it often returns a 0 as a "hit".

What this function is doing is checking to see whether the
first argument is a member of the array specified in the second
argument, and then tells you *which* element it is. for example:

member_array( "bar", ({ "foo", "bar", "baz" }) ) returns: 1

member_array( "foo", ({ "foo", "bar", "baz" }) ) returns: 0

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:

member_array( "shiz", ({ "foo", "bar", "baz" }) ) returns: -1


Example:

Does this player know how to polka? Return 1 for yes:

RIGHT: if(member_array("polka dancing", this_player()->GetSkills()) != -1) return 1;

WRONG: if(member_array("polka dancing", this_player()->GetSkills()) ) return 1;
 
The first way says "If 'polka dancing' has an element number that isn't -1,
then it is a member, so let's return 1"

The second way says "If 'polka dancing' has an element number that isn't 0,
then it is a member, so let's return 1"

The problem with the second way is that it is possible for "polka dancing"
to be element 0 in that array, and if it is, your code will incorrectly
tell you that you can't polka dance. But worse than this is that if
you actually can't polka dance, this second way will incorrectly tell
you that you can. Given random input, the second way would be wrong more than
half the time.


I'm trying to add two mappings together and the results are bizarre

Adding mappings together has to be done just so in order for
it to work the way one might expect. What can happen in
mapping arithmetic is that in the process of trying to
add the values of one mapping to another, you can change the
values of a mapping you didn't intend to. The deal is a
conflict between passing data by reference or by value. To
be sure that you don't accidentally modify an innocent
bystander, use the add_maps() sefun. For example:

MyMap = add_maps(HisMap, HerMap);

or

MyMap = add_maps(MyMap, HerMap);


When str = "abc", str[1] is 98, not "b". What gives?

What you're getting here is the ASCII code of element 1.
If you have to have that element as a string, use the
convert_ascii() sefun, like this:

convert_ascii(str[1])

You can instead use ranges, so that:

str[0..0] == "a"
str[1..1] == "b"
str[1..2] == "bc"

If you use ranges, do not use the convert_ascii() sefun.


How do I make an array1 that is the same as array2 but without an element?

Two ways:

1) array1 = array2 - ({ element });

2) array1 = filter(array2, (: $1 != element :) );


How do I pass arguments to a pointer in a functional?

With commas, like this:

(: eventKill, player :)

Your arguments will likely need to be constants, tokens, and/or global variables.


What does the tc() sefun do?

It's something I coded for myself long ago, basically
a personalized debug(). However, people have been
asking for that functionality for themselves, so
the debug() sefun now carries this functionality. For
more information, type:

man debug


How can I find out how many items are in an array quickly?

sizeof(array)


My SetRead isn't working

You may need an item for each read. For example,
SetRead( ([ ({"alpha", "bravo", "charlie"}) : "Delta.", ]) )

May need something like this *above* it:

SetItems( ([ ({"alpha", "bravo", "charlie"}) : "A thing you can read.", ]) )


My SetEnters/SetSmells/SetListens isn't working

See above.


Can I nest loops?

Can you? Probably. Should you? 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 humanly possible.
Use heart_beat() to time things instead.

2) Don't code stuff that replicates itself.

3) Don't code stuff that circumvents security. For
example, knowing that an admin is logged on but
invisible isn't much help to you if he bans you
for coding a tool to find him.

4) foreach() and filter() are faster than for() loops,
and harder to screw up.

5) switch() is faster and more economical than if()
for multiple evaluations.

6) Don't use callouts.

7) Don't use add_action for something that already
has a verb. There is no point in making an add_action
for "throw", for example. It's just going to confuse
players when your "throw" doesn't behave the way
"throw" does everywhere else on the mud.

8) Callouts are bad, mkay?

9) Don't code delays by using loops. This affects the
whole mud. If an action is to be delayed, use heart_beat().


How much different or heavily modified is Dead Souls than stock LPC?

This is a difficult question to answer on its own terms. It's
roughly equivalent to:

Is Fedora different from stock UNIX, or will my Solaris programs work on it?

This DVD movie is in NTSC format, so my TV can handle it, right?

The terms used roughly correspond to the same
general thing, but the assumption here is that there is a
"stock" LPC, and you can transplant code from one LP mud to
another.
Sometimes these transplants can be done. Oftentimes not.
This is because LPC has been interpreted and implemented in
many slightly different ways by many slightly different versions
of many different drivers. The end product of the DVD is a movie
playing on your TV, but how it gets there is very different from
how a videocassette does it, even if it's the same movie and its
signal is encoded in NTSC in both cases.

If you have two LPmuds that use different drivers, it
can be much like the difference between a DVD and a videotape.
Sometimes, if the drivers are related, the difference is smaller,
like VHS versus Betamax, but you'll still be embarking on a
major project getting the movies from one to play on the other.

The result is that a coder from Discworld and a coder
from Nightmare can roughly speak the same language, and discuss
solutions to their problems that make sense. And each coder
could probably visit the other mud and work with a very
small learning curve.
But the code itself would probably require substantial
retooling to be interchanged.


Is there a way to change the "default exit" room messages?

A lot of folks don't like having default exits displayed at the
top. The muds they're used to display them at the bottom of the room
descriptions, and that's how they want their DS mud to look.

In Dead Souls 2.4.1 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.0 of Dead Souls),
just avoid using it.


My NPC's stats are all hosed up.

Make sure you have SetLevel() *after* SetRace() and SetClass().
Also make sure there's a working ::create() in your create
function. Some examples are:

::create();
npc::create();
vendor::create();

And make sure your init() function has an:

::init();


This squirrel is taking *forever* to kill.

The mud is calculating its health points based on level and
race. If your squirrel has 340hp, it'll seem unreasonably
tough. Use SetMaxHealthPoints() to cap its vitality to
something like, say, 5.

Also, humans tend to be pretty crappy at combat, unless
they are of the fighter class. Even a rat can be
a challenge for a wimpy, weak little level 1 human. Try
using a dwarf or an orc to fight, or make your character
a fighter with: call me->ChangeClass("fighter")

Please note that carrying anything at all tends to
seriously hamper your ability to fight
. Drop anything
you're not carrying or wielding, or put it in a backpack.

Even slips of paper and a bag of feathers. Anything at all
in your possession will make it super hard to fight.

An admin can change this so that encumbrance has no effect
at all. On ds2.1a15 and above, this is done with the command:

mudconfig encumbrance off

and a reboot. On Dead Souls 2.4.1 and above, combat encumbrance is
disabled by default.


My room should not be entered/exited by just anyone. How
do I control this?

There are a couple of ways of controlling entry to a room.
Take a look at the "AddExit" method in:
/domains/town/room/valley.c

And also review the "CanReceive" style in:
/domains/town/room/wiz_hall.c

To prevent a room being exited unless certain conditions
are met, use CanRelease().

These strategies are not discussed in detail in the Creators Manual,
but the examples above should provide ample information as
to how to structure them.

Note that in general, objects with a CanReceive() override
should return ::CanReceive() unless there is a
good reason otherwise. It would look like this:

int CanReceive(object ob){

<if blah return 1>

<if bleh return 0>
<etc and so on>

return ::CanReceive();
}

Obviously the stuff between the <> symbols is pseudocode and
not LPC.


I zapped a monster, but instead of being dead, now it's undead!

Take a look at the code for this NPC. It probably has
eventDie() overridden in a way that does not return 1. This is
not necessarily wrong. You may *want* a monster that doesn't
die like normal monsters do. But if this behavior is unintended,
that is probably the cause.


How does the format for race files work?

Race attributes are specified in race files. They are found in
/secure/cfg/races

Here's a template with parameters in parentheses for clarity:

RACE (race name here)
SENSITIVITY (low light threshold):(bright light threshold)
LANGUAGE (self-explanatory)
RESISTANCE (damage type):(how resistant we are to the damage)
STATS (name of the stat):(the average):(how important. 1 is high)
LIMB (limb name):(where it attaches):(how important. 1 is high):(armor types)
SKILL (skill name):(starting level):(how important. 1 is high):(unused):(unused)

The unused fields in the skill section are reserved for
future implementation.

If the third field in the LIMB line is 1, losing that
limb will cause immediate death.

Special keywords can be appended for particular functionality.
These are:

FLYINGRACE (enables flying)
LIMBLESSRACE (enables limbless travel)
LIMBLESSCOMBATRACE (enables limbless combat)
NONBITINGRACE (some races can't or won't bite)
NOT_MEAT (specifies that when it dies, a meat corpse shouldn't appear)
SWIMMING_RACE (enables travel in water)
PLAYER_RACE 1 (enables the selection of this race for players)

Please note that while the LIB_BODY object does
specify a number of fingers, they aren't items that
can be severed, and their purpose mostly is determining
what kind of gloves you can wear.

NOT_MEAT is available in Dead Souls alpha 19 and above.
If NOT_MEAT is specified, then an npc of that race should
have SetBodyComposition() in its create() function.
For example, a rock golem should have:

SetBodyComposition("rock");

Please see /domains/default/npc/dummy.c for an example.

If an npc's race is NOT_MEAT, and it is not a robot,
and SetBodyComposition() is absent, it may not leave
any remains at all upon death, unless it has a composition
set by default in /lib/races.c

Dead Souls alpha libs have the following additional racial options:
MASS
An integer corresponding roughly to weight on planet Earth, in pounds, multiplied by 10.
SIZE
/include/size_types.h
RESPIRATION_TYPE
/include/respiration_types.h
BODY_TYPE
/include/body_types.h


How does the format for class files work?

Class files have only two types of
entry lines that Dead Souls currently supports.
The first is the name of the class.

Every line after that is presumed to be
a skill specification line, in the following
format:

skill name:starting level:importance to the class (1 is highest)


What do Properties do?

Properties are a way to provide flexibility in
the lib. Objects usually work by having variables
that are modified by functions. This allows a player
to have, for example, a SpellBook variable which
contains the spells she knows, and this variable in
turn is affected by "spell learning" functions, etc.

Suppose, however, that I want to set a
variable in a player, but that variable does not
exist. This is tricky indeed, because it would
involve a modification to one or more library objects,
and reloading them...possibly requiring re-logins
or (very rarely) even rebooting the mud.

Instead you can use properties as a quick
and dirty way to get that functionality without
rewriting lib objects. For example, if you do
something like this:

present("lamp",this_player())->SetProperty("blessed", 1);

Then that lamp is blessed, and maybe now
a monster has a function like this:

if(present("lamp",this_player())->GetProperty("blessed")) RunAway();

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?

victim->AddLimb("tentacle", "torso", 2, ({A_WEAPON }))

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:

ship_list += ({ "Caine", "Queeg", 117, "military", "destroyer minesweeper", 0 })

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:

mapping AllShips = ([]);

AllShips["Caine"] = ([ "captain" : "Queeg", "complement" : 117, "type" : "military",
"class" : "destroyer minesweeper", "cargo" : 0 ]);

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:

mapping FishTypes = ([ "carp" : "freshwater", "tuna" : "saltwater" ]);

So that FishTypes["carp"] is "freshwater".

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:

void heart_beat(){
this_object()->eventForce("say hi!");
}

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:

void heart_beat(){
counter++;
if(counter > 10) {
this_object()->eventForce("say hi!");
counter = 0;
}
}

If the NPC's heart_beat is set to 1, then the NPC will make
his greeting about every ten seconds. If its heart_beat is set to
ten, then it'll take a minute and forty seconds per greeting. Note
that at the end of the if() check, the counter is reset to 0 if
the action is triggered.


I need a list of all the functions available.

If you read the section on efuns and sefuns, you have an
idea of what they are. They are documented in /doc/sefun and
/doc/efun , and doing a list of the dirs and subdirs there
will give you a "list" of them. The documentation on individual
sefuns and efuns is generally available through the man command,
for example: man sscanf

If you're looking for lists of library functions,
such as SetClass in LIB_WEAPON, your best bet is the help
command, like this:

help library objects weapon

help library objects creator

That will list the functions in the library object
you specify. As of this writing, the documentation on lfuns
is not yet as thorough as the documentation on efuns and sefuns,
but this documentation is an ongoing project whose output
should eventually improve.

See also question 2.71


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.


Where is the list of available races?

Type: ls /secure/cfg/races

For details on adding races, see the admin FAQ.


How do languages work? Is there a list of them?

There is no list of languages. It doesn't work that way.
There is no centralized language database, daemon, or anything
like that. Languages are basically like a skill: only useful to
the extent that lib objects make use of them.

A player might be able to understand Tamarian, but if
nobody else in the lib does, it isn't much use. If no written material
is in Tamarian besides, then the player's language ability is a waste.

On the other hand, if a player wants to be able to
understand orcs, all she has to do is find a language teacher
that can instruct her in that tongue. After enough lessons,
she will be at 100% fluency, and if she encounters written or
spoken information in Tangetto, she'll be able to understand
all of it.

To know what languages you understand, and to what
extent, use the command:

language

To make yourself fluent in English, type:

anglicize me

To make yourself fluent in all languages, type:

polyglottize me

Obviously these commands are available only to creators.


When I try to call Bozo->SetLanguage("Clownish", 50), it sets it to 100%

Bozo is probably a newbie. If Bozo's player level is at or below
what is defined as newbie in /secure/include/config.h, then he understands
all languages at 100%. Raise his level above that, and you should see
his proficiency in that language drop to what you specified.


How do I update an .h file?

You don't, really. That's a header file, which contains code to
be included by a .c file. Only a .c file gets loaded into memory, so
to "update" an .h file, you update the .c file that includes it. In
the case of a global include, like daemons.h, you would update the
master object (also called the master daemon) thusly:

update /secure/daemon/master



I want to put an object in a room that doesn't show up in the inventory
but it can be manipulated.

Typically the job of "being invisible but examinable" is something
done by dummy items. In FAQ 2.39 you read about how dummy items work and
how they let you have things in rooms that are looked at, but not taken.

Suppose, however, that you want to have a sittable bench in the long
description, but you don't want it to show up in the room's inventory. Or
a chest that can be opened and closed, but again, not part of the
room's inventory list?

You can't just make the item invisible, because then "look at bench"
will return "There is no bench here." The solution is to *inherit* a
dummy item, and and give it benchy functionality by also inheriting the
things a sittable object needs. For example:

#include <lib.h>
inherit LIB_BASE_DUMMY;
inherit LIB_SIT;
inherit LIB_SURFACE;

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:
  1. Always inherit LIB_BASE_DUMMY first.
  2. Always invoke dummy::create() before other ::creates()'s.
  3. Make sure you have CanGet() return an error string.
  4. 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:

function drawingThis 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.



pass by valueAt 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


pass by reference
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:

string *SubtractElement(string *InputArray){
string *LocalArray = copy(InputArray);
LocalArray -= ({ LocalArray[0] });
return LocalArray;
}

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

See also Question 2.54


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.

An example might be:

write("Pat folds a " + ( (pat->GetGender() == "female") ? "blouse." : "shirt." ) );

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".



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: tell biff@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. This warning only
applies to the old intermud.org router, known as *gjs. The
intermud channel on the new *yatmim router is much
friendlier to newbies.

How do I emote on a channel?

Add the word
"emote" to the channel command. For example:

creemote compels your silence.

gets seen on the channel as:
<cre> Cratylus compels your silence.

You can also add a colon to the message, like this:

cre :compels your silence.

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


I am sick and tired of the *gjs intermud network going down. Please fix it.

See the Dead Souls Intermud Router page.


I just wanna chat. Is there a dchat channel?

Yes!

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?

Here are the router rules: http://lpmuds.net/intermud.html#rules

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.

For more context:
http://dead-souls.net/articles/chanban.html

http://lpmuds.net/forum/index.php?webtag=LPC&msg=177.22


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?

Dead Souls 2.5a16 and above include Shadyman@QuantumScape's
updates to Tim@TimMUD's IMC2 client. It works great for
connecting and chatting on IMC2 channels.

There may be a few kinks remaining with the other functions
of IMC2 clients. This is something I hope to improve on
an ongoing basis.



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->SetLevel(20)

    Now get the medical tricorder from your workroom's
chest and raise your stats. Give yourself 100 strength.
Why not?

    If you're carrying a chest, table, chair, and everything
else you've come across, you will be unable to do much
during combat. Try to wield a weapon, hold a couple of
shopping bags and boxes, and see how well you do against
a pissed off real-life enemy. You won't last long. So either
drop all the crap you're lugging around, or put it in
a backpack and wear the pack.

    Put the staff in your robe and quit using it as
a weapon. It's a creating tool. Not only is it a
poor weapon, by default you lack double-handed
weapon skills, making you really crappy at using
a really crappy weapon. No wonder the orcs were
beating you like an animal. Get a carving knife
from the mansion. Or an orcslayer. Or hell, just
use the zap command and stop wasting time. You
should have characters for this.

    See also Question 2.41


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. I've someone make a stink about
how a file they can't read shouldn't be visible to them
or some such thing. However, I think he was just
being difficult. Some files you can't read, even
though you have access to the directory they're in.
That's the story.


Is there a command to go back to your previous directory
without having to type it all out again?

The shell has a few handy builtins.

To go up a directory: cd ..

To go to your home dir: cd ~

To go to your area directory cd ~/area

To go to the /domains dir: cd ^

To go to /domains/default: cd ^default

To go to the directory you were in before the current one: cd ~-


When I'm in combat, I keep getting messages about not being
able to fight while carrying stuff, but I only have X, Y, and Z on me.

I was carrying some dishes to the kitchen a while back, and it
occurred to me that even if I had a sword, if someone jumped
out and started fighting me, the first thing I'd have to do is
drop anything I'm not wielding, or get my butt kicked.

The more I thought about it, the more it made sense to set up
an encumbrance system that prevented proper fighting ability so
long as you're carrying anything that isn't worn or wielded,
no matter how heavy.

If you don't like this behavior, talk to your admin abour changing
the encumbrance define in /secure/include/config.h .

See also questions 2.41 and 4.1


How do light sources work?

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.




Section 5: Building

QCS is putting stuff where I don't want it.

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:

create weapon /domains/My_Spiffy_Domain/weap/fruitcake

 
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.


- Cratylus

<my name here>@comcast.net

Dead Souls Homepage