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 <sys/cdefs.h>
65 #ifndef lint
66 __RCSID("$NetBSD: hack.u_init.c,v 1.13 2011/08/06 19:32:58 dholland Exp $");
67 #endif                                  /* not lint */
68 
69 #include <ctype.h>
70 #include <signal.h>
71 #include <stdlib.h>
72 #include "hack.h"
73 #include "extern.h"
74 
75 #define Strcpy      (void) strcpy
76 #define   Strcat    (void) strcat
77 #define   UNDEF_TYP 0
78 #define   UNDEF_SPE '\177'
79 
80 char pl_character[PL_CSIZ];
81 
82 static const struct you zerou;
83 static const char *(roles[]) = {      /* must all have distinct first letter */
84           /* roles[4] may be changed to -woman */
85           "Tourist", "Speleologist", "Fighter", "Knight",
86           "Cave-man", "Wizard"
87 };
88 #define   NR_OF_ROLES         SIZE(roles)
89 static char rolesyms[NR_OF_ROLES + 1];  /* filled by u_init() */
90 
91 struct trobj {
92           uchar           trotyp;
93           schar           trspe;
94           char            trolet;
95                           Bitfield(trquan, 6);
96                           Bitfield(trknown, 1);
97 };
98 
99 #ifdef WIZARD
100 static struct trobj Extra_objs[] = {
101           {0, 0, 0, 0, 0},
102           {0, 0, 0, 0, 0}
103 };
104 #endif    /* WIZARD */
105 
106 static struct trobj Cave_man[] = {
107           {MACE, 1, WEAPON_SYM, 1, 1},
108           {BOW, 1, WEAPON_SYM, 1, 1},
109           {ARROW, 0, WEAPON_SYM, 25, 1},          /* quan is variable */
110           {LEATHER_ARMOR, 0, ARMOR_SYM, 1, 1},
111           {0, 0, 0, 0, 0}
112 };
113 
114 static struct trobj Fighter[] = {
115           {TWO_HANDED_SWORD, 0, WEAPON_SYM, 1, 1},
116           {RING_MAIL, 0, ARMOR_SYM, 1, 1},
117           {0, 0, 0, 0, 0}
118 };
119 
120 static struct trobj Knight[] = {
121           {LONG_SWORD, 0, WEAPON_SYM, 1, 1},
122           {SPEAR, 2, WEAPON_SYM, 1, 1},
123           {RING_MAIL, 1, ARMOR_SYM, 1, 1},
124           {HELMET, 0, ARMOR_SYM, 1, 1},
125           {SHIELD, 0, ARMOR_SYM, 1, 1},
126           {PAIR_OF_GLOVES, 0, ARMOR_SYM, 1, 1},
127           {0, 0, 0, 0, 0}
128 };
129 
130 static struct trobj Speleologist[] = {
131           {STUDDED_LEATHER_ARMOR, 0, ARMOR_SYM, 1, 1},
132           {UNDEF_TYP, 0, POTION_SYM, 2, 0},
133           {FOOD_RATION, 0, FOOD_SYM, 3, 1},
134           {PICK_AXE, UNDEF_SPE, TOOL_SYM, 1, 0},
135           {ICE_BOX, 0, TOOL_SYM, 1, 0},
136           {0, 0, 0, 0, 0}
137 };
138 
139 static struct trobj Tinopener[] = {
140           {CAN_OPENER, 0, TOOL_SYM, 1, 1},
141           {0, 0, 0, 0, 0}
142 };
143 
144 static struct trobj Tourist[] = {
145           {UNDEF_TYP, 0, FOOD_SYM, 10, 1},
146           {POT_EXTRA_HEALING, 0, POTION_SYM, 2, 0},
147           {EXPENSIVE_CAMERA, 0, TOOL_SYM, 1, 1},
148           {DART, 2, WEAPON_SYM, 25, 1}, /* quan is variable */
149           {0, 0, 0, 0, 0}
150 };
151 
152 static struct trobj Wizard[] = {
153           {ELVEN_CLOAK, 0, ARMOR_SYM, 1, 1},
154           {UNDEF_TYP, UNDEF_SPE, WAND_SYM, 2, 0},
155           {UNDEF_TYP, UNDEF_SPE, RING_SYM, 2, 0},
156           {UNDEF_TYP, UNDEF_SPE, POTION_SYM, 2, 0},
157           {UNDEF_TYP, UNDEF_SPE, SCROLL_SYM, 3, 0},
158           {0, 0, 0, 0, 0}
159 };
160 
161 static void ini_inv(struct trobj *);
162 static void wiz_inv(void);
163 static int role_index(int);
164 
165 void
u_init(void)166 u_init(void)
167 {
168           int    i;
169           char            exper = 'y', pc;
170           if (flags.female)   /* should have been set in HACKOPTIONS */
171                     roles[4] = "Cave-woman";
172           for (i = 0; i < NR_OF_ROLES; i++)
173                     rolesyms[i] = roles[i][0];
174           rolesyms[i] = 0;
175 
176           if ((pc = pl_character[0]) != '\0') {
177                     if (islower((unsigned char)pc))
178                               pc = toupper((unsigned char)pc);
179                     if ((i = role_index(pc)) >= 0)
180                               goto got_suffix;    /* implies experienced */
181                     printf("\nUnknown role: %c\n", pc);
182                     pl_character[0] = pc = 0;
183           }
184           printf("\nAre you an experienced player? [ny] ");
185 
186           while (!strchr("ynYN \n\004", (exper = readchar())))
187                     sound_bell();
188           if (exper == '\004')          /* Give him an opportunity to get out */
189                     end_of_input();
190           printf("%c\n", exper);        /* echo */
191           if (strchr("Nn \n", exper)) {
192                     exper = 0;
193                     goto beginner;
194           }
195           printf("\nTell me what kind of character you are:\n");
196           printf("Are you");
197           for (i = 0; i < NR_OF_ROLES; i++) {
198                     printf(" a %s", roles[i]);
199                     if (i == 2)         /* %% */
200                               printf(",\n\t");
201                     else if (i < NR_OF_ROLES - 2)
202                               printf(",");
203                     else if (i == NR_OF_ROLES - 2)
204                               printf(" or");
205           }
206           printf("? [%s] ", rolesyms);
207 
208           while ((pc = readchar()) != '\0') {
209                     if (islower((unsigned char)pc))
210                               pc = toupper((unsigned char)pc);
211                     if ((i = role_index(pc)) >= 0) {
212                               printf("%c\n", pc); /* echo */
213                               (void) fflush(stdout);        /* should be seen */
214                               break;
215                     }
216                     if (pc == '\n')
217                               break;
218                     if (pc == '\004')   /* Give him the opportunity to get
219                                                    * out */
220                               end_of_input();
221                     sound_bell();
222           }
223           if (pc == '\n')
224                     pc = 0;
225 
226 beginner:
227           if (!pc) {
228                     printf("\nI'll choose a character for you.\n");
229                     i = rn2(NR_OF_ROLES);
230                     pc = rolesyms[i];
231                     printf("This game you will be a%s %s.\n",
232                            exper ? "n experienced" : "",
233                            roles[i]);
234                     getret();
235                     /* give him some feedback in case mklev takes much time */
236                     (void) putchar('\n');
237                     (void) fflush(stdout);
238           }
239 #if 0
240           /*
241            * Given the above code, I can't see why this would ever change
242            * anything; it does core pretty well, though.  - cmh 4/20/93
243            */
244           if (exper) {
245                     roles[i][0] = pc;
246           }
247 #endif
248 
249 got_suffix:
250 
251           (void) strncpy(pl_character, roles[i], PL_CSIZ - 1);
252           pl_character[PL_CSIZ - 1] = 0;
253           flags.beginner = 1;
254           u = zerou;
255           u.usym = '@';
256           u.ulevel = 1;
257           init_uhunger();
258 #ifdef QUEST
259           u.uhorizon = 6;
260 #endif    /* QUEST */
261           uarm = uarm2 = uarmh = uarms = uarmg = uwep = uball = uchain =
262                     uleft = uright = 0;
263 
264           switch (pc) {
265           case 'c':
266           case 'C':
267                     Cave_man[2].trquan = 12 + rnd(9) * rnd(9);
268                     u.uhp = u.uhpmax = 16;
269                     u.ustr = u.ustrmax = 18;
270                     ini_inv(Cave_man);
271                     break;
272           case 't':
273           case 'T':
274                     Tourist[3].trquan = 20 + rnd(20);
275                     u.ugold = u.ugold0 = rnd(1000);
276                     u.uhp = u.uhpmax = 10;
277                     u.ustr = u.ustrmax = 8;
278                     ini_inv(Tourist);
279                     if (!rn2(25))
280                               ini_inv(Tinopener);
281                     break;
282           case 'w':
283           case 'W':
284                     for (i = 1; i <= 4; i++)
285                               if (!rn2(5))
286                                         Wizard[i].trquan += rn2(3) - 1;
287                     u.uhp = u.uhpmax = 15;
288                     u.ustr = u.ustrmax = 16;
289                     ini_inv(Wizard);
290                     break;
291           case 's':
292           case 'S':
293                     Fast = INTRINSIC;
294                     Stealth = INTRINSIC;
295                     u.uhp = u.uhpmax = 12;
296                     u.ustr = u.ustrmax = 10;
297                     ini_inv(Speleologist);
298                     if (!rn2(10))
299                               ini_inv(Tinopener);
300                     break;
301           case 'k':
302           case 'K':
303                     u.uhp = u.uhpmax = 12;
304                     u.ustr = u.ustrmax = 10;
305                     ini_inv(Knight);
306                     break;
307           case 'f':
308           case 'F':
309                     u.uhp = u.uhpmax = 14;
310                     u.ustr = u.ustrmax = 17;
311                     ini_inv(Fighter);
312                     break;
313           default:            /* impossible */
314                     u.uhp = u.uhpmax = 12;
315                     u.ustr = u.ustrmax = 16;
316           }
317           find_ac();
318           if (!rn2(20)) {
319                     int    dr = rn2(7) - 2;       /* biased variation */
320                     u.ustr += dr;
321                     u.ustrmax += dr;
322           }
323 #ifdef WIZARD
324           if (wizard)
325                     wiz_inv();
326 #endif    /* WIZARD */
327 
328           /* make sure he can carry all he has - especially for T's */
329           while (inv_weight() > 0 && u.ustr < 118)
330                     u.ustr++, u.ustrmax++;
331 }
332 
333 void
ini_inv(struct trobj * trop)334 ini_inv(struct trobj *trop)
335 {
336           struct obj *obj;
337           while (trop->trolet) {
338                     obj = mkobj(trop->trolet);
339                     obj->known = trop->trknown;
340                     /* not obj->dknown = 1; - let him look at it at least once */
341                     obj->cursed = 0;
342                     if (obj->olet == WEAPON_SYM) {
343                               obj->quan = trop->trquan;
344                               trop->trquan = 1;
345                     }
346                     if (trop->trspe != UNDEF_SPE)
347                               obj->spe = trop->trspe;
348                     if (trop->trotyp != UNDEF_TYP)
349                               obj->otyp = trop->trotyp;
350                     else if (obj->otyp == WAN_WISHING)      /* gitpyr!robert */
351                               obj->otyp = WAN_DEATH;
352                     obj->owt = weight(obj);       /* defined after setting otyp+quan */
353                     obj = addinv(obj);
354                     if (obj->olet == ARMOR_SYM) {
355                               switch (obj->otyp) {
356                               case SHIELD:
357                                         if (!uarms)
358                                                   setworn(obj, W_ARMS);
359                                         break;
360                               case HELMET:
361                                         if (!uarmh)
362                                                   setworn(obj, W_ARMH);
363                                         break;
364                               case PAIR_OF_GLOVES:
365                                         if (!uarmg)
366                                                   setworn(obj, W_ARMG);
367                                         break;
368                               case ELVEN_CLOAK:
369                                         if (!uarm2)
370                                                   setworn(obj, W_ARM);
371                                         break;
372                               default:
373                                         if (!uarm)
374                                                   setworn(obj, W_ARM);
375                               }
376                     }
377                     if (obj->olet == WEAPON_SYM)
378                               if (!uwep)
379                                         setuwep(obj);
380                     if (--trop->trquan)
381                               continue; /* make a similar object */
382                     trop++;
383           }
384 }
385 
386 #ifdef WIZARD
387 void
wiz_inv(void)388 wiz_inv(void)
389 {
390           struct trobj *trop = &Extra_objs[0];
391           char  *ep = getenv("INVENT");
392           int    type;
393           while (ep && *ep) {
394                     type = atoi(ep);
395                     ep = strchr(ep, ',');
396                     if (ep)
397                               while (*ep == ',' || *ep == ' ')
398                                         ep++;
399                     if (type <= 0 || type > NROFOBJECTS)
400                               continue;
401                     trop->trotyp = type;
402                     trop->trolet = objects[type].oc_olet;
403                     trop->trspe = 4;
404                     trop->trknown = 1;
405                     trop->trquan = 1;
406                     ini_inv(trop);
407           }
408           /* give him a wand of wishing by default */
409           trop->trotyp = WAN_WISHING;
410           trop->trolet = WAND_SYM;
411           trop->trspe = 20;
412           trop->trknown = 1;
413           trop->trquan = 1;
414           ini_inv(trop);
415 }
416 #endif    /* WIZARD */
417 
418 void
plnamesuffix(void)419 plnamesuffix(void)
420 {
421           char  *p;
422           if ((p = strrchr(plname, '-')) != NULL) {
423                     *p = 0;
424                     pl_character[0] = p[1];
425                     pl_character[1] = 0;
426                     if (!plname[0]) {
427                               askname();
428                               plnamesuffix();
429                     }
430           }
431 }
432 
433 int
role_index(int pc)434 role_index(int pc)
435 {                                       /* must be called only from u_init() */
436           /* so that rolesyms[] is defined */
437           char  *cp;
438 
439           if ((cp = strchr(rolesyms, pc)) != NULL)
440                     return (cp - rolesyms);
441           return (-1);
442 }
443