THE CONCEPT AND IMPLEMENTATION OF RACES AND SUBRACES IN GENESIS
===============================================================

This document describes the way races (especially player races) work in
Genesis. For NPC's the race-story is rather short. NPC's can be of all races
or species, gender, size or shape. Even though the terms race and species
are not the same, here they are used interchangably. The two functions to
determine the race of a living, query_race() and query_race_name() both
return the same value for a particular NPC. End of story. For players, the
story is a bit more complex, though.

When a player first connects to the game, he or she will have to choose a
race to play. The mud defines only a few basic races to choose from, the
base races. Later, via the membership of a race guild, a player can select a
sub-race. Note that not all race guilds must define a sub-race. It is
perfectly normal for a race guild to focus on the base race. In fact, sub-
races should be the exception, not the rule.

BASE RACE AND SUB-RACE
======================

Two terms have been introduced so far, base race and sub-race. The base race
is one of the small list of races that has been designed by the creators of
the mud. They are dwarf, elf, gnome, goblin, hobbit and human. Each player
must choose one of these races when he creates his character. Various things
have been set for each race, like the way they speak, their racial stat
modifiers, average weight, height, et cetera.

A sub-race is considered to be a refinemenent, variation or breed of one of
the base races. This means that they have to adhere to the following:

- The sub-race can only be defined by a race guild. If an other type of
  major guild sets the sub-race of a player, this guild must _disallow_ the
  player to also be in a race guild.
- Players will always remain of their base race. Since a sub-race is a breed
  or modification of a base race, they will be "largely" similar. How
  "largely" this is, will naturally be the tricky point to define. It
  naturally all comes down to balance and using ones common sense. ;-)
- Hense, sub-races must be humanoid as the base races are humanoid. It is
  not possible to turn a dwarf in to a six-legged flying horse;
- When implementing a subrace, the essential identity and abilities of the
  guild members must remain consistent with their base race. Players of a
  certain sub-race will always keep the properties of the base race, like
  their racial stat modifiers, their height, average weight, et cetera;
- A sub-race may give minor variations in appearance to the player, so long
  as the variations do not introduce ambiguity as to the base race of the
  player. The player must always be logically identifyable as one of the
  base races;
- Domain-code retains the right to treat a player of a certain sub-race as
  being of one of the base races.

QUERYING THE RACE NAME
======================

Two functions are defined in players that will return a race name:

    string query_race()
    string query_race_name()

They both return a string. The query_race() of a player will _always_ return
the name of the base race, i.e. always one of the six races Genesis has
defined. The value returned from it cannot be changed, other than by
selecting a new body in the body shop!

The value returned for query_race_name() can change, though. The sub-race of
a player, or the temporary change of species of a player, is reflected via
query_race_name(). When there is no sub-race of temporary change of species,
the name of the base race is naturally returned.

SETTING A SUB-RACE OR TEMPORARILY CHANGING A RACE
=================================================

To change the name of a player and then reset it again, the following
functions can be used:

    void set_race_name(string race)
    void reset_race_name()

With set_race_name(), the name returned from query_race_name() is changed,
_until_ the player logs out. The value is not saved in the player file. This
is done to prevent people from getting stuck with a race name they should not
have. Therefore, guilds that set a sub-race name must set this _every_ time
the player logs in, just like the soul has to be added to the player each time
he logs in! For wizards, the set race name will stay, just like souls stay.

To temporarily change the race of a player, set_race_name() can also be
used. When the temporary race-change is over, the original race name _must_
be re-set, though. A single line of code suffices for that:

    player->reset_race_name();

RACE GUILDS, DEATH AND OTHER THINGS THAT CHECK RACE
===================================================

When you _check_ the race of a player, you should always use query_race(),
i.e. the base race of your player. This is especially so in racial guilds
that want to check whether the player is still of the proper race. It is not
the idea to kick people out of their guild just because they were turned
into a frog by an evil magician.

When you _display_ the race of a player, you should always use the visible
race, i.e. query_race_name(). When transmuted to smurf, it is quite silly to
have a guard say "Beat it, goblin, we do not want you here!".

DOCUMENTATION
=============

All guilds that alter the sub-race of the player must be approved by the
archwizard for domain matters for thematic confirmation. Also, all items
temporarily altering the race of a player (spells, potions, et cetera) must
have the same approval. This must be noted clearly in the documentation of
the code (file header and guild documentation). This info must include at
least the date and the name of the archwizard granting the approval.

EXAMPLES
========

Below a few examples of what is possible and what is not possible are given.

- a base race 'elf' can become a sub-race 'drow' in a race guild;
- a base race 'goblin' can become a sub-race 'orc' in a race guild;
- a base race 'hobbit' can NOT become a sub-race 'giant' in a race guild;
- NO base race can become a 'horse', 'fish' or 'dragon' in a race guild;
- both a base race 'elf' and 'human' can become a sub-race 'half-elf', as
  long as one can make out the base race by close examination of the person;
- via a spell, any base race can be transformed into a 'frog' temporarily.

CODE EXAMPLE
============

The below piece of example code shows how the functions for the base race
query_race() and sub-race query_race_name() can be used together to create
the best of both worlds: checking based on the base race and printing a
description based on the sub-race. It is the code of a simple command that
allows hobbits (and the like) to crawl through a into hole.

/*
 * Function name: crawl
 * Description  : Whenever a player tries to crawl somewhere, this function
 *                is called to process the command.
 * Arguments    : string str - the command line argument. [where to crawl]
 * Returns      : int 1/0 - success/failure.
 */
int
crawl(string str)
{
    /* Access failure. Does the player type something like 'crawl hole'
     * or a more elaborate 'crawl into the hole'? If not, give a fail msg.
     */
    if (!strlen(str) ||
	!parse_command(str, ({ }), "[in] / [into] [the] 'hole'"))
    {
        notify_fail("Crawl where?\n");
        return 0;
    }

    /* Only a hobbit would be small enough to crawl through this hole.
     * Notice that a hobbit with sub-race kender would also be allowed
     * as they have the same physical properties.
     */
    if (this_player()->query_race() != "hobbit")
    {
        /* The player is too big. Give a proper failure message. Notice
         * that here we do use the name of the sub-race, so that an elf
         * with sub-race drow gets a proper message.
         */
        notify_fail("The hole is just too tight for a " +
            this_player()->query_race_name() + " to crawl through!\n");
        return 0;
    }

    /* All checks have been made and passed? Then crawl into the hole!
     */
    write("You crawl into the hole.\n");
    this_player()->move_living("crawling into the hole", HOLE_ROOM);
    return 1;
}
