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 */
27const 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 */
388struct 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 */
406const 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 */
475struct 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 */
490const 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 */
498const 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
505STATIC_DCL char * FDECL(promptsep, (char *, int));
506STATIC_DCL int FDECL(role_gendercount, (int));
507STATIC_DCL int FDECL(race_alignmentcount, (int));
508
509/* used by str2XXX() */
510static char NEARDATA randomstr[] = "random";
511
512
513boolean
514validrole(rolenum)
515	int rolenum;
516{
517	return (rolenum >= 0 && rolenum < SIZE(roles)-1);
518}
519
520
521int
522randrole()
523{
524	return (rn2(SIZE(roles)-1));
525}
526
527
528int
529str2role(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
561boolean
562validrace(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
571int
572randrace(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
596int
597str2race(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
626boolean
627validgend(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
637int
638randgend(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
663int
664str2gend(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
692boolean
693validalign(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
703int
704randalign(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
729int
730str2align(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? */
758boolean
759ok_role(rolenum, racenum, gendnum, alignnum)
760int 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 */
798int
799pick_role(racenum, gendnum, alignnum, pickhow)
800int 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? */
824boolean
825ok_race(rolenum, racenum, gendnum, alignnum)
826int 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 */
864int
865pick_race(rolenum, gendnum, alignnum, pickhow)
866int 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) */
891boolean
892ok_gend(rolenum, racenum, gendnum, alignnum)
893int 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 */
926int
927pick_gend(rolenum, racenum, alignnum, pickhow)
928int 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) */
953boolean
954ok_align(rolenum, racenum, gendnum, alignnum)
955int 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 */
988int
989pick_align(rolenum, racenum, gendnum, pickhow)
990int 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
1013void
1014rigid_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
1053STATIC_VAR char pa[NUM_BP], post_attribs;
1054
1055STATIC_OVL char *
1056promptsep(buf, num_post_attribs)
1057char *buf;
1058int 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
1070STATIC_OVL int
1071role_gendercount(rolenum)
1072int 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
1083STATIC_OVL int
1084race_alignmentcount(racenum)
1085int 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
1096char *
1097root_plselection_prompt(suppliedbuf, buflen, rolenum, racenum, gendnum, alignnum)
1098char *suppliedbuf;
1099int 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
1231char *
1232build_plselection_prompt(buf, buflen, rolenum, racenum, gendnum, alignnum)
1233char *buf;
1234int 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
1291void
1292plnamesuffix()
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 */
1344void
1345role_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
1447const char *
1448Hello(mtmp)
1449struct 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
1472const char *
1473Goodbye()
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