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. */
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
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
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
24 * God names use a leading underscore to flag goddesses.
26 const struct Role roles[] = {
28 { { "Archeologist", 0 },
30 { "Field Worker", 0 },
31 { "Investigator", 0 },
35 { "Speleologist", 0 },
38 "Quetzalcoatl", "Camaxtli", "Huhetotl", /* Central American */
40 { { "
\8dl
\8cÃ
\8aw
\8eÒ", 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 },
50 "Quetzalcoatl", "Camaxtli", "Huhetotl", /* Central American */
54 "the College of Archeology",
55 "the Tomb of the Toltec Kings",
57 "
\8dl
\8cÃ
\8aw
\91å
\8aw",
58 "
\83g
\83\8b\83e
\83J
\89¤
\89Æ
\82Ì
\95æ",
65 PM_MINION_OF_HUHETOTL,
71 MH_HUMAN | MH_DWARF | MH_GNOME | ROLE_MALE | ROLE_FEMALE | ROLE_LAWFUL
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 */
90 { { "Plunderer", "Plunderess" },
97 { "Chieftain", "Chieftainess" },
98 { "Conqueror", "Conqueress" } },
99 "Mitra", "Crom", "Set", /* Hyborian */
101 { { "
\96ì
\94Ø
\90l", 0 },
102 { { "
\93\90\91¯", 0 },
103 { "
\97ª
\92D
\8eÒ", 0 },
106 { "
\90N
\97ª
\8eÒ", 0 },
108 { "
\8eE
\9dC
\8eÒ", 0 },
110 { "
\90ª
\95\9e\8eÒ", 0 } },
111 "Mitra", "Crom", "Set", /* Hyborian */
115 "the Camp of the Duali Tribe",
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",
131 ART_HEART_OF_AHRIMAN,
132 MH_HUMAN | MH_ORC | ROLE_MALE | ROLE_FEMALE | ROLE_NEUTRAL
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 },
150 { { "Caveman", "Cavewoman" },
151 { { "Troglodyte", 0 },
160 "Anu", "_Ishtar", "Anshar", /* Babylonian */
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 */
176 "the Caves of the Ancestors",
179 "
\91¾
\8cÃ
\82Ì
\93´
\8cA",
180 "
\97³
\82Ì
\89B
\82ê
\89Æ",
192 ART_SCEPTRE_OF_MIGHT,
193 MH_HUMAN | MH_DWARF | MH_GNOME | ROLE_MALE | ROLE_FEMALE | ROLE_LAWFUL
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 },
212 { { "Rhizotomist", 0 },
216 { "Medicus ossium", "Medica ossium" },
218 { "Magister", "Magistra" },
220 { "Chirurgeon", 0 } },
221 "_Athena", "Hermes", "Poseidon", /* Greek */
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 */
237 "the Temple of Epidaurus",
238 "the Temple of Coeus",
240 "
\83G
\83s
\83_
\83E
\83\8d\83X
\8e\9b\89@",
241 "
\83R
\83C
\83I
\83X
\8e\9b\89@",
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 },
278 { "Chevalier", "Chevaliere" },
279 { "Seignieur", "Dame" },
281 "Lugh", "_Brigit", "Manannan Mac Lir", /* Celtic */
284 { { "
\8c©
\8fK
\82¢", 0 },
288 { "
\8fd
\90í
\8em", 0 },
290 { "
\8fd
\8bR
\8em", 0 },
291 { "
\8cM
\8bR
\8em", 0 },
292 { "
\90¹
\8bR
\8em", 0 } },
293 "Lugh", "_Brigit", "Manannan Mac Lir", /* Celtic */
300 "
\83L
\83\83\83\81\83\8d\83b
\83g
\8fé",
301 "
\83K
\83\89\83X
\82Ì
\93\87",
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 },
332 { { "Candidate", 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 },
341 "Shan Lai Ching", "Chih Sung-tzu", "Huan Ti", /* Chinese */
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 */
357 "the Monastery of Chan-Sune",
358 "the Monastery of the Earth-Lord",
360 "
\83`
\83\83\83\93\81E
\83X
\81[
\8fC
\93¹
\89@",
361 "
\92n
\89¤
\82Ì
\8fC
\93¹
\89@",
373 ART_EYES_OF_THE_OVERWORLD,
374 MH_HUMAN | ROLE_MALE | ROLE_FEMALE | ROLE_LAWFUL | ROLE_NEUTRAL
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 },
392 { { "Priest", "Priestess" },
396 { "Priest", "Priestess" },
398 { "Canon", "Canoness" },
400 { "Patriarch", "Matriarch" },
401 { "High Priest", "High Priestess" } },
402 0, 0, 0, /* deities from a randomly chosen other role will be used */
404 { { "
\91m
\97µ", "
\93ò
\91m" },
405 { { "
\8fC
\93¹
\8eÒ", "
\8fC
\93¹
\8f\97" },
408 { "
\91m
\97µ", "
\93ò
\91m" },
409 { "
\8f\95\94C
\8ei
\8dÕ", 0 },
410 { "
\90¹
\8eÒ", "
\90¹
\8f\97" },
412 { "
\91å
\8ei
\8b³", 0 },
413 { "
\91å
\91m
\8fã", 0 } },
414 0, 0, 0, /* deities from a randomly chosen other role will be used */
419 "the Temple of Nalzok",
421 "
\88Ì
\91å
\82È
\82é
\8e\9b\89@",
422 "
\83i
\83\8b\83]
\83N
\8e\9b\89@",
434 ART_MITRE_OF_HOLINESS,
435 MH_HUMAN | MH_ELF | ROLE_MALE | ROLE_FEMALE | ROLE_LAWFUL | ROLE_NEUTRAL
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 },
452 /* Note: Rogue precedes Ranger so that use of `-R' on the command line
453 retains its traditional meaning. */
463 { "Magsman", "Magswoman" },
465 "Issek", "Mog", "Kos", /* Nehwon */
467 { { "
\93\90\91¯", 0 },
468 { { "
\92Ç
\82¢
\82Í
\82¬", 0 },
469 { "
\82Ð
\82Á
\82½
\82
\82è", 0 },
471 { "
\82²
\82ë
\82Â
\82«", 0 },
472 { "
\82±
\82»
\82Ç
\82ë", 0 },
476 { "
\91å
\93D
\96_", 0 } },
477 "Issek", "Mog", "Kos", /* Nehwon */
481 "the Thieves' Guild Hall",
482 "the Assassins' Guild Hall",
484 "
\93\90\91¯
\83M
\83\8b\83h",
485 "
\88Ã
\8eE
\8eÒ
\83M
\83\8b\83h",
490 PM_MASTER_OF_THIEVES,
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 },
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 */
532 { "Trailblazer", 0 },
533 { "Reconnoiterer", "Reconnoiteress" },
535 { "Arbalester", 0 }, /* One skilled at crossbows */
537 { "Sharpshooter", 0 },
538 { "Marksman", "Markswoman" } },
539 "Mercury", "_Venus", "Mars", /* Roman/planets */
541 { { "
\83\8c\83\93\83W
\83\83\81[", 0 },
543 { "
\8c©
\92£
\82è", 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 */
556 "the cave of the wumpus",
558 "
\83I
\83\8a\83I
\83\93\82Ì
\83L
\83\83\83\93\83v",
559 "
\83\8f\83\93\83p
\83X
\82Ì
\93´
\8cA",
563 PM_LITTLE_DOG /* Orion & canis major */,
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 },
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 */
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 */
616 "the Castle of the Taro Clan",
617 "the Shogun's Castle",
619 "
\91¾
\98Y
\88ê
\91°
\82Ì
\8fé",
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 },
653 { "Excursionist", 0 },
654 { "Peregrinator", "Peregrinatrix" },
659 { "Adventurer", 0 } },
660 "Blind Io", "_The Lady", "Offler", /* Discworld */
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 },
669 { "
\8dq
\8aC
\8eÒ", 0 },
670 { "
\92T
\8c\9f\89Æ", 0 },
671 { "
\96`
\8c¯
\8eÒ", 0 } },
672 "Blind Io", "_The Lady", "Offler", /* Discworld */
677 "the Thieves' Guild Hall",
680 "
\93\90\91¯
\83M
\83\8b\83h",
687 PM_MASTER_OF_THIEVES,
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 },
711 { { "Stripling", 0 },
714 { "Man-at-arms", "Woman-at-arms" },
716 { "Swashbuckler", 0 },
717 { "Hero", "Heroine" },
719 { "Lord", "Lady" } },
720 "Tyr", "Odin", "Loki", /* Norse */
722 { { "
\83\8f\83\8b\83L
\83\85\81[
\83\8c", 0 },
723 { { "
\8c©
\8fK
\82¢", 0 },
727 { "
\90í
\93¬
\95º", 0 },
728 { "
\8dU
\8c\82\95º", 0 },
730 { "
\90æ
\93±
\8eÒ", 0 },
731 { "
\83\8d\81[
\83h", "
\83\8c\83f
\83B" } },
732 "Tyr", "Odin", "Loki", /* Norse */
736 "the Shrine of Destiny",
737 "the cave of Surtur",
739 "
\89^
\96½
\82Ì
\90¹
\93°",
740 "
\83X
\83\8b\83g
\82Ì
\93´
\8cA",
744 NON_PM /*PM_WINTER_WOLF_CUB*/,
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 },
773 { "Thaumaturge", 0 },
775 { "Enchanter", "Enchantress" },
776 { "Sorcerer", "Sorceress" },
777 { "Necromancer", 0 },
780 "Ptah", "Thoth", "Anhur", /* Egyptian */
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 */
797 "the Tower of Darkness",
799 "
\8cÇ
\8d\82\82Ì
\93\83",
800 "
\88Ã
\8d\95\82Ì
\93\83",
805 PM_NEFERET_THE_GREEN,
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 },
830 /* Array terminator */
834 /* The player's role, created at runtime from initial
835 * choices. This may be munged in role_init().
837 struct Role urole = {
839 { { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 },
840 { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 } },
842 "Xxx", "home", "locate",
843 NON_PM, NON_PM, NON_PM, NON_PM, NON_PM, NON_PM, NON_PM, NON_PM,
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 },
862 /* Table of all races */
863 const struct Race races[] = {
874 MH_HUMAN | ROLE_MALE | ROLE_FEMALE | ROLE_LAWFUL | ROLE_NEUTRAL
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 */
896 MH_ELF | ROLE_MALE | ROLE_FEMALE | ROLE_CHAOTIC,
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 */
917 MH_DWARF | ROLE_MALE | ROLE_FEMALE | ROLE_LAWFUL,
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 */
938 MH_GNOME | ROLE_MALE | ROLE_FEMALE | ROLE_NEUTRAL,
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 */
959 MH_ORC | ROLE_MALE | ROLE_FEMALE | ROLE_CHAOTIC,
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 */
970 /* Array terminator */
974 /* The player's race, created at runtime from initial
975 * choices. This may be munged in role_init().
977 struct Race urace = {
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 */
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 }
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 }
1016 boolean roles[SIZE(roles)];
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));
1025 /* used by str2XXX() */
1026 static char NEARDATA randomstr[] = "random";
1032 return (boolean) (rolenum >= 0 && rolenum < SIZE(roles) - 1);
1038 return rn2(SIZE(roles) - 1);
1044 int i, n = 0, set[SIZE(roles)];
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))
1054 return n ? set[rn2(n)] : randrole();
1064 if (!str || !str[0])
1067 /* Match as much of str as is provided */
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))
1073 /* Or the female name? */
1074 if (roles[i].name.f && !strncmpi(str, roles[i].name.f, len))
1076 /* Or the filecode? */
1077 if (!strcmpi(str, roles[i].filecode))
1081 if ((len == 1 && (*str == '*' || *str == '@'))
1082 || !strncmpi(str, randomstr, len))
1085 /* Couldn't find anything appropriate */
1090 validrace(rolenum, racenum)
1091 int rolenum, racenum;
1093 /* Assumes validrole */
1094 return (boolean) (racenum >= 0 && racenum < SIZE(races) - 1
1095 && (roles[rolenum].allow & races[racenum].allow
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)
1110 /* Pick a random race */
1111 /* Use a factor of 100 in case of bad random number generators */
1113 n = rn2(n * 100) / 100;
1114 for (i = 0; races[i].noun; i++)
1115 if (roles[rolenum].allow & races[i].allow & ROLE_RACEMASK) {
1122 /* This role has no permitted races? */
1123 return rn2(SIZE(races) - 1);
1133 if (!str || !str[0])
1136 /* Match as much of str as is provided */
1138 for (i = 0; races[i].noun; i++) {
1139 /* Does it match the noun? */
1140 if (!strncmpi(str, races[i].noun, len))
1142 /* Or the filecode? */
1143 if (!strcmpi(str, races[i].filecode))
1147 if ((len == 1 && (*str == '*' || *str == '@'))
1148 || !strncmpi(str, randomstr, len))
1151 /* Couldn't find anything appropriate */
1156 validgend(rolenum, racenum, gendnum)
1157 int rolenum, racenum, gendnum;
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));
1166 randgend(rolenum, racenum)
1167 int rolenum, racenum;
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
1177 /* Pick a random gender */
1180 for (i = 0; i < ROLE_GENDERS; i++)
1181 if (roles[rolenum].allow & races[racenum].allow & genders[i].allow
1189 /* This role/race has no permitted genders? */
1190 return rn2(ROLE_GENDERS);
1200 if (!str || !str[0])
1203 /* Match as much of str as is provided */
1205 for (i = 0; i < ROLE_GENDERS; i++) {
1206 /* Does it match the adjective? */
1207 if (!strncmpi(str, genders[i].adj, len))
1209 /* Or the filecode? */
1210 if (!strcmpi(str, genders[i].filecode))
1213 if ((len == 1 && (*str == '*' || *str == '@'))
1214 || !strncmpi(str, randomstr, len))
1217 /* Couldn't find anything appropriate */
1222 validalign(rolenum, racenum, alignnum)
1223 int rolenum, racenum, alignnum;
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));
1232 randalign(rolenum, racenum)
1233 int rolenum, racenum;
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
1243 /* Pick a random alignment */
1246 for (i = 0; i < ROLE_ALIGNS; i++)
1247 if (roles[rolenum].allow & races[racenum].allow & aligns[i].allow
1255 /* This role/race has no permitted alignments? */
1256 return rn2(ROLE_ALIGNS);
1266 if (!str || !str[0])
1269 /* Match as much of str as is provided */
1271 for (i = 0; i < ROLE_ALIGNS; i++) {
1272 /* Does it match the adjective? */
1273 if (!strncmpi(str, aligns[i].adj, len))
1275 /* Or the filecode? */
1276 if (!strcmpi(str, aligns[i].filecode))
1279 if ((len == 1 && (*str == '*' || *str == '@'))
1280 || !strncmpi(str, randomstr, len))
1283 /* Couldn't find anything appropriate */
1287 /* is rolenum compatible with any racenum/gendnum/alignnum constraints? */
1289 ok_role(rolenum, racenum, gendnum, alignnum)
1290 int rolenum, racenum, gendnum, alignnum;
1295 if (rolenum >= 0 && rolenum < SIZE(roles) - 1) {
1296 if (filter.roles[rolenum])
1298 allow = roles[rolenum].allow;
1299 if (racenum >= 0 && racenum < SIZE(races) - 1
1300 && !(allow & races[racenum].allow & ROLE_RACEMASK))
1302 if (gendnum >= 0 && gendnum < ROLE_GENDERS
1303 && !(allow & genders[gendnum].allow & ROLE_GENDMASK))
1305 if (alignnum >= 0 && alignnum < ROLE_ALIGNS
1306 && !(allow & aligns[alignnum].allow & ROLE_ALIGNMASK))
1310 /* random; check whether any selection is possible */
1311 for (i = 0; i < SIZE(roles) - 1; i++) {
1312 if (filter.roles[i])
1314 allow = roles[i].allow;
1315 if (racenum >= 0 && racenum < SIZE(races) - 1
1316 && !(allow & races[racenum].allow & ROLE_RACEMASK))
1318 if (gendnum >= 0 && gendnum < ROLE_GENDERS
1319 && !(allow & genders[gendnum].allow & ROLE_GENDMASK))
1321 if (alignnum >= 0 && alignnum < ROLE_ALIGNS
1322 && !(allow & aligns[alignnum].allow & ROLE_ALIGNMASK))
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 */
1334 pick_role(racenum, gendnum, alignnum, pickhow)
1335 int racenum, gendnum, alignnum, pickhow;
1338 int roles_ok = 0, set[SIZE(roles)];
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,
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;
1350 if (roles_ok == 0 || (roles_ok > 1 && pickhow == PICK_RIGID))
1352 return set[rn2(roles_ok)];
1355 /* is racenum compatible with any rolenum/gendnum/alignnum constraints? */
1357 ok_race(rolenum, racenum, gendnum, alignnum)
1358 int rolenum, racenum, gendnum, alignnum;
1363 if (racenum >= 0 && racenum < SIZE(races) - 1) {
1364 if (filter.mask & races[racenum].selfmask)
1366 allow = races[racenum].allow;
1367 if (rolenum >= 0 && rolenum < SIZE(roles) - 1
1368 && !(allow & roles[rolenum].allow & ROLE_RACEMASK))
1370 if (gendnum >= 0 && gendnum < ROLE_GENDERS
1371 && !(allow & genders[gendnum].allow & ROLE_GENDMASK))
1373 if (alignnum >= 0 && alignnum < ROLE_ALIGNS
1374 && !(allow & aligns[alignnum].allow & ROLE_ALIGNMASK))
1378 /* random; check whether any selection is possible */
1379 for (i = 0; i < SIZE(races) - 1; i++) {
1380 if (filter.mask & races[i].selfmask)
1382 allow = races[i].allow;
1383 if (rolenum >= 0 && rolenum < SIZE(roles) - 1
1384 && !(allow & roles[rolenum].allow & ROLE_RACEMASK))
1386 if (gendnum >= 0 && gendnum < ROLE_GENDERS
1387 && !(allow & genders[gendnum].allow & ROLE_GENDMASK))
1389 if (alignnum >= 0 && alignnum < ROLE_ALIGNS
1390 && !(allow & aligns[alignnum].allow & ROLE_ALIGNMASK))
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 */
1402 pick_race(rolenum, gendnum, alignnum, pickhow)
1403 int rolenum, gendnum, alignnum, pickhow;
1408 for (i = 0; i < SIZE(races) - 1; i++) {
1409 if (ok_race(rolenum, i, gendnum, alignnum))
1412 if (races_ok == 0 || (races_ok > 1 && pickhow == PICK_RIGID))
1414 races_ok = rn2(races_ok);
1415 for (i = 0; i < SIZE(races) - 1; i++) {
1416 if (ok_race(rolenum, i, gendnum, alignnum)) {
1426 /* is gendnum compatible with any rolenum/racenum/alignnum constraints? */
1427 /* gender and alignment are not comparable (and also not constrainable) */
1429 ok_gend(rolenum, racenum, gendnum, alignnum)
1430 int rolenum, racenum, gendnum;
1431 int alignnum UNUSED;
1436 if (gendnum >= 0 && gendnum < ROLE_GENDERS) {
1437 if (filter.mask & genders[gendnum].allow)
1439 allow = genders[gendnum].allow;
1440 if (rolenum >= 0 && rolenum < SIZE(roles) - 1
1441 && !(allow & roles[rolenum].allow & ROLE_GENDMASK))
1443 if (racenum >= 0 && racenum < SIZE(races) - 1
1444 && !(allow & races[racenum].allow & ROLE_GENDMASK))
1448 /* random; check whether any selection is possible */
1449 for (i = 0; i < ROLE_GENDERS; i++) {
1450 if (filter.mask & genders[i].allow)
1452 allow = genders[i].allow;
1453 if (rolenum >= 0 && rolenum < SIZE(roles) - 1
1454 && !(allow & roles[rolenum].allow & ROLE_GENDMASK))
1456 if (racenum >= 0 && racenum < SIZE(races) - 1
1457 && !(allow & races[racenum].allow & ROLE_GENDMASK))
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 */
1470 pick_gend(rolenum, racenum, alignnum, pickhow)
1471 int rolenum, racenum, alignnum, pickhow;
1476 for (i = 0; i < ROLE_GENDERS; i++) {
1477 if (ok_gend(rolenum, racenum, i, alignnum))
1480 if (gends_ok == 0 || (gends_ok > 1 && pickhow == PICK_RIGID))
1482 gends_ok = rn2(gends_ok);
1483 for (i = 0; i < ROLE_GENDERS; i++) {
1484 if (ok_gend(rolenum, racenum, i, alignnum)) {
1494 /* is alignnum compatible with any rolenum/racenum/gendnum constraints? */
1495 /* alignment and gender are not comparable (and also not constrainable) */
1497 ok_align(rolenum, racenum, gendnum, alignnum)
1498 int rolenum, racenum;
1505 if (alignnum >= 0 && alignnum < ROLE_ALIGNS) {
1506 if (filter.mask & aligns[alignnum].allow)
1508 allow = aligns[alignnum].allow;
1509 if (rolenum >= 0 && rolenum < SIZE(roles) - 1
1510 && !(allow & roles[rolenum].allow & ROLE_ALIGNMASK))
1512 if (racenum >= 0 && racenum < SIZE(races) - 1
1513 && !(allow & races[racenum].allow & ROLE_ALIGNMASK))
1517 /* random; check whether any selection is possible */
1518 for (i = 0; i < ROLE_ALIGNS; i++) {
1519 if (filter.mask & aligns[i].allow)
1521 allow = aligns[i].allow;
1522 if (rolenum >= 0 && rolenum < SIZE(roles) - 1
1523 && !(allow & roles[rolenum].allow & ROLE_ALIGNMASK))
1525 if (racenum >= 0 && racenum < SIZE(races) - 1
1526 && !(allow & races[racenum].allow & ROLE_ALIGNMASK))
1534 /* pick a random alignment subject to any rolenum/racenum/gendnum constraints
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 */
1540 pick_align(rolenum, racenum, gendnum, pickhow)
1541 int rolenum, racenum, gendnum, pickhow;
1546 for (i = 0; i < ROLE_ALIGNS; i++) {
1547 if (ok_align(rolenum, racenum, gendnum, i))
1550 if (aligns_ok == 0 || (aligns_ok > 1 && pickhow == PICK_RIGID))
1552 aligns_ok = rn2(aligns_ok);
1553 for (i = 0; i < ROLE_ALIGNS; i++) {
1554 if (ok_align(rolenum, racenum, gendnum, i)) {
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.
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.
1580 flags.initrole = pick_role(flags.initrace, flags.initgend,
1581 flags.initalign, PICK_RANDOM);
1582 if (flags.initrole < 0)
1583 flags.initrole = randrole_filtered();
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);
1603 boolean reslt = TRUE;
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;
1625 for (i = 0; i < SIZE(roles); ++i)
1626 if (filter.roles[i])
1636 for (i = 0; i < SIZE(roles); ++i)
1637 filter.roles[i] = FALSE;
1647 STATIC_VAR char pa[NUM_BP], post_attribs;
1650 promptsep(buf, num_post_attribs)
1652 int num_post_attribs;
1654 const char *conjuct = "and ";
1656 if (num_post_attribs > 1 && post_attribs < num_post_attribs
1657 && post_attribs > 1)
1661 if (!post_attribs && num_post_attribs > 1)
1662 Strcat(buf, conjuct);
1667 role_gendercount(rolenum)
1672 if (validrole(rolenum)) {
1673 if (roles[rolenum].allow & ROLE_MALE)
1675 if (roles[rolenum].allow & ROLE_FEMALE)
1677 if (roles[rolenum].allow & ROLE_NEUTER)
1684 race_alignmentcount(racenum)
1689 if (racenum != ROLE_NONE && racenum != ROLE_RANDOM) {
1690 if (races[racenum].allow & ROLE_CHAOTIC)
1692 if (races[racenum].allow & ROLE_LAWFUL)
1694 if (races[racenum].allow & ROLE_NEUTRAL)
1701 root_plselection_prompt(suppliedbuf, buflen, rolenum, racenum, gendnum,
1704 int buflen, rolenum, racenum, gendnum, alignnum;
1706 int k, gendercount = 0, aligncount = 0;
1708 static char err_ret[] = " character's";
1709 boolean donefirst = FALSE;
1711 if (!suppliedbuf || buflen < 1)
1714 /* initialize these static variables each time this is called */
1716 for (k = 0; k < NUM_BP; ++k)
1719 *suppliedbuf = '\0';
1721 /* How many alignments are allowed for the desired race? */
1722 if (racenum != ROLE_NONE && racenum != ROLE_RANDOM)
1723 aligncount = race_alignmentcount(racenum);
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)) {
1731 Strcat(buf, aligns[alignnum].adj);
1736 Strcat(buf, aligns[alignnum].adj);
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)) {
1756 /* How many genders are allowed for the desired role? */
1757 if (validrole(rolenum))
1758 gendercount = role_gendercount(rolenum);
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) {
1768 Strcat(buf, genders[gendnum].adj);
1774 Strcat(buf, genders[gendnum].adj);
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)) {
1787 /* <your lawful female> */
1789 if (racenum != ROLE_NONE && racenum != ROLE_RANDOM) {
1790 if (validrole(rolenum)
1791 && ok_race(rolenum, racenum, gendnum, alignnum)) {
1794 Strcat(buf, (rolenum == ROLE_NONE) ? races[racenum].noun
1795 : races[racenum].adj);
1797 } else if (!validrole(rolenum)) {
1800 Strcat(buf, races[racenum].noun);
1810 /* <your lawful female gnomish> || <your lawful female gnome> */
1812 if (validrole(rolenum)) {
1815 if (gendnum != ROLE_NONE) {
1816 if (gendnum == 1 && roles[rolenum].name.f)
1817 Strcat(buf, roles[rolenum].name.f);
1819 Strcat(buf, roles[rolenum].name.m);
1821 if (roles[rolenum].name.f) {
1822 Strcat(buf, roles[rolenum].name.m);
1824 Strcat(buf, roles[rolenum].name.f);
1826 Strcat(buf, roles[rolenum].name.m);
1829 } else if (rolenum == ROLE_NONE) {
1834 if ((racenum == ROLE_NONE || racenum == ROLE_RANDOM)
1835 && !validrole(rolenum)) {
1838 Strcat(buf, "character");
1841 /* <your lawful female gnomish cavewoman> || <your lawful female gnome>
1842 * || <your lawful female character>
1844 if (buflen > (int) (strlen(buf) + 1)) {
1845 Strcpy(suppliedbuf, buf);
1852 build_plselection_prompt(buf, buflen, rolenum, racenum, gendnum, alignnum)
1854 int buflen, rolenum, racenum, gendnum, alignnum;
1856 const char *defprompt = "Shall I pick a character for you? [ynaq] ";
1857 int num_post_attribs = 0;
1858 char tmpbuf[BUFSZ], *p;
1860 if (buflen < QBUFSZ)
1861 return (char *) defprompt;
1863 Strcpy(tmpbuf, "Shall I pick ");
1864 if (racenum != ROLE_NONE || validrole(rolenum))
1865 Strcat(tmpbuf, "your ");
1867 Strcat(tmpbuf, "a ");
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');
1881 /* buf should now be:
1882 * <your lawful female gnomish cavewoman's>
1883 * || <your lawful female gnome's>
1884 * || <your lawful female character's>
1886 * Now append the post attributes to it
1888 num_post_attribs = post_attribs;
1891 (void) promptsep(eos(buf), num_post_attribs);
1892 Strcat(buf, "race");
1895 (void) promptsep(eos(buf), num_post_attribs);
1896 Strcat(buf, "role");
1899 (void) promptsep(eos(buf), num_post_attribs);
1900 Strcat(buf, "gender");
1903 (void) promptsep(eos(buf), num_post_attribs);
1904 Strcat(buf, "alignment");
1907 Strcat(buf, " for you? [ynaq] ");
1923 #ifdef GENERIC_USERNAMES
1925 /* some generic user names will be ignored in favor of prompting */
1926 const char *uptr = GENERIC_USERNAMES;
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() */
1938 askname(); /* fill plname[] if necessary */
1940 /* Look for tokens delimited by '-' */
1941 if ((eptr = index(plname, '-')) != (char *) 0)
1944 /* Isolate the next token */
1946 if ((eptr = index(sptr, '-')) != (char *) 0)
1949 /* Try to match it to something */
1950 if ((i = str2role(sptr)) != ROLE_NONE)
1952 else if ((i = str2race(sptr)) != ROLE_NONE)
1954 else if ((i = str2gend(sptr)) != ROLE_NONE)
1956 else if ((i = str2align(sptr)) != ROLE_NONE)
1957 flags.initalign = i;
1961 /* commas in the plname confuse the record file, convert to spaces */
1962 for (sptr = plname; *sptr; sptr++) {
1968 /* show current settings for name, role, race, gender, and alignment
1969 in the specified window */
1971 role_selection_prolog(which, where)
1975 static const char NEARDATA choosing[] = " choosing now",
1976 not_yet[] = " not yet specified",
1977 rand_choice[] = " random";
1979 int r, c, g, a, allowmask;
1984 a = flags.initalign;
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))
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] */
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] */
2012 /* [g and a don't constrain anything sufficiently
2013 to narrow something done to a single choice] */
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)
2021 : (r == ROLE_RANDOM)
2024 if (r >= 0 && roles[r].name.f) {
2025 /* distinct female name [caveman/cavewoman, priest/priestess] */
2027 /* female specified; replace male role name with female one */
2028 Sprintf(index(buf, ':'), ": %s", roles[r].name.f);
2030 /* gender unspecified; append slash and female role name */
2031 Sprintf(eos(buf), "/%s", roles[r].name.f);
2033 putstr(where, 0, buf);
2034 Sprintf(buf, "%12s ", "race:");
2035 Strcat(buf, (which == RS_RACE) ? choosing : (c == ROLE_NONE)
2037 : (c == ROLE_RANDOM)
2040 putstr(where, 0, buf);
2041 Sprintf(buf, "%12s ", "gender:");
2042 Strcat(buf, (which == RS_GENDER) ? choosing : (g == ROLE_NONE)
2044 : (g == ROLE_RANDOM)
2047 putstr(where, 0, buf);
2048 Sprintf(buf, "%12s ", "alignment:");
2049 Strcat(buf, (which == RS_ALGNMNT) ? choosing : (a == ROLE_NONE)
2051 : (a == ROLE_RANDOM)
2054 putstr(where, 0, buf);
2057 /* add a "pick alignment first"-type entry to the specified menu */
2059 role_menu_extra(which, where)
2063 static NEARDATA const char RS_menu_let[] = {
2068 '[', /* alignment */
2072 const char *what = 0, *constrainer = 0, *forcedvalue = 0;
2073 int f = 0, r, c, g, a, i, allowmask;
2084 for (i = 0; i < SIZE(roles); ++i)
2085 if (i != f && !filter.roles[i])
2087 if (i == SIZE(roles)) {
2088 constrainer = "filter";
2089 forcedvalue = "role";
2095 c = ROLE_NONE; /* override player's setting */
2097 allowmask = roles[r].allow & ROLE_RACEMASK;
2098 if (allowmask == MH_HUMAN)
2099 c = 0; /* races[human] */
2101 constrainer = "role";
2102 forcedvalue = races[c].noun;
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";
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] */
2123 constrainer = "role";
2124 forcedvalue = genders[g].adj;
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";
2136 f = flags.initalign;
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] */
2147 constrainer = "role";
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] */
2158 constrainer = "race";
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";
2168 forcedvalue = aligns[a].adj;
2172 any = zeroany; /* zero out all bits */
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,
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,
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",
2192 } else if (which == ROLE_NONE) {
2193 any.a_int = ROLE_NONE;
2194 add_menu(where, NO_GLYPH, &any, 'q', 0, ATR_NONE, "Quit",
2197 impossible("role_menu_extra: bad arg (%d)", which);
2202 * Special setup modifications here:
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. :-)
2208 * 1 - The Rogue Leader is the Tourist Nemesis.
2209 * 2 - Priests start with a random alignment - convert the leader and
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).
2216 * This code also replaces quest_init().
2222 struct permonst *pm;
2224 /* Strip the role letter out of the player name.
2225 * This is included for backwards compatibility.
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();
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';
2242 /* Check for a valid race */
2243 if (!validrace(flags.initrole, flags.initrace))
2244 flags.initrace = randrace(flags.initrole);
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;
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;
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;
2262 /* Initialize urole and urace */
2263 urole = roles[flags.initrole];
2264 urace = races[flags.initrace];
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)
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;
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);
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();
2309 urole.lgod = roles[flags.pantheon].lgod;
2310 urole.ngod = roles[flags.pantheon].ngod;
2311 urole.cgod = roles[flags.pantheon].cgod;
2313 /* 0 or 1; no gods are neuter, nor is gender randomized */
2314 quest_status.godgend = !strcmpi(align_gtitle(alignmnt), "goddess");
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
2327 mons[urole.malenum].mflags3 |= M3_INFRAVISION;
2328 if (urole.femalenum != NON_PM)
2329 mons[urole.femalenum].mflags3 |= M3_INFRAVISION;
2332 /* Artifacts are fixed in hack_artifacts() */
2342 switch (Role_switch) {
2344 return "Salutations"; /* Olde English */
2346 return (mtmp && mtmp->data == &mons[PM_SHOPKEEPER])
2348 : "Konnichi wa"; /* Japanese */
2350 return "Aloha"; /* Hawaiian */
2354 (mtmp && mtmp->data == &mons[PM_MAIL_DAEMON]) ? "Hallo" :
2356 "Velkommen"; /* Norse */
2365 switch (Role_switch) {
2367 return "Fare thee well"; /* Olde English */
2369 return "Sayonara"; /* Japanese */
2371 return "Aloha"; /* Hawaiian */
2373 return "Farvel"; /* Norse */