1 /* $NetBSD: hack.u_init.c,v 1.13 2011/08/06 19:32:58 dholland Exp $ */ 2 3 /* 4 * Copyright (c) 1985, Stichting Centrum voor Wiskunde en Informatica, 5 * Amsterdam 6 * All rights reserved. 7 * 8 * Redistribution and use in source and binary forms, with or without 9 * modification, are permitted provided that the following conditions are 10 * met: 11 * 12 * - Redistributions of source code must retain the above copyright notice, 13 * this list of conditions and the following disclaimer. 14 * 15 * - Redistributions in binary form must reproduce the above copyright 16 * notice, this list of conditions and the following disclaimer in the 17 * documentation and/or other materials provided with the distribution. 18 * 19 * - Neither the name of the Stichting Centrum voor Wiskunde en 20 * Informatica, nor the names of its contributors may be used to endorse or 21 * promote products derived from this software without specific prior 22 * written permission. 23 * 24 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS 25 * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 26 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A 27 * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER 28 * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 29 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 30 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 31 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 32 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 33 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 34 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 35 */ 36 37 /* 38 * Copyright (c) 1982 Jay Fenlason <hack@gnu.org> 39 * All rights reserved. 40 * 41 * Redistribution and use in source and binary forms, with or without 42 * modification, are permitted provided that the following conditions 43 * are met: 44 * 1. Redistributions of source code must retain the above copyright 45 * notice, this list of conditions and the following disclaimer. 46 * 2. Redistributions in binary form must reproduce the above copyright 47 * notice, this list of conditions and the following disclaimer in the 48 * documentation and/or other materials provided with the distribution. 49 * 3. The name of the author may not be used to endorse or promote products 50 * derived from this software without specific prior written permission. 51 * 52 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, 53 * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY 54 * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL 55 * THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 56 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 57 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; 58 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 59 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 60 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 61 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 62 */ 63 64 #include <ctype.h> 65 #include <signal.h> 66 #include <stdlib.h> 67 #include "hack.h" 68 #include "extern.h" 69 70 #define Strcpy (void) strcpy 71 #define Strcat (void) strcat 72 #define UNDEF_TYP 0 73 #define UNDEF_SPE '\177' 74 75 char pl_character[PL_CSIZ]; 76 77 static const struct you zerou; 78 static const char *(roles[]) = { /* must all have distinct first letter */ 79 /* roles[4] may be changed to -woman */ 80 "Tourist", "Speleologist", "Fighter", "Knight", 81 "Cave-man", "Wizard" 82 }; 83 #define NR_OF_ROLES SIZE(roles) 84 static char rolesyms[NR_OF_ROLES + 1]; /* filled by u_init() */ 85 86 struct trobj { 87 uchar trotyp; 88 schar trspe; 89 char trolet; 90 Bitfield(trquan, 6); 91 Bitfield(trknown, 1); 92 }; 93 94 #ifdef WIZARD 95 static struct trobj Extra_objs[] = { 96 {0, 0, 0, 0, 0}, 97 {0, 0, 0, 0, 0} 98 }; 99 #endif /* WIZARD */ 100 101 static struct trobj Cave_man[] = { 102 {MACE, 1, WEAPON_SYM, 1, 1}, 103 {BOW, 1, WEAPON_SYM, 1, 1}, 104 {ARROW, 0, WEAPON_SYM, 25, 1}, /* quan is variable */ 105 {LEATHER_ARMOR, 0, ARMOR_SYM, 1, 1}, 106 {0, 0, 0, 0, 0} 107 }; 108 109 static struct trobj Fighter[] = { 110 {TWO_HANDED_SWORD, 0, WEAPON_SYM, 1, 1}, 111 {RING_MAIL, 0, ARMOR_SYM, 1, 1}, 112 {0, 0, 0, 0, 0} 113 }; 114 115 static struct trobj Knight[] = { 116 {LONG_SWORD, 0, WEAPON_SYM, 1, 1}, 117 {SPEAR, 2, WEAPON_SYM, 1, 1}, 118 {RING_MAIL, 1, ARMOR_SYM, 1, 1}, 119 {HELMET, 0, ARMOR_SYM, 1, 1}, 120 {SHIELD, 0, ARMOR_SYM, 1, 1}, 121 {PAIR_OF_GLOVES, 0, ARMOR_SYM, 1, 1}, 122 {0, 0, 0, 0, 0} 123 }; 124 125 static struct trobj Speleologist[] = { 126 {STUDDED_LEATHER_ARMOR, 0, ARMOR_SYM, 1, 1}, 127 {UNDEF_TYP, 0, POTION_SYM, 2, 0}, 128 {FOOD_RATION, 0, FOOD_SYM, 3, 1}, 129 {PICK_AXE, UNDEF_SPE, TOOL_SYM, 1, 0}, 130 {ICE_BOX, 0, TOOL_SYM, 1, 0}, 131 {0, 0, 0, 0, 0} 132 }; 133 134 static struct trobj Tinopener[] = { 135 {CAN_OPENER, 0, TOOL_SYM, 1, 1}, 136 {0, 0, 0, 0, 0} 137 }; 138 139 static struct trobj Tourist[] = { 140 {UNDEF_TYP, 0, FOOD_SYM, 10, 1}, 141 {POT_EXTRA_HEALING, 0, POTION_SYM, 2, 0}, 142 {EXPENSIVE_CAMERA, 0, TOOL_SYM, 1, 1}, 143 {DART, 2, WEAPON_SYM, 25, 1}, /* quan is variable */ 144 {0, 0, 0, 0, 0} 145 }; 146 147 static struct trobj Wizard[] = { 148 {ELVEN_CLOAK, 0, ARMOR_SYM, 1, 1}, 149 {UNDEF_TYP, UNDEF_SPE, WAND_SYM, 2, 0}, 150 {UNDEF_TYP, UNDEF_SPE, RING_SYM, 2, 0}, 151 {UNDEF_TYP, UNDEF_SPE, POTION_SYM, 2, 0}, 152 {UNDEF_TYP, UNDEF_SPE, SCROLL_SYM, 3, 0}, 153 {0, 0, 0, 0, 0} 154 }; 155 156 static void ini_inv(struct trobj *); 157 static void wiz_inv(void); 158 static int role_index(int); 159 160 void 161 u_init(void) 162 { 163 int i; 164 char exper = 'y', pc; 165 if (flags.female) /* should have been set in HACKOPTIONS */ 166 roles[4] = "Cave-woman"; 167 for (i = 0; i < NR_OF_ROLES; i++) 168 rolesyms[i] = roles[i][0]; 169 rolesyms[i] = 0; 170 171 if ((pc = pl_character[0]) != '\0') { 172 if (islower((unsigned char)pc)) 173 pc = toupper((unsigned char)pc); 174 if ((i = role_index(pc)) >= 0) 175 goto got_suffix; /* implies experienced */ 176 printf("\nUnknown role: %c\n", pc); 177 pl_character[0] = pc = 0; 178 } 179 printf("\nAre you an experienced player? [ny] "); 180 181 while (!strchr("ynYN \n\004", (exper = readchar()))) 182 sound_bell(); 183 if (exper == '\004') /* Give him an opportunity to get out */ 184 end_of_input(); 185 printf("%c\n", exper); /* echo */ 186 if (strchr("Nn \n", exper)) { 187 exper = 0; 188 goto beginner; 189 } 190 printf("\nTell me what kind of character you are:\n"); 191 printf("Are you"); 192 for (i = 0; i < NR_OF_ROLES; i++) { 193 printf(" a %s", roles[i]); 194 if (i == 2) /* %% */ 195 printf(",\n\t"); 196 else if (i < NR_OF_ROLES - 2) 197 printf(","); 198 else if (i == NR_OF_ROLES - 2) 199 printf(" or"); 200 } 201 printf("? [%s] ", rolesyms); 202 203 while ((pc = readchar()) != '\0') { 204 if (islower((unsigned char)pc)) 205 pc = toupper((unsigned char)pc); 206 if ((i = role_index(pc)) >= 0) { 207 printf("%c\n", pc); /* echo */ 208 (void) fflush(stdout); /* should be seen */ 209 break; 210 } 211 if (pc == '\n') 212 break; 213 if (pc == '\004') /* Give him the opportunity to get 214 * out */ 215 end_of_input(); 216 sound_bell(); 217 } 218 if (pc == '\n') 219 pc = 0; 220 221 beginner: 222 if (!pc) { 223 printf("\nI'll choose a character for you.\n"); 224 i = rn2(NR_OF_ROLES); 225 pc = rolesyms[i]; 226 printf("This game you will be a%s %s.\n", 227 exper ? "n experienced" : "", 228 roles[i]); 229 getret(); 230 /* give him some feedback in case mklev takes much time */ 231 (void) putchar('\n'); 232 (void) fflush(stdout); 233 } 234 #if 0 235 /* 236 * Given the above code, I can't see why this would ever change 237 * anything; it does core pretty well, though. - cmh 4/20/93 238 */ 239 if (exper) { 240 roles[i][0] = pc; 241 } 242 #endif 243 244 got_suffix: 245 246 (void) strncpy(pl_character, roles[i], PL_CSIZ - 1); 247 pl_character[PL_CSIZ - 1] = 0; 248 flags.beginner = 1; 249 u = zerou; 250 u.usym = '@'; 251 u.ulevel = 1; 252 init_uhunger(); 253 #ifdef QUEST 254 u.uhorizon = 6; 255 #endif /* QUEST */ 256 uarm = uarm2 = uarmh = uarms = uarmg = uwep = uball = uchain = 257 uleft = uright = 0; 258 259 switch (pc) { 260 case 'c': 261 case 'C': 262 Cave_man[2].trquan = 12 + rnd(9) * rnd(9); 263 u.uhp = u.uhpmax = 16; 264 u.ustr = u.ustrmax = 18; 265 ini_inv(Cave_man); 266 break; 267 case 't': 268 case 'T': 269 Tourist[3].trquan = 20 + rnd(20); 270 u.ugold = u.ugold0 = rnd(1000); 271 u.uhp = u.uhpmax = 10; 272 u.ustr = u.ustrmax = 8; 273 ini_inv(Tourist); 274 if (!rn2(25)) 275 ini_inv(Tinopener); 276 break; 277 case 'w': 278 case 'W': 279 for (i = 1; i <= 4; i++) 280 if (!rn2(5)) 281 Wizard[i].trquan += rn2(3) - 1; 282 u.uhp = u.uhpmax = 15; 283 u.ustr = u.ustrmax = 16; 284 ini_inv(Wizard); 285 break; 286 case 's': 287 case 'S': 288 Fast = INTRINSIC; 289 Stealth = INTRINSIC; 290 u.uhp = u.uhpmax = 12; 291 u.ustr = u.ustrmax = 10; 292 ini_inv(Speleologist); 293 if (!rn2(10)) 294 ini_inv(Tinopener); 295 break; 296 case 'k': 297 case 'K': 298 u.uhp = u.uhpmax = 12; 299 u.ustr = u.ustrmax = 10; 300 ini_inv(Knight); 301 break; 302 case 'f': 303 case 'F': 304 u.uhp = u.uhpmax = 14; 305 u.ustr = u.ustrmax = 17; 306 ini_inv(Fighter); 307 break; 308 default: /* impossible */ 309 u.uhp = u.uhpmax = 12; 310 u.ustr = u.ustrmax = 16; 311 } 312 find_ac(); 313 if (!rn2(20)) { 314 int dr = rn2(7) - 2; /* biased variation */ 315 u.ustr += dr; 316 u.ustrmax += dr; 317 } 318 #ifdef WIZARD 319 if (wizard) 320 wiz_inv(); 321 #endif /* WIZARD */ 322 323 /* make sure he can carry all he has - especially for T's */ 324 while (inv_weight() > 0 && u.ustr < 118) 325 u.ustr++, u.ustrmax++; 326 } 327 328 void 329 ini_inv(struct trobj *trop) 330 { 331 struct obj *obj; 332 while (trop->trolet) { 333 obj = mkobj(trop->trolet); 334 obj->known = trop->trknown; 335 /* not obj->dknown = 1; - let him look at it at least once */ 336 obj->cursed = 0; 337 if (obj->olet == WEAPON_SYM) { 338 obj->quan = trop->trquan; 339 trop->trquan = 1; 340 } 341 if (trop->trspe != UNDEF_SPE) 342 obj->spe = trop->trspe; 343 if (trop->trotyp != UNDEF_TYP) 344 obj->otyp = trop->trotyp; 345 else if (obj->otyp == WAN_WISHING) /* gitpyr!robert */ 346 obj->otyp = WAN_DEATH; 347 obj->owt = weight(obj); /* defined after setting otyp+quan */ 348 obj = addinv(obj); 349 if (obj->olet == ARMOR_SYM) { 350 switch (obj->otyp) { 351 case SHIELD: 352 if (!uarms) 353 setworn(obj, W_ARMS); 354 break; 355 case HELMET: 356 if (!uarmh) 357 setworn(obj, W_ARMH); 358 break; 359 case PAIR_OF_GLOVES: 360 if (!uarmg) 361 setworn(obj, W_ARMG); 362 break; 363 case ELVEN_CLOAK: 364 if (!uarm2) 365 setworn(obj, W_ARM); 366 break; 367 default: 368 if (!uarm) 369 setworn(obj, W_ARM); 370 } 371 } 372 if (obj->olet == WEAPON_SYM) 373 if (!uwep) 374 setuwep(obj); 375 if (--trop->trquan) 376 continue; /* make a similar object */ 377 trop++; 378 } 379 } 380 381 #ifdef WIZARD 382 void 383 wiz_inv(void) 384 { 385 struct trobj *trop = &Extra_objs[0]; 386 char *ep = getenv("INVENT"); 387 int type; 388 while (ep && *ep) { 389 type = atoi(ep); 390 ep = strchr(ep, ','); 391 if (ep) 392 while (*ep == ',' || *ep == ' ') 393 ep++; 394 if (type <= 0 || type > NROFOBJECTS) 395 continue; 396 trop->trotyp = type; 397 trop->trolet = objects[type].oc_olet; 398 trop->trspe = 4; 399 trop->trknown = 1; 400 trop->trquan = 1; 401 ini_inv(trop); 402 } 403 /* give him a wand of wishing by default */ 404 trop->trotyp = WAN_WISHING; 405 trop->trolet = WAND_SYM; 406 trop->trspe = 20; 407 trop->trknown = 1; 408 trop->trquan = 1; 409 ini_inv(trop); 410 } 411 #endif /* WIZARD */ 412 413 void 414 plnamesuffix(void) 415 { 416 char *p; 417 if ((p = strrchr(plname, '-')) != NULL) { 418 *p = 0; 419 pl_character[0] = p[1]; 420 pl_character[1] = 0; 421 if (!plname[0]) { 422 askname(); 423 plnamesuffix(); 424 } 425 } 426 } 427 428 int 429 role_index(int pc) 430 { /* must be called only from u_init() */ 431 /* so that rolesyms[] is defined */ 432 char *cp; 433 434 if ((cp = strchr(rolesyms, pc)) != NULL) 435 return (cp - rolesyms); 436 return (-1); 437 } 438