/****************************************************************************
Using the configurable object /inherit/monster.
Coding Style: Have a neat style - It does make coding, and debugging easier.
Use strict types - It catches errors in compile time, rather
then in run-time. People looking at
your code know what the functions are
supposed to return.
Indent - Then you don't lose the blocks (ie. '{' '}'). Some
people use the indentor in the editor. I do it by
hand, usually indenting 2 spaces. Its up to you.
Note: This is an example file. The cloned object filenames do not actually
exist.
****************************************************************************/
/* orc shaman */
inherit "inherit/monster"; /* notes: 1 */
void reset(status arg) { /* notes: 2 */
::reset(arg); /* notes: 3 */
if(!present("staff")) { /* notes: 4 */
object staff; /* notes: 5 */
staff = clone_object("players/zilanthius/weapons/staff"); /* notes: 6 */
move_object(staff, this_object()); /* notes: 7 */
init_command("wield staff"); /* notes: 8 */
}
if(!present("robes")) {
object robes;
robes = clone_object("players/zilanthius/armour/robes");
move_object(robes, this_object());
init_command("wear robes");
}
if(arg) return; /* notes: 9 */
set_name("shaman"); /* notes: 10 */
set_alt_name("orc"); /* notes: 11 */
set_alias_name("orc shaman");
set_short("Orc Shaman"); /* notes: 12, 13, 14 */
set_long("The orc is dressed all in black. Wisps of smoke waft\n"+
"slowly from his shoulders.\n");
set_extra_info("Examining the shaman closely, you notice that the\n"=
"air is smoking from a recently cast fire spell.\n");
set_gender(1); /* notes: 15 */
set_race("orc"); /* notes: 16 */
set_level(8); /* notes: 17 */
add_class("mage"); /* notes: 18 */
add_class("cleric");
load_spells(10, ({ "minor malison", "comet", "sbf",
"cure minor wounds", "cause minor wounds",
})); /* notes: 19 */
load_chat(8, ({
"The shaman stares at you intently.\n",
"Shaman exclaims: Leave now!\n",
"The Orc Shaman gives you the Evil Eye!\n",
})); /* notes: 20 */
load_l_chat(8,"orc", ({
"Fools, they are all fools!",
"You will never find the secret ways.",
})); /* notes: 21 */
load_a_chat(15, ({
"The orc shaman screams!\n",
"Shaman says: Now you will never know!\n",
"Shaman hits you with a mighty blow!\n",
})); /* notes: 22 */
set_smell("The orc shaman hasn't had a bath for a while.\n");
}
/**************************************************************************
-=[ Notes ]=-
1. Inherit is an effeicient way to use memory. Inherit means, use the
functions of the inherited object, but make a copy of all the global
variables used in that object for my use. So in effect this object only
requires memory for its 'object header' and global variables.
2. The reset function is called the first time when a file is loaded into
memory (then we call it an object), or when an object is cloned with an
arguement 'arg' of 0. Thereafter reset is called 1 to 2 hours later
with an 'arg' of 1.
3. As soon as any function is written into this file, it will override
any functions of the same name which it has inherited. Note the if
any functions in that inherited file call this function name, it will
call this function. If you wish to use an overridden function in
the parent object then you must use the scoping operator. :: is known as
the scoping operator. "inherit/monster" has the reset() function to
initialise some variables, but to most importantly enable_commands().
enable_commands() is an efun which flags this object to allow it
to use actions(). Without actions the monster cannot wear, wield, or
move. So it is important to call ::reset(arg) first.
4. There are a number of ways to determine if a monster, or any object
in fact has the equipment on them. The method in the example is
recommended as it will replace equipment stolen by thieves. There
are alternative methods.
Alternative 1:
Object is unique throughout mud.
inherit "inherit/monster";
object staff;
void reset(status arg) {
::reset(arg);
if(!staff) {
Alternative 2:
Less efficient method of example. But useful when the monster is
carrying two or more pieces of the same equipment.
inherit "inherit/monster";
object staff;
void reset(status arg) {
::reset(arg);
if(!present(staff)) {
5. declare the variable 'staff' as an object (object is really an LPC
data structure, but you don't need to know that).
6. An alternative to cloning an already pre-configured object, is to
clone the configurable object and configure it direclty. If you
are going to use the weapon more then once it is recommended that you
use a pre-configured file. Cloning is very similar to inherit. It will
make a new object that has a copy of global variables, but using the
functions of the cloned object. This saves memory, when used in
conjunction with the configurable objects (most objects in /inherit
are configurable).
Alternative 1:
staff = clone_object("inherit/weapon");
staff->set_name("staff");
staff->set_alt_name("shaman staff");
staff->set_short("Shaman Staff");
staff->set_long("The staff is a gnarled piece of wood.\n");
staff->set_info("There is nothing magical about the staff.\n");
staff->set_smell("The wood smells quite smoky.\n");
staff->set_value(50);
staff->set_wc(10);
move_object(staff, this_object());
Alternative 2:
This is a shorthand of that shown in example, though long filenames
tend to cramp it.
if(!present("staff")) {
move_object(clone_object("players/zilanthius/staff"),this_object());
}
7. When an object is first loaded, or cloned it has no environment. Or
in otherwords an efun environment() call will return 0. Rooms usually
have no environment, and are not moved. But equipment of monsters are
moved to the monster, which is this_object().
8. This will command the monster to wield the staff. For appearances
it looks better when a monster is wielding or wearing their
equipment. (See also Notes: 3)
Alternative 1:
init_command() is a left over from the original mudlib. But is still
widely used.
command("wield staff", this_object());
9. The reset function is called every hour or so with an arg of 1 after
it is originally coded. It is really a waste of cpu time to reconfigure
stuff in the monster at each reset. So we return after checking to
see if equipment (or other statuses) is still on the monster.
10. Set name will set the living name of the monster with the efun
set_living_name(name). The monster will be able to be located with
find_living(name). However, if there is more then one monster with
the same living name, then only the last one which used set_living_name
will be found. Flagging the monster as living will allow it to
catch write(), tell_object(), say(), and tell_room() communication
messages with the function catch_tell(). This allows greater player
- npc interaction.
11. These set alternative ids that the orc shaman can be identified. So the
Orc Shaman can be call "orc", "shaman", or "orc shaman".
12. short - This is what a player will see when they first walk into the
room. If this is not set, then the monster is invisible to the player.
13. long - This is the message the player sees when they 'look at orc'.
14. extra_info - This is the message the player sees when they 'examine orc'
15. gender - there are 3 genders, 0. neuter, 1. male, and 2. female.
A lot of messages use gender pronoun, possessive, and objectives.
16. race - setting race is important. A lot of spells use the race for
spell effects. For example charm person works only on humanoid
type creatures.
17. level - The level determines the fighting difficulty of a monster.
Setting the level will set the appropriate hit points, weapon class,
armour class and experience for that monster.
18. add_class() - There are 4 standard classes. Fighter, thief, mage,
cleric. You should make the monster one or more of the above classes.
At the moment, thief does not do anything for a monster (but I will
work on that). The skill level of a class is equal to its level.
"fighter" - The class of fighter will make the monster gain better
fighting skills. These include multiple attacks, and multi-opponent
attacks;
"cleric" - The class of cleric will give the monster access to
spells from the cleric bin. Using the function load_spells().
"mage" - The class of mage will give the monster access to the spells
from the mage bin. Using the function load_spells().
Note that the monster must be of the appropriate casting level, and have
on them the necessary spell components. Some spells may be
inappropriate for this because of the default targeting system.
Passive spells ("cure light wounds) will default to monster. Whereas
offensive spells default to primary attack.
19. load_spells - It is a chance out of 100 per heart beat to caste one
of the spells. The monster has to be in an appropriate class, have
the right level, and spell components. Spell selection is random, and
does use spell points. This is the simplest way to add multiple spell
spell casting to the monster.
There is an alternative to add a single default spell. This can be
accessed in two ways. The old way is limited in its approach, but
is still usuable. Note that load_spells() will override the default
spell if they both chance to happen in the same heart beat.
Old Method:
This dates back to at least 2.4.5lib, is kept only for
compatibility.
set_chance(10); /* 10% chance per heart beat */
set_spell_dam(30); /* maximum damage */
set_spell_mess1("Fire explodes around you!\n"); /* msg target */
set_spell_mess2("Fire engulfs the room.\n"); /* msg room */
set_spell_type("fire"); /* immune to this, take no damage */
set_spell_skill_type("evocation"); /*school of spell - for new system */
New Method:
The new method is the same as writing spells for the spell bins. Read
the spell docs for a more detailed analysis (it is recommended).
Spell Example 1:
set_spell(({
"chance", 10,
"damage", 30,
"msg caster", "You see flames engulf @@query_name:$this_object()$@@.\n",
"msg room", "You see flames engulf @@query_name:$this_object()$@@.\n",
"msg target", "Fire explodes around you!\n",
"immune", "fire",
"sphere", "evocation",
}));
Example 2: Bypassing spell level, component limitations. A little
understanding of spell system is needed to understand how this works.
But the effort is worth it, if you want quick and easy special
spells.
set_spell(({
"target", this_object(),
"name", "Heal",
"sphere", "healing_sphere",
"cost", 5,
"spell object", "skills/cleric/heal",
"passive",
"chance", 2,
}));
20. load_chat - This will say() a statement to the whole room. The chance
to do so should be between 5 and 10 for good results. In this case
8%. note it has full punctuation, and newlines.
21. load_l_chat - This is a language chat. It actually runs through the
player 'say' command. And because of this it adds the newline for
you. The chance should be between 5 - 10 for good results.
22. load_a_chat - when attacking the load_l_chat, and load_chat switch off
and the load_a_chat is used. The chance should be between 15 and 30
for good results.
23. A nice message for 'smell orc'.
*/