Race & Class Compiler for gmoria

Table of Contents

1 Overview

This document describes the race & class compiler (rcc). In more precise terms, this is a code-generation tool that is used to create files called race_class_tables.c and race_class_constant.h in gmoria. It reads in a single human-readable file that completely describes all of the races and classes in the game, and it generates code that can be compiled into the game. rcc issues warnings and errors when things don’t quite make sense. This document describes how to use rcc, and the format of the definition file.

The audience for this tool is a person who wants to add new races or classes to moria in a safe way. Although it’s easy to add new races or classes, the definition file only goes so far; for example it doesn’t allow the adding of new spells, or prayers. There is a hard-coded limit in the game that allows a maximum of 32 classes. There are issues with displaying more than the current number of races in the character creation screen. The limiting factor on the number of races is character creation interface, there is currently space to add 2 more races. When the syntax of the definition file is insufficient, the next step is to change actual C code. Beware that adding new classes and races to the game breaks save-game compatibility with other versions of gmoria.

Some attributes are stored in unsigned 8-bit integers, and others are in unsigned or signed 16-bit integers. Special care needs to be taken to prevent integer overflow in the values of attributes. This document states the allowed values for each attribute.


2 The Defintion File

The definition file describes all of the races and classes in the game. A race is something like a human, or dwarf; while a class is an occupation, like warrior, or mage. rcc reads in this definition file to create the race_class_tables.c and race_class_constant.h files. It is meant to be human-readable, easily understood and modified by non-programmers.

The definition file is comprised of blocks. A block looks something like this:

race "Dwarf" {
	...
};

The block starts with a keyword denoting the kind of block (a race block). Following that there’s a name for the block ("Dwarf"), and then there are a set of braces, followed by a semicolon. The attributes of the dwarf race go inside of the braces (instead of ...).

The definition file has one race block for every race in the game, and one class block for every class in the game. There is also an experience_levels block that defines the number of experience points required to reach a given level. Lastly there are two blocks that map the spell and prayer keywords to their displayed names (spell_names, and prayer_names.)

The top-level structure of the definition file looks like this:

race "Human" {
	...
};
.
.
.
class "Warrior" {
	...
};
.
.
.
experience_levels {
        ...
};
.
.
.
spell_names {
        ...
};
.
.
.
prayer_names {
        ...
};

The race & class compiler will stop processing the definition file when a semi-colon is missing or a required block is forgotten. If an attribute is missing, the compiler will emit a warning. The consistency check option performs extra checking on the races and classes.


2.1 Race Blocks

The race block defines the humans, elves, dwarves (etc), that a character can be in the game. It consists of a series of attributes and some other blocks. The structure of the race block looks like this:

race "foo" {
  attribute: value;
  .
  .
  .

  classes { ... };

  store_price_adjust_by_race {
    .
    .
    .
  };

  shopkeep "name" "race" "store" {
    .
    .
    .
  };
  .
  .
  .
  backgrounds {
    .
    .
    .
  };
};

There are about 20 different required attributes. The classes block defines which classes this race can be. The shopkeep blocks declare the characteristics of the store owners of this race. Store owners change their prices based on what race the character is. The adjust_price_by_race block contains these adjustments. Lastly, the backgrounds block declares a series of sentence fragments that comprise the social history of the character. e.g. ‘you were the black sheep of the family’, etc.


2.2 Race Attributes

Most of these attributes are added to a same-named attribute in the class block (all attributes except age, weights, heights, and infra-vision). rcc will complain if any of these attributes are missing.

age

When characters begin the game they need an age. The age attribute specifies the base age (in years), and a modifier value of a random delta. The maximum value for both halves of the value is 255.

  age: 100|20; # race's age is between 101 and 120.
infra_vision

Some races can see farther into the darkness than others. The infra_vision attribute specifies how far away (in tiles) the character can sense a warm-blooded creature. The maximum value for this attribute is 255.

  infra_vision: 3; # race can sense warm-blooded creatures 3 tiles away. 
male_height

When male characters begin the game they need a height, but some races are taller than others. The male_height attribute specifies the base height (in inches), and a modifier value of a random delta. The maximum value for both halves of this attribute is 255.

  male_height: 62|6; # males in this race are 63 to 69 inches tall.
male_weight

When male characters begin the game they need a weight, but some races are heavier than others. The male_height attribute specifies the base weight (in pounds), and a modifier value of a random delta. The maximum value for both halves of this attribute is 255.

  male_weight: 190|10; # males in this race weigh 191 to 200 lbs.
female_height

Just like male_height but for females in the race.

female_weight

Just like male_weight but for females in the race.

hit_points

When characters begin a game they need a starting amount of hitpoints, but some races can take more damage than others. This attribute has a maximum value of 255.

  hit_points: 10; # the race starts out with a base amount of 10 hp.
disarming

When characters begin the game they have a base chance of disarming traps. The calculation to disarm a trap takes a lot of different factors into account, and this attribute is one of them. The unit of measurement of disarming is unknown, but 200 will disarm the vast majority of traps, and 0 will seldomly disarm traps. The attribute is stored in a 16-bit unsigned integer.

  disarming: 1; #this race has a small chance of disarming a trap.
search_chance

When characters begin the game they have a base chance of finding hidden doors and traps. The maximum value for this attribute is 200.

  search_chance: 10; # has a 5% chance at finding a hidden door or trap.
stealth_factor

When a monster seemingly doesn’t care that the character is walking past them in the dungeon, that’s the stealth factor at work. The maximum value for this attribute is 18. A higher value means more stealth.

  stealth_factor: 18; # a very stealthy race.
base_to_hit

Some races are better at melee fighting than others. The base_to_hit attribute is the base chance of hitting a foe. The maximum value for this attribute is 200.

  base_to_hit: 100; #has an innate ability to hit a foe 50% of the time.
base_to_hit_with_bows

Just like base_to_hit, but for ranged weapons.

saving_throw

Some races have an innate ability to avoid getting hit. The saving_throw attribute is the base chance of avoiding an attack. The unit of measurement for this attribute is unknown, but a value of 100 will probably always avoid an attack.

  saving_throw: 1; # a small innate ability to avoid attacks.
strength_modifier

Some races are stronger than others when characters are created. The strength_modifier typically ranges from 1 to 18, but a low value is sensible because this value is added to a die roll. Negative values are also allowed. To understand what the strength attribute is for (or any of the other main stats), see the Character Stats section of the game manual.

  strength_modifier: -1; #race has an initial strength penalty.
intelligence_modifier

Like strength_modifier but for intelligence.

wisdom_modifier

Like strength_modifier but for wisdom.

dexteriy_modifier

Like strength_modifier but for dexterity.

constitution_modifier

Like strength_modifier but for constitution.

charisma_modifier

Like strength_modifier but for charisma.

experience_factor

Gaining levels in the game means acruing experience points. The experience levels are not the same per race because of the experience_factor attribute, Experience levels can be raised or lowered according to this factor. A value of 0 would break the game, making all experience levels happen at zero experience points. A value of 100 means the levels are the standard levels as described in the experience_levels block. A value of 200 means that the experience levels for this race are doubled the standard. Take care when setting this value, because the experience_factor attribute is one of the greatest determiners of game balance.

  experience_factor: 105;  # race finds it more difficult to level-up.

2.3 Price Adjustment Block

The store_price_adjust_by_race block specifies how store owners (shopkeeps) raise or lower their prices for characters of a given race. Yes it’s true, the Half-Troll gives higher prices, and the Halfling might even give a bit of a break if the player’s character is also a Halfling.

The store_price_adjust_by_race block requires one line for every race specified in the definition file. The structure of the block is:

  store_price_adjust_by_race {
    "race-name" : price;
    .
    .
    .
  };

When the value of a price is 100, it means that the price is neither raised or lowered. When the value of a price is 50 it means the shopkeep of that race will sell things at half off to the given race. For example:

  store_price_adjust_by_race {
    "Human" : 100;
    "Dwarf" : 105;
    "Elf"   : 95;
  };

If this store_price_adjust_by_race block is inside a race "Human" block, and we go to a store with an Elven shopkeep, as a member of the Human race we will get a %5 deal on everything sold in that store. The dwarf will make us pay more.

Whenever a new race is added to, or removed from the definition file, all of the store_price_adjust_by_race blocks need to be updated.


2.4 Shopkeep Blocks

Shopkeeps are the owners of stores who buy and sell items. These quirky characters behave differently according to their attributes specified in a shopkeep block. Each of the six stores needs at least one shopkeep. The game will randomly select shopkeeps when a character is created.

Here is a sample shopkeep block:

  shopkeep "Erick the Honest" "Human" "General Store" {
    store: "1";         haggle_per: 4;          inflate: 108|67;
    max_insults: 12;    max_cost: 250;
  };

The first three chunks of text before the opening brace are used to create the top line that is seen in the store; so there are limits to the width of these chunks of text. The name chunk should be 22 characters or less; the class chunk should be 11 characters or less, and the store name chunk should be 14 characters or less. Although it might seem like the class name should align with the text seen in class blocks, it is not the case. One shopkeep in the game has a class specified here as "Human?".

There are 5 attributes in the shopkeep block:

store

The store attribute species which store the shopkeep occupies. "1" means the general store. All stores must be covered by at least one shopkeep block somewhere in the definition file.

  store: "1"; # the shopkeep occupies the general store.
haggle_per

Some shopkeeps haggle more intensely than others. The haggle_per sets the minimum haggling percent between the prices the player offers before the shopkeep gets insulted. A maximum haggling percent is 3 times haggle_per, where the shopkeep will try to offer a fairer price. The maximum value for haggle_per attribute is 33, but values much lower than this make more sense.

  haggle_per: 4; #allow 4% diff. in haggling offers before being insulted.
max_insults

Shopkeeps will ban characters forever if they insults them too many times by giving outrageous offers while haggling. max_insults is the number of times a shopkeep can be insulted before the shop-doors are closed forever. This value is per-game, not per-visit to the store. Players would definitely be surprised if the shopkeep only allowed one insult! Values of 10 to 20 make more sense. The max_insults attribute has a maxmimum value of 255, and a minimum value of 1.

  max_insults: 12; # can receive 12 insults before refusing service.
inflate

When shopkeeps start haggling they haggle the price between a set of goalposts. The inflate attribute sets these goalposts, as a percent. The first number is the minimum haggling percent, and the second number is added to the minimum to make the maximum haggling percent. The maximum value for both numbers added together is 255.

  inflate: 108|67; #haggles between 108-175 percent of real price.
max_cost

Some shopkeeps won’t sell items that are above a certain price. The max_cost attribute sets that price in gold pieces. It is also the amount of money the shopkeep has on hand to pay out when purchasing an item from the character, which means that there are some items that are just too expensive for the shopkeep to purchase from the character. The maximum value for this attribute is 65535.

max_cost: 250; #can't buy or sell items worth more than 250gp.

2.5 Backgrounds Block

The backgrounds block has two purposes: to assist in setting the initial social class of a character (which affects how many gold pieces is started with), and also to assist in setting the history blurb of the character. The history blurb is the randomized ‘you were a well liked child, with black hair’ text that appears in the character creation screen. The backgrounds block is the most confusing block in the definition file, because it consists of a non-linear chain of background blocks like so:

  backgrounds {
    background 1 2 { . . . },
    background 2 3 { . . . },
    background 3 0 { . . . }
  };

Where the first background (background 1) points to the second, and the second points to the third and the third background block points to nothing which ends the chain.

Note that the background blocks are separated by commas, not semi-colons like other blocks.

These background blocks can be chained across race blocks.

The user-interface of the game can support a history blurb of about 250 characters, or approximately 50 words, over a maximum of 4 lines.


2.5.1 Background Blocks

A background block defines a set of random history blurbs that form a sentence or part of a sentence. The structure of a background block is:

  background id next-id {
    fragment "foo" { . . . },
    fragment "bar" { . . . },
    fragment "baz" { . . . }
  },

The id variable is a unique numeric identifier for this background block among all other blocks. The next-id variable represents which background block this block is tied, or chained to.

The central purpose of the background block is to randomly select one of the contained fragments, and then move on to the next background block, unless the next-id is 0.

This partial example shows a background that defines a set of eye colours:

  background 1 2 {
    fragment "You have blue eyes." { . . . },
    fragment "You have green eyes." { . . . },
    fragment "You have hazel eyes." { . . . }
  },

The id of the background has a maximum value of 255 and cannot be 0. The next-id can be 0 (the value that ends the chain of background blocks), and can also have a maximum value of 255.


2.5.2 Fragment Blocks

Each fragment contains a sentence or a part of a sentence to be randomly selected according to some simple rules.

  fragment "foo" {
    roll: 50;                   social_class_bonus: 49;
  },
  fragment "bar" {
    roll: 100;                  social_class_bonus: 51;
  },

In this example, the bar fragment is randomly selected half of the time, and adds one (not 51) from the character’s social class. The foo fragment is also selected randomly half of the time, and it subtracts one from the character’s social class.

The fragment block starts off with a chunk of text before the opening brace. Sometimes these chunks of text are whole sentences, and sometimes they are just portions of a sentence. These chunks of text often end in spaces because they will be joined with other fragments.

There are two attributes in the fragment block:

roll

The roll attribute is a number between 1 and 100 that represents the chance interval of this fragment being randomly selected. When a fragment is being selected, a random number between 1 and 100 is selected. The first fragment with a roll value of more than the random number is selected.

social_class_bonus

The social_class_bonus attribute is how much to add to the character’s social class if this fragment is randomly selected. A value of 50 is the break-even value – it represents adding zero to the character’s social class. 49 means subtract 1 from the character’s social class. The maximum value for this attribute is 255.

Each set of fragment blocks must contain a roll of 100 to guarntee that one of the fragments is randomly selected.

When creating backgrounds, it is important to note that the character’s social class has a maximum value of 100, and a minimum value of 1.


2.6 Class Blocks

The class block defines the warriors, mages, rogues (etc), that a character can be in the game. It consists of a series of attributes and some other blocks. The structure of the class block looks like this:

  class "Rogue" {
    attribute: value;
    .
    .
    .

    adjust_per_one_third_level { . . . };

    titles { . . . };

    spells { . . . };

    prayers { . . . };
  };

A class can have a spells block or a prayers block (or neither), but a class cannot have both.


2.7 Class Attributes

The attributes of the class block all have their equivalents in the race block. At the beginning of the game when a player selects a race and a class, these same-named attributes are added together. The attributes are:

  hit_points: 6;             strength_modifier: 2;
  disarming: 45;             intelligence_modifier: 1;
  search_chance: 32;         wisdom_modifier: -2;
  stealth_factor: 5;         dexterity_modifier: 3;
  frequency_of_search: 16;   constitution_modifier: 1;
  base_to_hit: 60;           charisma_modifier: -1;
  base_to_hit_with_bows: 66; experience_factor: 0;
  saving_throw: 30;

The class is the main driver of these attributes. The ethos behind this is: what the character does is more important than what the character was born as. Some of these attributes are modified again according to the character’s level in the adjust_per_one_third_level block. The race modifies the values set in this block. For information on what these attributes mean, see Race Attributes. The attributes on the left are all unsigned 8-bit integers (unlike their same-named race counterparts which are 16-bit signed integers). The attributes on the right are all signed 16-bit integers.


2.8 Level Adjustment Block

Some of the class’ abilities are improved as the character gains experience. The adjust_per_one_third_level block is what controls this effect. Here is a sample of the block:

  adjust_per_one_third_level {
    adjust_base_to_hit: 3;
    adjust_base_to_hit_with_bows: 4;
    adjust_use_device: 3;
    adjust_disarming: 4;
    adjust_saving_throw: 3;
  };

The idea behind this block is that the character just naturally improves in these attributes during the game. The effect is meant to be subtle because only one third of the characters’ levels are considered in the calculation. For example, if the character has attained the 31st experience level, the base_to_hit_with_bows attribute is adjusted by +41 points (31 / 3 * 4).


2.9 Titles Block

Every experience level has a new "title", or name. A first level mage is a ‘Novice’. A 38th level rogue is an ‘Assassin’. The titles block sets all of the names of the experience levels for the class that contains it. There must be one title for every level specified in the experience_levels block. For example if there are only 5 experience levels, a title block for a fictional "Mechanic" class might look like:

  titles {
    "Grease Monkey", "Oil Changer", "Journeyman Mechanic",
    "Engine Specialist", "Master Mechanic"
  };

The titles block is one way that the game reveals itself slowly over time. Seeing a new title is a reward for attaining a new level, so create them with that in mind (e.g. try not to make boring titles). This can be a difficult task because there are usually 40 titles per class. Titles are limited to a maximum length of 13 characters on the main game screen.


2.10 Spells Block

Some classes can cast spells and some can’t. When classes can cast spells, the class has a spells block which defines which spells the class can cast. The spells block has this structure:

  spells {
    spell cure_light_wounds { . . . },
    spell lightning_bolt { . . . }
  };

It is important to note that subsequent spell blocks are separated by commas, and not semi-colons. A spell-casting class can cast the following spells:

magic_missiledetect_monsters
phase_doorlight_area
cure_light_woundsstinking_cloud
find_hidden_traps_and_doorsconfusion
lightning_bolttrap_and_door_destruction
sleep_icure_poison
teleport_selfremove_curse
frost_boltturn_stone_to_mud
create_foodrecharge_item_i
sleep_iipolymorph_other
identifysleep_iii
fire_boltslow_monster
frost_ballrecharge_item_ii
teleport_otherhaste_self
fire_ballword_of_destruction
genocideresist_poison_gas

For a short description about what these spells do, see the Treasure Compiler manual.

Each spell block declares when the spell becomes available to cast to the character, how much mana it takes to cast, how often it fails, and how many experience points are gained when the spell is cast for the first time. The spell block has the following structure:

  spell magic_missile {
    level: 1;         mana: 1;        fail: 22;       exp: 1;
  },

The spell block contains the following attributes:

level

The level attribute is the experience level that the spell can be cast at, if the character has the correct book. This attribute is stored in an 8-bit unsigned integer; so the maximum value is 255.

mana

The mana attribute is the number of mana points required to cast to spell. After the casting, this many mana points is subtracted from the players’ mana. This attribute is stored as an 8-bit unsigned integer; so the maximum value is 255. The minimum value for this attribute is 1.

fail

The fail attribute is the percent chance that the spell cannot be cast. The player’s chance of failure takes other factors into account other than just this attribute – so it is properly thought of as a base chance. The maximum value of this attribute is 100, but even that is too high in a practical sense.

exp

The exp attribute represents the number of experience points that are gained when the spell is successfully cast for the first time. The actual value of experience points gained is the given value bit-shifted two bits to the left. A value of 1 becomes 4; a value of 32 becomes 128, and a value of 128 becomes 512 experience points. The maximum value for the exp attribute is 255 (which results in 1020 experience points).


2.11 Prayers Block

The prayers block is just like the spells block but it contains prayer blocks instead of spell blocks. The following prayers can be prayed:

detect_evilcure_light_wounds
blessremove_fear
call_lightfind_traps
detect_doors_and_stairsslow_poison
blind_creatureportal
cure_medium_woundschant
sanctuarycreate_food
remove_curseresist_heat_and_cold
neutralize_poisonorb_of_draining
cure_serious_woundssense_invisible
protection_from_evilearthquake
sense_surroundingscure_critical_wounds
turn_undeadpray_prayer
dispel_undeadheal
dispel_evilglyph_of_warding
holy_wordresist_poision_gas

For a short description about what these prayers do, see the Treasure Compiler manual.


2.12 Experience Levels Block

The experience_levels block defines the number of experience levels in the game, and what number of experience points is required to attain each level. These levels are augmented for each race and class combination, as seen in the experience_factor attribute of the race and class blocks.

The experience_levels block looks like:

  experience_levels {
    10, 100, 1000, 1000
  };

The first experience level is at 10 points, the second is at 100 points and so on. The numbers must always increase.

Take care when setting the values in this block, because it is one of the greatest determiners of game balance.


2.13 Name Blocks

When a spell or prayer is casted, or listed on screen it has a name. The spell_names block lists the names of spells in the game, and the prayer_names block lists the names of prayers in the game.

The ordering of the spells or prayers in these blocks does not matter. The true ordering of spells is set by the ordering of spells in the Mage and Priest classes.

There must be a name given for every possible spell or prayer. For a list of spells see Spells Block, for prayers see Prayers Block.

The name block looks like this:

  spell_names {
    magic_missile: "Magic Missile";
  };

3 A Small Example

Let’s take this definition file as an example; one race and one class is define.:

race "Istari" {                 experience_factor: 100;
  age: 114|30;                  infra_vision: 2;
  male_height: 72|6;            male_weight: 180|25;
  female_height: 72|6;          female_weight: 180|25;
  hit_points: 14;               intelligence_modifier: 2;
  wisdom_modifier: 2;           dexterity_modifier: 2;

  classes { "Magic-User" };
  store_price_adjust_by_race { "Istari": 100; };

  shopkeep "Hundar the Blue " "Wizard" "Ye Olde Magic Shoppe" {
    store: "1"; haggle_per: 4; inflate: 108|67; max_insults: 12; max_cost: 250;
  };

  backgrounds {
    background 1 2 {
      fragment "You are affiliated with water spirits, " {
        roll: 44;       social_class_bonus: 35; },
      fragment "You are affiliated with fire spirits, " {
        roll: 100;      social_class_bonus: 50; } },
    background 2 0 {
      fragment "and remember some of the song of creation." {
        roll: 35;       social_class_bonus: 80; },
      fragment "and remember most of the song of creation." {
        roll: 80;       social_class_bonus: 90; },
      fragment "and remember the entire song of creation." {
        roll: 100;      social_class_bonus: 105; } }
  };
};

class "Magic-User" {            experience_factor: 30;
  disarming: 30;                search_chance: 16;
  stealth_factor: 2;            frequency_of_search: 20;
  base_to_hit: 34;              base_to_hit_with_bows: 20;
  saving_throw: 36;             strength_modifier: -5;
  intelligence_modifier: 3;     dexterity_modifier: 1;
  constitution_modifier: -2;    charisma_modifier: 1;

  adjust_per_one_third_level {  adjust_saving_throw: 3;
    adjust_base_to_hit: 2;      adjust_base_to_hit_with_bows: 2;
    adjust_use_device: 4;       adjust_disarming: 3;
  };

  titles {
    "Wizard (1st)", "Wizard (2nd)", "Wizard (3rd)", "Wizard (4th)",
    "Wizard (5th)", "Wizard (6th)", "Wizard (7th)", "Wizard (8th)"
  };

  spells {
    spell magic_missile  { level: 1;  mana: 1; fail: 22; exp: 1; },
    spell lightning_bolt { level: 10; mana: 4; fail: 30; exp: 6; }
  };
};

experience_levels {
  100, 500, 1800, 4400, 10200, 35000, 150000, 500000
};

spell_names {
  magic_missile: "Magic Missile";
  lightning_bolt: "Lightning Bolt";
};

The resulting file that rcc outputs looks like this:

/* The following was generated by the gmoria race & class compiler */
#include "constant.h"
#include "types.h"

/* Store owners have different characteristics for pricing and haggling*/
owner_type owners[MAX_OWNERS] = {
  {"Hundar the Blue        (Wizard)     Ye Olde Magic Shoppe",
   250, 175, 108, 4, 0, 12, 0},
};

/* Buying and selling adjustments for character race VS store   */
/* owner race                                                    */
int8u rgold_adj[MAX_RACES][MAX_RACES] = {
                  /* Ist */
/*Istari         */ {100}
};

/* Class titles for different levels                            */
char *player_title[MAX_CLASS][MAX_PLAYER_LEVEL] = {
  /* Magic-User    */
  {"Wizard (1st)", "Wizard (2nd)", "Wizard (3rd)", "Wizard (4th)", 
   "Wizard (5th)", "Wizard (6th)", "Wizard (7th)", "Wizard (8th)"},
};

/* Base experience levels, may be adjusted up for race and/or class*/
int32u player_exp[MAX_PLAYER_LEVEL] = {
  100, 500, 1800, 4400, 10200, 35000L, 150000L, 500000L,
};

/*  Race  STR,INT,WIS,DEX,CON,CHR, 
    Ages, heights, and weights (male then female)
    Racial Bases for: dis,srh,stl,fos,bth,bthb,bsav,hitdie,
    infra, exp base, choice-classes */
race_type race[MAX_RACES] = {
  {"Istari", 0, 2, 2, 2, 0, 0,
   114, 30, 72, 6, 180, 25, 72, 6, 180, 25,
   0, 0, 0, 0, 0, 0, 0, 14, 2, 100, 0x01,
   },
};

/* Classes.                                                     */
class_type class[MAX_CLASS] = {
/*            HP Dis Src Stl Fos bth btb sve  S  I  W  D Co Ch Spell Exp spl */
  {"Magic-User",  0, 30, 16,  2, 20, 34, 20, 36,-5, 3, 0, 1,-2, 1,MAGE,  30,  1}
};

/* making it 16 bits wastes a little space, but saves much signed/unsigned
   headaches in its use */
/* CLA_MISC_HIT is identical to CLA_SAVE, which takes advantage of
   the fact that the save values are independent of the class */
int16 class_level_adj[MAX_CLASS][MAX_LEV_ADJ] = {
/*             bth bthb  devices disarm save/misc hit  */
/* Magic-User */ {  2,   2,       4,     3,            3}
};

/* Background information                                       */
int background_start[MAX_RACES] = { /* starting .chart not index */
    1, /* Istari */
};

background_type background[MAX_BACKGROUND] = {
  {"You are affiliated with water spirits, ", 44, 1, 2, 35},
  {"You are affiliated with fire spirits, ", 100, 1, 2, 50},
  {"and remember some of the song of creation.", 35, 2, 0, 80},
  {"and remember most of the song of creation.", 80, 2, 0, 90},
  {"and remember the entire song of creation.", 100, 2, 0, 105}
};

spell_type magic_spell[MAX_CLASS][31] = {
  {                              /* Magic-User    */
   {1, 1, 22, 1},
   {MAX_SPELLS, MAX_SPELLS, 0, 0},
   {MAX_SPELLS, MAX_SPELLS, 0, 0},
   {MAX_SPELLS, MAX_SPELLS, 0, 0},
   {MAX_SPELLS, MAX_SPELLS, 0, 0},
   {MAX_SPELLS, MAX_SPELLS, 0, 0},
   {MAX_SPELLS, MAX_SPELLS, 0, 0},
   {MAX_SPELLS, MAX_SPELLS, 0, 0},
   {10, 4, 30, 6},
   {MAX_SPELLS, MAX_SPELLS, 0, 0},
   {MAX_SPELLS, MAX_SPELLS, 0, 0},
   {MAX_SPELLS, MAX_SPELLS, 0, 0},
   {MAX_SPELLS, MAX_SPELLS, 0, 0},
   {MAX_SPELLS, MAX_SPELLS, 0, 0},
   {MAX_SPELLS, MAX_SPELLS, 0, 0},
   {MAX_SPELLS, MAX_SPELLS, 0, 0},
   {MAX_SPELLS, MAX_SPELLS, 0, 0},
   {MAX_SPELLS, MAX_SPELLS, 0, 0},
   {MAX_SPELLS, MAX_SPELLS, 0, 0},
   {MAX_SPELLS, MAX_SPELLS, 0, 0},
   {MAX_SPELLS, MAX_SPELLS, 0, 0},
   {MAX_SPELLS, MAX_SPELLS, 0, 0},
   {MAX_SPELLS, MAX_SPELLS, 0, 0},
   {MAX_SPELLS, MAX_SPELLS, 0, 0},
   {MAX_SPELLS, MAX_SPELLS, 0, 0},
   {MAX_SPELLS, MAX_SPELLS, 0, 0},
   {MAX_SPELLS, MAX_SPELLS, 0, 0},
   {MAX_SPELLS, MAX_SPELLS, 0, 0},
   {MAX_SPELLS, MAX_SPELLS, 0, 0},
   {MAX_SPELLS, MAX_SPELLS, 0, 0},
   {MAX_SPELLS, MAX_SPELLS, 0, 0}
   }
};

char *spell_names[2][MAX_SPELLS] = {
  {
  /* Mage Spells */
    "Magic Missile", "", "", "", "", "", "", "", "Lightning Bolt", 
    "", "", "", "", "", "", "", "", "", "", "", "", "", "", 
    "", "", "", "", "", "", "", "", ""
  }, {
  /* Priest Prayers */
    "", "", "", "", "", "", "", "", "", "", "", "", "", "", 
    "", "", "", "", "", "", "", "", "", "", "", "", "", "", 
    "", "", "", ""
  }
};

4 Invoking moria-rcc

This is the output of the command ‘rcc --help’:

Usage: moria-rcc [OPTION...] FILE
Generate gmoria's race_class_tables.c from FILE.

  -c, --consistency-check    check for consistency errors
  -C, --constants            generate constants instead of tables.
  -o, --outfile=FILE         put generated code into FILE
  -?, --help                 give this help list
      --usage                give a short usage message
  -V, --version              print program version

By default the race_class_tables.c file goes to the standard output unless the
-o option is used.

For complete documentation, visit: <http://sv.nongnu.org/p/gmoria/>

Report bugs to gmoria@nym.hush.com.

FILE is the defintion file to "compile". If it is "-", then it will be read from the standard input.

rcc supports the following options:

-o
--outputfile

Put generated code into FILE. This option puts the generated race_class_tables.c file into the given FILE. If FILE is "-", then it will go to the standard output. This is the default.

-c
--consistency-check

Check for consistency errors. A loose set of rules is applied the definition file.

-C
--constants

Generate constants instead of tables. This option makes moria-rcc generate the race_class_constant.h file instead of the race_class_tables.c file.


4.1 Consistency Checks


5 Workflow

moria-mc will typically be used in this fashion:

  1. start a new definition file
  2. add and modify race and class blocks
  3. run moria-rcc on the new definition file
  4. check for warning and errors, goto 2 if there are any
  5. put the resulting file in src/race_class_tables.c.
  6. now re-run moria-rcc with the –constants option and the same defintion file.
  7. put the resulting file in src/race_class_constant.h.
  8. recompile gmoria by typing ‘make’ in the top level directory.

6 Contributors

The following persons have contributed to this software:


7 Reporting Bugs

If you find a bug in moria-rcc, please send electronic mail to gmoria@nym.hush.com. Include the version number, which you can find by running ‘rcc --version. Also include in your message the output that the program produced and the output you expected.

If you have other questions, comments or suggestions about moria-rcc, contact the author via electronic mail to gmoria@nym.hush.com.