ROM Coding Help

MUD helps, FAQs, and tutorials
User avatar
Benny
Dreampiece Founder
Posts: 3370
Joined: Jan 4th, 2009, 6:36 pm
PSN: Dreampiece
Steam: bennysoo
Wii: 0384-8082-7959-9771
Xbox Live: S7th
Origin ID: bennysoo
Location: San Francisco, CA
Contact:

ROM Coding Help

Postby Benny » Jul 8th, 2009, 3:27 pm

Code: Select all

Contents:
            --------

   Disclaimer
   Credits
   Introduction

   Adding a New Race
   Deleting or Modifying Existing Races

   Understanding Classes
   Adding a New Class
   Deleting or Modifying Existing Classes

   Understanding Groups
   Adding a New Group

   Adding a New Skill or Spell
   Understanding Gsn's.



Disclaimer
==========

   Although I believe the information in this document to be correct, it
is by no means infallible or complete.  By far more valuable than the
entire rest of this paper is the advice "Back up your code!" and "Roll up
your sleeves and dig in". The best way to learn anything is by doing it.

   In any case, use this information at your own risk.  It's your code,
your responsibility. 


Credits
========

  For those of you who have not bothered to read the credits and license
agreements for ROM, I recommend you do, they are located in the /doc
directory and are called license.txt, license.doc, rom.license and
rom.credits.

  My thanks to Rus Taylor for his efforts with ROM, and also to all of the
original creators of Diku and Merc MUD.  Thanks also to all of you on the
ROM mailing list (rom@rom.org). heh, yeah, even you flamers... The sheer
knowledge base available on that list has helped me immensely.
 

  A special thanks To Erwin Andreasen, who's snippets and documents for Merc
and ROM mud have helped hundreds of mud admins and coders alike. It's peoplelike
this, and thier seemingly tireless patience and willingness to help others that make
the MUD community possible.


ROM 2.4 is copyright 1993, 1996 by Russ Taylor.  and is a deriviative
of Merc Diku Mud.

Merc Diku Mud is a derivative of the original Diku Mud and is subject to
their copyright and license agreement.  Merc Diku Mud contains substantial
enhancements to Diku Mud.  These enhancements are copyright 1992, 1993 by
Michael Chastain, Michael Quan, and Mitchell Tse.

Diku Mud is copyright (C) 1990, 1991 by Sebastian Hammer, Michael Seifert,
Hans Henrik St{rfeldt, Tom Madsen, and Katja Nyboe.  Their license
agreement is in the file 'license.doc'.


Introduction
=============

  This file was written by Gary McNickle (gary@dharvest.com) at Dark
Harvest Systems.  The reason for it is simple, I've seen too many requests
over the ROM mailing list of "how do I add a new race/class/skill???"...
The process is fairly straight forward, but there are a few considerations
to think of when removing or modifying races, classes, skills and groups
that we'll cover here. This document should provide you with the
instructions you need to add/delete/modify races for ROM 2.4x as well as
WoT 1.x Keep in mind, that as these versions change, the procedures for
adding races may change along with them...

  To begin, if you are not allready at least familiar with the basic
concepts and verbage of programming in general, you should become so
before you try to make even small changes... If you have a background in
just about any programming language, then you should have no problem
picking up this information...  At the very least, you should be familiar
with the different data types used in C programming.

  if you find any errors, or have any comments or suggestions, please
send them via email to: gary@dharvest.com



Adding a new race:
===================
 
   Adding a new race is actually quite simple...  There are two primary
types of races, "PC" and "NPC" or "Player Character" and "Non Player
Character" races.  Also, there are two different structures for races, the
"race_type" structure, and the "pc_race_type" structure.  ALL races,
wether or not they are "PC" races, MUST be defined in the "race_type"
structure. Only "PC" races need to be further defined in the
"pc_race_type" structure.  Let's cover the "race_type" first..

In the file "const.c" in
your /src directory, find the data structure defined as:

/* race table */
const   struct  race_type       race_table      []              =
{
    {
        "human",   TRUE,
        0,      0,      0,
        0,      0,      0,
        A|H|M|V,   A|B|C|D|E|F|G|H|I|J|K
    },

    {
        "elf",      TRUE,
        0,      AFF_INFRARED,   0,
        0,      RES_CHARM,   VULN_IRON,
        A|H|M|V,   A|B|C|D|E|F|G|H|I|J|K
    },

  See the two races, "human" and "elf"?  Since it has data for most of the
defined fields, let's take apart the "elf" and see what make's him tick...

Line 1:

"elf"   
-This is the name of the race

TRUE   
-Tells us that this race is available for players to play.
putting FALSE here would mean that noone can select this
race during character creation.

Line 2:

0
-The "act" or "action" flags for this race. In this example, there are
none, so it's set to 0.  see "ACT bits for MOBS" in the file "merc.h" for
a complete listing of avialable action bits.

  NOTE: when adding flags, (or bits, as they are called) to any of the
  following fields, there may be times when you will want to add more than
  one (although, please think that through first). Say, for example, that
  instead of none (0), in this "act" field, you wanted your elf to be an
  aggressive (will attack player characters) thief. That's two "action"
  bits, you would add them like so: (replace '0' with:)

  AFF_AGGRESSIVE|AFF_THIEF

  notice the '|' seperating the two? You can add quite a few flags that
  way, certainly more than you should be able to... *grin*


AFF_INFRARED
-The "aff" or "affected by" flags for this race.  in this example, "elves"
are automatically affected by "infrared". This means that a player
selecting this race is getting a new character that has "infrared" vision.
See "bits for affected_by" in the file "merc.h" for a complete listing of
available affect bits.

0
-The "off" or "offensive" flags for this race.  These flags determine what
"offensive" actions a MOB (NPC) of this race will have when created.
See "OFF bits for mobiles" in the file "merc.h" for a complete listing of
available offensive bits.
(NOTE: YES, it's important that you pay attention to these bits, just
because you may be creating a "player" race, does not mean that you
shouldnt bother with defining these.  This race can be used by your
builders in area creation when they create MOBS as well, and this
information will then be important)

Line 3:

These 3 items (set as: 0,   RES_CHARM,   VULN_IRON) determine, in
order, the "imm", "res" and "vuln" flags of this race. Or, in english,
"immunities, resistance and vulnerabilities". for a complete listing, see
"IMM, RES and VUNL bits for mobiles" in the file "merc.h".

Line 4:

A|H|M|V
These are the "form" bits for this race type, sepearted as mentioned
earlier, with a '|'.  Form bits determine things such as weather or not
the race is edible, poisonous, undead, sentient, bipedal, mammal, etc..
See "body form" and "actual form" in "merc.h" for a complete listing.

A|B|C|D|E|F|G|H|I|J|K
This listing is the "parts" bits for your race. These determine things
such as weather or not it has legs, eyes, a nose, ears, tails, claws,
etc.. See "body parts" in "merc.h" for a complete listing.


That's it for the "race_type" table, now, if your adding a new "PC" race
type, it has a few further definitions that we need to add, these are put
into the "pc_race_table". Look in "const.c" for the following definition:

const   struct  pc_race_type    pc_race_table   []      =

and again, let's break this down, line by line... Here's some examples
from my mud...

    {
        "human",        "Human",        0,
        { 100, 100, 100, 100 },
        { "" },
        { 13, 13, 13, 13, 13 }, { 18, 18, 18, 18, 18 }, SIZE_MEDIUM
    },

    {
        "trolloc",      "Trlck",      10,
        { 125, 125, 125, 100 },
        { "detect good", "bash", "berserk", "second attack" },
        { 16, 10, 12, 13, 15 }, { 23, 12, 14, 16, 23 }, SIZE_LARGE
    },

Let's break down the "Trolloc" race, since it's more fleshed out...

Line 1:

"trolloc"
-This is the actual "name" of the race. This name MUST match with a name
in the above "race_type" table.

"Trlck"
-This is the "Short name", displayed when someone does a "who" command.

10
-The number of creation points it costs the player if they select this
race.

Line 2:

{ 200, 300, 150, 100 },
-This is the "experience multiplier" for each class. This is used to
determine experience points PER LEVEL, for this race, based on the class
that the PC belongs to.  Notice how "human" is all 100? That's because this
number is divided by 100 in the function that determines experience, SO... T
his is a percentage figure.  The higher the number, the more experience
points it will take for that particular class to gain a level.
Now, the four positions here relate to the four classes that came with
"stock ROM". (note: if you add classes, you'll also need to add to this
data structure) and, "out of the box", go in order of, mage, cleric,
thief, warrior) In this particular example, "Trollocs" are not very smart,
and dont care about much more than killing, a Trolloc certainly would
never be a cleric, so, it's twice as hard for a trolloc to be a Mage as it
is to be a warrior, three times as hard to be a cleric, and, since they
are too big to make good thieves, one and a half times as hard to be a
thief...

Line 3:

{ "detect good", "bash", "berserk", "second attack" },
-This array (skills[5]) determines what skills and spells the race is
given at creation (you might say born with). Each of these must relate to
a spell or skill previously defined in the "skill_table". In stock ROM,
there is a pre-set limit of five skills that can be defined here.

Line 4:
{ 16, 10, 12, 13, 15 },
-This array (stats[MAX_STATS]) determines the "minimum" stats that this
race will start out with. The number of different stats is defined in
"merc.h" as "MAX_STATS". The order these stats are listed in here is:
"strength", "intelligence", "wisdom", "dexterity", "constiution"

{ 23, 12, 14, 16, 23 },
-This array (max_stats[MAX_STATS]) determines the "maximum" stats that
this race can ever hope to achieve (unmodified, without special equipment
or magic) and, like above, the number of different stats is defined in
"merc.h" as "MAX_STATS".  If you add a new stat type, you'll need to
adjust that define. The order is the same as above.

SIZE_LARGE
=This determines the rough size of the race. There are three size
definitions in stock ROM, "SIZE_SMALL", "SIZE_MEDIUM" and "SIZE_LARGE".
As a reference, a human is typically SIZE_MEDIUM, where a horse would be
"SIZE_LARGE"


  Well, that's it for races. Use the pre-defined race tables in "const.c"
as a reference point, and you should have no problems. NOTE: once you add
or even change a race, you should do a "clean" compile, in other words,
delete all the .o files in the directory, and compile fresh. (you should
do this any time you change any structure.

There may also be source code modifications you might want to make for
your new races, for examples of these, try doing a search in your /src
directory for "human". (ie: grep -n human *.c)


Deleting or Modifying existing races
====================================

Ahh... there's something to consider here.  If, in your area files, any of
the current races are allready being used then you will have problems if
you delete those races from the source code. Also, you'll have problems if
you change the "name" of a race that is being used in an area file... So,
what do you do?  Well, delete or modify all you want, just remember to do
a search through all your area files (I recommend using 'grep') and make
the necessary modifications in the affected files.  Dont worry, ROM will
certainly let you know if it finds a problem...


Understanding Classes
=====================

   What is a "Class". Simple, for example; "Warriors" are a class all
by themselves, as are "Thieves", "Mages", "Clerics". A class, quite
simply, is a characters "job", what it does for a living. In ROM Classes
are defined to allow the mud to distinguish between different types of
players. In other words, Warriors and Mages for example, have different
skills, where a Warrior has been trained in the arts of War, a Mage has
been trained in the arts of Magic, and thier knowledge and skills should
reflect this. SO, we use "classes" to set up these different "base"
skills, what skills and knowledge a "level 1" warrior or mage should have
before they set off to make their mark on the world.  Also, Classes are
used to set how difficult or easy it may be for a class to learn certain
things. It's much more difficult for a warrior to cast a spell (or
impossible!) than it is for a mage...



Adding a new Class
==================

The number of different classes you can have on your mud is determined by
the define "MAX_CLASS" in the file "merc.h", so, adjust that define as the
need arises.

Find in "const.c", the line:

const struct  class_type      class_table     [MAX_CLASS]     =

{
    {
        "mage", "Mag",  STAT_INT,  OBJ_VNUM_SCHOOL_DAGGER,
        { 3018, 9618 },  75,  20, 6,  6,  8, TRUE,
        "mage basics", "mage default"
    },

Now, as we did for races, let's break this down, line by line...

Line 1:

"mage",
-This is the "name" of the class being defined.
(*name)

"Mag", 
-This is the "who_name" of the class, and is what is displayed when a
player used the command "who". This name can be no more than three letters
long.
(who_name[4])

STAT_INT, 
-This is the primte attribute of the class. What is a "prime attribute"?
Well, it's the one attribute that a member of this class is best at. This
attribute will raise higher than others when a "mage" raises a level. The
attributes available are: STAT_STR, STAT_INT, STAT_WIS, STAT_DEX, and
STAT_CON.
(attr_prime)

OBJ_VNUM_SCHOOL_DAGGER,
-This is the weapon that a member of this class is given when they are
first created.  Each player is given one weapon by the mud immediately
after creation, this defines the "VNUM" (see "Virutal Numbers"  in the ROM
documentation) to use for this particular class, and MUST allready exist.
Your mud will crash if it tries to find this vnum in an area file and it
dosent exist! See "Well known object virtual numbers" in "merc.h" for a
complete listing of weapon types that come shipped with stock ROM. (Note:
if you want to add weapons of your own, you'll have to first create them
in an area file, and then add thier define to merc.h)
(weapon)

Line 2:
{ 3018, 9618 }, 
-These define the two different rooms that lead to this class's GUILDMASTER,
in stock ROM there are rooms for the various classes in Midgaard and New Thalos.
(Thanks to Zain Dirkbane for this information.)

75,
-The level at which, one reached, a player can no longer practice a
skill. Typically 75.  When a player spends a "practice" on a skill to
raise his level of knowledge in that skill, this number is the limit that
it can be raised to.  Do your players a favor, and dont raise this past
75, make them earn the rest!
(skill_adept)

20,
-This is the "To Hit Armor Class of 0"  In other words...  When a
player (or an npc for that matter) tries to hit someone else, a "dice
roll" is made based on their skill, and thier thac0. A thac0 is defined as
a minimum, so, this number is the minimum that a player must get on that
dice roll to get a successful hit.  There are two thac0's, one for low to
mid level characters, and one for mid-high level. This is the first, low
to mid level. 
(thac0_00)

6, 
-This is the "To Hit Armor Class of 0" for mid to high level characters.
(thac0_32)

6, 
-The minimum amount of hit points that a character of this class
will gain when they raise a level.
(hp_min)

8,
-The (hp_max) Maximum amount of hit points that a character of this class
will gain when they raise a level.

TRUE,
-Whether or not this class gains any mana when they raise a level.
(fMana)

Line 3:
"mage basics",
-The "base group" that a character of this class is automatically given
when they choose to modify their character during character creation.
See "understanding groups" for further information.
(base_group)

"mage default"
-The "default group" that a character of this class is automatically given
when they choose NOT to modify their character during character creation.
(default_group)


That's it for the class_table, but there are a few other things to
consider when adding new classes, just as with new races. For example; if
you want to be able to set mobiles with this new classs, you'll have to
add it to the act_flags table in tables.c. There may also be special code
changes you will want/need to make within the code to help 'flesh out'
your new class. do a search on the "warrior" class (in /src directory,
"grep -n warrior *.c") to get an example of source code modifications that
are class specific. Lastly, for each new class that you add, there are
fields in the "skill_type" table that you will have to add to, as well as
in the "group_type" table...


Deleting or Modifying existing classes
======================================

  As with races, when you delete or modify an existing class, there are
many areas where trouble can happen if you dont make sure that you go
through all the relevant source code and area files and make the required
changes.  Basically, for the source code, just go back through the steps
to make a new class and be sure that any/all changed information is
updated, but if, in your area files, any of your NPC MOBS are defined as
one of these classes that have been deleted or modified, you'll have to
make the changes in the area files as well.  Also, be sure to inform your
players when you make changes to classes or races or add new skills.


Understanding groups
====================

  There are two primary "groups" in ROM when it comes to classes and
races. These were discussed briefly in "adding a new class". The two
groups were talking about are the "base_group" and "default_group".

  A group definition is simply a categorized grouping of spells and
skills.  for example, you might have a "default elf" group that contains
all the base skills and spells that members of the "elf" race are given
when they are first created.  There is an important distinction between a
"base group" and a "default group".

  When a player creates a new character, they are given the option to
"customize" their new character.  If they say "Yes, I want to customize
it!" then the "base group" is automatically added to thier characters list
of skills and spells (at no cost to the character), and the "default
group" is shown during customization as a "package deal" that they can
usually purchase for less than if they were to buy each skill seperately.
If they say "Naw... I trust you, I dont want to customize", then the "base
group" is all that's given to them. ROM has defined "MAX_GROUP" as the
maximum number of groups that you can have in your mud, you'll need to
change that define if you go over that number.


Adding a new group
==================

  Keep in mind, that the number of groups that you can have is defined in
"merc.h" as "MAX_GROUP"

  Now, lets tear apart one of the stock ROM groups and see what's in it..

 In "const.c", find the line:
 const   struct  group_type      group_table     [MAX_GROUP]     =
 {
    {
        "warrior basics",       { -1, -1, -1, 0 },
        { "sword", "second attack" }
    },

Line 1:
"warrior basics",       
-This is the name of this group. Simple, eh?

{ -1, -1, -1, 0 },
-This is the "rating" for each class (in order: mage, cleric, thief, warrior)
What this does is determine how much this group costs the player in
"creation points" when they select it, based on thier class. Now, "warrior
basics" is a "base group" and it's only available to memeber of the
warrior class, so the -1 set's this group as "not available" to mage,
cleric, and thief classes, while the 0 means that it is available to
warriros, and dosent cost them any creation points. (increase the 0, and
you increase the cost)
(rating[MAX_CLASS])

Line 2:
{ "sword", "second attack" }
-This is a listing of the skills and spells that come with this group. The
limit to how many you can have here is defined in "merc.h" as "MAX_IN_GROUP".
Each of the spells/skills listed here, will be given to this group, at
whatever cost is mentioned in the rating. (see above)
(spells[MAX_IN_GROUP])


Now, the group we just looked at was a "base group", the costs in the
rating are usually different if it's a "default group". Normally, the cost
to the member of the specific class in a default group is 40, instead of
0. Remember, this is what the character is "suggested" to take as a
minimum during customization.

You can also have other groups.. here's some examples:

  {
    "weaponsmaster",        { 40, 40, 40, 20 },
    { "axe", "dagger", "flail", "mace", "polearm", "spear", "sword","whip" }
  },

  {
    "attack",               { -1, 5, -1, 8 },
    { "demonfire", "dispel evil", "dispel good", "earthquake",
      "flamestrike", "heat metal", "ray of truth" }
  },

 See how the costs vary? Take the "attack" group for example, mages are
not allowed to purchase this group of spells, (-1), for clerics, it costs
5 creation points, thieves are also not allowed to purchase it, and for
warriors, heh, it cost's a whopping 8 points!
 

Adding a new skill or spell
===========================


  Adding new skills or spells can be as complex or simple as you want to
make them. Fortunately for the creative portion of your brain, they
require some actual coding on your part.  You have to actually write what
the new skill or spell does.  It is beyond the scope of this document to
instruct you on how to do that, however, we can help you to understand the
internal structures of skills and spells for ROM.

In "const.c" find the line:

  struct  skill_type      skill_table     [MAX_SKILL]     =

 here are defined all the skills available to players and mobs on your
mud. You'll add all your new skills to this table.  Let's take a look at
the first skill (spell actually) that comes with stock ROM.

    {
        "acid blast",           { 28, 53, 35, 42 },     { 1,  1,  2,  2},
        spell_acid_blast,       TAR_CHAR_OFFENSIVE,     POS_FIGHTING,
        NULL,                   SLOT(70),       20,     12,
        "acid blast",           "!Acid Blast!",      ""
    },

Now, to break it down, line by line...

Line 1:

"acid blast",           
-The name of the skill
(char *name)

{ 28, 53, 35, 42 },     
-The levels needed (in order of class) by the various classes. As before,
this order is Mage, Cleric, Thief, Warrior. (if you add new classes, you
have to add to this field as well) In this example, "Acid Blast" is a
level 28 mage spell, a level 53 (Immortal) cleric skill, a level 35 thief
skill and a level 42 warrior skill. In other words, a warrior must be
level 42 before he can practice or use this skill.
(skill_level[MAX_CLASS])

{ 1,  1,  2,  2},
-These determine how difficult it is for each class to learn this skill. A
value of 0 or less here means that this class is unable to learn this
skill. This also determines how many "training sessions" it will cost a
member of that class to "gain" this skill. It's also the divisor used when
practicing the skill. The lower the number (min 1) the better. It's harder
for a class with a rating of 2 to practice or learn, than it is for a
rating of 1.
(rating[MAX_CLASS])

Line 2:

spell_acid_blast,       
-This is the function that implements the skill, most spell functions are
stored in "magic.c" and "magic2.c" while skills are found throught the
source code.  These skill functions take four arguments, an "sn" (see
"understanding gsn's") a level, the caster and a target. I recommend
looking at the spells in "magic.c" and "magic2.c" to get a solid grasp on
how other's have gone about things before you. 
(*spell_fun)

TAR_CHAR_OFFENSIVE,     
-The target of the skill.  See "Target Types" in "merc.h" for a complete
list, but here well discus the major ones:
(target)

TAR_CHAR_OFFENSIVE   This skill is "offensive", you may be attacked for
          using it!
TAR_CHAR_DEFENSIVE   This skill is "defensive", no one will bother you
         for using it.
TAR_CHAR_SELF      This skill can only be used on yourself.
TAR_CHAR_ROOM      This skill get's used on the entire room!
TAR_IGNORE      The skill itself chooses it's target
TAR_OBJ         This skill affects objects only


POS_FIGHTING,
-This shows the minimum position the player can be in to use this skill.
POS_FIGHTING for example, will allow the skill to be used if the player is
either standing (POS_STANDING) or allready fighting. See "positions" in
"merc.h" for a complete listing.
(minimum_position)

Line 3:

NULL,                   
-The address to an associated "gsn" (see "understanding gsn's") for this
skill. Almost all skills have gsn's, few spells do.
(*pgsn)

SLOT(70),       
-The slot number.  This field is out of date, and no longer used in ROM
2.4+ However, since it's still in the skill_table, you must put something
here... *grin* Or remove it from the code (and all skills!)
(slot)

20,     
-The minimum amount of mana that using this spell will cost.
(min_mana)

12,
-How long to pause the character when using this skill, in "Pulses". 4
pulses = 1 second.
(beats)

Line 4:
"acid blast",           
-This is what is shown in the damage message when this skill is used, for
example: "Your acid blast anhilates fido".
(noun_damage)

"!Acid Blast!"
-The "wear off" message.  This message is what's shown when the skill
wears off. NOTE: If (like in this example) it's an instantaneous spell,
put an "!" at the beginning and end of this message. This signifies an
"error" message, and is very obvious when displayed.  Also, skills (vs
spells) dont use this field.
(msg_off)

""
-The wear off message for objects. As above, but applies to objects
instead of characters.
(msg_obj)

For skills (vs spells), the following fields are not used;
'slot', 'min_mana', 'spell_fun', and 'target'. (the target is instead
taken from the command line)

Once you have written the skill itself, and added it (as we've just
described) to the skill_table in const.c, you will also need to add it in
two other places.  Just as with any other command that the players can
use, you have to add it's "do_function" to interp.h (or magic.h for
spells) and add the command itself to the command table in "interp.c".

Note: some skills are actually 'automatic', for an example of these
skills, see "meditate", "fast healing", "parry", "dodge", "second attack"
and others like them. (many are found in fight.c)

Also, many of your skills will need gsns. These are added to db.c and
merc.h

Now, about gsns....


Understanding gsn's.
====================

  GSN, or "Global Skill Number" are nothing more than a reference number
for ROM. They are defined as follows:

/* in db.c, the gsn is set like so: */
sh_int                  gsn_dodge; 

/* in merc.h, an extern gsn is set as: */
extern  sh_int  gsn_dodge;

  For skills that require gsn's, you have to add both the db.c gsn, and
the extern version in merc.h.  How do you determine if your skill needs a
gsn? Simple, will it be used often, by a lot of people? If so, then it
should have a gsn.  Also, if it's an "automatic" skill, then by all means
it should have one.  GSN's are used to speed up the search for the skill
in the database, skills without them take longer to search for than skills
that have one.  It's that simple... Now, it seems to me that a sorted
linked list would be an even faster way to search, I'll be adding that to
my ROM code soon and let you know how it works out...
[b]PSN: Dreampiece | 360: S7th | Wii: 0384-8082-7959-9771 | Steam: bennysoo | Origin: bennysoo

Return to “Documentation”

Who is online

Users browsing this forum: No registered users and 1 guest