OSDN Git Service

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