1 #include "rogue.h"
2 #include "curses.h"
3 
4 /*
5  * Routines to deal with the pack
6  *
7  * pack.c	1.4 (A.I. Design)	12/14/84
8  */
9 
10 THING *
11 pack_obj(ch, chp)
12 byte ch, *chp;
13 {
14 	register THING *obj;
15 	register byte och;
16 
17     for (obj = pack, och = 'a'; obj != NULL; obj = next(obj), och++)
18 		if (ch == och)
19 			return obj;
20 	*chp = och;
21 	return NULL;
22 }
23 
24 /*
25  * add_pack:
26  *	Pick up an object and add it to the pack.  If the argument is
27  *	non-null use it as the linked_list pointer instead of gettting
28  *	it off the ground.
29  */
30 add_pack(obj, silent)
31 register THING *obj;
32 bool silent;
33 {
34     register THING *op, *lp;
35     register bool exact, from_floor;
36     register byte floor;
37 
38     if (obj == NULL)
39     {
40 	from_floor = TRUE;
41 	if ((obj = find_obj(hero.y, hero.x)) == NULL)
42 	    return;
43     }
44     else
45 	from_floor = FALSE;
46     /*
47      * Link it into the pack.  Search the pack for a object of similar type
48      * if there isn't one, stuff it at the beginning, if there is, look for one
49      * that is exactly the same and just increment the count if there is.
50      * Food is always put at the beginning for ease of access, but it
51      * is not ordered so that you can't tell good food from bad.  First check
52      * to see if there is something in the same group and if there is then
53      * increment the count.
54      */
55     floor = (proom->r_flags & ISGONE) ? PASSAGE : FLOOR;
56     if (obj->o_group)
57     {
58 	for (op = pack; op != NULL; op = next(op))
59 	{
60 	    if (op->o_group == obj->o_group)
61 	    {
62 		/*
63 		 * Put it in the pack and notify the user
64 		 */
65 		op->o_count += obj->o_count;
66 		if (from_floor)
67 		{
68 		    detach(lvl_obj, obj);
69 		    mvaddch(hero.y, hero.x, floor);
70 		    chat(hero.y, hero.x) = floor;
71 		}
72 		discard(obj);
73 		obj = op;
74 		goto picked_up;
75 	    }
76 	}
77     }
78     /*
79      * Check if there is room
80      */
81     if (inpack >= MAXPACK-1)
82     {
83 	msg("you can't carry anything else");
84 	return;
85     }
86     /*
87      * Check for and deal with scare monster scrolls
88      */
89     if (obj->o_type == SCROLL && obj->o_which == S_SCARE)
90 	if (obj->o_flags & ISFOUND)
91 	{
92 	    detach(lvl_obj, obj);
93 	    mvaddch(hero.y, hero.x, floor);
94 	    chat(hero.y, hero.x) = floor;
95 		msg("the scroll turns to dust%s.", noterse(" as you pick it up"));
96 	    return;
97 	}
98 	else
99 	    obj->o_flags |= ISFOUND;
100 
101     inpack++;
102     if (from_floor)
103     {
104 	detach(lvl_obj, obj);
105 	mvaddch(hero.y, hero.x, floor);
106 	chat(hero.y, hero.x) = floor;
107     }
108     /*
109      * Search for an object of the same type
110      */
111     exact = FALSE;
112     for (op = pack; op != NULL; op = next(op))
113 	if (obj->o_type == op->o_type)
114 	    break;
115     if (op == NULL)
116     {
117 	/*
118 	 * Put it at the end of the pack since it is a new type
119 	 */
120 	for (op = pack; op != NULL; op = next(op))
121 	{
122 	    if (op->o_type != FOOD)
123 		break;
124 	    lp = op;
125 	}
126     }
127     else
128     {
129 	/*
130 	 * Search for an object which is exactly the same
131 	 */
132 	while (op->o_type == obj->o_type)
133 	{
134 	    if (op->o_which == obj->o_which)
135 	    {
136 		exact = TRUE;
137 		break;
138 	    }
139 	    lp = op;
140 	    if ((op = next(op)) == NULL)
141 		break;
142 	}
143     }
144     if (op == NULL)
145     {
146 	/*
147 	 * Didn't find an exact match, just stick it here
148 	 */
149 	if (pack == NULL)
150 	    pack = obj;
151 	else
152 	{
153 	    lp->l_next = obj;
154 	    obj->l_prev = lp;
155 	    obj->l_next = NULL;
156 	}
157     }
158     else
159     {
160 	/*
161 	 * If we found an exact match.  If it is a potion, food, or a 
162 	 * scroll, increase the count, otherwise put it with its clones.
163 	 */
164 	if (exact && ISMULT(obj->o_type))
165 	{
166 	    op->o_count++;
167 	    discard(obj);
168 	    obj = op;
169 	    goto picked_up;
170 	}
171 	if ((obj->l_prev = prev(op)) != NULL)
172 	    obj->l_prev->l_next = obj;
173 	else
174 	    pack = obj;
175 	obj->l_next = op;
176 	op->l_prev = obj;
177     }
178 picked_up:
179     /*
180      * If this was the object of something's desire, that monster will
181      * get mad and run at the hero
182      */
183     for (op = mlist; op != NULL; op = next(op))
184 	/*
185 	 *  compiler bug: jll : 2-7-83
186 	 *		It is stupid because it thinks the obj... is not an lvalue
187 	 *		this may be true since there is no structure assignments,
188 	 *		but still it should let you have the address??!!
189 	 *
190 	if (&obj->_o._o_pos == op->t_dest)
191 	 *
192 	 *  the following should do the same
193 	 */  
194 	if ((op->t_dest->x == obj->o_pos.x) && (op->t_dest->y == obj->o_pos.y))
195 	    op->t_dest = &hero;
196 
197     if (obj->o_type == AMULET)
198     {
199 	amulet = TRUE;
200 	saw_amulet = TRUE;
201     }
202     /*
203      * Notify the user
204      */
205     if (!silent)
206 	msg("%s%s (%c)",noterse("you now have "),
207 		inv_name(obj, TRUE), pack_char(obj));
208 }
209 
210 /*
211  * inventory:
212  *	List what is in the pack
213  */
214 inventory(list, type, lstr)
215 THING *list;
216 int type;
217 char *lstr;
218 {
219     register byte ch;
220     register int n_objs;
221     char inv_temp[MAXSTR];
222 
223     n_objs = 0;
224     for (ch = 'a'; list != NULL; ch++, list = next(list))
225     {
226 	/*
227 	 * Don't print this one if:
228 	 *	the type doesn't match the type we were passed AND
229 	 *	it isn't a callable type AND
230 	 *	it isn't a zappable weapon
231 	 */
232 	if (type && type != list->o_type && !(type == CALLABLE &&
233 	    (list->o_type == SCROLL || list->o_type == POTION ||
234 	     list->o_type == RING || list->o_type == STICK)) &&
235 	     !(type == WEAPON && list->o_type == POTION) &&
236 	     !(type == STICK && list->o_enemy && list->o_charges))
237 		continue;
238 	n_objs++;
239 	sprintf(inv_temp, "%c) %%s", ch);
240 	add_line(lstr, inv_temp, inv_name(list, FALSE));
241     }
242     if (n_objs == 0)
243     {
244 	msg(type == 0 ? "you are empty handed" :
245 			    "you don't have anything appropriate");
246 	return FALSE;
247     }
248     return(end_line(lstr));
249 }
250 
251 /*
252  * pick_up:
253  *	Add something to characters pack.
254  */
255 pick_up(ch)
256 byte ch;
257 {
258     register THING *obj;
259 
260     switch (ch)
261     {
262 	case GOLD:
263 	    if ((obj = find_obj(hero.y, hero.x)) == NULL)
264 		return;
265 	    money(obj->o_goldval);
266 	    detach(lvl_obj, obj);
267 	    discard(obj);
268 	    proom->r_goldval = 0;
269 	    break;
270 	default:
271 	case ARMOR:
272 	case POTION:
273 	case FOOD:
274 	case WEAPON:
275 	case SCROLL:	
276 	case AMULET:
277 	case RING:
278 	case STICK:
279 	    add_pack(NULL, FALSE);
280 	    break;
281     }
282 }
283 
284 /*
285  * get_item:
286  *	Pick something out of a pack for a purpose
287  */
288 THING *
289 get_item(purpose, type)
290 char *purpose;
291 int type;
292 {
293     register THING *obj;
294     register byte ch;
295 	byte och;
296     static byte lch;
297 	static THING *wasthing = NULL;
298     byte gi_state;	/* get item sub state */
299     int once_only = FALSE;
300 
301 	if (((!strncmp(s_menu,"sel",3) && strcmp(purpose,"eat") 
302 		 && strcmp(purpose,"drop"))) || !strcmp(s_menu,"on"))
303 			once_only = TRUE;
304 
305     gi_state = again;
306     if (pack == NULL)
307 		msg("you aren't carrying anything");
308     else {
309         ch = lch;
310 		for (;;) {
311 		    /*
312 		     * if we are doing something AGAIN, and the pack hasn't
313 		     * changed then don't ask just give him the same thing
314 		     * he got on the last command.
315 		     */
316 		    if (gi_state && wasthing == pack_obj(ch, &och))
317 		        goto skip;
318 		    if (once_only) {
319 		    	ch = '*';
320 		    	goto skip;
321 		    }
322 		    if (!terse && !expert)
323 				addmsg("which object do you want to ");
324 		    msg("%s? (* for list): ",purpose);
325 		    /*
326 		     * ignore any alt characters that may be typed
327 		     */
328 		    ch = readchar();
329 		    skip:
330 		    mpos = 0;
331 		    gi_state = FALSE;
332     	    once_only = FALSE;
333 		    if (ch == '*') {
334 				if ((ch = inventory(pack, type, purpose)) == 0) {
335 				    after = FALSE;
336 				    return NULL;
337 				}
338 				if (ch == ' ')
339 				    continue;
340 				lch = ch;
341 		    }
342 		    /*
343 		     * Give the poor player a chance to abort the command
344 		     */
345 		    if (ch == ESCAPE) {
346 				after = FALSE;
347 				msg("");
348 				return NULL;
349 		    }
350 		    if ((obj = pack_obj(ch, &och)) == NULL) {
351 				ifterse1("range is 'a' to '%c'","please specify a letter between 'a' and '%c'", och-1);
352 				continue;
353 		    } else {
354 		        /*
355 		         * If you find an object reset flag because
356 		         * you really don't know if the object he is getting
357 		         * is going to change the pack.  If he detaches the
358 		         * thing from the pack later this flag will get set.
359 		         */
360 				if (strcmp(purpose, "identify")) {
361 				    lch = ch;
362 					wasthing = obj;
363 				}
364 				return obj;
365 		   }
366 		}
367     }
368     return NULL;
369 }
370 
371 /*
372  * pack_char:
373  *	Return which character would address a pack object
374  */
375 pack_char(obj)
376 register THING *obj;
377 {
378     register THING *item;
379     register byte c;
380 
381     c = 'a';
382     for (item = pack; item != NULL; item = next(item))
383 	if (item == obj)
384 	    return c;
385 	else
386 	    c++;
387     return '?';
388 }
389 
390 /*
391  * money:
392  *	Add or subtract gold from the pack
393  */
394 money(value)
395 register int value;
396 {
397     register byte floor;
398 
399     floor = (proom->r_flags & ISGONE) ? PASSAGE : FLOOR;
400     purse += value;
401     mvaddch(hero.y, hero.x, floor);
402     chat(hero.y, hero.x) = floor;
403     if (value > 0)
404     {
405 	msg("you found %d gold pieces", value);
406     }
407 }
408 