Source:NetHack 3.4.0/role.c

Below is the full text to role.c from the source code of NetHack 3.4.0. To link to a particular line, write [[NetHack 3.4.0/role.c#line123 ]], for example.

Warning! This is the source code from an old release. For the latest release, see Source code

1.   /*	SCCS Id: @(#)role.c	3.4	2000/08/20	*/ 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.   */  27.   const 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.   382.  };  383.   384.   385.  /* The player's role, created at runtime from initial 386.  * choices. This may be munged in role_init. 387.  */  388.  struct 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 */ 406. const 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.  */  475.  struct 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 */ 490. const 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 */ 498. const 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.   505.  STATIC_DCL char * FDECL(promptsep, (char *, int)); 506. STATIC_DCL int FDECL(role_gendercount, (int)); 507. STATIC_DCL int FDECL(race_alignmentcount, (int)); 508.  509.  /* used by str2XXX */ 510. static char NEARDATA randomstr[] = "random"; 511.  512.   513.  boolean 514. validrole(rolenum) 515. 	int rolenum; 516. {  517.  	return (rolenum >= 0 && rolenum < SIZE(roles)-1); 518. }  519.   520.   521.  int 522. randrole 523. {  524.  	return (rn2(SIZE(roles)-1)); 525. }  526.   527.   528.  int 529. str2role(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.   561.  boolean 562. validrace(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.   571.  int 572. randrace(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.   596.  int 597. str2race(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.   626.  boolean 627. validgend(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.   637.  int 638. randgend(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.   663.  int 664. str2gend(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.   692.  boolean 693. validalign(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.   703.  int 704. randalign(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.   729.  int 730. str2align(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? */ 758.  boolean 759. ok_role(rolenum, racenum, gendnum, alignnum) 760. int 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 */ 798. int 799. pick_role(racenum, gendnum, alignnum, pickhow) 800. int 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? */ 824.  boolean 825. ok_race(rolenum, racenum, gendnum, alignnum) 826. int 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 */ 864. int 865. pick_race(rolenum, gendnum, alignnum, pickhow) 866. int 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) */ 891. boolean 892. ok_gend(rolenum, racenum, gendnum, alignnum) 893. int 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 */ 926. int 927. pick_gend(rolenum, racenum, alignnum, pickhow) 928. int 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) */ 953. boolean 954. ok_align(rolenum, racenum, gendnum, alignnum) 955. int 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 */ 988. int 989. pick_align(rolenum, racenum, gendnum, pickhow) 990. int 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.  1013. void 1014. rigid_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. 1053. STATIC_VAR char pa[NUM_BP], post_attribs; 1054. 1055. STATIC_OVL char * 1056. promptsep(buf, num_post_attribs) 1057. char *buf; 1058. int 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.  1070. STATIC_OVL int 1071. role_gendercount(rolenum) 1072. int 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.  1083. STATIC_OVL int 1084. race_alignmentcount(racenum) 1085. int 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.  1096. char * 1097. root_plselection_prompt(suppliedbuf, buflen, rolenum, racenum, gendnum, alignnum) 1098. char *suppliedbuf; 1099. int buflen, rolenum, racenum, gendnum, alignnum; 1100. { 1101. 	int k, gendercount = 0, aligncount = 0; 1102. 	char buf[BUFSZ]; 1103. 	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. 	/* */  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. 	/* */  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. 	/*  || */ 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. 	/*  || 1222. 	 *   ||  1223. 	 */ 1224. 	if (buflen > (int) (strlen(buf) + 1)) { 1225. 		Strcpy(suppliedbuf, buf); 1226. 		return suppliedbuf; 1227. 	} else 1228. 		return err_ret; 1229. } 1230.  1231. char * 1232. build_plselection_prompt(buf, buflen, rolenum, racenum, gendnum, alignnum) 1233. char *buf; 1234. int 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. 	/* */  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> ||  1257. *   ||   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. 1291. void 1292. plnamesuffix 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.  */  1344. void  1345. role_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. Try flags.igend first. */ 1372. 	if (!validgend(flags.initrole, flags.initrace, flags.initgend)) 1373. 	   /* Use flags.female second. Note that there is no way 1374. 	    * to check for an unspecified gender. 1375. 	    */  1376. 	    flags.initgend = flags.female; 1377. 	/* Don't change flags.female; this may be a restore */ 1378. 1379. 	/* Check for a valid alignment */ 1380. 	if (!validalign(flags.initrole, flags.initrace, flags.initalign)) 1381. 	   /* Pick a random alignment */ 1382. 	   flags.initalign = randalign(flags.initrole, flags.initrace); 1383. 	alignmnt = aligns[flags.initalign].value; 1384. 1385. 	/* Initialize urole and urace */ 1386. 	urole = roles[flags.initrole]; 1387. 	urace = races[flags.initrace]; 1388. 1389. 	/* Fix up the quest leader */ 1390. 	if (urole.ldrnum != NON_PM) { 1391. 	   mons[urole.ldrnum].msound = MS_LEADER; 1392. 	   mons[urole.ldrnum].mflags2 |= (M2_PEACEFUL); 1393. 	   mons[urole.ldrnum].mflags3 |= M3_CLOSE; 1394. 	   mons[urole.ldrnum].maligntyp = alignmnt * 3; 1395. 	} 1396.  1397. 	/* Fix up the quest guardians */ 1398. 	if (urole.guardnum != NON_PM) { 1399. 	   mons[urole.guardnum].mflags2 |= (M2_PEACEFUL); 1400. 	   mons[urole.guardnum].maligntyp = alignmnt * 3; 1401. 	} 1402.  1403. 	/* Fix up the quest nemesis */ 1404. 	if (urole.neminum != NON_PM) { 1405. 	   mons[urole.neminum].msound = MS_NEMESIS; 1406. 	   mons[urole.neminum].mflags2 &= ~(M2_PEACEFUL); 1407. 	   mons[urole.neminum].mflags2 |= (M2_NASTY|M2_STALK|M2_HOSTILE); 1408. 	   mons[urole.neminum].mflags3 |= M3_WANTSARTI | M3_WAITFORU; 1409. 	} 1410.  1411. 	/* Fix up the god names */ 1412. 	if (flags.pantheon == -1) {		/* new game */ 1413. 	   flags.pantheon = flags.initrole;	/* use own gods */ 1414. 	   while (!roles[flags.pantheon].lgod)	/* unless they're missing */ 1415. 		flags.pantheon = randrole; 1416. 	} 1417. 	if (!urole.lgod) { 1418. 	   urole.lgod = roles[flags.pantheon].lgod; 1419. 	   urole.ngod = roles[flags.pantheon].ngod; 1420. 	   urole.cgod = roles[flags.pantheon].cgod; 1421. 	} 1422.  1423. 	/* Fix up infravision */ 1424. 	if (mons[urace.malenum].mflags3 & M3_INFRAVISION) { 1425. 	   /* although an infravision intrinsic is possible, infravision 1426. 	    * is purely a property of the physical race. This means that we 1427. * must put the infravision flag in the player's current race 1428. 	    * (either that or have separate permonst entries for  1429. 	     * elven/non-elven members of each class). The side effect is that 1430. 	    * all NPCs of that class will have (probably bogus) infravision, 1431. 	    * but since infravision has no effect for NPCs anyway we can 1432. 	    * ignore this. 1433. 	    */  1434. 	    mons[urole.malenum].mflags3 |= M3_INFRAVISION; 1435. 	   if (urole.femalenum != NON_PM) 1436. 	   	mons[urole.femalenum].mflags3 |= M3_INFRAVISION; 1437. 	} 1438.  1439. 	/* Artifacts are fixed in hack_artifacts */ 1440. 1441. 	/* Success! */ 1442. 	return; 1443. } 1444.  1445. const char * 1446. Hello(mtmp) 1447. struct monst *mtmp; 1448. { 1449. 	switch (Role_switch) { 1450. 	case PM_KNIGHT: 1451. 	   return ("Salutations"); /* Olde English */ 1452. 	case PM_SAMURAI: 1453. 	   return (mtmp && mtmp->data == &mons[PM_SHOPKEEPER] ?  1454. 	    		"Irasshaimase" : "Konnichi wa"); /* Japanese */ 1455. #ifdef TOURIST 1456. 	case PM_TOURIST: 1457. 	   return ("Aloha");       /* Hawaiian */ 1458. #endif 1459. 	case PM_VALKYRIE: 1460. 	   return (  1461. #ifdef MAIL  1462. 	    		mtmp && mtmp->data == &mons[PM_MAIL_DAEMON] ? "Hallo" :  1463. #endif  1464. 	    		"Velkommen");   /* Norse */ 1465. 	default: 1466. 	   return ("Hello"); 1467. 	} 1468. }  1469.  1470. const char * 1471. Goodbye 1472. { 1473. 	switch (Role_switch) { 1474. 	case PM_KNIGHT: 1475. 	   return ("Fare thee well");  /* Olde English */ 1476. 	case PM_SAMURAI: 1477. 	   return ("Sayonara");        /* Japanese */ 1478. #ifdef TOURIST 1479. 	case PM_TOURIST: 1480. 	   return ("Aloha");           /* Hawaiian */ 1481. #endif 1482. 	case PM_VALKYRIE: 1483. 	   return ("Farvel");          /* Norse */ 1484. 	default: 1485. 	   return ("Goodbye"); 1486. 	} 1487. }  1488.  1489. /* role.c */