1 /* NetHack 3.6 role.c $NHDT-Date: 1463561393 2016/05/18 08:49:53 $ $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.38 $ */
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
[] = {
27 { { "Archeologist", 0 },
29 { "Field Worker", 0 },
30 { "Investigator", 0 },
34 { "Speleologist", 0 },
37 "Quetzalcoatl", "Camaxtli", "Huhetotl", /* Central American */
39 "the College of Archeology",
40 "the Tomb of the Toltec Kings",
46 PM_MINION_OF_HUHETOTL
,
52 MH_HUMAN
| MH_DWARF
| MH_GNOME
| ROLE_MALE
| ROLE_FEMALE
| ROLE_LAWFUL
54 /* Str Int Wis Dex Con Cha */
55 { 7, 10, 10, 7, 7, 7 },
56 { 20, 20, 20, 10, 20, 10 },
57 /* Init Lower Higher */
58 { 11, 0, 0, 8, 1, 0 }, /* Hit points */
70 { { "Plunderer", "Plunderess" },
77 { "Chieftain", "Chieftainess" },
78 { "Conqueror", "Conqueress" } },
79 "Mitra", "Crom", "Set", /* Hyborian */
81 "the Camp of the Duali Tribe",
94 MH_HUMAN
| MH_ORC
| ROLE_MALE
| ROLE_FEMALE
| ROLE_NEUTRAL
96 /* Str Int Wis Dex Con Cha */
97 { 16, 7, 7, 15, 16, 6 },
98 { 30, 6, 7, 20, 30, 7 },
99 /* Init Lower Higher */
100 { 14, 0, 0, 10, 2, 0 }, /* Hit points */
101 { 1, 0, 0, 1, 0, 1 },
111 { { "Caveman", "Cavewoman" },
112 { { "Troglodyte", 0 },
121 "Anu", "_Ishtar", "Anshar", /* Babylonian */
123 "the Caves of the Ancestors",
135 ART_SCEPTRE_OF_MIGHT
,
136 MH_HUMAN
| MH_DWARF
| MH_GNOME
| ROLE_MALE
| ROLE_FEMALE
| ROLE_LAWFUL
138 /* Str Int Wis Dex Con Cha */
139 { 10, 7, 7, 7, 8, 6 },
140 { 30, 6, 7, 20, 30, 7 },
141 /* Init Lower Higher */
142 { 14, 0, 0, 8, 2, 0 }, /* Hit points */
143 { 1, 0, 0, 1, 0, 1 },
154 { { "Rhizotomist", 0 },
158 { "Medicus ossium", "Medica ossium" },
160 { "Magister", "Magistra" },
162 { "Chirurgeon", 0 } },
163 "_Athena", "Hermes", "Poseidon", /* Greek */
165 "the Temple of Epidaurus",
166 "the Temple of Coeus",
177 ART_STAFF_OF_AESCULAPIUS
,
178 MH_HUMAN
| MH_GNOME
| ROLE_MALE
| ROLE_FEMALE
| ROLE_NEUTRAL
,
179 /* Str Int Wis Dex Con Cha */
180 { 7, 7, 13, 7, 11, 16 },
181 { 15, 20, 20, 15, 25, 5 },
182 /* Init Lower Higher */
183 { 11, 0, 0, 8, 1, 0 }, /* Hit points */
184 { 1, 4, 0, 1, 0, 2 },
201 { "Chevalier", "Chevaliere" },
202 { "Seignieur", "Dame" },
204 "Lugh", "_Brigit", "Manannan Mac Lir", /* Celtic */
218 ART_MAGIC_MIRROR_OF_MERLIN
,
219 MH_HUMAN
| ROLE_MALE
| ROLE_FEMALE
| ROLE_LAWFUL
,
220 /* Str Int Wis Dex Con Cha */
221 { 13, 7, 14, 8, 10, 17 },
222 { 30, 15, 15, 10, 20, 10 },
223 /* Init Lower Higher */
224 { 14, 0, 0, 8, 2, 0 }, /* Hit points */
225 { 1, 4, 0, 1, 0, 2 },
236 { { "Candidate", 0 },
239 { "Student of Stones", 0 },
240 { "Student of Waters", 0 },
241 { "Student of Metals", 0 },
242 { "Student of Winds", 0 },
243 { "Student of Fire", 0 },
245 "Shan Lai Ching", "Chih Sung-tzu", "Huan Ti", /* Chinese */
247 "the Monastery of Chan-Sune",
248 "the Monastery of the Earth-Lord",
259 ART_EYES_OF_THE_OVERWORLD
,
260 MH_HUMAN
| ROLE_MALE
| ROLE_FEMALE
| ROLE_LAWFUL
| ROLE_NEUTRAL
262 /* Str Int Wis Dex Con Cha */
263 { 10, 7, 8, 8, 7, 7 },
264 { 25, 10, 20, 20, 15, 10 },
265 /* Init Lower Higher */
266 { 12, 0, 0, 8, 1, 0 }, /* Hit points */
267 { 2, 2, 0, 2, 0, 2 },
277 { { "Priest", "Priestess" },
281 { "Priest", "Priestess" },
283 { "Canon", "Canoness" },
285 { "Patriarch", "Matriarch" },
286 { "High Priest", "High Priestess" } },
287 0, 0, 0, /* deities from a randomly chosen other role will be used */
290 "the Temple of Nalzok",
301 ART_MITRE_OF_HOLINESS
,
302 MH_HUMAN
| MH_ELF
| ROLE_MALE
| ROLE_FEMALE
| ROLE_LAWFUL
| ROLE_NEUTRAL
304 /* Str Int Wis Dex Con Cha */
305 { 7, 7, 10, 7, 7, 7 },
306 { 15, 10, 30, 15, 20, 10 },
307 /* Init Lower Higher */
308 { 12, 0, 0, 8, 1, 0 }, /* Hit points */
309 { 4, 3, 0, 2, 0, 2 },
319 /* Note: Rogue precedes Ranger so that use of `-R' on the command line
320 retains its traditional meaning. */
329 { "Magsman", "Magswoman" },
331 "Issek", "Mog", "Kos", /* Nehwon */
333 "the Thieves' Guild Hall",
334 "the Assassins' Guild Hall",
338 PM_MASTER_OF_THIEVES
,
345 ART_MASTER_KEY_OF_THIEVERY
,
346 MH_HUMAN
| MH_ORC
| ROLE_MALE
| ROLE_FEMALE
| ROLE_CHAOTIC
,
347 /* Str Int Wis Dex Con Cha */
348 { 7, 7, 7, 10, 7, 6 },
349 { 20, 10, 10, 30, 20, 10 },
350 /* Init Lower Higher */
351 { 10, 0, 0, 8, 1, 0 }, /* Hit points */
352 { 1, 0, 0, 1, 0, 1 },
366 {"Edhel", "Elleth"}, /* elf-maid */
367 {"Ohtar", "Ohtie"}, /* warrior */
368 {"Kano", "Kanie"}, /* commander (Q.) ['a] educated guess,
369 until further research- SAC */
370 {"Arandur"," Aranduriel"}, /* king's servant, minister (Q.) - guess */
371 {"Hir", "Hiril"}, /* lord, lady (S.) ['ir] */
372 {"Aredhel", "Arwen"}, /* noble elf, maiden (S.) */
373 {"Ernil", "Elentariel"}, /* prince (S.), elf-maiden (Q.) */
374 {"Elentar", "Elentari"}, /* Star-king, -queen (Q.) */
375 "Solonor Thelandira", "Aerdrie Faenya", "Lolth", /* Elven */
379 { "Trailblazer", 0 },
380 { "Reconnoiterer", "Reconnoiteress" },
382 { "Arbalester", 0 }, /* One skilled at crossbows */
384 { "Sharpshooter", 0 },
385 { "Marksman", "Markswoman" } },
386 "Mercury", "_Venus", "Mars", /* Roman/planets */
389 "the cave of the wumpus",
392 PM_LITTLE_DOG
/* Orion & canis major */,
400 ART_LONGBOW_OF_DIANA
,
401 MH_HUMAN
| MH_ELF
| MH_GNOME
| MH_ORC
| ROLE_MALE
| ROLE_FEMALE
402 | ROLE_NEUTRAL
| ROLE_CHAOTIC
,
403 /* Str Int Wis Dex Con Cha */
404 { 13, 13, 13, 9, 13, 7 },
405 { 30, 10, 10, 20, 20, 10 },
406 /* Init Lower Higher */
407 { 13, 0, 0, 6, 1, 0 }, /* Hit points */
408 { 1, 0, 0, 1, 0, 1 },
419 { { "Hatamoto", 0 }, /* Banner Knight */
420 { "Ronin", 0 }, /* no allegiance */
421 { "Ninja", "Kunoichi" }, /* secret society */
422 { "Joshu", 0 }, /* heads a castle */
423 { "Ryoshu", 0 }, /* has a territory */
424 { "Kokushu", 0 }, /* heads a province */
425 { "Daimyo", 0 }, /* a samurai lord */
426 { "Kuge", 0 }, /* Noble of the Court */
427 { "Shogun", 0 } }, /* supreme commander, warlord */
428 "_Amaterasu Omikami", "Raijin", "Susanowo", /* Japanese */
430 "the Castle of the Taro Clan",
431 "the Shogun's Castle",
442 ART_TSURUGI_OF_MURAMASA
,
443 MH_HUMAN
| ROLE_MALE
| ROLE_FEMALE
| ROLE_LAWFUL
,
444 /* Str Int Wis Dex Con Cha */
445 { 10, 8, 7, 10, 17, 6 },
446 { 30, 10, 8, 30, 14, 8 },
447 /* Init Lower Higher */
448 { 13, 0, 0, 8, 1, 0 }, /* Hit points */
449 { 1, 0, 0, 1, 0, 1 },
462 { "Excursionist", 0 },
463 { "Peregrinator", "Peregrinatrix" },
468 { "Adventurer", 0 } },
469 "Blind Io", "_The Lady", "Offler", /* Discworld */
472 "the Thieves' Guild Hall",
478 PM_MASTER_OF_THIEVES
,
483 ART_YENDORIAN_EXPRESS_CARD
,
484 MH_HUMAN
| ROLE_MALE
| ROLE_FEMALE
| ROLE_NEUTRAL
,
485 /* Str Int Wis Dex Con Cha */
486 { 7, 10, 6, 7, 7, 10 },
487 { 15, 10, 10, 15, 30, 20 },
488 /* Init Lower Higher */
489 { 8, 0, 0, 8, 0, 0 }, /* Hit points */
490 { 1, 0, 0, 1, 0, 1 },
501 { { "Stripling", 0 },
504 { "Man-at-arms", "Woman-at-arms" },
506 { "Swashbuckler", 0 },
507 { "Hero", "Heroine" },
509 { "Lord", "Lady" } },
510 "Tyr", "Odin", "Loki", /* Norse */
512 "the Shrine of Destiny",
513 "the cave of Surtur",
516 NON_PM
/*PM_WINTER_WOLF_CUB*/,
525 MH_HUMAN
| MH_DWARF
| ROLE_FEMALE
| ROLE_LAWFUL
| ROLE_NEUTRAL
,
526 /* Str Int Wis Dex Con Cha */
527 { 10, 7, 7, 7, 10, 7 },
528 { 30, 6, 7, 20, 30, 7 },
529 /* Init Lower Higher */
530 { 14, 0, 0, 8, 2, 0 }, /* Hit points */
531 { 1, 0, 0, 1, 0, 1 },
544 { "Thaumaturge", 0 },
546 { "Enchanter", "Enchantress" },
547 { "Sorcerer", "Sorceress" },
548 { "Necromancer", 0 },
551 "Ptah", "Thoth", "Anhur", /* Egyptian */
554 "the Tower of Darkness",
558 PM_NEFERET_THE_GREEN
,
565 ART_EYE_OF_THE_AETHIOPICA
,
566 MH_HUMAN
| MH_ELF
| MH_GNOME
| MH_ORC
| ROLE_MALE
| ROLE_FEMALE
567 | ROLE_NEUTRAL
| ROLE_CHAOTIC
,
568 /* Str Int Wis Dex Con Cha */
569 { 7, 10, 7, 7, 7, 7 },
570 { 10, 30, 10, 20, 20, 10 },
571 /* Init Lower Higher */
572 { 10, 0, 0, 8, 1, 0 }, /* Hit points */
573 { 4, 3, 0, 2, 0, 3 },
583 /* Array terminator */
587 /* The player's role, created at runtime from initial
588 * choices. This may be munged in role_init().
590 struct Role urole
= {
592 { { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 },
593 { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 } },
595 "Xxx", "home", "locate",
596 NON_PM
, NON_PM
, NON_PM
, NON_PM
, NON_PM
, NON_PM
, NON_PM
, NON_PM
,
598 /* Str Int Wis Dex Con Cha */
599 { 7, 7, 7, 7, 7, 7 },
600 { 20, 15, 15, 20, 20, 10 },
601 /* Init Lower Higher */
602 { 10, 0, 0, 8, 1, 0 }, /* Hit points */
603 { 2, 0, 0, 2, 0, 3 },
615 /* Table of all races */
616 const struct Race races
[] = {
627 MH_HUMAN
| ROLE_MALE
| ROLE_FEMALE
| ROLE_LAWFUL
| ROLE_NEUTRAL
632 /* Str Int Wis Dex Con Cha */
633 { 3, 3, 3, 3, 3, 3 },
634 { STR18(100), 18, 18, 18, 18, 18 },
635 /* Init Lower Higher */
636 { 2, 0, 0, 2, 1, 0 }, /* Hit points */
637 { 1, 0, 2, 0, 2, 0 } /* Energy */
649 MH_ELF
| ROLE_MALE
| ROLE_FEMALE
| ROLE_CHAOTIC
,
653 /* Str Int Wis Dex Con Cha */
654 { 3, 3, 3, 3, 3, 3 },
655 { 18, 20, 20, 18, 16, 18 },
656 /* Init Lower Higher */
657 { 1, 0, 0, 1, 1, 0 }, /* Hit points */
658 { 2, 0, 3, 0, 3, 0 } /* Energy */
670 MH_DWARF
| ROLE_MALE
| ROLE_FEMALE
| ROLE_LAWFUL
,
674 /* Str Int Wis Dex Con Cha */
675 { 3, 3, 3, 3, 3, 3 },
676 { STR18(100), 16, 16, 20, 20, 16 },
677 /* Init Lower Higher */
678 { 4, 0, 0, 3, 2, 0 }, /* Hit points */
679 { 0, 0, 0, 0, 0, 0 } /* Energy */
691 MH_GNOME
| ROLE_MALE
| ROLE_FEMALE
| ROLE_NEUTRAL
,
695 /* Str Int Wis Dex Con Cha */
696 { 3, 3, 3, 3, 3, 3 },
697 { STR18(50), 19, 18, 18, 18, 18 },
698 /* Init Lower Higher */
699 { 1, 0, 0, 1, 0, 0 }, /* Hit points */
700 { 2, 0, 2, 0, 2, 0 } /* Energy */
712 MH_ORC
| ROLE_MALE
| ROLE_FEMALE
| ROLE_CHAOTIC
,
715 MH_HUMAN
| MH_ELF
| MH_DWARF
,
716 /* Str Int Wis Dex Con Cha */
717 { 3, 3, 3, 3, 3, 3 },
718 { STR18(50), 16, 16, 18, 18, 16 },
719 /* Init Lower Higher */
720 { 1, 0, 0, 1, 0, 0 }, /* Hit points */
721 { 1, 0, 1, 0, 1, 0 } /* Energy */
723 /* Array terminator */
727 /* The player's race, created at runtime from initial
728 * choices. This may be munged in role_init().
730 struct Race urace
= {
744 /* Str Int Wis Dex Con Cha */
745 { 3, 3, 3, 3, 3, 3 },
746 { STR18(100), 18, 18, 18, 18, 18 },
747 /* Init Lower Higher */
748 { 2, 0, 0, 2, 1, 0 }, /* Hit points */
749 { 1, 0, 2, 0, 2, 0 } /* Energy */
752 /* Table of all genders */
753 const struct Gender genders
[] = {
754 { "male", "he", "him", "his", "Mal", ROLE_MALE
},
755 { "female", "she", "her", "her", "Fem", ROLE_FEMALE
},
756 { "neuter", "it", "it", "its", "Ntr", ROLE_NEUTER
}
759 /* Table of all alignments */
760 const struct Align aligns
[] = {
761 { "law", "lawful", "Law", ROLE_LAWFUL
, A_LAWFUL
},
762 { "balance", "neutral", "Neu", ROLE_NEUTRAL
, A_NEUTRAL
},
763 { "chaos", "chaotic", "Cha", ROLE_CHAOTIC
, A_CHAOTIC
},
764 { "evil", "unaligned", "Una", 0, A_NONE
}
769 boolean roles
[SIZE(roles
)];
773 STATIC_DCL
int NDECL(randrole_filtered
);
774 STATIC_DCL
char *FDECL(promptsep
, (char *, int));
775 STATIC_DCL
int FDECL(role_gendercount
, (int));
776 STATIC_DCL
int FDECL(race_alignmentcount
, (int));
778 /* used by str2XXX() */
779 static char NEARDATA randomstr
[] = "random";
785 return (boolean
) (rolenum
>= 0 && rolenum
< SIZE(roles
) - 1);
791 return rn2(SIZE(roles
) - 1);
797 int i
, n
= 0, set
[SIZE(roles
)];
799 /* this doesn't rule out impossible combinations but attempts to
800 honor all the filter masks */
801 for (i
= 0; i
< SIZE(roles
); ++i
)
802 if (ok_role(i
, ROLE_NONE
, ROLE_NONE
, ROLE_NONE
)
803 && ok_race(i
, ROLE_RANDOM
, ROLE_NONE
, ROLE_NONE
)
804 && ok_gend(i
, ROLE_NONE
, ROLE_RANDOM
, ROLE_NONE
)
805 && ok_align(i
, ROLE_NONE
, ROLE_NONE
, ROLE_RANDOM
))
807 return n
? set
[rn2(n
)] : randrole();
820 /* Match as much of str as is provided */
822 for (i
= 0; roles
[i
].name
.m
; i
++) {
823 /* Does it match the male name? */
824 if (!strncmpi(str
, roles
[i
].name
.m
, len
))
826 /* Or the female name? */
827 if (roles
[i
].name
.f
&& !strncmpi(str
, roles
[i
].name
.f
, len
))
829 /* Or the filecode? */
830 if (!strcmpi(str
, roles
[i
].filecode
))
834 if ((len
== 1 && (*str
== '*' || *str
== '@'))
835 || !strncmpi(str
, randomstr
, len
))
838 /* Couldn't find anything appropriate */
843 validrace(rolenum
, racenum
)
844 int rolenum
, racenum
;
846 /* Assumes validrole */
847 return (boolean
) (racenum
>= 0 && racenum
< SIZE(races
) - 1
848 && (roles
[rolenum
].allow
& races
[racenum
].allow
858 /* Count the number of valid races */
859 for (i
= 0; races
[i
].noun
; i
++)
860 if (roles
[rolenum
].allow
& races
[i
].allow
& ROLE_RACEMASK
)
863 /* Pick a random race */
864 /* Use a factor of 100 in case of bad random number generators */
866 n
= rn2(n
* 100) / 100;
867 for (i
= 0; races
[i
].noun
; i
++)
868 if (roles
[rolenum
].allow
& races
[i
].allow
& ROLE_RACEMASK
) {
875 /* This role has no permitted races? */
876 return rn2(SIZE(races
) - 1);
889 /* Match as much of str as is provided */
891 for (i
= 0; races
[i
].noun
; i
++) {
892 /* Does it match the noun? */
893 if (!strncmpi(str
, races
[i
].noun
, len
))
895 /* Or the filecode? */
896 if (!strcmpi(str
, races
[i
].filecode
))
900 if ((len
== 1 && (*str
== '*' || *str
== '@'))
901 || !strncmpi(str
, randomstr
, len
))
904 /* Couldn't find anything appropriate */
909 validgend(rolenum
, racenum
, gendnum
)
910 int rolenum
, racenum
, gendnum
;
912 /* Assumes validrole and validrace */
913 return (boolean
) (gendnum
>= 0 && gendnum
< ROLE_GENDERS
914 && (roles
[rolenum
].allow
& races
[racenum
].allow
915 & genders
[gendnum
].allow
& ROLE_GENDMASK
));
919 randgend(rolenum
, racenum
)
920 int rolenum
, racenum
;
924 /* Count the number of valid genders */
925 for (i
= 0; i
< ROLE_GENDERS
; i
++)
926 if (roles
[rolenum
].allow
& races
[racenum
].allow
& genders
[i
].allow
930 /* Pick a random gender */
933 for (i
= 0; i
< ROLE_GENDERS
; i
++)
934 if (roles
[rolenum
].allow
& races
[racenum
].allow
& genders
[i
].allow
942 /* This role/race has no permitted genders? */
943 return rn2(ROLE_GENDERS
);
956 /* Match as much of str as is provided */
958 for (i
= 0; i
< ROLE_GENDERS
; i
++) {
959 /* Does it match the adjective? */
960 if (!strncmpi(str
, genders
[i
].adj
, len
))
962 /* Or the filecode? */
963 if (!strcmpi(str
, genders
[i
].filecode
))
966 if ((len
== 1 && (*str
== '*' || *str
== '@'))
967 || !strncmpi(str
, randomstr
, len
))
970 /* Couldn't find anything appropriate */
975 validalign(rolenum
, racenum
, alignnum
)
976 int rolenum
, racenum
, alignnum
;
978 /* Assumes validrole and validrace */
979 return (boolean
) (alignnum
>= 0 && alignnum
< ROLE_ALIGNS
980 && (roles
[rolenum
].allow
& races
[racenum
].allow
981 & aligns
[alignnum
].allow
& ROLE_ALIGNMASK
));
985 randalign(rolenum
, racenum
)
986 int rolenum
, racenum
;
990 /* Count the number of valid alignments */
991 for (i
= 0; i
< ROLE_ALIGNS
; i
++)
992 if (roles
[rolenum
].allow
& races
[racenum
].allow
& aligns
[i
].allow
996 /* Pick a random alignment */
999 for (i
= 0; i
< ROLE_ALIGNS
; i
++)
1000 if (roles
[rolenum
].allow
& races
[racenum
].allow
& aligns
[i
].allow
1008 /* This role/race has no permitted alignments? */
1009 return rn2(ROLE_ALIGNS
);
1019 if (!str
|| !str
[0])
1022 /* Match as much of str as is provided */
1024 for (i
= 0; i
< ROLE_ALIGNS
; i
++) {
1025 /* Does it match the adjective? */
1026 if (!strncmpi(str
, aligns
[i
].adj
, len
))
1028 /* Or the filecode? */
1029 if (!strcmpi(str
, aligns
[i
].filecode
))
1032 if ((len
== 1 && (*str
== '*' || *str
== '@'))
1033 || !strncmpi(str
, randomstr
, len
))
1036 /* Couldn't find anything appropriate */
1040 /* is rolenum compatible with any racenum/gendnum/alignnum constraints? */
1042 ok_role(rolenum
, racenum
, gendnum
, alignnum
)
1043 int rolenum
, racenum
, gendnum
, alignnum
;
1048 if (rolenum
>= 0 && rolenum
< SIZE(roles
) - 1) {
1049 if (rfilter
.roles
[rolenum
])
1051 allow
= roles
[rolenum
].allow
;
1052 if (racenum
>= 0 && racenum
< SIZE(races
) - 1
1053 && !(allow
& races
[racenum
].allow
& ROLE_RACEMASK
))
1055 if (gendnum
>= 0 && gendnum
< ROLE_GENDERS
1056 && !(allow
& genders
[gendnum
].allow
& ROLE_GENDMASK
))
1058 if (alignnum
>= 0 && alignnum
< ROLE_ALIGNS
1059 && !(allow
& aligns
[alignnum
].allow
& ROLE_ALIGNMASK
))
1063 /* random; check whether any selection is possible */
1064 for (i
= 0; i
< SIZE(roles
) - 1; i
++) {
1065 if (rfilter
.roles
[i
])
1067 allow
= roles
[i
].allow
;
1068 if (racenum
>= 0 && racenum
< SIZE(races
) - 1
1069 && !(allow
& races
[racenum
].allow
& ROLE_RACEMASK
))
1071 if (gendnum
>= 0 && gendnum
< ROLE_GENDERS
1072 && !(allow
& genders
[gendnum
].allow
& ROLE_GENDMASK
))
1074 if (alignnum
>= 0 && alignnum
< ROLE_ALIGNS
1075 && !(allow
& aligns
[alignnum
].allow
& ROLE_ALIGNMASK
))
1083 /* pick a random role subject to any racenum/gendnum/alignnum constraints */
1084 /* If pickhow == PICK_RIGID a role is returned only if there is */
1085 /* a single possibility */
1087 pick_role(racenum
, gendnum
, alignnum
, pickhow
)
1088 int racenum
, gendnum
, alignnum
, pickhow
;
1091 int roles_ok
= 0, set
[SIZE(roles
)];
1093 for (i
= 0; i
< SIZE(roles
) - 1; i
++) {
1094 if (ok_role(i
, racenum
, gendnum
, alignnum
)
1095 && ok_race(i
, (racenum
>= 0) ? racenum
: ROLE_RANDOM
,
1097 && ok_gend(i
, racenum
,
1098 (gendnum
>= 0) ? gendnum
: ROLE_RANDOM
, alignnum
)
1099 && ok_race(i
, racenum
,
1100 gendnum
, (alignnum
>= 0) ? alignnum
: ROLE_RANDOM
))
1101 set
[roles_ok
++] = i
;
1103 if (roles_ok
== 0 || (roles_ok
> 1 && pickhow
== PICK_RIGID
))
1105 return set
[rn2(roles_ok
)];
1108 /* is racenum compatible with any rolenum/gendnum/alignnum constraints? */
1110 ok_race(rolenum
, racenum
, gendnum
, alignnum
)
1111 int rolenum
, racenum
, gendnum
, alignnum
;
1116 if (racenum
>= 0 && racenum
< SIZE(races
) - 1) {
1117 if (rfilter
.mask
& races
[racenum
].selfmask
)
1119 allow
= races
[racenum
].allow
;
1120 if (rolenum
>= 0 && rolenum
< SIZE(roles
) - 1
1121 && !(allow
& roles
[rolenum
].allow
& ROLE_RACEMASK
))
1123 if (gendnum
>= 0 && gendnum
< ROLE_GENDERS
1124 && !(allow
& genders
[gendnum
].allow
& ROLE_GENDMASK
))
1126 if (alignnum
>= 0 && alignnum
< ROLE_ALIGNS
1127 && !(allow
& aligns
[alignnum
].allow
& ROLE_ALIGNMASK
))
1131 /* random; check whether any selection is possible */
1132 for (i
= 0; i
< SIZE(races
) - 1; i
++) {
1133 if (rfilter
.mask
& races
[i
].selfmask
)
1135 allow
= races
[i
].allow
;
1136 if (rolenum
>= 0 && rolenum
< SIZE(roles
) - 1
1137 && !(allow
& roles
[rolenum
].allow
& ROLE_RACEMASK
))
1139 if (gendnum
>= 0 && gendnum
< ROLE_GENDERS
1140 && !(allow
& genders
[gendnum
].allow
& ROLE_GENDMASK
))
1142 if (alignnum
>= 0 && alignnum
< ROLE_ALIGNS
1143 && !(allow
& aligns
[alignnum
].allow
& ROLE_ALIGNMASK
))
1151 /* Pick a random race subject to any rolenum/gendnum/alignnum constraints.
1152 If pickhow == PICK_RIGID a race is returned only if there is
1153 a single possibility. */
1155 pick_race(rolenum
, gendnum
, alignnum
, pickhow
)
1156 int rolenum
, gendnum
, alignnum
, pickhow
;
1161 for (i
= 0; i
< SIZE(races
) - 1; i
++) {
1162 if (ok_race(rolenum
, i
, gendnum
, alignnum
))
1165 if (races_ok
== 0 || (races_ok
> 1 && pickhow
== PICK_RIGID
))
1167 races_ok
= rn2(races_ok
);
1168 for (i
= 0; i
< SIZE(races
) - 1; i
++) {
1169 if (ok_race(rolenum
, i
, gendnum
, alignnum
)) {
1179 /* is gendnum compatible with any rolenum/racenum/alignnum constraints? */
1180 /* gender and alignment are not comparable (and also not constrainable) */
1182 ok_gend(rolenum
, racenum
, gendnum
, alignnum
)
1183 int rolenum
, racenum
, gendnum
;
1184 int alignnum UNUSED
;
1189 if (gendnum
>= 0 && gendnum
< ROLE_GENDERS
) {
1190 if (rfilter
.mask
& genders
[gendnum
].allow
)
1192 allow
= genders
[gendnum
].allow
;
1193 if (rolenum
>= 0 && rolenum
< SIZE(roles
) - 1
1194 && !(allow
& roles
[rolenum
].allow
& ROLE_GENDMASK
))
1196 if (racenum
>= 0 && racenum
< SIZE(races
) - 1
1197 && !(allow
& races
[racenum
].allow
& ROLE_GENDMASK
))
1201 /* random; check whether any selection is possible */
1202 for (i
= 0; i
< ROLE_GENDERS
; i
++) {
1203 if (rfilter
.mask
& genders
[i
].allow
)
1205 allow
= genders
[i
].allow
;
1206 if (rolenum
>= 0 && rolenum
< SIZE(roles
) - 1
1207 && !(allow
& roles
[rolenum
].allow
& ROLE_GENDMASK
))
1209 if (racenum
>= 0 && racenum
< SIZE(races
) - 1
1210 && !(allow
& races
[racenum
].allow
& ROLE_GENDMASK
))
1218 /* pick a random gender subject to any rolenum/racenum/alignnum constraints */
1219 /* gender and alignment are not comparable (and also not constrainable) */
1220 /* If pickhow == PICK_RIGID a gender is returned only if there is */
1221 /* a single possibility */
1223 pick_gend(rolenum
, racenum
, alignnum
, pickhow
)
1224 int rolenum
, racenum
, alignnum
, pickhow
;
1229 for (i
= 0; i
< ROLE_GENDERS
; i
++) {
1230 if (ok_gend(rolenum
, racenum
, i
, alignnum
))
1233 if (gends_ok
== 0 || (gends_ok
> 1 && pickhow
== PICK_RIGID
))
1235 gends_ok
= rn2(gends_ok
);
1236 for (i
= 0; i
< ROLE_GENDERS
; i
++) {
1237 if (ok_gend(rolenum
, racenum
, i
, alignnum
)) {
1247 /* is alignnum compatible with any rolenum/racenum/gendnum constraints? */
1248 /* alignment and gender are not comparable (and also not constrainable) */
1250 ok_align(rolenum
, racenum
, gendnum
, alignnum
)
1251 int rolenum
, racenum
;
1258 if (alignnum
>= 0 && alignnum
< ROLE_ALIGNS
) {
1259 if (rfilter
.mask
& aligns
[alignnum
].allow
)
1261 allow
= aligns
[alignnum
].allow
;
1262 if (rolenum
>= 0 && rolenum
< SIZE(roles
) - 1
1263 && !(allow
& roles
[rolenum
].allow
& ROLE_ALIGNMASK
))
1265 if (racenum
>= 0 && racenum
< SIZE(races
) - 1
1266 && !(allow
& races
[racenum
].allow
& ROLE_ALIGNMASK
))
1270 /* random; check whether any selection is possible */
1271 for (i
= 0; i
< ROLE_ALIGNS
; i
++) {
1272 if (rfilter
.mask
& aligns
[i
].allow
)
1274 allow
= aligns
[i
].allow
;
1275 if (rolenum
>= 0 && rolenum
< SIZE(roles
) - 1
1276 && !(allow
& roles
[rolenum
].allow
& ROLE_ALIGNMASK
))
1278 if (racenum
>= 0 && racenum
< SIZE(races
) - 1
1279 && !(allow
& races
[racenum
].allow
& ROLE_ALIGNMASK
))
1287 /* Pick a random alignment subject to any rolenum/racenum/gendnum constraints;
1288 alignment and gender are not comparable (and also not constrainable).
1289 If pickhow == PICK_RIGID an alignment is returned only if there is
1290 a single possibility. */
1292 pick_align(rolenum
, racenum
, gendnum
, pickhow
)
1293 int rolenum
, racenum
, gendnum
, pickhow
;
1298 for (i
= 0; i
< ROLE_ALIGNS
; i
++) {
1299 if (ok_align(rolenum
, racenum
, gendnum
, i
))
1302 if (aligns_ok
== 0 || (aligns_ok
> 1 && pickhow
== PICK_RIGID
))
1304 aligns_ok
= rn2(aligns_ok
);
1305 for (i
= 0; i
< ROLE_ALIGNS
; i
++) {
1306 if (ok_align(rolenum
, racenum
, gendnum
, i
)) {
1321 /* Some roles are limited to a single race, alignment, or gender and
1322 * calling this routine prior to XXX_player_selection() will help
1323 * prevent an extraneous prompt that actually doesn't allow
1324 * you to choose anything further. Note the use of PICK_RIGID which
1325 * causes the pick_XX() routine to return a value only if there is one
1326 * single possible selection, otherwise it returns ROLE_NONE.
1329 if (flags
.initrole
== ROLE_RANDOM
) {
1330 /* If the role was explicitly specified as ROLE_RANDOM
1331 * via -uXXXX-@ or OPTIONS=role:random then choose the role
1332 * in here to narrow down later choices.
1334 flags
.initrole
= pick_role(flags
.initrace
, flags
.initgend
,
1335 flags
.initalign
, PICK_RANDOM
);
1336 if (flags
.initrole
< 0)
1337 flags
.initrole
= randrole_filtered();
1339 if (flags
.initrace
== ROLE_RANDOM
1340 && (tmp
= pick_race(flags
.initrole
, flags
.initgend
,
1341 flags
.initalign
, PICK_RANDOM
)) != ROLE_NONE
)
1342 flags
.initrace
= tmp
;
1343 if (flags
.initalign
== ROLE_RANDOM
1344 && (tmp
= pick_align(flags
.initrole
, flags
.initrace
,
1345 flags
.initgend
, PICK_RANDOM
)) != ROLE_NONE
)
1346 flags
.initalign
= tmp
;
1347 if (flags
.initgend
== ROLE_RANDOM
1348 && (tmp
= pick_gend(flags
.initrole
, flags
.initrace
,
1349 flags
.initalign
, PICK_RANDOM
)) != ROLE_NONE
)
1350 flags
.initgend
= tmp
;
1352 if (flags
.initrole
!= ROLE_NONE
) {
1353 if (flags
.initrace
== ROLE_NONE
)
1354 flags
.initrace
= pick_race(flags
.initrole
, flags
.initgend
,
1355 flags
.initalign
, PICK_RIGID
);
1356 if (flags
.initalign
== ROLE_NONE
)
1357 flags
.initalign
= pick_align(flags
.initrole
, flags
.initrace
,
1358 flags
.initgend
, PICK_RIGID
);
1359 if (flags
.initgend
== ROLE_NONE
)
1360 flags
.initgend
= pick_gend(flags
.initrole
, flags
.initrace
,
1361 flags
.initalign
, PICK_RIGID
);
1370 boolean reslt
= TRUE
;
1372 if ((i
= str2role(bufp
)) != ROLE_NONE
&& i
!= ROLE_RANDOM
)
1373 rfilter
.roles
[i
] = TRUE
;
1374 else if ((i
= str2race(bufp
)) != ROLE_NONE
&& i
!= ROLE_RANDOM
)
1375 rfilter
.mask
|= races
[i
].selfmask
;
1376 else if ((i
= str2gend(bufp
)) != ROLE_NONE
&& i
!= ROLE_RANDOM
)
1377 rfilter
.mask
|= genders
[i
].allow
;
1378 else if ((i
= str2align(bufp
)) != ROLE_NONE
&& i
!= ROLE_RANDOM
)
1379 rfilter
.mask
|= aligns
[i
].allow
;
1392 for (i
= 0; i
< SIZE(roles
); ++i
)
1393 if (rfilter
.roles
[i
])
1403 for (i
= 0; i
< SIZE(roles
); ++i
)
1404 rfilter
.roles
[i
] = FALSE
;
1414 STATIC_VAR
char pa
[NUM_BP
], post_attribs
;
1417 promptsep(buf
, num_post_attribs
)
1419 int num_post_attribs
;
1421 const char *conjuct
= "and ";
1423 if (num_post_attribs
> 1 && post_attribs
< num_post_attribs
1424 && post_attribs
> 1)
1428 if (!post_attribs
&& num_post_attribs
> 1)
1429 Strcat(buf
, conjuct
);
1434 role_gendercount(rolenum
)
1439 if (validrole(rolenum
)) {
1440 if (roles
[rolenum
].allow
& ROLE_MALE
)
1442 if (roles
[rolenum
].allow
& ROLE_FEMALE
)
1444 if (roles
[rolenum
].allow
& ROLE_NEUTER
)
1451 race_alignmentcount(racenum
)
1456 if (racenum
!= ROLE_NONE
&& racenum
!= ROLE_RANDOM
) {
1457 if (races
[racenum
].allow
& ROLE_CHAOTIC
)
1459 if (races
[racenum
].allow
& ROLE_LAWFUL
)
1461 if (races
[racenum
].allow
& ROLE_NEUTRAL
)
1468 root_plselection_prompt(suppliedbuf
, buflen
, rolenum
, racenum
, gendnum
,
1471 int buflen
, rolenum
, racenum
, gendnum
, alignnum
;
1473 int k
, gendercount
= 0, aligncount
= 0;
1475 static char err_ret
[] = " character's";
1476 boolean donefirst
= FALSE
;
1478 if (!suppliedbuf
|| buflen
< 1)
1481 /* initialize these static variables each time this is called */
1483 for (k
= 0; k
< NUM_BP
; ++k
)
1486 *suppliedbuf
= '\0';
1488 /* How many alignments are allowed for the desired race? */
1489 if (racenum
!= ROLE_NONE
&& racenum
!= ROLE_RANDOM
)
1490 aligncount
= race_alignmentcount(racenum
);
1492 if (alignnum
!= ROLE_NONE
&& alignnum
!= ROLE_RANDOM
1493 && ok_align(rolenum
, racenum
, gendnum
, alignnum
)) {
1494 /* if race specified, and multiple choice of alignments for it */
1495 if ((racenum
>= 0) && (aligncount
> 1)) {
1498 Strcat(buf
, aligns
[alignnum
].adj
);
1503 Strcat(buf
, aligns
[alignnum
].adj
);
1507 /* in case we got here by failing the ok_align() test */
1508 if (alignnum
!= ROLE_RANDOM
)
1509 alignnum
= ROLE_NONE
;
1510 /* if alignment not specified, but race is specified
1511 and only one choice of alignment for that race then
1512 don't include it in the later list */
1513 if ((((racenum
!= ROLE_NONE
&& racenum
!= ROLE_RANDOM
)
1514 && ok_race(rolenum
, racenum
, gendnum
, alignnum
))
1515 && (aligncount
> 1))
1516 || (racenum
== ROLE_NONE
|| racenum
== ROLE_RANDOM
)) {
1523 /* How many genders are allowed for the desired role? */
1524 if (validrole(rolenum
))
1525 gendercount
= role_gendercount(rolenum
);
1527 if (gendnum
!= ROLE_NONE
&& gendnum
!= ROLE_RANDOM
) {
1528 if (validrole(rolenum
)) {
1529 /* if role specified, and multiple choice of genders for it,
1530 and name of role itself does not distinguish gender */
1531 if ((rolenum
!= ROLE_NONE
) && (gendercount
> 1)
1532 && !roles
[rolenum
].name
.f
) {
1535 Strcat(buf
, genders
[gendnum
].adj
);
1541 Strcat(buf
, genders
[gendnum
].adj
);
1545 /* if gender not specified, but role is specified
1546 and only one choice of gender then
1547 don't include it in the later list */
1548 if ((validrole(rolenum
) && (gendercount
> 1))
1549 || !validrole(rolenum
)) {
1554 /* <your lawful female> */
1556 if (racenum
!= ROLE_NONE
&& racenum
!= ROLE_RANDOM
) {
1557 if (validrole(rolenum
)
1558 && ok_race(rolenum
, racenum
, gendnum
, alignnum
)) {
1561 Strcat(buf
, (rolenum
== ROLE_NONE
) ? races
[racenum
].noun
1562 : races
[racenum
].adj
);
1564 } else if (!validrole(rolenum
)) {
1567 Strcat(buf
, races
[racenum
].noun
);
1577 /* <your lawful female gnomish> || <your lawful female gnome> */
1579 if (validrole(rolenum
)) {
1582 if (gendnum
!= ROLE_NONE
) {
1583 if (gendnum
== 1 && roles
[rolenum
].name
.f
)
1584 Strcat(buf
, roles
[rolenum
].name
.f
);
1586 Strcat(buf
, roles
[rolenum
].name
.m
);
1588 if (roles
[rolenum
].name
.f
) {
1589 Strcat(buf
, roles
[rolenum
].name
.m
);
1591 Strcat(buf
, roles
[rolenum
].name
.f
);
1593 Strcat(buf
, roles
[rolenum
].name
.m
);
1596 } else if (rolenum
== ROLE_NONE
) {
1601 if ((racenum
== ROLE_NONE
|| racenum
== ROLE_RANDOM
)
1602 && !validrole(rolenum
)) {
1605 Strcat(buf
, "character");
1608 /* <your lawful female gnomish cavewoman> || <your lawful female gnome>
1609 * || <your lawful female character>
1611 if (buflen
> (int) (strlen(buf
) + 1)) {
1612 Strcpy(suppliedbuf
, buf
);
1619 build_plselection_prompt(buf
, buflen
, rolenum
, racenum
, gendnum
, alignnum
)
1621 int buflen
, rolenum
, racenum
, gendnum
, alignnum
;
1623 const char *defprompt
= "Shall I pick a character for you? [ynaq] ";
1624 int num_post_attribs
= 0;
1625 char tmpbuf
[BUFSZ
], *p
;
1627 if (buflen
< QBUFSZ
)
1628 return (char *) defprompt
;
1630 Strcpy(tmpbuf
, "Shall I pick ");
1631 if (racenum
!= ROLE_NONE
|| validrole(rolenum
))
1632 Strcat(tmpbuf
, "your ");
1634 Strcat(tmpbuf
, "a ");
1638 (void) root_plselection_prompt(eos(tmpbuf
), buflen
- strlen(tmpbuf
),
1639 rolenum
, racenum
, gendnum
, alignnum
);
1640 Sprintf(buf
, "%s", s_suffix(tmpbuf
));
1641 /* don't bother splitting caveman/cavewoman or priest/priestess
1642 in order to apply possessive suffix to both halves, but do
1643 change "priest/priestess'" to "priest/priestess's" */
1644 if ((p
= strstri(buf
, "priest/priestess'")) != 0
1645 && p
[sizeof "priest/priestess'" - sizeof ""] == '\0')
1646 strkitten(buf
, 's');
1648 /* buf should now be:
1649 * <your lawful female gnomish cavewoman's>
1650 * || <your lawful female gnome's>
1651 * || <your lawful female character's>
1653 * Now append the post attributes to it
1655 num_post_attribs
= post_attribs
;
1656 if (!num_post_attribs
) {
1657 /* some constraints might have been mutually exclusive, in which case
1658 some prompting that would have been omitted is needed after all */
1659 if (flags
.initrole
== ROLE_NONE
&& !pa
[BP_ROLE
])
1660 pa
[BP_ROLE
] = ++post_attribs
;
1661 if (flags
.initrace
== ROLE_NONE
&& !pa
[BP_RACE
])
1662 pa
[BP_RACE
] = ++post_attribs
;
1663 if (flags
.initalign
== ROLE_NONE
&& !pa
[BP_ALIGN
])
1664 pa
[BP_ALIGN
] = ++post_attribs
;
1665 if (flags
.initgend
== ROLE_NONE
&& !pa
[BP_GEND
])
1666 pa
[BP_GEND
] = ++post_attribs
;
1667 num_post_attribs
= post_attribs
;
1669 if (num_post_attribs
) {
1671 (void) promptsep(eos(buf
), num_post_attribs
);
1672 Strcat(buf
, "race");
1675 (void) promptsep(eos(buf
), num_post_attribs
);
1676 Strcat(buf
, "role");
1679 (void) promptsep(eos(buf
), num_post_attribs
);
1680 Strcat(buf
, "gender");
1683 (void) promptsep(eos(buf
), num_post_attribs
);
1684 Strcat(buf
, "alignment");
1687 Strcat(buf
, " for you? [ynaq] ");
1703 /* some generic user names will be ignored in favor of prompting */
1704 if (sysopt
.genericusers
) {
1705 if (*sysopt
.genericusers
== '*') *plname
= '\0';
1707 i
= (int)strlen(plname
);
1708 if ((sptr
= strstri(sysopt
.genericusers
, plname
)) != 0
1709 && (sptr
== sysopt
.genericusers
|| sptr
[-1] == ' ')
1710 && (sptr
[i
] == ' ' || sptr
[i
] == '\0'))
1711 *plname
= '\0'; /* call askname() */
1717 askname(); /* fill plname[] if necessary */
1719 /* Look for tokens delimited by '-' */
1720 if ((eptr
= index(plname
, '-')) != (char *) 0)
1723 /* Isolate the next token */
1725 if ((eptr
= index(sptr
, '-')) != (char *) 0)
1728 /* Try to match it to something */
1729 if ((i
= str2role(sptr
)) != ROLE_NONE
)
1731 else if ((i
= str2race(sptr
)) != ROLE_NONE
)
1733 else if ((i
= str2gend(sptr
)) != ROLE_NONE
)
1735 else if ((i
= str2align(sptr
)) != ROLE_NONE
)
1736 flags
.initalign
= i
;
1740 /* commas in the plname confuse the record file, convert to spaces */
1741 for (sptr
= plname
; *sptr
; sptr
++) {
1747 /* show current settings for name, role, race, gender, and alignment
1748 in the specified window */
1750 role_selection_prolog(which
, where
)
1754 static const char NEARDATA choosing
[] = " choosing now",
1755 not_yet
[] = " not yet specified",
1756 rand_choice
[] = " random";
1758 int r
, c
, g
, a
, allowmask
;
1763 a
= flags
.initalign
;
1765 allowmask
= roles
[r
].allow
;
1766 if ((allowmask
& ROLE_RACEMASK
) == MH_HUMAN
)
1767 c
= 0; /* races[human] */
1768 else if (c
>= 0 && !(allowmask
& ROLE_RACEMASK
& races
[c
].allow
))
1770 if ((allowmask
& ROLE_GENDMASK
) == ROLE_MALE
)
1771 g
= 0; /* role forces male (hypothetical) */
1772 else if ((allowmask
& ROLE_GENDMASK
) == ROLE_FEMALE
)
1773 g
= 1; /* role forces female (valkyrie) */
1774 if ((allowmask
& ROLE_ALIGNMASK
) == AM_LAWFUL
)
1775 a
= 0; /* aligns[lawful] */
1776 else if ((allowmask
& ROLE_ALIGNMASK
) == AM_NEUTRAL
)
1777 a
= 1; /* aligns[neutral] */
1778 else if ((allowmask
& ROLE_ALIGNMASK
) == AM_CHAOTIC
)
1779 a
= 2; /* alings[chaotic] */
1782 allowmask
= races
[c
].allow
;
1783 if ((allowmask
& ROLE_ALIGNMASK
) == AM_LAWFUL
)
1784 a
= 0; /* aligns[lawful] */
1785 else if ((allowmask
& ROLE_ALIGNMASK
) == AM_NEUTRAL
)
1786 a
= 1; /* aligns[neutral] */
1787 else if ((allowmask
& ROLE_ALIGNMASK
) == AM_CHAOTIC
)
1788 a
= 2; /* alings[chaotic] */
1789 /* [c never forces gender] */
1791 /* [g and a don't constrain anything sufficiently
1792 to narrow something done to a single choice] */
1794 Sprintf(buf
, "%12s ", "name:");
1795 Strcat(buf
, (which
== RS_NAME
) ? choosing
: !*plname
? not_yet
: plname
);
1796 putstr(where
, 0, buf
);
1797 Sprintf(buf
, "%12s ", "role:");
1798 Strcat(buf
, (which
== RS_ROLE
) ? choosing
: (r
== ROLE_NONE
)
1800 : (r
== ROLE_RANDOM
)
1803 if (r
>= 0 && roles
[r
].name
.f
) {
1804 /* distinct female name [caveman/cavewoman, priest/priestess] */
1806 /* female specified; replace male role name with female one */
1807 Sprintf(index(buf
, ':'), ": %s", roles
[r
].name
.f
);
1809 /* gender unspecified; append slash and female role name */
1810 Sprintf(eos(buf
), "/%s", roles
[r
].name
.f
);
1812 putstr(where
, 0, buf
);
1813 Sprintf(buf
, "%12s ", "race:");
1814 Strcat(buf
, (which
== RS_RACE
) ? choosing
: (c
== ROLE_NONE
)
1816 : (c
== ROLE_RANDOM
)
1819 putstr(where
, 0, buf
);
1820 Sprintf(buf
, "%12s ", "gender:");
1821 Strcat(buf
, (which
== RS_GENDER
) ? choosing
: (g
== ROLE_NONE
)
1823 : (g
== ROLE_RANDOM
)
1826 putstr(where
, 0, buf
);
1827 Sprintf(buf
, "%12s ", "alignment:");
1828 Strcat(buf
, (which
== RS_ALGNMNT
) ? choosing
: (a
== ROLE_NONE
)
1830 : (a
== ROLE_RANDOM
)
1833 putstr(where
, 0, buf
);
1836 /* add a "pick alignment first"-type entry to the specified menu */
1838 role_menu_extra(which
, where
, preselect
)
1843 static NEARDATA
const char RS_menu_let
[] = {
1848 '[', /* alignment */
1852 const char *what
= 0, *constrainer
= 0, *forcedvalue
= 0;
1853 int f
= 0, r
, c
, g
, a
, i
, allowmask
;
1864 for (i
= 0; i
< SIZE(roles
); ++i
)
1865 if (i
!= f
&& !rfilter
.roles
[i
])
1867 if (i
== SIZE(roles
)) {
1868 constrainer
= "filter";
1869 forcedvalue
= "role";
1875 c
= ROLE_NONE
; /* override player's setting */
1877 allowmask
= roles
[r
].allow
& ROLE_RACEMASK
;
1878 if (allowmask
== MH_HUMAN
)
1879 c
= 0; /* races[human] */
1881 constrainer
= "role";
1882 forcedvalue
= races
[c
].noun
;
1884 && (allowmask
& ~rfilter
.mask
) == races
[f
].selfmask
) {
1885 /* if there is only one race choice available due to user
1886 options disallowing others, race menu entry is disabled */
1887 constrainer
= "filter";
1888 forcedvalue
= "race";
1897 allowmask
= roles
[r
].allow
& ROLE_GENDMASK
;
1898 if (allowmask
== ROLE_MALE
)
1899 g
= 0; /* genders[male] */
1900 else if (allowmask
== ROLE_FEMALE
)
1901 g
= 1; /* genders[female] */
1903 constrainer
= "role";
1904 forcedvalue
= genders
[g
].adj
;
1906 && (allowmask
& ~rfilter
.mask
) == genders
[f
].allow
) {
1907 /* if there is only one gender choice available due to user
1908 options disallowing other, gender menu entry is disabled */
1909 constrainer
= "filter";
1910 forcedvalue
= "gender";
1916 f
= flags
.initalign
;
1919 allowmask
= roles
[r
].allow
& ROLE_ALIGNMASK
;
1920 if (allowmask
== AM_LAWFUL
)
1921 a
= 0; /* aligns[lawful] */
1922 else if (allowmask
== AM_NEUTRAL
)
1923 a
= 1; /* aligns[neutral] */
1924 else if (allowmask
== AM_CHAOTIC
)
1925 a
= 2; /* aligns[chaotic] */
1927 constrainer
= "role";
1929 if (c
>= 0 && !constrainer
) {
1930 allowmask
= races
[c
].allow
& ROLE_ALIGNMASK
;
1931 if (allowmask
== AM_LAWFUL
)
1932 a
= 0; /* aligns[lawful] */
1933 else if (allowmask
== AM_NEUTRAL
)
1934 a
= 1; /* aligns[neutral] */
1935 else if (allowmask
== AM_CHAOTIC
)
1936 a
= 2; /* aligns[chaotic] */
1938 constrainer
= "race";
1940 if (f
>= 0 && !constrainer
1941 && (ROLE_ALIGNMASK
& ~rfilter
.mask
) == aligns
[f
].allow
) {
1942 /* if there is only one alignment choice available due to user
1943 options disallowing others, algn menu entry is disabled */
1944 constrainer
= "filter";
1945 forcedvalue
= "alignment";
1948 forcedvalue
= aligns
[a
].adj
;
1952 any
= zeroany
; /* zero out all bits */
1955 /* use four spaces of padding to fake a grayed out menu choice */
1956 Sprintf(buf
, "%4s%s forces %s", "", constrainer
, forcedvalue
);
1957 add_menu(where
, NO_GLYPH
, &any
, 0, 0, ATR_NONE
, buf
,
1960 any
.a_int
= RS_menu_arg(which
);
1961 Sprintf(buf
, "Pick%s %s first", (f
>= 0) ? " another" : "", what
);
1962 add_menu(where
, NO_GLYPH
, &any
, RS_menu_let
[which
], 0, ATR_NONE
, buf
,
1964 } else if (which
== RS_filter
) {
1965 any
.a_int
= RS_menu_arg(RS_filter
);
1966 add_menu(where
, NO_GLYPH
, &any
, '~', 0, ATR_NONE
,
1967 "Reset role/race/&c filtering", MENU_UNSELECTED
);
1968 } else if (which
== ROLE_RANDOM
) {
1969 any
.a_int
= ROLE_RANDOM
;
1970 add_menu(where
, NO_GLYPH
, &any
, '*', 0, ATR_NONE
, "Random",
1971 preselect
? MENU_SELECTED
: MENU_UNSELECTED
);
1972 } else if (which
== ROLE_NONE
) {
1973 any
.a_int
= ROLE_NONE
;
1974 add_menu(where
, NO_GLYPH
, &any
, 'q', 0, ATR_NONE
, "Quit",
1975 preselect
? MENU_SELECTED
: MENU_UNSELECTED
);
1977 impossible("role_menu_extra: bad arg (%d)", which
);
1982 * Special setup modifications here:
1984 * Unfortunately, this is going to have to be done
1985 * on each newgame or restore, because you lose the permonst mods
1986 * across a save/restore. :-)
1988 * 1 - The Rogue Leader is the Tourist Nemesis.
1989 * 2 - Priests start with a random alignment - convert the leader and
1991 * 3 - Priests also get their of deities from a randomly chosen role.
1992 * 4 - [obsolete] Elves can have one of two different leaders,
1993 * but can't work it out here because it requires hacking the
1994 * level file data (see sp_lev.c).
1996 * This code also replaces quest_init().
2002 struct permonst
*pm
;
2004 /* Strip the role letter out of the player name.
2005 * This is included for backwards compatibility.
2009 /* Check for a valid role. Try flags.initrole first. */
2010 if (!validrole(flags
.initrole
)) {
2011 /* Try the player letter second */
2012 if ((flags
.initrole
= str2role(pl_character
)) < 0)
2013 /* None specified; pick a random role */
2014 flags
.initrole
= randrole_filtered();
2017 /* We now have a valid role index. Copy the role name back. */
2018 /* This should become OBSOLETE */
2019 Strcpy(pl_character
, roles
[flags
.initrole
].name
.m
);
2020 pl_character
[PL_CSIZ
- 1] = '\0';
2022 /* Check for a valid race */
2023 if (!validrace(flags
.initrole
, flags
.initrace
))
2024 flags
.initrace
= randrace(flags
.initrole
);
2026 /* Check for a valid gender. If new game, check both initgend
2027 * and female. On restore, assume flags.female is correct. */
2028 if (flags
.pantheon
== -1) { /* new game */
2029 if (!validgend(flags
.initrole
, flags
.initrace
, flags
.female
))
2030 flags
.female
= !flags
.female
;
2032 if (!validgend(flags
.initrole
, flags
.initrace
, flags
.initgend
))
2033 /* Note that there is no way to check for an unspecified gender. */
2034 flags
.initgend
= flags
.female
;
2036 /* Check for a valid alignment */
2037 if (!validalign(flags
.initrole
, flags
.initrace
, flags
.initalign
))
2038 /* Pick a random alignment */
2039 flags
.initalign
= randalign(flags
.initrole
, flags
.initrace
);
2040 alignmnt
= aligns
[flags
.initalign
].value
;
2042 /* Initialize urole and urace */
2043 urole
= roles
[flags
.initrole
];
2044 urace
= races
[flags
.initrace
];
2046 /* Fix up the quest leader */
2047 if (urole
.ldrnum
!= NON_PM
) {
2048 pm
= &mons
[urole
.ldrnum
];
2049 pm
->msound
= MS_LEADER
;
2050 pm
->mflags2
|= (M2_PEACEFUL
);
2051 pm
->mflags3
|= M3_CLOSE
;
2052 pm
->maligntyp
= alignmnt
* 3;
2053 /* if gender is random, we choose it now instead of waiting
2054 until the leader monster is created */
2055 quest_status
.ldrgend
=
2056 is_neuter(pm
) ? 2 : is_female(pm
) ? 1 : is_male(pm
)
2061 /* Fix up the quest guardians */
2062 if (urole
.guardnum
!= NON_PM
) {
2063 pm
= &mons
[urole
.guardnum
];
2064 pm
->mflags2
|= (M2_PEACEFUL
);
2065 pm
->maligntyp
= alignmnt
* 3;
2068 /* Fix up the quest nemesis */
2069 if (urole
.neminum
!= NON_PM
) {
2070 pm
= &mons
[urole
.neminum
];
2071 pm
->msound
= MS_NEMESIS
;
2072 pm
->mflags2
&= ~(M2_PEACEFUL
);
2073 pm
->mflags2
|= (M2_NASTY
| M2_STALK
| M2_HOSTILE
);
2074 pm
->mflags3
&= ~(M3_CLOSE
);
2075 pm
->mflags3
|= M3_WANTSARTI
| M3_WAITFORU
;
2076 /* if gender is random, we choose it now instead of waiting
2077 until the nemesis monster is created */
2078 quest_status
.nemgend
= is_neuter(pm
) ? 2 : is_female(pm
) ? 1
2079 : is_male(pm
) ? 0 : (rn2(100) < 50);
2082 /* Fix up the god names */
2083 if (flags
.pantheon
== -1) { /* new game */
2084 flags
.pantheon
= flags
.initrole
; /* use own gods */
2085 while (!roles
[flags
.pantheon
].lgod
) /* unless they're missing */
2086 flags
.pantheon
= randrole();
2089 urole
.lgod
= roles
[flags
.pantheon
].lgod
;
2090 urole
.ngod
= roles
[flags
.pantheon
].ngod
;
2091 urole
.cgod
= roles
[flags
.pantheon
].cgod
;
2093 /* 0 or 1; no gods are neuter, nor is gender randomized */
2094 quest_status
.godgend
= !strcmpi(align_gtitle(alignmnt
), "goddess");
2096 /* Fix up infravision */
2097 if (mons
[urace
.malenum
].mflags3
& M3_INFRAVISION
) {
2098 /* although an infravision intrinsic is possible, infravision
2099 * is purely a property of the physical race. This means that we
2100 * must put the infravision flag in the player's current race
2101 * (either that or have separate permonst entries for
2102 * elven/non-elven members of each class). The side effect is that
2103 * all NPCs of that class will have (probably bogus) infravision,
2104 * but since infravision has no effect for NPCs anyway we can
2107 mons
[urole
.malenum
].mflags3
|= M3_INFRAVISION
;
2108 if (urole
.femalenum
!= NON_PM
)
2109 mons
[urole
.femalenum
].mflags3
|= M3_INFRAVISION
;
2112 /* Artifacts are fixed in hack_artifacts() */
2122 switch (Role_switch
) {
2124 return "Salutations"; /* Olde English */
2126 return (mtmp
&& mtmp
->data
== &mons
[PM_SHOPKEEPER
])
2128 : "Konnichi wa"; /* Japanese */
2130 return "Aloha"; /* Hawaiian */
2134 (mtmp
&& mtmp
->data
== &mons
[PM_MAIL_DAEMON
]) ? "Hallo" :
2136 "Velkommen"; /* Norse */
2145 switch (Role_switch
) {
2147 return "Fare thee well"; /* Olde English */
2149 return "Sayonara"; /* Japanese */
2151 return "Aloha"; /* Hawaiian */
2153 return "Farvel"; /* Norse */