comparison urogue/pack.c @ 256:c495a4f288c6

Import UltraRogue from the Roguelike Restoration Project (r1490)
author John "Elwin" Edwards
date Tue, 31 Jan 2017 19:56:04 -0500
parents
children 74351bf23e5e
comparison
equal deleted inserted replaced
253:d9badb9c0179 256:c495a4f288c6
1 /*
2 pack.c - Routines to deal with the pack.
3
4 UltraRogue: The Ultimate Adventure in the Dungeons of Doom
5 Copyright (C) 1985, 1986, 1992, 1993, 1995 Herb Chong
6 All rights reserved.
7
8 Based on "Advanced Rogue"
9 Copyright (C) 1984, 1985 Michael Morgan, Ken Dalka
10 All rights reserved.
11
12 Based on "Rogue: Exploring the Dungeons of Doom"
13 Copyright (C) 1980, 1981 Michael Toy, Ken Arnold and Glenn Wichman
14 All rights reserved.
15
16 See the file LICENSE.TXT for full copyright and licensing information.
17 */
18
19 /*
20 Notes
21
22 The new pack is implemented through the use of bags,
23 and items are classed by their types (see rogue.h) which also
24 happen to be their display character.
25 */
26
27 #include <stdlib.h>
28 #include <ctype.h>
29 #include "rogue.h"
30
31 #define ESCAPE_EXIT(x) if (x == ESCAPE) {after = FALSE; msg(""); return(NULL);}
32 #define BAD_NEWS -1
33 #define BAD_LIST ((struct linked_list *) BAD_NEWS)
34 #define GOOD_NEWS 0
35
36 static char type_list[] = "!?])/=:,"; /* things to inventory */
37
38 /*
39 swap_top()
40 Takes an stacked object and exchanges places with the top
41 object. <node> must belong to the <top>'s stacked object list.
42 */
43
44 void
45 swap_top(struct linked_list *top, struct linked_list *node)
46 {
47 struct object *obt, *obn;
48
49 obt = OBJPTR(top);
50 obn = OBJPTR(node);
51
52 detach((obt->next_obj), node); /* Take it out of the stack */
53 attach(lvl_obj, node); /* and put it into the level */
54 detach(lvl_obj, top); /* Remove item from level */
55
56 obn->next_obj = obt->next_obj;
57
58 if (obn->next_obj)
59 obn->next_obj->l_prev = NULL;
60
61 attach((obn->next_obj), top);
62 }
63
64
65 /*
66 get_all()
67 Get as many stacked items as possible.
68 */
69
70 void
71 get_all(struct linked_list *top)
72 {
73 struct linked_list *node;
74 struct object *obt;
75
76 while (top)
77 {
78 obt = OBJPTR(top);
79 node = obt->next_obj;
80
81 rem_obj(top, FALSE);
82
83 if (!add_pack(top, FALSE))
84 return;
85
86 top = node;
87 }
88 }
89
90
91 /*
92 get_stack()
93 Allows the user to chose from a stack of items.
94 */
95
96 struct linked_list *
97 get_stack(struct linked_list *item)
98 {
99 struct object *obj;
100 char buf[2 * LINELEN];
101 int i = 0, j;
102 struct linked_list *ll;
103 mpos = 0;
104 obj = OBJPTR(item);
105
106 ll = obj->next_obj;
107
108 sprintf(buf, "You are standing on top of the following items: ");
109 add_line(buf);
110 sprintf(buf, "%d) -- %s", i, inv_name(obj, TRUE));
111 add_line(buf);
112
113 while (ll)
114 {
115 i++;
116 obj = OBJPTR(ll);
117 sprintf(buf, "%d) -- %s", i, inv_name(obj, TRUE));
118 add_line(buf);
119 ll = next(ll);
120 }
121
122 end_line();
123
124 msg("Which one do you want to pick up? [* for all] ");
125
126 switch(get_string(buf, cw))
127 {
128 case NORM:
129 break;
130 case QUIT: /* pick up nothing */
131 msg("");
132 return (NULL);
133 }
134
135 if (buf[0] == '*')
136 {
137 get_all(item);
138 msg("");
139 return(NULL);
140 }
141 else
142 {
143 i = atoi(buf);
144
145 if (i)
146 {
147 obj = OBJPTR(item);
148 ll = obj->next_obj;
149 j = 1;
150
151 while (ll && (j != i))
152 {
153 ll = next(ll);
154 j++;
155 }
156
157 if (ll)
158 {
159 swap_top(item, ll);
160 return(ll);
161 }
162 else
163 {
164 debug("Got past last item while picking up.");
165 return(item);
166 }
167 }
168 else
169 return (item);
170 }
171 }
172
173 /*
174 add_pack()
175 Pick up an object and add it to the pack. If the argument is
176 non-null use it as the linked_list pointer instead of getting it off the
177 ground.
178 */
179
180 int
181 add_pack(struct linked_list *item, int print_message)
182 {
183 struct object *obj, *op;
184 int from_floor;
185
186 if (item == NULL)
187 {
188 from_floor = TRUE;
189
190 if ((item = find_obj(hero.y, hero.x)) == NULL)
191 {
192 msg("Nothing to pick up.");
193 return(FALSE);
194 }
195 }
196 else
197 from_floor = FALSE;
198
199 if (from_floor)
200 {
201 item = get_stack(item);
202
203 if (!item)
204 return(FALSE);
205 }
206
207 obj = OBJPTR(item);
208
209 /* If it is gold, just add its value to rogue's purse and get rid of */
210
211 if (obj->o_type == GOLD)
212 {
213 struct linked_list *mitem;
214 struct thing *tp;
215
216 if (print_message)
217 {
218 if (!terse)
219 addmsg("You found ");
220
221 msg("%d gold pieces.", obj->o_count);
222 }
223
224 /*
225 * First make sure no greedy monster is after this gold. If
226 * so, make the monster run after the rogue instead.
227 */
228
229 for (mitem = mlist; mitem != NULL; mitem = next(mitem))
230 {
231 tp = THINGPTR(mitem);
232
233 if (tp->t_horde==obj)
234 {
235 tp->t_ischasing = TRUE;
236 tp->t_chasee = &player;
237 tp->t_horde = NULL;
238 }
239 }
240
241 /*
242 * This will cause problems if people are able to drop and
243 * pick up gold, or when GOLDSTEAL monsters are killed.
244 */
245
246 /* Thieves get EXP for gold they pick up */
247
248 if (player.t_ctype == C_THIEF)
249 {
250 pstats.s_exp += obj->o_count / 4;
251 check_level();
252 }
253
254 purse += obj->o_count;
255
256 if (from_floor)
257 rem_obj(item, TRUE); /* Remove object from the level */
258
259 return (TRUE);
260 }
261
262 /* see if he can carry any more weight */
263
264 if (itemweight(obj) + pstats.s_pack > pstats.s_carry)
265 {
266 msg("Too much for you to carry.");
267
268 if (print_message)
269 {
270 msg("%s onto %s", terse ? "Moved" : "You moved",
271 inv_name(obj, LOWERCASE));
272 }
273
274 return(FALSE);
275 }
276
277 /*
278 * Link it into the pack. If the item can be grouped, try to find its
279 * neighbors and bump the count. A special case is food, which can't
280 * be grouped, but an exact match allows the count to get
281 * incremented.
282 */
283
284 if ((op = apply_to_bag(pack, obj->o_type, bff_group, NULL, obj)) != NULL)
285 {
286 op->o_count += obj->o_count; /* add it to the rest */
287
288 if (from_floor)
289 rem_obj(item, FALSE);
290
291 pack_report(op, print_message, "You now have ");
292
293 return(TRUE);
294 }
295
296 /* Check for and deal with scare monster scrolls */
297
298 if (obj->o_type == SCROLL && obj->o_which == S_SCARE)
299 if (obj->o_flags & ISCURSED)
300 {
301 msg("The scroll turns to dust as you pick it up.");
302 rem_obj(item, TRUE);
303 return(TRUE);
304 }
305
306 /* Check if there is room */
307
308 if (count_bag(pack, obj->o_type, NULL) == max_print())
309 {
310 msg("You have no room for more %s.", name_type(obj->o_type));
311
312 if (print_message)
313 {
314 obj = OBJPTR(item);
315 msg("%s onto %s.", terse ? "Moved" : "You moved",
316 inv_name(obj, LOWERCASE));
317 }
318
319 return(FALSE);
320 }
321
322 /*
323 * finally, add the new item to the bag, and free up the linked list
324 * on top of it.
325 */
326
327 if (from_floor)
328 rem_obj(item, FALSE);
329
330 push_bag(&pack, obj);
331 pack_report(obj, print_message, "You now have ");
332 ur_free(item);
333
334 return(TRUE); /* signal success */
335 }
336
337 /*
338 pack_report()
339 Notify the user about the results of the pack operation and do some
340 post processing.
341 */
342
343 void
344 pack_report(object *obj, int print_message, char *message)
345 {
346 /* Notify the user */
347
348 if (print_message)
349 {
350 if (!terse)
351 addmsg(message);
352
353 msg("(%c%c) %s.", obj->o_type, print_letters[get_ident(obj)],
354 inv_name(obj, !terse));
355 }
356
357 if (obj->o_type == ARTIFACT)
358 {
359 has_artifact |= (1 << obj->o_which);
360 picked_artifact |= (1 << obj->o_which);
361
362 if (!(obj->ar_flags & ISUSED))
363 {
364 obj->ar_flags |= ISUSED;
365 pstats.s_exp += arts[obj->o_which].ar_worth / 10;
366 check_level();
367 }
368 }
369
370 updpack();
371
372 return;
373 }
374
375 /*
376 inventory()
377 list what is in the pack
378 */
379
380 void
381 inventory(struct linked_list *container, int type)
382 {
383 int cnt;
384
385 if (type == 0)
386 {
387 msg("What kind of item <%s> to inventory (* for all)?", type_list);
388
389 type = readchar();
390
391 if (type == ESCAPE)
392 {
393 after = FALSE;
394 msg("");
395 return;
396 }
397 }
398
399 /*
400 * Get a list of items to print out. If the user selects '*', list
401 * them all.
402 */
403
404 if (type == '*')
405 type = 0; /* no type passed ->use them all */
406
407 mpos = 0;
408
409 if ((cnt = count_bag(container, type, NULL)) == 0)
410 msg("You don't have any %s.", name_type(type));
411 else
412 {
413 apply_to_bag(container, type, NULL, baf_print_item, &type);
414 end_line();
415 msg("");
416 }
417
418 return;
419 }
420
421 /*
422 pick_up()
423 Add something to characters pack.
424 */
425
426 void
427 pick_up(char ch)
428 {
429 switch(ch)
430 {
431 default:
432 debug("Where did you pick that up???");
433 break;
434
435 case GOLD:
436 case ARMOR:
437 case POTION:
438 case FOOD:
439 case WEAPON:
440 case SCROLL:
441 case ARTIFACT:
442 case RING:
443 case STICK:
444 add_pack(NULL, MESSAGE);
445 break;
446 }
447 }
448
449 /*
450 get_object()
451
452 Pick something out of a pack for a purpose. The basic idea is to
453 list all the possibilities, let the user select one, get that item
454 from the container, and pass it back to the calling routine.
455 */
456
457 struct object *
458 get_object(struct linked_list *container, char *purpose, int type, int (*bff_p)(struct object *obj, bag_arg *junk))
459 /* char *container; what container has what we want */
460 /* char *purpose; a message (verb) to print if we cant find any */
461 /* char type; type (o_type) to pick out (NULL = any) */
462 /* int (*bff_p) (); bag filter function to test item */
463 {
464 struct object *obj_p = NULL;
465 char sel_id; /* selected type and id */
466 int sel_type;
467 char response;
468
469 if (container == NULL)
470 {
471 msg("There isn't anything in there.");
472 after = FALSE;
473 return(NULL);
474 }
475
476 /* Make sure we have at least one item that qualifies! */
477
478 if (apply_to_bag(container, type, bff_p, NULL, NULL) == NULL)
479 {
480 msg("You seem to have nothing to %s.", purpose);
481 after = FALSE;
482 return(NULL);
483 }
484
485 while (obj_p == NULL)
486 {
487 if (type == 0)
488 {
489 msg("What kind of item <%s> do you want to %s (* for list)?", type_list, purpose);
490
491 response = readchar();
492 ESCAPE_EXIT(response);
493 msg("");
494
495 if (response == '*')
496 {
497 add_line("! Potion");
498 add_line("? Scroll");
499 add_line("= Ring");
500 add_line("/ Stick");
501 add_line("] Armor");
502 add_line(") Weapon");
503 add_line(": Food");
504 end_line();
505 continue;
506 }
507
508
509 if (!is_member(type_list, response)) { beep();
510 continue; }
511
512
513 if (count_bag(container, response, NULL) == 0)
514 {
515 msg("You don't have any %s.", name_type(response));
516 continue;
517 }
518
519 type = response;
520 }
521
522 while(obj_p == NULL)
523 {
524 msg("What item do you want to %s (* for list)?", purpose);
525 response = readchar();
526 msg("");
527 ESCAPE_EXIT(response);
528
529 if (response == '*')
530 {
531 mpos = 0;
532 apply_to_bag(container, type, bff_p, baf_print_item, &type);
533 end_line();
534 continue;
535 }
536
537 sel_type = type;
538 sel_id = response;
539
540 obj_p = scan_bag(container, sel_type,unprint_id(&sel_id));
541 }
542 }
543
544 mpos = 0;
545 msg("");
546 return(obj_p);
547 }
548
549 /*
550 get_item()
551
552 This is only an interim function that serves as an interface to
553 the old function get_item and its replacement get_object. It
554 assumes a NULL action routine and allocates a linked_list
555 structure on top of the object pointer.
556 */
557
558 struct linked_list *
559 get_item(char *purpose, int type)
560 {
561 struct object *obj_p;
562
563 if ((obj_p = get_object(pack, purpose, type, NULL)) == NULL)
564 return(NULL);
565
566 return(make_item(obj_p));
567 }
568
569 /*
570 del_pack()
571 Take something out of the hero's pack and throw it away.
572 */
573
574 void
575 del_pack(struct linked_list *what)
576 {
577 rem_pack(OBJPTR(what));
578 discard(what);
579 }
580
581 /*
582 discard_pack
583 take an object from the pack and throw it away (like del_pack,
584 but without the linked_list structure)
585 */
586
587 void
588 discard_pack(struct object *obj_p)
589 {
590 rem_pack(obj_p);
591 throw_away(obj_p);
592 }
593
594 /*
595 rem_pack()
596 Removes an item from the pack.
597 */
598
599 void
600 rem_pack(struct object *obj_p)
601 {
602 cur_null(obj_p); /* check for current stuff */
603 pop_bag(&pack, obj_p);
604 updpack();
605 return; /* tell caller an item has been removed */
606 }
607
608 /*
609 cur_null()
610 This updates cur_weapon etc for dropping things
611 */
612
613 void
614 cur_null(struct object *op)
615 {
616 if (op == cur_weapon)
617 cur_weapon = NULL;
618 else if (op == cur_armor)
619 cur_armor = NULL;
620 else if (op == cur_ring[LEFT_1])
621 cur_ring[LEFT_1] = NULL;
622 else if (op == cur_ring[LEFT_2])
623 cur_ring[LEFT_2] = NULL;
624 else if (op == cur_ring[LEFT_3])
625 cur_ring[LEFT_3] = NULL;
626 else if (op == cur_ring[LEFT_4])
627 cur_ring[LEFT_4] = NULL;
628 else if (op == cur_ring[LEFT_5])
629 cur_ring[LEFT_5] = NULL;
630 else if (op == cur_ring[RIGHT_1])
631 cur_ring[RIGHT_1] = NULL;
632 else if (op == cur_ring[RIGHT_2])
633 cur_ring[RIGHT_2] = NULL;
634 else if (op == cur_ring[RIGHT_3])
635 cur_ring[RIGHT_3] = NULL;
636 else if (op == cur_ring[RIGHT_4])
637 cur_ring[RIGHT_4] = NULL;
638 else if (op == cur_ring[RIGHT_5])
639 cur_ring[RIGHT_5] = NULL;
640 }
641
642 /*
643 idenpack()
644 Identify all the items in the pack
645 */
646
647 void
648 idenpack(void)
649 {
650 apply_to_bag(pack, 0, NULL, baf_identify, NULL);
651 }
652
653 /*
654 show_floor()
655 Print out the item on the floor. Used by the move command.
656 */
657
658 void
659 show_floor(void)
660 {
661 struct linked_list *item;
662 struct object *obj;
663
664 item = find_obj(hero.y, hero.x);
665
666 if (item != NULL)
667 {
668 addmsg("%s onto ", terse ? "Moved" : "You moved");
669
670 obj = OBJPTR(item);
671
672 if (obj->next_obj != NULL)
673 msg("a stack of things.");
674 else if (obj->o_type == GOLD)
675 msg("%d gold pieces.", obj->o_count);
676 else
677 {
678 addmsg(inv_name(obj, TRUE));
679 addmsg(".");
680 endmsg();
681 }
682 }
683 }