In the default ToME module, you get to choose from a race, a sub-race, gender, a background, a class, and then a subclass. To the T-Engine, these are all the same thing, called 'player descriptors' (Charcter descriptors would be more accurate, but that's nitpicking), or PDs for short. PDs are what let you alter the player character in all sorts of different ways. Player descriptors typically stack, so any modifications done to one will usually add with any other modifications, rather than replacing them.
There's no definition or distinction between different types of PDs by the engine. They can all have the same functionality, the only place any consistency is found is by the module author. So, if you only want stats to come from races, and skills from classes, you will have to make sure that only races gain stat bonuses and only classes have skill bonuses. The engine will not discriminate against this for you.
All the example below will be from the default ToME module, so you should be able to see pretty easily where everything came from and can easily modify it and see what happens with your copy of ToME.
Possibly the most important PD is the one that the player will never see, the base descriptor, found in /data/player/descriptors.lua. This is the one that is loaded for every character, and provides the universal traits that each character will share. The function for it, in 3.0.0alpha19, looks like this:
Code: Select all
new_player_descriptor
{
type = "base"
name = "Base Descriptor"
body = { INVEN=23 MAINHAND=1 OFFHAND=1 BODY=1 OUTER=1 LITE=1 HANDS=1 TOOL=1 RING=2 HEAD=1 NECK=1 FEET=1 MOUNT=1 BACKPACK=1 }
skills =
{
["Monster-lore"] = { mods.add(0), mods.add(500) }
["Prayer"] = { mods.add(0), mods.add(500) }
["Udun"] = { mods.add(0), mods.add(400) }
["Magic-device"] = { mods.add(1000), mods.add(1000) }
["Riding"] = { mods.add(0), mods.add(500) }
}
starting_objects =
{
{ obj=function(obj) object_prep(obj, TV_PARCHMENT, SV_BEGINNER_PARCHMENT) end },
{ obj=function(obj) object_prep(obj, TV_FOOD, SV_FOOD_RATION) end min=3 max=7 },
{ obj=function(obj) object_prep(obj, TV_LITE, SV_LITE_TORCH) end min=3 max=7 },
{ obj=function(obj) object_prep(obj, TV_TOOL, SV_SHOVEL) end },
}
}
The second PD applied by the ToME module is your race, followed by subrace, found appropriate in /data/player/races.lua and /data/player/subraces.lua. Races are where ToME typically grants the charcter their most unique abilities and major stat adjustments. Below is the PD for elves, and then a subrace of elf.
Code: Select all
new_player_descriptor
{
type = "race"
define_as = "RACE_ELF"
name = "Elf"
desc = {
"Elves are the first born of Arda.",
}
descriptor_choices =
{
subrace =
{
Noldor = "allow"
Avari = "allow"
__ALL__ = "never"
}
}
stats = { [A_STR]=1, [A_INT]=3, [A_WIS]=2, [A_DEX]=3, [A_CON]=1, [A_CHR]=5, }
life_rating = 15
experience = 100
age = { 100, 30 }
weight =
{
female = { 180, 15 }
male = { 190, 20 }
}
height =
{
female = { 82, 10 }
male = { 90, 10 }
}
infravision = 4
flags = { ELF=1 }
}
new_player_descriptor
{
type = "subrace"
define_as = "SUBRACE_NOLDOR"
name = "Noldor"
desc = {
"The Noldor are the second clan of Elves who came to Valinor, and ",
"are accounted as the greatest of all peoples in Middle-earth. ",
"They are masters of all skills, and are strong and intelligent. ",
"They can play all classes except rogues, and very well at that. ",
"High-elves begin their lives able to see the unseen, and resist ",
"light effects just like regular elves. However, there are few ",
"things that they have not seen already, and experience is very ",
"hard for them to gain."
}
stats = { [A_STR]=1, [A_INT]=3, [A_WIS]=2, [A_DEX]=3, [A_CON]=1, [A_CHR]=5, }
experience = 200
levels =
{
[1] = { SEE_INVIS=true RESIST=getter.resists{LITE=60} }
}
skills = {
["Weaponmastery"] = { mods.add( 2000), mods.add(0) },
["Archery"] = { mods.add( 5000), mods.add(0) },
["Sneakiness"] = { mods.add( 600), mods.add(0) },
["Stealth"] = { mods.add( 8000), mods.add(0) },
["Disarming"] = { mods.add( 800), mods.add(0) },
["Magic-device"] = { mods.add( 4000), mods.add(0) },
["Spirituality"] = { mods.add(20000), mods.add(0) }
}
}
Code: Select all
new_player_descriptor
{
type = "sex"
name = "Male"
desc = "Males. Need a good description"
flags =
{
MALE=true
}
}
Code: Select all
new_player_descriptor
{
type = "race_background"
name = "Barbarian"
desc = {
"Hardy members of their race they are strong fighters but poor spellcasters.",
}
stats = { [A_STR]=2, [A_INT]=-3, [A_WIS]=-2, [A_DEX]=1, [A_CON]=1, [A_CHR]=-3, }
luck = 1
mana = 50
life_rating = 2
experience = 25
flags = { PLACE=birth.place.AFTER }
levels =
{
[10] = {
RESIST = getter.resists{FEAR=100}
}
}
}
Code: Select all
new_player_descriptor
{
type = "subclass"
name = "Archer"
desc = {
"'Kill them before they see you' could be the motto of the archer class.",
"As deadly with a bow as a warrior is with a sword.",
}
stats = { [A_STR]=2, [A_INT]=1, [A_DEX]=2, [A_CON]=1, [A_CHR]=1, }
skills =
{
["Archery"] = { mods.add(1000), mods.add(850) }
["Bow-mastery"] = { mods.add(0) , mods.add(500) }
["Combat"] = { mods.add(1000), mods.add(800) }
["Disarming"] = { mods.add(1000), mods.add(900) }
["Magic"] = { mods.add(0) ,mods.add(200) }
["Magic-device"] = { mods.add(0) , mods.add(100) }
["Sling-mastery"] = { mods.add(0) , mods.add(500) }
["Sneakiness"] = { mods.add(1000), mods.add(900) }
["Weaponmastery"] = { mods.add(1000), mods.add(500) }
}
starting_objects =
{
{ obj = lookup_kind(TV_LIGHT_ARMOUR, SV_SOFT_LEATHER_JACKET) },
{ obj = lookup_kind(TV_BOW, SV_SHORT_BOW) },
{ obj = lookup_kind(TV_ARROW, SV_BODKIN_ARROW) min=25 max=25 },
}
}
Code: Select all
birth.sequence
{
-- Load the base template, only one possibility, no choice will
-- be displayed
{ descriptor_type = "base" },
-- Ask for race
{
title = "Select your race"
desc = {
"Race determines your basic physical and mental statistisc and some races may"
"have special powers."
"If you do not know what to choose, Humans are the best for beginners."
}
descriptor_type = "race"
},
-- Ask for subrace
{
title = "Select your subrace"
desc = {
"The race you have selected comes in different 'flavors',"
"each of them has different traits and may have special powers."
"If you do not know what to choose, the first choice is the best for beginners."
}
descriptor_type = "subrace"
},
-- Ask for racial background
To insert your own PD in this sequence, you'd just need to add in your own block of code into this list like this:
Code: Select all
-- Ask for new PD
{
title = "Select your NEW_PD_HERE"
desc = {
"This is the description for your new PD.",
"Make it clear, but don't use actual numbers."
}
descriptor_type = "NEW_PD_HERE"
},
type: This is used by the T-Engine to sort out all of the PDs present in the module. Mostly, this is used when displaying the options during character creation. To define it, use a statement like 'type = "race"' inside the PD.
name: The player-readable name of this PD. This is what will be displayed on the character sheet screen, and at character creation when choosing this type of PD. To define it, use a statement like 'name = "Human"' inside the PD.
desc: The player-readable name of this PD. This is what will be displayed at character creation when choosing this type of PD. To define it, use a statement like the example below inside the PD:
Code: Select all
'desc = {
"Humans are are everywhere.",
"They are the basic race to which all others are compared.",
"Average in ability, they can be any class.",
}'
descriptor_choices: This block is used to determine which other PDs are allowed to mix with this PD. In ToME, this is mostly used to define out subraces, but is also used for gender. You can apply this to as many other types of PD as you want, as seen in the example below, but you should make sure not to exclude PDs that have already been chosen by the player. A pretty complex example is below:
Code: Select all
'descriptor_choices =
{
subrace =
{
Noldor = "allow"
Avari = "allow"
__ALL__ = "never"
} --sets the default elven subraces as valid options for this entry
sex =
{
__ALL__ = "never"
Male = "allow"
} --disallows females to exist for this descriptor.
}'
stats: The stats block of code displays the stat adjustments for this PD. The baseline for each stat in ToME is 10, and ToME uses the standard Dungeons and Dragons 3rd edition core stats. If your module has other stats or removes any of these, then you will need to make sure your stats block matches up to your stats. You can adjust stats up or down, and you can choose to not alter a stat simply by leaving it out of your block. A typical stats block looks like this:
stats = { [A_STR]=-1, [A_INT]=3, [A_WIS]=2, [A_DEX]=3, [A_CON]=-1, [A_CHR]=5, }
This block reduces strength and constitution by 1, boosts intelligence and dexterity by 3, wisdom by 2, and charisma by 5. Without any other stat adjustments on other PDs, this character has a strength of 9, intelligence of 13, etc.
luck: Luck is a pretty simple stat, that partially determines the quality and likelihood of random drops, good dungeon floors, etc. It is limited by the T-Engine to a range between -30 and 30, defaulting to 0 without any modifier. To set luck for a PD, simply use a statement like 'luck = 5'
mana: The mana statement determines how much mana your character will gain in compairison to the baseline. This factor is a percentage multiplier, and defaults to 100. Barbarians, for example, have the statement 'mana = 50' in their PD, so they will gain 50% of the mana that a normal character would. Hermits, on the other hand, have 'mana = 120', and gain 20% more than normal characters.
blows: The blows statement lets you define attacks for a PD. They can set the number of attacks, the weight behind them (if you want one particular race to hit harder without giving them a strength modifier, for example), and a multiplier value, the purpose of which I'm uncertain. An example blows statement is below:
Code: Select all
'blows =
{
mul = 4 --multiplier value
num = 4 --4 starting blows per round.
weight = 35 --weight factor of each hit.
}'
life_rating: life_rating is a modifier to the hit points a character has. This can be a bonus or a negative penalty. Not defining one simply means that the character will get the standard hit points. To adjust it, just use a statement like 'life_rating = 21'.
experience: This is a factor that determines how fast a character will level. Each instance of this statement adds onto previous ones, though you can subtract by using negative values. Adjusting this is the most typical way to balance playable races in roguelikes, though in ToME some classes or backgrounds can have slight adjustments to it as well. This is 0 by default, which would prevent your character from ever gaining levels, and I have no idea how a total negative value would be handled, so it's best to make sure that it has a positive value after charcter creation. To set it, use a statement like 'experience = 150'.
age: The age block determines what the spread is for the age of a character. The first number is the minimum age, and the second is how many more years could be added onto that, determined randomly. unlike most stats, a second age block will replace the first, instead of adding to it. To set it, use a block like the example:
'age = { 14, 6 } --Character is at least 14, may be up to 20 years old.'
weight: This block determines the random weight for the player. Behaves very similarly to age, in that the first number is the base weight and the second is the maximum to add onto the base. Differs from age in that you need to set weights for all the genders available (The T-Engine defines a third gender, NEUTER, but never uses it anywhere, nor does the ToME module). An example use is:
Code: Select all
'weight =
{
female = { 100, 20 } --At least 100, add 0-20 on top of that
male = { 100, 25 } --At least 100, add 0-25 on top of that
}'
height: Exactly like weight above, but for how tall the character is, rather than how heavy.
Code: Select all
'height=
{
female = { 66, 4 } -- 66 inches minium, up to 70 inches.
male = { 72, 6 } -- 72 inches minimum, up to 78 inches.
}'
infravision: Sets the infravision radius, in map squares/tiles, of the PD. If this is 0, the PD does not grant infravision (in which case, you should just leave this statement out instead). Infravision can detect certain monsters that you couldn't otherwise see once they're in range.
levels: If you want this PD to provide specific benefits at certain levels, you'll want to define those in here. This can be used to set any flag you could set otherwise in the game, and adjust any particular number by an yamount you want. The example below details out a small sample of how to set a few different levels with a few different benefits:
Code: Select all
'levels =
{
[ 1] = { RESIST = getter.resists{BLIND=100} SPEEDS=getter.speeds{WALK=-7} }
[ 5] = { SEE_INVIS=true }
[20] = { ESP=getter.flags{ORC=1 TROLL=1 EVIL=1 } }
--At level 1, we are immune to blinding effects and have a reduced walk speed.
--At level 5, the SEE_INVIS flag is set to true, letting us see invisible monsters.
--At level 20, we get to detect monsters with the ORC, TROLL, or EVIL flags.
}'
body: body is used to set how many inventory and equipment slots a character has. In most cases this will be set in the base descriptor, but if you wanted to make a race that couldn't wear armor, you could use a negative value in the proper slot. If you don't want to modify a specific value, simply leave it out from the statement in the current PD. The base example for body is:
'body = { INVEN=23 MAINHAND=1 OFFHAND=1 BODY=1 OUTER=1 LITE=1 HANDS=1 TOOL=1 RING=2 HEAD=1 NECK=1 FEET=1 MOUNT=1 BACKPACK=1 }'
If you wanted to have a 'one-armed bandit' PD, you could use 'body = { OFFHAND = -1 }' to remove the offhand slot.
flags: The flags block allows you to set any flag in the game to the desired value. Unlike levels, these flags are always on from character creation, and don't require you to gain any levels to use them. These tend to be fairly simple, obvious things in ToME, but there's no reason it couldn't be. A simple, gender example:
'flags = { MALE=true } --set the MALE flag value'
skills: The skills block is used to adjust both the current skill value and the amount-gained-per-skill-point value of skills. To use this, first call out a skill by it's visible name, then set the amount to add to the skill, then the amount to gain per skill point. These values all add with other instances, and can be negative to provide a penalty. The example below shows both uses:
Code: Select all
'skills =
{
["Barehand-combat"] = { mods.add(0) , mods.add(200) }
["Boulder-throwing"] = { mods.add(0) , mods.add(600) }
["Stealth"] = { mods.add(-2000), mods.add(0) }
--0 point in barehand combat, .2 added to its level per skill point spent.
--0 point in boulder throwing, .6 added to its level per skill point spent.
--2 points removed from stealth, doesn't adjust the amount gained per skill point.
}'
starting_objects: starting_objects gives the character the included items from this PD at character creation. In most cases, you'll end up calling out the items by T_VAL and S_VAL, but sometimes you'll also want to add in an amount of them for things like food or ammo, in which case you can set the 'min=' and 'max=' statements. If 'min' and 'max' are not the same, the character will receive a random value somewhere between them. This statement cannot remove items already given to a player.
Code: Select all
'starting_objects =
{
{ obj = lookup_kind(TV_LIGHT_ARMOUR, SV_SOFT_LEATHER_JACKET) },
{ obj = lookup_kind(TV_BOW, SV_SHORT_BOW) },
{ obj = lookup_kind(TV_ARROW, SV_BODKIN_ARROW) min=25 max=25 },
--Gives the character starting armor, weapon, and ammo.
}'
abilities: The abilities block lets you set when a PD grants an ability (specifically those defined with the new_ability() function). The abilities appear on the same page as skills in the character creation process. You have to call out the ability by name exactly as it appears on that screen, and then use the = character to set which level you will gain that. The example abilities block from the Ent race:
Code: Select all
'abilities =
{
["Tree walking"] = 1
--Enabled the ability named "Tree Walking" at level 1.
}'
The last 2 statements are ToME-specific statements, and are not part of the T-Engine. These would have to be handled by your module elsewhere within it's code, which is beyond the scope of this document.
titles: titles presents the list of titles to present to a character as they increase in level, usually only set for the character's class. This statement is used by the ToME module, and doesn't appear in the T-Engine of its own accord. The basic mage list is our example:
titles = { "Apprentice", "Trickster", "Illusionist", "Spellbinder", "Evoker", "Conjurer", "Warlock", "Sorcerer", "Ipsissimus", "Archimage", }'
allowed_gods: This statement appears in the caster classes in ToME, but doesn't appear to be implemented yet. It's usage is 'allowed_gods = "All Gods"' in all cases where it does appear.
Now that we'e gone over all of the things you can do with player descriptors, you should be able to go back to the examples at the very top and see what each one is doing when the player selects it. You should also have a pretty good idea of how to make your own player descriptors now, limited less by the engine and more free to use your creativity to bring your ideas to fruition with the proper application of these statements.