1 /*	SCCS Id: @(#)role.c	3.4	2003/01/08	*/
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 	{"Medicus ossium", "Medica ossium"},
112 	{"Herbalist",      0},
113 	{"Magister",       "Magistra"},
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, 5 },
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",   "Chevaliere"},
139 	{"Seignieur",   "Dame"},
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 	{  30, 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",       "Kunoichi"},  /* 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,  8, 30, 14,  8 },
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 Lonely Tower", "the Tower of Darkness",
366 	PM_WIZARD, NON_PM, PM_KITTEN,
367 	PM_NEFERET_THE_GREEN, 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 STATIC_DCL char * FDECL(promptsep, (char *, int));
506 STATIC_DCL int FDECL(role_gendercount, (int));
507 STATIC_DCL int FDECL(race_alignmentcount, (int));
508 
509 /* used by str2XXX() */
510 static char NEARDATA randomstr[] = "random";
511 
512 
513 boolean
validrole(rolenum)514 validrole(rolenum)
515 	int rolenum;
516 {
517 	return (rolenum >= 0 && rolenum < SIZE(roles)-1);
518 }
519 
520 
521 int
randrole()522 randrole()
523 {
524 	return (rn2(SIZE(roles)-1));
525 }
526 
527 
528 int
str2role(str)529 str2role(str)
530 	char *str;
531 {
532 	int i, len;
533 
534 	/* Is str valid? */
535 	if (!str || !str[0])
536 	    return ROLE_NONE;
537 
538 	/* Match as much of str as is provided */
539 	len = strlen(str);
540 	for (i = 0; roles[i].name.m; i++) {
541 	    /* Does it match the male name? */
542 	    if (!strncmpi(str, roles[i].name.m, len))
543 		return i;
544 	    /* Or the female name? */
545 	    if (roles[i].name.f && !strncmpi(str, roles[i].name.f, len))
546 		return i;
547 	    /* Or the filecode? */
548 	    if (!strcmpi(str, roles[i].filecode))
549 		return i;
550 	}
551 
552 	if ((len == 1 && (*str == '*' || *str == '@')) ||
553 		!strncmpi(str, randomstr, len))
554 	    return ROLE_RANDOM;
555 
556 	/* Couldn't find anything appropriate */
557 	return ROLE_NONE;
558 }
559 
560 
561 boolean
validrace(rolenum,racenum)562 validrace(rolenum, racenum)
563 	int rolenum, racenum;
564 {
565 	/* Assumes validrole */
566 	return (racenum >= 0 && racenum < SIZE(races)-1 &&
567 		(roles[rolenum].allow & races[racenum].allow & ROLE_RACEMASK));
568 }
569 
570 
571 int
randrace(rolenum)572 randrace(rolenum)
573 	int rolenum;
574 {
575 	int i, n = 0;
576 
577 	/* Count the number of valid races */
578 	for (i = 0; races[i].noun; i++)
579 	    if (roles[rolenum].allow & races[i].allow & ROLE_RACEMASK)
580 	    	n++;
581 
582 	/* Pick a random race */
583 	/* Use a factor of 100 in case of bad random number generators */
584 	if (n) n = rn2(n*100)/100;
585 	for (i = 0; races[i].noun; i++)
586 	    if (roles[rolenum].allow & races[i].allow & ROLE_RACEMASK) {
587 	    	if (n) n--;
588 	    	else return (i);
589 	    }
590 
591 	/* This role has no permitted races? */
592 	return (rn2(SIZE(races)-1));
593 }
594 
595 
596 int
str2race(str)597 str2race(str)
598 	char *str;
599 {
600 	int i, len;
601 
602 	/* Is str valid? */
603 	if (!str || !str[0])
604 	    return ROLE_NONE;
605 
606 	/* Match as much of str as is provided */
607 	len = strlen(str);
608 	for (i = 0; races[i].noun; i++) {
609 	    /* Does it match the noun? */
610 	    if (!strncmpi(str, races[i].noun, len))
611 		return i;
612 	    /* Or the filecode? */
613 	    if (!strcmpi(str, races[i].filecode))
614 		return i;
615 	}
616 
617 	if ((len == 1 && (*str == '*' || *str == '@')) ||
618 		!strncmpi(str, randomstr, len))
619 	    return ROLE_RANDOM;
620 
621 	/* Couldn't find anything appropriate */
622 	return ROLE_NONE;
623 }
624 
625 
626 boolean
validgend(rolenum,racenum,gendnum)627 validgend(rolenum, racenum, gendnum)
628 	int rolenum, racenum, gendnum;
629 {
630 	/* Assumes validrole and validrace */
631 	return (gendnum >= 0 && gendnum < ROLE_GENDERS &&
632 		(roles[rolenum].allow & races[racenum].allow &
633 		 genders[gendnum].allow & ROLE_GENDMASK));
634 }
635 
636 
637 int
randgend(rolenum,racenum)638 randgend(rolenum, racenum)
639 	int rolenum, racenum;
640 {
641 	int i, n = 0;
642 
643 	/* Count the number of valid genders */
644 	for (i = 0; i < ROLE_GENDERS; i++)
645 	    if (roles[rolenum].allow & races[racenum].allow &
646 	    		genders[i].allow & ROLE_GENDMASK)
647 	    	n++;
648 
649 	/* Pick a random gender */
650 	if (n) n = rn2(n);
651 	for (i = 0; i < ROLE_GENDERS; i++)
652 	    if (roles[rolenum].allow & races[racenum].allow &
653 	    		genders[i].allow & ROLE_GENDMASK) {
654 	    	if (n) n--;
655 	    	else return (i);
656 	    }
657 
658 	/* This role/race has no permitted genders? */
659 	return (rn2(ROLE_GENDERS));
660 }
661 
662 
663 int
str2gend(str)664 str2gend(str)
665 	char *str;
666 {
667 	int i, len;
668 
669 	/* Is str valid? */
670 	if (!str || !str[0])
671 	    return ROLE_NONE;
672 
673 	/* Match as much of str as is provided */
674 	len = strlen(str);
675 	for (i = 0; i < ROLE_GENDERS; i++) {
676 	    /* Does it match the adjective? */
677 	    if (!strncmpi(str, genders[i].adj, len))
678 		return i;
679 	    /* Or the filecode? */
680 	    if (!strcmpi(str, genders[i].filecode))
681 		return i;
682 	}
683 	if ((len == 1 && (*str == '*' || *str == '@')) ||
684 		!strncmpi(str, randomstr, len))
685 	    return ROLE_RANDOM;
686 
687 	/* Couldn't find anything appropriate */
688 	return ROLE_NONE;
689 }
690 
691 
692 boolean
validalign(rolenum,racenum,alignnum)693 validalign(rolenum, racenum, alignnum)
694 	int rolenum, racenum, alignnum;
695 {
696 	/* Assumes validrole and validrace */
697 	return (alignnum >= 0 && alignnum < ROLE_ALIGNS &&
698 		(roles[rolenum].allow & races[racenum].allow &
699 		 aligns[alignnum].allow & ROLE_ALIGNMASK));
700 }
701 
702 
703 int
randalign(rolenum,racenum)704 randalign(rolenum, racenum)
705 	int rolenum, racenum;
706 {
707 	int i, n = 0;
708 
709 	/* Count the number of valid alignments */
710 	for (i = 0; i < ROLE_ALIGNS; i++)
711 	    if (roles[rolenum].allow & races[racenum].allow &
712 	    		aligns[i].allow & ROLE_ALIGNMASK)
713 	    	n++;
714 
715 	/* Pick a random alignment */
716 	if (n) n = rn2(n);
717 	for (i = 0; i < ROLE_ALIGNS; i++)
718 	    if (roles[rolenum].allow & races[racenum].allow &
719 	    		aligns[i].allow & ROLE_ALIGNMASK) {
720 	    	if (n) n--;
721 	    	else return (i);
722 	    }
723 
724 	/* This role/race has no permitted alignments? */
725 	return (rn2(ROLE_ALIGNS));
726 }
727 
728 
729 int
str2align(str)730 str2align(str)
731 	char *str;
732 {
733 	int i, len;
734 
735 	/* Is str valid? */
736 	if (!str || !str[0])
737 	    return ROLE_NONE;
738 
739 	/* Match as much of str as is provided */
740 	len = strlen(str);
741 	for (i = 0; i < ROLE_ALIGNS; i++) {
742 	    /* Does it match the adjective? */
743 	    if (!strncmpi(str, aligns[i].adj, len))
744 		return i;
745 	    /* Or the filecode? */
746 	    if (!strcmpi(str, aligns[i].filecode))
747 		return i;
748 	}
749 	if ((len == 1 && (*str == '*' || *str == '@')) ||
750 		!strncmpi(str, randomstr, len))
751 	    return ROLE_RANDOM;
752 
753 	/* Couldn't find anything appropriate */
754 	return ROLE_NONE;
755 }
756 
757 /* is rolenum compatible with any racenum/gendnum/alignnum constraints? */
758 boolean
ok_role(rolenum,racenum,gendnum,alignnum)759 ok_role(rolenum, racenum, gendnum, alignnum)
760 int rolenum, racenum, gendnum, alignnum;
761 {
762     int i;
763     short allow;
764 
765     if (rolenum >= 0 && rolenum < SIZE(roles)-1) {
766 	allow = roles[rolenum].allow;
767 	if (racenum >= 0 && racenum < SIZE(races)-1 &&
768 		!(allow & races[racenum].allow & ROLE_RACEMASK))
769 	    return FALSE;
770 	if (gendnum >= 0 && gendnum < ROLE_GENDERS &&
771 		!(allow & genders[gendnum].allow & ROLE_GENDMASK))
772 	    return FALSE;
773 	if (alignnum >= 0 && alignnum < ROLE_ALIGNS &&
774 		!(allow & aligns[alignnum].allow & ROLE_ALIGNMASK))
775 	    return FALSE;
776 	return TRUE;
777     } else {
778 	for (i = 0; i < SIZE(roles)-1; i++) {
779 	    allow = roles[i].allow;
780 	    if (racenum >= 0 && racenum < SIZE(races)-1 &&
781 		    !(allow & races[racenum].allow & ROLE_RACEMASK))
782 		continue;
783 	    if (gendnum >= 0 && gendnum < ROLE_GENDERS &&
784 		    !(allow & genders[gendnum].allow & ROLE_GENDMASK))
785 		continue;
786 	    if (alignnum >= 0 && alignnum < ROLE_ALIGNS &&
787 		    !(allow & aligns[alignnum].allow & ROLE_ALIGNMASK))
788 		continue;
789 	    return TRUE;
790 	}
791 	return FALSE;
792     }
793 }
794 
795 /* pick a random role subject to any racenum/gendnum/alignnum constraints */
796 /* If pickhow == PICK_RIGID a role is returned only if there is  */
797 /* a single possibility */
798 int
pick_role(racenum,gendnum,alignnum,pickhow)799 pick_role(racenum, gendnum, alignnum, pickhow)
800 int racenum, gendnum, alignnum, pickhow;
801 {
802     int i;
803     int roles_ok = 0;
804 
805     for (i = 0; i < SIZE(roles)-1; i++) {
806 	if (ok_role(i, racenum, gendnum, alignnum))
807 	    roles_ok++;
808     }
809     if (roles_ok == 0 || (roles_ok > 1 && pickhow == PICK_RIGID))
810 	return ROLE_NONE;
811     roles_ok = rn2(roles_ok);
812     for (i = 0; i < SIZE(roles)-1; i++) {
813 	if (ok_role(i, racenum, gendnum, alignnum)) {
814 	    if (roles_ok == 0)
815 		return i;
816 	    else
817 		roles_ok--;
818 	}
819     }
820     return ROLE_NONE;
821 }
822 
823 /* is racenum compatible with any rolenum/gendnum/alignnum constraints? */
824 boolean
ok_race(rolenum,racenum,gendnum,alignnum)825 ok_race(rolenum, racenum, gendnum, alignnum)
826 int rolenum, racenum, gendnum, alignnum;
827 {
828     int i;
829     short allow;
830 
831     if (racenum >= 0 && racenum < SIZE(races)-1) {
832 	allow = races[racenum].allow;
833 	if (rolenum >= 0 && rolenum < SIZE(roles)-1 &&
834 		!(allow & roles[rolenum].allow & ROLE_RACEMASK))
835 	    return FALSE;
836 	if (gendnum >= 0 && gendnum < ROLE_GENDERS &&
837 		!(allow & genders[gendnum].allow & ROLE_GENDMASK))
838 	    return FALSE;
839 	if (alignnum >= 0 && alignnum < ROLE_ALIGNS &&
840 		!(allow & aligns[alignnum].allow & ROLE_ALIGNMASK))
841 	    return FALSE;
842 	return TRUE;
843     } else {
844 	for (i = 0; i < SIZE(races)-1; i++) {
845 	    allow = races[i].allow;
846 	    if (rolenum >= 0 && rolenum < SIZE(roles)-1 &&
847 		    !(allow & roles[rolenum].allow & ROLE_RACEMASK))
848 		continue;
849 	    if (gendnum >= 0 && gendnum < ROLE_GENDERS &&
850 		    !(allow & genders[gendnum].allow & ROLE_GENDMASK))
851 		continue;
852 	    if (alignnum >= 0 && alignnum < ROLE_ALIGNS &&
853 		    !(allow & aligns[alignnum].allow & ROLE_ALIGNMASK))
854 		continue;
855 	    return TRUE;
856 	}
857 	return FALSE;
858     }
859 }
860 
861 /* pick a random race subject to any rolenum/gendnum/alignnum constraints */
862 /* If pickhow == PICK_RIGID a race is returned only if there is  */
863 /* a single possibility */
864 int
pick_race(rolenum,gendnum,alignnum,pickhow)865 pick_race(rolenum, gendnum, alignnum, pickhow)
866 int rolenum, gendnum, alignnum, pickhow;
867 {
868     int i;
869     int races_ok = 0;
870 
871     for (i = 0; i < SIZE(races)-1; i++) {
872 	if (ok_race(rolenum, i, gendnum, alignnum))
873 	    races_ok++;
874     }
875     if (races_ok == 0 || (races_ok > 1 && pickhow == PICK_RIGID))
876 	return ROLE_NONE;
877     races_ok = rn2(races_ok);
878     for (i = 0; i < SIZE(races)-1; i++) {
879 	if (ok_race(rolenum, i, gendnum, alignnum)) {
880 	    if (races_ok == 0)
881 		return i;
882 	    else
883 		races_ok--;
884 	}
885     }
886     return ROLE_NONE;
887 }
888 
889 /* is gendnum compatible with any rolenum/racenum/alignnum constraints? */
890 /* gender and alignment are not comparable (and also not constrainable) */
891 boolean
ok_gend(rolenum,racenum,gendnum,alignnum)892 ok_gend(rolenum, racenum, gendnum, alignnum)
893 int rolenum, racenum, gendnum, alignnum;
894 {
895     int i;
896     short allow;
897 
898     if (gendnum >= 0 && gendnum < ROLE_GENDERS) {
899 	allow = genders[gendnum].allow;
900 	if (rolenum >= 0 && rolenum < SIZE(roles)-1 &&
901 		!(allow & roles[rolenum].allow & ROLE_GENDMASK))
902 	    return FALSE;
903 	if (racenum >= 0 && racenum < SIZE(races)-1 &&
904 		!(allow & races[racenum].allow & ROLE_GENDMASK))
905 	    return FALSE;
906 	return TRUE;
907     } else {
908 	for (i = 0; i < ROLE_GENDERS; i++) {
909 	    allow = genders[i].allow;
910 	    if (rolenum >= 0 && rolenum < SIZE(roles)-1 &&
911 		    !(allow & roles[rolenum].allow & ROLE_GENDMASK))
912 		continue;
913 	    if (racenum >= 0 && racenum < SIZE(races)-1 &&
914 		    !(allow & races[racenum].allow & ROLE_GENDMASK))
915 		continue;
916 	    return TRUE;
917 	}
918 	return FALSE;
919     }
920 }
921 
922 /* pick a random gender subject to any rolenum/racenum/alignnum constraints */
923 /* gender and alignment are not comparable (and also not constrainable) */
924 /* If pickhow == PICK_RIGID a gender is returned only if there is  */
925 /* a single possibility */
926 int
pick_gend(rolenum,racenum,alignnum,pickhow)927 pick_gend(rolenum, racenum, alignnum, pickhow)
928 int rolenum, racenum, alignnum, pickhow;
929 {
930     int i;
931     int gends_ok = 0;
932 
933     for (i = 0; i < ROLE_GENDERS; i++) {
934 	if (ok_gend(rolenum, racenum, i, alignnum))
935 	    gends_ok++;
936     }
937     if (gends_ok == 0 || (gends_ok > 1 && pickhow == PICK_RIGID))
938 	return ROLE_NONE;
939     gends_ok = rn2(gends_ok);
940     for (i = 0; i < ROLE_GENDERS; i++) {
941 	if (ok_gend(rolenum, racenum, i, alignnum)) {
942 	    if (gends_ok == 0)
943 		return i;
944 	    else
945 		gends_ok--;
946 	}
947     }
948     return ROLE_NONE;
949 }
950 
951 /* is alignnum compatible with any rolenum/racenum/gendnum constraints? */
952 /* alignment and gender are not comparable (and also not constrainable) */
953 boolean
ok_align(rolenum,racenum,gendnum,alignnum)954 ok_align(rolenum, racenum, gendnum, alignnum)
955 int rolenum, racenum, gendnum, alignnum;
956 {
957     int i;
958     short allow;
959 
960     if (alignnum >= 0 && alignnum < ROLE_ALIGNS) {
961 	allow = aligns[alignnum].allow;
962 	if (rolenum >= 0 && rolenum < SIZE(roles)-1 &&
963 		!(allow & roles[rolenum].allow & ROLE_ALIGNMASK))
964 	    return FALSE;
965 	if (racenum >= 0 && racenum < SIZE(races)-1 &&
966 		!(allow & races[racenum].allow & ROLE_ALIGNMASK))
967 	    return FALSE;
968 	return TRUE;
969     } else {
970 	for (i = 0; i < ROLE_ALIGNS; i++) {
971 	    allow = races[i].allow;
972 	    if (rolenum >= 0 && rolenum < SIZE(roles)-1 &&
973 		    !(allow & roles[rolenum].allow & ROLE_ALIGNMASK))
974 		continue;
975 	    if (racenum >= 0 && racenum < SIZE(races)-1 &&
976 		    !(allow & races[racenum].allow & ROLE_ALIGNMASK))
977 		continue;
978 	    return TRUE;
979 	}
980 	return FALSE;
981     }
982 }
983 
984 /* pick a random alignment subject to any rolenum/racenum/gendnum constraints */
985 /* alignment and gender are not comparable (and also not constrainable) */
986 /* If pickhow == PICK_RIGID an alignment is returned only if there is  */
987 /* a single possibility */
988 int
pick_align(rolenum,racenum,gendnum,pickhow)989 pick_align(rolenum, racenum, gendnum, pickhow)
990 int rolenum, racenum, gendnum, pickhow;
991 {
992     int i;
993     int aligns_ok = 0;
994 
995     for (i = 0; i < ROLE_ALIGNS; i++) {
996 	if (ok_align(rolenum, racenum, gendnum, i))
997 	    aligns_ok++;
998     }
999     if (aligns_ok == 0 || (aligns_ok > 1 && pickhow == PICK_RIGID))
1000 	return ROLE_NONE;
1001     aligns_ok = rn2(aligns_ok);
1002     for (i = 0; i < ROLE_ALIGNS; i++) {
1003 	if (ok_align(rolenum, racenum, gendnum, i)) {
1004 	    if (aligns_ok == 0)
1005 		return i;
1006 	    else
1007 		aligns_ok--;
1008 	}
1009     }
1010     return ROLE_NONE;
1011 }
1012 
1013 void
rigid_role_checks()1014 rigid_role_checks()
1015 {
1016     /* Some roles are limited to a single race, alignment, or gender and
1017      * calling this routine prior to XXX_player_selection() will help
1018      * prevent an extraneous prompt that actually doesn't allow
1019      * you to choose anything further. Note the use of PICK_RIGID which
1020      * causes the pick_XX() routine to return a value only if there is one
1021      * single possible selection, otherwise it returns ROLE_NONE.
1022      *
1023      */
1024     if (flags.initrole == ROLE_RANDOM) {
1025 	/* If the role was explicitly specified as ROLE_RANDOM
1026 	 * via -uXXXX-@ then choose the role in here to narrow down
1027 	 * later choices. Pick a random role in this case.
1028 	 */
1029 	flags.initrole = pick_role(flags.initrace, flags.initgend,
1030 					flags.initalign, PICK_RANDOM);
1031 	if (flags.initrole < 0)
1032 	    flags.initrole = randrole();
1033     }
1034     if (flags.initrole != ROLE_NONE) {
1035 	if (flags.initrace == ROLE_NONE)
1036 	     flags.initrace = pick_race(flags.initrole, flags.initgend,
1037 						flags.initalign, PICK_RIGID);
1038 	if (flags.initalign == ROLE_NONE)
1039 	     flags.initalign = pick_align(flags.initrole, flags.initrace,
1040 						flags.initgend, PICK_RIGID);
1041 	if (flags.initgend == ROLE_NONE)
1042 	     flags.initgend = pick_gend(flags.initrole, flags.initrace,
1043 						flags.initalign, PICK_RIGID);
1044     }
1045 }
1046 
1047 #define BP_ALIGN	0
1048 #define BP_GEND		1
1049 #define BP_RACE		2
1050 #define BP_ROLE		3
1051 #define NUM_BP		4
1052 
1053 STATIC_VAR char pa[NUM_BP], post_attribs;
1054 
1055 STATIC_OVL char *
promptsep(buf,num_post_attribs)1056 promptsep(buf, num_post_attribs)
1057 char *buf;
1058 int num_post_attribs;
1059 {
1060 	const char *conj = "and ";
1061 	if (num_post_attribs > 1
1062 	    && post_attribs < num_post_attribs && post_attribs > 1)
1063 	 	Strcat(buf, ",");
1064 	Strcat(buf, " ");
1065 	--post_attribs;
1066 	if (!post_attribs && num_post_attribs > 1) Strcat(buf, conj);
1067 	return buf;
1068 }
1069 
1070 STATIC_OVL int
role_gendercount(rolenum)1071 role_gendercount(rolenum)
1072 int rolenum;
1073 {
1074 	int gendcount = 0;
1075 	if (validrole(rolenum)) {
1076 		if (roles[rolenum].allow & ROLE_MALE) ++gendcount;
1077 		if (roles[rolenum].allow & ROLE_FEMALE) ++gendcount;
1078 		if (roles[rolenum].allow & ROLE_NEUTER) ++gendcount;
1079 	}
1080 	return gendcount;
1081 }
1082 
1083 STATIC_OVL int
race_alignmentcount(racenum)1084 race_alignmentcount(racenum)
1085 int racenum;
1086 {
1087 	int aligncount = 0;
1088 	if (racenum != ROLE_NONE && racenum != ROLE_RANDOM) {
1089 		if (races[racenum].allow & ROLE_CHAOTIC) ++aligncount;
1090 		if (races[racenum].allow & ROLE_LAWFUL) ++aligncount;
1091 		if (races[racenum].allow & ROLE_NEUTRAL) ++aligncount;
1092 	}
1093 	return aligncount;
1094 }
1095 
1096 char *
root_plselection_prompt(suppliedbuf,buflen,rolenum,racenum,gendnum,alignnum)1097 root_plselection_prompt(suppliedbuf, buflen, rolenum, racenum, gendnum, alignnum)
1098 char *suppliedbuf;
1099 int buflen, rolenum, racenum, gendnum, alignnum;
1100 {
1101 	int k, gendercount = 0, aligncount = 0;
1102 	char buf[BUFSZ];
1103 	static char err_ret[] = " character's";
1104 	boolean donefirst = FALSE;
1105 
1106 	if (!suppliedbuf || buflen < 1) return err_ret;
1107 
1108 	/* initialize these static variables each time this is called */
1109 	post_attribs = 0;
1110 	for (k=0; k < NUM_BP; ++k)
1111 		pa[k] = 0;
1112 	buf[0] = '\0';
1113 	*suppliedbuf = '\0';
1114 
1115 	/* How many alignments are allowed for the desired race? */
1116 	if (racenum != ROLE_NONE && racenum != ROLE_RANDOM)
1117 		aligncount = race_alignmentcount(racenum);
1118 
1119 	if (alignnum != ROLE_NONE && alignnum != ROLE_RANDOM) {
1120 		/* if race specified, and multiple choice of alignments for it */
1121 		if ((racenum >= 0) && (aligncount > 1)) {
1122 			if (donefirst) Strcat(buf, " ");
1123 			Strcat(buf, aligns[alignnum].adj);
1124 			donefirst = TRUE;
1125 		} else {
1126 			if (donefirst) Strcat(buf, " ");
1127 			Strcat(buf, aligns[alignnum].adj);
1128 			donefirst = TRUE;
1129 		}
1130 	} else {
1131 		/* if alignment not specified, but race is specified
1132 			and only one choice of alignment for that race then
1133 			don't include it in the later list */
1134 		if ((((racenum != ROLE_NONE && racenum != ROLE_RANDOM) &&
1135 			ok_race(rolenum, racenum, gendnum, alignnum))
1136 		      && (aligncount > 1))
1137 		     || (racenum == ROLE_NONE || racenum == ROLE_RANDOM)) {
1138 			pa[BP_ALIGN] = 1;
1139 			post_attribs++;
1140 		}
1141 	}
1142 	/* <your lawful> */
1143 
1144 	/* How many genders are allowed for the desired role? */
1145 	if (validrole(rolenum))
1146 		gendercount = role_gendercount(rolenum);
1147 
1148 	if (gendnum != ROLE_NONE  && gendnum != ROLE_RANDOM) {
1149 		if (validrole(rolenum)) {
1150 		     /* if role specified, and multiple choice of genders for it,
1151 			and name of role itself does not distinguish gender */
1152 			if ((rolenum != ROLE_NONE) && (gendercount > 1)
1153 						&& !roles[rolenum].name.f) {
1154 				if (donefirst) Strcat(buf, " ");
1155 				Strcat(buf, genders[gendnum].adj);
1156 				donefirst = TRUE;
1157 			}
1158 	        } else {
1159 			if (donefirst) Strcat(buf, " ");
1160 	        	Strcat(buf, genders[gendnum].adj);
1161 			donefirst = TRUE;
1162 	        }
1163 	} else {
1164 		/* if gender not specified, but role is specified
1165 			and only one choice of gender then
1166 			don't include it in the later list */
1167 		if ((validrole(rolenum) && (gendercount > 1)) || !validrole(rolenum)) {
1168 			pa[BP_GEND] = 1;
1169 			post_attribs++;
1170 		}
1171 	}
1172 	/* <your lawful female> */
1173 
1174 	if (racenum != ROLE_NONE && racenum != ROLE_RANDOM) {
1175 		if (validrole(rolenum) && ok_race(rolenum, racenum, gendnum, alignnum)) {
1176 			if (donefirst) Strcat(buf, " ");
1177 			Strcat(buf, (rolenum == ROLE_NONE) ?
1178 				races[racenum].noun :
1179 				races[racenum].adj);
1180 			donefirst = TRUE;
1181 		} else if (!validrole(rolenum)) {
1182 			if (donefirst) Strcat(buf, " ");
1183 			Strcat(buf, races[racenum].noun);
1184 			donefirst = TRUE;
1185 		} else {
1186 			pa[BP_RACE] = 1;
1187 			post_attribs++;
1188 		}
1189 	} else {
1190 		pa[BP_RACE] = 1;
1191 		post_attribs++;
1192 	}
1193 	/* <your lawful female gnomish> || <your lawful female gnome> */
1194 
1195 	if (validrole(rolenum)) {
1196 		if (donefirst) Strcat(buf, " ");
1197 		if (gendnum != ROLE_NONE) {
1198 		    if (gendnum == 1  && roles[rolenum].name.f)
1199 			Strcat(buf, roles[rolenum].name.f);
1200 		    else
1201   			Strcat(buf, roles[rolenum].name.m);
1202 		} else {
1203 			if (roles[rolenum].name.f) {
1204 				Strcat(buf, roles[rolenum].name.m);
1205 				Strcat(buf, "/");
1206 				Strcat(buf, roles[rolenum].name.f);
1207 			} else
1208 				Strcat(buf, roles[rolenum].name.m);
1209 		}
1210 		donefirst = TRUE;
1211 	} else if (rolenum == ROLE_NONE) {
1212 		pa[BP_ROLE] = 1;
1213 		post_attribs++;
1214 	}
1215 
1216 	if ((racenum == ROLE_NONE || racenum == ROLE_RANDOM) && !validrole(rolenum)) {
1217 		if (donefirst) Strcat(buf, " ");
1218 		Strcat(buf, "character");
1219 		donefirst = TRUE;
1220 	}
1221 	/* <your lawful female gnomish cavewoman> || <your lawful female gnome>
1222 	 *    || <your lawful female character>
1223 	 */
1224 	if (buflen > (int) (strlen(buf) + 1)) {
1225 		Strcpy(suppliedbuf, buf);
1226 		return suppliedbuf;
1227 	} else
1228 		return err_ret;
1229 }
1230 
1231 char *
build_plselection_prompt(buf,buflen,rolenum,racenum,gendnum,alignnum)1232 build_plselection_prompt(buf, buflen, rolenum, racenum, gendnum, alignnum)
1233 char *buf;
1234 int buflen, rolenum, racenum, gendnum, alignnum;
1235 {
1236 	const char *defprompt = "Shall I pick a character for you? [ynq] ";
1237 	int num_post_attribs = 0;
1238 	char tmpbuf[BUFSZ];
1239 
1240 	if (buflen < QBUFSZ)
1241 		return (char *)defprompt;
1242 
1243 	Strcpy(tmpbuf, "Shall I pick ");
1244 	if (racenum != ROLE_NONE || validrole(rolenum))
1245 		Strcat(tmpbuf, "your ");
1246 	else {
1247 		Strcat(tmpbuf, "a ");
1248 	}
1249 	/* <your> */
1250 
1251 	(void)  root_plselection_prompt(eos(tmpbuf), buflen - strlen(tmpbuf),
1252 					rolenum, racenum, gendnum, alignnum);
1253 	Sprintf(buf, "%s", s_suffix(tmpbuf));
1254 
1255 	/* buf should now be:
1256 	 * < your lawful female gnomish cavewoman's> || <your lawful female gnome's>
1257 	 *    || <your lawful female character's>
1258 	 *
1259          * Now append the post attributes to it
1260 	 */
1261 
1262 	num_post_attribs = post_attribs;
1263 	if (post_attribs) {
1264 		if (pa[BP_RACE]) {
1265 			(void) promptsep(eos(buf), num_post_attribs);
1266 			Strcat(buf, "race");
1267 		}
1268 		if (pa[BP_ROLE]) {
1269 			(void) promptsep(eos(buf), num_post_attribs);
1270 			Strcat(buf, "role");
1271 		}
1272 		if (pa[BP_GEND]) {
1273 			(void) promptsep(eos(buf), num_post_attribs);
1274 			Strcat(buf, "gender");
1275 		}
1276 		if (pa[BP_ALIGN]) {
1277 			(void) promptsep(eos(buf), num_post_attribs);
1278 			Strcat(buf, "alignment");
1279 		}
1280 	}
1281 	Strcat(buf, " for you? [ynq] ");
1282 	return buf;
1283 }
1284 
1285 #undef BP_ALIGN
1286 #undef BP_GEND
1287 #undef BP_RACE
1288 #undef BP_ROLE
1289 #undef NUM_BP
1290 
1291 void
plnamesuffix()1292 plnamesuffix()
1293 {
1294 	char *sptr, *eptr;
1295 	int i;
1296 
1297 	/* Look for tokens delimited by '-' */
1298 	if ((eptr = index(plname, '-')) != (char *) 0)
1299 	    *eptr++ = '\0';
1300 	while (eptr) {
1301 	    /* Isolate the next token */
1302 	    sptr = eptr;
1303 	    if ((eptr = index(sptr, '-')) != (char *)0)
1304 		*eptr++ = '\0';
1305 
1306 	    /* Try to match it to something */
1307 	    if ((i = str2role(sptr)) != ROLE_NONE)
1308 		flags.initrole = i;
1309 	    else if ((i = str2race(sptr)) != ROLE_NONE)
1310 		flags.initrace = i;
1311 	    else if ((i = str2gend(sptr)) != ROLE_NONE)
1312 		flags.initgend = i;
1313 	    else if ((i = str2align(sptr)) != ROLE_NONE)
1314 		flags.initalign = i;
1315 	}
1316 	if(!plname[0]) {
1317 	    askname();
1318 	    plnamesuffix();
1319 	}
1320 
1321 	/* commas in the plname confuse the record file, convert to spaces */
1322 	for (sptr = plname; *sptr; sptr++) {
1323 		if (*sptr == ',') *sptr = ' ';
1324 	}
1325 }
1326 
1327 
1328 /*
1329  *	Special setup modifications here:
1330  *
1331  *	Unfortunately, this is going to have to be done
1332  *	on each newgame or restore, because you lose the permonst mods
1333  *	across a save/restore.  :-)
1334  *
1335  *	1 - The Rogue Leader is the Tourist Nemesis.
1336  *	2 - Priests start with a random alignment - convert the leader and
1337  *	    guardians here.
1338  *	3 - Elves can have one of two different leaders, but can't work it
1339  *	    out here because it requires hacking the level file data (see
1340  *	    sp_lev.c).
1341  *
1342  * This code also replaces quest_init().
1343  */
1344 void
role_init()1345 role_init()
1346 {
1347 	int alignmnt;
1348 
1349 	/* Strip the role letter out of the player name.
1350 	 * This is included for backwards compatibility.
1351 	 */
1352 	plnamesuffix();
1353 
1354 	/* Check for a valid role.  Try flags.initrole first. */
1355 	if (!validrole(flags.initrole)) {
1356 	    /* Try the player letter second */
1357 	    if ((flags.initrole = str2role(pl_character)) < 0)
1358 	    	/* None specified; pick a random role */
1359 	    	flags.initrole = randrole();
1360 	}
1361 
1362 	/* We now have a valid role index.  Copy the role name back. */
1363 	/* This should become OBSOLETE */
1364 	Strcpy(pl_character, roles[flags.initrole].name.m);
1365 	pl_character[PL_CSIZ-1] = '\0';
1366 
1367 	/* Check for a valid race */
1368 	if (!validrace(flags.initrole, flags.initrace))
1369 	    flags.initrace = randrace(flags.initrole);
1370 
1371 	/* Check for a valid gender.  If new game, check both initgend
1372 	 * and female.  On restore, assume flags.female is correct. */
1373 	if (flags.pantheon == -1) {	/* new game */
1374 	    if (!validgend(flags.initrole, flags.initrace, flags.female))
1375 		flags.female = !flags.female;
1376 	}
1377 	if (!validgend(flags.initrole, flags.initrace, flags.initgend))
1378 	    /* Note that there is no way to check for an unspecified gender. */
1379 	    flags.initgend = flags.female;
1380 
1381 	/* Check for a valid alignment */
1382 	if (!validalign(flags.initrole, flags.initrace, flags.initalign))
1383 	    /* Pick a random alignment */
1384 	    flags.initalign = randalign(flags.initrole, flags.initrace);
1385 	alignmnt = aligns[flags.initalign].value;
1386 
1387 	/* Initialize urole and urace */
1388 	urole = roles[flags.initrole];
1389 	urace = races[flags.initrace];
1390 
1391 	/* Fix up the quest leader */
1392 	if (urole.ldrnum != NON_PM) {
1393 	    mons[urole.ldrnum].msound = MS_LEADER;
1394 	    mons[urole.ldrnum].mflags2 |= (M2_PEACEFUL);
1395 	    mons[urole.ldrnum].mflags3 |= M3_CLOSE;
1396 	    mons[urole.ldrnum].maligntyp = alignmnt * 3;
1397 	}
1398 
1399 	/* Fix up the quest guardians */
1400 	if (urole.guardnum != NON_PM) {
1401 	    mons[urole.guardnum].mflags2 |= (M2_PEACEFUL);
1402 	    mons[urole.guardnum].maligntyp = alignmnt * 3;
1403 	}
1404 
1405 	/* Fix up the quest nemesis */
1406 	if (urole.neminum != NON_PM) {
1407 	    mons[urole.neminum].msound = MS_NEMESIS;
1408 	    mons[urole.neminum].mflags2 &= ~(M2_PEACEFUL);
1409 	    mons[urole.neminum].mflags2 |= (M2_NASTY|M2_STALK|M2_HOSTILE);
1410 	    mons[urole.neminum].mflags3 |= M3_WANTSARTI | M3_WAITFORU;
1411 	}
1412 
1413 	/* Fix up the god names */
1414 	if (flags.pantheon == -1) {		/* new game */
1415 	    flags.pantheon = flags.initrole;	/* use own gods */
1416 	    while (!roles[flags.pantheon].lgod)	/* unless they're missing */
1417 		flags.pantheon = randrole();
1418 	}
1419 	if (!urole.lgod) {
1420 	    urole.lgod = roles[flags.pantheon].lgod;
1421 	    urole.ngod = roles[flags.pantheon].ngod;
1422 	    urole.cgod = roles[flags.pantheon].cgod;
1423 	}
1424 
1425 	/* Fix up infravision */
1426 	if (mons[urace.malenum].mflags3 & M3_INFRAVISION) {
1427 	    /* although an infravision intrinsic is possible, infravision
1428 	     * is purely a property of the physical race.  This means that we
1429 	     * must put the infravision flag in the player's current race
1430 	     * (either that or have separate permonst entries for
1431 	     * elven/non-elven members of each class).  The side effect is that
1432 	     * all NPCs of that class will have (probably bogus) infravision,
1433 	     * but since infravision has no effect for NPCs anyway we can
1434 	     * ignore this.
1435 	     */
1436 	    mons[urole.malenum].mflags3 |= M3_INFRAVISION;
1437 	    if (urole.femalenum != NON_PM)
1438 	    	mons[urole.femalenum].mflags3 |= M3_INFRAVISION;
1439 	}
1440 
1441 	/* Artifacts are fixed in hack_artifacts() */
1442 
1443 	/* Success! */
1444 	return;
1445 }
1446 
1447 const char *
Hello(mtmp)1448 Hello(mtmp)
1449 struct monst *mtmp;
1450 {
1451 	switch (Role_switch) {
1452 	case PM_KNIGHT:
1453 	    return ("Salutations"); /* Olde English */
1454 	case PM_SAMURAI:
1455 	    return (mtmp && mtmp->data == &mons[PM_SHOPKEEPER] ?
1456 	    		"Irasshaimase" : "Konnichi wa"); /* Japanese */
1457 #ifdef TOURIST
1458 	case PM_TOURIST:
1459 	    return ("Aloha");       /* Hawaiian */
1460 #endif
1461 	case PM_VALKYRIE:
1462 	    return (
1463 #ifdef MAIL
1464 	    		mtmp && mtmp->data == &mons[PM_MAIL_DAEMON] ? "Hallo" :
1465 #endif
1466 	    		"Velkommen");   /* Norse */
1467 	default:
1468 	    return ("Hello");
1469 	}
1470 }
1471 
1472 const char *
Goodbye()1473 Goodbye()
1474 {
1475 	switch (Role_switch) {
1476 	case PM_KNIGHT:
1477 	    return ("Fare thee well");  /* Olde English */
1478 	case PM_SAMURAI:
1479 	    return ("Sayonara");        /* Japanese */
1480 #ifdef TOURIST
1481 	case PM_TOURIST:
1482 	    return ("Aloha");           /* Hawaiian */
1483 #endif
1484 	case PM_VALKYRIE:
1485 	    return ("Farvel");          /* Norse */
1486 	default:
1487 	    return ("Goodbye");
1488 	}
1489 }
1490 
1491 /* role.c */
1492