dumplog message history groundwork
[aNetHack.git] / src / role.c
blob5a1a4ab56755ec7f79e873cf1837c18b550be477
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. */
5 #include "hack.h"
7 /*** Table of all roles ***/
8 /* According to AD&D, HD for some classes (ex. Wizard) should be smaller
9 * (4-sided for wizards). But this is not AD&D, and using the AD&D
10 * rule here produces an unplayable character. Thus I have used a minimum
11 * of an 10-sided hit die for everything. Another AD&D change: wizards get
12 * a minimum strength of 4 since without one you can't teleport or cast
13 * spells. --KAA
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
22 * humans. --KMH
24 * God names use a leading underscore to flag goddesses.
26 const struct Role roles[] = {
27 { { "Archeologist", 0 },
28 { { "Digger", 0 },
29 { "Field Worker", 0 },
30 { "Investigator", 0 },
31 { "Exhumer", 0 },
32 { "Excavator", 0 },
33 { "Spelunker", 0 },
34 { "Speleologist", 0 },
35 { "Collector", 0 },
36 { "Curator", 0 } },
37 "Quetzalcoatl", "Camaxtli", "Huhetotl", /* Central American */
38 "Arc",
39 "the College of Archeology",
40 "the Tomb of the Toltec Kings",
41 PM_ARCHEOLOGIST,
42 NON_PM,
43 NON_PM,
44 PM_LORD_CARNARVON,
45 PM_STUDENT,
46 PM_MINION_OF_HUHETOTL,
47 NON_PM,
48 PM_HUMAN_MUMMY,
49 S_SNAKE,
50 S_MUMMY,
51 ART_ORB_OF_DETECTION,
52 MH_HUMAN | MH_DWARF | MH_GNOME | ROLE_MALE | ROLE_FEMALE | ROLE_LAWFUL
53 | ROLE_NEUTRAL,
54 /* Str Int Wis Dex Con Cha */
55 { 7, 10, 10, 7, 7, 7 },
56 { 20, 20, 20, 10, 20, 10 },
57 /* Init Lower Higher */
58 { 11, 0, 0, 8, 1, 0 }, /* Hit points */
59 { 1, 0, 0, 1, 0, 1 },
60 14, /* Energy */
61 10,
65 10,
66 A_INT,
67 SPE_MAGIC_MAPPING,
68 -4 },
69 { { "Barbarian", 0 },
70 { { "Plunderer", "Plunderess" },
71 { "Pillager", 0 },
72 { "Bandit", 0 },
73 { "Brigand", 0 },
74 { "Raider", 0 },
75 { "Reaver", 0 },
76 { "Slayer", 0 },
77 { "Chieftain", "Chieftainess" },
78 { "Conqueror", "Conqueress" } },
79 "Mitra", "Crom", "Set", /* Hyborian */
80 "Bar",
81 "the Camp of the Duali Tribe",
82 "the Duali Oasis",
83 PM_BARBARIAN,
84 NON_PM,
85 NON_PM,
86 PM_PELIAS,
87 PM_CHIEFTAIN,
88 PM_THOTH_AMON,
89 PM_OGRE,
90 PM_TROLL,
91 S_OGRE,
92 S_TROLL,
93 ART_HEART_OF_AHRIMAN,
94 MH_HUMAN | MH_ORC | ROLE_MALE | ROLE_FEMALE | ROLE_NEUTRAL
95 | ROLE_CHAOTIC,
96 /* Str Int Wis Dex Con Cha */
97 { 16, 7, 7, 15, 16, 6 },
98 { 30, 6, 7, 20, 30, 7 },
99 /* Init Lower Higher */
100 { 14, 0, 0, 10, 2, 0 }, /* Hit points */
101 { 1, 0, 0, 1, 0, 1 },
102 10, /* Energy */
108 A_INT,
109 SPE_HASTE_SELF,
110 -4 },
111 { { "Caveman", "Cavewoman" },
112 { { "Troglodyte", 0 },
113 { "Aborigine", 0 },
114 { "Wanderer", 0 },
115 { "Vagrant", 0 },
116 { "Wayfarer", 0 },
117 { "Roamer", 0 },
118 { "Nomad", 0 },
119 { "Rover", 0 },
120 { "Pioneer", 0 } },
121 "Anu", "_Ishtar", "Anshar", /* Babylonian */
122 "Cav",
123 "the Caves of the Ancestors",
124 "the Dragon's Lair",
125 PM_CAVEMAN,
126 PM_CAVEWOMAN,
127 PM_LITTLE_DOG,
128 PM_SHAMAN_KARNOV,
129 PM_NEANDERTHAL,
130 PM_CHROMATIC_DRAGON,
131 PM_BUGBEAR,
132 PM_HILL_GIANT,
133 S_HUMANOID,
134 S_GIANT,
135 ART_SCEPTRE_OF_MIGHT,
136 MH_HUMAN | MH_DWARF | MH_GNOME | ROLE_MALE | ROLE_FEMALE | ROLE_LAWFUL
137 | ROLE_NEUTRAL,
138 /* Str Int Wis Dex Con Cha */
139 { 10, 7, 7, 7, 8, 6 },
140 { 30, 6, 7, 20, 30, 7 },
141 /* Init Lower Higher */
142 { 14, 0, 0, 8, 2, 0 }, /* Hit points */
143 { 1, 0, 0, 1, 0, 1 },
144 10, /* Energy */
150 A_INT,
151 SPE_DIG,
152 -4 },
153 { { "Healer", 0 },
154 { { "Rhizotomist", 0 },
155 { "Empiric", 0 },
156 { "Embalmer", 0 },
157 { "Dresser", 0 },
158 { "Medicus ossium", "Medica ossium" },
159 { "Herbalist", 0 },
160 { "Magister", "Magistra" },
161 { "Physician", 0 },
162 { "Chirurgeon", 0 } },
163 "_Athena", "Hermes", "Poseidon", /* Greek */
164 "Hea",
165 "the Temple of Epidaurus",
166 "the Temple of Coeus",
167 PM_HEALER,
168 NON_PM,
169 NON_PM,
170 PM_HIPPOCRATES,
171 PM_ATTENDANT,
172 PM_CYCLOPS,
173 PM_GIANT_RAT,
174 PM_SNAKE,
175 S_RODENT,
176 S_YETI,
177 ART_STAFF_OF_AESCULAPIUS,
178 MH_HUMAN | MH_GNOME | ROLE_MALE | ROLE_FEMALE | ROLE_NEUTRAL,
179 /* Str Int Wis Dex Con Cha */
180 { 7, 7, 13, 7, 11, 16 },
181 { 15, 20, 20, 15, 25, 5 },
182 /* Init Lower Higher */
183 { 11, 0, 0, 8, 1, 0 }, /* Hit points */
184 { 1, 4, 0, 1, 0, 2 },
185 20, /* Energy */
191 A_WIS,
192 SPE_CURE_SICKNESS,
193 -4 },
194 { { "Knight", 0 },
195 { { "Gallant", 0 },
196 { "Esquire", 0 },
197 { "Bachelor", 0 },
198 { "Sergeant", 0 },
199 { "Knight", 0 },
200 { "Banneret", 0 },
201 { "Chevalier", "Chevaliere" },
202 { "Seignieur", "Dame" },
203 { "Paladin", 0 } },
204 "Lugh", "_Brigit", "Manannan Mac Lir", /* Celtic */
205 "Kni",
206 "Camelot Castle",
207 "the Isle of Glass",
208 PM_KNIGHT,
209 NON_PM,
210 PM_PONY,
211 PM_KING_ARTHUR,
212 PM_PAGE,
213 PM_IXOTH,
214 PM_QUASIT,
215 PM_OCHRE_JELLY,
216 S_IMP,
217 S_JELLY,
218 ART_MAGIC_MIRROR_OF_MERLIN,
219 MH_HUMAN | ROLE_MALE | ROLE_FEMALE | ROLE_LAWFUL,
220 /* Str Int Wis Dex Con Cha */
221 { 13, 7, 14, 8, 10, 17 },
222 { 30, 15, 15, 10, 20, 10 },
223 /* Init Lower Higher */
224 { 14, 0, 0, 8, 2, 0 }, /* Hit points */
225 { 1, 4, 0, 1, 0, 2 },
226 10, /* Energy */
232 A_WIS,
233 SPE_TURN_UNDEAD,
234 -4 },
235 { { "Monk", 0 },
236 { { "Candidate", 0 },
237 { "Novice", 0 },
238 { "Initiate", 0 },
239 { "Student of Stones", 0 },
240 { "Student of Waters", 0 },
241 { "Student of Metals", 0 },
242 { "Student of Winds", 0 },
243 { "Student of Fire", 0 },
244 { "Master", 0 } },
245 "Shan Lai Ching", "Chih Sung-tzu", "Huan Ti", /* Chinese */
246 "Mon",
247 "the Monastery of Chan-Sune",
248 "the Monastery of the Earth-Lord",
249 PM_MONK,
250 NON_PM,
251 NON_PM,
252 PM_GRAND_MASTER,
253 PM_ABBOT,
254 PM_MASTER_KAEN,
255 PM_EARTH_ELEMENTAL,
256 PM_XORN,
257 S_ELEMENTAL,
258 S_XORN,
259 ART_EYES_OF_THE_OVERWORLD,
260 MH_HUMAN | ROLE_MALE | ROLE_FEMALE | ROLE_LAWFUL | ROLE_NEUTRAL
261 | ROLE_CHAOTIC,
262 /* Str Int Wis Dex Con Cha */
263 { 10, 7, 8, 8, 7, 7 },
264 { 25, 10, 20, 20, 15, 10 },
265 /* Init Lower Higher */
266 { 12, 0, 0, 8, 1, 0 }, /* Hit points */
267 { 2, 2, 0, 2, 0, 2 },
268 10, /* Energy */
274 A_WIS,
275 SPE_RESTORE_ABILITY,
276 -4 },
277 { { "Priest", "Priestess" },
278 { { "Aspirant", 0 },
279 { "Acolyte", 0 },
280 { "Adept", 0 },
281 { "Priest", "Priestess" },
282 { "Curate", 0 },
283 { "Canon", "Canoness" },
284 { "Lama", 0 },
285 { "Patriarch", "Matriarch" },
286 { "High Priest", "High Priestess" } },
287 0, 0, 0, /* deities from a randomly chosen other role will be used */
288 "Pri",
289 "the Great Temple",
290 "the Temple of Nalzok",
291 PM_PRIEST,
292 PM_PRIESTESS,
293 NON_PM,
294 PM_ARCH_PRIEST,
295 PM_ACOLYTE,
296 PM_NALZOK,
297 PM_HUMAN_ZOMBIE,
298 PM_WRAITH,
299 S_ZOMBIE,
300 S_WRAITH,
301 ART_MITRE_OF_HOLINESS,
302 MH_HUMAN | MH_ELF | ROLE_MALE | ROLE_FEMALE | ROLE_LAWFUL | ROLE_NEUTRAL
303 | ROLE_CHAOTIC,
304 /* Str Int Wis Dex Con Cha */
305 { 7, 7, 10, 7, 7, 7 },
306 { 15, 10, 30, 15, 20, 10 },
307 /* Init Lower Higher */
308 { 12, 0, 0, 8, 1, 0 }, /* Hit points */
309 { 4, 3, 0, 2, 0, 2 },
310 10, /* Energy */
316 A_WIS,
317 SPE_REMOVE_CURSE,
318 -4 },
319 /* Note: Rogue precedes Ranger so that use of `-R' on the command line
320 retains its traditional meaning. */
321 { { "Rogue", 0 },
322 { { "Footpad", 0 },
323 { "Cutpurse", 0 },
324 { "Rogue", 0 },
325 { "Pilferer", 0 },
326 { "Robber", 0 },
327 { "Burglar", 0 },
328 { "Filcher", 0 },
329 { "Magsman", "Magswoman" },
330 { "Thief", 0 } },
331 "Issek", "Mog", "Kos", /* Nehwon */
332 "Rog",
333 "the Thieves' Guild Hall",
334 "the Assassins' Guild Hall",
335 PM_ROGUE,
336 NON_PM,
337 NON_PM,
338 PM_MASTER_OF_THIEVES,
339 PM_THUG,
340 PM_MASTER_ASSASSIN,
341 PM_LEPRECHAUN,
342 PM_GUARDIAN_NAGA,
343 S_NYMPH,
344 S_NAGA,
345 ART_MASTER_KEY_OF_THIEVERY,
346 MH_HUMAN | MH_ORC | ROLE_MALE | ROLE_FEMALE | ROLE_CHAOTIC,
347 /* Str Int Wis Dex Con Cha */
348 { 7, 7, 7, 10, 7, 6 },
349 { 20, 10, 10, 30, 20, 10 },
350 /* Init Lower Higher */
351 { 10, 0, 0, 8, 1, 0 }, /* Hit points */
352 { 1, 0, 0, 1, 0, 1 },
353 11, /* Energy */
359 A_INT,
360 SPE_DETECT_TREASURE,
361 -4 },
362 { { "Ranger", 0 },
364 #if 0 /* OBSOLETE */
365 {"Edhel", "Elleth"},
366 {"Edhel", "Elleth"}, /* elf-maid */
367 {"Ohtar", "Ohtie"}, /* warrior */
368 {"Kano", "Kanie"}, /* commander (Q.) ['a] educated guess,
369 until further research- SAC */
370 {"Arandur"," Aranduriel"}, /* king's servant, minister (Q.) - guess */
371 {"Hir", "Hiril"}, /* lord, lady (S.) ['ir] */
372 {"Aredhel", "Arwen"}, /* noble elf, maiden (S.) */
373 {"Ernil", "Elentariel"}, /* prince (S.), elf-maiden (Q.) */
374 {"Elentar", "Elentari"}, /* Star-king, -queen (Q.) */
375 "Solonor Thelandira", "Aerdrie Faenya", "Lolth", /* Elven */
376 #endif
377 { "Tenderfoot", 0 },
378 { "Lookout", 0 },
379 { "Trailblazer", 0 },
380 { "Reconnoiterer", "Reconnoiteress" },
381 { "Scout", 0 },
382 { "Arbalester", 0 }, /* One skilled at crossbows */
383 { "Archer", 0 },
384 { "Sharpshooter", 0 },
385 { "Marksman", "Markswoman" } },
386 "Mercury", "_Venus", "Mars", /* Roman/planets */
387 "Ran",
388 "Orion's camp",
389 "the cave of the wumpus",
390 PM_RANGER,
391 NON_PM,
392 PM_LITTLE_DOG /* Orion & canis major */,
393 PM_ORION,
394 PM_HUNTER,
395 PM_SCORPIUS,
396 PM_FOREST_CENTAUR,
397 PM_SCORPION,
398 S_CENTAUR,
399 S_SPIDER,
400 ART_LONGBOW_OF_DIANA,
401 MH_HUMAN | MH_ELF | MH_GNOME | MH_ORC | ROLE_MALE | ROLE_FEMALE
402 | ROLE_NEUTRAL | ROLE_CHAOTIC,
403 /* Str Int Wis Dex Con Cha */
404 { 13, 13, 13, 9, 13, 7 },
405 { 30, 10, 10, 20, 20, 10 },
406 /* Init Lower Higher */
407 { 13, 0, 0, 6, 1, 0 }, /* Hit points */
408 { 1, 0, 0, 1, 0, 1 },
409 12, /* Energy */
415 A_INT,
416 SPE_INVISIBILITY,
417 -4 },
418 { { "Samurai", 0 },
419 { { "Hatamoto", 0 }, /* Banner Knight */
420 { "Ronin", 0 }, /* no allegiance */
421 { "Ninja", "Kunoichi" }, /* secret society */
422 { "Joshu", 0 }, /* heads a castle */
423 { "Ryoshu", 0 }, /* has a territory */
424 { "Kokushu", 0 }, /* heads a province */
425 { "Daimyo", 0 }, /* a samurai lord */
426 { "Kuge", 0 }, /* Noble of the Court */
427 { "Shogun", 0 } }, /* supreme commander, warlord */
428 "_Amaterasu Omikami", "Raijin", "Susanowo", /* Japanese */
429 "Sam",
430 "the Castle of the Taro Clan",
431 "the Shogun's Castle",
432 PM_SAMURAI,
433 NON_PM,
434 PM_LITTLE_DOG,
435 PM_LORD_SATO,
436 PM_ROSHI,
437 PM_ASHIKAGA_TAKAUJI,
438 PM_WOLF,
439 PM_STALKER,
440 S_DOG,
441 S_ELEMENTAL,
442 ART_TSURUGI_OF_MURAMASA,
443 MH_HUMAN | ROLE_MALE | ROLE_FEMALE | ROLE_LAWFUL,
444 /* Str Int Wis Dex Con Cha */
445 { 10, 8, 7, 10, 17, 6 },
446 { 30, 10, 8, 30, 14, 8 },
447 /* Init Lower Higher */
448 { 13, 0, 0, 8, 1, 0 }, /* Hit points */
449 { 1, 0, 0, 1, 0, 1 },
450 11, /* Energy */
456 A_INT,
457 SPE_CLAIRVOYANCE,
458 -4 },
459 { { "Tourist", 0 },
460 { { "Rambler", 0 },
461 { "Sightseer", 0 },
462 { "Excursionist", 0 },
463 { "Peregrinator", "Peregrinatrix" },
464 { "Traveler", 0 },
465 { "Journeyer", 0 },
466 { "Voyager", 0 },
467 { "Explorer", 0 },
468 { "Adventurer", 0 } },
469 "Blind Io", "_The Lady", "Offler", /* Discworld */
470 "Tou",
471 "Ankh-Morpork",
472 "the Thieves' Guild Hall",
473 PM_TOURIST,
474 NON_PM,
475 NON_PM,
476 PM_TWOFLOWER,
477 PM_GUIDE,
478 PM_MASTER_OF_THIEVES,
479 PM_GIANT_SPIDER,
480 PM_FOREST_CENTAUR,
481 S_SPIDER,
482 S_CENTAUR,
483 ART_YENDORIAN_EXPRESS_CARD,
484 MH_HUMAN | ROLE_MALE | ROLE_FEMALE | ROLE_NEUTRAL,
485 /* Str Int Wis Dex Con Cha */
486 { 7, 10, 6, 7, 7, 10 },
487 { 15, 10, 10, 15, 30, 20 },
488 /* Init Lower Higher */
489 { 8, 0, 0, 8, 0, 0 }, /* Hit points */
490 { 1, 0, 0, 1, 0, 1 },
491 14, /* Energy */
497 A_INT,
498 SPE_CHARM_MONSTER,
499 -4 },
500 { { "Valkyrie", 0 },
501 { { "Stripling", 0 },
502 { "Skirmisher", 0 },
503 { "Fighter", 0 },
504 { "Man-at-arms", "Woman-at-arms" },
505 { "Warrior", 0 },
506 { "Swashbuckler", 0 },
507 { "Hero", "Heroine" },
508 { "Champion", 0 },
509 { "Lord", "Lady" } },
510 "Tyr", "Odin", "Loki", /* Norse */
511 "Val",
512 "the Shrine of Destiny",
513 "the cave of Surtur",
514 PM_VALKYRIE,
515 NON_PM,
516 NON_PM /*PM_WINTER_WOLF_CUB*/,
517 PM_NORN,
518 PM_WARRIOR,
519 PM_LORD_SURTUR,
520 PM_FIRE_ANT,
521 PM_FIRE_GIANT,
522 S_ANT,
523 S_GIANT,
524 ART_ORB_OF_FATE,
525 MH_HUMAN | MH_DWARF | ROLE_FEMALE | ROLE_LAWFUL | ROLE_NEUTRAL,
526 /* Str Int Wis Dex Con Cha */
527 { 10, 7, 7, 7, 10, 7 },
528 { 30, 6, 7, 20, 30, 7 },
529 /* Init Lower Higher */
530 { 14, 0, 0, 8, 2, 0 }, /* Hit points */
531 { 1, 0, 0, 1, 0, 1 },
532 10, /* Energy */
538 A_WIS,
539 SPE_CONE_OF_COLD,
540 -4 },
541 { { "Wizard", 0 },
542 { { "Evoker", 0 },
543 { "Conjurer", 0 },
544 { "Thaumaturge", 0 },
545 { "Magician", 0 },
546 { "Enchanter", "Enchantress" },
547 { "Sorcerer", "Sorceress" },
548 { "Necromancer", 0 },
549 { "Wizard", 0 },
550 { "Mage", 0 } },
551 "Ptah", "Thoth", "Anhur", /* Egyptian */
552 "Wiz",
553 "the Lonely Tower",
554 "the Tower of Darkness",
555 PM_WIZARD,
556 NON_PM,
557 PM_KITTEN,
558 PM_NEFERET_THE_GREEN,
559 PM_APPRENTICE,
560 PM_DARK_ONE,
561 PM_VAMPIRE_BAT,
562 PM_XORN,
563 S_BAT,
564 S_WRAITH,
565 ART_EYE_OF_THE_AETHIOPICA,
566 MH_HUMAN | MH_ELF | MH_GNOME | MH_ORC | ROLE_MALE | ROLE_FEMALE
567 | ROLE_NEUTRAL | ROLE_CHAOTIC,
568 /* Str Int Wis Dex Con Cha */
569 { 7, 10, 7, 7, 7, 7 },
570 { 10, 30, 10, 20, 20, 10 },
571 /* Init Lower Higher */
572 { 10, 0, 0, 8, 1, 0 }, /* Hit points */
573 { 4, 3, 0, 2, 0, 3 },
574 12, /* Energy */
580 A_INT,
581 SPE_MAGIC_MISSILE,
582 -4 },
583 /* Array terminator */
584 { { 0, 0 } }
587 /* The player's role, created at runtime from initial
588 * choices. This may be munged in role_init().
590 struct Role urole = {
591 { "Undefined", 0 },
592 { { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 },
593 { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 } },
594 "L", "N", "C",
595 "Xxx", "home", "locate",
596 NON_PM, NON_PM, NON_PM, NON_PM, NON_PM, NON_PM, NON_PM, NON_PM,
597 0, 0, 0, 0,
598 /* Str Int Wis Dex Con Cha */
599 { 7, 7, 7, 7, 7, 7 },
600 { 20, 15, 15, 20, 20, 10 },
601 /* Init Lower Higher */
602 { 10, 0, 0, 8, 1, 0 }, /* Hit points */
603 { 2, 0, 0, 2, 0, 3 },
604 14, /* Energy */
610 A_INT,
615 /* Table of all races */
616 const struct Race races[] = {
618 "human",
619 "human",
620 "humanity",
621 "Hum",
622 { "man", "woman" },
623 PM_HUMAN,
624 NON_PM,
625 PM_HUMAN_MUMMY,
626 PM_HUMAN_ZOMBIE,
627 MH_HUMAN | ROLE_MALE | ROLE_FEMALE | ROLE_LAWFUL | ROLE_NEUTRAL
628 | ROLE_CHAOTIC,
629 MH_HUMAN,
631 MH_GNOME | MH_ORC,
632 /* Str Int Wis Dex Con Cha */
633 { 3, 3, 3, 3, 3, 3 },
634 { STR18(100), 18, 18, 18, 18, 18 },
635 /* Init Lower Higher */
636 { 2, 0, 0, 2, 1, 0 }, /* Hit points */
637 { 1, 0, 2, 0, 2, 0 } /* Energy */
640 "elf",
641 "elven",
642 "elvenkind",
643 "Elf",
644 { 0, 0 },
645 PM_ELF,
646 NON_PM,
647 PM_ELF_MUMMY,
648 PM_ELF_ZOMBIE,
649 MH_ELF | ROLE_MALE | ROLE_FEMALE | ROLE_CHAOTIC,
650 MH_ELF,
651 MH_ELF,
652 MH_ORC,
653 /* Str Int Wis Dex Con Cha */
654 { 3, 3, 3, 3, 3, 3 },
655 { 18, 20, 20, 18, 16, 18 },
656 /* Init Lower Higher */
657 { 1, 0, 0, 1, 1, 0 }, /* Hit points */
658 { 2, 0, 3, 0, 3, 0 } /* Energy */
661 "dwarf",
662 "dwarven",
663 "dwarvenkind",
664 "Dwa",
665 { 0, 0 },
666 PM_DWARF,
667 NON_PM,
668 PM_DWARF_MUMMY,
669 PM_DWARF_ZOMBIE,
670 MH_DWARF | ROLE_MALE | ROLE_FEMALE | ROLE_LAWFUL,
671 MH_DWARF,
672 MH_DWARF | MH_GNOME,
673 MH_ORC,
674 /* Str Int Wis Dex Con Cha */
675 { 3, 3, 3, 3, 3, 3 },
676 { STR18(100), 16, 16, 20, 20, 16 },
677 /* Init Lower Higher */
678 { 4, 0, 0, 3, 2, 0 }, /* Hit points */
679 { 0, 0, 0, 0, 0, 0 } /* Energy */
682 "gnome",
683 "gnomish",
684 "gnomehood",
685 "Gno",
686 { 0, 0 },
687 PM_GNOME,
688 NON_PM,
689 PM_GNOME_MUMMY,
690 PM_GNOME_ZOMBIE,
691 MH_GNOME | ROLE_MALE | ROLE_FEMALE | ROLE_NEUTRAL,
692 MH_GNOME,
693 MH_DWARF | MH_GNOME,
694 MH_HUMAN,
695 /* Str Int Wis Dex Con Cha */
696 { 3, 3, 3, 3, 3, 3 },
697 { STR18(50), 19, 18, 18, 18, 18 },
698 /* Init Lower Higher */
699 { 1, 0, 0, 1, 0, 0 }, /* Hit points */
700 { 2, 0, 2, 0, 2, 0 } /* Energy */
703 "orc",
704 "orcish",
705 "orcdom",
706 "Orc",
707 { 0, 0 },
708 PM_ORC,
709 NON_PM,
710 PM_ORC_MUMMY,
711 PM_ORC_ZOMBIE,
712 MH_ORC | ROLE_MALE | ROLE_FEMALE | ROLE_CHAOTIC,
713 MH_ORC,
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 */
724 { 0, 0, 0, 0 }
727 /* The player's race, created at runtime from initial
728 * choices. This may be munged in role_init().
730 struct Race urace = {
731 "something",
732 "undefined",
733 "something",
734 "Xxx",
735 { 0, 0 },
736 NON_PM,
737 NON_PM,
738 NON_PM,
739 NON_PM,
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 }
767 /* Filters */
768 static struct {
769 boolean roles[SIZE(roles)];
770 short mask;
771 } rfilter;
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";
781 boolean
782 validrole(rolenum)
783 int rolenum;
785 return (boolean) (rolenum >= 0 && rolenum < SIZE(roles) - 1);
789 randrole()
791 return rn2(SIZE(roles) - 1);
794 STATIC_OVL int
795 randrole_filtered()
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))
806 set[n++] = i;
807 return n ? set[rn2(n)] : randrole();
811 str2role(str)
812 const char *str;
814 int i, len;
816 /* Is str valid? */
817 if (!str || !str[0])
818 return ROLE_NONE;
820 /* Match as much of str as is provided */
821 len = strlen(str);
822 for (i = 0; roles[i].name.m; i++) {
823 /* Does it match the male name? */
824 if (!strncmpi(str, roles[i].name.m, len))
825 return i;
826 /* Or the female name? */
827 if (roles[i].name.f && !strncmpi(str, roles[i].name.f, len))
828 return i;
829 /* Or the filecode? */
830 if (!strcmpi(str, roles[i].filecode))
831 return i;
834 if ((len == 1 && (*str == '*' || *str == '@'))
835 || !strncmpi(str, randomstr, len))
836 return ROLE_RANDOM;
838 /* Couldn't find anything appropriate */
839 return ROLE_NONE;
842 boolean
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
849 & ROLE_RACEMASK));
853 randrace(rolenum)
854 int rolenum;
856 int i, n = 0;
858 /* Count the number of valid races */
859 for (i = 0; races[i].noun; i++)
860 if (roles[rolenum].allow & races[i].allow & ROLE_RACEMASK)
861 n++;
863 /* Pick a random race */
864 /* Use a factor of 100 in case of bad random number generators */
865 if (n)
866 n = rn2(n * 100) / 100;
867 for (i = 0; races[i].noun; i++)
868 if (roles[rolenum].allow & races[i].allow & ROLE_RACEMASK) {
869 if (n)
870 n--;
871 else
872 return i;
875 /* This role has no permitted races? */
876 return rn2(SIZE(races) - 1);
880 str2race(str)
881 const char *str;
883 int i, len;
885 /* Is str valid? */
886 if (!str || !str[0])
887 return ROLE_NONE;
889 /* Match as much of str as is provided */
890 len = strlen(str);
891 for (i = 0; races[i].noun; i++) {
892 /* Does it match the noun? */
893 if (!strncmpi(str, races[i].noun, len))
894 return i;
895 /* Or the filecode? */
896 if (!strcmpi(str, races[i].filecode))
897 return i;
900 if ((len == 1 && (*str == '*' || *str == '@'))
901 || !strncmpi(str, randomstr, len))
902 return ROLE_RANDOM;
904 /* Couldn't find anything appropriate */
905 return ROLE_NONE;
908 boolean
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;
922 int i, n = 0;
924 /* Count the number of valid genders */
925 for (i = 0; i < ROLE_GENDERS; i++)
926 if (roles[rolenum].allow & races[racenum].allow & genders[i].allow
927 & ROLE_GENDMASK)
928 n++;
930 /* Pick a random gender */
931 if (n)
932 n = rn2(n);
933 for (i = 0; i < ROLE_GENDERS; i++)
934 if (roles[rolenum].allow & races[racenum].allow & genders[i].allow
935 & ROLE_GENDMASK) {
936 if (n)
937 n--;
938 else
939 return i;
942 /* This role/race has no permitted genders? */
943 return rn2(ROLE_GENDERS);
947 str2gend(str)
948 const char *str;
950 int i, len;
952 /* Is str valid? */
953 if (!str || !str[0])
954 return ROLE_NONE;
956 /* Match as much of str as is provided */
957 len = strlen(str);
958 for (i = 0; i < ROLE_GENDERS; i++) {
959 /* Does it match the adjective? */
960 if (!strncmpi(str, genders[i].adj, len))
961 return i;
962 /* Or the filecode? */
963 if (!strcmpi(str, genders[i].filecode))
964 return i;
966 if ((len == 1 && (*str == '*' || *str == '@'))
967 || !strncmpi(str, randomstr, len))
968 return ROLE_RANDOM;
970 /* Couldn't find anything appropriate */
971 return ROLE_NONE;
974 boolean
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;
988 int i, n = 0;
990 /* Count the number of valid alignments */
991 for (i = 0; i < ROLE_ALIGNS; i++)
992 if (roles[rolenum].allow & races[racenum].allow & aligns[i].allow
993 & ROLE_ALIGNMASK)
994 n++;
996 /* Pick a random alignment */
997 if (n)
998 n = rn2(n);
999 for (i = 0; i < ROLE_ALIGNS; i++)
1000 if (roles[rolenum].allow & races[racenum].allow & aligns[i].allow
1001 & ROLE_ALIGNMASK) {
1002 if (n)
1003 n--;
1004 else
1005 return i;
1008 /* This role/race has no permitted alignments? */
1009 return rn2(ROLE_ALIGNS);
1013 str2align(str)
1014 const char *str;
1016 int i, len;
1018 /* Is str valid? */
1019 if (!str || !str[0])
1020 return ROLE_NONE;
1022 /* Match as much of str as is provided */
1023 len = strlen(str);
1024 for (i = 0; i < ROLE_ALIGNS; i++) {
1025 /* Does it match the adjective? */
1026 if (!strncmpi(str, aligns[i].adj, len))
1027 return i;
1028 /* Or the filecode? */
1029 if (!strcmpi(str, aligns[i].filecode))
1030 return i;
1032 if ((len == 1 && (*str == '*' || *str == '@'))
1033 || !strncmpi(str, randomstr, len))
1034 return ROLE_RANDOM;
1036 /* Couldn't find anything appropriate */
1037 return ROLE_NONE;
1040 /* is rolenum compatible with any racenum/gendnum/alignnum constraints? */
1041 boolean
1042 ok_role(rolenum, racenum, gendnum, alignnum)
1043 int rolenum, racenum, gendnum, alignnum;
1045 int i;
1046 short allow;
1048 if (rolenum >= 0 && rolenum < SIZE(roles) - 1) {
1049 if (rfilter.roles[rolenum])
1050 return FALSE;
1051 allow = roles[rolenum].allow;
1052 if (racenum >= 0 && racenum < SIZE(races) - 1
1053 && !(allow & races[racenum].allow & ROLE_RACEMASK))
1054 return FALSE;
1055 if (gendnum >= 0 && gendnum < ROLE_GENDERS
1056 && !(allow & genders[gendnum].allow & ROLE_GENDMASK))
1057 return FALSE;
1058 if (alignnum >= 0 && alignnum < ROLE_ALIGNS
1059 && !(allow & aligns[alignnum].allow & ROLE_ALIGNMASK))
1060 return FALSE;
1061 return TRUE;
1062 } else {
1063 /* random; check whether any selection is possible */
1064 for (i = 0; i < SIZE(roles) - 1; i++) {
1065 if (rfilter.roles[i])
1066 continue;
1067 allow = roles[i].allow;
1068 if (racenum >= 0 && racenum < SIZE(races) - 1
1069 && !(allow & races[racenum].allow & ROLE_RACEMASK))
1070 continue;
1071 if (gendnum >= 0 && gendnum < ROLE_GENDERS
1072 && !(allow & genders[gendnum].allow & ROLE_GENDMASK))
1073 continue;
1074 if (alignnum >= 0 && alignnum < ROLE_ALIGNS
1075 && !(allow & aligns[alignnum].allow & ROLE_ALIGNMASK))
1076 continue;
1077 return TRUE;
1079 return FALSE;
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;
1090 int i;
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,
1096 gendnum, alignnum)
1097 && ok_gend(i, racenum,
1098 (gendnum >= 0) ? gendnum : ROLE_RANDOM, alignnum)
1099 && ok_race(i, racenum,
1100 gendnum, (alignnum >= 0) ? alignnum : ROLE_RANDOM))
1101 set[roles_ok++] = i;
1103 if (roles_ok == 0 || (roles_ok > 1 && pickhow == PICK_RIGID))
1104 return ROLE_NONE;
1105 return set[rn2(roles_ok)];
1108 /* is racenum compatible with any rolenum/gendnum/alignnum constraints? */
1109 boolean
1110 ok_race(rolenum, racenum, gendnum, alignnum)
1111 int rolenum, racenum, gendnum, alignnum;
1113 int i;
1114 short allow;
1116 if (racenum >= 0 && racenum < SIZE(races) - 1) {
1117 if (rfilter.mask & races[racenum].selfmask)
1118 return FALSE;
1119 allow = races[racenum].allow;
1120 if (rolenum >= 0 && rolenum < SIZE(roles) - 1
1121 && !(allow & roles[rolenum].allow & ROLE_RACEMASK))
1122 return FALSE;
1123 if (gendnum >= 0 && gendnum < ROLE_GENDERS
1124 && !(allow & genders[gendnum].allow & ROLE_GENDMASK))
1125 return FALSE;
1126 if (alignnum >= 0 && alignnum < ROLE_ALIGNS
1127 && !(allow & aligns[alignnum].allow & ROLE_ALIGNMASK))
1128 return FALSE;
1129 return TRUE;
1130 } else {
1131 /* random; check whether any selection is possible */
1132 for (i = 0; i < SIZE(races) - 1; i++) {
1133 if (rfilter.mask & races[i].selfmask)
1134 continue;
1135 allow = races[i].allow;
1136 if (rolenum >= 0 && rolenum < SIZE(roles) - 1
1137 && !(allow & roles[rolenum].allow & ROLE_RACEMASK))
1138 continue;
1139 if (gendnum >= 0 && gendnum < ROLE_GENDERS
1140 && !(allow & genders[gendnum].allow & ROLE_GENDMASK))
1141 continue;
1142 if (alignnum >= 0 && alignnum < ROLE_ALIGNS
1143 && !(allow & aligns[alignnum].allow & ROLE_ALIGNMASK))
1144 continue;
1145 return TRUE;
1147 return FALSE;
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;
1158 int i;
1159 int races_ok = 0;
1161 for (i = 0; i < SIZE(races) - 1; i++) {
1162 if (ok_race(rolenum, i, gendnum, alignnum))
1163 races_ok++;
1165 if (races_ok == 0 || (races_ok > 1 && pickhow == PICK_RIGID))
1166 return ROLE_NONE;
1167 races_ok = rn2(races_ok);
1168 for (i = 0; i < SIZE(races) - 1; i++) {
1169 if (ok_race(rolenum, i, gendnum, alignnum)) {
1170 if (races_ok == 0)
1171 return i;
1172 else
1173 races_ok--;
1176 return ROLE_NONE;
1179 /* is gendnum compatible with any rolenum/racenum/alignnum constraints? */
1180 /* gender and alignment are not comparable (and also not constrainable) */
1181 boolean
1182 ok_gend(rolenum, racenum, gendnum, alignnum)
1183 int rolenum, racenum, gendnum;
1184 int alignnum UNUSED;
1186 int i;
1187 short allow;
1189 if (gendnum >= 0 && gendnum < ROLE_GENDERS) {
1190 if (rfilter.mask & genders[gendnum].allow)
1191 return FALSE;
1192 allow = genders[gendnum].allow;
1193 if (rolenum >= 0 && rolenum < SIZE(roles) - 1
1194 && !(allow & roles[rolenum].allow & ROLE_GENDMASK))
1195 return FALSE;
1196 if (racenum >= 0 && racenum < SIZE(races) - 1
1197 && !(allow & races[racenum].allow & ROLE_GENDMASK))
1198 return FALSE;
1199 return TRUE;
1200 } else {
1201 /* random; check whether any selection is possible */
1202 for (i = 0; i < ROLE_GENDERS; i++) {
1203 if (rfilter.mask & genders[i].allow)
1204 continue;
1205 allow = genders[i].allow;
1206 if (rolenum >= 0 && rolenum < SIZE(roles) - 1
1207 && !(allow & roles[rolenum].allow & ROLE_GENDMASK))
1208 continue;
1209 if (racenum >= 0 && racenum < SIZE(races) - 1
1210 && !(allow & races[racenum].allow & ROLE_GENDMASK))
1211 continue;
1212 return TRUE;
1214 return FALSE;
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;
1226 int i;
1227 int gends_ok = 0;
1229 for (i = 0; i < ROLE_GENDERS; i++) {
1230 if (ok_gend(rolenum, racenum, i, alignnum))
1231 gends_ok++;
1233 if (gends_ok == 0 || (gends_ok > 1 && pickhow == PICK_RIGID))
1234 return ROLE_NONE;
1235 gends_ok = rn2(gends_ok);
1236 for (i = 0; i < ROLE_GENDERS; i++) {
1237 if (ok_gend(rolenum, racenum, i, alignnum)) {
1238 if (gends_ok == 0)
1239 return i;
1240 else
1241 gends_ok--;
1244 return ROLE_NONE;
1247 /* is alignnum compatible with any rolenum/racenum/gendnum constraints? */
1248 /* alignment and gender are not comparable (and also not constrainable) */
1249 boolean
1250 ok_align(rolenum, racenum, gendnum, alignnum)
1251 int rolenum, racenum;
1252 int gendnum UNUSED;
1253 int alignnum;
1255 int i;
1256 short allow;
1258 if (alignnum >= 0 && alignnum < ROLE_ALIGNS) {
1259 if (rfilter.mask & aligns[alignnum].allow)
1260 return FALSE;
1261 allow = aligns[alignnum].allow;
1262 if (rolenum >= 0 && rolenum < SIZE(roles) - 1
1263 && !(allow & roles[rolenum].allow & ROLE_ALIGNMASK))
1264 return FALSE;
1265 if (racenum >= 0 && racenum < SIZE(races) - 1
1266 && !(allow & races[racenum].allow & ROLE_ALIGNMASK))
1267 return FALSE;
1268 return TRUE;
1269 } else {
1270 /* random; check whether any selection is possible */
1271 for (i = 0; i < ROLE_ALIGNS; i++) {
1272 if (rfilter.mask & aligns[i].allow)
1273 return FALSE;
1274 allow = aligns[i].allow;
1275 if (rolenum >= 0 && rolenum < SIZE(roles) - 1
1276 && !(allow & roles[rolenum].allow & ROLE_ALIGNMASK))
1277 continue;
1278 if (racenum >= 0 && racenum < SIZE(races) - 1
1279 && !(allow & races[racenum].allow & ROLE_ALIGNMASK))
1280 continue;
1281 return TRUE;
1283 return FALSE;
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;
1295 int i;
1296 int aligns_ok = 0;
1298 for (i = 0; i < ROLE_ALIGNS; i++) {
1299 if (ok_align(rolenum, racenum, gendnum, i))
1300 aligns_ok++;
1302 if (aligns_ok == 0 || (aligns_ok > 1 && pickhow == PICK_RIGID))
1303 return ROLE_NONE;
1304 aligns_ok = rn2(aligns_ok);
1305 for (i = 0; i < ROLE_ALIGNS; i++) {
1306 if (ok_align(rolenum, racenum, gendnum, i)) {
1307 if (aligns_ok == 0)
1308 return i;
1309 else
1310 aligns_ok--;
1313 return ROLE_NONE;
1316 void
1317 rigid_role_checks()
1319 int tmp;
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);
1365 boolean
1366 setrolefilter(bufp)
1367 const char *bufp;
1369 int i;
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;
1380 else
1381 reslt = FALSE;
1382 return reslt;
1385 boolean
1386 gotrolefilter()
1388 int i;
1390 if (rfilter.mask)
1391 return TRUE;
1392 for (i = 0; i < SIZE(roles); ++i)
1393 if (rfilter.roles[i])
1394 return TRUE;
1395 return FALSE;
1398 void
1399 clearrolefilter()
1401 int i;
1403 for (i = 0; i < SIZE(roles); ++i)
1404 rfilter.roles[i] = FALSE;
1405 rfilter.mask = 0;
1408 #define BP_ALIGN 0
1409 #define BP_GEND 1
1410 #define BP_RACE 2
1411 #define BP_ROLE 3
1412 #define NUM_BP 4
1414 STATIC_VAR char pa[NUM_BP], post_attribs;
1416 STATIC_OVL char *
1417 promptsep(buf, num_post_attribs)
1418 char *buf;
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)
1425 Strcat(buf, ",");
1426 Strcat(buf, " ");
1427 --post_attribs;
1428 if (!post_attribs && num_post_attribs > 1)
1429 Strcat(buf, conjuct);
1430 return buf;
1433 STATIC_OVL int
1434 role_gendercount(rolenum)
1435 int rolenum;
1437 int gendcount = 0;
1439 if (validrole(rolenum)) {
1440 if (roles[rolenum].allow & ROLE_MALE)
1441 ++gendcount;
1442 if (roles[rolenum].allow & ROLE_FEMALE)
1443 ++gendcount;
1444 if (roles[rolenum].allow & ROLE_NEUTER)
1445 ++gendcount;
1447 return gendcount;
1450 STATIC_OVL int
1451 race_alignmentcount(racenum)
1452 int racenum;
1454 int aligncount = 0;
1456 if (racenum != ROLE_NONE && racenum != ROLE_RANDOM) {
1457 if (races[racenum].allow & ROLE_CHAOTIC)
1458 ++aligncount;
1459 if (races[racenum].allow & ROLE_LAWFUL)
1460 ++aligncount;
1461 if (races[racenum].allow & ROLE_NEUTRAL)
1462 ++aligncount;
1464 return aligncount;
1467 char *
1468 root_plselection_prompt(suppliedbuf, buflen, rolenum, racenum, gendnum,
1469 alignnum)
1470 char *suppliedbuf;
1471 int buflen, rolenum, racenum, gendnum, alignnum;
1473 int k, gendercount = 0, aligncount = 0;
1474 char buf[BUFSZ];
1475 static char err_ret[] = " character's";
1476 boolean donefirst = FALSE;
1478 if (!suppliedbuf || buflen < 1)
1479 return err_ret;
1481 /* initialize these static variables each time this is called */
1482 post_attribs = 0;
1483 for (k = 0; k < NUM_BP; ++k)
1484 pa[k] = 0;
1485 buf[0] = '\0';
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)) {
1496 if (donefirst)
1497 Strcat(buf, " ");
1498 Strcat(buf, aligns[alignnum].adj);
1499 donefirst = TRUE;
1500 } else {
1501 if (donefirst)
1502 Strcat(buf, " ");
1503 Strcat(buf, aligns[alignnum].adj);
1504 donefirst = TRUE;
1506 } else {
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)) {
1517 pa[BP_ALIGN] = 1;
1518 post_attribs++;
1521 /* <your lawful> */
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) {
1533 if (donefirst)
1534 Strcat(buf, " ");
1535 Strcat(buf, genders[gendnum].adj);
1536 donefirst = TRUE;
1538 } else {
1539 if (donefirst)
1540 Strcat(buf, " ");
1541 Strcat(buf, genders[gendnum].adj);
1542 donefirst = TRUE;
1544 } else {
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)) {
1550 pa[BP_GEND] = 1;
1551 post_attribs++;
1554 /* <your lawful female> */
1556 if (racenum != ROLE_NONE && racenum != ROLE_RANDOM) {
1557 if (validrole(rolenum)
1558 && ok_race(rolenum, racenum, gendnum, alignnum)) {
1559 if (donefirst)
1560 Strcat(buf, " ");
1561 Strcat(buf, (rolenum == ROLE_NONE) ? races[racenum].noun
1562 : races[racenum].adj);
1563 donefirst = TRUE;
1564 } else if (!validrole(rolenum)) {
1565 if (donefirst)
1566 Strcat(buf, " ");
1567 Strcat(buf, races[racenum].noun);
1568 donefirst = TRUE;
1569 } else {
1570 pa[BP_RACE] = 1;
1571 post_attribs++;
1573 } else {
1574 pa[BP_RACE] = 1;
1575 post_attribs++;
1577 /* <your lawful female gnomish> || <your lawful female gnome> */
1579 if (validrole(rolenum)) {
1580 if (donefirst)
1581 Strcat(buf, " ");
1582 if (gendnum != ROLE_NONE) {
1583 if (gendnum == 1 && roles[rolenum].name.f)
1584 Strcat(buf, roles[rolenum].name.f);
1585 else
1586 Strcat(buf, roles[rolenum].name.m);
1587 } else {
1588 if (roles[rolenum].name.f) {
1589 Strcat(buf, roles[rolenum].name.m);
1590 Strcat(buf, "/");
1591 Strcat(buf, roles[rolenum].name.f);
1592 } else
1593 Strcat(buf, roles[rolenum].name.m);
1595 donefirst = TRUE;
1596 } else if (rolenum == ROLE_NONE) {
1597 pa[BP_ROLE] = 1;
1598 post_attribs++;
1601 if ((racenum == ROLE_NONE || racenum == ROLE_RANDOM)
1602 && !validrole(rolenum)) {
1603 if (donefirst)
1604 Strcat(buf, " ");
1605 Strcat(buf, "character");
1606 donefirst = TRUE;
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);
1613 return suppliedbuf;
1614 } else
1615 return err_ret;
1618 char *
1619 build_plselection_prompt(buf, buflen, rolenum, racenum, gendnum, alignnum)
1620 char *buf;
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 ");
1633 else {
1634 Strcat(tmpbuf, "a ");
1636 /* <your> */
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) {
1670 if (pa[BP_RACE]) {
1671 (void) promptsep(eos(buf), num_post_attribs);
1672 Strcat(buf, "race");
1674 if (pa[BP_ROLE]) {
1675 (void) promptsep(eos(buf), num_post_attribs);
1676 Strcat(buf, "role");
1678 if (pa[BP_GEND]) {
1679 (void) promptsep(eos(buf), num_post_attribs);
1680 Strcat(buf, "gender");
1682 if (pa[BP_ALIGN]) {
1683 (void) promptsep(eos(buf), num_post_attribs);
1684 Strcat(buf, "alignment");
1687 Strcat(buf, " for you? [ynaq] ");
1688 return buf;
1691 #undef BP_ALIGN
1692 #undef BP_GEND
1693 #undef BP_RACE
1694 #undef BP_ROLE
1695 #undef NUM_BP
1697 void
1698 plnamesuffix()
1700 char *sptr, *eptr;
1701 int i;
1703 /* some generic user names will be ignored in favor of prompting */
1704 if (sysopt.genericusers) {
1705 if (*sysopt.genericusers == '*') *plname = '\0';
1706 else {
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() */
1715 do {
1716 if (!*plname)
1717 askname(); /* fill plname[] if necessary */
1719 /* Look for tokens delimited by '-' */
1720 if ((eptr = index(plname, '-')) != (char *) 0)
1721 *eptr++ = '\0';
1722 while (eptr) {
1723 /* Isolate the next token */
1724 sptr = eptr;
1725 if ((eptr = index(sptr, '-')) != (char *) 0)
1726 *eptr++ = '\0';
1728 /* Try to match it to something */
1729 if ((i = str2role(sptr)) != ROLE_NONE)
1730 flags.initrole = i;
1731 else if ((i = str2race(sptr)) != ROLE_NONE)
1732 flags.initrace = i;
1733 else if ((i = str2gend(sptr)) != ROLE_NONE)
1734 flags.initgend = i;
1735 else if ((i = str2align(sptr)) != ROLE_NONE)
1736 flags.initalign = i;
1738 } while (!*plname);
1740 /* commas in the plname confuse the record file, convert to spaces */
1741 for (sptr = plname; *sptr; sptr++) {
1742 if (*sptr == ',')
1743 *sptr = ' ';
1747 /* show current settings for name, role, race, gender, and alignment
1748 in the specified window */
1749 void
1750 role_selection_prolog(which, where)
1751 int which;
1752 winid where;
1754 static const char NEARDATA choosing[] = " choosing now",
1755 not_yet[] = " not yet specified",
1756 rand_choice[] = " random";
1757 char buf[BUFSZ];
1758 int r, c, g, a, allowmask;
1760 r = flags.initrole;
1761 c = flags.initrace;
1762 g = flags.initgend;
1763 a = flags.initalign;
1764 if (r >= 0) {
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))
1769 c = ROLE_RANDOM;
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] */
1781 if (c >= 0) {
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)
1799 ? not_yet
1800 : (r == ROLE_RANDOM)
1801 ? rand_choice
1802 : roles[r].name.m);
1803 if (r >= 0 && roles[r].name.f) {
1804 /* distinct female name [caveman/cavewoman, priest/priestess] */
1805 if (g == 1)
1806 /* female specified; replace male role name with female one */
1807 Sprintf(index(buf, ':'), ": %s", roles[r].name.f);
1808 else if (g < 0)
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)
1815 ? not_yet
1816 : (c == ROLE_RANDOM)
1817 ? rand_choice
1818 : races[c].noun);
1819 putstr(where, 0, buf);
1820 Sprintf(buf, "%12s ", "gender:");
1821 Strcat(buf, (which == RS_GENDER) ? choosing : (g == ROLE_NONE)
1822 ? not_yet
1823 : (g == ROLE_RANDOM)
1824 ? rand_choice
1825 : genders[g].adj);
1826 putstr(where, 0, buf);
1827 Sprintf(buf, "%12s ", "alignment:");
1828 Strcat(buf, (which == RS_ALGNMNT) ? choosing : (a == ROLE_NONE)
1829 ? not_yet
1830 : (a == ROLE_RANDOM)
1831 ? rand_choice
1832 : aligns[a].adj);
1833 putstr(where, 0, buf);
1836 /* add a "pick alignment first"-type entry to the specified menu */
1837 void
1838 role_menu_extra(which, where, preselect)
1839 int which;
1840 winid where;
1841 boolean preselect;
1843 static NEARDATA const char RS_menu_let[] = {
1844 '=', /* name */
1845 '?', /* role */
1846 '/', /* race */
1847 '\"', /* gender */
1848 '[', /* alignment */
1850 anything any;
1851 char buf[BUFSZ];
1852 const char *what = 0, *constrainer = 0, *forcedvalue = 0;
1853 int f = 0, r, c, g, a, i, allowmask;
1855 r = flags.initrole;
1856 c = flags.initrace;
1857 switch (which) {
1858 case RS_NAME:
1859 what = "name";
1860 break;
1861 case RS_ROLE:
1862 what = "role";
1863 f = r;
1864 for (i = 0; i < SIZE(roles); ++i)
1865 if (i != f && !rfilter.roles[i])
1866 break;
1867 if (i == SIZE(roles)) {
1868 constrainer = "filter";
1869 forcedvalue = "role";
1871 break;
1872 case RS_RACE:
1873 what = "race";
1874 f = flags.initrace;
1875 c = ROLE_NONE; /* override player's setting */
1876 if (r >= 0) {
1877 allowmask = roles[r].allow & ROLE_RACEMASK;
1878 if (allowmask == MH_HUMAN)
1879 c = 0; /* races[human] */
1880 if (c >= 0) {
1881 constrainer = "role";
1882 forcedvalue = races[c].noun;
1883 } else if (f >= 0
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";
1891 break;
1892 case RS_GENDER:
1893 what = "gender";
1894 f = flags.initgend;
1895 g = ROLE_NONE;
1896 if (r >= 0) {
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] */
1902 if (g >= 0) {
1903 constrainer = "role";
1904 forcedvalue = genders[g].adj;
1905 } else if (f >= 0
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";
1913 break;
1914 case RS_ALGNMNT:
1915 what = "alignment";
1916 f = flags.initalign;
1917 a = ROLE_NONE;
1918 if (r >= 0) {
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] */
1926 if (a >= 0)
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] */
1937 if (a >= 0)
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";
1947 if (a >= 0)
1948 forcedvalue = aligns[a].adj;
1949 break;
1952 any = zeroany; /* zero out all bits */
1953 if (constrainer) {
1954 any.a_int = 0;
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,
1958 MENU_UNSELECTED);
1959 } else if (what) {
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,
1963 MENU_UNSELECTED);
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);
1976 } else {
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
1990 * guardians here.
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().
1998 void
1999 role_init()
2001 int alignmnt;
2002 struct permonst *pm;
2004 /* Strip the role letter out of the player name.
2005 * This is included for backwards compatibility.
2007 plnamesuffix();
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)
2058 : (rn2(100) < 50);
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();
2088 if (!urole.lgod) {
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
2105 * ignore this.
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() */
2114 /* Success! */
2115 return;
2118 const char *
2119 Hello(mtmp)
2120 struct monst *mtmp;
2122 switch (Role_switch) {
2123 case PM_KNIGHT:
2124 return "Salutations"; /* Olde English */
2125 case PM_SAMURAI:
2126 return (mtmp && mtmp->data == &mons[PM_SHOPKEEPER])
2127 ? "Irasshaimase"
2128 : "Konnichi wa"; /* Japanese */
2129 case PM_TOURIST:
2130 return "Aloha"; /* Hawaiian */
2131 case PM_VALKYRIE:
2132 return
2133 #ifdef MAIL
2134 (mtmp && mtmp->data == &mons[PM_MAIL_DAEMON]) ? "Hallo" :
2135 #endif
2136 "Velkommen"; /* Norse */
2137 default:
2138 return "Hello";
2142 const char *
2143 Goodbye()
2145 switch (Role_switch) {
2146 case PM_KNIGHT:
2147 return "Fare thee well"; /* Olde English */
2148 case PM_SAMURAI:
2149 return "Sayonara"; /* Japanese */
2150 case PM_TOURIST:
2151 return "Aloha"; /* Hawaiian */
2152 case PM_VALKYRIE:
2153 return "Farvel"; /* Norse */
2154 default:
2155 return "Goodbye";
2159 /* role.c */