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