1    | /*	SCCS Id: @(#)role.c	3.3	2000/05/21	*/
2    | /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985-1999. */
3    | /* NetHack may be freely redistributed.  See license for details. */
4    | 
5    | #include "hack.h"
6    | 
7    | 
8    | /*** Table of all roles ***/
9    | /* According to AD&D, HD for some classes (ex. Wizard) should be smaller
10   |  * (4-sided for wizards).  But this is not AD&D, and using the AD&D
11   |  * rule here produces an unplayable character.  Thus I have used a minimum
12   |  * of an 10-sided hit die for everything.  Another AD&D change: wizards get
13   |  * a minimum strength of 4 since without one you can't teleport or cast
14   |  * spells. --KAA
15   |  *
16   |  * As the wizard has been updated (wizard patch 5 jun '96) their HD can be
17   |  * brought closer into line with AD&D. This forces wizards to use magic more
18   |  * and distance themselves from their attackers. --LSZ
19   |  *
20   |  * With the introduction of races, some hit points and energy
21   |  * has been reallocated for each race.  The values assigned
22   |  * to the roles has been reduced by the amount allocated to
23   |  * humans.  --KMH
24   |  *
25   |  * God names use a leading underscore to flag goddesses.
26   |  */
27   | const struct Role roles[] = {
28   | {	{"Archeologist", 0}, {
29   | 	{"Digger",      0},
30   | 	{"Field Worker",0},
31   | 	{"Investigator",0},
32   | 	{"Exhumer",     0},
33   | 	{"Excavator",   0},
34   | 	{"Spelunker",   0},
35   | 	{"Speleologist",0},
36   | 	{"Collector",   0},
37   | 	{"Curator",     0} },
38   | 	"Quetzalcoatl", "Camaxtli", "Huhetotl", /* Central American */
39   | 	"Arc", "the College of Archeology", "the Tomb of the Toltec Kings",
40   | 	PM_ARCHEOLOGIST, NON_PM, NON_PM,
41   | 	PM_LORD_CARNARVON, PM_STUDENT, PM_MINION_OF_HUHETOTL,
42   | 	NON_PM, PM_HUMAN_MUMMY, S_SNAKE, S_MUMMY,
43   | 	ART_ORB_OF_DETECTION,
44   | 	MH_HUMAN|MH_DWARF|MH_GNOME | ROLE_MALE|ROLE_FEMALE |
45   | 	  ROLE_LAWFUL|ROLE_NEUTRAL,
46   | 	/* Str Int Wis Dex Con Cha */
47   | 	{   7, 10, 10,  7,  7,  7 },
48   | 	{  20, 20, 20, 10, 20, 10 },
49   | 	/* Init   Lower  Higher */
50   | 	{ 11, 0,  0, 8,  1, 0 },	/* Hit points */
51   | 	{  1, 0,  0, 1,  0, 1 },14,	/* Energy */
52   | 	10, 5, 0, 2, 10, A_INT, SPE_MAGIC_MAPPING,   -4
53   | },
54   | {	{"Barbarian", 0}, {
55   | 	{"Plunderer",   "Plunderess"},
56   | 	{"Pillager",    0},
57   | 	{"Bandit",      0},
58   | 	{"Brigand",     0},
59   | 	{"Raider",      0},
60   | 	{"Reaver",      0},
61   | 	{"Slayer",      0},
62   | 	{"Chieftain",   "Chieftainess"},
63   | 	{"Conqueror",   "Conqueress"} },
64   | 	"Mitra", "Crom", "Set", /* Hyborian */
65   | 	"Bar", "the Camp of the Duali Tribe", "the Duali Oasis",
66   | 	PM_BARBARIAN, NON_PM, NON_PM,
67   | 	PM_PELIAS, PM_CHIEFTAIN, PM_THOTH_AMON,
68   | 	PM_OGRE, PM_TROLL, S_OGRE, S_TROLL,
69   | 	ART_HEART_OF_AHRIMAN,
70   | 	MH_HUMAN|MH_ORC | ROLE_MALE|ROLE_FEMALE |
71   | 	  ROLE_NEUTRAL|ROLE_CHAOTIC,
72   | 	/* Str Int Wis Dex Con Cha */
73   | 	{  16,  7,  7, 15, 16,  6 },
74   | 	{  30,  6,  7, 20, 30,  7 },
75   | 	/* Init   Lower  Higher */
76   | 	{ 14, 0,  0,10,  2, 0 },	/* Hit points */
77   | 	{  1, 0,  0, 1,  0, 1 },10,	/* Energy */
78   | 	10, 14, 0, 0,  8, A_INT, SPE_HASTE_SELF,      -4
79   | },
80   | {	{"Caveman", "Cavewoman"}, {
81   | 	{"Troglodyte",  0},
82   | 	{"Aborigine",   0},
83   | 	{"Wanderer",    0},
84   | 	{"Vagrant",     0},
85   | 	{"Wayfarer",    0},
86   | 	{"Roamer",      0},
87   | 	{"Nomad",       0},
88   | 	{"Rover",       0},
89   | 	{"Pioneer",     0} },
90   | 	"Anu", "_Ishtar", "Anshar", /* Babylonian */
91   | 	"Cav", "the Caves of the Ancestors", "the Dragon's Lair",
92   | 	PM_CAVEMAN, PM_CAVEWOMAN, PM_LITTLE_DOG,
93   | 	PM_SHAMAN_KARNOV, PM_NEANDERTHAL, PM_CHROMATIC_DRAGON,
94   | 	PM_BUGBEAR, PM_HILL_GIANT, S_HUMANOID, S_GIANT,
95   | 	ART_SCEPTRE_OF_MIGHT,
96   | 	MH_HUMAN|MH_DWARF|MH_GNOME | ROLE_MALE|ROLE_FEMALE |
97   | 	  ROLE_LAWFUL|ROLE_NEUTRAL,
98   | 	/* Str Int Wis Dex Con Cha */
99   | 	{  10,  7,  7,  7,  8,  6 },
100  | 	{  30,  6,  7, 20, 30,  7 },
101  | 	/* Init   Lower  Higher */
102  | 	{ 14, 0,  0, 8,  2, 0 },	/* Hit points */
103  | 	{  1, 0,  0, 1,  0, 1 },10,	/* Energy */
104  | 	0, 12, 0, 1,  8, A_INT, SPE_DIG,             -4
105  | },
106  | {	{"Healer", 0}, {
107  | 	{"Rhizotomist",    0},
108  | 	{"Empiric",        0},
109  | 	{"Embalmer",       0},
110  | 	{"Dresser",        0},
111  | 	{"Medici ossium",  0},
112  | 	{"Herbalist",      0},
113  | 	{"Magister",       0},
114  | 	{"Physician",      0},
115  | 	{"Chirurgeon",     0} },
116  | 	"_Athena", "Hermes", "Poseidon", /* Greek */
117  | 	"Hea", "the Temple of Epidaurus", "the Temple of Coeus",
118  | 	PM_HEALER, NON_PM, NON_PM,
119  | 	PM_HIPPOCRATES, PM_ATTENDANT, PM_CYCLOPS,
120  | 	PM_GIANT_RAT, PM_SNAKE, S_RODENT, S_YETI,
121  | 	ART_STAFF_OF_AESCULAPIUS,
122  | 	MH_HUMAN|MH_GNOME | ROLE_MALE|ROLE_FEMALE | ROLE_NEUTRAL,
123  | 	/* Str Int Wis Dex Con Cha */
124  | 	{   7,  7, 13,  7, 11, 16 },
125  | 	{  15, 20, 20, 15, 25, 10 },
126  | 	/* Init   Lower  Higher */
127  | 	{ 11, 0,  0, 8,  1, 0 },	/* Hit points */
128  | 	{  1, 4,  0, 1,  0, 2 },20,	/* Energy */
129  | 	10, 3,-3, 2, 10, A_WIS, SPE_CURE_SICKNESS,   -4
130  | },
131  | {	{"Knight", 0}, {
132  | 	{"Gallant",     0},
133  | 	{"Esquire",     0},
134  | 	{"Bachelor",    0},
135  | 	{"Sergeant",    0},
136  | 	{"Knight",      0},
137  | 	{"Banneret",    0},
138  | 	{"Chevalier",   0},
139  | 	{"Seignieur",   0},
140  | 	{"Paladin",     0} },
141  | 	"Lugh", "_Brigit", "Manannan Mac Lir", /* Celtic */
142  | 	"Kni", "Camelot Castle", "the Isle of Glass",
143  | 	PM_KNIGHT, NON_PM, PM_PONY,
144  | 	PM_KING_ARTHUR, PM_PAGE, PM_IXOTH,
145  | 	PM_QUASIT, PM_OCHRE_JELLY, S_IMP, S_JELLY,
146  | 	ART_MAGIC_MIRROR_OF_MERLIN,
147  | 	MH_HUMAN | ROLE_MALE|ROLE_FEMALE | ROLE_LAWFUL,
148  | 	/* Str Int Wis Dex Con Cha */
149  | 	{  13,  7, 14,  8, 10, 17 },
150  | 	{  20, 15, 15, 10, 20, 10 },
151  | 	/* Init   Lower  Higher */
152  | 	{ 14, 0,  0, 8,  2, 0 },	/* Hit points */
153  | 	{  1, 4,  0, 1,  0, 2 },10,	/* Energy */
154  | 	10, 8,-2, 0,  9, A_WIS, SPE_TURN_UNDEAD,     -4
155  | },
156  | {	{"Monk", 0}, {
157  | 	{"Candidate",         0},
158  | 	{"Novice",            0},
159  | 	{"Initiate",          0},
160  | 	{"Student of Stones", 0},
161  | 	{"Student of Waters", 0},
162  | 	{"Student of Metals", 0},
163  | 	{"Student of Winds",  0},
164  | 	{"Student of Fire",   0},
165  | 	{"Master",            0} },
166  | 	"Shan Lai Ching", "Chih Sung-tzu", "Huan Ti", /* Chinese */
167  | 	"Mon", "the Monastery of Chan-Sune",
168  | 	  "the Monastery of the Earth-Lord",
169  | 	PM_MONK, NON_PM, NON_PM,
170  | 	PM_GRAND_MASTER, PM_ABBOT, PM_MASTER_KAEN,
171  | 	PM_EARTH_ELEMENTAL, PM_XORN, S_ELEMENTAL, S_XORN,
172  | 	ART_EYES_OF_THE_OVERWORLD,
173  | 	MH_HUMAN | ROLE_MALE|ROLE_FEMALE |
174  | 	  ROLE_LAWFUL|ROLE_NEUTRAL|ROLE_CHAOTIC,
175  | 	/* Str Int Wis Dex Con Cha */
176  | 	{  10,  7,  8,  8,  7,  7 },
177  | 	{  25, 10, 20, 20, 15, 10 },
178  | 	/* Init   Lower  Higher */
179  | 	{ 12, 0,  0, 8,  1, 0 },	/* Hit points */
180  | 	{  2, 2,  0, 2,  0, 2 },10,	/* Energy */
181  | 	10, 8,-2, 2, 20, A_WIS, SPE_RESTORE_ABILITY, -4
182  | },
183  | {	{"Priest", "Priestess"}, {
184  | 	{"Aspirant",    0},
185  | 	{"Acolyte",     0},
186  | 	{"Adept",       0},
187  | 	{"Priest",      "Priestess"},
188  | 	{"Curate",      0},
189  | 	{"Canon",       "Canoness"},
190  | 	{"Lama",        0},
191  | 	{"Patriarch",   "Matriarch"},
192  | 	{"High Priest", "High Priestess"} },
193  | 	0, 0, 0,	/* chosen randomly from among the other roles */
194  | 	"Pri", "the Great Temple", "the Temple of Nalzok",
195  | 	PM_PRIEST, PM_PRIESTESS, NON_PM,
196  | 	PM_ARCH_PRIEST, PM_ACOLYTE, PM_NALZOK,
197  | 	PM_HUMAN_ZOMBIE, PM_WRAITH, S_ZOMBIE, S_WRAITH,
198  | 	ART_MITRE_OF_HOLINESS,
199  | 	MH_HUMAN|MH_ELF | ROLE_MALE|ROLE_FEMALE |
200  | 	  ROLE_LAWFUL|ROLE_NEUTRAL|ROLE_CHAOTIC,
201  | 	/* Str Int Wis Dex Con Cha */
202  | 	{   7,  7, 10,  7,  7,  7 },
203  | 	{  15, 10, 30, 15, 20, 10 },
204  | 	/* Init   Lower  Higher */
205  | 	{ 12, 0,  0, 8,  1, 0 },	/* Hit points */
206  | 	{  4, 3,  0, 2,  0, 2 },10,	/* Energy */
207  | 	0, 3,-2, 2, 10, A_WIS, SPE_REMOVE_CURSE,    -4
208  | },
209  |   /* Note:  Rogue precedes Ranger so that use of `-R' on the command line
210  |      retains its traditional meaning. */
211  | {	{"Rogue", 0}, {
212  | 	{"Footpad",     0},
213  | 	{"Cutpurse",    0},
214  | 	{"Rogue",       0},
215  | 	{"Pilferer",    0},
216  | 	{"Robber",      0},
217  | 	{"Burglar",     0},
218  | 	{"Filcher",     0},
219  | 	{"Magsman",     "Magswoman"},
220  | 	{"Thief",       0} },
221  | 	"Issek", "Mog", "Kos", /* Nehwon */
222  | 	"Rog", "the Thieves' Guild Hall", "the Assassins' Guild Hall",
223  | 	PM_ROGUE, NON_PM, NON_PM,
224  | 	PM_MASTER_OF_THIEVES, PM_THUG, PM_MASTER_ASSASSIN,
225  | 	PM_LEPRECHAUN, PM_GUARDIAN_NAGA, S_NYMPH, S_NAGA,
226  | 	ART_MASTER_KEY_OF_THIEVERY,
227  | 	MH_HUMAN|MH_ORC | ROLE_MALE|ROLE_FEMALE |
228  | 	  ROLE_CHAOTIC,
229  | 	/* Str Int Wis Dex Con Cha */
230  | 	{   7,  7,  7, 10,  7,  6 },
231  | 	{  20, 10, 10, 30, 20, 10 },
232  | 	/* Init   Lower  Higher */
233  | 	{ 10, 0,  0, 8,  1, 0 },	/* Hit points */
234  | 	{  1, 0,  0, 1,  0, 1 },11,	/* Energy */
235  | 	10, 8, 0, 1,  9, A_INT, SPE_DETECT_TREASURE, -4
236  | },
237  | {	{"Ranger", 0}, {
238  | #if 0	/* OBSOLETE */
239  | 	{"Edhel",       "Elleth"},
240  | 	{"Edhel",       "Elleth"},      /* elf-maid */
241  | 	{"Ohtar",       "Ohtie"},       /* warrior */
242  | 	{"Kano",			/* commander (Q.) ['a] */
243  | 			"Kanie"},	/* educated guess, until further research- SAC */
244  | 	{"Arandur",			/* king's servant, minister (Q.) - guess */
245  | 			"Aranduriel"},	/* educated guess */
246  | 	{"Hir",         "Hiril"},       /* lord, lady (S.) ['ir] */
247  | 	{"Aredhel",     "Arwen"},       /* noble elf, maiden (S.) */
248  | 	{"Ernil",       "Elentariel"},  /* prince (S.), elf-maiden (Q.) */
249  | 	{"Elentar",     "Elentari"},	/* Star-king, -queen (Q.) */
250  | 	"Solonor Thelandira", "Aerdrie Faenya", "Lolth", /* Elven */
251  | #endif
252  | 	{"Tenderfoot",    0},
253  | 	{"Lookout",       0},
254  | 	{"Trailblazer",   0},
255  | 	{"Reconnoiterer", "Reconnoiteress"},
256  | 	{"Scout",         0},
257  | 	{"Arbalester",    0},	/* One skilled at crossbows */
258  | 	{"Archer",        0},
259  | 	{"Sharpshooter",  0},
260  | 	{"Marksman",      "Markswoman"} },
261  | 	"Mercury", "_Venus", "Mars", /* Roman/planets */
262  | 	"Ran", "Orion's camp", "the cave of the wumpus",
263  | 	PM_RANGER, NON_PM, PM_LITTLE_DOG /* Orion & canis major */,
264  | 	PM_ORION, PM_HUNTER, PM_SCORPIUS,
265  | 	PM_FOREST_CENTAUR, PM_SCORPION, S_CENTAUR, S_SPIDER,
266  | 	ART_LONGBOW_OF_DIANA,
267  | 	MH_HUMAN|MH_ELF|MH_GNOME|MH_ORC | ROLE_MALE|ROLE_FEMALE |
268  | 	  ROLE_NEUTRAL|ROLE_CHAOTIC,
269  | 	/* Str Int Wis Dex Con Cha */
270  | 	{  13, 13, 13,  9, 13,  7 },
271  | 	{  30, 10, 10, 20, 20, 10 },
272  | 	/* Init   Lower  Higher */
273  | 	{ 13, 0,  0, 6,  1, 0 },	/* Hit points */
274  | 	{  1, 0,  0, 1,  0, 1 },12,	/* Energy */
275  | 	10, 9, 2, 1, 10, A_INT, SPE_INVISIBILITY,   -4
276  | },
277  | {	{"Samurai", 0}, {
278  | 	{"Hatamoto",    0},  /* Banner Knight */
279  | 	{"Ronin",       0},  /* no allegiance */
280  | 	{"Ninja",       0},  /* secret society */
281  | 	{"Joshu",       0},  /* heads a castle */
282  | 	{"Ryoshu",      0},  /* has a territory */
283  | 	{"Kokushu",     0},  /* heads a province */
284  | 	{"Daimyo",      0},  /* a samurai lord */
285  | 	{"Kuge",        0},  /* Noble of the Court */
286  | 	{"Shogun",      0} },/* supreme commander, warlord */
287  | 	"_Amaterasu Omikami", "Raijin", "Susanowo", /* Japanese */
288  | 	"Sam", "the Castle of the Taro Clan", "the Shogun's Castle",
289  | 	PM_SAMURAI, NON_PM, PM_LITTLE_DOG,
290  | 	PM_LORD_SATO, PM_ROSHI, PM_ASHIKAGA_TAKAUJI,
291  | 	PM_WOLF, PM_STALKER, S_DOG, S_ELEMENTAL,
292  | 	ART_TSURUGI_OF_MURAMASA,
293  | 	MH_HUMAN | ROLE_MALE|ROLE_FEMALE | ROLE_LAWFUL,
294  | 	/* Str Int Wis Dex Con Cha */
295  | 	{  10,  8,  7, 10, 17,  6 },
296  | 	{  30, 10, 10, 30, 14, 10 },
297  | 	/* Init   Lower  Higher */
298  | 	{ 13, 0,  0, 8,  1, 0 },	/* Hit points */
299  | 	{  1, 0,  0, 1,  0, 1 },11,	/* Energy */
300  | 	10, 10, 0, 0,  8, A_INT, SPE_CLAIRVOYANCE,    -4
301  | },
302  | #ifdef TOURIST
303  | {	{"Tourist", 0}, {
304  | 	{"Rambler",     0},
305  | 	{"Sightseer",   0},
306  | 	{"Excursionist",0},
307  | 	{"Peregrinator","Peregrinatrix"},
308  | 	{"Traveler",    0},
309  | 	{"Journeyer",   0},
310  | 	{"Voyager",     0},
311  | 	{"Explorer",    0},
312  | 	{"Adventurer",  0} },
313  | 	"Blind Io", "_The Lady", "Offler", /* Discworld */
314  | 	"Tou", "Ankh-Morpork", "the Thieves' Guild Hall",
315  | 	PM_TOURIST, NON_PM, NON_PM,
316  | 	PM_TWOFLOWER, PM_GUIDE, PM_MASTER_OF_THIEVES,
317  | 	PM_GIANT_SPIDER, PM_FOREST_CENTAUR, S_SPIDER, S_CENTAUR,
318  | 	ART_YENDORIAN_EXPRESS_CARD,
319  | 	MH_HUMAN | ROLE_MALE|ROLE_FEMALE | ROLE_NEUTRAL,
320  | 	/* Str Int Wis Dex Con Cha */
321  | 	{   7, 10,  6,  7,  7, 10 },
322  | 	{  15, 10, 10, 15, 30, 20 },
323  | 	/* Init   Lower  Higher */
324  | 	{  8, 0,  0, 8,  0, 0 },	/* Hit points */
325  | 	{  1, 0,  0, 1,  0, 1 },14,	/* Energy */
326  | 	0, 5, 1, 2, 10, A_INT, SPE_CHARM_MONSTER,   -4
327  | },
328  | #endif
329  | {	{"Valkyrie", 0}, {
330  | 	{"Stripling",   0},
331  | 	{"Skirmisher",  0},
332  | 	{"Fighter",     0},
333  | 	{"Man-at-arms", "Woman-at-arms"},
334  | 	{"Warrior",     0},
335  | 	{"Swashbuckler",0},
336  | 	{"Hero",        "Heroine"},
337  | 	{"Champion",    0},
338  | 	{"Lord",        "Lady"} },
339  | 	"Tyr", "Odin", "Loki", /* Norse */
340  | 	"Val", "the Shrine of Destiny", "the cave of Surtur",
341  | 	PM_VALKYRIE, NON_PM, NON_PM /*PM_WINTER_WOLF_CUB*/,
342  | 	PM_NORN, PM_WARRIOR, PM_LORD_SURTUR,
343  | 	PM_FIRE_ANT, PM_FIRE_GIANT, S_ANT, S_GIANT,
344  | 	ART_ORB_OF_FATE,
345  | 	MH_HUMAN|MH_DWARF | ROLE_FEMALE | ROLE_LAWFUL|ROLE_NEUTRAL,
346  | 	/* Str Int Wis Dex Con Cha */
347  | 	{  10,  7,  7,  7, 10,  7 },
348  | 	{  30,  6,  7, 20, 30,  7 },
349  | 	/* Init   Lower  Higher */
350  | 	{ 14, 0,  0, 8,  2, 0 },	/* Hit points */
351  | 	{  1, 0,  0, 1,  0, 1 },10,	/* Energy */
352  | 	0, 10,-2, 0,  9, A_WIS, SPE_CONE_OF_COLD,    -4
353  | },
354  | {	{"Wizard", 0}, {
355  | 	{"Evoker",      0},
356  | 	{"Conjurer",    0},
357  | 	{"Thaumaturge", 0},
358  | 	{"Magician",    0},
359  | 	{"Enchanter",   "Enchantress"},
360  | 	{"Sorcerer",    "Sorceress"},
361  | 	{"Necromancer", 0},
362  | 	{"Wizard",      0},
363  | 	{"Mage",        0} },
364  | 	"Ptah", "Thoth", "Anhur", /* Egyptian */
365  | 	"Wiz", "the Tower of the Balance", "the Tower of Darkness",
366  | 	PM_WIZARD, NON_PM, PM_KITTEN,
367  | 	PM_WIZARD_OF_BALANCE, PM_APPRENTICE, PM_DARK_ONE,
368  | 	PM_VAMPIRE_BAT, PM_XORN, S_BAT, S_WRAITH,
369  | 	ART_EYE_OF_THE_AETHIOPICA,
370  | 	MH_HUMAN|MH_ELF|MH_GNOME|MH_ORC | ROLE_MALE|ROLE_FEMALE |
371  | 	  ROLE_NEUTRAL|ROLE_CHAOTIC,
372  | 	/* Str Int Wis Dex Con Cha */
373  | 	{   7, 10,  7,  7,  7,  7 },
374  | 	{  10, 30, 10, 20, 20, 10 },
375  | 	/* Init   Lower  Higher */
376  | 	{ 10, 0,  0, 8,  1, 0 },	/* Hit points */
377  | 	{  4, 3,  0, 2,  0, 3 },12,	/* Energy */
378  | 	0, 1, 0, 3, 10, A_INT, SPE_MAGIC_MISSILE,   -4
379  | },
380  | /* Array terminator */
381  | {{0, 0}}
382  | };
383  | 
384  | 
385  | /* The player's role, created at runtime from initial
386  |  * choices.  This may be munged in role_init().
387  |  */
388  | struct Role urole =
389  | {	{"Undefined", 0}, { {0, 0}, {0, 0}, {0, 0},
390  | 	{0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0} },
391  | 	"L", "N", "C", "Xxx", "home", "locate",
392  | 	NON_PM, NON_PM, NON_PM, NON_PM, NON_PM, NON_PM,
393  | 	NON_PM, NON_PM, 0, 0, 0, 0,
394  | 	/* Str Int Wis Dex Con Cha */
395  | 	{   7,  7,  7,  7,  7,  7 },
396  | 	{  20, 15, 15, 20, 20, 10 },
397  | 	/* Init   Lower  Higher */
398  | 	{ 10, 0,  0, 8,  1, 0 },	/* Hit points */
399  | 	{  2, 0,  0, 2,  0, 3 },14,	/* Energy */
400  | 	0, 10, 0, 0,  4, A_INT, 0, -3
401  | };
402  | 
403  | 
404  | 
405  | /* Table of all races */
406  | const struct Race races[] = {
407  | {	"human", "human", "humanity", "Hum",
408  | 	{"man", "woman"},
409  | 	PM_HUMAN, NON_PM, PM_HUMAN_MUMMY, PM_HUMAN_ZOMBIE,
410  | 	MH_HUMAN | ROLE_MALE|ROLE_FEMALE |
411  | 	  ROLE_LAWFUL|ROLE_NEUTRAL|ROLE_CHAOTIC,
412  | 	MH_HUMAN, 0, MH_GNOME|MH_ORC,
413  | 	/*    Str     Int Wis Dex Con Cha */
414  | 	{      3,      3,  3,  3,  3,  3 },
415  | 	{ STR18(100), 18, 18, 18, 18, 18 },
416  | 	/* Init   Lower  Higher */
417  | 	{  2, 0,  0, 2,  1, 0 },	/* Hit points */
418  | 	{  1, 0,  2, 0,  2, 0 }		/* Energy */
419  | },
420  | {	"elf", "elven", "elvenkind", "Elf",
421  | 	{0, 0},
422  | 	PM_ELF, NON_PM, PM_ELF_MUMMY, PM_ELF_ZOMBIE,
423  | 	MH_ELF | ROLE_MALE|ROLE_FEMALE | ROLE_CHAOTIC,
424  | 	MH_ELF, MH_ELF, MH_ORC,
425  | 	/*  Str    Int Wis Dex Con Cha */
426  | 	{    3,     3,  3,  3,  3,  3 },
427  | 	{   18,    20, 20, 18, 16, 18 },
428  | 	/* Init   Lower  Higher */
429  | 	{  1, 0,  0, 1,  1, 0 },	/* Hit points */
430  | 	{  2, 0,  3, 0,  3, 0 }		/* Energy */
431  | },
432  | {	"dwarf", "dwarven", "dwarvenkind", "Dwa",
433  | 	{0, 0},
434  | 	PM_DWARF, NON_PM, PM_DWARF_MUMMY, PM_DWARF_ZOMBIE,
435  | 	MH_DWARF | ROLE_MALE|ROLE_FEMALE | ROLE_LAWFUL,
436  | 	MH_DWARF, MH_DWARF|MH_GNOME, MH_ORC,
437  | 	/*    Str     Int Wis Dex Con Cha */
438  | 	{      3,      3,  3,  3,  3,  3 },
439  | 	{ STR18(100), 16, 16, 20, 20, 16 },
440  | 	/* Init   Lower  Higher */
441  | 	{  4, 0,  0, 3,  2, 0 },	/* Hit points */
442  | 	{  0, 0,  0, 0,  0, 0 }		/* Energy */
443  | },
444  | {	"gnome", "gnomish", "gnomehood", "Gno",
445  | 	{0, 0},
446  | 	PM_GNOME, NON_PM, PM_GNOME_MUMMY, PM_GNOME_ZOMBIE,
447  | 	MH_GNOME | ROLE_MALE|ROLE_FEMALE | ROLE_NEUTRAL,
448  | 	MH_GNOME, MH_DWARF|MH_GNOME, MH_HUMAN,
449  | 	/*  Str    Int Wis Dex Con Cha */
450  | 	{    3,     3,  3,  3,  3,  3 },
451  | 	{STR18(50),19, 18, 18, 18, 18 },
452  | 	/* Init   Lower  Higher */
453  | 	{  1, 0,  0, 1,  0, 0 },	/* Hit points */
454  | 	{  2, 0,  2, 0,  2, 0 }		/* Energy */
455  | },
456  | {	"orc", "orcish", "orcdom", "Orc",
457  | 	{0, 0},
458  | 	PM_ORC, NON_PM, PM_ORC_MUMMY, PM_ORC_ZOMBIE,
459  | 	MH_ORC | ROLE_MALE|ROLE_FEMALE | ROLE_CHAOTIC,
460  | 	MH_ORC, 0, MH_HUMAN|MH_ELF|MH_DWARF,
461  | 	/*  Str    Int Wis Dex Con Cha */
462  | 	{   3,      3,  3,  3,  3,  3 },
463  | 	{STR18(50),16, 16, 18, 18, 16 },
464  | 	/* Init   Lower  Higher */
465  | 	{  1, 0,  0, 1,  0, 0 },	/* Hit points */
466  | 	{  1, 0,  1, 0,  1, 0 }		/* Energy */
467  | },
468  | /* Array terminator */
469  | { 0, 0, 0, 0 }};
470  | 
471  | 
472  | /* The player's race, created at runtime from initial
473  |  * choices.  This may be munged in role_init().
474  |  */
475  | struct Race urace =
476  | {	"something", "undefined", "something", "Xxx",
477  | 	{0, 0},
478  | 	NON_PM, NON_PM, NON_PM, NON_PM,
479  | 	0, 0, 0, 0,
480  | 	/*    Str     Int Wis Dex Con Cha */
481  | 	{      3,      3,  3,  3,  3,  3 },
482  | 	{ STR18(100), 18, 18, 18, 18, 18 },
483  | 	/* Init   Lower  Higher */
484  | 	{  2, 0,  0, 2,  1, 0 },	/* Hit points */
485  | 	{  1, 0,  2, 0,  2, 0 }		/* Energy */
486  | };
487  | 
488  | 
489  | /* Table of all genders */
490  | const struct Gender genders[] = {
491  | 	{"male",	"he",	"him",	"his",	"Mal",	ROLE_MALE},
492  | 	{"female",	"she",	"her",	"her",	"Fem",	ROLE_FEMALE},
493  | 	{"neuter",	"it",	"it",	"its",	"Ntr",	ROLE_NEUTER}
494  | };
495  | 
496  | 
497  | /* Table of all alignments */
498  | const struct Align aligns[] = {
499  | 	{"law",		"lawful",	"Law",	ROLE_LAWFUL,	A_LAWFUL},
500  | 	{"balance",	"neutral",	"Neu",	ROLE_NEUTRAL,	A_NEUTRAL},
501  | 	{"chaos",	"chaotic",	"Cha",	ROLE_CHAOTIC,	A_CHAOTIC},
502  | 	{"evil",	"unaligned",	"Una",	0,		A_NONE}
503  | };
504  | 
505  | /* used by str2XXX() */
506  | static char NEARDATA randomstr[] = "random";
507  | 
508  | 
509  | boolean
510  | validrole(rolenum)
511  | 	int rolenum;
512  | {
513  | 	return (rolenum >= 0 && rolenum < SIZE(roles)-1);
514  | }
515  | 
516  | 
517  | int
518  | randrole()
519  | {
520  | 	return (rn2(SIZE(roles)-1));
521  | }
522  | 
523  | 
524  | int
525  | str2role(str)
526  | 	char *str;
527  | {
528  | 	int i, len;
529  | 
530  | 	/* Is str valid? */
531  | 	if (!str || !str[0])
532  | 	    return ROLE_NONE;
533  | 
534  | 	/* Match as much of str as is provided */
535  | 	len = strlen(str);
536  | 	for (i = 0; roles[i].name.m; i++) {
537  | 	    /* Does it match the male name? */
538  | 	    if (!strncmpi(str, roles[i].name.m, len))
539  | 		return i;
540  | 	    /* Or the female name? */
541  | 	    if (roles[i].name.f && !strncmpi(str, roles[i].name.f, len))
542  | 		return i;
543  | 	    /* Or the filecode? */
544  | 	    if (!strcmpi(str, roles[i].filecode))
545  | 		return i;
546  | 	}
547  | 
548  | 	if ((len == 1 && (*str == '*' || *str == '@')) ||
549  | 		!strncmpi(str, randomstr, len))
550  | 	    return ROLE_RANDOM;
551  | 
552  | 	/* Couldn't find anything appropriate */
553  | 	return ROLE_NONE;
554  | }
555  | 
556  | 
557  | boolean
558  | validrace(rolenum, racenum)
559  | 	int rolenum, racenum;
560  | {
561  | 	/* Assumes validrole */
562  | 	return (racenum >= 0 && racenum < SIZE(races)-1 &&
563  | 		(roles[rolenum].allow & races[racenum].allow & ROLE_RACEMASK));
564  | }
565  | 
566  | 
567  | int
568  | randrace(rolenum)
569  | 	int rolenum;
570  | {
571  | 	int i, n = 0;
572  | 
573  | 	/* Count the number of valid races */
574  | 	for (i = 0; races[i].noun; i++)
575  | 	    if (roles[rolenum].allow & races[i].allow & ROLE_RACEMASK)
576  | 	    	n++;
577  | 
578  | 	/* Pick a random race */
579  | 	/* Use a factor of 100 in case of bad random number generators */
580  | 	if (n) n = rn2(n*100)/100;
581  | 	for (i = 0; races[i].noun; i++)
582  | 	    if (roles[rolenum].allow & races[i].allow & ROLE_RACEMASK) {
583  | 	    	if (n) n--;
584  | 	    	else return (i);
585  | 	    }
586  | 
587  | 	/* This role has no permitted races? */
588  | 	return (rn2(SIZE(races)-1));
589  | }
590  | 
591  | 
592  | int
593  | str2race(str)
594  | 	char *str;
595  | {
596  | 	int i, len;
597  | 
598  | 	/* Is str valid? */
599  | 	if (!str || !str[0])
600  | 	    return ROLE_NONE;
601  | 
602  | 	/* Match as much of str as is provided */
603  | 	len = strlen(str);
604  | 	for (i = 0; races[i].noun; i++) {
605  | 	    /* Does it match the noun? */
606  | 	    if (!strncmpi(str, races[i].noun, len))
607  | 		return i;
608  | 	    /* Or the filecode? */
609  | 	    if (!strcmpi(str, races[i].filecode))
610  | 		return i;
611  | 	}
612  | 
613  | 	if ((len == 1 && (*str == '*' || *str == '@')) ||
614  | 		!strncmpi(str, randomstr, len))
615  | 	    return ROLE_RANDOM;
616  | 
617  | 	/* Couldn't find anything appropriate */
618  | 	return ROLE_NONE;
619  | }
620  | 
621  | 
622  | boolean
623  | validgend(rolenum, racenum, gendnum)
624  | 	int rolenum, racenum, gendnum;
625  | {
626  | 	/* Assumes validrole and validrace */
627  | 	return (gendnum >= 0 && gendnum < ROLE_GENDERS &&
628  | 		(roles[rolenum].allow & races[racenum].allow &
629  | 		 genders[gendnum].allow & ROLE_GENDMASK));
630  | }
631  | 
632  | 
633  | int
634  | randgend(rolenum, racenum)
635  | 	int rolenum, racenum;
636  | {
637  | 	int i, n = 0;
638  | 
639  | 	/* Count the number of valid genders */
640  | 	for (i = 0; i < ROLE_GENDERS; i++)
641  | 	    if (roles[rolenum].allow & races[racenum].allow &
642  | 	    		genders[i].allow & ROLE_GENDMASK)
643  | 	    	n++;
644  | 
645  | 	/* Pick a random gender */
646  | 	if (n) n = rn2(n);
647  | 	for (i = 0; i < ROLE_GENDERS; i++)
648  | 	    if (roles[rolenum].allow & races[racenum].allow &
649  | 	    		genders[i].allow & ROLE_GENDMASK) {
650  | 	    	if (n) n--;
651  | 	    	else return (i);
652  | 	    }
653  | 
654  | 	/* This role/race has no permitted genders? */
655  | 	return (rn2(ROLE_GENDERS));
656  | }
657  | 
658  | 
659  | int
660  | str2gend(str)
661  | 	char *str;
662  | {
663  | 	int i, len;
664  | 
665  | 	/* Is str valid? */
666  | 	if (!str || !str[0])
667  | 	    return ROLE_NONE;
668  | 
669  | 	/* Match as much of str as is provided */
670  | 	len = strlen(str);
671  | 	for (i = 0; i < ROLE_GENDERS; i++) {
672  | 	    /* Does it match the adjective? */
673  | 	    if (!strncmpi(str, genders[i].adj, len))
674  | 		return i;
675  | 	    /* Or the filecode? */
676  | 	    if (!strcmpi(str, genders[i].filecode))
677  | 		return i;
678  | 	}
679  | 	if ((len == 1 && (*str == '*' || *str == '@')) ||
680  | 		!strncmpi(str, randomstr, len))
681  | 	    return ROLE_RANDOM;
682  | 
683  | 	/* Couldn't find anything appropriate */
684  | 	return ROLE_NONE;
685  | }
686  | 
687  | 
688  | boolean
689  | validalign(rolenum, racenum, alignnum)
690  | 	int rolenum, racenum, alignnum;
691  | {
692  | 	/* Assumes validrole and validrace */
693  | 	return (alignnum >= 0 && alignnum < ROLE_ALIGNS &&
694  | 		(roles[rolenum].allow & races[racenum].allow &
695  | 		 aligns[alignnum].allow & ROLE_ALIGNMASK));
696  | }
697  | 
698  | 
699  | int
700  | randalign(rolenum, racenum)
701  | 	int rolenum, racenum;
702  | {
703  | 	int i, n = 0;
704  | 
705  | 	/* Count the number of valid alignments */
706  | 	for (i = 0; i < ROLE_ALIGNS; i++)
707  | 	    if (roles[rolenum].allow & races[racenum].allow &
708  | 	    		aligns[i].allow & ROLE_ALIGNMASK)
709  | 	    	n++;
710  | 
711  | 	/* Pick a random alignment */
712  | 	if (n) n = rn2(n);
713  | 	for (i = 0; i < ROLE_ALIGNS; i++)
714  | 	    if (roles[rolenum].allow & races[racenum].allow &
715  | 	    		aligns[i].allow & ROLE_ALIGNMASK) {
716  | 	    	if (n) n--;
717  | 	    	else return (i);
718  | 	    }
719  | 
720  | 	/* This role/race has no permitted alignments? */
721  | 	return (rn2(ROLE_ALIGNS));
722  | }
723  | 
724  | 
725  | int
726  | str2align(str)
727  | 	char *str;
728  | {
729  | 	int i, len;
730  | 
731  | 	/* Is str valid? */
732  | 	if (!str || !str[0])
733  | 	    return ROLE_NONE;
734  | 
735  | 	/* Match as much of str as is provided */
736  | 	len = strlen(str);
737  | 	for (i = 0; i < ROLE_ALIGNS; i++) {
738  | 	    /* Does it match the adjective? */
739  | 	    if (!strncmpi(str, aligns[i].adj, len))
740  | 		return i;
741  | 	    /* Or the filecode? */
742  | 	    if (!strcmpi(str, aligns[i].filecode))
743  | 		return i;
744  | 	}
745  | 	if ((len == 1 && (*str == '*' || *str == '@')) ||
746  | 		!strncmpi(str, randomstr, len))
747  | 	    return ROLE_RANDOM;
748  | 
749  | 	/* Couldn't find anything appropriate */
750  | 	return ROLE_NONE;
751  | }
752  | 
753  | /* is rolenum compatible with any racenum/gendnum/alignnum constraints? */
754  | boolean
755  | ok_role(rolenum, racenum, gendnum, alignnum)
756  | int rolenum, racenum, gendnum, alignnum;
757  | {
758  |     int i;
759  |     short allow;
760  | 
761  |     if (rolenum >= 0 && rolenum < SIZE(roles)-1) {
762  | 	allow = roles[rolenum].allow;
763  | 	if (racenum >= 0 && racenum < SIZE(races)-1 &&
764  | 		!(allow & races[racenum].allow & ROLE_RACEMASK))
765  | 	    return FALSE;
766  | 	if (gendnum >= 0 && gendnum < ROLE_GENDERS &&
767  | 		!(allow & genders[gendnum].allow & ROLE_GENDMASK))
768  | 	    return FALSE;
769  | 	if (alignnum >= 0 && alignnum < ROLE_ALIGNS &&
770  | 		!(allow & aligns[alignnum].allow & ROLE_ALIGNMASK))
771  | 	    return FALSE;
772  | 	return TRUE;
773  |     } else {
774  | 	for (i = 0; i < SIZE(roles)-1; i++) {
775  | 	    allow = roles[i].allow;
776  | 	    if (racenum >= 0 && racenum < SIZE(races)-1 &&
777  | 		    !(allow & races[racenum].allow & ROLE_RACEMASK))
778  | 		continue;
779  | 	    if (gendnum >= 0 && gendnum < ROLE_GENDERS &&
780  | 		    !(allow & genders[gendnum].allow & ROLE_GENDMASK))
781  | 		continue;
782  | 	    if (alignnum >= 0 && alignnum < ROLE_ALIGNS &&
783  | 		    !(allow & aligns[alignnum].allow & ROLE_ALIGNMASK))
784  | 		continue;
785  | 	    return TRUE;
786  | 	}
787  | 	return FALSE;
788  |     }
789  | }
790  | 
791  | /* pick a random role subject to any racenum/gendnum/alignnum constraints */
792  | int
793  | pick_role(racenum, gendnum, alignnum)
794  | int racenum, gendnum, alignnum;
795  | {
796  |     int i;
797  |     int roles_ok = 0;
798  | 
799  |     for (i = 0; i < SIZE(roles)-1; i++) {
800  | 	if (ok_role(i, racenum, gendnum, alignnum))
801  | 	    roles_ok++;
802  |     }
803  |     if (roles_ok == 0)
804  | 	return ROLE_NONE;
805  |     roles_ok = rn2(roles_ok);
806  |     for (i = 0; i < SIZE(roles)-1; i++) {
807  | 	if (ok_role(i, racenum, gendnum, alignnum)) {
808  | 	    if (roles_ok == 0)
809  | 		return i;
810  | 	    else
811  | 		roles_ok--;
812  | 	}
813  |     }
814  |     return ROLE_NONE;
815  | }
816  | 
817  | /* is racenum compatible with any rolenum/gendnum/alignnum constraints? */
818  | boolean
819  | ok_race(rolenum, racenum, gendnum, alignnum)
820  | int rolenum, racenum, gendnum, alignnum;
821  | {
822  |     int i;
823  |     short allow;
824  | 
825  |     if (racenum >= 0 && racenum < SIZE(races)-1) {
826  | 	allow = races[racenum].allow;
827  | 	if (rolenum >= 0 && rolenum < SIZE(roles)-1 &&
828  | 		!(allow & roles[rolenum].allow & ROLE_RACEMASK))
829  | 	    return FALSE;
830  | 	if (gendnum >= 0 && gendnum < ROLE_GENDERS &&
831  | 		!(allow & genders[gendnum].allow & ROLE_GENDMASK))
832  | 	    return FALSE;
833  | 	if (alignnum >= 0 && alignnum < ROLE_ALIGNS &&
834  | 		!(allow & aligns[alignnum].allow & ROLE_ALIGNMASK))
835  | 	    return FALSE;
836  | 	return TRUE;
837  |     } else {
838  | 	for (i = 0; i < SIZE(races)-1; i++) {
839  | 	    allow = races[i].allow;
840  | 	    if (rolenum >= 0 && rolenum < SIZE(roles)-1 &&
841  | 		    !(allow & roles[rolenum].allow & ROLE_RACEMASK))
842  | 		continue;
843  | 	    if (gendnum >= 0 && gendnum < ROLE_GENDERS &&
844  | 		    !(allow & genders[gendnum].allow & ROLE_GENDMASK))
845  | 		continue;
846  | 	    if (alignnum >= 0 && alignnum < ROLE_ALIGNS &&
847  | 		    !(allow & aligns[alignnum].allow & ROLE_ALIGNMASK))
848  | 		continue;
849  | 	    return TRUE;
850  | 	}
851  | 	return FALSE;
852  |     }
853  | }
854  | 
855  | /* pick a random race subject to any rolenum/gendnum/alignnum constraints */
856  | int
857  | pick_race(rolenum, gendnum, alignnum)
858  | int rolenum, gendnum, alignnum;
859  | {
860  |     int i;
861  |     int races_ok = 0;
862  | 
863  |     for (i = 0; i < SIZE(races)-1; i++) {
864  | 	if (ok_race(rolenum, i, gendnum, alignnum))
865  | 	    races_ok++;
866  |     }
867  |     if (races_ok == 0)
868  | 	return ROLE_NONE;
869  |     races_ok = rn2(races_ok);
870  |     for (i = 0; i < SIZE(races)-1; i++) {
871  | 	if (ok_race(rolenum, i, gendnum, alignnum)) {
872  | 	    if (races_ok == 0)
873  | 		return i;
874  | 	    else
875  | 		races_ok--;
876  | 	}
877  |     }
878  |     return ROLE_NONE;
879  | }
880  | 
881  | /* is gendnum compatible with any rolenum/racenum/alignnum constraints? */
882  | /* gender and alignment are not comparable (and also not constrainable) */
883  | boolean
884  | ok_gend(rolenum, racenum, gendnum, alignnum)
885  | int rolenum, racenum, gendnum, alignnum;
886  | {
887  |     int i;
888  |     short allow;
889  | 
890  |     if (gendnum >= 0 && gendnum < ROLE_GENDERS) {
891  | 	allow = genders[gendnum].allow;
892  | 	if (rolenum >= 0 && rolenum < SIZE(roles)-1 &&
893  | 		!(allow & roles[rolenum].allow & ROLE_GENDMASK))
894  | 	    return FALSE;
895  | 	if (racenum >= 0 && racenum < SIZE(races)-1 &&
896  | 		!(allow & races[racenum].allow & ROLE_GENDMASK))
897  | 	    return FALSE;
898  | 	return TRUE;
899  |     } else {
900  | 	for (i = 0; i < ROLE_GENDERS; i++) {
901  | 	    allow = genders[i].allow;
902  | 	    if (rolenum >= 0 && rolenum < SIZE(roles)-1 &&
903  | 		    !(allow & roles[rolenum].allow & ROLE_GENDMASK))
904  | 		continue;
905  | 	    if (racenum >= 0 && racenum < SIZE(races)-1 &&
906  | 		    !(allow & races[racenum].allow & ROLE_GENDMASK))
907  | 		continue;
908  | 	    return TRUE;
909  | 	}
910  | 	return FALSE;
911  |     }
912  | }
913  | 
914  | /* pick a random gender subject to any rolenum/racenum/alignnum constraints */
915  | /* gender and alignment are not comparable (and also not constrainable) */
916  | int
917  | pick_gend(rolenum, racenum, alignnum)
918  | int rolenum, racenum, alignnum;
919  | {
920  |     int i;
921  |     int gends_ok = 0;
922  | 
923  |     for (i = 0; i < ROLE_GENDERS; i++) {
924  | 	if (ok_gend(rolenum, racenum, i, alignnum))
925  | 	    gends_ok++;
926  |     }
927  |     if (gends_ok == 0)
928  | 	return ROLE_NONE;
929  |     gends_ok = rn2(gends_ok);
930  |     for (i = 0; i < ROLE_GENDERS; i++) {
931  | 	if (ok_gend(rolenum, racenum, i, alignnum)) {
932  | 	    if (gends_ok == 0)
933  | 		return i;
934  | 	    else
935  | 		gends_ok--;
936  | 	}
937  |     }
938  |     return ROLE_NONE;
939  | }
940  | 
941  | /* is alignnum compatible with any rolenum/racenum/gendnum constraints? */
942  | /* alignment and gender are not comparable (and also not constrainable) */
943  | boolean
944  | ok_align(rolenum, racenum, gendnum, alignnum)
945  | int rolenum, racenum, gendnum, alignnum;
946  | {
947  |     int i;
948  |     short allow;
949  | 
950  |     if (alignnum >= 0 && alignnum < ROLE_ALIGNS) {
951  | 	allow = aligns[alignnum].allow;
952  | 	if (rolenum >= 0 && rolenum < SIZE(roles)-1 &&
953  | 		!(allow & roles[rolenum].allow & ROLE_ALIGNMASK))
954  | 	    return FALSE;
955  | 	if (racenum >= 0 && racenum < SIZE(races)-1 &&
956  | 		!(allow & races[racenum].allow & ROLE_ALIGNMASK))
957  | 	    return FALSE;
958  | 	return TRUE;
959  |     } else {
960  | 	for (i = 0; i < ROLE_ALIGNS; i++) {
961  | 	    allow = races[i].allow;
962  | 	    if (rolenum >= 0 && rolenum < SIZE(roles)-1 &&
963  | 		    !(allow & roles[rolenum].allow & ROLE_ALIGNMASK))
964  | 		continue;
965  | 	    if (racenum >= 0 && racenum < SIZE(races)-1 &&
966  | 		    !(allow & races[racenum].allow & ROLE_ALIGNMASK))
967  | 		continue;
968  | 	    return TRUE;
969  | 	}
970  | 	return FALSE;
971  |     }
972  | }
973  | 
974  | /* pick a random alignment subject to any rolenum/racenum/gendnum constraints */
975  | /* alignment and gender are not comparable (and also not constrainable) */
976  | int
977  | pick_align(rolenum, racenum, gendnum)
978  | int rolenum, racenum, gendnum;
979  | {
980  |     int i;
981  |     int aligns_ok = 0;
982  | 
983  |     for (i = 0; i < ROLE_ALIGNS; i++) {
984  | 	if (ok_align(rolenum, racenum, gendnum, i))
985  | 	    aligns_ok++;
986  |     }
987  |     if (aligns_ok == 0)
988  | 	return ROLE_NONE;
989  |     aligns_ok = rn2(aligns_ok);
990  |     for (i = 0; i < ROLE_ALIGNS; i++) {
991  | 	if (ok_align(rolenum, racenum, gendnum, i)) {
992  | 	    if (aligns_ok == 0)
993  | 		return i;
994  | 	    else
995  | 		aligns_ok--;
996  | 	}
997  |     }
998  |     return ROLE_NONE;
999  | }
1000 | 
1001 | 
1002 | void
1003 | plnamesuffix()
1004 | {
1005 | 	char *sptr, *eptr;
1006 | 	int i;
1007 | 
1008 | 	/* Look for tokens delimited by '-' */
1009 | 	if ((eptr = index(plname, '-')) != (char *) 0)
1010 | 	    *eptr++ = '\0';
1011 | 	while (eptr) {
1012 | 	    /* Isolate the next token */
1013 | 	    sptr = eptr;
1014 | 	    if ((eptr = index(sptr, '-')) != (char *)0)
1015 | 		*eptr++ = '\0';
1016 | 
1017 | 	    /* Try to match it to something */
1018 | 	    if ((i = str2role(sptr)) != ROLE_NONE)
1019 | 		flags.initrole = i;
1020 | 	    else if ((i = str2race(sptr)) != ROLE_NONE)
1021 | 		flags.initrace = i;
1022 | 	    else if ((i = str2gend(sptr)) != ROLE_NONE)
1023 | 		flags.initgend = i;
1024 | 	    else if ((i = str2align(sptr)) != ROLE_NONE)
1025 | 		flags.initalign = i;
1026 | 	}
1027 | 	if(!plname[0]) {
1028 | 	    askname();
1029 | 	    plnamesuffix();
1030 | 	}
1031 | 
1032 | 	/* commas in the plname confuse the record file, convert to spaces */
1033 | 	for (sptr = plname; *sptr; sptr++) {
1034 | 		if (*sptr == ',') *sptr = ' ';
1035 | 	}
1036 | }
1037 | 
1038 | 
1039 | /*
1040 |  *	Special setup modifications here:
1041 |  *
1042 |  *	Unfortunately, this is going to have to be done
1043 |  *	on each newgame or restore, because you lose the permonst mods
1044 |  *	across a save/restore.  :-)
1045 |  *
1046 |  *	1 - The Rogue Leader is the Tourist Nemesis.
1047 |  *	2 - Priests start with a random alignment - convert the leader and
1048 |  *	    guardians here.
1049 |  *	3 - Elves can have one of two different leaders, but can't work it
1050 |  *	    out here because it requires hacking the level file data (see
1051 |  *	    sp_lev.c).
1052 |  *
1053 |  * This code also replaces quest_init().
1054 |  */
1055 | void
1056 | role_init()
1057 | {
1058 | 	int alignmnt;
1059 | 
1060 | 	/* Strip the role letter out of the player name.
1061 | 	 * This is included for backwards compatibility.
1062 | 	 */
1063 | 	plnamesuffix();
1064 | 
1065 | 	/* Check for a valid role.  Try flags.initrole first. */
1066 | 	if (!validrole(flags.initrole)) {
1067 | 	    /* Try the player letter second */
1068 | 	    if ((flags.initrole = str2role(pl_character)) < 0)
1069 | 	    	/* None specified; pick a random role */
1070 | 	    	flags.initrole = randrole();
1071 | 	}
1072 | 
1073 | 	/* We now have a valid role index.  Copy the role name back. */
1074 | 	/* This should become OBSOLETE */
1075 | 	Strcpy(pl_character, roles[flags.initrole].name.m);
1076 | 	pl_character[PL_CSIZ-1] = '\0';
1077 | 
1078 | 	/* Check for a valid race */
1079 | 	if (!validrace(flags.initrole, flags.initrace))
1080 | 	    flags.initrace = randrace(flags.initrole);
1081 | 
1082 | 	/* Check for a valid gender.  Try flags.igend first. */
1083 | 	if (!validgend(flags.initrole, flags.initrace, flags.initgend))
1084 | 	    /* Use flags.female second.  Note that there is no way
1085 | 	     * to check for an unspecified gender.
1086 | 	     */
1087 | 	    flags.initgend = flags.female;
1088 | 	/* Don't change flags.female; this may be a restore */
1089 | 
1090 | 	/* Check for a valid alignment */
1091 | 	if (!validalign(flags.initrole, flags.initrace, flags.initalign))
1092 | 	    /* Pick a random alignment */
1093 | 	    flags.initalign = randalign(flags.initrole, flags.initrace);
1094 | 	alignmnt = aligns[flags.initalign].value;
1095 | 
1096 | 	/* Initialize urole and urace */
1097 | 	urole = roles[flags.initrole];
1098 | 	urace = races[flags.initrace];
1099 | 
1100 | 	/* Fix up the quest leader */
1101 | 	if (urole.ldrnum != NON_PM) {
1102 | 	    mons[urole.ldrnum].msound = MS_LEADER;
1103 | 	    mons[urole.ldrnum].mflags2 |= (M2_PEACEFUL);
1104 | 	    mons[urole.ldrnum].mflags3 |= M3_CLOSE;
1105 | 	    mons[urole.ldrnum].maligntyp = alignmnt * 3;
1106 | 	}
1107 | 
1108 | 	/* Fix up the quest guardians */
1109 | 	if (urole.guardnum != NON_PM) {
1110 | 	    mons[urole.guardnum].mflags2 |= (M2_PEACEFUL);
1111 | 	    mons[urole.guardnum].maligntyp = alignmnt * 3;
1112 | 	}
1113 | 
1114 | 	/* Fix up the quest nemesis */
1115 | 	if (urole.neminum != NON_PM) {
1116 | 	    mons[urole.neminum].msound = MS_NEMESIS;
1117 | 	    mons[urole.neminum].mflags2 &= ~(M2_PEACEFUL);
1118 | 	    mons[urole.neminum].mflags2 |= (M2_NASTY|M2_STALK|M2_HOSTILE);
1119 | 	    mons[urole.neminum].mflags3 |= M3_WANTSARTI | M3_WAITFORU;
1120 | 	}
1121 | 
1122 | 	/* Fix up the god names */
1123 | 	if (flags.pantheon == -1) {		/* new game */
1124 | 	    flags.pantheon = flags.initrole;	/* use own gods */
1125 | 	    while (!roles[flags.pantheon].lgod)	/* unless they're missing */
1126 | 		flags.pantheon = randrole();
1127 | 	}
1128 | 	if (!urole.lgod) {
1129 | 	    urole.lgod = roles[flags.pantheon].lgod;
1130 | 	    urole.ngod = roles[flags.pantheon].ngod;
1131 | 	    urole.cgod = roles[flags.pantheon].cgod;
1132 | 	}
1133 | 
1134 | 	/* Fix up infravision */
1135 | 	if (mons[urace.malenum].mflags3 & M3_INFRAVISION) {
1136 | 	    /* although an infravision intrinsic is possible, infravision
1137 | 	     * is purely a property of the physical race.  This means that we
1138 | 	     * must put the infravision flag in the player's current race
1139 | 	     * (either that or have separate permonst entries for
1140 | 	     * elven/non-elven members of each class).  The side effect is that
1141 | 	     * all NPCs of that class will have (probably bogus) infravision,
1142 | 	     * but since infravision has no effect for NPCs anyway we can
1143 | 	     * ignore this.
1144 | 	     */
1145 | 	    mons[urole.malenum].mflags3 |= M3_INFRAVISION;
1146 | 	    if (urole.femalenum != NON_PM)
1147 | 	    	mons[urole.femalenum].mflags3 |= M3_INFRAVISION;
1148 | 	}
1149 | 
1150 | 	/* Artifacts are fixed in hack_artifacts() */
1151 | 
1152 | 	/* Success! */
1153 | 	return;
1154 | }
1155 | 
1156 | const char *
1157 | Hello(mtmp)
1158 | struct monst *mtmp;
1159 | {
1160 | 	switch (Role_switch) {
1161 | 	case PM_KNIGHT:
1162 | 	    return ("Salutations"); /* Olde English */
1163 | 	case PM_SAMURAI:
1164 | 	    return (mtmp && mtmp->data == &mons[PM_SHOPKEEPER] ?
1165 | 	    		"Irasshaimase" : "Konnichi wa"); /* Japanese */
1166 | #ifdef TOURIST
1167 | 	case PM_TOURIST:
1168 | 	    return ("Aloha");       /* Hawaiian */
1169 | #endif
1170 | 	case PM_VALKYRIE:
1171 | 	    return (
1172 | #ifdef MAIL
1173 | 	    		mtmp && mtmp->data == &mons[PM_MAIL_DAEMON] ? "Hallo" :
1174 | #endif
1175 | 	    		"Velkommen");   /* Norse */
1176 | 	default:
1177 | 	    return ("Hello");
1178 | 	}
1179 | }
1180 | 
1181 | const char *
1182 | Goodbye()
1183 | {
1184 | 	switch (Role_switch) {
1185 | 	case PM_KNIGHT:
1186 | 	    return ("Fare thee well");  /* Olde English */
1187 | 	case PM_SAMURAI:
1188 | 	    return ("Sayonara");        /* Japanese */
1189 | #ifdef TOURIST
1190 | 	case PM_TOURIST:
1191 | 	    return ("Aloha");           /* Hawaiian */
1192 | #endif
1193 | 	case PM_VALKYRIE:
1194 | 	    return ("Farvel");          /* Norse */
1195 | 	default:
1196 | 	    return ("Goodbye");
1197 | 	}
1198 | }
1199 | 
1200 | /* role.c */