mirror of
https://github.com/alexmchale/merc-mud
synced 2026-08-12 12:26:04 -04:00
254 lines
9 KiB
Text
254 lines
9 KiB
Text
Merc Release 2.1
|
|
Sunday 01 August 1993
|
|
|
|
Furey mec@shell.portal.com
|
|
Hatchet hatchet@uclink.berkeley.edu
|
|
Kahn michael@uclink.berkeley.edu
|
|
|
|
|
|
|
|
=== Skills and Spells
|
|
|
|
The central organizing table for skills and spells is skill_table, an array
|
|
of type 'struct skill_type' (merc.h), and is defined in const.c. Skills
|
|
include spells as a special case. Indexes into this table are 'skill numbers'
|
|
or 'spell numbers', abbreviated 'sn'. An 'sn' is a purely internal value, and
|
|
can vary over time as skills and spells are added. This way, the skill table
|
|
can be expanded conveniently.
|
|
|
|
The 'practice' command and player saving/loading are completely table-driven
|
|
from skill_table. Skills and spells may be freely added or deleted without
|
|
changing these functions.
|
|
|
|
The fields of skill_table are:
|
|
|
|
char * name;
|
|
|
|
The name is used for practising the skill or spell and by the 'cast'
|
|
command. Mobiles which cast spells also often invoke the spell by
|
|
name. Save files contain this name.
|
|
|
|
sh_int skill_level[MAX_CLASS];
|
|
|
|
This array is indexed by character class, GET_CLASS(ch). It contains
|
|
the minimum level which each class needs in order to practice the skill
|
|
or spell. If a given class cannot use this skill or spell, the level
|
|
is set to 37, so that all immortals can use all skills and spells.
|
|
Mobiles ignore this table; generally their skill percentages are a
|
|
simple function of level.
|
|
|
|
SPELL_FUN * spell_fun;
|
|
|
|
This is the function which implements the spell. Spell functions
|
|
take four arguments: an 'sn', a level, a caster, and a pointer to a
|
|
target victim or object. This field is unused for skills.
|
|
|
|
sh_int target;
|
|
|
|
This identifies the targets of the spell. The legal values are:
|
|
|
|
TAR_IGNORE Spell chooses its own targets.
|
|
TAR_CHAR_OFFENSIVE Spell is offensive (starts combat).
|
|
TAR_CHAR_DEFENSIVE Spell is defensive (any char is legal).
|
|
TAR_CHAR_SELF Spell is personal-effect only.
|
|
TAR_OBJ_INV Spell is used on an object.
|
|
|
|
PC's may not cast TAR_CHAR_OFFENSIVE spells on other PC's. These
|
|
spells also cause the victim to attack the caster.
|
|
|
|
This field is unused for skills.
|
|
|
|
sh_int minimum_position;
|
|
|
|
This is the minimum position needed to cast the spell. It is always
|
|
either POSITION_FIGHTING or POSITION_STANDING. This field is unused
|
|
for skills.
|
|
|
|
sh_int slot;
|
|
|
|
This is the slot number, which indexes the spell from magical objects
|
|
in #OBJECTS sections of area files (but not save files, which use the
|
|
ascii name). Once assigned, a slot number can never be changed.
|
|
Skills do not have slot numbers.
|
|
|
|
sh_int min_mana;
|
|
|
|
This is the minimum mana required to cast this spell by a sufficiently
|
|
high level spell caster. A lower level spell caster will need more
|
|
mana than the minimum; see 'do_cast' in 'magic.c' for the algorithm.
|
|
This field is unused for skills.
|
|
|
|
sh_int beats;
|
|
|
|
This is the delay time, in pulses, imposed on the user of a spell or
|
|
caster of a spell. One pulse is 0.25 second (this is derived from
|
|
PULSE_PER_SECOND in merc.h).
|
|
|
|
sh_int * pgsn;
|
|
|
|
This is the address of a gsn (global skill/spell number) associated
|
|
with this skill or spell. Almost all skills have gsn's; a few spells
|
|
do.
|
|
|
|
char * noun_damage;
|
|
|
|
This is a noun or noun phrase containing the damage message for skills
|
|
or spells that perform damage.
|
|
|
|
char * msg_off;
|
|
|
|
This is the message sent to the character when the skill or spell wears
|
|
off.
|
|
|
|
|
|
|
|
=== Examples
|
|
|
|
{
|
|
"fireball", { 15, 37, 37, 37 },
|
|
spell_fireball, TAR_CHAR_OFFENSIVE, POS_FIGHTING,
|
|
NULL, SLOT(26), 15, 12,
|
|
"fireball", "!Fireball!"
|
|
},
|
|
|
|
This is a fifteenth level magic-user spell. The slot number is 26. It
|
|
costs 15 mana, and imposes 12 pulses (3 seconds) of delay time on the
|
|
caster. It's an offensive spell, and can be used either fighting or
|
|
standing. There is no gsn. The damage message will say 'fireball',
|
|
and the wear-off message has a strange form to indicate errors because
|
|
this spell is instantaneous.
|
|
|
|
{
|
|
"armor", { 5, 1, 37, 37 },
|
|
spell_armor, TAR_CHAR_DEFENSIVE, POS_STANDING,
|
|
NULL, SLOT( 1), 5, 12,
|
|
"", "You feel less protected."
|
|
},
|
|
|
|
This is a fifth level magic-user or first level cleric spell. It can
|
|
be cast on any char without starting a fight. It has no damage message
|
|
but does have a wear-off message.
|
|
|
|
{
|
|
"gas breath", { 35, 37, 37, 37 },
|
|
spell_gas_breath, TAR_IGNORE, POS_FIGHTING,
|
|
NULL, SLOT(203), 0, 4,
|
|
"blast of gas", "!Gas Breath!"
|
|
},
|
|
|
|
This is one of the dragon-breath spells. It is accessible only to
|
|
35th level magic users. The spell selects its own targets (TAR_IGNORE)
|
|
rather than using the common spell-driver target selection code.
|
|
|
|
{
|
|
"pick lock", { 37, 37, 1, 37 },
|
|
spell_null, TAR_IGNORE, POS_STANDING,
|
|
&gsn_pick_lock, SLOT( 0), 0, 12,
|
|
"", "!Pick!"
|
|
},
|
|
|
|
This is a first-level thief skill. Many of the fields are unused.
|
|
This skill has a gsn, so that do_pick_lock does not have to call
|
|
'skill_lookup' to find the sn.
|
|
|
|
|
|
|
|
=== Indexing skill_table
|
|
|
|
'skill_table' is indexed by an 'sn' or 'gsn'. The function 'skill_lookup'
|
|
takes a string and returns the appropriate sn, or -1 if the name is not found.
|
|
|
|
Some skills, such as 'second attack', are referenced very frequently. For
|
|
these skills, a global variable such as 'gsn_second_attack' is initialized to
|
|
the sn of this skill. Most of the fighter and thief skills have gsn's; only a
|
|
few spells need gsn's.
|
|
|
|
Gsn's are initialized at boot time in boot_db, which follows the 'pgsn' field
|
|
in skill_table. This takes slightly more time and space than using '#define'
|
|
to define them as constants, but is much more error-proof.
|
|
|
|
Magic items (potions, scrolls, pills, wands, and staves) have charges of
|
|
magical spells. These spells are referenced by 'slot number' in area files.
|
|
(Slot numbers are also used in the save files). The function 'slot_lookup'
|
|
converts slot numbers to skill numbers.
|
|
|
|
The range of slot numbers is 0 to 32767. There is no need to assign them
|
|
consecutively. In the future, slot numbers may disappear completely, and
|
|
area files may reference spells directly by name instead of by slot number.
|
|
|
|
[For those familiar with original Diku code ... slot numbers are simply the
|
|
original Diku spell numbers.]
|
|
|
|
|
|
|
|
=== The spell driver
|
|
|
|
The spell driver level is the first half of 'magic.c'. It consists of
|
|
'do_cast' for the 'cast' command and 'obj_cast_spell' which is called from
|
|
'do_brandish', 'do_eat', 'do_quaff', 'do_recite', and 'do_zap'.
|
|
|
|
The spell driver takes care of level checking, position checking, target
|
|
selection, target validation (such as preventing PC's from casting offensive
|
|
spells on other PC's), staff area effect (just multi-target selection), mana
|
|
costs, wait states, and starting combat for offensive spells. All of these
|
|
things are table-driven by 'skill_table'.
|
|
|
|
The spell function itself takes care of calling functions like 'damage' and
|
|
'affect_to_char'. Read the existing ones to see what is needed for a new one.
|
|
|
|
Some spells, such as 'earthquake', 'locate object' or 'summon', perform their
|
|
own target selection. These spells are target type TAR_IGNORE. Within the
|
|
spell function, the variable 'target_name' is available (set by the spell
|
|
driver).
|
|
|
|
|
|
|
|
=== Adding a new spell
|
|
|
|
(1) Find a free slot number. Make sure it's not already used in 'const.c'.
|
|
Merc reserves slot numbers below 500 for future expansion. We promise we
|
|
won't use numbers 500 or above in future Merc releases. Thus if you number
|
|
your spells 500 or above, you will have an easier time upgrading to future
|
|
releases of the Merc base code.
|
|
|
|
(2) Choose appropriate values for the other 'skill_table' fields, and write
|
|
your new paragraph into 'const.c'. Order is immaterial.
|
|
|
|
(3) Add the 'spell_*' function declaration to the 'DECLARE_SPELL_FUN' section
|
|
of 'merc.h'.
|
|
|
|
(4) Drop the code for the spell function into 'magic.c'.
|
|
|
|
(5) If your spell needs 'AFF_*' bits, create new 'AFF_* bits' in 'merc.h'.
|
|
|
|
(6) You may need to increase 'MAX_SKILL' in 'merc.h'.
|
|
|
|
|
|
|
|
=== Adding a new skill
|
|
|
|
For skills, only some of the fields are relevant: 'name', 'skill_level',
|
|
'beats', 'pgsn', 'noun_damage', and 'msg_off' are used; 'slot', 'min_mana',
|
|
'spell_fun', 'target', and 'minimum_position' are not used.
|
|
|
|
Skills are either automatic (such as 'parry') or manual (such as 'rescue').
|
|
Many automatic skills are referenced in 'fight.c'; look at 'multi_hit' for
|
|
examples of the use of 'gsn_second_attack' and 'gsn_third_attack'.
|
|
|
|
An explicit skill such as 'rescue' has its associated command 'do_rescue'.
|
|
This command is defined and called in the normal way in interp.c. Within
|
|
'do_rescue', 'gsn_rescue' is used to find fields such as 'beats'.
|
|
|
|
To add a new skill:
|
|
|
|
(1) Choose appropriate values for the 'skill_table' fields, and write your new
|
|
paragraph into 'const.c'. Order is immaterial.
|
|
|
|
(2) You'll probably need a 'gsn'. Declare it in 'merc.h' and 'db.c'. Drop its
|
|
address into the 'pgsn' field of the paragraph in 'const.c'.
|
|
|
|
(3) If the skill is automatic, just use 'ch->pcdata->learned[gsn_new_skill]'
|
|
in your code. If your skill is manual, you need to write an appropriate
|
|
command function for it.
|
|
|
|
(4) You may need to increase 'MAX_SKILL' in 'merc.h'.
|