root/trunk/src/cmd1.c

Revision 918, 16.3 kB (checked in by takkaria, 3 months ago)

Use consistent newlines everywhere, and also set the svn:eol-style property to native on all text files.

  • Property svn:eol-style set to native
Line 
1 /*
2  * File: cmd1.c
3  * Purpose: Searching, movement, and pickup
4  *
5  * Copyright (c) 1997 Ben Harrison, James E. Wilson, Robert A. Koeneke,
6  * Copyright (c) 2007 Leon Marrick
7  *
8  * This work is free software; you can redistribute it and/or modify it
9  * under the terms of either:
10  *
11  * a) the GNU General Public License as published by the Free Software
12  *    Foundation, version 2, or
13  *
14  * b) the "Angband licence":
15  *    This software may be copied and distributed for educational, research,
16  *    and not for profit purposes provided that this copyright and statement
17  *    are included in all such copies.  Other copyrights may also apply.
18  */
19 #include "angband.h"
20 #include "tvalsval.h"
21 #include "cmds.h"
22
23
24
25
26 /*
27  * Search for hidden things
28  */
29 void search(void)
30 {
31         int py = p_ptr->py;
32         int px = p_ptr->px;
33
34         int y, x, chance;
35
36         object_type *o_ptr;
37
38
39         /* Start with base search ability */
40         chance = p_ptr->skills[SKILL_SEARCH];
41
42         /* Penalize various conditions */
43         if (p_ptr->timed[TMD_BLIND] || no_lite()) chance = chance / 10;
44         if (p_ptr->timed[TMD_CONFUSED] || p_ptr->timed[TMD_IMAGE]) chance = chance / 10;
45
46         /* Search the nearby grids, which are always in bounds */
47         for (y = (py - 1); y <= (py + 1); y++)
48         {
49                 for (x = (px - 1); x <= (px + 1); x++)
50                 {
51                         /* Sometimes, notice things */
52                         if (randint0(100) < chance)
53                         {
54                                 /* Invisible trap */
55                                 if (cave_feat[y][x] == FEAT_INVIS)
56                                 {
57                                         /* Pick a trap */
58                                         pick_trap(y, x);
59
60                                         /* Message */
61                                         msg_print("You have found a trap.");
62
63                                         /* Disturb */
64                                         disturb(0, 0);
65                                 }
66
67                                 /* Secret door */
68                                 if (cave_feat[y][x] == FEAT_SECRET)
69                                 {
70                                         /* Message */
71                                         msg_print("You have found a secret door.");
72
73                                         /* Pick a door */
74                                         place_closed_door(y, x);
75
76                                         /* Disturb */
77                                         disturb(0, 0);
78                                 }
79
80                                 /* Scan all objects in the grid */
81                                 for (o_ptr = get_first_object(y, x); o_ptr; o_ptr = get_next_object(o_ptr))
82                                 {
83                                         /* Skip non-chests */
84                                         if (o_ptr->tval != TV_CHEST) continue;
85
86                                         /* Skip disarmed chests */
87                                         if (o_ptr->pval <= 0) continue;
88
89                                         /* Skip non-trapped chests */
90                                         if (!chest_traps[o_ptr->pval]) continue;
91
92                                         /* Identify once */
93                                         if (!object_known_p(o_ptr))
94                                         {
95                                                 /* Message */
96                                                 msg_print("You have discovered a trap on the chest!");
97
98                                                 /* Know the trap */
99                                                 object_known(o_ptr);
100
101                                                 /* Notice it */
102                                                 disturb(0, 0);
103                                         }
104                                 }
105                         }
106                 }
107         }
108 }
109
110
111 /*** Pickup ***/
112
113 /*
114  * Pickup all gold at the player's current location.
115  */
116 static void py_pickup_gold(void)
117 {
118         int py = p_ptr->py;
119         int px = p_ptr->px;
120
121         s32b total_gold = 0L;
122         byte *treasure;
123
124         s16b this_o_idx, next_o_idx = 0;
125
126         object_type *o_ptr;
127
128         int sound_msg;
129
130         /* Allocate an array of ordinary gold objects */
131         treasure = C_ZNEW(SV_GOLD_MAX, byte);
132
133
134         /* Pick up all the ordinary gold objects */
135         for (this_o_idx = cave_o_idx[py][px]; this_o_idx; this_o_idx = next_o_idx)
136         {
137                 /* Get the object */
138                 o_ptr = &o_list[this_o_idx];
139
140                 /* Get the next object */
141                 next_o_idx = o_ptr->next_o_idx;
142
143                 /* Ignore if not legal treasure */
144                 if ((o_ptr->tval != TV_GOLD) ||
145                     (o_ptr->sval >= SV_GOLD_MAX)) continue;
146
147                 /* Note that we have this kind of treasure */
148                 treasure[o_ptr->sval]++;
149
150                 /* Increment total value */
151                 total_gold += (s32b)o_ptr->pval;
152
153                 /* Delete the gold */
154                 delete_object_idx(this_o_idx);
155         }
156
157         /* Pick up the gold, if present */
158         if (total_gold)
159         {
160                 char buf[1024];
161                 char tmp[80];
162                 int i, count, total, k_idx;
163
164                 /* Build a message */
165                 (void)strnfmt(buf, sizeof(buf), "You have found %ld gold pieces worth of ",  total_gold);
166
167                 /* Count the types of treasure present */
168                 for (total = 0, i = 0; i < SV_GOLD_MAX; i++)
169                 {
170                         if (treasure[i]) total++;
171                 }
172
173                 /* List the treasure types */
174                 for (count = 0, i = 0; i < SV_GOLD_MAX; i++)
175                 {
176                         /* Skip if no treasure of this type */
177                         if (!treasure[i]) continue;
178
179                         /* Get this object index */
180                         k_idx = lookup_kind(TV_GOLD, i);
181
182                         /* Skip past errors  XXX */
183                         if (k_idx <= 0) continue;
184
185                         /* Get the object name */
186                         object_kind_name(tmp, sizeof tmp, k_idx, TRUE);
187
188                         /* Build up the pickup string */
189                         my_strcat(buf, tmp, sizeof(buf));
190
191                         /* Added another kind of treasure */
192                         count++;
193
194                         /* Add a comma if necessary */
195                         if ((total > 2) && (count < total)) my_strcat(buf, ",", sizeof(buf));
196
197                         /* Add an "and" if necessary */
198                         if ((total >= 2) && (count == total-1)) my_strcat(buf, " and", sizeof(buf));
199
200                         /* Add a space or period if necessary */
201                         if (count < total) my_strcat(buf, " ", sizeof(buf));
202                         else               my_strcat(buf, ".", sizeof(buf));
203                 }
204
205                 /* Determine which sound to play */
206                 if      (total_gold < 200) sound_msg = MSG_MONEY1;
207                 else if (total_gold < 600) sound_msg = MSG_MONEY2;
208                 else                       sound_msg = MSG_MONEY3;
209
210                 /* Display the message */
211                 message(sound_msg, 0, buf);
212
213                 /* Add gold to purse */
214                 p_ptr->au += total_gold;
215
216                 /* Redraw gold */
217                 p_ptr->redraw |= (PR_GOLD);
218         }
219
220         /* Free the gold array */
221         FREE(treasure);
222 }
223
224
225
226 /*
227  * Determine if the object can be picked up automatically.
228  */
229 static bool auto_pickup_okay(const object_type *o_ptr)
230 {
231         /* Bad wounds prelude autopickup */
232         if (p_ptr->chp < (p_ptr->mhp * op_ptr->hitpoint_warn / 10)) return FALSE;
233
234         if (!inven_carry_okay(o_ptr)) return FALSE;
235
236         if (OPT(pickup_inven) && inven_stack_okay(o_ptr)) return TRUE;
237         if (OPT(pickup_always) || check_for_inscrip(o_ptr, "=g")) return TRUE;
238
239         return FALSE;
240 }
241
242
243 /*
244  * Carry an object and delete it.
245  */
246 static void py_pickup_aux(int o_idx, bool msg)
247 {
248         int slot;
249
250         char o_name[80];
251         object_type *o_ptr = &o_list[o_idx];
252
253         /* Carry the object */
254         slot = inven_carry(o_ptr);
255
256         /* Handle errors (paranoia) */
257         if (slot < 0) return;
258
259         /* Get the new object */
260         o_ptr = &inventory[slot];
261
262         /* Set squelch status */
263         p_ptr->notice |= PN_SQUELCH;
264
265         /* Optionally, display a message */
266         if (msg)
267         {
268                 /* Describe the object */
269                 object_desc(o_name, sizeof(o_name), o_ptr, TRUE, ODESC_FULL);
270
271                 /* Message */
272                 msg_format("You have %s (%c).", o_name, index_to_label(slot));
273         }
274
275         /* Log if picking up an artifact. */
276         if (artifact_p(o_ptr))
277                 history_add_artifact(o_ptr->name1, object_known_p(o_ptr));
278
279         /* Delete the object */
280         delete_object_idx(o_idx);
281 }
282
283
284 /*
285  * Pick up objects and treasure on the floor.  -LM-
286  *
287  * Called with pickup:
288  * 0 to act according to the player's settings
289  * 1 to quickly pickup single objects or present a menu for more
290  * 2 to force a menu for any number of objects
291  *
292  * Scan the list of objects in that floor grid. Pick up gold automatically.
293  * Pick up objects automatically until backpack space is full if
294  * auto-pickup option is on, Otherwise, store objects on
295  * floor in an array, and tally both how many there are and can be picked up.
296  *
297  * If not picking up anything, indicate objects on the floor.  Show more
298  * details if the "pickup_detail" option is set.  Do the same thing if we
299  * don't have room for anything.
300  *
301  * [This paragraph is not true, intentional?]
302  * If we are picking up objects automatically, and have room for at least
303  * one, allow the "pickup_detail" option to display information about objects
304  * and prompt the player.  Otherwise, automatically pick up a single object
305  * or use a menu for more than one.
306  *
307  * Pick up multiple objects using Tim Baker's menu system.   Recursively
308  * call this function (forcing menus for any number of objects) until
309  * objects are gone, backpack is full, or player is satisfied.
310  *
311  * We keep track of number of objects picked up to calculate time spent.
312  * This tally is incremented even for automatic pickup, so we are careful
313  * (in "dungeon.c" and elsewhere) to handle pickup as either a separate
314  * automated move or a no-cost part of the stay still or 'g'et command.
315  *
316  * Note the lack of chance for the character to be disturbed by unmarked
317  * objects.  They are truly "unknown".
318  */
319 byte py_pickup(int pickup)
320 {
321         int py = p_ptr->py;
322         int px = p_ptr->px;
323
324         char o_name[80];
325
326         s16b this_o_idx, next_o_idx = 0;
327
328         object_type *o_ptr;
329
330         /* Objects picked up.  Used to determine time cost of command. */
331         byte objs_picked_up = 0;
332
333         size_t floor_num = 0;
334         int floor_list[MAX_FLOOR_STACK + 1], floor_o_idx = 0;
335
336         int can_pickup = 0;
337         bool call_function_again = FALSE;
338
339         bool blind = ((p_ptr->timed[TMD_BLIND]) || (no_lite()));
340         bool msg = TRUE;
341
342
343         /* Nothing to pick up -- return */
344         if (!cave_o_idx[py][px]) return (0);
345
346
347         /* Always pickup gold, effortlessly */
348         py_pickup_gold();
349
350
351         /* Scan the remaining objects */
352         for (this_o_idx = cave_o_idx[py][px]; this_o_idx; this_o_idx = next_o_idx)
353         {
354                 /* Get the object and the next object */
355                 o_ptr = &o_list[this_o_idx];
356                 next_o_idx = o_ptr->next_o_idx;
357
358                 /* Ignore all hidden objects and non-objects */
359                 if (squelch_hide_item(o_ptr) || !o_ptr->k_idx) continue;
360
361                 /* XXX Hack -- Enforce limit */
362                 if (floor_num >= N_ELEMENTS(floor_list)) break;
363
364
365                 /* Hack -- disturb */
366                 disturb(0, 0);
367
368
369                 /* Automatically pick up items into the backpack */
370                 if (auto_pickup_okay(o_ptr))
371                 {
372                         /* Pick up the object with message */
373                         py_pickup_aux(this_o_idx, TRUE);
374                         objs_picked_up++;
375
376                         continue;
377                 }
378
379
380                 /* Tally objects and store them in an array. */
381
382                 /* Remember this object index */
383                 floor_list[floor_num] = this_o_idx;
384
385                 /* Count non-gold objects that remain on the floor. */
386                 floor_num++;
387
388                 /* Tally objects that can be picked up.*/
389                 if (inven_carry_okay(o_ptr))
390                         can_pickup++;
391         }
392
393         /* There are no objects left */
394         if (!floor_num)
395                 return objs_picked_up;
396
397
398         /* Get hold of the last floor index */
399         floor_o_idx = floor_list[floor_num - 1];
400
401
402
403         /* Mention the objects if player is not picking them up. */
404         if (pickup == 0 || !can_pickup)
405         {
406                 const char *p = "see";
407
408                 /* One object */
409                 if (floor_num == 1)
410                 {
411                         if (!can_pickup)        p = "have no room for";
412                         else if (blind)     p = "feel";
413
414                         /* Get the object */
415                         o_ptr = &o_list[floor_o_idx];
416
417                         /* Describe the object.  Less detail if blind. */
418                         if (blind) object_desc(o_name, sizeof(o_name), o_ptr, TRUE, ODESC_BASE);
419                         else       object_desc(o_name, sizeof(o_name), o_ptr, TRUE, ODESC_FULL);
420
421                         /* Message */
422                         message_flush();
423                         msg_format("You %s %s.", p, o_name);
424                 }
425                 else
426                 {
427                         /* Optionally, display more information about floor items */
428                         if (pickup_detail)
429                         {
430                                 if (!can_pickup)        p = "have no room for the following objects";
431                                 else if (blind)     p = "feel something on the floor";
432
433                                 /* Scan all marked objects in the grid */
434                                 floor_num = scan_floor(floor_list, N_ELEMENTS(floor_list), py, px, 0x03);
435
436                                 /* Save screen */
437                                 screen_save();
438
439                                 /* Display objects on the floor */
440                                 show_floor(floor_list, floor_num, FALSE);
441
442                                 /* Display prompt */
443                                 prt(format("You %s: ", p), 0, 0);
444
445                                 /* Move cursor back to character, if needed */
446                                 if (hilite_player) move_cursor_relative(p_ptr->py, p_ptr->px);
447
448                                 /* Wait for it.  Use key as next command. */
449                                 p_ptr->command_new = inkey();
450
451                                 /* Restore screen */
452                                 screen_load();
453                         }
454
455                         /* Show less detail */
456                         else
457                         {
458                                 message_flush();
459
460                                 if (!can_pickup)
461                                         msg_print("You have no room for any of the items on the floor.");
462                                 else
463                                         msg_format("You %s a pile of %d items.", (blind ? "feel" : "see"), floor_num);
464                         }
465                 }
466
467                 /* Done */
468                 return (objs_picked_up);
469         }
470
471
472         /* We can pick up objects.  Menus are not requested (yet). */
473         if (pickup == 1)
474         {
475                 /* Scan floor (again) */
476                 floor_num = scan_floor(floor_list, N_ELEMENTS(floor_list), py, px, 0x03);
477
478                 /* Use a menu interface for multiple objects, or pickup single objects */
479                 if (floor_num > 1)
480                         pickup = 2;
481                 else
482                         this_o_idx = floor_o_idx;
483         }
484
485
486         /* Display a list if requested. */
487         if (pickup == 2)
488         {
489                 cptr q, s;
490                 int item;
491
492                 /* Restrict the choices */
493                 item_tester_hook = inven_carry_okay;
494
495                 /* Get an object or exit. */
496                 q = "Get which item?";
497                 s = "You see nothing there.";
498                 if (!get_item(&item, q, s, USE_FLOOR))
499                         return (objs_picked_up);
500
501                 this_o_idx = 0 - item;
502                 call_function_again = TRUE;
503
504                 /* With a list, we do not need explicit pickup messages */
505                 msg = FALSE;
506         }
507
508         /* Pick up object, if legal */
509         if (this_o_idx)
510         {
511                 /* Pick up the object */
512                 py_pickup_aux(this_o_idx, msg);
513
514                 /* Indicate an object picked up. */
515                 objs_picked_up = 1;
516         }
517
518         /*
519          * If requested, call this function recursively.  Count objects picked
520          * up.  Force the display of a menu in all cases.
521          */
522         if (call_function_again) objs_picked_up += py_pickup(2);
523
524         /* Indicate how many objects have been picked up. */
525         return (objs_picked_up);
526 }
527
528
529
530 /*
531  * Move player in the given direction.
532  *
533  * This routine should only be called when energy has been expended.
534  *
535  * Note that this routine handles monsters in the destination grid,
536  * and also handles attempting to move into walls/doors/rubble/etc.
537  */
538 void move_player(int dir)
539 {
540         int py = p_ptr->py;
541         int px = p_ptr->px;
542
543         int y, x;
544
545
546         bool old_dtrap, new_dtrap;
547
548
549         /* Find the result of moving */
550         y = py + ddy[dir];
551         x = px + ddx[dir];
552
553
554         /* Hack -- attack monsters */
555         if (cave_m_idx[y][x] > 0)
556         {
557                 /* Attack */
558                 py_attack(y, x);
559         }
560
561         /* Optionally alter known traps/doors on movement */
562         else if (easy_alter &&
563                  (cave_info[y][x] & (CAVE_MARK)) &&
564                  (cave_feat[y][x] >= FEAT_TRAP_HEAD) &&
565                  (cave_feat[y][x] <= FEAT_DOOR_TAIL))
566         {
567                 /*
568                  * There should always be an explicit confirmation made before fiddling
569                  * with traps.  XXX XXX
570                  */
571
572                 /* Auto-repeat if not already repeating */
573                 if (!p_ptr->command_rep && (p_ptr->command_arg <= 0))
574                 {
575                         /* Repeat 99 times */
576                         p_ptr->command_rep = 99;
577
578                         /* Reset the command count */
579                         p_ptr->command_arg = 0;
580                 }
581
582                 /* Alter */
583                 do_cmd_alter();
584         }
585
586         /* Player can not walk through "walls" */
587         else if (!cave_floor_bold(y, x))
588         {
589                 /* Disturb the player */
590                 disturb(0, 0);
591
592                 /* Notice unknown obstacles */
593                 if (!(cave_info[y][x] & (CAVE_MARK)))
594                 {
595                         /* Rubble */
596                         if (cave_feat[y][x] == FEAT_RUBBLE)
597                         {
598                                 message(MSG_HITWALL, 0, "You feel a pile of rubble blocking your way.");
599                                 cave_info[y][x] |= (CAVE_MARK);
600                                 lite_spot(y, x);
601                         }
602
603                         /* Closed door */
604                         else if (cave_feat[y][x] < FEAT_SECRET)
605                         {
606                                 message(MSG_HITWALL, 0, "You feel a door blocking your way.");
607                                 cave_info[y][x] |= (CAVE_MARK);
608                                 lite_spot(y, x);
609                         }
610
611                         /* Wall (or secret door) */
612                         else
613                         {
614                                 message(MSG_HITWALL, 0, "You feel a wall blocking your way.");
615                                 cave_info[y][x] |= (CAVE_MARK);
616                                 lite_spot(y, x);
617                         }
618                 }
619
620                 /* Mention known obstacles */
621                 else
622                 {
623                         /* Rubble */
624                         if (cave_feat[y][x] == FEAT_RUBBLE)
625                         {
626                                 message(MSG_HITWALL, 0, "There is a pile of rubble blocking your way.");
627                         }
628
629                         /* Closed door */
630                         else if (cave_feat[y][x] < FEAT_SECRET)
631                         {
632                                 message(MSG_HITWALL, 0, "There is a door blocking your way.");
633                         }
634
635                         /* Wall (or secret door) */
636                         else
637                         {
638                                 message(MSG_HITWALL, 0, "There is a wall blocking your way.");
639                         }
640                 }
641         }
642
643         /* Normal movement */
644         else
645         {
646                 /* Sound XXX XXX XXX */
647                 /* sound(MSG_WALK); */
648
649                 /* See if trap detection status will change */
650                 old_dtrap = ((cave_info2[py][px] & (CAVE2_DTRAP)) != 0);
651                 new_dtrap = ((cave_info2[y][x] & (CAVE2_DTRAP)) != 0);
652
653                 /* Note the change in the detect status */
654                 if (old_dtrap != new_dtrap) p_ptr->redraw |= (PR_DTRAP);
655
656                 /* Disturb player if the player is about to leave the detect area XXX */
657                 if (disturb_detect && p_ptr->running && old_dtrap && !new_dtrap)
658                 {
659                         /* Disturb the player */
660                         disturb(0, 0);
661
662                         /* Done XXX */
663                         return;
664                 }
665
666                 /* Move player */
667                 monster_swap(py, px, y, x);
668  
669
670
671                 /* New location */
672                 y = py = p_ptr->py;
673                 x = px = p_ptr->px;
674
675
676                 /* Spontaneous Searching */
677                 if ((p_ptr->skills[SKILL_SEARCH_FREQUENCY] >= 50) ||
678                     one_in_(50 - p_ptr->skills[SKILL_SEARCH_FREQUENCY]))
679                 {
680                         search();
681                 }
682
683                 /* Continuous Searching */
684                 if (p_ptr->searching)
685                 {
686                         search();
687                 }
688
689
690                 /* Handle "store doors" */
691                 if ((cave_feat[y][x] >= FEAT_SHOP_HEAD) &&
692                     (cave_feat[y][x] <= FEAT_SHOP_TAIL))
693                 {
694                         /* Disturb */
695                         disturb(0, 0);
696
697                         /* Hack -- Enter store */
698                         p_ptr->command_new = '_';
699                 }
700
701
702                 /* All other grids (including traps) */
703                 else
704                 {
705                         /* Handle objects (later) */
706                         p_ptr->notice |= (PN_PICKUP);
707                 }
708
709
710                 /* Discover invisible traps */
711                 if (cave_feat[y][x] == FEAT_INVIS)
712                 {
713                         /* Disturb */
714                         disturb(0, 0);
715
716                         /* Message */
717                         msg_print("You found a trap!");
718
719                         /* Pick a trap */
720                         pick_trap(y, x);
721
722                         /* Hit the trap */
723                         hit_trap(y, x);
724                 }
725
726                 /* Set off an visible trap */
727                 else if ((cave_feat[y][x] >= FEAT_TRAP_HEAD) &&
728                          (cave_feat[y][x] <= FEAT_TRAP_TAIL))
729                 {
730                         /* Disturb */
731                         disturb(0, 0);
732
733                         /* Hit the trap */
734                         hit_trap(y, x);
735                 }
736         }
737 }
Note: See TracBrowser for help on using the browser.