1/* SCCS Id: @(#)role.c 3.4 2003/01/08 */ 2/* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985-1999. */ 3/* NetHack may be freely redistributed. See license for details. */ 4 5#include "hack.h" 6 7 8/*** Table of all roles ***/ 9/* According to AD&D, HD for some classes (ex. Wizard) should be smaller 10 * (4-sided for wizards). But this is not AD&D, and using the AD&D 11 * rule here produces an unplayable character. Thus I have used a minimum 12 * of an 10-sided hit die for everything. Another AD&D change: wizards get 13 * a minimum strength of 4 since without one you can't teleport or cast 14 * spells. --KAA 15 * 16 * As the wizard has been updated (wizard patch 5 jun '96) their HD can be 17 * brought closer into line with AD&D. This forces wizards to use magic more 18 * and distance themselves from their attackers. --LSZ 19 * 20 * With the introduction of races, some hit points and energy 21 * has been reallocated for each race. The values assigned 22 * to the roles has been reduced by the amount allocated to 23 * humans. --KMH 24 * 25 * God names use a leading underscore to flag goddesses. 26 */ 27const struct Role roles[] = { 28{ {"Archeologist", 0}, { 29 {"Digger", 0}, 30 {"Field Worker",0}, 31 {"Investigator",0}, 32 {"Exhumer", 0}, 33 {"Excavator", 0}, 34 {"Spelunker", 0}, 35 {"Speleologist",0}, 36 {"Collector", 0}, 37 {"Curator", 0} }, 38 "Quetzalcoatl", "Camaxtli", "Huhetotl", /* Central American */ 39 "Arc", "the College of Archeology", "the Tomb of the Toltec Kings", 40 PM_ARCHEOLOGIST, NON_PM, NON_PM, 41 PM_LORD_CARNARVON, PM_STUDENT, PM_MINION_OF_HUHETOTL, 42 NON_PM, PM_HUMAN_MUMMY, S_SNAKE, S_MUMMY, 43 ART_ORB_OF_DETECTION, 44 MH_HUMAN|MH_DWARF|MH_GNOME | ROLE_MALE|ROLE_FEMALE | 45 ROLE_LAWFUL|ROLE_NEUTRAL, 46 /* Str Int Wis Dex Con Cha */ 47 { 7, 10, 10, 7, 7, 7 }, 48 { 20, 20, 20, 10, 20, 10 }, 49 /* Init Lower Higher */ 50 { 11, 0, 0, 8, 1, 0 }, /* Hit points */ 51 { 1, 0, 0, 1, 0, 1 },14, /* Energy */ 52 10, 5, 0, 2, 10, A_INT, SPE_MAGIC_MAPPING, -4 53}, 54{ {"Barbarian", 0}, { 55 {"Plunderer", "Plunderess"}, 56 {"Pillager", 0}, 57 {"Bandit", 0}, 58 {"Brigand", 0}, 59 {"Raider", 0}, 60 {"Reaver", 0}, 61 {"Slayer", 0}, 62 {"Chieftain", "Chieftainess"}, 63 {"Conqueror", "Conqueress"} }, 64 "Mitra", "Crom", "Set", /* Hyborian */ 65 "Bar", "the Camp of the Duali Tribe", "the Duali Oasis", 66 PM_BARBARIAN, NON_PM, NON_PM, 67 PM_PELIAS, PM_CHIEFTAIN, PM_THOTH_AMON, 68 PM_OGRE, PM_TROLL, S_OGRE, S_TROLL, 69 ART_HEART_OF_AHRIMAN, 70 MH_HUMAN|MH_ORC | ROLE_MALE|ROLE_FEMALE | 71 ROLE_NEUTRAL|ROLE_CHAOTIC, 72 /* Str Int Wis Dex Con Cha */ 73 { 16, 7, 7, 15, 16, 6 }, 74 { 30, 6, 7, 20, 30, 7 }, 75 /* Init Lower Higher */ 76 { 14, 0, 0,10, 2, 0 }, /* Hit points */ 77 { 1, 0, 0, 1, 0, 1 },10, /* Energy */ 78 10, 14, 0, 0, 8, A_INT, SPE_HASTE_SELF, -4 79}, 80{ {"Caveman", "Cavewoman"}, { 81 {"Troglodyte", 0}, 82 {"Aborigine", 0}, 83 {"Wanderer", 0}, 84 {"Vagrant", 0}, 85 {"Wayfarer", 0}, 86 {"Roamer", 0}, 87 {"Nomad", 0}, 88 {"Rover", 0}, 89 {"Pioneer", 0} }, 90 "Anu", "_Ishtar", "Anshar", /* Babylonian */ 91 "Cav", "the Caves of the Ancestors", "the Dragon's Lair", 92 PM_CAVEMAN, PM_CAVEWOMAN, PM_LITTLE_DOG, 93 PM_SHAMAN_KARNOV, PM_NEANDERTHAL, PM_CHROMATIC_DRAGON, 94 PM_BUGBEAR, PM_HILL_GIANT, S_HUMANOID, S_GIANT, 95 ART_SCEPTRE_OF_MIGHT, 96 MH_HUMAN|MH_DWARF|MH_GNOME | ROLE_MALE|ROLE_FEMALE | 97 ROLE_LAWFUL|ROLE_NEUTRAL, 98 /* Str Int Wis Dex Con Cha */ 99 { 10, 7, 7, 7, 8, 6 }, 100 { 30, 6, 7, 20, 30, 7 }, 101 /* Init Lower Higher */ 102 { 14, 0, 0, 8, 2, 0 }, /* Hit points */ 103 { 1, 0, 0, 1, 0, 1 },10, /* Energy */ 104 0, 12, 0, 1, 8, A_INT, SPE_DIG, -4 105}, 106{ {"Healer", 0}, { 107 {"Rhizotomist", 0}, 108 {"Empiric", 0}, 109 {"Embalmer", 0}, 110 {"Dresser", 0}, 111 {"Medicus ossium", "Medica ossium"}, 112 {"Herbalist", 0}, 113 {"Magister", "Magistra"}, 114 {"Physician", 0}, 115 {"Chirurgeon", 0} }, 116 "_Athena", "Hermes", "Poseidon", /* Greek */ 117 "Hea", "the Temple of Epidaurus", "the Temple of Coeus", 118 PM_HEALER, NON_PM, NON_PM, 119 PM_HIPPOCRATES, PM_ATTENDANT, PM_CYCLOPS, 120 PM_GIANT_RAT, PM_SNAKE, S_RODENT, S_YETI, 121 ART_STAFF_OF_AESCULAPIUS, 122 MH_HUMAN|MH_GNOME | ROLE_MALE|ROLE_FEMALE | ROLE_NEUTRAL, 123 /* Str Int Wis Dex Con Cha */ 124 { 7, 7, 13, 7, 11, 16 }, 125 { 15, 20, 20, 15, 25, 5 }, 126 /* Init Lower Higher */ 127 { 11, 0, 0, 8, 1, 0 }, /* Hit points */ 128 { 1, 4, 0, 1, 0, 2 },20, /* Energy */ 129 10, 3,-3, 2, 10, A_WIS, SPE_CURE_SICKNESS, -4 130}, 131{ {"Knight", 0}, { 132 {"Gallant", 0}, 133 {"Esquire", 0}, 134 {"Bachelor", 0}, 135 {"Sergeant", 0}, 136 {"Knight", 0}, 137 {"Banneret", 0}, 138 {"Chevalier", "Chevaliere"}, 139 {"Seignieur", "Dame"}, 140 {"Paladin", 0} }, 141 "Lugh", "_Brigit", "Manannan Mac Lir", /* Celtic */ 142 "Kni", "Camelot Castle", "the Isle of Glass", 143 PM_KNIGHT, NON_PM, PM_PONY, 144 PM_KING_ARTHUR, PM_PAGE, PM_IXOTH, 145 PM_QUASIT, PM_OCHRE_JELLY, S_IMP, S_JELLY, 146 ART_MAGIC_MIRROR_OF_MERLIN, 147 MH_HUMAN | ROLE_MALE|ROLE_FEMALE | ROLE_LAWFUL, 148 /* Str Int Wis Dex Con Cha */ 149 { 13, 7, 14, 8, 10, 17 }, 150 { 30, 15, 15, 10, 20, 10 }, 151 /* Init Lower Higher */ 152 { 14, 0, 0, 8, 2, 0 }, /* Hit points */ 153 { 1, 4, 0, 1, 0, 2 },10, /* Energy */ 154 10, 8,-2, 0, 9, A_WIS, SPE_TURN_UNDEAD, -4 155}, 156{ {"Monk", 0}, { 157 {"Candidate", 0}, 158 {"Novice", 0}, 159 {"Initiate", 0}, 160 {"Student of Stones", 0}, 161 {"Student of Waters", 0}, 162 {"Student of Metals", 0}, 163 {"Student of Winds", 0}, 164 {"Student of Fire", 0}, 165 {"Master", 0} }, 166 "Shan Lai Ching", "Chih Sung-tzu", "Huan Ti", /* Chinese */ 167 "Mon", "the Monastery of Chan-Sune", 168 "the Monastery of the Earth-Lord", 169 PM_MONK, NON_PM, NON_PM, 170 PM_GRAND_MASTER, PM_ABBOT, PM_MASTER_KAEN, 171 PM_EARTH_ELEMENTAL, PM_XORN, S_ELEMENTAL, S_XORN, 172 ART_EYES_OF_THE_OVERWORLD, 173 MH_HUMAN | ROLE_MALE|ROLE_FEMALE | 174 ROLE_LAWFUL|ROLE_NEUTRAL|ROLE_CHAOTIC, 175 /* Str Int Wis Dex Con Cha */ 176 { 10, 7, 8, 8, 7, 7 }, 177 { 25, 10, 20, 20, 15, 10 }, 178 /* Init Lower Higher */ 179 { 12, 0, 0, 8, 1, 0 }, /* Hit points */ 180 { 2, 2, 0, 2, 0, 2 },10, /* Energy */ 181 10, 8,-2, 2, 20, A_WIS, SPE_RESTORE_ABILITY, -4 182}, 183{ {"Priest", "Priestess"}, { 184 {"Aspirant", 0}, 185 {"Acolyte", 0}, 186 {"Adept", 0}, 187 {"Priest", "Priestess"}, 188 {"Curate", 0}, 189 {"Canon", "Canoness"}, 190 {"Lama", 0}, 191 {"Patriarch", "Matriarch"}, 192 {"High Priest", "High Priestess"} }, 193 0, 0, 0, /* chosen randomly from among the other roles */ 194 "Pri", "the Great Temple", "the Temple of Nalzok", 195 PM_PRIEST, PM_PRIESTESS, NON_PM, 196 PM_ARCH_PRIEST, PM_ACOLYTE, PM_NALZOK, 197 PM_HUMAN_ZOMBIE, PM_WRAITH, S_ZOMBIE, S_WRAITH, 198 ART_MITRE_OF_HOLINESS, 199 MH_HUMAN|MH_ELF | ROLE_MALE|ROLE_FEMALE | 200 ROLE_LAWFUL|ROLE_NEUTRAL|ROLE_CHAOTIC, 201 /* Str Int Wis Dex Con Cha */ 202 { 7, 7, 10, 7, 7, 7 }, 203 { 15, 10, 30, 15, 20, 10 }, 204 /* Init Lower Higher */ 205 { 12, 0, 0, 8, 1, 0 }, /* Hit points */ 206 { 4, 3, 0, 2, 0, 2 },10, /* Energy */ 207 0, 3,-2, 2, 10, A_WIS, SPE_REMOVE_CURSE, -4 208}, 209 /* Note: Rogue precedes Ranger so that use of `-R' on the command line 210 retains its traditional meaning. */ 211{ {"Rogue", 0}, { 212 {"Footpad", 0}, 213 {"Cutpurse", 0}, 214 {"Rogue", 0}, 215 {"Pilferer", 0}, 216 {"Robber", 0}, 217 {"Burglar", 0}, 218 {"Filcher", 0}, 219 {"Magsman", "Magswoman"}, 220 {"Thief", 0} }, 221 "Issek", "Mog", "Kos", /* Nehwon */ 222 "Rog", "the Thieves' Guild Hall", "the Assassins' Guild Hall", 223 PM_ROGUE, NON_PM, NON_PM, 224 PM_MASTER_OF_THIEVES, PM_THUG, PM_MASTER_ASSASSIN, 225 PM_LEPRECHAUN, PM_GUARDIAN_NAGA, S_NYMPH, S_NAGA, 226 ART_MASTER_KEY_OF_THIEVERY, 227 MH_HUMAN|MH_ORC | ROLE_MALE|ROLE_FEMALE | 228 ROLE_CHAOTIC, 229 /* Str Int Wis Dex Con Cha */ 230 { 7, 7, 7, 10, 7, 6 }, 231 { 20, 10, 10, 30, 20, 10 }, 232 /* Init Lower Higher */ 233 { 10, 0, 0, 8, 1, 0 }, /* Hit points */ 234 { 1, 0, 0, 1, 0, 1 },11, /* Energy */ 235 10, 8, 0, 1, 9, A_INT, SPE_DETECT_TREASURE, -4 236}, 237{ {"Ranger", 0}, { 238#if 0 /* OBSOLETE */ 239 {"Edhel", "Elleth"}, 240 {"Edhel", "Elleth"}, /* elf-maid */ 241 {"Ohtar", "Ohtie"}, /* warrior */ 242 {"Kano", /* commander (Q.) ['a] */ 243 "Kanie"}, /* educated guess, until further research- SAC */ 244 {"Arandur", /* king's servant, minister (Q.) - guess */ 245 "Aranduriel"}, /* educated guess */ 246 {"Hir", "Hiril"}, /* lord, lady (S.) ['ir] */ 247 {"Aredhel", "Arwen"}, /* noble elf, maiden (S.) */ 248 {"Ernil", "Elentariel"}, /* prince (S.), elf-maiden (Q.) */ 249 {"Elentar", "Elentari"}, /* Star-king, -queen (Q.) */ 250 "Solonor Thelandira", "Aerdrie Faenya", "Lolth", /* Elven */ 251#endif 252 {"Tenderfoot", 0}, 253 {"Lookout", 0}, 254 {"Trailblazer", 0}, 255 {"Reconnoiterer", "Reconnoiteress"}, 256 {"Scout", 0}, 257 {"Arbalester", 0}, /* One skilled at crossbows */ 258 {"Archer", 0}, 259 {"Sharpshooter", 0}, 260 {"Marksman", "Markswoman"} }, 261 "Mercury", "_Venus", "Mars", /* Roman/planets */ 262 "Ran", "Orion's camp", "the cave of the wumpus", 263 PM_RANGER, NON_PM, PM_LITTLE_DOG /* Orion & canis major */, 264 PM_ORION, PM_HUNTER, PM_SCORPIUS, 265 PM_FOREST_CENTAUR, PM_SCORPION, S_CENTAUR, S_SPIDER, 266 ART_LONGBOW_OF_DIANA, 267 MH_HUMAN|MH_ELF|MH_GNOME|MH_ORC | ROLE_MALE|ROLE_FEMALE | 268 ROLE_NEUTRAL|ROLE_CHAOTIC, 269 /* Str Int Wis Dex Con Cha */ 270 { 13, 13, 13, 9, 13, 7 }, 271 { 30, 10, 10, 20, 20, 10 }, 272 /* Init Lower Higher */ 273 { 13, 0, 0, 6, 1, 0 }, /* Hit points */ 274 { 1, 0, 0, 1, 0, 1 },12, /* Energy */ 275 10, 9, 2, 1, 10, A_INT, SPE_INVISIBILITY, -4 276}, 277{ {"Samurai", 0}, { 278 {"Hatamoto", 0}, /* Banner Knight */ 279 {"Ronin", 0}, /* no allegiance */ 280 {"Ninja", "Kunoichi"}, /* secret society */ 281 {"Joshu", 0}, /* heads a castle */ 282 {"Ryoshu", 0}, /* has a territory */ 283 {"Kokushu", 0}, /* heads a province */ 284 {"Daimyo", 0}, /* a samurai lord */ 285 {"Kuge", 0}, /* Noble of the Court */ 286 {"Shogun", 0} },/* supreme commander, warlord */ 287 "_Amaterasu Omikami", "Raijin", "Susanowo", /* Japanese */ 288 "Sam", "the Castle of the Taro Clan", "the Shogun's Castle", 289 PM_SAMURAI, NON_PM, PM_LITTLE_DOG, 290 PM_LORD_SATO, PM_ROSHI, PM_ASHIKAGA_TAKAUJI, 291 PM_WOLF, PM_STALKER, S_DOG, S_ELEMENTAL, 292 ART_TSURUGI_OF_MURAMASA, 293 MH_HUMAN | ROLE_MALE|ROLE_FEMALE | ROLE_LAWFUL, 294 /* Str Int Wis Dex Con Cha */ 295 { 10, 8, 7, 10, 17, 6 }, 296 { 30, 10, 8, 30, 14, 8 }, 297 /* Init Lower Higher */ 298 { 13, 0, 0, 8, 1, 0 }, /* Hit points */ 299 { 1, 0, 0, 1, 0, 1 },11, /* Energy */ 300 10, 10, 0, 0, 8, A_INT, SPE_CLAIRVOYANCE, -4 301}, 302#ifdef TOURIST 303{ {"Tourist", 0}, { 304 {"Rambler", 0}, 305 {"Sightseer", 0}, 306 {"Excursionist",0}, 307 {"Peregrinator","Peregrinatrix"}, 308 {"Traveler", 0}, 309 {"Journeyer", 0}, 310 {"Voyager", 0}, 311 {"Explorer", 0}, 312 {"Adventurer", 0} }, 313 "Blind Io", "_The Lady", "Offler", /* Discworld */ 314 "Tou", "Ankh-Morpork", "the Thieves' Guild Hall", 315 PM_TOURIST, NON_PM, NON_PM, 316 PM_TWOFLOWER, PM_GUIDE, PM_MASTER_OF_THIEVES, 317 PM_GIANT_SPIDER, PM_FOREST_CENTAUR, S_SPIDER, S_CENTAUR, 318 ART_YENDORIAN_EXPRESS_CARD, 319 MH_HUMAN | ROLE_MALE|ROLE_FEMALE | ROLE_NEUTRAL, 320 /* Str Int Wis Dex Con Cha */ 321 { 7, 10, 6, 7, 7, 10 }, 322 { 15, 10, 10, 15, 30, 20 }, 323 /* Init Lower Higher */ 324 { 8, 0, 0, 8, 0, 0 }, /* Hit points */ 325 { 1, 0, 0, 1, 0, 1 },14, /* Energy */ 326 0, 5, 1, 2, 10, A_INT, SPE_CHARM_MONSTER, -4 327}, 328#endif 329{ {"Valkyrie", 0}, { 330 {"Stripling", 0}, 331 {"Skirmisher", 0}, 332 {"Fighter", 0}, 333 {"Man-at-arms", "Woman-at-arms"}, 334 {"Warrior", 0}, 335 {"Swashbuckler",0}, 336 {"Hero", "Heroine"}, 337 {"Champion", 0}, 338 {"Lord", "Lady"} }, 339 "Tyr", "Odin", "Loki", /* Norse */ 340 "Val", "the Shrine of Destiny", "the cave of Surtur", 341 PM_VALKYRIE, NON_PM, NON_PM /*PM_WINTER_WOLF_CUB*/, 342 PM_NORN, PM_WARRIOR, PM_LORD_SURTUR, 343 PM_FIRE_ANT, PM_FIRE_GIANT, S_ANT, S_GIANT, 344 ART_ORB_OF_FATE, 345 MH_HUMAN|MH_DWARF | ROLE_FEMALE | ROLE_LAWFUL|ROLE_NEUTRAL, 346 /* Str Int Wis Dex Con Cha */ 347 { 10, 7, 7, 7, 10, 7 }, 348 { 30, 6, 7, 20, 30, 7 }, 349 /* Init Lower Higher */ 350 { 14, 0, 0, 8, 2, 0 }, /* Hit points */ 351 { 1, 0, 0, 1, 0, 1 },10, /* Energy */ 352 0, 10,-2, 0, 9, A_WIS, SPE_CONE_OF_COLD, -4 353}, 354{ {"Wizard", 0}, { 355 {"Evoker", 0}, 356 {"Conjurer", 0}, 357 {"Thaumaturge", 0}, 358 {"Magician", 0}, 359 {"Enchanter", "Enchantress"}, 360 {"Sorcerer", "Sorceress"}, 361 {"Necromancer", 0}, 362 {"Wizard", 0}, 363 {"Mage", 0} }, 364 "Ptah", "Thoth", "Anhur", /* Egyptian */ 365 "Wiz", "the Lonely Tower", "the Tower of Darkness", 366 PM_WIZARD, NON_PM, PM_KITTEN, 367 PM_NEFERET_THE_GREEN, PM_APPRENTICE, PM_DARK_ONE, 368 PM_VAMPIRE_BAT, PM_XORN, S_BAT, S_WRAITH, 369 ART_EYE_OF_THE_AETHIOPICA, 370 MH_HUMAN|MH_ELF|MH_GNOME|MH_ORC | ROLE_MALE|ROLE_FEMALE | 371 ROLE_NEUTRAL|ROLE_CHAOTIC, 372 /* Str Int Wis Dex Con Cha */ 373 { 7, 10, 7, 7, 7, 7 }, 374 { 10, 30, 10, 20, 20, 10 }, 375 /* Init Lower Higher */ 376 { 10, 0, 0, 8, 1, 0 }, /* Hit points */ 377 { 4, 3, 0, 2, 0, 3 },12, /* Energy */ 378 0, 1, 0, 3, 10, A_INT, SPE_MAGIC_MISSILE, -4 379}, 380/* Array terminator */ 381{{0, 0}} 382}; 383 384 385/* The player's role, created at runtime from initial 386 * choices. This may be munged in role_init(). 387 */ 388struct Role urole = 389{ {"Undefined", 0}, { {0, 0}, {0, 0}, {0, 0}, 390 {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 391 "L", "N", "C", "Xxx", "home", "locate", 392 NON_PM, NON_PM, NON_PM, NON_PM, NON_PM, NON_PM, 393 NON_PM, NON_PM, 0, 0, 0, 0, 394 /* Str Int Wis Dex Con Cha */ 395 { 7, 7, 7, 7, 7, 7 }, 396 { 20, 15, 15, 20, 20, 10 }, 397 /* Init Lower Higher */ 398 { 10, 0, 0, 8, 1, 0 }, /* Hit points */ 399 { 2, 0, 0, 2, 0, 3 },14, /* Energy */ 400 0, 10, 0, 0, 4, A_INT, 0, -3 401}; 402 403 404 405/* Table of all races */ 406const struct Race races[] = { 407{ "human", "human", "humanity", "Hum", 408 {"man", "woman"}, 409 PM_HUMAN, NON_PM, PM_HUMAN_MUMMY, PM_HUMAN_ZOMBIE, 410 MH_HUMAN | ROLE_MALE|ROLE_FEMALE | 411 ROLE_LAWFUL|ROLE_NEUTRAL|ROLE_CHAOTIC, 412 MH_HUMAN, 0, MH_GNOME|MH_ORC, 413 /* Str Int Wis Dex Con Cha */ 414 { 3, 3, 3, 3, 3, 3 }, 415 { STR18(100), 18, 18, 18, 18, 18 }, 416 /* Init Lower Higher */ 417 { 2, 0, 0, 2, 1, 0 }, /* Hit points */ 418 { 1, 0, 2, 0, 2, 0 } /* Energy */ 419}, 420{ "elf", "elven", "elvenkind", "Elf", 421 {0, 0}, 422 PM_ELF, NON_PM, PM_ELF_MUMMY, PM_ELF_ZOMBIE, 423 MH_ELF | ROLE_MALE|ROLE_FEMALE | ROLE_CHAOTIC, 424 MH_ELF, MH_ELF, MH_ORC, 425 /* Str Int Wis Dex Con Cha */ 426 { 3, 3, 3, 3, 3, 3 }, 427 { 18, 20, 20, 18, 16, 18 }, 428 /* Init Lower Higher */ 429 { 1, 0, 0, 1, 1, 0 }, /* Hit points */ 430 { 2, 0, 3, 0, 3, 0 } /* Energy */ 431}, 432{ "dwarf", "dwarven", "dwarvenkind", "Dwa", 433 {0, 0}, 434 PM_DWARF, NON_PM, PM_DWARF_MUMMY, PM_DWARF_ZOMBIE, 435 MH_DWARF | ROLE_MALE|ROLE_FEMALE | ROLE_LAWFUL, 436 MH_DWARF, MH_DWARF|MH_GNOME, MH_ORC, 437 /* Str Int Wis Dex Con Cha */ 438 { 3, 3, 3, 3, 3, 3 }, 439 { STR18(100), 16, 16, 20, 20, 16 }, 440 /* Init Lower Higher */ 441 { 4, 0, 0, 3, 2, 0 }, /* Hit points */ 442 { 0, 0, 0, 0, 0, 0 } /* Energy */ 443}, 444{ "gnome", "gnomish", "gnomehood", "Gno", 445 {0, 0}, 446 PM_GNOME, NON_PM, PM_GNOME_MUMMY, PM_GNOME_ZOMBIE, 447 MH_GNOME | ROLE_MALE|ROLE_FEMALE | ROLE_NEUTRAL, 448 MH_GNOME, MH_DWARF|MH_GNOME, MH_HUMAN, 449 /* Str Int Wis Dex Con Cha */ 450 { 3, 3, 3, 3, 3, 3 }, 451 {STR18(50),19, 18, 18, 18, 18 }, 452 /* Init Lower Higher */ 453 { 1, 0, 0, 1, 0, 0 }, /* Hit points */ 454 { 2, 0, 2, 0, 2, 0 } /* Energy */ 455}, 456{ "orc", "orcish", "orcdom", "Orc", 457 {0, 0}, 458 PM_ORC, NON_PM, PM_ORC_MUMMY, PM_ORC_ZOMBIE, 459 MH_ORC | ROLE_MALE|ROLE_FEMALE | ROLE_CHAOTIC, 460 MH_ORC, 0, MH_HUMAN|MH_ELF|MH_DWARF, 461 /* Str Int Wis Dex Con Cha */ 462 { 3, 3, 3, 3, 3, 3 }, 463 {STR18(50),16, 16, 18, 18, 16 }, 464 /* Init Lower Higher */ 465 { 1, 0, 0, 1, 0, 0 }, /* Hit points */ 466 { 1, 0, 1, 0, 1, 0 } /* Energy */ 467}, 468/* Array terminator */ 469{ 0, 0, 0, 0 }}; 470 471 472/* The player's race, created at runtime from initial 473 * choices. This may be munged in role_init(). 474 */ 475struct Race urace = 476{ "something", "undefined", "something", "Xxx", 477 {0, 0}, 478 NON_PM, NON_PM, NON_PM, NON_PM, 479 0, 0, 0, 0, 480 /* Str Int Wis Dex Con Cha */ 481 { 3, 3, 3, 3, 3, 3 }, 482 { STR18(100), 18, 18, 18, 18, 18 }, 483 /* Init Lower Higher */ 484 { 2, 0, 0, 2, 1, 0 }, /* Hit points */ 485 { 1, 0, 2, 0, 2, 0 } /* Energy */ 486}; 487 488 489/* Table of all genders */ 490const struct Gender genders[] = { 491 {"male", "he", "him", "his", "Mal", ROLE_MALE}, 492 {"female", "she", "her", "her", "Fem", ROLE_FEMALE}, 493 {"neuter", "it", "it", "its", "Ntr", ROLE_NEUTER} 494}; 495 496 497/* Table of all alignments */ 498const struct Align aligns[] = { 499 {"law", "lawful", "Law", ROLE_LAWFUL, A_LAWFUL}, 500 {"balance", "neutral", "Neu", ROLE_NEUTRAL, A_NEUTRAL}, 501 {"chaos", "chaotic", "Cha", ROLE_CHAOTIC, A_CHAOTIC}, 502 {"evil", "unaligned", "Una", 0, A_NONE} 503}; 504 505STATIC_DCL char * FDECL(promptsep, (char *, int)); 506STATIC_DCL int FDECL(role_gendercount, (int)); 507STATIC_DCL int FDECL(race_alignmentcount, (int)); 508 509/* used by str2XXX() */ 510static char NEARDATA randomstr[] = "random"; 511 512 513boolean 514validrole(rolenum) 515 int rolenum; 516{ 517 return (rolenum >= 0 && rolenum < SIZE(roles)-1); 518} 519 520 521int 522randrole() 523{ 524 return (rn2(SIZE(roles)-1)); 525} 526 527 528int 529str2role(str) 530 char *str; 531{ 532 int i, len; 533 534 /* Is str valid? */ 535 if (!str || !str[0]) 536 return ROLE_NONE; 537 538 /* Match as much of str as is provided */ 539 len = strlen(str); 540 for (i = 0; roles[i].name.m; i++) { 541 /* Does it match the male name? */ 542 if (!strncmpi(str, roles[i].name.m, len)) 543 return i; 544 /* Or the female name? */ 545 if (roles[i].name.f && !strncmpi(str, roles[i].name.f, len)) 546 return i; 547 /* Or the filecode? */ 548 if (!strcmpi(str, roles[i].filecode)) 549 return i; 550 } 551 552 if ((len == 1 && (*str == '*' || *str == '@')) || 553 !strncmpi(str, randomstr, len)) 554 return ROLE_RANDOM; 555 556 /* Couldn't find anything appropriate */ 557 return ROLE_NONE; 558} 559 560 561boolean 562validrace(rolenum, racenum) 563 int rolenum, racenum; 564{ 565 /* Assumes validrole */ 566 return (racenum >= 0 && racenum < SIZE(races)-1 && 567 (roles[rolenum].allow & races[racenum].allow & ROLE_RACEMASK)); 568} 569 570 571int 572randrace(rolenum) 573 int rolenum; 574{ 575 int i, n = 0; 576 577 /* Count the number of valid races */ 578 for (i = 0; races[i].noun; i++) 579 if (roles[rolenum].allow & races[i].allow & ROLE_RACEMASK) 580 n++; 581 582 /* Pick a random race */ 583 /* Use a factor of 100 in case of bad random number generators */ 584 if (n) n = rn2(n*100)/100; 585 for (i = 0; races[i].noun; i++) 586 if (roles[rolenum].allow & races[i].allow & ROLE_RACEMASK) { 587 if (n) n--; 588 else return (i); 589 } 590 591 /* This role has no permitted races? */ 592 return (rn2(SIZE(races)-1)); 593} 594 595 596int 597str2race(str) 598 char *str; 599{ 600 int i, len; 601 602 /* Is str valid? */ 603 if (!str || !str[0]) 604 return ROLE_NONE; 605 606 /* Match as much of str as is provided */ 607 len = strlen(str); 608 for (i = 0; races[i].noun; i++) { 609 /* Does it match the noun? */ 610 if (!strncmpi(str, races[i].noun, len)) 611 return i; 612 /* Or the filecode? */ 613 if (!strcmpi(str, races[i].filecode)) 614 return i; 615 } 616 617 if ((len == 1 && (*str == '*' || *str == '@')) || 618 !strncmpi(str, randomstr, len)) 619 return ROLE_RANDOM; 620 621 /* Couldn't find anything appropriate */ 622 return ROLE_NONE; 623} 624 625 626boolean 627validgend(rolenum, racenum, gendnum) 628 int rolenum, racenum, gendnum; 629{ 630 /* Assumes validrole and validrace */ 631 return (gendnum >= 0 && gendnum < ROLE_GENDERS && 632 (roles[rolenum].allow & races[racenum].allow & 633 genders[gendnum].allow & ROLE_GENDMASK)); 634} 635 636 637int 638randgend(rolenum, racenum) 639 int rolenum, racenum; 640{ 641 int i, n = 0; 642 643 /* Count the number of valid genders */ 644 for (i = 0; i < ROLE_GENDERS; i++) 645 if (roles[rolenum].allow & races[racenum].allow & 646 genders[i].allow & ROLE_GENDMASK) 647 n++; 648 649 /* Pick a random gender */ 650 if (n) n = rn2(n); 651 for (i = 0; i < ROLE_GENDERS; i++) 652 if (roles[rolenum].allow & races[racenum].allow & 653 genders[i].allow & ROLE_GENDMASK) { 654 if (n) n--; 655 else return (i); 656 } 657 658 /* This role/race has no permitted genders? */ 659 return (rn2(ROLE_GENDERS)); 660} 661 662 663int 664str2gend(str) 665 char *str; 666{ 667 int i, len; 668 669 /* Is str valid? */ 670 if (!str || !str[0]) 671 return ROLE_NONE; 672 673 /* Match as much of str as is provided */ 674 len = strlen(str); 675 for (i = 0; i < ROLE_GENDERS; i++) { 676 /* Does it match the adjective? */ 677 if (!strncmpi(str, genders[i].adj, len)) 678 return i; 679 /* Or the filecode? */ 680 if (!strcmpi(str, genders[i].filecode)) 681 return i; 682 } 683 if ((len == 1 && (*str == '*' || *str == '@')) || 684 !strncmpi(str, randomstr, len)) 685 return ROLE_RANDOM; 686 687 /* Couldn't find anything appropriate */ 688 return ROLE_NONE; 689} 690 691 692boolean 693validalign(rolenum, racenum, alignnum) 694 int rolenum, racenum, alignnum; 695{ 696 /* Assumes validrole and validrace */ 697 return (alignnum >= 0 && alignnum < ROLE_ALIGNS && 698 (roles[rolenum].allow & races[racenum].allow & 699 aligns[alignnum].allow & ROLE_ALIGNMASK)); 700} 701 702 703int 704randalign(rolenum, racenum) 705 int rolenum, racenum; 706{ 707 int i, n = 0; 708 709 /* Count the number of valid alignments */ 710 for (i = 0; i < ROLE_ALIGNS; i++) 711 if (roles[rolenum].allow & races[racenum].allow & 712 aligns[i].allow & ROLE_ALIGNMASK) 713 n++; 714 715 /* Pick a random alignment */ 716 if (n) n = rn2(n); 717 for (i = 0; i < ROLE_ALIGNS; i++) 718 if (roles[rolenum].allow & races[racenum].allow & 719 aligns[i].allow & ROLE_ALIGNMASK) { 720 if (n) n--; 721 else return (i); 722 } 723 724 /* This role/race has no permitted alignments? */ 725 return (rn2(ROLE_ALIGNS)); 726} 727 728 729int 730str2align(str) 731 char *str; 732{ 733 int i, len; 734 735 /* Is str valid? */ 736 if (!str || !str[0]) 737 return ROLE_NONE; 738 739 /* Match as much of str as is provided */ 740 len = strlen(str); 741 for (i = 0; i < ROLE_ALIGNS; i++) { 742 /* Does it match the adjective? */ 743 if (!strncmpi(str, aligns[i].adj, len)) 744 return i; 745 /* Or the filecode? */ 746 if (!strcmpi(str, aligns[i].filecode)) 747 return i; 748 } 749 if ((len == 1 && (*str == '*' || *str == '@')) || 750 !strncmpi(str, randomstr, len)) 751 return ROLE_RANDOM; 752 753 /* Couldn't find anything appropriate */ 754 return ROLE_NONE; 755} 756 757/* is rolenum compatible with any racenum/gendnum/alignnum constraints? */ 758boolean 759ok_role(rolenum, racenum, gendnum, alignnum) 760int rolenum, racenum, gendnum, alignnum; 761{ 762 int i; 763 short allow; 764 765 if (rolenum >= 0 && rolenum < SIZE(roles)-1) { 766 allow = roles[rolenum].allow; 767 if (racenum >= 0 && racenum < SIZE(races)-1 && 768 !(allow & races[racenum].allow & ROLE_RACEMASK)) 769 return FALSE; 770 if (gendnum >= 0 && gendnum < ROLE_GENDERS && 771 !(allow & genders[gendnum].allow & ROLE_GENDMASK)) 772 return FALSE; 773 if (alignnum >= 0 && alignnum < ROLE_ALIGNS && 774 !(allow & aligns[alignnum].allow & ROLE_ALIGNMASK)) 775 return FALSE; 776 return TRUE; 777 } else { 778 for (i = 0; i < SIZE(roles)-1; i++) { 779 allow = roles[i].allow; 780 if (racenum >= 0 && racenum < SIZE(races)-1 && 781 !(allow & races[racenum].allow & ROLE_RACEMASK)) 782 continue; 783 if (gendnum >= 0 && gendnum < ROLE_GENDERS && 784 !(allow & genders[gendnum].allow & ROLE_GENDMASK)) 785 continue; 786 if (alignnum >= 0 && alignnum < ROLE_ALIGNS && 787 !(allow & aligns[alignnum].allow & ROLE_ALIGNMASK)) 788 continue; 789 return TRUE; 790 } 791 return FALSE; 792 } 793} 794 795/* pick a random role subject to any racenum/gendnum/alignnum constraints */ 796/* If pickhow == PICK_RIGID a role is returned only if there is */ 797/* a single possibility */ 798int 799pick_role(racenum, gendnum, alignnum, pickhow) 800int racenum, gendnum, alignnum, pickhow; 801{ 802 int i; 803 int roles_ok = 0; 804 805 for (i = 0; i < SIZE(roles)-1; i++) { 806 if (ok_role(i, racenum, gendnum, alignnum)) 807 roles_ok++; 808 } 809 if (roles_ok == 0 || (roles_ok > 1 && pickhow == PICK_RIGID)) 810 return ROLE_NONE; 811 roles_ok = rn2(roles_ok); 812 for (i = 0; i < SIZE(roles)-1; i++) { 813 if (ok_role(i, racenum, gendnum, alignnum)) { 814 if (roles_ok == 0) 815 return i; 816 else 817 roles_ok--; 818 } 819 } 820 return ROLE_NONE; 821} 822 823/* is racenum compatible with any rolenum/gendnum/alignnum constraints? */ 824boolean 825ok_race(rolenum, racenum, gendnum, alignnum) 826int rolenum, racenum, gendnum, alignnum; 827{ 828 int i; 829 short allow; 830 831 if (racenum >= 0 && racenum < SIZE(races)-1) { 832 allow = races[racenum].allow; 833 if (rolenum >= 0 && rolenum < SIZE(roles)-1 && 834 !(allow & roles[rolenum].allow & ROLE_RACEMASK)) 835 return FALSE; 836 if (gendnum >= 0 && gendnum < ROLE_GENDERS && 837 !(allow & genders[gendnum].allow & ROLE_GENDMASK)) 838 return FALSE; 839 if (alignnum >= 0 && alignnum < ROLE_ALIGNS && 840 !(allow & aligns[alignnum].allow & ROLE_ALIGNMASK)) 841 return FALSE; 842 return TRUE; 843 } else { 844 for (i = 0; i < SIZE(races)-1; i++) { 845 allow = races[i].allow; 846 if (rolenum >= 0 && rolenum < SIZE(roles)-1 && 847 !(allow & roles[rolenum].allow & ROLE_RACEMASK)) 848 continue; 849 if (gendnum >= 0 && gendnum < ROLE_GENDERS && 850 !(allow & genders[gendnum].allow & ROLE_GENDMASK)) 851 continue; 852 if (alignnum >= 0 && alignnum < ROLE_ALIGNS && 853 !(allow & aligns[alignnum].allow & ROLE_ALIGNMASK)) 854 continue; 855 return TRUE; 856 } 857 return FALSE; 858 } 859} 860 861/* pick a random race subject to any rolenum/gendnum/alignnum constraints */ 862/* If pickhow == PICK_RIGID a race is returned only if there is */ 863/* a single possibility */ 864int 865pick_race(rolenum, gendnum, alignnum, pickhow) 866int rolenum, gendnum, alignnum, pickhow; 867{ 868 int i; 869 int races_ok = 0; 870 871 for (i = 0; i < SIZE(races)-1; i++) { 872 if (ok_race(rolenum, i, gendnum, alignnum)) 873 races_ok++; 874 } 875 if (races_ok == 0 || (races_ok > 1 && pickhow == PICK_RIGID)) 876 return ROLE_NONE; 877 races_ok = rn2(races_ok); 878 for (i = 0; i < SIZE(races)-1; i++) { 879 if (ok_race(rolenum, i, gendnum, alignnum)) { 880 if (races_ok == 0) 881 return i; 882 else 883 races_ok--; 884 } 885 } 886 return ROLE_NONE; 887} 888 889/* is gendnum compatible with any rolenum/racenum/alignnum constraints? */ 890/* gender and alignment are not comparable (and also not constrainable) */ 891boolean 892ok_gend(rolenum, racenum, gendnum, alignnum) 893int rolenum, racenum, gendnum, alignnum; 894{ 895 int i; 896 short allow; 897 898 if (gendnum >= 0 && gendnum < ROLE_GENDERS) { 899 allow = genders[gendnum].allow; 900 if (rolenum >= 0 && rolenum < SIZE(roles)-1 && 901 !(allow & roles[rolenum].allow & ROLE_GENDMASK)) 902 return FALSE; 903 if (racenum >= 0 && racenum < SIZE(races)-1 && 904 !(allow & races[racenum].allow & ROLE_GENDMASK)) 905 return FALSE; 906 return TRUE; 907 } else { 908 for (i = 0; i < ROLE_GENDERS; i++) { 909 allow = genders[i].allow; 910 if (rolenum >= 0 && rolenum < SIZE(roles)-1 && 911 !(allow & roles[rolenum].allow & ROLE_GENDMASK)) 912 continue; 913 if (racenum >= 0 && racenum < SIZE(races)-1 && 914 !(allow & races[racenum].allow & ROLE_GENDMASK)) 915 continue; 916 return TRUE; 917 } 918 return FALSE; 919 } 920} 921 922/* pick a random gender subject to any rolenum/racenum/alignnum constraints */ 923/* gender and alignment are not comparable (and also not constrainable) */ 924/* If pickhow == PICK_RIGID a gender is returned only if there is */ 925/* a single possibility */ 926int 927pick_gend(rolenum, racenum, alignnum, pickhow) 928int rolenum, racenum, alignnum, pickhow; 929{ 930 int i; 931 int gends_ok = 0; 932 933 for (i = 0; i < ROLE_GENDERS; i++) { 934 if (ok_gend(rolenum, racenum, i, alignnum)) 935 gends_ok++; 936 } 937 if (gends_ok == 0 || (gends_ok > 1 && pickhow == PICK_RIGID)) 938 return ROLE_NONE; 939 gends_ok = rn2(gends_ok); 940 for (i = 0; i < ROLE_GENDERS; i++) { 941 if (ok_gend(rolenum, racenum, i, alignnum)) { 942 if (gends_ok == 0) 943 return i; 944 else 945 gends_ok--; 946 } 947 } 948 return ROLE_NONE; 949} 950 951/* is alignnum compatible with any rolenum/racenum/gendnum constraints? */ 952/* alignment and gender are not comparable (and also not constrainable) */ 953boolean 954ok_align(rolenum, racenum, gendnum, alignnum) 955int rolenum, racenum, gendnum, alignnum; 956{ 957 int i; 958 short allow; 959 960 if (alignnum >= 0 && alignnum < ROLE_ALIGNS) { 961 allow = aligns[alignnum].allow; 962 if (rolenum >= 0 && rolenum < SIZE(roles)-1 && 963 !(allow & roles[rolenum].allow & ROLE_ALIGNMASK)) 964 return FALSE; 965 if (racenum >= 0 && racenum < SIZE(races)-1 && 966 !(allow & races[racenum].allow & ROLE_ALIGNMASK)) 967 return FALSE; 968 return TRUE; 969 } else { 970 for (i = 0; i < ROLE_ALIGNS; i++) { 971 allow = races[i].allow; 972 if (rolenum >= 0 && rolenum < SIZE(roles)-1 && 973 !(allow & roles[rolenum].allow & ROLE_ALIGNMASK)) 974 continue; 975 if (racenum >= 0 && racenum < SIZE(races)-1 && 976 !(allow & races[racenum].allow & ROLE_ALIGNMASK)) 977 continue; 978 return TRUE; 979 } 980 return FALSE; 981 } 982} 983 984/* pick a random alignment subject to any rolenum/racenum/gendnum constraints */ 985/* alignment and gender are not comparable (and also not constrainable) */ 986/* If pickhow == PICK_RIGID an alignment is returned only if there is */ 987/* a single possibility */ 988int 989pick_align(rolenum, racenum, gendnum, pickhow) 990int rolenum, racenum, gendnum, pickhow; 991{ 992 int i; 993 int aligns_ok = 0; 994 995 for (i = 0; i < ROLE_ALIGNS; i++) { 996 if (ok_align(rolenum, racenum, gendnum, i)) 997 aligns_ok++; 998 } 999 if (aligns_ok == 0 || (aligns_ok > 1 && pickhow == PICK_RIGID)) 1000 return ROLE_NONE; 1001 aligns_ok = rn2(aligns_ok); 1002 for (i = 0; i < ROLE_ALIGNS; i++) { 1003 if (ok_align(rolenum, racenum, gendnum, i)) { 1004 if (aligns_ok == 0) 1005 return i; 1006 else 1007 aligns_ok--; 1008 } 1009 } 1010 return ROLE_NONE; 1011} 1012 1013void 1014rigid_role_checks() 1015{ 1016 /* Some roles are limited to a single race, alignment, or gender and 1017 * calling this routine prior to XXX_player_selection() will help 1018 * prevent an extraneous prompt that actually doesn't allow 1019 * you to choose anything further. Note the use of PICK_RIGID which 1020 * causes the pick_XX() routine to return a value only if there is one 1021 * single possible selection, otherwise it returns ROLE_NONE. 1022 * 1023 */ 1024 if (flags.initrole == ROLE_RANDOM) { 1025 /* If the role was explicitly specified as ROLE_RANDOM 1026 * via -uXXXX-@ then choose the role in here to narrow down 1027 * later choices. Pick a random role in this case. 1028 */ 1029 flags.initrole = pick_role(flags.initrace, flags.initgend, 1030 flags.initalign, PICK_RANDOM); 1031 if (flags.initrole < 0) 1032 flags.initrole = randrole(); 1033 } 1034 if (flags.initrole != ROLE_NONE) { 1035 if (flags.initrace == ROLE_NONE) 1036 flags.initrace = pick_race(flags.initrole, flags.initgend, 1037 flags.initalign, PICK_RIGID); 1038 if (flags.initalign == ROLE_NONE) 1039 flags.initalign = pick_align(flags.initrole, flags.initrace, 1040 flags.initgend, PICK_RIGID); 1041 if (flags.initgend == ROLE_NONE) 1042 flags.initgend = pick_gend(flags.initrole, flags.initrace, 1043 flags.initalign, PICK_RIGID); 1044 } 1045} 1046 1047#define BP_ALIGN 0 1048#define BP_GEND 1 1049#define BP_RACE 2 1050#define BP_ROLE 3 1051#define NUM_BP 4 1052 1053STATIC_VAR char pa[NUM_BP], post_attribs; 1054 1055STATIC_OVL char * 1056promptsep(buf, num_post_attribs) 1057char *buf; 1058int num_post_attribs; 1059{ 1060 const char *conj = "and "; 1061 if (num_post_attribs > 1 1062 && post_attribs < num_post_attribs && post_attribs > 1) 1063 Strcat(buf, ","); 1064 Strcat(buf, " "); 1065 --post_attribs; 1066 if (!post_attribs && num_post_attribs > 1) Strcat(buf, conj); 1067 return buf; 1068} 1069 1070STATIC_OVL int 1071role_gendercount(rolenum) 1072int rolenum; 1073{ 1074 int gendcount = 0; 1075 if (validrole(rolenum)) { 1076 if (roles[rolenum].allow & ROLE_MALE) ++gendcount; 1077 if (roles[rolenum].allow & ROLE_FEMALE) ++gendcount; 1078 if (roles[rolenum].allow & ROLE_NEUTER) ++gendcount; 1079 } 1080 return gendcount; 1081} 1082 1083STATIC_OVL int 1084race_alignmentcount(racenum) 1085int racenum; 1086{ 1087 int aligncount = 0; 1088 if (racenum != ROLE_NONE && racenum != ROLE_RANDOM) { 1089 if (races[racenum].allow & ROLE_CHAOTIC) ++aligncount; 1090 if (races[racenum].allow & ROLE_LAWFUL) ++aligncount; 1091 if (races[racenum].allow & ROLE_NEUTRAL) ++aligncount; 1092 } 1093 return aligncount; 1094} 1095 1096char * 1097root_plselection_prompt(suppliedbuf, buflen, rolenum, racenum, gendnum, alignnum) 1098char *suppliedbuf; 1099int buflen, rolenum, racenum, gendnum, alignnum; 1100{ 1101 int k, gendercount = 0, aligncount = 0; 1102 char buf[BUFSZ]; 1103 static char err_ret[] = " character's"; 1104 boolean donefirst = FALSE; 1105 1106 if (!suppliedbuf || buflen < 1) return err_ret; 1107 1108 /* initialize these static variables each time this is called */ 1109 post_attribs = 0; 1110 for (k=0; k < NUM_BP; ++k) 1111 pa[k] = 0; 1112 buf[0] = '\0'; 1113 *suppliedbuf = '\0'; 1114 1115 /* How many alignments are allowed for the desired race? */ 1116 if (racenum != ROLE_NONE && racenum != ROLE_RANDOM) 1117 aligncount = race_alignmentcount(racenum); 1118 1119 if (alignnum != ROLE_NONE && alignnum != ROLE_RANDOM) { 1120 /* if race specified, and multiple choice of alignments for it */ 1121 if ((racenum >= 0) && (aligncount > 1)) { 1122 if (donefirst) Strcat(buf, " "); 1123 Strcat(buf, aligns[alignnum].adj); 1124 donefirst = TRUE; 1125 } else { 1126 if (donefirst) Strcat(buf, " "); 1127 Strcat(buf, aligns[alignnum].adj); 1128 donefirst = TRUE; 1129 } 1130 } else { 1131 /* if alignment not specified, but race is specified 1132 and only one choice of alignment for that race then 1133 don't include it in the later list */ 1134 if ((((racenum != ROLE_NONE && racenum != ROLE_RANDOM) && 1135 ok_race(rolenum, racenum, gendnum, alignnum)) 1136 && (aligncount > 1)) 1137 || (racenum == ROLE_NONE || racenum == ROLE_RANDOM)) { 1138 pa[BP_ALIGN] = 1; 1139 post_attribs++; 1140 } 1141 } 1142 /* <your lawful> */ 1143 1144 /* How many genders are allowed for the desired role? */ 1145 if (validrole(rolenum)) 1146 gendercount = role_gendercount(rolenum); 1147 1148 if (gendnum != ROLE_NONE && gendnum != ROLE_RANDOM) { 1149 if (validrole(rolenum)) { 1150 /* if role specified, and multiple choice of genders for it, 1151 and name of role itself does not distinguish gender */ 1152 if ((rolenum != ROLE_NONE) && (gendercount > 1) 1153 && !roles[rolenum].name.f) { 1154 if (donefirst) Strcat(buf, " "); 1155 Strcat(buf, genders[gendnum].adj); 1156 donefirst = TRUE; 1157 } 1158 } else { 1159 if (donefirst) Strcat(buf, " "); 1160 Strcat(buf, genders[gendnum].adj); 1161 donefirst = TRUE; 1162 } 1163 } else { 1164 /* if gender not specified, but role is specified 1165 and only one choice of gender then 1166 don't include it in the later list */ 1167 if ((validrole(rolenum) && (gendercount > 1)) || !validrole(rolenum)) { 1168 pa[BP_GEND] = 1; 1169 post_attribs++; 1170 } 1171 } 1172 /* <your lawful female> */ 1173 1174 if (racenum != ROLE_NONE && racenum != ROLE_RANDOM) { 1175 if (validrole(rolenum) && ok_race(rolenum, racenum, gendnum, alignnum)) { 1176 if (donefirst) Strcat(buf, " "); 1177 Strcat(buf, (rolenum == ROLE_NONE) ? 1178 races[racenum].noun : 1179 races[racenum].adj); 1180 donefirst = TRUE; 1181 } else if (!validrole(rolenum)) { 1182 if (donefirst) Strcat(buf, " "); 1183 Strcat(buf, races[racenum].noun); 1184 donefirst = TRUE; 1185 } else { 1186 pa[BP_RACE] = 1; 1187 post_attribs++; 1188 } 1189 } else { 1190 pa[BP_RACE] = 1; 1191 post_attribs++; 1192 } 1193 /* <your lawful female gnomish> || <your lawful female gnome> */ 1194 1195 if (validrole(rolenum)) { 1196 if (donefirst) Strcat(buf, " "); 1197 if (gendnum != ROLE_NONE) { 1198 if (gendnum == 1 && roles[rolenum].name.f) 1199 Strcat(buf, roles[rolenum].name.f); 1200 else 1201 Strcat(buf, roles[rolenum].name.m); 1202 } else { 1203 if (roles[rolenum].name.f) { 1204 Strcat(buf, roles[rolenum].name.m); 1205 Strcat(buf, "/"); 1206 Strcat(buf, roles[rolenum].name.f); 1207 } else 1208 Strcat(buf, roles[rolenum].name.m); 1209 } 1210 donefirst = TRUE; 1211 } else if (rolenum == ROLE_NONE) { 1212 pa[BP_ROLE] = 1; 1213 post_attribs++; 1214 } 1215 1216 if ((racenum == ROLE_NONE || racenum == ROLE_RANDOM) && !validrole(rolenum)) { 1217 if (donefirst) Strcat(buf, " "); 1218 Strcat(buf, "character"); 1219 donefirst = TRUE; 1220 } 1221 /* <your lawful female gnomish cavewoman> || <your lawful female gnome> 1222 * || <your lawful female character> 1223 */ 1224 if (buflen > (int) (strlen(buf) + 1)) { 1225 Strcpy(suppliedbuf, buf); 1226 return suppliedbuf; 1227 } else 1228 return err_ret; 1229} 1230 1231char * 1232build_plselection_prompt(buf, buflen, rolenum, racenum, gendnum, alignnum) 1233char *buf; 1234int buflen, rolenum, racenum, gendnum, alignnum; 1235{ 1236 const char *defprompt = "Shall I pick a character for you? [ynq] "; 1237 int num_post_attribs = 0; 1238 char tmpbuf[BUFSZ]; 1239 1240 if (buflen < QBUFSZ) 1241 return (char *)defprompt; 1242 1243 Strcpy(tmpbuf, "Shall I pick "); 1244 if (racenum != ROLE_NONE || validrole(rolenum)) 1245 Strcat(tmpbuf, "your "); 1246 else { 1247 Strcat(tmpbuf, "a "); 1248 } 1249 /* <your> */ 1250 1251 (void) root_plselection_prompt(eos(tmpbuf), buflen - strlen(tmpbuf), 1252 rolenum, racenum, gendnum, alignnum); 1253 Sprintf(buf, "%s", s_suffix(tmpbuf)); 1254 1255 /* buf should now be: 1256 * < your lawful female gnomish cavewoman's> || <your lawful female gnome's> 1257 * || <your lawful female character's> 1258 * 1259 * Now append the post attributes to it 1260 */ 1261 1262 num_post_attribs = post_attribs; 1263 if (post_attribs) { 1264 if (pa[BP_RACE]) { 1265 (void) promptsep(eos(buf), num_post_attribs); 1266 Strcat(buf, "race"); 1267 } 1268 if (pa[BP_ROLE]) { 1269 (void) promptsep(eos(buf), num_post_attribs); 1270 Strcat(buf, "role"); 1271 } 1272 if (pa[BP_GEND]) { 1273 (void) promptsep(eos(buf), num_post_attribs); 1274 Strcat(buf, "gender"); 1275 } 1276 if (pa[BP_ALIGN]) { 1277 (void) promptsep(eos(buf), num_post_attribs); 1278 Strcat(buf, "alignment"); 1279 } 1280 } 1281 Strcat(buf, " for you? [ynq] "); 1282 return buf; 1283} 1284 1285#undef BP_ALIGN 1286#undef BP_GEND 1287#undef BP_RACE 1288#undef BP_ROLE 1289#undef NUM_BP 1290 1291void 1292plnamesuffix() 1293{ 1294 char *sptr, *eptr; 1295 int i; 1296 1297 /* Look for tokens delimited by '-' */ 1298 if ((eptr = index(plname, '-')) != (char *) 0) 1299 *eptr++ = '\0'; 1300 while (eptr) { 1301 /* Isolate the next token */ 1302 sptr = eptr; 1303 if ((eptr = index(sptr, '-')) != (char *)0) 1304 *eptr++ = '\0'; 1305 1306 /* Try to match it to something */ 1307 if ((i = str2role(sptr)) != ROLE_NONE) 1308 flags.initrole = i; 1309 else if ((i = str2race(sptr)) != ROLE_NONE) 1310 flags.initrace = i; 1311 else if ((i = str2gend(sptr)) != ROLE_NONE) 1312 flags.initgend = i; 1313 else if ((i = str2align(sptr)) != ROLE_NONE) 1314 flags.initalign = i; 1315 } 1316 if(!plname[0]) { 1317 askname(); 1318 plnamesuffix(); 1319 } 1320 1321 /* commas in the plname confuse the record file, convert to spaces */ 1322 for (sptr = plname; *sptr; sptr++) { 1323 if (*sptr == ',') *sptr = ' '; 1324 } 1325} 1326 1327 1328/* 1329 * Special setup modifications here: 1330 * 1331 * Unfortunately, this is going to have to be done 1332 * on each newgame or restore, because you lose the permonst mods 1333 * across a save/restore. :-) 1334 * 1335 * 1 - The Rogue Leader is the Tourist Nemesis. 1336 * 2 - Priests start with a random alignment - convert the leader and 1337 * guardians here. 1338 * 3 - Elves can have one of two different leaders, but can't work it 1339 * out here because it requires hacking the level file data (see 1340 * sp_lev.c). 1341 * 1342 * This code also replaces quest_init(). 1343 */ 1344void 1345role_init() 1346{ 1347 int alignmnt; 1348 1349 /* Strip the role letter out of the player name. 1350 * This is included for backwards compatibility. 1351 */ 1352 plnamesuffix(); 1353 1354 /* Check for a valid role. Try flags.initrole first. */ 1355 if (!validrole(flags.initrole)) { 1356 /* Try the player letter second */ 1357 if ((flags.initrole = str2role(pl_character)) < 0) 1358 /* None specified; pick a random role */ 1359 flags.initrole = randrole(); 1360 } 1361 1362 /* We now have a valid role index. Copy the role name back. */ 1363 /* This should become OBSOLETE */ 1364 Strcpy(pl_character, roles[flags.initrole].name.m); 1365 pl_character[PL_CSIZ-1] = '\0'; 1366 1367 /* Check for a valid race */ 1368 if (!validrace(flags.initrole, flags.initrace)) 1369 flags.initrace = randrace(flags.initrole); 1370 1371 /* Check for a valid gender. If new game, check both initgend 1372 * and female. On restore, assume flags.female is correct. */ 1373 if (flags.pantheon == -1) { /* new game */ 1374 if (!validgend(flags.initrole, flags.initrace, flags.female)) 1375 flags.female = !flags.female; 1376 } 1377 if (!validgend(flags.initrole, flags.initrace, flags.initgend)) 1378 /* Note that there is no way to check for an unspecified gender. */ 1379 flags.initgend = flags.female; 1380 1381 /* Check for a valid alignment */ 1382 if (!validalign(flags.initrole, flags.initrace, flags.initalign)) 1383 /* Pick a random alignment */ 1384 flags.initalign = randalign(flags.initrole, flags.initrace); 1385 alignmnt = aligns[flags.initalign].value; 1386 1387 /* Initialize urole and urace */ 1388 urole = roles[flags.initrole]; 1389 urace = races[flags.initrace]; 1390 1391 /* Fix up the quest leader */ 1392 if (urole.ldrnum != NON_PM) { 1393 mons[urole.ldrnum].msound = MS_LEADER; 1394 mons[urole.ldrnum].mflags2 |= (M2_PEACEFUL); 1395 mons[urole.ldrnum].mflags3 |= M3_CLOSE; 1396 mons[urole.ldrnum].maligntyp = alignmnt * 3; 1397 } 1398 1399 /* Fix up the quest guardians */ 1400 if (urole.guardnum != NON_PM) { 1401 mons[urole.guardnum].mflags2 |= (M2_PEACEFUL); 1402 mons[urole.guardnum].maligntyp = alignmnt * 3; 1403 } 1404 1405 /* Fix up the quest nemesis */ 1406 if (urole.neminum != NON_PM) { 1407 mons[urole.neminum].msound = MS_NEMESIS; 1408 mons[urole.neminum].mflags2 &= ~(M2_PEACEFUL); 1409 mons[urole.neminum].mflags2 |= (M2_NASTY|M2_STALK|M2_HOSTILE); 1410 mons[urole.neminum].mflags3 |= M3_WANTSARTI | M3_WAITFORU; 1411 } 1412 1413 /* Fix up the god names */ 1414 if (flags.pantheon == -1) { /* new game */ 1415 flags.pantheon = flags.initrole; /* use own gods */ 1416 while (!roles[flags.pantheon].lgod) /* unless they're missing */ 1417 flags.pantheon = randrole(); 1418 } 1419 if (!urole.lgod) { 1420 urole.lgod = roles[flags.pantheon].lgod; 1421 urole.ngod = roles[flags.pantheon].ngod; 1422 urole.cgod = roles[flags.pantheon].cgod; 1423 } 1424 1425 /* Fix up infravision */ 1426 if (mons[urace.malenum].mflags3 & M3_INFRAVISION) { 1427 /* although an infravision intrinsic is possible, infravision 1428 * is purely a property of the physical race. This means that we 1429 * must put the infravision flag in the player's current race 1430 * (either that or have separate permonst entries for 1431 * elven/non-elven members of each class). The side effect is that 1432 * all NPCs of that class will have (probably bogus) infravision, 1433 * but since infravision has no effect for NPCs anyway we can 1434 * ignore this. 1435 */ 1436 mons[urole.malenum].mflags3 |= M3_INFRAVISION; 1437 if (urole.femalenum != NON_PM) 1438 mons[urole.femalenum].mflags3 |= M3_INFRAVISION; 1439 } 1440 1441 /* Artifacts are fixed in hack_artifacts() */ 1442 1443 /* Success! */ 1444 return; 1445} 1446 1447const char * 1448Hello(mtmp) 1449struct monst *mtmp; 1450{ 1451 switch (Role_switch) { 1452 case PM_KNIGHT: 1453 return ("Salutations"); /* Olde English */ 1454 case PM_SAMURAI: 1455 return (mtmp && mtmp->data == &mons[PM_SHOPKEEPER] ? 1456 "Irasshaimase" : "Konnichi wa"); /* Japanese */ 1457#ifdef TOURIST 1458 case PM_TOURIST: 1459 return ("Aloha"); /* Hawaiian */ 1460#endif 1461 case PM_VALKYRIE: 1462 return ( 1463#ifdef MAIL 1464 mtmp && mtmp->data == &mons[PM_MAIL_DAEMON] ? "Hallo" : 1465#endif 1466 "Velkommen"); /* Norse */ 1467 default: 1468 return ("Hello"); 1469 } 1470} 1471 1472const char * 1473Goodbye() 1474{ 1475 switch (Role_switch) { 1476 case PM_KNIGHT: 1477 return ("Fare thee well"); /* Olde English */ 1478 case PM_SAMURAI: 1479 return ("Sayonara"); /* Japanese */ 1480#ifdef TOURIST 1481 case PM_TOURIST: 1482 return ("Aloha"); /* Hawaiian */ 1483#endif 1484 case PM_VALKYRIE: 1485 return ("Farvel"); /* Norse */ 1486 default: 1487 return ("Goodbye"); 1488 } 1489} 1490 1491/* role.c */ 1492