OSDN Git Service

import nethack-3.6.0
[jnethack/source.git] / src / role.c
1 /* NetHack 3.6  role.c  $NHDT-Date: 1446861770 2015/11/07 02:02:50 $  $NHDT-Branch: master $:$NHDT-Revision: 1.34 $ */
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 /*** Table of all roles ***/
8 /* According to AD&D, HD for some classes (ex. Wizard) should be smaller
9  * (4-sided for wizards).  But this is not AD&D, and using the AD&D
10  * rule here produces an unplayable character.  Thus I have used a minimum
11  * of an 10-sided hit die for everything.  Another AD&D change: wizards get
12  * a minimum strength of 4 since without one you can't teleport or cast
13  * spells. --KAA
14  *
15  * As the wizard has been updated (wizard patch 5 jun '96) their HD can be
16  * brought closer into line with AD&D. This forces wizards to use magic more
17  * and distance themselves from their attackers. --LSZ
18  *
19  * With the introduction of races, some hit points and energy
20  * has been reallocated for each race.  The values assigned
21  * to the roles has been reduced by the amount allocated to
22  * humans.  --KMH
23  *
24  * God names use a leading underscore to flag goddesses.
25  */
26 const struct Role roles[] = {
27     { { "Archeologist", 0 },
28       { { "Digger", 0 },
29         { "Field Worker", 0 },
30         { "Investigator", 0 },
31         { "Exhumer", 0 },
32         { "Excavator", 0 },
33         { "Spelunker", 0 },
34         { "Speleologist", 0 },
35         { "Collector", 0 },
36         { "Curator", 0 } },
37       "Quetzalcoatl", "Camaxtli", "Huhetotl", /* Central American */
38       "Arc",
39       "the College of Archeology",
40       "the Tomb of the Toltec Kings",
41       PM_ARCHEOLOGIST,
42       NON_PM,
43       NON_PM,
44       PM_LORD_CARNARVON,
45       PM_STUDENT,
46       PM_MINION_OF_HUHETOTL,
47       NON_PM,
48       PM_HUMAN_MUMMY,
49       S_SNAKE,
50       S_MUMMY,
51       ART_ORB_OF_DETECTION,
52       MH_HUMAN | MH_DWARF | MH_GNOME | ROLE_MALE | ROLE_FEMALE | ROLE_LAWFUL
53           | ROLE_NEUTRAL,
54       /* Str Int Wis Dex Con Cha */
55       { 7, 10, 10, 7, 7, 7 },
56       { 20, 20, 20, 10, 20, 10 },
57       /* Init   Lower  Higher */
58       { 11, 0, 0, 8, 1, 0 }, /* Hit points */
59       { 1, 0, 0, 1, 0, 1 },
60       14, /* Energy */
61       10,
62       5,
63       0,
64       2,
65       10,
66       A_INT,
67       SPE_MAGIC_MAPPING,
68       -4 },
69     { { "Barbarian", 0 },
70       { { "Plunderer", "Plunderess" },
71         { "Pillager", 0 },
72         { "Bandit", 0 },
73         { "Brigand", 0 },
74         { "Raider", 0 },
75         { "Reaver", 0 },
76         { "Slayer", 0 },
77         { "Chieftain", "Chieftainess" },
78         { "Conqueror", "Conqueress" } },
79       "Mitra", "Crom", "Set", /* Hyborian */
80       "Bar",
81       "the Camp of the Duali Tribe",
82       "the Duali Oasis",
83       PM_BARBARIAN,
84       NON_PM,
85       NON_PM,
86       PM_PELIAS,
87       PM_CHIEFTAIN,
88       PM_THOTH_AMON,
89       PM_OGRE,
90       PM_TROLL,
91       S_OGRE,
92       S_TROLL,
93       ART_HEART_OF_AHRIMAN,
94       MH_HUMAN | MH_ORC | ROLE_MALE | ROLE_FEMALE | ROLE_NEUTRAL
95           | ROLE_CHAOTIC,
96       /* Str Int Wis Dex Con Cha */
97       { 16, 7, 7, 15, 16, 6 },
98       { 30, 6, 7, 20, 30, 7 },
99       /* Init   Lower  Higher */
100       { 14, 0, 0, 10, 2, 0 }, /* Hit points */
101       { 1, 0, 0, 1, 0, 1 },
102       10, /* Energy */
103       10,
104       14,
105       0,
106       0,
107       8,
108       A_INT,
109       SPE_HASTE_SELF,
110       -4 },
111     { { "Caveman", "Cavewoman" },
112       { { "Troglodyte", 0 },
113         { "Aborigine", 0 },
114         { "Wanderer", 0 },
115         { "Vagrant", 0 },
116         { "Wayfarer", 0 },
117         { "Roamer", 0 },
118         { "Nomad", 0 },
119         { "Rover", 0 },
120         { "Pioneer", 0 } },
121       "Anu", "_Ishtar", "Anshar", /* Babylonian */
122       "Cav",
123       "the Caves of the Ancestors",
124       "the Dragon's Lair",
125       PM_CAVEMAN,
126       PM_CAVEWOMAN,
127       PM_LITTLE_DOG,
128       PM_SHAMAN_KARNOV,
129       PM_NEANDERTHAL,
130       PM_CHROMATIC_DRAGON,
131       PM_BUGBEAR,
132       PM_HILL_GIANT,
133       S_HUMANOID,
134       S_GIANT,
135       ART_SCEPTRE_OF_MIGHT,
136       MH_HUMAN | MH_DWARF | MH_GNOME | ROLE_MALE | ROLE_FEMALE | ROLE_LAWFUL
137           | ROLE_NEUTRAL,
138       /* Str Int Wis Dex Con Cha */
139       { 10, 7, 7, 7, 8, 6 },
140       { 30, 6, 7, 20, 30, 7 },
141       /* Init   Lower  Higher */
142       { 14, 0, 0, 8, 2, 0 }, /* Hit points */
143       { 1, 0, 0, 1, 0, 1 },
144       10, /* Energy */
145       0,
146       12,
147       0,
148       1,
149       8,
150       A_INT,
151       SPE_DIG,
152       -4 },
153     { { "Healer", 0 },
154       { { "Rhizotomist", 0 },
155         { "Empiric", 0 },
156         { "Embalmer", 0 },
157         { "Dresser", 0 },
158         { "Medicus ossium", "Medica ossium" },
159         { "Herbalist", 0 },
160         { "Magister", "Magistra" },
161         { "Physician", 0 },
162         { "Chirurgeon", 0 } },
163       "_Athena", "Hermes", "Poseidon", /* Greek */
164       "Hea",
165       "the Temple of Epidaurus",
166       "the Temple of Coeus",
167       PM_HEALER,
168       NON_PM,
169       NON_PM,
170       PM_HIPPOCRATES,
171       PM_ATTENDANT,
172       PM_CYCLOPS,
173       PM_GIANT_RAT,
174       PM_SNAKE,
175       S_RODENT,
176       S_YETI,
177       ART_STAFF_OF_AESCULAPIUS,
178       MH_HUMAN | MH_GNOME | ROLE_MALE | ROLE_FEMALE | ROLE_NEUTRAL,
179       /* Str Int Wis Dex Con Cha */
180       { 7, 7, 13, 7, 11, 16 },
181       { 15, 20, 20, 15, 25, 5 },
182       /* Init   Lower  Higher */
183       { 11, 0, 0, 8, 1, 0 }, /* Hit points */
184       { 1, 4, 0, 1, 0, 2 },
185       20, /* Energy */
186       10,
187       3,
188       -3,
189       2,
190       10,
191       A_WIS,
192       SPE_CURE_SICKNESS,
193       -4 },
194     { { "Knight", 0 },
195       { { "Gallant", 0 },
196         { "Esquire", 0 },
197         { "Bachelor", 0 },
198         { "Sergeant", 0 },
199         { "Knight", 0 },
200         { "Banneret", 0 },
201         { "Chevalier", "Chevaliere" },
202         { "Seignieur", "Dame" },
203         { "Paladin", 0 } },
204       "Lugh", "_Brigit", "Manannan Mac Lir", /* Celtic */
205       "Kni",
206       "Camelot Castle",
207       "the Isle of Glass",
208       PM_KNIGHT,
209       NON_PM,
210       PM_PONY,
211       PM_KING_ARTHUR,
212       PM_PAGE,
213       PM_IXOTH,
214       PM_QUASIT,
215       PM_OCHRE_JELLY,
216       S_IMP,
217       S_JELLY,
218       ART_MAGIC_MIRROR_OF_MERLIN,
219       MH_HUMAN | ROLE_MALE | ROLE_FEMALE | ROLE_LAWFUL,
220       /* Str Int Wis Dex Con Cha */
221       { 13, 7, 14, 8, 10, 17 },
222       { 30, 15, 15, 10, 20, 10 },
223       /* Init   Lower  Higher */
224       { 14, 0, 0, 8, 2, 0 }, /* Hit points */
225       { 1, 4, 0, 1, 0, 2 },
226       10, /* Energy */
227       10,
228       8,
229       -2,
230       0,
231       9,
232       A_WIS,
233       SPE_TURN_UNDEAD,
234       -4 },
235     { { "Monk", 0 },
236       { { "Candidate", 0 },
237         { "Novice", 0 },
238         { "Initiate", 0 },
239         { "Student of Stones", 0 },
240         { "Student of Waters", 0 },
241         { "Student of Metals", 0 },
242         { "Student of Winds", 0 },
243         { "Student of Fire", 0 },
244         { "Master", 0 } },
245       "Shan Lai Ching", "Chih Sung-tzu", "Huan Ti", /* Chinese */
246       "Mon",
247       "the Monastery of Chan-Sune",
248       "the Monastery of the Earth-Lord",
249       PM_MONK,
250       NON_PM,
251       NON_PM,
252       PM_GRAND_MASTER,
253       PM_ABBOT,
254       PM_MASTER_KAEN,
255       PM_EARTH_ELEMENTAL,
256       PM_XORN,
257       S_ELEMENTAL,
258       S_XORN,
259       ART_EYES_OF_THE_OVERWORLD,
260       MH_HUMAN | ROLE_MALE | ROLE_FEMALE | ROLE_LAWFUL | ROLE_NEUTRAL
261           | ROLE_CHAOTIC,
262       /* Str Int Wis Dex Con Cha */
263       { 10, 7, 8, 8, 7, 7 },
264       { 25, 10, 20, 20, 15, 10 },
265       /* Init   Lower  Higher */
266       { 12, 0, 0, 8, 1, 0 }, /* Hit points */
267       { 2, 2, 0, 2, 0, 2 },
268       10, /* Energy */
269       10,
270       8,
271       -2,
272       2,
273       20,
274       A_WIS,
275       SPE_RESTORE_ABILITY,
276       -4 },
277     { { "Priest", "Priestess" },
278       { { "Aspirant", 0 },
279         { "Acolyte", 0 },
280         { "Adept", 0 },
281         { "Priest", "Priestess" },
282         { "Curate", 0 },
283         { "Canon", "Canoness" },
284         { "Lama", 0 },
285         { "Patriarch", "Matriarch" },
286         { "High Priest", "High Priestess" } },
287       0, 0, 0, /* deities from a randomly chosen other role will be used */
288       "Pri",
289       "the Great Temple",
290       "the Temple of Nalzok",
291       PM_PRIEST,
292       PM_PRIESTESS,
293       NON_PM,
294       PM_ARCH_PRIEST,
295       PM_ACOLYTE,
296       PM_NALZOK,
297       PM_HUMAN_ZOMBIE,
298       PM_WRAITH,
299       S_ZOMBIE,
300       S_WRAITH,
301       ART_MITRE_OF_HOLINESS,
302       MH_HUMAN | MH_ELF | ROLE_MALE | ROLE_FEMALE | ROLE_LAWFUL | ROLE_NEUTRAL
303           | ROLE_CHAOTIC,
304       /* Str Int Wis Dex Con Cha */
305       { 7, 7, 10, 7, 7, 7 },
306       { 15, 10, 30, 15, 20, 10 },
307       /* Init   Lower  Higher */
308       { 12, 0, 0, 8, 1, 0 }, /* Hit points */
309       { 4, 3, 0, 2, 0, 2 },
310       10, /* Energy */
311       0,
312       3,
313       -2,
314       2,
315       10,
316       A_WIS,
317       SPE_REMOVE_CURSE,
318       -4 },
319     /* Note:  Rogue precedes Ranger so that use of `-R' on the command line
320        retains its traditional meaning. */
321     { { "Rogue", 0 },
322       { { "Footpad", 0 },
323         { "Cutpurse", 0 },
324         { "Rogue", 0 },
325         { "Pilferer", 0 },
326         { "Robber", 0 },
327         { "Burglar", 0 },
328         { "Filcher", 0 },
329         { "Magsman", "Magswoman" },
330         { "Thief", 0 } },
331       "Issek", "Mog", "Kos", /* Nehwon */
332       "Rog",
333       "the Thieves' Guild Hall",
334       "the Assassins' Guild Hall",
335       PM_ROGUE,
336       NON_PM,
337       NON_PM,
338       PM_MASTER_OF_THIEVES,
339       PM_THUG,
340       PM_MASTER_ASSASSIN,
341       PM_LEPRECHAUN,
342       PM_GUARDIAN_NAGA,
343       S_NYMPH,
344       S_NAGA,
345       ART_MASTER_KEY_OF_THIEVERY,
346       MH_HUMAN | MH_ORC | ROLE_MALE | ROLE_FEMALE | ROLE_CHAOTIC,
347       /* Str Int Wis Dex Con Cha */
348       { 7, 7, 7, 10, 7, 6 },
349       { 20, 10, 10, 30, 20, 10 },
350       /* Init   Lower  Higher */
351       { 10, 0, 0, 8, 1, 0 }, /* Hit points */
352       { 1, 0, 0, 1, 0, 1 },
353       11, /* Energy */
354       10,
355       8,
356       0,
357       1,
358       9,
359       A_INT,
360       SPE_DETECT_TREASURE,
361       -4 },
362     { { "Ranger", 0 },
363       {
364 #if 0 /* OBSOLETE */
365         {"Edhel",   "Elleth"},
366         {"Edhel",   "Elleth"},         /* elf-maid */
367         {"Ohtar",   "Ohtie"},          /* warrior */
368         {"Kano",    "Kanie"},          /* commander (Q.) ['a] educated guess,
369                                           until further research- SAC */
370         {"Arandur"," Aranduriel"}, /* king's servant, minister (Q.) - guess */
371         {"Hir",         "Hiril"},      /* lord, lady (S.) ['ir] */
372         {"Aredhel",     "Arwen"},      /* noble elf, maiden (S.) */
373         {"Ernil",       "Elentariel"}, /* prince (S.), elf-maiden (Q.) */
374         {"Elentar",     "Elentari"},   /* Star-king, -queen (Q.) */
375         "Solonor Thelandira", "Aerdrie Faenya", "Lolth", /* Elven */
376 #endif
377         { "Tenderfoot", 0 },
378         { "Lookout", 0 },
379         { "Trailblazer", 0 },
380         { "Reconnoiterer", "Reconnoiteress" },
381         { "Scout", 0 },
382         { "Arbalester", 0 }, /* One skilled at crossbows */
383         { "Archer", 0 },
384         { "Sharpshooter", 0 },
385         { "Marksman", "Markswoman" } },
386       "Mercury", "_Venus", "Mars", /* Roman/planets */
387       "Ran",
388       "Orion's camp",
389       "the cave of the wumpus",
390       PM_RANGER,
391       NON_PM,
392       PM_LITTLE_DOG /* Orion & canis major */,
393       PM_ORION,
394       PM_HUNTER,
395       PM_SCORPIUS,
396       PM_FOREST_CENTAUR,
397       PM_SCORPION,
398       S_CENTAUR,
399       S_SPIDER,
400       ART_LONGBOW_OF_DIANA,
401       MH_HUMAN | MH_ELF | MH_GNOME | MH_ORC | ROLE_MALE | ROLE_FEMALE
402           | ROLE_NEUTRAL | ROLE_CHAOTIC,
403       /* Str Int Wis Dex Con Cha */
404       { 13, 13, 13, 9, 13, 7 },
405       { 30, 10, 10, 20, 20, 10 },
406       /* Init   Lower  Higher */
407       { 13, 0, 0, 6, 1, 0 }, /* Hit points */
408       { 1, 0, 0, 1, 0, 1 },
409       12, /* Energy */
410       10,
411       9,
412       2,
413       1,
414       10,
415       A_INT,
416       SPE_INVISIBILITY,
417       -4 },
418     { { "Samurai", 0 },
419       { { "Hatamoto", 0 },       /* Banner Knight */
420         { "Ronin", 0 },          /* no allegiance */
421         { "Ninja", "Kunoichi" }, /* secret society */
422         { "Joshu", 0 },          /* heads a castle */
423         { "Ryoshu", 0 },         /* has a territory */
424         { "Kokushu", 0 },        /* heads a province */
425         { "Daimyo", 0 },         /* a samurai lord */
426         { "Kuge", 0 },           /* Noble of the Court */
427         { "Shogun", 0 } },       /* supreme commander, warlord */
428       "_Amaterasu Omikami", "Raijin", "Susanowo", /* Japanese */
429       "Sam",
430       "the Castle of the Taro Clan",
431       "the Shogun's Castle",
432       PM_SAMURAI,
433       NON_PM,
434       PM_LITTLE_DOG,
435       PM_LORD_SATO,
436       PM_ROSHI,
437       PM_ASHIKAGA_TAKAUJI,
438       PM_WOLF,
439       PM_STALKER,
440       S_DOG,
441       S_ELEMENTAL,
442       ART_TSURUGI_OF_MURAMASA,
443       MH_HUMAN | ROLE_MALE | ROLE_FEMALE | ROLE_LAWFUL,
444       /* Str Int Wis Dex Con Cha */
445       { 10, 8, 7, 10, 17, 6 },
446       { 30, 10, 8, 30, 14, 8 },
447       /* Init   Lower  Higher */
448       { 13, 0, 0, 8, 1, 0 }, /* Hit points */
449       { 1, 0, 0, 1, 0, 1 },
450       11, /* Energy */
451       10,
452       10,
453       0,
454       0,
455       8,
456       A_INT,
457       SPE_CLAIRVOYANCE,
458       -4 },
459     { { "Tourist", 0 },
460       { { "Rambler", 0 },
461         { "Sightseer", 0 },
462         { "Excursionist", 0 },
463         { "Peregrinator", "Peregrinatrix" },
464         { "Traveler", 0 },
465         { "Journeyer", 0 },
466         { "Voyager", 0 },
467         { "Explorer", 0 },
468         { "Adventurer", 0 } },
469       "Blind Io", "_The Lady", "Offler", /* Discworld */
470       "Tou",
471       "Ankh-Morpork",
472       "the Thieves' Guild Hall",
473       PM_TOURIST,
474       NON_PM,
475       NON_PM,
476       PM_TWOFLOWER,
477       PM_GUIDE,
478       PM_MASTER_OF_THIEVES,
479       PM_GIANT_SPIDER,
480       PM_FOREST_CENTAUR,
481       S_SPIDER,
482       S_CENTAUR,
483       ART_YENDORIAN_EXPRESS_CARD,
484       MH_HUMAN | ROLE_MALE | ROLE_FEMALE | ROLE_NEUTRAL,
485       /* Str Int Wis Dex Con Cha */
486       { 7, 10, 6, 7, 7, 10 },
487       { 15, 10, 10, 15, 30, 20 },
488       /* Init   Lower  Higher */
489       { 8, 0, 0, 8, 0, 0 }, /* Hit points */
490       { 1, 0, 0, 1, 0, 1 },
491       14, /* Energy */
492       0,
493       5,
494       1,
495       2,
496       10,
497       A_INT,
498       SPE_CHARM_MONSTER,
499       -4 },
500     { { "Valkyrie", 0 },
501       { { "Stripling", 0 },
502         { "Skirmisher", 0 },
503         { "Fighter", 0 },
504         { "Man-at-arms", "Woman-at-arms" },
505         { "Warrior", 0 },
506         { "Swashbuckler", 0 },
507         { "Hero", "Heroine" },
508         { "Champion", 0 },
509         { "Lord", "Lady" } },
510       "Tyr", "Odin", "Loki", /* Norse */
511       "Val",
512       "the Shrine of Destiny",
513       "the cave of Surtur",
514       PM_VALKYRIE,
515       NON_PM,
516       NON_PM /*PM_WINTER_WOLF_CUB*/,
517       PM_NORN,
518       PM_WARRIOR,
519       PM_LORD_SURTUR,
520       PM_FIRE_ANT,
521       PM_FIRE_GIANT,
522       S_ANT,
523       S_GIANT,
524       ART_ORB_OF_FATE,
525       MH_HUMAN | MH_DWARF | ROLE_FEMALE | ROLE_LAWFUL | ROLE_NEUTRAL,
526       /* Str Int Wis Dex Con Cha */
527       { 10, 7, 7, 7, 10, 7 },
528       { 30, 6, 7, 20, 30, 7 },
529       /* Init   Lower  Higher */
530       { 14, 0, 0, 8, 2, 0 }, /* Hit points */
531       { 1, 0, 0, 1, 0, 1 },
532       10, /* Energy */
533       0,
534       10,
535       -2,
536       0,
537       9,
538       A_WIS,
539       SPE_CONE_OF_COLD,
540       -4 },
541     { { "Wizard", 0 },
542       { { "Evoker", 0 },
543         { "Conjurer", 0 },
544         { "Thaumaturge", 0 },
545         { "Magician", 0 },
546         { "Enchanter", "Enchantress" },
547         { "Sorcerer", "Sorceress" },
548         { "Necromancer", 0 },
549         { "Wizard", 0 },
550         { "Mage", 0 } },
551       "Ptah", "Thoth", "Anhur", /* Egyptian */
552       "Wiz",
553       "the Lonely Tower",
554       "the Tower of Darkness",
555       PM_WIZARD,
556       NON_PM,
557       PM_KITTEN,
558       PM_NEFERET_THE_GREEN,
559       PM_APPRENTICE,
560       PM_DARK_ONE,
561       PM_VAMPIRE_BAT,
562       PM_XORN,
563       S_BAT,
564       S_WRAITH,
565       ART_EYE_OF_THE_AETHIOPICA,
566       MH_HUMAN | MH_ELF | MH_GNOME | MH_ORC | ROLE_MALE | ROLE_FEMALE
567           | ROLE_NEUTRAL | ROLE_CHAOTIC,
568       /* Str Int Wis Dex Con Cha */
569       { 7, 10, 7, 7, 7, 7 },
570       { 10, 30, 10, 20, 20, 10 },
571       /* Init   Lower  Higher */
572       { 10, 0, 0, 8, 1, 0 }, /* Hit points */
573       { 4, 3, 0, 2, 0, 3 },
574       12, /* Energy */
575       0,
576       1,
577       0,
578       3,
579       10,
580       A_INT,
581       SPE_MAGIC_MISSILE,
582       -4 },
583     /* Array terminator */
584     { { 0, 0 } }
585 };
586
587 /* The player's role, created at runtime from initial
588  * choices.  This may be munged in role_init().
589  */
590 struct Role urole = {
591     { "Undefined", 0 },
592     { { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 },
593       { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 } },
594     "L", "N", "C",
595     "Xxx", "home", "locate",
596     NON_PM, NON_PM, NON_PM, NON_PM, NON_PM, NON_PM, NON_PM, NON_PM,
597     0, 0, 0, 0,
598     /* Str Int Wis Dex Con Cha */
599     { 7, 7, 7, 7, 7, 7 },
600     { 20, 15, 15, 20, 20, 10 },
601     /* Init   Lower  Higher */
602     { 10, 0, 0, 8, 1, 0 }, /* Hit points */
603     { 2, 0, 0, 2, 0, 3 },
604     14, /* Energy */
605      0,
606     10,
607      0,
608      0,
609      4,
610     A_INT,
611      0,
612     -3
613 };
614
615 /* Table of all races */
616 const struct Race races[] = {
617     {
618         "human",
619         "human",
620         "humanity",
621         "Hum",
622         { "man", "woman" },
623         PM_HUMAN,
624         NON_PM,
625         PM_HUMAN_MUMMY,
626         PM_HUMAN_ZOMBIE,
627         MH_HUMAN | ROLE_MALE | ROLE_FEMALE | ROLE_LAWFUL | ROLE_NEUTRAL
628             | ROLE_CHAOTIC,
629         MH_HUMAN,
630         0,
631         MH_GNOME | MH_ORC,
632         /*    Str     Int Wis Dex Con Cha */
633         { 3, 3, 3, 3, 3, 3 },
634         { STR18(100), 18, 18, 18, 18, 18 },
635         /* Init   Lower  Higher */
636         { 2, 0, 0, 2, 1, 0 }, /* Hit points */
637         { 1, 0, 2, 0, 2, 0 }  /* Energy */
638     },
639     {
640         "elf",
641         "elven",
642         "elvenkind",
643         "Elf",
644         { 0, 0 },
645         PM_ELF,
646         NON_PM,
647         PM_ELF_MUMMY,
648         PM_ELF_ZOMBIE,
649         MH_ELF | ROLE_MALE | ROLE_FEMALE | ROLE_CHAOTIC,
650         MH_ELF,
651         MH_ELF,
652         MH_ORC,
653         /*  Str    Int Wis Dex Con Cha */
654         { 3, 3, 3, 3, 3, 3 },
655         { 18, 20, 20, 18, 16, 18 },
656         /* Init   Lower  Higher */
657         { 1, 0, 0, 1, 1, 0 }, /* Hit points */
658         { 2, 0, 3, 0, 3, 0 }  /* Energy */
659     },
660     {
661         "dwarf",
662         "dwarven",
663         "dwarvenkind",
664         "Dwa",
665         { 0, 0 },
666         PM_DWARF,
667         NON_PM,
668         PM_DWARF_MUMMY,
669         PM_DWARF_ZOMBIE,
670         MH_DWARF | ROLE_MALE | ROLE_FEMALE | ROLE_LAWFUL,
671         MH_DWARF,
672         MH_DWARF | MH_GNOME,
673         MH_ORC,
674         /*    Str     Int Wis Dex Con Cha */
675         { 3, 3, 3, 3, 3, 3 },
676         { STR18(100), 16, 16, 20, 20, 16 },
677         /* Init   Lower  Higher */
678         { 4, 0, 0, 3, 2, 0 }, /* Hit points */
679         { 0, 0, 0, 0, 0, 0 }  /* Energy */
680     },
681     {
682         "gnome",
683         "gnomish",
684         "gnomehood",
685         "Gno",
686         { 0, 0 },
687         PM_GNOME,
688         NON_PM,
689         PM_GNOME_MUMMY,
690         PM_GNOME_ZOMBIE,
691         MH_GNOME | ROLE_MALE | ROLE_FEMALE | ROLE_NEUTRAL,
692         MH_GNOME,
693         MH_DWARF | MH_GNOME,
694         MH_HUMAN,
695         /*  Str    Int Wis Dex Con Cha */
696         { 3, 3, 3, 3, 3, 3 },
697         { STR18(50), 19, 18, 18, 18, 18 },
698         /* Init   Lower  Higher */
699         { 1, 0, 0, 1, 0, 0 }, /* Hit points */
700         { 2, 0, 2, 0, 2, 0 }  /* Energy */
701     },
702     {
703         "orc",
704         "orcish",
705         "orcdom",
706         "Orc",
707         { 0, 0 },
708         PM_ORC,
709         NON_PM,
710         PM_ORC_MUMMY,
711         PM_ORC_ZOMBIE,
712         MH_ORC | ROLE_MALE | ROLE_FEMALE | ROLE_CHAOTIC,
713         MH_ORC,
714         0,
715         MH_HUMAN | MH_ELF | MH_DWARF,
716         /*  Str    Int Wis Dex Con Cha */
717         { 3, 3, 3, 3, 3, 3 },
718         { STR18(50), 16, 16, 18, 18, 16 },
719         /* Init   Lower  Higher */
720         { 1, 0, 0, 1, 0, 0 }, /* Hit points */
721         { 1, 0, 1, 0, 1, 0 }  /* Energy */
722     },
723     /* Array terminator */
724     { 0, 0, 0, 0 }
725 };
726
727 /* The player's race, created at runtime from initial
728  * choices.  This may be munged in role_init().
729  */
730 struct Race urace = {
731     "something",
732     "undefined",
733     "something",
734     "Xxx",
735     { 0, 0 },
736     NON_PM,
737     NON_PM,
738     NON_PM,
739     NON_PM,
740     0,
741     0,
742     0,
743     0,
744     /*    Str     Int Wis Dex Con Cha */
745     { 3, 3, 3, 3, 3, 3 },
746     { STR18(100), 18, 18, 18, 18, 18 },
747     /* Init   Lower  Higher */
748     { 2, 0, 0, 2, 1, 0 }, /* Hit points */
749     { 1, 0, 2, 0, 2, 0 }  /* Energy */
750 };
751
752 /* Table of all genders */
753 const struct Gender genders[] = {
754     { "male", "he", "him", "his", "Mal", ROLE_MALE },
755     { "female", "she", "her", "her", "Fem", ROLE_FEMALE },
756     { "neuter", "it", "it", "its", "Ntr", ROLE_NEUTER }
757 };
758
759 /* Table of all alignments */
760 const struct Align aligns[] = {
761     { "law", "lawful", "Law", ROLE_LAWFUL, A_LAWFUL },
762     { "balance", "neutral", "Neu", ROLE_NEUTRAL, A_NEUTRAL },
763     { "chaos", "chaotic", "Cha", ROLE_CHAOTIC, A_CHAOTIC },
764     { "evil", "unaligned", "Una", 0, A_NONE }
765 };
766
767 /* Filters */
768 static struct {
769     boolean roles[SIZE(roles)];
770     short mask;
771 } filter;
772
773 STATIC_DCL int NDECL(randrole_filtered);
774 STATIC_DCL char *FDECL(promptsep, (char *, int));
775 STATIC_DCL int FDECL(role_gendercount, (int));
776 STATIC_DCL int FDECL(race_alignmentcount, (int));
777
778 /* used by str2XXX() */
779 static char NEARDATA randomstr[] = "random";
780
781 boolean
782 validrole(rolenum)
783 int rolenum;
784 {
785     return (boolean) (rolenum >= 0 && rolenum < SIZE(roles) - 1);
786 }
787
788 int
789 randrole()
790 {
791     return rn2(SIZE(roles) - 1);
792 }
793
794 STATIC_OVL int
795 randrole_filtered()
796 {
797     int i, n = 0, set[SIZE(roles)];
798
799     /* this doesn't rule out impossible combinations but attempts to
800        honor all the filter masks */
801     for (i = 0; i < SIZE(roles); ++i)
802         if (ok_role(i, ROLE_NONE, ROLE_NONE, ROLE_NONE)
803             && ok_race(i, ROLE_RANDOM, ROLE_NONE, ROLE_NONE)
804             && ok_gend(i, ROLE_NONE, ROLE_RANDOM, ROLE_NONE)
805             && ok_align(i, ROLE_NONE, ROLE_NONE, ROLE_RANDOM))
806             set[n++] = i;
807     return n ? set[rn2(n)] : randrole();
808 }
809
810 int
811 str2role(str)
812 const char *str;
813 {
814     int i, len;
815
816     /* Is str valid? */
817     if (!str || !str[0])
818         return ROLE_NONE;
819
820     /* Match as much of str as is provided */
821     len = strlen(str);
822     for (i = 0; roles[i].name.m; i++) {
823         /* Does it match the male name? */
824         if (!strncmpi(str, roles[i].name.m, len))
825             return i;
826         /* Or the female name? */
827         if (roles[i].name.f && !strncmpi(str, roles[i].name.f, len))
828             return i;
829         /* Or the filecode? */
830         if (!strcmpi(str, roles[i].filecode))
831             return i;
832     }
833
834     if ((len == 1 && (*str == '*' || *str == '@'))
835         || !strncmpi(str, randomstr, len))
836         return ROLE_RANDOM;
837
838     /* Couldn't find anything appropriate */
839     return ROLE_NONE;
840 }
841
842 boolean
843 validrace(rolenum, racenum)
844 int rolenum, racenum;
845 {
846     /* Assumes validrole */
847     return (boolean) (racenum >= 0 && racenum < SIZE(races) - 1
848                       && (roles[rolenum].allow & races[racenum].allow
849                           & ROLE_RACEMASK));
850 }
851
852 int
853 randrace(rolenum)
854 int rolenum;
855 {
856     int i, n = 0;
857
858     /* Count the number of valid races */
859     for (i = 0; races[i].noun; i++)
860         if (roles[rolenum].allow & races[i].allow & ROLE_RACEMASK)
861             n++;
862
863     /* Pick a random race */
864     /* Use a factor of 100 in case of bad random number generators */
865     if (n)
866         n = rn2(n * 100) / 100;
867     for (i = 0; races[i].noun; i++)
868         if (roles[rolenum].allow & races[i].allow & ROLE_RACEMASK) {
869             if (n)
870                 n--;
871             else
872                 return i;
873         }
874
875     /* This role has no permitted races? */
876     return rn2(SIZE(races) - 1);
877 }
878
879 int
880 str2race(str)
881 const char *str;
882 {
883     int i, len;
884
885     /* Is str valid? */
886     if (!str || !str[0])
887         return ROLE_NONE;
888
889     /* Match as much of str as is provided */
890     len = strlen(str);
891     for (i = 0; races[i].noun; i++) {
892         /* Does it match the noun? */
893         if (!strncmpi(str, races[i].noun, len))
894             return i;
895         /* Or the filecode? */
896         if (!strcmpi(str, races[i].filecode))
897             return i;
898     }
899
900     if ((len == 1 && (*str == '*' || *str == '@'))
901         || !strncmpi(str, randomstr, len))
902         return ROLE_RANDOM;
903
904     /* Couldn't find anything appropriate */
905     return ROLE_NONE;
906 }
907
908 boolean
909 validgend(rolenum, racenum, gendnum)
910 int rolenum, racenum, gendnum;
911 {
912     /* Assumes validrole and validrace */
913     return (boolean) (gendnum >= 0 && gendnum < ROLE_GENDERS
914                       && (roles[rolenum].allow & races[racenum].allow
915                           & genders[gendnum].allow & ROLE_GENDMASK));
916 }
917
918 int
919 randgend(rolenum, racenum)
920 int rolenum, racenum;
921 {
922     int i, n = 0;
923
924     /* Count the number of valid genders */
925     for (i = 0; i < ROLE_GENDERS; i++)
926         if (roles[rolenum].allow & races[racenum].allow & genders[i].allow
927             & ROLE_GENDMASK)
928             n++;
929
930     /* Pick a random gender */
931     if (n)
932         n = rn2(n);
933     for (i = 0; i < ROLE_GENDERS; i++)
934         if (roles[rolenum].allow & races[racenum].allow & genders[i].allow
935             & ROLE_GENDMASK) {
936             if (n)
937                 n--;
938             else
939                 return i;
940         }
941
942     /* This role/race has no permitted genders? */
943     return rn2(ROLE_GENDERS);
944 }
945
946 int
947 str2gend(str)
948 const char *str;
949 {
950     int i, len;
951
952     /* Is str valid? */
953     if (!str || !str[0])
954         return ROLE_NONE;
955
956     /* Match as much of str as is provided */
957     len = strlen(str);
958     for (i = 0; i < ROLE_GENDERS; i++) {
959         /* Does it match the adjective? */
960         if (!strncmpi(str, genders[i].adj, len))
961             return i;
962         /* Or the filecode? */
963         if (!strcmpi(str, genders[i].filecode))
964             return i;
965     }
966     if ((len == 1 && (*str == '*' || *str == '@'))
967         || !strncmpi(str, randomstr, len))
968         return ROLE_RANDOM;
969
970     /* Couldn't find anything appropriate */
971     return ROLE_NONE;
972 }
973
974 boolean
975 validalign(rolenum, racenum, alignnum)
976 int rolenum, racenum, alignnum;
977 {
978     /* Assumes validrole and validrace */
979     return (boolean) (alignnum >= 0 && alignnum < ROLE_ALIGNS
980                       && (roles[rolenum].allow & races[racenum].allow
981                           & aligns[alignnum].allow & ROLE_ALIGNMASK));
982 }
983
984 int
985 randalign(rolenum, racenum)
986 int rolenum, racenum;
987 {
988     int i, n = 0;
989
990     /* Count the number of valid alignments */
991     for (i = 0; i < ROLE_ALIGNS; i++)
992         if (roles[rolenum].allow & races[racenum].allow & aligns[i].allow
993             & ROLE_ALIGNMASK)
994             n++;
995
996     /* Pick a random alignment */
997     if (n)
998         n = rn2(n);
999     for (i = 0; i < ROLE_ALIGNS; i++)
1000         if (roles[rolenum].allow & races[racenum].allow & aligns[i].allow
1001             & ROLE_ALIGNMASK) {
1002             if (n)
1003                 n--;
1004             else
1005                 return i;
1006         }
1007
1008     /* This role/race has no permitted alignments? */
1009     return rn2(ROLE_ALIGNS);
1010 }
1011
1012 int
1013 str2align(str)
1014 const char *str;
1015 {
1016     int i, len;
1017
1018     /* Is str valid? */
1019     if (!str || !str[0])
1020         return ROLE_NONE;
1021
1022     /* Match as much of str as is provided */
1023     len = strlen(str);
1024     for (i = 0; i < ROLE_ALIGNS; i++) {
1025         /* Does it match the adjective? */
1026         if (!strncmpi(str, aligns[i].adj, len))
1027             return i;
1028         /* Or the filecode? */
1029         if (!strcmpi(str, aligns[i].filecode))
1030             return i;
1031     }
1032     if ((len == 1 && (*str == '*' || *str == '@'))
1033         || !strncmpi(str, randomstr, len))
1034         return ROLE_RANDOM;
1035
1036     /* Couldn't find anything appropriate */
1037     return ROLE_NONE;
1038 }
1039
1040 /* is rolenum compatible with any racenum/gendnum/alignnum constraints? */
1041 boolean
1042 ok_role(rolenum, racenum, gendnum, alignnum)
1043 int rolenum, racenum, gendnum, alignnum;
1044 {
1045     int i;
1046     short allow;
1047
1048     if (rolenum >= 0 && rolenum < SIZE(roles) - 1) {
1049         if (filter.roles[rolenum])
1050             return FALSE;
1051         allow = roles[rolenum].allow;
1052         if (racenum >= 0 && racenum < SIZE(races) - 1
1053             && !(allow & races[racenum].allow & ROLE_RACEMASK))
1054             return FALSE;
1055         if (gendnum >= 0 && gendnum < ROLE_GENDERS
1056             && !(allow & genders[gendnum].allow & ROLE_GENDMASK))
1057             return FALSE;
1058         if (alignnum >= 0 && alignnum < ROLE_ALIGNS
1059             && !(allow & aligns[alignnum].allow & ROLE_ALIGNMASK))
1060             return FALSE;
1061         return TRUE;
1062     } else {
1063         /* random; check whether any selection is possible */
1064         for (i = 0; i < SIZE(roles) - 1; i++) {
1065             if (filter.roles[i])
1066                 continue;
1067             allow = roles[i].allow;
1068             if (racenum >= 0 && racenum < SIZE(races) - 1
1069                 && !(allow & races[racenum].allow & ROLE_RACEMASK))
1070                 continue;
1071             if (gendnum >= 0 && gendnum < ROLE_GENDERS
1072                 && !(allow & genders[gendnum].allow & ROLE_GENDMASK))
1073                 continue;
1074             if (alignnum >= 0 && alignnum < ROLE_ALIGNS
1075                 && !(allow & aligns[alignnum].allow & ROLE_ALIGNMASK))
1076                 continue;
1077             return TRUE;
1078         }
1079         return FALSE;
1080     }
1081 }
1082
1083 /* pick a random role subject to any racenum/gendnum/alignnum constraints */
1084 /* If pickhow == PICK_RIGID a role is returned only if there is  */
1085 /* a single possibility */
1086 int
1087 pick_role(racenum, gendnum, alignnum, pickhow)
1088 int racenum, gendnum, alignnum, pickhow;
1089 {
1090     int i;
1091     int roles_ok = 0, set[SIZE(roles)];
1092
1093     for (i = 0; i < SIZE(roles) - 1; i++) {
1094         if (ok_role(i, racenum, gendnum, alignnum)
1095             && ok_race(i, (racenum >= 0) ? racenum : ROLE_RANDOM,
1096                        gendnum, alignnum)
1097             && ok_gend(i, racenum,
1098                        (gendnum >= 0) ? gendnum : ROLE_RANDOM, alignnum)
1099             && ok_race(i, racenum,
1100                        gendnum, (alignnum >= 0) ? alignnum : ROLE_RANDOM))
1101             set[roles_ok++] = i;
1102     }
1103     if (roles_ok == 0 || (roles_ok > 1 && pickhow == PICK_RIGID))
1104         return ROLE_NONE;
1105     return set[rn2(roles_ok)];
1106 }
1107
1108 /* is racenum compatible with any rolenum/gendnum/alignnum constraints? */
1109 boolean
1110 ok_race(rolenum, racenum, gendnum, alignnum)
1111 int rolenum, racenum, gendnum, alignnum;
1112 {
1113     int i;
1114     short allow;
1115
1116     if (racenum >= 0 && racenum < SIZE(races) - 1) {
1117         if (filter.mask & races[racenum].selfmask)
1118             return FALSE;
1119         allow = races[racenum].allow;
1120         if (rolenum >= 0 && rolenum < SIZE(roles) - 1
1121             && !(allow & roles[rolenum].allow & ROLE_RACEMASK))
1122             return FALSE;
1123         if (gendnum >= 0 && gendnum < ROLE_GENDERS
1124             && !(allow & genders[gendnum].allow & ROLE_GENDMASK))
1125             return FALSE;
1126         if (alignnum >= 0 && alignnum < ROLE_ALIGNS
1127             && !(allow & aligns[alignnum].allow & ROLE_ALIGNMASK))
1128             return FALSE;
1129         return TRUE;
1130     } else {
1131         /* random; check whether any selection is possible */
1132         for (i = 0; i < SIZE(races) - 1; i++) {
1133             if (filter.mask & races[i].selfmask)
1134                 continue;
1135             allow = races[i].allow;
1136             if (rolenum >= 0 && rolenum < SIZE(roles) - 1
1137                 && !(allow & roles[rolenum].allow & ROLE_RACEMASK))
1138                 continue;
1139             if (gendnum >= 0 && gendnum < ROLE_GENDERS
1140                 && !(allow & genders[gendnum].allow & ROLE_GENDMASK))
1141                 continue;
1142             if (alignnum >= 0 && alignnum < ROLE_ALIGNS
1143                 && !(allow & aligns[alignnum].allow & ROLE_ALIGNMASK))
1144                 continue;
1145             return TRUE;
1146         }
1147         return FALSE;
1148     }
1149 }
1150
1151 /* pick a random race subject to any rolenum/gendnum/alignnum constraints */
1152 /* If pickhow == PICK_RIGID a race is returned only if there is  */
1153 /* a single possibility */
1154 int
1155 pick_race(rolenum, gendnum, alignnum, pickhow)
1156 int rolenum, gendnum, alignnum, pickhow;
1157 {
1158     int i;
1159     int races_ok = 0;
1160
1161     for (i = 0; i < SIZE(races) - 1; i++) {
1162         if (ok_race(rolenum, i, gendnum, alignnum))
1163             races_ok++;
1164     }
1165     if (races_ok == 0 || (races_ok > 1 && pickhow == PICK_RIGID))
1166         return ROLE_NONE;
1167     races_ok = rn2(races_ok);
1168     for (i = 0; i < SIZE(races) - 1; i++) {
1169         if (ok_race(rolenum, i, gendnum, alignnum)) {
1170             if (races_ok == 0)
1171                 return i;
1172             else
1173                 races_ok--;
1174         }
1175     }
1176     return ROLE_NONE;
1177 }
1178
1179 /* is gendnum compatible with any rolenum/racenum/alignnum constraints? */
1180 /* gender and alignment are not comparable (and also not constrainable) */
1181 boolean
1182 ok_gend(rolenum, racenum, gendnum, alignnum)
1183 int rolenum, racenum, gendnum;
1184 int alignnum UNUSED;
1185 {
1186     int i;
1187     short allow;
1188
1189     if (gendnum >= 0 && gendnum < ROLE_GENDERS) {
1190         if (filter.mask & genders[gendnum].allow)
1191             return FALSE;
1192         allow = genders[gendnum].allow;
1193         if (rolenum >= 0 && rolenum < SIZE(roles) - 1
1194             && !(allow & roles[rolenum].allow & ROLE_GENDMASK))
1195             return FALSE;
1196         if (racenum >= 0 && racenum < SIZE(races) - 1
1197             && !(allow & races[racenum].allow & ROLE_GENDMASK))
1198             return FALSE;
1199         return TRUE;
1200     } else {
1201         /* random; check whether any selection is possible */
1202         for (i = 0; i < ROLE_GENDERS; i++) {
1203             if (filter.mask & genders[i].allow)
1204                 continue;
1205             allow = genders[i].allow;
1206             if (rolenum >= 0 && rolenum < SIZE(roles) - 1
1207                 && !(allow & roles[rolenum].allow & ROLE_GENDMASK))
1208                 continue;
1209             if (racenum >= 0 && racenum < SIZE(races) - 1
1210                 && !(allow & races[racenum].allow & ROLE_GENDMASK))
1211                 continue;
1212             return TRUE;
1213         }
1214         return FALSE;
1215     }
1216 }
1217
1218 /* pick a random gender subject to any rolenum/racenum/alignnum constraints */
1219 /* gender and alignment are not comparable (and also not constrainable) */
1220 /* If pickhow == PICK_RIGID a gender is returned only if there is  */
1221 /* a single possibility */
1222 int
1223 pick_gend(rolenum, racenum, alignnum, pickhow)
1224 int rolenum, racenum, alignnum, pickhow;
1225 {
1226     int i;
1227     int gends_ok = 0;
1228
1229     for (i = 0; i < ROLE_GENDERS; i++) {
1230         if (ok_gend(rolenum, racenum, i, alignnum))
1231             gends_ok++;
1232     }
1233     if (gends_ok == 0 || (gends_ok > 1 && pickhow == PICK_RIGID))
1234         return ROLE_NONE;
1235     gends_ok = rn2(gends_ok);
1236     for (i = 0; i < ROLE_GENDERS; i++) {
1237         if (ok_gend(rolenum, racenum, i, alignnum)) {
1238             if (gends_ok == 0)
1239                 return i;
1240             else
1241                 gends_ok--;
1242         }
1243     }
1244     return ROLE_NONE;
1245 }
1246
1247 /* is alignnum compatible with any rolenum/racenum/gendnum constraints? */
1248 /* alignment and gender are not comparable (and also not constrainable) */
1249 boolean
1250 ok_align(rolenum, racenum, gendnum, alignnum)
1251 int rolenum, racenum;
1252 int gendnum UNUSED;
1253 int alignnum;
1254 {
1255     int i;
1256     short allow;
1257
1258     if (alignnum >= 0 && alignnum < ROLE_ALIGNS) {
1259         if (filter.mask & aligns[alignnum].allow)
1260             return FALSE;
1261         allow = aligns[alignnum].allow;
1262         if (rolenum >= 0 && rolenum < SIZE(roles) - 1
1263             && !(allow & roles[rolenum].allow & ROLE_ALIGNMASK))
1264             return FALSE;
1265         if (racenum >= 0 && racenum < SIZE(races) - 1
1266             && !(allow & races[racenum].allow & ROLE_ALIGNMASK))
1267             return FALSE;
1268         return TRUE;
1269     } else {
1270         /* random; check whether any selection is possible */
1271         for (i = 0; i < ROLE_ALIGNS; i++) {
1272             if (filter.mask & aligns[i].allow)
1273                 return FALSE;
1274             allow = aligns[i].allow;
1275             if (rolenum >= 0 && rolenum < SIZE(roles) - 1
1276                 && !(allow & roles[rolenum].allow & ROLE_ALIGNMASK))
1277                 continue;
1278             if (racenum >= 0 && racenum < SIZE(races) - 1
1279                 && !(allow & races[racenum].allow & ROLE_ALIGNMASK))
1280                 continue;
1281             return TRUE;
1282         }
1283         return FALSE;
1284     }
1285 }
1286
1287 /* pick a random alignment subject to any rolenum/racenum/gendnum constraints
1288  */
1289 /* alignment and gender are not comparable (and also not constrainable) */
1290 /* If pickhow == PICK_RIGID an alignment is returned only if there is  */
1291 /* a single possibility */
1292 int
1293 pick_align(rolenum, racenum, gendnum, pickhow)
1294 int rolenum, racenum, gendnum, pickhow;
1295 {
1296     int i;
1297     int aligns_ok = 0;
1298
1299     for (i = 0; i < ROLE_ALIGNS; i++) {
1300         if (ok_align(rolenum, racenum, gendnum, i))
1301             aligns_ok++;
1302     }
1303     if (aligns_ok == 0 || (aligns_ok > 1 && pickhow == PICK_RIGID))
1304         return ROLE_NONE;
1305     aligns_ok = rn2(aligns_ok);
1306     for (i = 0; i < ROLE_ALIGNS; i++) {
1307         if (ok_align(rolenum, racenum, gendnum, i)) {
1308             if (aligns_ok == 0)
1309                 return i;
1310             else
1311                 aligns_ok--;
1312         }
1313     }
1314     return ROLE_NONE;
1315 }
1316
1317 void
1318 rigid_role_checks()
1319 {
1320     /* Some roles are limited to a single race, alignment, or gender and
1321      * calling this routine prior to XXX_player_selection() will help
1322      * prevent an extraneous prompt that actually doesn't allow
1323      * you to choose anything further. Note the use of PICK_RIGID which
1324      * causes the pick_XX() routine to return a value only if there is one
1325      * single possible selection, otherwise it returns ROLE_NONE.
1326      *
1327      */
1328     if (flags.initrole == ROLE_RANDOM) {
1329         /* If the role was explicitly specified as ROLE_RANDOM
1330          * via -uXXXX-@ then choose the role in here to narrow down
1331          * later choices. Pick a random role in this case.
1332          */
1333         flags.initrole = pick_role(flags.initrace, flags.initgend,
1334                                    flags.initalign, PICK_RANDOM);
1335         if (flags.initrole < 0)
1336             flags.initrole = randrole_filtered();
1337     }
1338     if (flags.initrole != ROLE_NONE) {
1339         if (flags.initrace == ROLE_NONE)
1340             flags.initrace = pick_race(flags.initrole, flags.initgend,
1341                                        flags.initalign, PICK_RIGID);
1342         if (flags.initalign == ROLE_NONE)
1343             flags.initalign = pick_align(flags.initrole, flags.initrace,
1344                                          flags.initgend, PICK_RIGID);
1345         if (flags.initgend == ROLE_NONE)
1346             flags.initgend = pick_gend(flags.initrole, flags.initrace,
1347                                        flags.initalign, PICK_RIGID);
1348     }
1349 }
1350
1351 boolean
1352 setrolefilter(bufp)
1353 const char *bufp;
1354 {
1355     int i;
1356     boolean reslt = TRUE;
1357
1358     if ((i = str2role(bufp)) != ROLE_NONE && i != ROLE_RANDOM)
1359         filter.roles[i] = TRUE;
1360     else if ((i = str2race(bufp)) != ROLE_NONE && i != ROLE_RANDOM)
1361         filter.mask |= races[i].selfmask;
1362     else if ((i = str2gend(bufp)) != ROLE_NONE && i != ROLE_RANDOM)
1363         filter.mask |= genders[i].allow;
1364     else if ((i = str2align(bufp)) != ROLE_NONE && i != ROLE_RANDOM)
1365         filter.mask |= aligns[i].allow;
1366     else
1367         reslt = FALSE;
1368     return reslt;
1369 }
1370
1371 boolean
1372 gotrolefilter()
1373 {
1374     int i;
1375
1376     if (filter.mask)
1377         return TRUE;
1378     for (i = 0; i < SIZE(roles); ++i)
1379         if (filter.roles[i])
1380             return TRUE;
1381     return FALSE;
1382 }
1383
1384 void
1385 clearrolefilter()
1386 {
1387     int i;
1388
1389     for (i = 0; i < SIZE(roles); ++i)
1390         filter.roles[i] = FALSE;
1391     filter.mask = 0;
1392 }
1393
1394 #define BP_ALIGN 0
1395 #define BP_GEND 1
1396 #define BP_RACE 2
1397 #define BP_ROLE 3
1398 #define NUM_BP 4
1399
1400 STATIC_VAR char pa[NUM_BP], post_attribs;
1401
1402 STATIC_OVL char *
1403 promptsep(buf, num_post_attribs)
1404 char *buf;
1405 int num_post_attribs;
1406 {
1407     const char *conjuct = "and ";
1408
1409     if (num_post_attribs > 1 && post_attribs < num_post_attribs
1410         && post_attribs > 1)
1411         Strcat(buf, ",");
1412     Strcat(buf, " ");
1413     --post_attribs;
1414     if (!post_attribs && num_post_attribs > 1)
1415         Strcat(buf, conjuct);
1416     return buf;
1417 }
1418
1419 STATIC_OVL int
1420 role_gendercount(rolenum)
1421 int rolenum;
1422 {
1423     int gendcount = 0;
1424
1425     if (validrole(rolenum)) {
1426         if (roles[rolenum].allow & ROLE_MALE)
1427             ++gendcount;
1428         if (roles[rolenum].allow & ROLE_FEMALE)
1429             ++gendcount;
1430         if (roles[rolenum].allow & ROLE_NEUTER)
1431             ++gendcount;
1432     }
1433     return gendcount;
1434 }
1435
1436 STATIC_OVL int
1437 race_alignmentcount(racenum)
1438 int racenum;
1439 {
1440     int aligncount = 0;
1441
1442     if (racenum != ROLE_NONE && racenum != ROLE_RANDOM) {
1443         if (races[racenum].allow & ROLE_CHAOTIC)
1444             ++aligncount;
1445         if (races[racenum].allow & ROLE_LAWFUL)
1446             ++aligncount;
1447         if (races[racenum].allow & ROLE_NEUTRAL)
1448             ++aligncount;
1449     }
1450     return aligncount;
1451 }
1452
1453 char *
1454 root_plselection_prompt(suppliedbuf, buflen, rolenum, racenum, gendnum,
1455                         alignnum)
1456 char *suppliedbuf;
1457 int buflen, rolenum, racenum, gendnum, alignnum;
1458 {
1459     int k, gendercount = 0, aligncount = 0;
1460     char buf[BUFSZ];
1461     static char err_ret[] = " character's";
1462     boolean donefirst = FALSE;
1463
1464     if (!suppliedbuf || buflen < 1)
1465         return err_ret;
1466
1467     /* initialize these static variables each time this is called */
1468     post_attribs = 0;
1469     for (k = 0; k < NUM_BP; ++k)
1470         pa[k] = 0;
1471     buf[0] = '\0';
1472     *suppliedbuf = '\0';
1473
1474     /* How many alignments are allowed for the desired race? */
1475     if (racenum != ROLE_NONE && racenum != ROLE_RANDOM)
1476         aligncount = race_alignmentcount(racenum);
1477
1478     if (alignnum != ROLE_NONE && alignnum != ROLE_RANDOM
1479         && ok_align(rolenum, racenum, gendnum, alignnum)) {
1480         /* if race specified, and multiple choice of alignments for it */
1481         if ((racenum >= 0) && (aligncount > 1)) {
1482             if (donefirst)
1483                 Strcat(buf, " ");
1484             Strcat(buf, aligns[alignnum].adj);
1485             donefirst = TRUE;
1486         } else {
1487             if (donefirst)
1488                 Strcat(buf, " ");
1489             Strcat(buf, aligns[alignnum].adj);
1490             donefirst = TRUE;
1491         }
1492     } else {
1493         /* in case we got here by failing the ok_align() test */
1494         if (alignnum != ROLE_RANDOM)
1495             alignnum = ROLE_NONE;
1496         /* if alignment not specified, but race is specified
1497            and only one choice of alignment for that race then
1498            don't include it in the later list */
1499         if ((((racenum != ROLE_NONE && racenum != ROLE_RANDOM)
1500               && ok_race(rolenum, racenum, gendnum, alignnum))
1501              && (aligncount > 1))
1502             || (racenum == ROLE_NONE || racenum == ROLE_RANDOM)) {
1503             pa[BP_ALIGN] = 1;
1504             post_attribs++;
1505         }
1506     }
1507     /* <your lawful> */
1508
1509     /* How many genders are allowed for the desired role? */
1510     if (validrole(rolenum))
1511         gendercount = role_gendercount(rolenum);
1512
1513     if (gendnum != ROLE_NONE && gendnum != ROLE_RANDOM) {
1514         if (validrole(rolenum)) {
1515             /* if role specified, and multiple choice of genders for it,
1516                and name of role itself does not distinguish gender */
1517             if ((rolenum != ROLE_NONE) && (gendercount > 1)
1518                 && !roles[rolenum].name.f) {
1519                 if (donefirst)
1520                     Strcat(buf, " ");
1521                 Strcat(buf, genders[gendnum].adj);
1522                 donefirst = TRUE;
1523             }
1524         } else {
1525             if (donefirst)
1526                 Strcat(buf, " ");
1527             Strcat(buf, genders[gendnum].adj);
1528             donefirst = TRUE;
1529         }
1530     } else {
1531         /* if gender not specified, but role is specified
1532                 and only one choice of gender then
1533                 don't include it in the later list */
1534         if ((validrole(rolenum) && (gendercount > 1))
1535             || !validrole(rolenum)) {
1536             pa[BP_GEND] = 1;
1537             post_attribs++;
1538         }
1539     }
1540     /* <your lawful female> */
1541
1542     if (racenum != ROLE_NONE && racenum != ROLE_RANDOM) {
1543         if (validrole(rolenum)
1544             && ok_race(rolenum, racenum, gendnum, alignnum)) {
1545             if (donefirst)
1546                 Strcat(buf, " ");
1547             Strcat(buf, (rolenum == ROLE_NONE) ? races[racenum].noun
1548                                                : races[racenum].adj);
1549             donefirst = TRUE;
1550         } else if (!validrole(rolenum)) {
1551             if (donefirst)
1552                 Strcat(buf, " ");
1553             Strcat(buf, races[racenum].noun);
1554             donefirst = TRUE;
1555         } else {
1556             pa[BP_RACE] = 1;
1557             post_attribs++;
1558         }
1559     } else {
1560         pa[BP_RACE] = 1;
1561         post_attribs++;
1562     }
1563     /* <your lawful female gnomish> || <your lawful female gnome> */
1564
1565     if (validrole(rolenum)) {
1566         if (donefirst)
1567             Strcat(buf, " ");
1568         if (gendnum != ROLE_NONE) {
1569             if (gendnum == 1 && roles[rolenum].name.f)
1570                 Strcat(buf, roles[rolenum].name.f);
1571             else
1572                 Strcat(buf, roles[rolenum].name.m);
1573         } else {
1574             if (roles[rolenum].name.f) {
1575                 Strcat(buf, roles[rolenum].name.m);
1576                 Strcat(buf, "/");
1577                 Strcat(buf, roles[rolenum].name.f);
1578             } else
1579                 Strcat(buf, roles[rolenum].name.m);
1580         }
1581         donefirst = TRUE;
1582     } else if (rolenum == ROLE_NONE) {
1583         pa[BP_ROLE] = 1;
1584         post_attribs++;
1585     }
1586
1587     if ((racenum == ROLE_NONE || racenum == ROLE_RANDOM)
1588         && !validrole(rolenum)) {
1589         if (donefirst)
1590             Strcat(buf, " ");
1591         Strcat(buf, "character");
1592         donefirst = TRUE;
1593     }
1594     /* <your lawful female gnomish cavewoman> || <your lawful female gnome>
1595      *    || <your lawful female character>
1596      */
1597     if (buflen > (int) (strlen(buf) + 1)) {
1598         Strcpy(suppliedbuf, buf);
1599         return suppliedbuf;
1600     } else
1601         return err_ret;
1602 }
1603
1604 char *
1605 build_plselection_prompt(buf, buflen, rolenum, racenum, gendnum, alignnum)
1606 char *buf;
1607 int buflen, rolenum, racenum, gendnum, alignnum;
1608 {
1609     const char *defprompt = "Shall I pick a character for you? [ynaq] ";
1610     int num_post_attribs = 0;
1611     char tmpbuf[BUFSZ], *p;
1612
1613     if (buflen < QBUFSZ)
1614         return (char *) defprompt;
1615
1616     Strcpy(tmpbuf, "Shall I pick ");
1617     if (racenum != ROLE_NONE || validrole(rolenum))
1618         Strcat(tmpbuf, "your ");
1619     else {
1620         Strcat(tmpbuf, "a ");
1621     }
1622     /* <your> */
1623
1624     (void) root_plselection_prompt(eos(tmpbuf), buflen - strlen(tmpbuf),
1625                                    rolenum, racenum, gendnum, alignnum);
1626     Sprintf(buf, "%s", s_suffix(tmpbuf));
1627     /* don't bother splitting caveman/cavewoman or priest/priestess
1628        in order to apply possessive suffix to both halves, but do
1629        change "priest/priestess'" to "priest/priestess's" */
1630     if ((p = strstri(buf, "priest/priestess'")) != 0
1631         && p[sizeof "priest/priestess'" - sizeof ""] == '\0')
1632         strkitten(buf, 's');
1633
1634     /* buf should now be:
1635      *    <your lawful female gnomish cavewoman's>
1636      * || <your lawful female gnome's>
1637      * || <your lawful female character's>
1638      *
1639      * Now append the post attributes to it
1640      */
1641     num_post_attribs = post_attribs;
1642     if (post_attribs) {
1643         if (pa[BP_RACE]) {
1644             (void) promptsep(eos(buf), num_post_attribs);
1645             Strcat(buf, "race");
1646         }
1647         if (pa[BP_ROLE]) {
1648             (void) promptsep(eos(buf), num_post_attribs);
1649             Strcat(buf, "role");
1650         }
1651         if (pa[BP_GEND]) {
1652             (void) promptsep(eos(buf), num_post_attribs);
1653             Strcat(buf, "gender");
1654         }
1655         if (pa[BP_ALIGN]) {
1656             (void) promptsep(eos(buf), num_post_attribs);
1657             Strcat(buf, "alignment");
1658         }
1659     }
1660     Strcat(buf, " for you? [ynaq] ");
1661     return buf;
1662 }
1663
1664 #undef BP_ALIGN
1665 #undef BP_GEND
1666 #undef BP_RACE
1667 #undef BP_ROLE
1668 #undef NUM_BP
1669
1670 void
1671 plnamesuffix()
1672 {
1673     char *sptr, *eptr;
1674     int i;
1675
1676 #ifdef GENERIC_USERNAMES
1677     {
1678         /* some generic user names will be ignored in favor of prompting */
1679         const char *uptr = GENERIC_USERNAMES;
1680
1681         i = (int) strlen(plname);
1682         if ((sptr = strstri(uptr, plname)) != 0
1683             && (sptr == uptr || sptr[-1] == ' ')
1684             && (sptr[i] == ' ' || sptr[i] == '\0'))
1685             *plname = '\0'; /* call askname() */
1686     }
1687 #endif
1688
1689     do {
1690         if (!*plname)
1691             askname(); /* fill plname[] if necessary */
1692
1693         /* Look for tokens delimited by '-' */
1694         if ((eptr = index(plname, '-')) != (char *) 0)
1695             *eptr++ = '\0';
1696         while (eptr) {
1697             /* Isolate the next token */
1698             sptr = eptr;
1699             if ((eptr = index(sptr, '-')) != (char *) 0)
1700                 *eptr++ = '\0';
1701
1702             /* Try to match it to something */
1703             if ((i = str2role(sptr)) != ROLE_NONE)
1704                 flags.initrole = i;
1705             else if ((i = str2race(sptr)) != ROLE_NONE)
1706                 flags.initrace = i;
1707             else if ((i = str2gend(sptr)) != ROLE_NONE)
1708                 flags.initgend = i;
1709             else if ((i = str2align(sptr)) != ROLE_NONE)
1710                 flags.initalign = i;
1711         }
1712     } while (!*plname);
1713
1714     /* commas in the plname confuse the record file, convert to spaces */
1715     for (sptr = plname; *sptr; sptr++) {
1716         if (*sptr == ',')
1717             *sptr = ' ';
1718     }
1719 }
1720
1721 /* show current settings for name, role, race, gender, and alignment
1722    in the specified window */
1723 void
1724 role_selection_prolog(which, where)
1725 int which;
1726 winid where;
1727 {
1728     static const char NEARDATA choosing[] = " choosing now",
1729                                not_yet[] = " not yet specified",
1730                                rand_choice[] = " random";
1731     char buf[BUFSZ];
1732     int r, c, g, a, allowmask;
1733
1734     r = flags.initrole;
1735     c = flags.initrace;
1736     g = flags.initgend;
1737     a = flags.initalign;
1738     if (r >= 0) {
1739         allowmask = roles[r].allow;
1740         if ((allowmask & ROLE_RACEMASK) == MH_HUMAN)
1741             c = 0; /* races[human] */
1742         else if (c >= 0 && !(allowmask & ROLE_RACEMASK & races[c].allow))
1743             c = ROLE_RANDOM;
1744         if ((allowmask & ROLE_GENDMASK) == ROLE_MALE)
1745             g = 0; /* role forces male (hypothetical) */
1746         else if ((allowmask & ROLE_GENDMASK) == ROLE_FEMALE)
1747             g = 1; /* role forces female (valkyrie) */
1748         if ((allowmask & ROLE_ALIGNMASK) == AM_LAWFUL)
1749             a = 0; /* aligns[lawful] */
1750         else if ((allowmask & ROLE_ALIGNMASK) == AM_NEUTRAL)
1751             a = 1; /* aligns[neutral] */
1752         else if ((allowmask & ROLE_ALIGNMASK) == AM_CHAOTIC)
1753             a = 2; /* alings[chaotic] */
1754     }
1755     if (c >= 0) {
1756         allowmask = races[c].allow;
1757         if ((allowmask & ROLE_ALIGNMASK) == AM_LAWFUL)
1758             a = 0; /* aligns[lawful] */
1759         else if ((allowmask & ROLE_ALIGNMASK) == AM_NEUTRAL)
1760             a = 1; /* aligns[neutral] */
1761         else if ((allowmask & ROLE_ALIGNMASK) == AM_CHAOTIC)
1762             a = 2; /* alings[chaotic] */
1763         /* [c never forces gender] */
1764     }
1765     /* [g and a don't constrain anything sufficiently
1766        to narrow something done to a single choice] */
1767
1768     Sprintf(buf, "%12s ", "name:");
1769     Strcat(buf, (which == RS_NAME) ? choosing : !*plname ? not_yet : plname);
1770     putstr(where, 0, buf);
1771     Sprintf(buf, "%12s ", "role:");
1772     Strcat(buf, (which == RS_ROLE) ? choosing : (r == ROLE_NONE)
1773                                                     ? not_yet
1774                                                     : (r == ROLE_RANDOM)
1775                                                           ? rand_choice
1776                                                           : roles[r].name.m);
1777     if (r >= 0 && roles[r].name.f) {
1778         /* distinct female name [caveman/cavewoman, priest/priestess] */
1779         if (g == 1)
1780             /* female specified; replace male role name with female one */
1781             Sprintf(index(buf, ':'), ": %s", roles[r].name.f);
1782         else if (g < 0)
1783             /* gender unspecified; append slash and female role name */
1784             Sprintf(eos(buf), "/%s", roles[r].name.f);
1785     }
1786     putstr(where, 0, buf);
1787     Sprintf(buf, "%12s ", "race:");
1788     Strcat(buf, (which == RS_RACE) ? choosing : (c == ROLE_NONE)
1789                                                     ? not_yet
1790                                                     : (c == ROLE_RANDOM)
1791                                                           ? rand_choice
1792                                                           : races[c].noun);
1793     putstr(where, 0, buf);
1794     Sprintf(buf, "%12s ", "gender:");
1795     Strcat(buf, (which == RS_GENDER) ? choosing : (g == ROLE_NONE)
1796                                                       ? not_yet
1797                                                       : (g == ROLE_RANDOM)
1798                                                             ? rand_choice
1799                                                             : genders[g].adj);
1800     putstr(where, 0, buf);
1801     Sprintf(buf, "%12s ", "alignment:");
1802     Strcat(buf, (which == RS_ALGNMNT) ? choosing : (a == ROLE_NONE)
1803                                                        ? not_yet
1804                                                        : (a == ROLE_RANDOM)
1805                                                              ? rand_choice
1806                                                              : aligns[a].adj);
1807     putstr(where, 0, buf);
1808 }
1809
1810 /* add a "pick alignment first"-type entry to the specified menu */
1811 void
1812 role_menu_extra(which, where)
1813 int which;
1814 winid where;
1815 {
1816     static NEARDATA const char RS_menu_let[] = {
1817         '=',  /* name */
1818         '?',  /* role */
1819         '/',  /* race */
1820         '\"', /* gender */
1821         '[',  /* alignment */
1822     };
1823     anything any;
1824     char buf[BUFSZ];
1825     const char *what = 0, *constrainer = 0, *forcedvalue = 0;
1826     int f = 0, r, c, g, a, i, allowmask;
1827
1828     r = flags.initrole;
1829     c = flags.initrace;
1830     switch (which) {
1831     case RS_NAME:
1832         what = "name";
1833         break;
1834     case RS_ROLE:
1835         what = "role";
1836         f = r;
1837         for (i = 0; i < SIZE(roles); ++i)
1838             if (i != f && !filter.roles[i])
1839                 break;
1840         if (i == SIZE(roles)) {
1841             constrainer = "filter";
1842             forcedvalue = "role";
1843         }
1844         break;
1845     case RS_RACE:
1846         what = "race";
1847         f = flags.initrace;
1848         c = ROLE_NONE; /* override player's setting */
1849         if (r >= 0) {
1850             allowmask = roles[r].allow & ROLE_RACEMASK;
1851             if (allowmask == MH_HUMAN)
1852                 c = 0; /* races[human] */
1853             if (c >= 0) {
1854                 constrainer = "role";
1855                 forcedvalue = races[c].noun;
1856             } else if (f >= 0
1857                        && (allowmask & ~filter.mask) == races[f].selfmask) {
1858                 /* if there is only one race choice available due to user
1859                    options disallowing others, race menu entry is disabled */
1860                 constrainer = "filter";
1861                 forcedvalue = "race";
1862             }
1863         }
1864         break;
1865     case RS_GENDER:
1866         what = "gender";
1867         f = flags.initgend;
1868         g = ROLE_NONE;
1869         if (r >= 0) {
1870             allowmask = roles[r].allow & ROLE_GENDMASK;
1871             if (allowmask == ROLE_MALE)
1872                 g = 0; /* genders[male] */
1873             else if (allowmask == ROLE_FEMALE)
1874                 g = 1; /* genders[female] */
1875             if (g >= 0) {
1876                 constrainer = "role";
1877                 forcedvalue = genders[g].adj;
1878             } else if (f >= 0
1879                        && (allowmask & ~filter.mask) == genders[f].allow) {
1880                 /* if there is only one gender choice available due to user
1881                    options disallowing other, gender menu entry is disabled */
1882                 constrainer = "filter";
1883                 forcedvalue = "gender";
1884             }
1885         }
1886         break;
1887     case RS_ALGNMNT:
1888         what = "alignment";
1889         f = flags.initalign;
1890         a = ROLE_NONE;
1891         if (r >= 0) {
1892             allowmask = roles[r].allow & ROLE_ALIGNMASK;
1893             if (allowmask == AM_LAWFUL)
1894                 a = 0; /* aligns[lawful] */
1895             else if (allowmask == AM_NEUTRAL)
1896                 a = 1; /* aligns[neutral] */
1897             else if (allowmask == AM_CHAOTIC)
1898                 a = 2; /* aligns[chaotic] */
1899             if (a >= 0)
1900                 constrainer = "role";
1901         }
1902         if (c >= 0 && !constrainer) {
1903             allowmask = races[c].allow & ROLE_ALIGNMASK;
1904             if (allowmask == AM_LAWFUL)
1905                 a = 0; /* aligns[lawful] */
1906             else if (allowmask == AM_NEUTRAL)
1907                 a = 1; /* aligns[neutral] */
1908             else if (allowmask == AM_CHAOTIC)
1909                 a = 2; /* aligns[chaotic] */
1910             if (a >= 0)
1911                 constrainer = "race";
1912         }
1913         if (f >= 0 && !constrainer
1914             && (ROLE_ALIGNMASK & ~filter.mask) == aligns[f].allow) {
1915             /* if there is only one alignment choice available due to user
1916                options disallowing others, algn menu entry is disabled */
1917             constrainer = "filter";
1918             forcedvalue = "alignment";
1919         }
1920         if (a >= 0)
1921             forcedvalue = aligns[a].adj;
1922         break;
1923     }
1924
1925     any = zeroany; /* zero out all bits */
1926     if (constrainer) {
1927         any.a_int = 0;
1928         /* use four spaces of padding to fake a grayed out menu choice */
1929         Sprintf(buf, "%4s%s forces %s", "", constrainer, forcedvalue);
1930         add_menu(where, NO_GLYPH, &any, ' ', 0, ATR_NONE, buf,
1931                  MENU_UNSELECTED);
1932     } else if (what) {
1933         any.a_int = RS_menu_arg(which);
1934         Sprintf(buf, "Pick%s %s first", (f >= 0) ? " another" : "", what);
1935         add_menu(where, NO_GLYPH, &any, RS_menu_let[which], 0, ATR_NONE, buf,
1936                  MENU_UNSELECTED);
1937     } else if (which == RS_filter) {
1938         any.a_int = RS_menu_arg(RS_filter);
1939         add_menu(where, NO_GLYPH, &any, '~', 0, ATR_NONE,
1940                  "Reset role/race/&c filtering", MENU_UNSELECTED);
1941     } else if (which == ROLE_RANDOM) {
1942         any.a_int = ROLE_RANDOM;
1943         add_menu(where, NO_GLYPH, &any, '*', 0, ATR_NONE, "Random",
1944                  MENU_UNSELECTED);
1945     } else if (which == ROLE_NONE) {
1946         any.a_int = ROLE_NONE;
1947         add_menu(where, NO_GLYPH, &any, 'q', 0, ATR_NONE, "Quit",
1948                  MENU_UNSELECTED);
1949     } else {
1950         impossible("role_menu_extra: bad arg (%d)", which);
1951     }
1952 }
1953
1954 /*
1955  *      Special setup modifications here:
1956  *
1957  *      Unfortunately, this is going to have to be done
1958  *      on each newgame or restore, because you lose the permonst mods
1959  *      across a save/restore.  :-)
1960  *
1961  *      1 - The Rogue Leader is the Tourist Nemesis.
1962  *      2 - Priests start with a random alignment - convert the leader and
1963  *          guardians here.
1964  *      3 - Priests also get their of deities from a randomly chosen role.
1965  *      4 - [obsolete] Elves can have one of two different leaders,
1966  *          but can't work it out here because it requires hacking the
1967  *          level file data (see sp_lev.c).
1968  *
1969  * This code also replaces quest_init().
1970  */
1971 void
1972 role_init()
1973 {
1974     int alignmnt;
1975     struct permonst *pm;
1976
1977     /* Strip the role letter out of the player name.
1978      * This is included for backwards compatibility.
1979      */
1980     plnamesuffix();
1981
1982     /* Check for a valid role.  Try flags.initrole first. */
1983     if (!validrole(flags.initrole)) {
1984         /* Try the player letter second */
1985         if ((flags.initrole = str2role(pl_character)) < 0)
1986             /* None specified; pick a random role */
1987             flags.initrole = randrole_filtered();
1988     }
1989
1990     /* We now have a valid role index.  Copy the role name back. */
1991     /* This should become OBSOLETE */
1992     Strcpy(pl_character, roles[flags.initrole].name.m);
1993     pl_character[PL_CSIZ - 1] = '\0';
1994
1995     /* Check for a valid race */
1996     if (!validrace(flags.initrole, flags.initrace))
1997         flags.initrace = randrace(flags.initrole);
1998
1999     /* Check for a valid gender.  If new game, check both initgend
2000      * and female.  On restore, assume flags.female is correct. */
2001     if (flags.pantheon == -1) { /* new game */
2002         if (!validgend(flags.initrole, flags.initrace, flags.female))
2003             flags.female = !flags.female;
2004     }
2005     if (!validgend(flags.initrole, flags.initrace, flags.initgend))
2006         /* Note that there is no way to check for an unspecified gender. */
2007         flags.initgend = flags.female;
2008
2009     /* Check for a valid alignment */
2010     if (!validalign(flags.initrole, flags.initrace, flags.initalign))
2011         /* Pick a random alignment */
2012         flags.initalign = randalign(flags.initrole, flags.initrace);
2013     alignmnt = aligns[flags.initalign].value;
2014
2015     /* Initialize urole and urace */
2016     urole = roles[flags.initrole];
2017     urace = races[flags.initrace];
2018
2019     /* Fix up the quest leader */
2020     if (urole.ldrnum != NON_PM) {
2021         pm = &mons[urole.ldrnum];
2022         pm->msound = MS_LEADER;
2023         pm->mflags2 |= (M2_PEACEFUL);
2024         pm->mflags3 |= M3_CLOSE;
2025         pm->maligntyp = alignmnt * 3;
2026         /* if gender is random, we choose it now instead of waiting
2027            until the leader monster is created */
2028         quest_status.ldrgend =
2029             is_neuter(pm) ? 2 : is_female(pm) ? 1 : is_male(pm)
2030                                                         ? 0
2031                                                         : (rn2(100) < 50);
2032     }
2033
2034     /* Fix up the quest guardians */
2035     if (urole.guardnum != NON_PM) {
2036         pm = &mons[urole.guardnum];
2037         pm->mflags2 |= (M2_PEACEFUL);
2038         pm->maligntyp = alignmnt * 3;
2039     }
2040
2041     /* Fix up the quest nemesis */
2042     if (urole.neminum != NON_PM) {
2043         pm = &mons[urole.neminum];
2044         pm->msound = MS_NEMESIS;
2045         pm->mflags2 &= ~(M2_PEACEFUL);
2046         pm->mflags2 |= (M2_NASTY | M2_STALK | M2_HOSTILE);
2047         pm->mflags3 &= ~(M3_CLOSE);
2048         pm->mflags3 |= M3_WANTSARTI | M3_WAITFORU;
2049         /* if gender is random, we choose it now instead of waiting
2050            until the nemesis monster is created */
2051         quest_status.nemgend = is_neuter(pm) ? 2 : is_female(pm) ? 1
2052                                    : is_male(pm) ? 0 : (rn2(100) < 50);
2053     }
2054
2055     /* Fix up the god names */
2056     if (flags.pantheon == -1) {             /* new game */
2057         flags.pantheon = flags.initrole;    /* use own gods */
2058         while (!roles[flags.pantheon].lgod) /* unless they're missing */
2059             flags.pantheon = randrole();
2060     }
2061     if (!urole.lgod) {
2062         urole.lgod = roles[flags.pantheon].lgod;
2063         urole.ngod = roles[flags.pantheon].ngod;
2064         urole.cgod = roles[flags.pantheon].cgod;
2065     }
2066     /* 0 or 1; no gods are neuter, nor is gender randomized */
2067     quest_status.godgend = !strcmpi(align_gtitle(alignmnt), "goddess");
2068
2069     /* Fix up infravision */
2070     if (mons[urace.malenum].mflags3 & M3_INFRAVISION) {
2071         /* although an infravision intrinsic is possible, infravision
2072          * is purely a property of the physical race.  This means that we
2073          * must put the infravision flag in the player's current race
2074          * (either that or have separate permonst entries for
2075          * elven/non-elven members of each class).  The side effect is that
2076          * all NPCs of that class will have (probably bogus) infravision,
2077          * but since infravision has no effect for NPCs anyway we can
2078          * ignore this.
2079          */
2080         mons[urole.malenum].mflags3 |= M3_INFRAVISION;
2081         if (urole.femalenum != NON_PM)
2082             mons[urole.femalenum].mflags3 |= M3_INFRAVISION;
2083     }
2084
2085     /* Artifacts are fixed in hack_artifacts() */
2086
2087     /* Success! */
2088     return;
2089 }
2090
2091 const char *
2092 Hello(mtmp)
2093 struct monst *mtmp;
2094 {
2095     switch (Role_switch) {
2096     case PM_KNIGHT:
2097         return "Salutations"; /* Olde English */
2098     case PM_SAMURAI:
2099         return (mtmp && mtmp->data == &mons[PM_SHOPKEEPER])
2100                     ? "Irasshaimase"
2101                     : "Konnichi wa"; /* Japanese */
2102     case PM_TOURIST:
2103         return "Aloha"; /* Hawaiian */
2104     case PM_VALKYRIE:
2105         return
2106 #ifdef MAIL
2107                (mtmp && mtmp->data == &mons[PM_MAIL_DAEMON]) ? "Hallo" :
2108 #endif
2109                "Velkommen"; /* Norse */
2110     default:
2111         return "Hello";
2112     }
2113 }
2114
2115 const char *
2116 Goodbye()
2117 {
2118     switch (Role_switch) {
2119     case PM_KNIGHT:
2120         return "Fare thee well"; /* Olde English */
2121     case PM_SAMURAI:
2122         return "Sayonara"; /* Japanese */
2123     case PM_TOURIST:
2124         return "Aloha"; /* Hawaiian */
2125     case PM_VALKYRIE:
2126         return "Farvel"; /* Norse */
2127     default:
2128         return "Goodbye";
2129     }
2130 }
2131
2132 /* role.c */