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