Use ^ rather than & so the player can't be generated 'too boring' for any monster...
[rogue-pphs.git] / pack.c
1 /*
2 * Routines to deal with the pack
3 *
4 * @(#)pack.c 3.6 (Berkeley) 6/15/81
5 *
6 * Rogue: Exploring the Dungeons of Doom
7 * Copyright (C) 1980, 1981 Michael Toy, Ken Arnold and Glenn Wichman
8 * All rights reserved.
9 *
10 * See the file LICENSE.TXT for full copyright and licensing information.
11 */
12
13 #include "curses.h"
14 #include <ctype.h>
15 #include "rogue.h"
16
17 /*
18 * add_pack:
19 * Pick up an object and add it to the pack. If the argument is non-null
20 * use it as the linked_list pointer instead of gettting it off the ground.
21 */
22 add_pack(item, silent)
23 register struct linked_list *item;
24 bool silent;
25 {
26 register struct linked_list *ip, *lp;
27 register struct object *obj, *op;
28 register bool exact, from_floor;
29
30 if (item == NULL)
31 {
32 from_floor = TRUE;
33 if ((item = find_obj(hero.y, hero.x)) == NULL)
34 return;
35 }
36 else
37 from_floor = FALSE;
38 obj = (struct object *) ldata(item);
39 /*
40 * Link it into the pack. Search the pack for a object of similar type
41 * if there isn't one, stuff it at the beginning, if there is, look for one
42 * that is exactly the same and just increment the count if there is.
43 * it that. Food is always put at the beginning for ease of access, but
44 * is not ordered so that you can't tell good food from bad. First check
45 * to see if there is something in thr same group and if there is then
46 * increment the count.
47 */
48 if (obj->o_group)
49 {
50 for (ip = pack; ip != NULL; ip = next(ip))
51 {
52 op = (struct object *) ldata(ip);
53 if (op->o_group == obj->o_group)
54 {
55 /*
56 * Put it in the pack and notify the user
57 */
58 op->o_count++;
59 if (from_floor)
60 {
61 detach(lvl_obj, item);
62 mvaddch(hero.y, hero.x,
63 (roomin(&hero) == NULL ? PASSAGE : FLOOR));
64 }
65 discard(item);
66 item = ip;
67 goto picked_up;
68 }
69 }
70 }
71 /*
72 * Check if there is room
73 */
74 if (inpack == MAXPACK-1)
75 {
76 msg("You can't carry anything else.");
77 return;
78 }
79 /*
80 * Check for and deal with scare monster scrolls
81 */
82 if (obj->o_type == SCROLL && obj->o_which == S_SCARE)
83 if (obj->o_flags & ISFOUND)
84 {
85 msg("The scroll turns to dust as you pick it up.");
86 detach(lvl_obj, item);
87 mvaddch(hero.y, hero.x, FLOOR);
88 return;
89 }
90 else
91 obj->o_flags |= ISFOUND;
92
93 inpack++;
94 if (from_floor)
95 {
96 detach(lvl_obj, item);
97 mvaddch(hero.y, hero.x, (roomin(&hero) == NULL ? PASSAGE : FLOOR));
98 }
99 /*
100 * Search for an object of the same type
101 */
102 exact = FALSE;
103 for (ip = pack; ip != NULL; ip = next(ip))
104 {
105 op = (struct object *) ldata(ip);
106 if (obj->o_type == op->o_type)
107 break;
108 }
109 if (ip == NULL)
110 {
111 /*
112 * Put it at the end of the pack since it is a new type
113 */
114 for (ip = pack; ip != NULL; ip = next(ip))
115 {
116 op = (struct object *) ldata(ip);
117 if (op->o_type != FOOD)
118 break;
119 lp = ip;
120 }
121 }
122 else
123 {
124 /*
125 * Search for an object which is exactly the same
126 */
127 while (ip != NULL && op->o_type == obj->o_type)
128 {
129 if (op->o_which == obj->o_which)
130 {
131 exact = TRUE;
132 break;
133 }
134 lp = ip;
135 if ((ip = next(ip)) == NULL)
136 break;
137 op = (struct object *) ldata(ip);
138 }
139 }
140 if (ip == NULL)
141 {
142 /*
143 * Didn't find an exact match, just stick it here
144 */
145 if (pack == NULL)
146 pack = item;
147 else
148 {
149 lp->l_next = item;
150 item->l_prev = lp;
151 item->l_next = NULL;
152 }
153 }
154 else
155 {
156 /*
157 * If we found an exact match. If it is a potion, food, or a
158 * scroll, increase the count, otherwise put it with its clones.
159 */
160 if (exact && ISMULT(obj->o_type))
161 {
162 op->o_count++;
163 discard(item);
164 item = ip;
165 goto picked_up;
166 }
167 if ((item->l_prev = prev(ip)) != NULL)
168 item->l_prev->l_next = item;
169 else
170 pack = item;
171 item->l_next = ip;
172 ip->l_prev = item;
173 }
174 picked_up:
175 /*
176 * Notify the user
177 */
178 obj = (struct object *) ldata(item);
179 if (notify && !silent)
180 {
181 if (!terse)
182 addmsg("You now have ");
183 msg("%s (%c)", inv_name(obj, !terse), pack_char(obj));
184 }
185 if (obj->o_type == AMULET)
186 amulet = TRUE;
187 }
188
189 /*
190 * inventory:
191 * list what is in the pack
192 */
193 inventory(list, type)
194 struct linked_list *list;
195 int type;
196 {
197 register struct object *obj;
198 register char ch;
199 register int n_objs;
200 char inv_temp[80];
201
202 n_objs = 0;
203 for (ch = 'a'; list != NULL; ch++, list = next(list))
204 {
205 obj = (struct object *) ldata(list);
206 if (type && type != obj->o_type && !(type == CALLABLE &&
207 (obj->o_type == SCROLL || obj->o_type == POTION ||
208 obj->o_type == RING || obj->o_type == STICK)))
209 continue;
210 switch (n_objs++)
211 {
212 /*
213 * For the first thing in the inventory, just save the string
214 * in case there is only one.
215 */
216 case 0:
217 sprintf(inv_temp, "%c) %s", ch, inv_name(obj, FALSE));
218 break;
219 /*
220 * If there is more than one, clear the screen, print the
221 * saved message and fall through to ...
222 */
223 case 1:
224 if (slow_invent)
225 msg(inv_temp);
226 else
227 {
228 wclear(hw);
229 waddstr(hw, inv_temp);
230 waddch(hw, '\n');
231 }
232 /*
233 * Print the line for this object
234 */
235 default:
236 if (slow_invent)
237 msg("%c) %s", ch, inv_name(obj, FALSE));
238 else
239 wprintw(hw, "%c) %s\n", ch, inv_name(obj, FALSE));
240 }
241 }
242 if (n_objs == 0)
243 {
244 if (terse)
245 msg(type == 0 ? "Empty handed." :
246 "Nothing appropriate");
247 else
248 msg(type == 0 ? "You are empty handed." :
249 "You don't have anything appropriate");
250 return FALSE;
251 }
252 if (n_objs == 1)
253 {
254 msg(inv_temp);
255 return TRUE;
256 }
257 if (!slow_invent)
258 {
259 mvwaddstr(hw, LINES-1, 0, "--Press space to continue--");
260 draw(hw);
261 wait_for(hw,' ');
262 clearok(cw, TRUE);
263 touchwin(cw);
264 }
265 return TRUE;
266 }
267
268 /*
269 * pick_up:
270 * Add something to characters pack.
271 */
272 pick_up(ch)
273 char ch;
274 {
275 switch(ch)
276 {
277 case GOLD:
278 money();
279 break;
280 default:
281 debug("Where did you pick that up???");
282 case ARMOR:
283 case POTION:
284 case FOOD:
285 case WEAPON:
286 case SCROLL:
287 case AMULET:
288 case RING:
289 case STICK:
290 add_pack(NULL, FALSE);
291 break;
292 }
293 }
294
295 /*
296 * picky_inven:
297 * Allow player to inventory a single item
298 */
299 picky_inven()
300 {
301 register struct linked_list *item;
302 register char ch, mch;
303
304 if (pack == NULL)
305 msg("You aren't carrying anything");
306 else if (next(pack) == NULL)
307 msg("a) %s", inv_name((struct object *) ldata(pack), FALSE));
308 else
309 {
310 msg(terse ? "Item: " : "Which item do you wish to inventory: ");
311 mpos = 0;
312 if ((mch = readchar(cw)) == ESCAPE)
313 {
314 msg("");
315 return;
316 }
317 for (ch = 'a', item = pack; item != NULL; item = next(item), ch++)
318 if (ch == mch)
319 {
320 msg("%c) %s",ch,inv_name((struct object *) ldata(item), FALSE));
321 return;
322 }
323 if (!terse)
324 msg("'%s' not in pack", unctrl(mch));
325 msg("Range is 'a' to '%c'", --ch);
326 }
327 }
328
329 /*
330 * get_item:
331 * pick something out of a pack for a purpose
332 */
333 struct linked_list *
334 get_item(purpose, type)
335 char *purpose;
336 int type;
337 {
338 register struct linked_list *obj;
339 register char ch, och;
340
341 if (pack == NULL)
342 msg("You aren't carrying anything.");
343 else
344 {
345 for (;;)
346 {
347 if (!terse)
348 addmsg("Which object do you want to ");
349 addmsg(purpose);
350 if (terse)
351 addmsg(" what");
352 msg("? (* for list): ");
353 ch = readchar(cw);
354 mpos = 0;
355 /*
356 * Give the poor player a chance to abort the command
357 */
358 if (ch == ESCAPE || ch == CTRL('G'))
359 {
360 after = FALSE;
361 msg("");
362 return NULL;
363 }
364 if (ch == '*')
365 {
366 mpos = 0;
367 if (inventory(pack, type) == 0)
368 {
369 after = FALSE;
370 return NULL;
371 }
372 continue;
373 }
374 for (obj = pack, och = 'a'; obj != NULL; obj = next(obj), och++)
375 if (ch == och)
376 break;
377 if (obj == NULL)
378 {
379 msg("Please specify a letter between 'a' and '%c'", och-1);
380 continue;
381 }
382 else
383 return obj;
384 }
385 }
386 return NULL;
387 }
388
389 pack_char(obj)
390 register struct object *obj;
391 {
392 register struct linked_list *item;
393 register char c;
394
395 c = 'a';
396 for (item = pack; item != NULL; item = next(item))
397 if ((struct object *) ldata(item) == obj)
398 return c;
399 else
400 c++;
401 return 'z';
402 }