1 /* File: cmd2.c */
2
3 /* Purpose: Movement commands (part 2) */
4
5 /*
6 * Copyright (c) 1989 James E. Wilson, Robert A. Koeneke
7 *
8 * This software may be copied and distributed for educational, research, and
9 * not for profit purposes provided that this copyright and statement are
10 * included in all such copies.
11 */
12
13 #include "mangband.h"
14
15
16
17 /*
18 * Go up one level -RAK-
19 */
do_cmd_go_up(player_type * p_ptr)20 void do_cmd_go_up(player_type *p_ptr)
21 {
22 int Depth = p_ptr->dun_depth;
23
24 cave_type *c_ptr;
25
26 /* Make sure he hasn't just changed depth */
27 if (p_ptr->new_level_flag)
28 return;
29
30 /* Check preventive inscription '^<' */
31 __trap(p_ptr, CPI(p_ptr, '<'));
32
33 /* Player grid */
34 c_ptr = &cave[Depth][p_ptr->py][p_ptr->px];
35
36 /* Verify stairs if not a ghost, or admin wizard */
37 if (!p_ptr->ghost && c_ptr->feat != FEAT_LESS)
38 {
39 msg_print(p_ptr, "I see no up staircase here.");
40 return;
41 }
42 else
43 {
44 if (p_ptr->dun_depth <= 0)
45 {
46 msg_print(p_ptr, "There is nothing above you.");
47 return;
48 }
49 }
50
51 if (cfg_ironman)
52 {
53 /*
54 * Ironmen don't go up
55 */
56 if(!is_dm_p(p_ptr))
57 {
58 msg_print(p_ptr, "Morgoth awaits you in the darkness below.");
59 return;
60 }
61 }
62
63 /* Remove the player from the old location */
64 c_ptr->m_idx = 0;
65
66 /* Show everyone that's he left */
67 everyone_lite_spot(Depth, p_ptr->py, p_ptr->px);
68
69 /* Tell everyone to re-calculate visiblity for this player */
70 update_player(p_ptr);
71
72 /* Forget his lite and viewing area */
73 forget_lite(p_ptr);
74 forget_view(p_ptr);
75
76 /* Hack -- take a turn */
77 p_ptr->energy -= level_speed(p_ptr->dun_depth);
78
79 /* Success */
80 if (c_ptr->feat == FEAT_LESS)
81 {
82 msg_print(p_ptr, "You enter a maze of up staircases.");
83 sound(p_ptr, MSG_STAIRS_UP);
84 p_ptr->new_level_method = LEVEL_UP;
85 }
86 else
87 {
88 msg_print(p_ptr, "You float upwards.");
89 p_ptr->new_level_method = LEVEL_GHOST;
90 }
91
92 /* A player has left this depth */
93 players_on_depth[p_ptr->dun_depth]--;
94
95 /* Go up the stairs */
96 p_ptr->dun_depth--;
97
98 /* And another player has entered this depth */
99 players_on_depth[p_ptr->dun_depth]++;
100
101 p_ptr->new_level_flag = TRUE;
102
103 /* Create a way back */
104 create_down_stair = TRUE;
105 }
106
107
108 /*
109 * Go down one level
110 */
do_cmd_go_down(player_type * p_ptr)111 void do_cmd_go_down(player_type *p_ptr)
112 {
113 int Depth = p_ptr->dun_depth;
114
115 cave_type *c_ptr;
116
117 /* Make sure he hasn't just changed depth */
118 if (p_ptr->new_level_flag)
119 return;
120
121 /* Check preventive inscription '^>' */
122 __trap(p_ptr, CPI(p_ptr, '>'));
123
124 /* Player grid */
125 c_ptr = &cave[Depth][p_ptr->py][p_ptr->px];
126
127 /* Verify stairs */
128 if (!p_ptr->ghost && c_ptr->feat != FEAT_MORE)
129 {
130 msg_print(p_ptr, "I see no down staircase here.");
131 return;
132 }
133 else
134 {
135 /* No ghost diving unless DM or allowed in config */
136 if (p_ptr->ghost && !cfg_ghost_diving && !is_dm_p(p_ptr)) {
137 msg_print(p_ptr, "You seem unable to go down. Try going up.");
138 return;
139 };
140
141 /* Can't go down on a "quest" level */
142 if (is_quest_level(p_ptr, p_ptr->dun_depth)
143 /* Hack -- ..but not in Ironman mode. See #1365 */
144 && !cfg_ironman
145 )
146 {
147 /* Inform */
148 msg_print(p_ptr, "An unvanquished adversary pulls you back, you can descend no further.");
149 return;
150 }
151
152 /* Can't go down in the wilderness */
153 if (p_ptr->dun_depth < 0)
154 {
155 msg_print(p_ptr, "There is nothing below you.");
156 return;
157 }
158
159 /* Verify maximum depth */
160 if (p_ptr->dun_depth >= 127)
161 {
162 msg_print(p_ptr, "You are at the bottom of the dungeon.");
163 return;
164 }
165 }
166
167 /* Remove the player from the old location */
168 c_ptr->m_idx = 0;
169
170 /* Show everyone that's he left */
171 everyone_lite_spot(Depth, p_ptr->py, p_ptr->px);
172
173 /* Tell everyone to re-calculate visiblity for this player */
174 update_player(p_ptr);
175
176 /* Forget his lite and viewing area */
177 forget_lite(p_ptr);
178 forget_view(p_ptr);
179
180 /* Hack -- take a turn */
181 p_ptr->energy -= level_speed(p_ptr->dun_depth);
182
183 /* Success */
184 if (c_ptr->feat == FEAT_MORE)
185 {
186 msg_print(p_ptr, "You enter a maze of down staircases.");
187 sound(p_ptr, MSG_STAIRS_DOWN);
188 p_ptr->new_level_method = LEVEL_DOWN;
189 }
190 else
191 {
192 msg_print(p_ptr, "You float downwards.");
193 p_ptr->new_level_method = LEVEL_GHOST;
194 }
195
196 /* A player has left this depth */
197 players_on_depth[p_ptr->dun_depth]--;
198
199 /* Go down */
200 p_ptr->dun_depth++;
201
202 /* Another player has entered this depth */
203 players_on_depth[p_ptr->dun_depth]++;
204
205 p_ptr->new_level_flag = TRUE;
206
207 /* Create a way back */
208 create_up_stair = TRUE;
209 }
210
211
212
213 /*
214 * Simple command to "search" for one turn
215 */
do_cmd_search(player_type * p_ptr)216 void do_cmd_search(player_type *p_ptr)
217 {
218 /* Allow repeated command */
219 if (p_ptr->command_arg)
220 {
221 /* Set repeat count */
222 /*command_rep = command_arg - 1;*/
223
224 /* Redraw the state */
225 p_ptr->redraw |= (PR_STATE);
226
227 /* Cancel the arg */
228 p_ptr->command_arg = 0;
229 }
230
231 /* Take a turn */
232 p_ptr->energy -= level_speed(p_ptr->dun_depth);
233
234 /* Search */
235 search(p_ptr);
236 }
237
238
239 /*
240 * Hack -- toggle search mode
241 */
do_cmd_toggle_search(player_type * p_ptr)242 void do_cmd_toggle_search(player_type *p_ptr)
243 {
244 /* Stop searching */
245 if (p_ptr->searching)
246 {
247 /* Clear the searching flag */
248 p_ptr->searching = FALSE;
249
250 /* Recalculate bonuses */
251 p_ptr->update |= (PU_BONUS);
252
253 /* Redraw the state */
254 p_ptr->redraw |= (PR_STATE);
255 }
256
257 /* Start searching */
258 else
259 {
260 /* Set the searching flag */
261 p_ptr->searching = TRUE;
262
263 /* Update stuff */
264 p_ptr->update |= (PU_BONUS);
265
266 /* Redraw stuff */
267 p_ptr->redraw |= (PR_STATE | PR_SPEED);
268 }
269 }
270
271
272
273 /*
274 * Allocates objects upon opening a chest -BEN-
275 *
276 * Disperse treasures from the chest "o_ptr", centered at (x,y).
277 *
278 * Small chests often contain "gold", while Large chests always contain
279 * items. Wooden chests contain 2 items, Iron chests contain 4 items,
280 * and Steel chests contain 6 items. The "value" of the items in a
281 * chest is based on the "power" of the chest, which is in turn based
282 * on the level on which the chest is generated.
283 */
chest_death(player_type * p_ptr,int y,int x,object_type * o_ptr)284 static void chest_death(player_type *p_ptr, int y, int x, object_type *o_ptr)
285 {
286 int Depth = p_ptr->dun_depth;
287
288 int i, d, ny, nx;
289 int number, small_;
290
291
292 /* Must be a chest */
293 if (o_ptr->tval != TV_CHEST) return;
294
295 /* Small chests often hold "gold" */
296 small_ = (o_ptr->sval < SV_CHEST_MIN_LARGE);
297
298 /* Determine how much to drop (see above) */
299 number = (o_ptr->sval % SV_CHEST_MIN_LARGE) * 2;
300
301 /* Generate some treasure */
302 if (o_ptr->pval && (number > 0))
303 {
304 /* Drop some objects (non-chests) */
305 for (; number > 0; --number)
306 {
307 /* Try 20 times per item */
308 for (i = 0; i < 20; ++i)
309 {
310 /* Pick a distance */
311 d = ((i + 15) / 15);
312
313 /* Pick a location */
314 scatter(Depth, &ny, &nx, y, x, d, 0);
315
316 /* Must be a clean floor grid */
317 if (!cave_clean_bold(Depth, ny, nx)) continue;
318
319 /* Opening a chest */
320 opening_chest = TRUE;
321
322 /* Determine the "value" of the items */
323 object_level = ABS(o_ptr->pval) + 10;
324
325 /* Small chests often drop gold */
326 if (small_ && (randint0(100) < 75))
327 {
328 place_gold(Depth, ny, nx);
329 }
330
331 /* Otherwise drop an item */
332 else
333 {
334 object_type *j_ptr;
335 j_ptr = place_object(Depth, ny, nx, FALSE, FALSE, 0);
336 if (j_ptr)
337 {
338 j_ptr->origin = ORIGIN_CHEST;
339 j_ptr->origin_depth = o_ptr->origin_depth;
340 }
341 }
342
343 /* Reset the object level */
344 object_level = Depth;
345
346 /* No longer opening a chest */
347 opening_chest = FALSE;
348
349 /* Successful placement */
350 break;
351 }
352 }
353 }
354
355 /* Empty */
356 o_ptr->pval = 0;
357
358 /* Known */
359 object_known(o_ptr);
360 }
361
362
363 /*
364 * Chests have traps too.
365 *
366 * Exploding chest destroys contents (and traps).
367 * Note that the chest itself is never destroyed.
368 */
chest_trap(player_type * p_ptr,int y,int x,object_type * o_ptr)369 static void chest_trap(player_type *p_ptr, int y, int x, object_type *o_ptr)
370 {
371 int i, trap;
372
373
374 /* Only analyze chests */
375 if (o_ptr->tval != TV_CHEST) return;
376
377 /* Ignore disarmed chests */
378 if (o_ptr->pval <= 0) return;
379
380 /* Obtain the traps */
381 trap = chest_traps[o_ptr->pval];
382
383 /* Lose strength */
384 if (trap & CHEST_LOSE_STR)
385 {
386 msg_print(p_ptr, "A small needle has pricked you!");
387 take_hit(p_ptr, damroll(1, 4), "a poison needle");
388 (void)do_dec_stat(p_ptr, A_STR);
389 }
390
391 /* Lose constitution */
392 if (trap & CHEST_LOSE_CON)
393 {
394 msg_print(p_ptr, "A small needle has pricked you!");
395 take_hit(p_ptr, damroll(1, 4), "a poison needle");
396 (void)do_dec_stat(p_ptr, A_CON);
397 }
398
399 /* Poison */
400 if (trap & CHEST_POISON)
401 {
402 msg_print(p_ptr, "A puff of green gas surrounds you!");
403 if (!(p_ptr->resist_pois || p_ptr->oppose_pois))
404 {
405 (void)set_poisoned(p_ptr, p_ptr->poisoned + 10 + randint1(20));
406 }
407 }
408
409 /* Paralyze */
410 if (trap & CHEST_PARALYZE)
411 {
412 msg_print(p_ptr, "A puff of yellow gas surrounds you!");
413 if (!p_ptr->free_act)
414 {
415 (void)set_paralyzed(p_ptr, p_ptr->paralyzed + 10 + randint1(20));
416 }
417 }
418
419 /* Summon monsters */
420 if (trap & CHEST_SUMMON)
421 {
422 int num = 2 + randint1(3);
423 msg_print(p_ptr, "You are enveloped in a cloud of smoke!");
424 sound(p_ptr, MSG_SUM_MONSTER);
425 for (i = 0; i < num; i++)
426 {
427 (void)summon_specific(p_ptr->dun_depth, y, x, p_ptr->dun_depth, 0);
428 }
429 }
430
431 /* Explode */
432 if (trap & CHEST_EXPLODE)
433 {
434 msg_print(p_ptr, "There is a sudden explosion!");
435 msg_print(p_ptr, "Everything inside the chest is destroyed!");
436 o_ptr->pval = 0;
437 take_hit(p_ptr, damroll(5, 8), "an exploding chest");
438 }
439 }
440
441
442 /*
443 * Return the index of a house given an coordinate pair
444 */
pick_house(int Depth,int y,int x)445 int pick_house(int Depth, int y, int x)
446 {
447 int i;
448
449 /* Check each house */
450 for (i = 0; i < num_houses; i++)
451 {
452 /* Check this one */
453 if (houses[i].door_x == x && houses[i].door_y == y && houses[i].depth == Depth)
454 {
455 /* Return */
456 return i;
457 }
458 }
459
460 /* Failure */
461 return -1;
462 }
463
464 /*
465 * Determine if the player is inside the house
466 */
house_inside(player_type * p_ptr,int house)467 bool house_inside(player_type *p_ptr, int house)
468 {
469 if (house >= 0 && house < num_houses)
470 {
471 if (houses[house].depth == p_ptr->dun_depth
472 && p_ptr->px >= houses[house].x_1 && p_ptr->px <= houses[house].x_2
473 && p_ptr->py >= houses[house].y_1 && p_ptr->py <= houses[house].y_2)
474 {
475 return TRUE;
476 }
477 }
478
479 return FALSE;
480 }
481
482 /*
483 * Determine if the given house is owned
484 */
house_owned(int house)485 bool house_owned(int house)
486 {
487 if (house >= 0 && house < num_houses)
488 {
489 if (houses[house].owned[0])
490 {
491 return TRUE;
492 }
493 }
494 return FALSE;
495 }
496
497 /*
498 * Determine if the given player owns the given house
499 */
house_owned_by(player_type * p_ptr,int house)500 bool house_owned_by(player_type *p_ptr, int house)
501 {
502 /* If not owned at all, obviously not owned by this player */
503 if (!house_owned(house)) return FALSE;
504
505 /* It's owned, is it by this player */
506 if (!strcmp(p_ptr->name,houses[house].owned))
507 {
508 return TRUE;
509 }
510 return FALSE;
511 }
512
513 /*
514 * Return the number of houses owned by the player
515 */
houses_owned(player_type * p_ptr)516 int houses_owned(player_type *p_ptr)
517 {
518 int i;
519 int owned = 0;
520
521 /* Check each house */
522 for (i = 0; i < num_houses; i++)
523 {
524 if (house_owned_by(p_ptr, i))
525 {
526 owned++;
527 }
528 }
529
530 return owned;
531 }
532
533 /*
534 * Given coordinates return a house to which they belong.
535 * Houses can be overlapping, so a single coordinate pair may match several
536 * houses. The offset parameter allows searching for the next match.
537 */
find_house(int Depth,int x,int y,int offset)538 int find_house(int Depth, int x, int y, int offset)
539 {
540 int i;
541
542 for (i = offset; i < num_houses; i++)
543 {
544 /* Check the house position *including* the walls */
545 if (houses[i].depth == Depth
546 && x >= houses[i].x_1-1 && x <= houses[i].x_2+1
547 && y >= houses[i].y_1-1 && y <= houses[i].y_2+1)
548 {
549 /* We found the house this section of wall belongs to */
550 return i;
551 }
552 }
553 return -1;
554 }
555
556 /*
557 * Determine if the given location is ok to use as part of the foundation
558 * of a house.
559 */
is_valid_foundation(player_type * p_ptr,int x,int y)560 bool is_valid_foundation(player_type *p_ptr, int x, int y)
561 {
562 int house;
563 cave_type *c_ptr;
564 object_type *o_ptr;
565
566 /* Foundation stones are always valid */
567 o_ptr = &o_list[cave[p_ptr->dun_depth][y][x].o_idx];
568 if (o_ptr->tval == TV_JUNK && o_ptr->sval == SV_HOUSE_FOUNDATION)
569 {
570 return TRUE;
571 }
572
573 /* Perma walls and doors are valid if they are part of a house owned
574 * by this player */
575 c_ptr = &cave[p_ptr->dun_depth][y][x];
576 if( (c_ptr->feat == FEAT_PERM_EXTRA)
577 || (c_ptr->feat >= FEAT_HOME_HEAD && c_ptr->feat <= FEAT_HOME_TAIL))
578 {
579 /* Looks like part of a house, which house? */
580 house = find_house(p_ptr->dun_depth, x, y, 0);
581 if(house >= 0)
582 {
583 /* Do we own this house? */
584 if (house_owned_by(p_ptr, house))
585 {
586 /* Valid, a wall or door in our own house. */
587 return TRUE;
588 }
589 }
590 }
591 return FALSE;
592 }
593
594 /*
595 * Create a new house door at the given location.
596 * Due to the fact that houses can overlap (i.e. share a common wall) it
597 * may not be possible to identify the house to which the door should belong.
598 *
599 * For example, on the left below, we have two houses overlapping, neither
600 * have doors. On the right the player creates a door, but to which house does
601 * it belong?
602 *
603 * #### ####
604 * # #@ # #@
605 * # ### # +##
606 * #### # #### #
607 * # # # #
608 * ### ###
609 *
610 * It is therefore possible to create a complex of houses such that the player
611 * owned shop mechanism becomes confused. When a player bumps one door they
612 * see the contents of a different room listed.
613 *
614 * FIXME Therefore the player owned shop mechanism should treat overlapping
615 * player created houses as a *single* house and present all goods in all
616 * attached houses.
617 */
create_house_door(player_type * p_ptr,int x,int y)618 bool create_house_door(player_type *p_ptr, int x, int y)
619 {
620 int house, i, lastmatch;
621 cave_type *c_ptr;
622
623 /* Which house is the given location part of? */
624 lastmatch = 0;
625 while( (house = find_house(p_ptr->dun_depth,x,y,lastmatch)) > -1 )
626 {
627 lastmatch = house+1;
628
629 /* Do we own this house? */
630 if (!house_owned_by(p_ptr, house))
631 {
632 /* If we don't own this one, we can't own any overlapping ones */
633 msg_print(p_ptr, "You do not own this house");
634 return FALSE;
635 }
636
637 /* Does it already have a door? */
638 if(houses[house].door_y == 0 && houses[house].door_x == 0)
639 {
640 /* No door, so create one! */
641 houses[house].door_y = y;
642 houses[house].door_x = x;
643 c_ptr = &cave[p_ptr->dun_depth][y][x];
644 c_ptr->feat = FEAT_HOME_HEAD;
645 everyone_lite_spot(p_ptr->dun_depth, y, x);
646 msg_print(p_ptr, "You create a door for your house!");
647 return TRUE;
648 }
649 }
650 /* We searched all matching houses and none needed a door */
651 return FALSE;
652 }
653
654 /*
655 * Determine the area for a house foundation.
656 *
657 * Although an individual house must be rectangular, a foundation
658 * can be non-rectangular. This is because we allow existing walls to
659 * form part of our foundation, and therefore allow complex shaped houses
660 * to be consructed.
661 * ~~~
662 * For example this is a legal foundation: ~~~~~~
663 * ~~~~~~
664 * In this sitation:
665 *
666 * ##### #####
667 * # # # #
668 * # # Forming a final shape: # #
669 * #####~~~ ###+####
670 * ~~~~~~ # #
671 * ~~~~~~ ######
672 *
673 * This function is also responsible for rejecting illegal shapes and sizes.
674 *
675 * We start from the player location (who must be stood on a foundation stone)
676 * and work our way outwards to find the bounding rectange of the foundation.
677 * Conceptually imagine a box radiating out from the player, we keep extending
678 * the box in each dimension for as long as all points on the perimeter are
679 * either foundation stones or walls of houses the player owns.
680 *
681 */
get_house_foundation(player_type * p_ptr,int * px1,int * py1,int * px2,int * py2)682 bool get_house_foundation(player_type *p_ptr, int *px1, int *py1, int *px2, int *py2)
683 {
684 int x, y, x1, y1, x2, y2;
685 bool done;
686 bool n,s,e,w,ne,nw,se,sw;
687 object_type *o_ptr;
688
689 plog(format("Player is at x,y %d, %d",p_ptr->px, p_ptr->py));
690
691 /* We must be stood on a house foundation */
692 o_ptr = &o_list[cave[p_ptr->dun_depth][p_ptr->py][p_ptr->px].o_idx];
693 if (o_ptr->tval != TV_JUNK || o_ptr->sval != SV_HOUSE_FOUNDATION)
694 {
695 msg_print(p_ptr, "There is no house foundation here.");
696 return FALSE;
697 }
698
699 /* Start from the players position */
700 x1 = p_ptr->px;
701 x2 = p_ptr->px;
702 y1 = p_ptr->py;
703 y2 = p_ptr->py;
704
705 done = FALSE;
706 while(!done)
707 {
708 n = s = e = w = ne = nw = se = sw = FALSE;
709
710 /* Could we expand north? */
711 n = TRUE;
712 for(x = x1; x <= x2; x++)
713 {
714 /* Is this a valid location for part of our house? */
715 if(!is_valid_foundation(p_ptr, x, y1-1))
716 {
717 /* Not a valid perimeter */
718 n = FALSE;
719 break;
720 }
721 }
722
723 /* Could we expand east? */
724 e = TRUE;
725 for(y = y1; y <= y2; y++)
726 {
727 /* Is this a valid location for part of our house? */
728 if(!is_valid_foundation(p_ptr, x2+1, y))
729 {
730 /* Not a valid perimeter */
731 e = FALSE;
732 break;
733 }
734 }
735
736 /* Could we expend south? */
737 s = TRUE;
738 for(x = x1; x <= x2; x++)
739 {
740 /* Is this a valid location for part of our house? */
741 if(!is_valid_foundation(p_ptr, x, y2+1))
742 {
743 /* Not a valid perimeter */
744 s = FALSE;
745 break;
746 }
747 }
748
749 /* Could we expand west? */
750 w = TRUE;
751 for(y = y1; y <= y2; y++)
752 {
753 /* Is this a valid location for part of our house? */
754 if(!is_valid_foundation(p_ptr, x1-1, y))
755 {
756 /* Not a valid perimeter */
757 w = FALSE;
758 break;
759 }
760 }
761
762 /* Could we expand the corners? */
763 ne = is_valid_foundation(p_ptr, x2+1, y1-1);
764 nw = is_valid_foundation(p_ptr, x1-1, y1-1);
765 se = is_valid_foundation(p_ptr, x2+1, y2+1);
766 sw = is_valid_foundation(p_ptr, x1-1, y2+1);
767
768 /* Only permit expansion in a way that maintains a rectangle, we don't
769 * want to create fancy polygons. */
770 if( n ) n = (!e && !w) || ( e && ne ) || ( w && nw );
771 if( e ) e = (!n && !s) || ( n && ne ) || ( s && se );
772 if( s ) s = (!e && !w) || ( e && se ) || ( w && sw );
773 if( w ) w = (!n && !s) || ( n && nw ) || ( s && sw );
774
775 /* Actually expand the boundary */
776 if( n ) y1--;
777 if( s ) y2++;
778 if( w ) x1--;
779 if( e ) x2++;
780
781 /* Stop if we couldn't expand */
782 done = !(n || s || w || e);
783
784 }
785
786 plog(format("Proposed house is at x1,y1,x2,y2 %d,%d,%d,%d",x1,y1,x2,y2));
787
788 /* Is the bounding rectangle we found big enough? */
789 if(x2-x1 < 2 || y2-y1 < 2)
790 {
791 msg_print(p_ptr, "The foundation is too small.");
792 return FALSE;
793 }
794
795 /* Return the area */
796 *px1 = x1;
797 *px2 = x2;
798 *py1 = y1;
799 *py2 = y2;
800 return TRUE;
801 }
802
803 /*
804 * Create a new house.
805 * The creating player owns the house.
806 */
create_house(player_type * p_ptr)807 bool create_house(player_type *p_ptr)
808 {
809 int x1, x2, y1, y2, x, y;
810 cave_type *c_ptr;
811
812 /* Not in dungeon, not in town */
813 if (p_ptr->dun_depth >= 0 || check_special_level(p_ptr->dun_depth))
814 {
815 msg_print(p_ptr, "The surrounding magic is too strong for House Creation.");
816 return FALSE;
817 }
818
819 /* Determine the area of the house foundation */
820 if (!get_house_foundation(p_ptr, &x1, &y1, &x2, &y2))
821 {
822 return FALSE;
823 }
824
825 /* Is the location allowed? */
826 /* XXX We should check if too near other houses, roads, level edges, etc */
827
828 /* Add a house to our houses list */
829 houses[num_houses].price = 0; /* XXX */
830 houses[num_houses].x_1 = x1+1;
831 houses[num_houses].y_1 = y1+1;
832 houses[num_houses].x_2 = x2-1;
833 houses[num_houses].y_2 = y2-1;
834 houses[num_houses].depth = p_ptr->dun_depth;
835 houses[num_houses].door_y = 0;
836 houses[num_houses].door_x = 0;
837 set_house_owner(p_ptr, num_houses);
838 num_houses++;
839
840 /* Render into the terrain */
841 for (y = y1; y <= y2; y++)
842 {
843 for (x = x1; x <= x2; x++)
844 {
845 /* Get the grid */
846 c_ptr = &cave[p_ptr->dun_depth][y][x];
847
848 /* Delete any object */
849 delete_object(p_ptr->dun_depth, y, x);
850
851 /* Build a wall, but don't destroy any existing door */
852 if( c_ptr->feat < FEAT_HOME_HEAD || c_ptr->feat > FEAT_HOME_TAIL)
853 {
854 c_ptr->feat = FEAT_PERM_EXTRA;
855 }
856
857 /* Update the spot */
858 everyone_lite_spot(p_ptr->dun_depth, y, x);
859 }
860 }
861 for (y = y1 + 1; y < y2; y++)
862 {
863 for (x = x1 + 1; x < x2; x++)
864 {
865 /* Get the grid */
866 c_ptr = &cave[p_ptr->dun_depth][y][x];
867
868 /* Delete any object */
869 delete_object(p_ptr->dun_depth, y, x);
870
871 /* Fill with floor */
872 c_ptr->feat = FEAT_FLOOR;
873
874 /* Make it "icky" */
875 c_ptr->info |= CAVE_ICKY;
876
877 /* Update the spot */
878 everyone_lite_spot(p_ptr->dun_depth, y, x);
879 }
880 }
881 return TRUE;
882 }
883
884 /*
885 * Set the owner of the given house
886 */
set_house_owner(player_type * p_ptr,int house)887 bool set_house_owner(player_type *p_ptr, int house)
888 {
889 /* Not if it's already owned */
890 if (house_owned(house)) return FALSE;
891
892 /* Set the player as the owner */
893 my_strcpy(houses[house].owned, p_ptr->name, MAX_NAME_LEN+1);
894
895 return TRUE;
896 }
897
898 /*
899 * Set the given house as unowned
900 */
disown_house(int house)901 void disown_house(int house)
902 {
903 cave_type *c_ptr;
904 int i,j, Depth;
905
906 if (house >= 0 && house < num_houses)
907 {
908 Depth = houses[house].depth;
909 houses[house].owned[0] = '\0';
910 houses[house].strength = 0;
911 /* Remove all players from the house */
912 for (i = 1; i <= NumPlayers; i++)
913 {
914 if (house_inside(Players[i], house))
915 {
916 msg_print(Players[i], "You have been expelled from the house.");
917 teleport_player(Players[i], 5);
918 }
919 }
920 /* Clear any items from the house */
921 for (i = houses[house].y_1; i <= houses[house].y_2; i++)
922 {
923 for (j = houses[house].x_1; j <= houses[house].x_2; j++)
924 {
925 delete_object(houses[house].depth,i,j);
926 }
927 }
928
929 /* Paranoia! */
930 if (!cave[Depth]) return;
931
932 /* Get requested grid */
933 c_ptr = &cave[Depth][houses[house].door_y][houses[house].door_x];
934
935 /* Close the door */
936 c_ptr->feat = FEAT_HOME_HEAD + houses[house].strength;
937
938 /* Reshow */
939 everyone_lite_spot(Depth, houses[house].door_y, houses[house].door_x);
940
941 }
942 }
943
944 /*
945 * Attempt to open the given chest at the given location
946 *
947 * Assume there is no monster blocking the destination
948 *
949 * Returns TRUE if repeated commands may continue
950 */
do_cmd_open_chest(player_type * p_ptr,int y,int x,s16b o_idx)951 static bool do_cmd_open_chest(player_type *p_ptr, int y, int x, s16b o_idx)
952 {
953 int i, j;
954
955 bool flag = TRUE;
956
957 bool more = FALSE;
958
959 object_type *o_ptr = &o_list[o_idx];
960
961
962 /* Attempt to unlock it */
963 if (o_ptr->pval > 0)
964 {
965 /* Assume locked, and thus not open */
966 flag = FALSE;
967
968 /* Get the "disarm" factor */
969 i = p_ptr->skill_dis;
970
971 /* Penalize some conditions */
972 if (p_ptr->blind || no_lite(p_ptr)) i = i / 10;
973 if (p_ptr->confused || p_ptr->image) i = i / 10;
974
975 /* Extract the difficulty */
976 j = i - o_ptr->pval;
977
978 /* Always have a small chance of success */
979 if (j < 2) j = 2;
980
981 /* Success -- May still have traps */
982 if (randint0(100) < j)
983 {
984 msg_print_aux(p_ptr, "You have picked the lock.", MSG_LOCKPICK);
985 sound(p_ptr, MSG_LOCKPICK);
986 gain_exp(p_ptr, 1);
987 flag = TRUE;
988 }
989
990 /* Failure -- Keep trying */
991 else
992 {
993 /* We may continue repeating */
994 more = TRUE;
995 /*if (flush_failure) flush();*/
996 msg_print_aux(p_ptr, "You failed to pick the lock.", MSG_LOCKPICK_FAIL);
997 sound(p_ptr, MSG_LOCKPICK_FAIL);
998 }
999 }
1000
1001 /* Allowed to open */
1002 if (flag)
1003 {
1004 /* Apply chest traps, if any */
1005 chest_trap(p_ptr, y, x, o_ptr);
1006
1007 /* Let the Chest drop items */
1008 chest_death(p_ptr, y, x, o_ptr);
1009 }
1010
1011 /* Result */
1012 return (more);
1013 }
1014
1015 /*
1016 * Attempt to disarm the chest at the given location
1017 *
1018 * Assume there is no monster blocking the destination
1019 *
1020 * Returns TRUE if repeated commands may continue
1021 */
do_cmd_disarm_chest(player_type * p_ptr,int y,int x,s16b o_idx)1022 static bool do_cmd_disarm_chest(player_type *p_ptr, int y, int x, s16b o_idx)
1023 {
1024 int i, j;
1025
1026 bool more = FALSE;
1027
1028 object_type *o_ptr = &o_list[o_idx];
1029
1030
1031 /* Get the "disarm" factor */
1032 i = p_ptr->skill_dis;
1033
1034 /* Penalize some conditions */
1035 if (p_ptr->blind || no_lite(p_ptr)) i = i / 10;
1036 if (p_ptr->confused || p_ptr->image) i = i / 10;
1037
1038 /* Extract the difficulty */
1039 j = i - o_ptr->pval;
1040
1041 /* Always have a small chance of success */
1042 if (j < 2) j = 2;
1043
1044 /* Must find the trap first. */
1045 if (!object_known_p(p_ptr, o_ptr))
1046 {
1047 msg_print(p_ptr, "I don't see any traps.");
1048 }
1049
1050 /* Already disarmed/unlocked */
1051 else if (o_ptr->pval <= 0)
1052 {
1053 msg_print(p_ptr, "The chest is not trapped.");
1054 }
1055
1056 /* No traps to find. */
1057 else if (!chest_traps[o_ptr->pval])
1058 {
1059 msg_print(p_ptr, "The chest is not trapped.");
1060 }
1061
1062 /* Success (get a lot of experience) */
1063 else if (randint0(100) < j)
1064 {
1065 msg_print_aux(p_ptr, "You have disarmed the chest.", MSG_DISARM);
1066 sound(p_ptr, MSG_DISARM);
1067 gain_exp(p_ptr, o_ptr->pval);
1068 o_ptr->pval = (0 - o_ptr->pval);
1069 }
1070
1071 /* Failure -- Keep trying */
1072 else if ((i > 5) && (randint1(i) > 5))
1073 {
1074 /* We may keep trying */
1075 more = TRUE;
1076 /*if (flush_failure) flush();*/
1077 msg_print(p_ptr, "You failed to disarm the chest.");
1078 }
1079
1080 /* Failure -- Set off the trap */
1081 else
1082 {
1083 msg_print(p_ptr, "You set off a trap!");
1084 chest_trap(p_ptr, y, x, o_ptr);
1085 }
1086
1087 /* Result */
1088 return (more);
1089 }
1090
1091
1092
1093
1094 /*
1095 * Tunnel through wall. Assumes valid location.
1096 *
1097 * Note that it is impossible to "extend" rooms past their
1098 * outer walls (which are actually part of the room).
1099 *
1100 * This will, however, produce grids which are NOT illuminated
1101 * (or darkened) along with the rest of the room.
1102 */
twall(player_type * p_ptr,int y,int x)1103 static bool twall(player_type *p_ptr, int y, int x)
1104 {
1105 int Depth = p_ptr->dun_depth;
1106
1107 /* Paranoia -- Require a wall or door or some such */
1108 if (cave_floor_bold(Depth, y, x)) return (FALSE);
1109
1110 /* Sound */
1111 sound(p_ptr, MSG_DIG);
1112
1113 /* Forget the wall */
1114 everyone_forget_spot(Depth, y, x);
1115
1116 /* Remove the feature */
1117 if (Depth > 0)
1118 cave_set_feat(Depth, y, x, FEAT_FLOOR);
1119 else
1120 cave_set_feat(Depth, y, x, FEAT_DIRT);
1121
1122 /* Note: cave_set_feat has handled updates for all players! */
1123
1124 /* Result */
1125 return (TRUE);
1126 }
1127
1128 /*
1129 * Determine if a given grid may be "opened"
1130 */
do_cmd_open_test(player_type * p_ptr,int y,int x)1131 static bool do_cmd_open_test(player_type *p_ptr, int y, int x)
1132 {
1133 int Depth = p_ptr->dun_depth;
1134
1135 cave_type *c_ptr;
1136
1137 /* Ghosts cannot open */
1138 if ( (p_ptr->ghost || p_ptr->fruit_bat) && !(p_ptr->dm_flags & DM_GHOST_HANDS) )
1139 {
1140 /* Message */
1141 msg_print(p_ptr, "You cannot open things!");
1142
1143 return (FALSE);
1144 }
1145
1146 /* Get grid and contents */
1147 c_ptr = &cave[Depth][y][x];
1148
1149 /* Must have knowledge */
1150 if (!(p_ptr->cave_flag[y][x] & (CAVE_MARK)))
1151 {
1152 /* Message */
1153 msg_print(p_ptr, "You see nothing there.");
1154
1155 /* Nope */
1156 return (FALSE);
1157 }
1158
1159 /* Must be a closed door */
1160 if (!((c_ptr->feat >= FEAT_DOOR_HEAD) &&
1161 (c_ptr->feat <= FEAT_DOOR_TAIL)) &&
1162 /* OR MAngband-specific: Player house doors */
1163 !((c_ptr->feat >= FEAT_HOME_HEAD) &&
1164 (c_ptr->feat <= FEAT_HOME_TAIL)) &&
1165 /* OR MAngband-specific: House Creation */
1166 !(c_ptr->feat == FEAT_PERM_EXTRA))
1167 {
1168 /* Message */
1169 msg_print_aux(p_ptr, "You see nothing there to open.", MSG_NOTHING_TO_OPEN);
1170 sound(p_ptr, MSG_NOTHING_TO_OPEN);
1171
1172 /* Nope */
1173 return (FALSE);
1174 }
1175
1176 /* Okay */
1177 return (TRUE);
1178 }
1179
1180
1181 /*
1182 * Perform the basic "open" command on doors
1183 *
1184 * Assume there is no monster blocking the destination
1185 *
1186 * Returns TRUE if repeated commands may continue
1187 */
do_cmd_open_aux(player_type * p_ptr,int y,int x)1188 static bool do_cmd_open_aux(player_type *p_ptr, int y, int x)
1189 {
1190 int Depth = p_ptr->dun_depth;
1191
1192 cave_type *c_ptr;
1193
1194 int i, j, k;
1195
1196 bool more = FALSE;
1197
1198
1199 /* Verify legality */
1200 if (!do_cmd_open_test(p_ptr, y, x)) return (FALSE);
1201
1202 /* Get grid and contents */
1203 c_ptr = &cave[Depth][y][x];
1204
1205
1206 /* We put MAngband-specific tests on top, as new FEATs are larger */
1207 /* Player Houses */
1208 if (c_ptr->feat >= FEAT_HOME_HEAD && c_ptr->feat <= FEAT_HOME_TAIL)
1209 {
1210 i = pick_house(Depth, y, x);
1211
1212 if (i == -1)
1213 {
1214 debug(format("No house found at Depth %d, X=%d, Y=%d !", Depth, y, x));
1215 return (FALSE);
1216 }
1217
1218 /* Do we own this house? */
1219 if (house_owned_by(p_ptr, i) || (p_ptr->dm_flags & DM_HOUSE_CONTROL) )
1220 {
1221
1222 /* If someone is in our store, we eject them (anti-exploit) */
1223 for (k = 1; k <= NumPlayers; k++ )
1224 {
1225 /* We don't block if the owner is getting out! */
1226 player_type *q_ptr = Players[k];
1227 if (q_ptr && !same_player(p_ptr, q_ptr))
1228 {
1229 /* We do block if the owner is getting in */
1230 if(q_ptr->player_store_num == i && q_ptr->store_num == 8)
1231 {
1232 q_ptr->store_num = -1;
1233 send_store_leave(q_ptr);
1234 msg_print(q_ptr, "The shopkeeper locks the doors.");
1235 }
1236 }
1237 }
1238
1239 /* Open the door */
1240 c_ptr->feat = FEAT_HOME_OPEN;
1241
1242 /* Notice */
1243 note_spot_depth(Depth, y, x);
1244
1245 /* Redraw */
1246 everyone_lite_spot(Depth, y, x);
1247
1248 /* Update some things */
1249 p_ptr->update |= (PU_VIEW | PU_LITE | PU_MONSTERS);
1250 }
1251
1252 /* He's not the owner, check if owned */
1253 else if (house_owned(i))
1254 {
1255 /* Player owned store! */
1256
1257 /* Disturb */
1258 disturb(p_ptr, 0, 0);
1259
1260 /* Hack -- Enter store */
1261 /*command_new = '_';*/
1262 do_cmd_store(p_ptr, i);
1263 }
1264 else
1265 {
1266 int price, factor;
1267
1268 /* Take CHR into account */
1269 factor = adj_chr_gold[p_ptr->stat_ind[A_CHR]];
1270 price = (unsigned long) houses[i].price * factor / 100;
1271 if(Depth==0) {
1272 price = (unsigned long)price *5L;
1273 };
1274
1275 /* Tell him the price */
1276 msg_format(p_ptr, "This house costs %ld gold.", price);
1277 }
1278 }
1279
1280 /* Open a perma wall */
1281 else if (c_ptr->feat == FEAT_PERM_EXTRA)
1282 {
1283 /* Opening a wall? Either the player has lost his mind or he
1284 * is trying to create a door! */
1285 create_house_door(p_ptr, x, y);
1286 }
1287
1288 /* Jammed door */
1289 else if (c_ptr->feat >= FEAT_DOOR_HEAD + 0x08)
1290 {
1291 /* Stuck */
1292 msg_print(p_ptr, "The door appears to be stuck.");
1293 }
1294
1295 /* Locked door */
1296 else if (c_ptr->feat >= FEAT_DOOR_HEAD + 0x01)
1297 {
1298 /* Disarm factor */
1299 i = p_ptr->skill_dis;
1300
1301 /* Penalize some conditions */
1302 if (p_ptr->blind || no_lite(p_ptr)) i = i / 10;
1303 if (p_ptr->confused || p_ptr->image) i = i / 10;
1304
1305 /* Extract the lock power */
1306 j = c_ptr->feat - FEAT_DOOR_HEAD;
1307
1308 /* Extract the difficulty XXX XXX XXX */
1309 j = i - (j * 4);
1310
1311 /* Always have a small chance of success */
1312 if (j < 2) j = 2;
1313
1314 /* Success */
1315 if (randint0(100) < j)
1316 {
1317 /* Message */
1318 msg_print_aux(p_ptr, "You have picked the lock.", MSG_LOCKPICK);
1319 sound(p_ptr, MSG_LOCKPICK);
1320
1321 /* Open the door */
1322 cave_set_feat(Depth, y, x, FEAT_OPEN);
1323
1324 /* Experience */
1325 gain_exp(p_ptr, 1);
1326 }
1327
1328 /* Failure */
1329 else
1330 {
1331 /* Failure */
1332 /*if (flush_failure) flush();*/
1333
1334 /* Message */
1335 msg_print_aux(p_ptr, "You failed to pick the lock.", MSG_LOCKPICK_FAIL);
1336 sound(p_ptr, MSG_LOCKPICK_FAIL);
1337
1338 /* We may keep trying */
1339 more = TRUE;
1340 }
1341 }
1342
1343 /* Closed door */
1344 else
1345 {
1346 /* Open the door */
1347 /*cave_set_feat(y, x, FEAT_OPEN);*/
1348 c_ptr->feat = FEAT_OPEN;
1349
1350 /* Notice */
1351 note_spot_depth(Depth, y, x);
1352
1353 /* Redraw */
1354 everyone_lite_spot(Depth, y, x);
1355
1356 /* Update some things */
1357 p_ptr->update |= (PU_VIEW | PU_LITE | PU_MONSTERS);
1358
1359 /* Sound */
1360 sound(p_ptr, MSG_OPENDOOR);
1361 }
1362
1363 /* Result */
1364 return (more);
1365 }
1366
1367
1368
1369 /*
1370 * Open a closed/locked/jammed door or a closed/locked chest.
1371 *
1372 * Unlocking a locked door/chest is worth one experience point.
1373 */
do_cmd_open(player_type * p_ptr,int dir)1374 void do_cmd_open(player_type *p_ptr, int dir)
1375 {
1376 int Depth = p_ptr->dun_depth;
1377
1378 cave_type *c_ptr;
1379 object_type *o_ptr;
1380
1381 int y, x;
1382
1383 s16b o_idx;
1384
1385 bool more = FALSE;
1386
1387 #if 0
1388 /* Easy Open */
1389 if (p_ptr->easy_open)
1390 {
1391 int num_doors, num_chests;
1392
1393 /* Count closed doors */
1394 num_doors = count_feats(&y, &x, is_closed, FALSE);
1395
1396 /* Count chests (locked) */
1397 num_chests = count_chests(&y, &x, FALSE);
1398
1399 /* See if only one target */
1400 if ((num_doors + num_chests) == 1)
1401 {
1402 p_ptr->command_dir = motion_dir(p_ptr->py, p_ptr->px, y, x);
1403 }
1404 }
1405 #endif
1406 /* Get a direction (or abort) */
1407 /*if (!get_rep_dir(&dir)) return;*/
1408 if (!VALID_DIR(dir)) return;
1409
1410 /* Get location */
1411 y = p_ptr->py + ddy[dir];
1412 x = p_ptr->px + ddx[dir];
1413
1414 /* Get grid and contents */
1415 c_ptr = &cave[Depth][y][x];
1416
1417 /* Access the item */
1418 o_ptr = &o_list[c_ptr->o_idx];
1419
1420 /* Check for chests */
1421 o_idx = (o_ptr->tval == TV_CHEST ? c_ptr->o_idx : 0);
1422
1423
1424 /* Verify legality */
1425 if (!o_idx && !do_cmd_open_test(p_ptr, y, x)) return;
1426
1427
1428 /* Take a turn */
1429 p_ptr->energy -= level_speed(p_ptr->dun_depth);
1430
1431 /* Apply confusion */
1432 if (confuse_dir((bool)p_ptr->confused, &dir))
1433 {
1434 /* Get location */
1435 y = p_ptr->py + ddy[dir];
1436 x = p_ptr->px + ddx[dir];
1437
1438 /* Get grid and contents */
1439 c_ptr = &cave[Depth][y][x];
1440
1441 /* Access the item */
1442 o_ptr = &o_list[c_ptr->o_idx];
1443
1444 /* Check for chest */
1445 o_idx = (o_ptr->tval == TV_CHEST ? c_ptr->o_idx : 0);
1446 }
1447
1448
1449 /* Allow repeated command */
1450 if (p_ptr->command_arg)
1451 {
1452 /* Set repeat count */
1453 /*p_ptr->command_rep = p_ptr->command_arg - 1;*/
1454
1455 /* Redraw the state */
1456 p_ptr->redraw |= (PR_STATE);
1457
1458 /* Cancel the arg */
1459 p_ptr->command_arg = 0;
1460 }
1461
1462 /* Monster */
1463 if (c_ptr->m_idx > 0)
1464 {
1465 /* Message */
1466 msg_print(p_ptr, "There is a monster in the way!");
1467
1468 /* Attack */
1469 py_attack(p_ptr, y, x);
1470 }
1471
1472 /* Player in the way */
1473 else if (c_ptr->m_idx < 0)
1474 {
1475 /* Take a turn */
1476 p_ptr->energy -= level_speed(p_ptr->dun_depth);
1477
1478 /* Message */
1479 msg_print(p_ptr, "There is a player in the way!");
1480
1481 }
1482
1483 /* Chest */
1484 else if (o_idx)
1485 {
1486 /* Open the chest */
1487 more = do_cmd_open_chest(p_ptr, y, x, o_idx);
1488 }
1489
1490 /* Door */
1491 else
1492 {
1493 /* Open the door */
1494 more = do_cmd_open_aux(p_ptr, y, x);
1495 }
1496
1497 /* Cancel repeat unless we may continue */
1498 if (!more) disturb(p_ptr, 0, 0);
1499 }
1500
1501
1502 /*
1503 * Determine if a given grid may be "closed"
1504 */
do_cmd_close_test(player_type * p_ptr,int y,int x)1505 static bool do_cmd_close_test(player_type *p_ptr, int y, int x)
1506 {
1507 int Depth = p_ptr->dun_depth;
1508
1509 cave_type *c_ptr;
1510
1511 #if 0
1512 /* Ghosts cannot close */
1513 if ( (p_ptr->ghost || p_ptr->fruit_bat) && !(p_ptr->dm_flags & DM_GHOST_HANDS) )
1514 {
1515 /* Message */
1516 msg_print(p_ptr, "You cannot close things!");
1517
1518 return (FALSE);
1519 }
1520 #endif
1521 /* Get grid and contents */
1522 c_ptr = &cave[Depth][y][x];
1523
1524 /* Must have knowledge */
1525 if (!(p_ptr->cave_flag[y][x] & (CAVE_MARK)))
1526 {
1527 /* Message */
1528 msg_print(p_ptr, "You see nothing there.");
1529
1530 /* Nope */
1531 return (FALSE);
1532 }
1533
1534 /* Require open/broken door */
1535 if ((c_ptr->feat != FEAT_OPEN) &&
1536 (c_ptr->feat != FEAT_BROKEN) &&
1537 (c_ptr->feat != FEAT_HOME_OPEN))
1538 {
1539 /* Message */
1540 msg_print(p_ptr, "You see nothing there to close.");
1541
1542 /* Nope */
1543 return (FALSE);
1544 }
1545
1546 /* Okay */
1547 return (TRUE);
1548 }
1549
1550
1551 /*
1552 * Perform the basic "close" command
1553 *
1554 * Assume there is no monster blocking the destination
1555 *
1556 * Returns TRUE if repeated commands may continue
1557 */
do_cmd_close_aux(player_type * p_ptr,int y,int x)1558 static bool do_cmd_close_aux(player_type *p_ptr, int y, int x)
1559 {
1560 int Depth = p_ptr->dun_depth;
1561
1562 cave_type *c_ptr;
1563
1564 int i;
1565
1566 bool more = FALSE;
1567
1568 /* Verify legality */
1569 if (!do_cmd_close_test(p_ptr, y, x)) return (FALSE);
1570
1571
1572 /* Get grid and contents */
1573 c_ptr = &cave[Depth][y][x];
1574
1575
1576 /* Broken door */
1577 if (c_ptr->feat == FEAT_BROKEN)
1578 {
1579 /* Message */
1580 msg_print(p_ptr, "The door appears to be broken.");
1581 }
1582
1583 /* (MAngband-specific) House door, close it */
1584 else if (c_ptr->feat == FEAT_HOME_OPEN)
1585 {
1586 /* Find this house */
1587 i = pick_house(Depth, y, x);
1588
1589 /* Close the door */
1590 c_ptr->feat = FEAT_HOME_HEAD + houses[i].strength;
1591
1592 /* Notice */
1593 note_spot_depth(Depth, y, x);
1594
1595 /* Redraw */
1596 everyone_lite_spot(Depth, y, x);
1597
1598 /* Update some things */
1599 p_ptr->update |= (PU_VIEW | PU_LITE | PU_MONSTERS);
1600 }
1601
1602 /* Open door */
1603 else
1604 {
1605 /* Close the door */
1606 c_ptr->feat = FEAT_DOOR_HEAD + 0x00;
1607
1608 /* Notice */
1609 note_spot_depth(Depth, y, x);
1610
1611 /* Redraw */
1612 everyone_lite_spot(Depth, y, x);
1613
1614 /* Update some things */
1615 p_ptr->update |= (PU_VIEW | PU_LITE | PU_MONSTERS);
1616
1617 /* Sound */
1618 sound(p_ptr, MSG_SHUTDOOR);
1619 }
1620
1621 /* Result */
1622 return (more);
1623 }
1624
1625
1626 /*
1627 * Close an open door.
1628 */
do_cmd_close(player_type * p_ptr,int dir)1629 void do_cmd_close(player_type *p_ptr, int dir)
1630 {
1631 int Depth = p_ptr->dun_depth;
1632
1633 cave_type *c_ptr;
1634
1635 int y, x;
1636
1637 bool more = FALSE;
1638
1639 /* Check preventive inscription '^c' */
1640 __trap(p_ptr, CPI(p_ptr, 'c'));
1641
1642 #if 0
1643 /* Easy Close */
1644 if (p_ptr->easy_open)
1645 {
1646 /* Count open doors */
1647 if (count_feats(&y, &x, is_open, FALSE) == 1)
1648 {
1649 p_ptr->command_dir = motion_dir(p_ptr->py, p_ptr->px, y, x);
1650 }
1651 }
1652 #endif
1653 /* Get a direction (or abort) */
1654 /*if (!get_rep_dir(&dir)) return;*/
1655 if (!VALID_DIR(dir)) return;
1656
1657 /* Get location */
1658 y = p_ptr->py + ddy[dir];
1659 x = p_ptr->px + ddx[dir];
1660
1661 /* Verify legality */
1662 if (!do_cmd_close_test(p_ptr, y, x)) return;
1663
1664 /* Take a turn */
1665 p_ptr->energy -= level_speed(p_ptr->dun_depth);
1666
1667 /* Apply confusion */
1668 if (confuse_dir((bool)p_ptr->confused, &dir))
1669 {
1670 /* Get location */
1671 y = p_ptr->py + ddy[dir];
1672 x = p_ptr->px + ddx[dir];
1673 }
1674
1675 /* Get grid and contents */
1676 c_ptr = &cave[Depth][y][x];
1677
1678 /* Allow repeated command */
1679 if (p_ptr->command_arg)
1680 {
1681 /* Set repeat count */
1682 /*p_ptr->command_rep = p_ptr->command_arg - 1;*/
1683
1684 /* Redraw the state */
1685 p_ptr->redraw |= (PR_STATE);
1686
1687 /* Cancel the arg */
1688 p_ptr->command_arg = 0;
1689 }
1690
1691 /* Monster */
1692 if (c_ptr->m_idx > 0)
1693 {
1694 /* Message */
1695 msg_print(p_ptr, "There is a monster in the way!");
1696
1697 /* Attack */
1698 py_attack(p_ptr, y, x);
1699 }
1700
1701 /* Player in the way */
1702 else if (c_ptr->m_idx < 0)
1703 {
1704 /* Message */
1705 msg_print(p_ptr, "There is a player in the way!");
1706 }
1707
1708 /* Door */
1709 else
1710 {
1711 /* Close door */
1712 more = do_cmd_close_aux(p_ptr, y, x);
1713 }
1714
1715 /* Cancel repeat unless told not to */
1716 if (!more) disturb(p_ptr, 0, 0);
1717 }
1718
1719
1720 /*
1721 * Determine if a given grid may be "tunneled"
1722 */
do_cmd_tunnel_test(player_type * p_ptr,int y,int x)1723 static bool do_cmd_tunnel_test(player_type *p_ptr, int y, int x)
1724 {
1725 int Depth = p_ptr->dun_depth;
1726
1727 cave_type *c_ptr;
1728
1729
1730 /* Ghosts cannot tunnel */
1731 if ( (p_ptr->ghost || p_ptr->fruit_bat) && !(p_ptr->dm_flags & DM_GHOST_HANDS) )
1732 {
1733 /* Message */
1734 msg_print(p_ptr, "You cannot tunnel!");
1735
1736 return (FALSE);
1737 }
1738
1739 /* Get grid and contents */
1740 c_ptr = &cave[Depth][y][x];
1741
1742 /* Must have knowledge */
1743 if (!(p_ptr->cave_flag[y][x] & (CAVE_MARK)))
1744 {
1745 /* Message */
1746 msg_print(p_ptr, "You see nothing there.");
1747
1748 /* Nope */
1749 return (FALSE);
1750 }
1751
1752 /* Must be a wall/door/etc */
1753 if (cave_floor_bold(Depth, y, x))
1754 {
1755 /* Message */
1756 msg_print(p_ptr, "You see nothing there to tunnel.");
1757
1758 /* Nope */
1759 return (FALSE);
1760 }
1761
1762 /* No tunnelling through house doors */
1763 if (c_ptr->feat == FEAT_HOME_OPEN ||
1764 (c_ptr->feat >= FEAT_HOME_HEAD && c_ptr->feat <= FEAT_HOME_TAIL))
1765 {
1766 /* Message */
1767 msg_print(p_ptr, "You cannot tunnel through house doors.");
1768
1769 /* Nope */
1770 return (FALSE);
1771 }
1772 #if 0
1773 /* No tunnelling through emptiness */
1774 if ( (cave_floor_bold(Depth, y, x)) || (c_ptr->feat == FEAT_PERM_CLEAR) )
1775 {
1776 /* Message */
1777 msg_print(p_ptr, "You see nothing there to tunnel through.");
1778 }
1779 #endif
1780 /* Okay */
1781 return (TRUE);
1782 }
1783
1784 /* Return "cutting bonus" (0-4) based on weapon effeciency against trees
1785 * This macro depends on TV_SWORD SVALues being ordered from less
1786 * powerfull to more powerfull. */
1787 #define wielding_cut(TV,SV) \
1788 ((((TV) == TV_SWORD) ? (((SV) >= SV_LONG_SWORD) ? 2 : \
1789 (((SV) >= SV_SMALL_SWORD) ? 1 : 0)) : \
1790 (((TV) == TV_POLEARM) ? (((SV) == SV_SCYTHE_OF_SLICING) ? 4 : \
1791 (((SV) >= SV_SCYTHE) ? 3 : (((SV) >= SV_BEAKED_AXE) ? 2 : 0))) : 0 )))
1792
1793 #define wielding_cut_o(O) \
1794 (wielding_cut((O).tval,(O).sval))
1795 #define wielding_cut_p(P) \
1796 (wielding_cut_o((P)->inventory[INVEN_WIELD]))
1797 /*
1798 * Perform the basic "tunnel" command
1799 *
1800 * Assumes that no monster is blocking the destination
1801 *
1802 * Uses "twall" (above) to do all "terrain feature changing".
1803 *
1804 * Returns TRUE if repeated commands may continue
1805 */
do_cmd_tunnel_aux(player_type * p_ptr,int y,int x)1806 static bool do_cmd_tunnel_aux(player_type *p_ptr, int y, int x)
1807 {
1808 int Depth = p_ptr->dun_depth;
1809
1810 cave_type *c_ptr;
1811
1812 bool more = FALSE;
1813
1814
1815 /* Verify legality */
1816 if (!do_cmd_tunnel_test(p_ptr, y, x)) return (FALSE);
1817
1818 /* Get grid and contents */
1819 c_ptr = &cave[Depth][y][x];
1820
1821 /* Sound XXX XXX XXX */
1822 sound(p_ptr, MSG_DIG);
1823
1824 /* Hack -- We put MAngband-specific terrain features on top, as they are higher */
1825
1826 /* Vegetation */
1827 if (c_ptr->feat == FEAT_TREE)
1828 {
1829 /* Mow down the vegetation */
1830 if ((p_ptr->skill_dig + wielding_cut_p(p_ptr) * 10 > randint0(400)) && twall(p_ptr, y, x))
1831 {
1832 if (Depth == 0) trees_in_town--;
1833
1834 /* Message */
1835 msg_print(p_ptr, "You hack your way through the vegetation.");
1836 }
1837 else
1838 {
1839 /* Message, keep digging */
1840 msg_print(p_ptr, "You attempt to clear a path.");
1841 more = TRUE;
1842 }
1843 }
1844
1845 else if (c_ptr->feat == FEAT_EVIL_TREE)
1846 {
1847 /* Mow down the vegetation */
1848 if ((p_ptr->skill_dig + wielding_cut_p(p_ptr) * 10 > randint0(600)) && twall(p_ptr, y, x))
1849 {
1850 /* Message */
1851 msg_print(p_ptr, "You hack your way through the vegetation.");
1852 }
1853 else
1854 {
1855 /* Message, keep digging */
1856 msg_print(p_ptr, "You attempt to clear a path.");
1857 more = TRUE;
1858 }
1859 }
1860
1861 /* Titanium */
1862 else if (c_ptr->feat >= FEAT_PERM_EXTRA)
1863 {
1864 msg_print(p_ptr, "This seems to be permanent rock.");
1865 }
1866
1867 /* Granite */
1868 else if (c_ptr->feat >= FEAT_WALL_EXTRA)
1869 {
1870 /* Tunnel */
1871 if ((p_ptr->skill_dig > 40 + randint0(1600)) && twall(p_ptr, y, x))
1872 {
1873 msg_print(p_ptr, "You have finished the tunnel.");
1874 }
1875
1876 /* Keep trying */
1877 else
1878 {
1879 /* We may continue tunelling */
1880 msg_print(p_ptr, "You tunnel into the granite wall.");
1881 more = TRUE;
1882 }
1883 }
1884
1885 /* Quartz / Magma */
1886 else if (c_ptr->feat >= FEAT_MAGMA)
1887 {
1888 bool okay = FALSE;
1889 bool gold = FALSE;
1890 bool hard = FALSE;
1891
1892 /* Found gold */
1893 if (c_ptr->feat >= FEAT_MAGMA_H)
1894 {
1895 gold = TRUE;
1896 }
1897
1898 /* Extract "quartz" flag XXX XXX XXX */
1899 if ((c_ptr->feat - FEAT_MAGMA) & 0x01)
1900 {
1901 hard = TRUE;
1902 }
1903
1904 /* Quartz */
1905 if (hard)
1906 {
1907 okay = (p_ptr->skill_dig > 20 + randint0(800));
1908 }
1909
1910 /* Magma */
1911 else
1912 {
1913 okay = (p_ptr->skill_dig > 10 + randint0(400));
1914 }
1915
1916 /* Success */
1917 if (okay && twall(p_ptr, y, x))
1918 {
1919 /* Found treasure */
1920 if (gold)
1921 {
1922 /* Place some gold */
1923 place_gold(Depth, y, x);
1924
1925 /* Message */
1926 msg_print(p_ptr, "You have found something!");
1927 }
1928
1929 /* Found nothing */
1930 else
1931 {
1932 /* Message */
1933 msg_print(p_ptr, "You have finished the tunnel.");
1934 }
1935 }
1936
1937 /* Failure (quartz) */
1938 else if (hard)
1939 {
1940 /* Message, continue digging */
1941 msg_print(p_ptr, "You tunnel into the quartz vein.");
1942 more = TRUE;
1943 }
1944
1945 /* Failure (magma) */
1946 else
1947 {
1948 /* Message, continue digging */
1949 msg_print(p_ptr, "You tunnel into the magma vein.");
1950 more = TRUE;
1951 }
1952 }
1953
1954 /* Rubble */
1955 else if (c_ptr->feat == FEAT_RUBBLE)
1956 {
1957 /* Remove the rubble */
1958 if ((p_ptr->skill_dig > randint0(200)) && twall(p_ptr, y, x))
1959 {
1960 /* Message */
1961 msg_print(p_ptr, "You have removed the rubble.");
1962
1963 /* Hack -- place an object */
1964 if (randint0(100) < 10)
1965 {
1966 /* Create a simple object */
1967 place_object(Depth, y, x, FALSE, FALSE, ORIGIN_RUBBLE);
1968
1969 /* Observe new object */
1970 if (player_can_see_bold(p_ptr, y, x))
1971 {
1972 msg_print(p_ptr, "You have found something!");
1973 }
1974 }
1975 }
1976
1977 else
1978 {
1979 /* Message, keep digging */
1980 msg_print(p_ptr, "You dig in the rubble.");
1981 more = TRUE;
1982 }
1983 }
1984
1985 /* Secret doors */
1986 else if (c_ptr->feat >= FEAT_SECRET)
1987 {
1988 /* Tunnel */
1989 if ((p_ptr->skill_dig > 30 + randint0(1200)) && twall(p_ptr, y, x))
1990 {
1991 msg_print(p_ptr, "You have finished the tunnel.");
1992 }
1993
1994 /* Keep trying */
1995 else
1996 {
1997 /* We may continue tunelling */
1998 msg_print(p_ptr, "You tunnel into the granite wall.");
1999 more = TRUE;
2000
2001 /* Occasional Search XXX XXX */
2002 if (randint0(100) < 25) search(p_ptr);
2003 }
2004 }
2005
2006 /* Doors */
2007 else
2008 {
2009 /* Tunnel */
2010 if ((p_ptr->skill_dig > 30 + randint0(1200)) && twall(p_ptr, y, x))
2011 {
2012 msg_print(p_ptr, "You have finished the tunnel.");
2013 }
2014
2015 /* Keep trying */
2016 else
2017 {
2018 /* We may continue tunelling */
2019 msg_print(p_ptr, "You tunnel into the door.");
2020 more = TRUE;
2021 }
2022 }
2023
2024 /* Result */
2025 return (more);
2026 }
2027
2028
2029 /*
2030 * Tunnel through "walls" (including rubble and secret doors)
2031 *
2032 * Digging is very difficult without a "digger" weapon, but can be
2033 * accomplished by strong players using heavy weapons.
2034 */
do_cmd_tunnel(player_type * p_ptr,int dir)2035 void do_cmd_tunnel(player_type *p_ptr, int dir)
2036 {
2037 int Depth = p_ptr->dun_depth;
2038
2039 cave_type *c_ptr;
2040
2041 int y, x;
2042
2043 bool more = FALSE;
2044
2045 /* Check preventive inscription '^T' */
2046 __trap(p_ptr, CPI(p_ptr, 'T'));
2047
2048 /* Get a direction (or abort) */
2049 /*if (!get_rep_dir(&dir)) return;*/
2050 if (!VALID_DIR(dir)) return;
2051
2052 /* Get location */
2053 y = p_ptr->py + ddy[dir];
2054 x = p_ptr->px + ddx[dir];
2055
2056 /* Oops */
2057 if (!do_cmd_tunnel_test(p_ptr, y, x)) return;
2058
2059 /* Take a turn */
2060 p_ptr->energy -= level_speed(p_ptr->dun_depth);
2061
2062 /* Apply confusion */
2063 if (confuse_dir((bool)p_ptr->confused, &dir))
2064 {
2065 /* Get location */
2066 y = p_ptr->py + ddy[dir];
2067 x = p_ptr->px + ddx[dir];
2068 }
2069
2070 /* Get grid and contents */
2071 c_ptr = &cave[Depth][y][x];
2072
2073 /* Allow repeated command */
2074 if (p_ptr->command_arg)
2075 {
2076 /* Set repeat count */
2077 /* p_ptr->command_rep = p_ptr->command_arg - 1; */
2078
2079 /* Redraw the state */
2080 p_ptr->redraw |= (PR_STATE);
2081
2082 /* Cancel the arg */
2083 p_ptr->command_arg = 0;
2084 }
2085
2086 /* Monster */
2087 if (c_ptr->m_idx > 0)
2088 {
2089 /* Message */
2090 msg_print(p_ptr, "There is a monster in the way!");
2091
2092 /* Attack */
2093 py_attack(p_ptr, y, x);
2094 }
2095
2096 /* Player in the way */
2097 else if (c_ptr->m_idx < 0)
2098 {
2099 /* Message */
2100 msg_print(p_ptr, "There is a player in the way!");
2101 }
2102
2103 /* Walls */
2104 else
2105 {
2106 /* Tunnel through walls */
2107 more = do_cmd_tunnel_aux(p_ptr, y, x);
2108 }
2109
2110 /* Cancel repetition unless we can continue */
2111 if (!more) disturb(p_ptr, 0, 0);
2112 }
2113
2114
2115 /*
2116 * Determine if a given grid may be "disarmed"
2117 */
do_cmd_disarm_test(player_type * p_ptr,int y,int x)2118 static bool do_cmd_disarm_test(player_type *p_ptr, int y, int x)
2119 {
2120 int Depth = p_ptr->dun_depth;
2121
2122 cave_type *c_ptr;
2123 object_type *o_ptr;
2124
2125
2126 /* Ghosts cannot disarm */
2127 if ( (p_ptr->ghost || p_ptr->fruit_bat) && !(p_ptr->dm_flags & DM_GHOST_HANDS) )
2128 {
2129 /* Message */
2130 msg_print(p_ptr, "You cannot disarm things!");
2131
2132 return (FALSE);
2133 }
2134
2135 /* Get grid and contents */
2136 c_ptr = &cave[Depth][y][x];
2137
2138 /* Access the item */
2139 o_ptr = &o_list[c_ptr->o_idx];
2140
2141 /* Must have knowledge */
2142 if (!(p_ptr->cave_flag[y][x] & (CAVE_MARK)))
2143 {
2144 /* Message */
2145 msg_print(p_ptr, "You see nothing there.");
2146
2147 /* Nope */
2148 return (FALSE);
2149 }
2150
2151 /* Require an actual trap */
2152 if (!((c_ptr->feat >= FEAT_TRAP_HEAD) &&
2153 (c_ptr->feat <= FEAT_TRAP_TAIL)))
2154 {
2155 /* Message */
2156 msg_print(p_ptr, "You see nothing there to disarm.");
2157
2158 /* Nope */
2159 return (FALSE);
2160 }
2161
2162 /* Okay */
2163 return (TRUE);
2164 }
2165
2166
2167 /*
2168 * Perform the basic "disarm" command
2169 *
2170 * Assume there is no monster blocking the destination
2171 *
2172 * Returns TRUE if repeated commands may continue
2173 */
do_cmd_disarm_aux(player_type * p_ptr,int y,int x,int dir)2174 static bool do_cmd_disarm_aux(player_type *p_ptr, int y, int x, int dir)
2175 {
2176 int Depth = p_ptr->dun_depth;
2177
2178 cave_type *c_ptr;
2179
2180 int i, j, power;
2181
2182 cptr name;
2183
2184 bool more = FALSE;
2185
2186
2187 /* Verify legality */
2188 if (!do_cmd_disarm_test(p_ptr, y, x)) return (FALSE);
2189
2190 /* Get grid and contents */
2191 c_ptr = &cave[Depth][y][x];
2192
2193 /* Get the trap name */
2194 name = (f_name + f_info[c_ptr->feat].name);
2195
2196 /* Get the "disarm" factor */
2197 i = p_ptr->skill_dis;
2198
2199 /* Penalize some conditions */
2200 if (p_ptr->blind || no_lite(p_ptr)) i = i / 10;
2201 if (p_ptr->confused || p_ptr->image) i = i / 10;
2202
2203 /* XXX XXX XXX Variable power? */
2204
2205 /* Extract trap "power" */
2206 power = 5;
2207
2208 /* Extract the difficulty */
2209 j = i - power;
2210
2211 /* Always have a small chance of success */
2212 if (j < 2) j = 2;
2213
2214 /* Success */
2215 if (randint0(100) < j)
2216 {
2217 /* Message */
2218 msg_format_type(p_ptr, MSG_DISARM, "You have disarmed the %s.", name);
2219 sound(p_ptr, MSG_DISARM);
2220
2221 /* Reward */
2222 gain_exp(p_ptr, power);
2223
2224 /* Forget the trap */
2225 everyone_forget_spot(Depth, y, x);
2226
2227 /* Remove the trap */
2228 /* cave_set_feat(Depth, y, x, FEAT_FLOOR); */
2229 c_ptr->feat = FEAT_FLOOR;
2230
2231 /* Notice */
2232 note_spot_depth(Depth, y, x);
2233
2234 /* Redisplay the grid */
2235 everyone_lite_spot(Depth, y, x);
2236 #if 0
2237 /* move the player onto the trap grid */
2238 move_player(p_ptr, dir, FALSE);
2239 #endif
2240 }
2241
2242 /* Failure -- Keep trying */
2243 else if ((i > 5) && (randint1(i) > 5))
2244 {
2245 /* Failure */
2246 /*if (flush_failure) flush();*/
2247
2248 /* Message */
2249 msg_format(p_ptr, "You failed to disarm the %s.", name);
2250
2251 /* We may keep trying */
2252 more = TRUE;
2253 }
2254
2255 /* Failure -- Set off the trap */
2256 else
2257 {
2258 /* Message */
2259 msg_format(p_ptr, "You set off the %s!", name);
2260
2261 /* Hit the trap */
2262 /*hit_trap(y, x); in MAngband we move.. some hack..? */
2263 /* Move the player onto the trap */
2264 move_player(p_ptr, dir, FALSE);
2265 }
2266
2267 /* Result */
2268 return (more);
2269 }
2270
2271
2272 /*
2273 * Disarms a trap, or a chest
2274 */
do_cmd_disarm(player_type * p_ptr,int dir)2275 void do_cmd_disarm(player_type *p_ptr, int dir)
2276 {
2277 int Depth = p_ptr->dun_depth;
2278
2279 cave_type *c_ptr;
2280 object_type *o_ptr;
2281
2282 int y, x;
2283
2284 s16b o_idx;
2285
2286 bool more = FALSE;
2287
2288 /* Check preventive inscription '^D' */
2289 __trap(p_ptr, CPI(p_ptr, 'D'));
2290
2291 #if 0
2292 /* Easy Disarm */
2293 if (p_ptr->easy_open)
2294 {
2295 int num_traps, num_chests;
2296
2297 /* Count visible traps */
2298 num_traps = count_feats(&y, &x, is_trap, TRUE);
2299
2300 /* Count chests (trapped) */
2301 num_chests = count_chests(&y, &x, TRUE);
2302
2303 /* See if only one target */
2304 if (num_traps || num_chests)
2305 {
2306 if (num_traps + num_chests <= 1)
2307 p_ptr->command_dir = motion_dir(p_ptr->py, p_ptr->px, y, x);
2308 }
2309 }
2310
2311 /* Get a direction (or abort) */
2312 if (!get_rep_dir(&dir)) return;
2313 #endif
2314 if (!VALID_DIR(dir)) return;
2315
2316 /* Get location */
2317 y = p_ptr->py + ddy[dir];
2318 x = p_ptr->px + ddx[dir];
2319
2320 /* Get grid and contents */
2321 c_ptr = &cave[Depth][y][x];
2322
2323 /* Access the item */
2324 o_ptr = &o_list[c_ptr->o_idx];
2325
2326 /* Check for chests */
2327 o_idx = (o_ptr->tval == TV_CHEST ? c_ptr->o_idx : 0);
2328
2329
2330 /* Verify legality */
2331 if (!o_idx && !do_cmd_disarm_test(p_ptr, y, x)) return;
2332
2333
2334 /* Take a turn */
2335 p_ptr->energy -= level_speed(p_ptr->dun_depth);
2336
2337 /* Apply confusion */
2338 if (confuse_dir((bool)p_ptr->confused, &dir))
2339 {
2340 /* Get location */
2341 y = p_ptr->py + ddy[dir];
2342 x = p_ptr->px + ddx[dir];
2343
2344 /* Get grid and contents */
2345 c_ptr = &cave[Depth][y][x];
2346
2347 /* Access the item */
2348 o_ptr = &o_list[c_ptr->o_idx];
2349
2350 /* Check for chests */
2351 o_idx = (o_ptr->tval == TV_CHEST ? c_ptr->o_idx : 0);
2352 }
2353
2354
2355 /* Allow repeated command */
2356 if (p_ptr->command_arg)
2357 {
2358 /* Set repeat count */
2359 /* p_ptr->command_rep = p_ptr->command_arg - 1; */
2360
2361 /* Redraw the state */
2362 p_ptr->redraw |= (PR_STATE);
2363
2364 /* Cancel the arg */
2365 p_ptr->command_arg = 0;
2366 }
2367
2368 /* Monster */
2369 if (c_ptr->m_idx > 0)
2370 {
2371 /* Message */
2372 msg_print(p_ptr, "There is a monster in the way!");
2373
2374 /* Attack */
2375 py_attack(p_ptr, y, x);
2376 }
2377
2378 /* Player in the way */
2379 else if (c_ptr->m_idx < 0)
2380 {
2381 /* Message */
2382 msg_print(p_ptr, "There is a player in the way!");
2383 }
2384
2385 /* Chest */
2386 else if (o_idx)
2387 {
2388 /* Disarm the chest */
2389 more = do_cmd_disarm_chest(p_ptr, y, x, o_idx);
2390 }
2391
2392 /* Disarm trap */
2393 else
2394 {
2395 /* Disarm the trap */
2396 more = do_cmd_disarm_aux(p_ptr, y, x, dir);
2397 }
2398
2399 /* Cancel repeat unless told not to */
2400 if (!more) disturb(p_ptr, 0, 0);
2401 }
2402
2403 /*
2404 * Determine if a given grid may be "bashed"
2405 */
do_cmd_bash_test(player_type * p_ptr,int y,int x)2406 static bool do_cmd_bash_test(player_type *p_ptr, int y, int x)
2407 {
2408 int Depth = p_ptr->dun_depth;
2409
2410 cave_type *c_ptr;
2411
2412
2413 /* Ghosts cannot bash */
2414 if ( (p_ptr->ghost || p_ptr->fruit_bat) && !(p_ptr->dm_flags & DM_GHOST_HANDS) )
2415 {
2416 /* Message */
2417 msg_print(p_ptr, "You cannot bash things!");
2418
2419 return (FALSE);
2420 }
2421
2422 /* Get grid and contents */
2423 c_ptr = &cave[Depth][y][x];
2424
2425 /* Must have knowledge */
2426 if (!(p_ptr->cave_flag[y][x] & (CAVE_MARK)))
2427 {
2428 /* Message */
2429 msg_print(p_ptr, "You see nothing there.");
2430
2431 /* Nope */
2432 return (FALSE);
2433 }
2434
2435 /* Require a door */
2436 if (!((c_ptr->feat >= FEAT_DOOR_HEAD) &&
2437 (c_ptr->feat <= FEAT_DOOR_TAIL)))
2438 {
2439 /* Message */
2440 msg_print(p_ptr, "You see nothing there to bash.");
2441
2442 /* Nope */
2443 return (FALSE);
2444 }
2445
2446 /* Okay */
2447 return (TRUE);
2448 }
2449
2450
2451 /*
2452 * Perform the basic "bash" command
2453 *
2454 * Assume there is no monster blocking the destination
2455 *
2456 * Returns TRUE if repeated commands may continue
2457 */
do_cmd_bash_aux(player_type * p_ptr,int y,int x)2458 static bool do_cmd_bash_aux(player_type *p_ptr, int y, int x)
2459 {
2460 int Depth = p_ptr->dun_depth;
2461
2462 cave_type *c_ptr;
2463
2464 int bash, temp;
2465
2466 bool more = FALSE;
2467
2468
2469 /* Verify legality */
2470 if (!do_cmd_bash_test(p_ptr, y, x)) return (FALSE);
2471
2472 /* Get grid and contents */
2473 c_ptr = &cave[Depth][y][x];
2474
2475 /* Message */
2476 msg_print(p_ptr, "You smash into the door!");
2477
2478 /* Hack -- Bash power based on strength */
2479 /* (Ranges from 3 to 20 to 100 to 200) */
2480 bash = adj_str_blow[p_ptr->stat_ind[A_STR]];
2481
2482 /* Extract door power */
2483 temp = ((c_ptr->feat - FEAT_DOOR_HEAD) & 0x07);
2484
2485 /* Compare bash power to door power XXX XXX XXX */
2486 temp = (bash - (temp * 10));
2487
2488 /* Hack -- always have a chance */
2489 if (temp < 1) temp = 1;
2490
2491 /* Hack -- attempt to bash down the door */
2492 if (randint0(100) < temp)
2493 {
2494 /* Message */
2495 msg_print_aux(p_ptr, "The door crashes open!", MSG_OPENDOOR);
2496 sound(p_ptr, MSG_OPENDOOR);
2497
2498 /* Break down the door */
2499 if (randint0(100) < 50)
2500 {
2501 c_ptr->feat = FEAT_BROKEN;
2502 }
2503
2504 /* Open the door */
2505 else
2506 {
2507 c_ptr->feat = FEAT_OPEN;
2508 }
2509
2510 /* Notice */
2511 note_spot_depth(Depth, y, x);
2512
2513 /* Redraw */
2514 everyone_lite_spot(Depth, y, x);
2515 #if 0
2516 /* Hack -- Fall through the door */
2517 move_player(p_ptr, dir, FALSE);
2518 #endif
2519 /* Update some things */
2520 p_ptr->update |= (PU_VIEW | PU_LITE);
2521 p_ptr->update |= (PU_DISTANCE);
2522 }
2523
2524 /* Saving throw against stun */
2525 else if (randint0(100) < adj_dex_safe[p_ptr->stat_ind[A_DEX]] +
2526 p_ptr->lev)
2527 {
2528 /* Message */
2529 msg_print(p_ptr, "The door holds firm.");
2530
2531 /* Allow repeated bashing */
2532 more = TRUE;
2533 }
2534
2535 /* High dexterity yields coolness */
2536 else
2537 {
2538 /* Message */
2539 msg_print(p_ptr, "You are off-balance.");
2540
2541 /* Hack -- Lose balance ala paralysis */
2542 (void)set_paralyzed(p_ptr, p_ptr->paralyzed + 2 + randint0(2));
2543 }
2544
2545 /* Result */
2546 return (more);
2547 }
2548
2549
2550 /*
2551 * Bash open a door, success based on character strength
2552 *
2553 * For a closed door, pval is positive if locked; negative if stuck.
2554 *
2555 * For an open door, pval is positive for a broken door.
2556 *
2557 * A closed door can be opened - harder if locked. Any door might be
2558 * bashed open (and thereby broken). Bashing a door is (potentially)
2559 * faster! You move into the door way. To open a stuck door, it must
2560 * be bashed. A closed door can be jammed (see do_cmd_spike()).
2561 *
2562 * Creatures can also open or bash doors, see elsewhere.
2563 */
do_cmd_bash(player_type * p_ptr,int dir)2564 void do_cmd_bash(player_type *p_ptr, int dir)
2565 {
2566 int Depth = p_ptr->dun_depth;
2567
2568 cave_type *c_ptr;
2569
2570 int y, x;
2571
2572 /* Check preventive inscription '^B' */
2573 __trap(p_ptr, CPI(p_ptr, 'B'));
2574
2575 /* Get a direction (or abort) */
2576 /* if (!get_rep_dir(&dir)) return; */
2577 if (!VALID_DIR(dir)) return;
2578
2579 /* Get location */
2580 y = p_ptr->py + ddy[dir];
2581 x = p_ptr->px + ddx[dir];
2582
2583 /* Verify legality */
2584 if (!do_cmd_bash_test(p_ptr, y, x)) return;
2585
2586
2587 /* Take a turn */
2588 p_ptr->energy -= level_speed(p_ptr->dun_depth);
2589
2590 /* Apply confusion */
2591 if (confuse_dir((bool)p_ptr->confused, &dir))
2592 {
2593 /* Get location */
2594 y = p_ptr->py + ddy[dir];
2595 x = p_ptr->px + ddx[dir];
2596 }
2597
2598 /* Get grid */
2599 c_ptr = &cave[Depth][y][x];
2600
2601 /* Allow repeated command */
2602 if (p_ptr->command_arg)
2603 {
2604 /* Set repeat count */
2605 /*p_ptr->command_rep = p_ptr->command_arg - 1;*/
2606
2607 /* Redraw the state */
2608 p_ptr->redraw |= (PR_STATE);
2609
2610 /* Cancel the arg */
2611 p_ptr->command_arg = 0;
2612 }
2613
2614 /* Monster */
2615 if (c_ptr->m_idx > 0)
2616 {
2617 /* Message */
2618 msg_print(p_ptr, "There is a monster in the way!");
2619
2620 /* Attack */
2621 py_attack(p_ptr, y, x);
2622 }
2623
2624 /* Player in the way */
2625 else if (c_ptr->m_idx < 0)
2626 {
2627 /* Message */
2628 msg_print(p_ptr, "There is a player in the way!");
2629 }
2630
2631 /* Door */
2632 else
2633 {
2634 /* Bash the door */
2635 if (!do_cmd_bash_aux(p_ptr, y, x))
2636 {
2637 /* Cancel repeat */
2638 disturb(p_ptr, 0, 0);
2639 }
2640 }
2641 }
2642
2643
2644
2645
2646
2647
2648 /*
2649 * Manipulate an adjacent grid in some way
2650 *
2651 * Attack monsters, tunnel through walls, disarm traps, open doors.
2652 *
2653 * <s>This command must always take energy, to prevent free detection
2654 * of invisible monsters.</s>
2655 * REVISED FOR MAngband-specific reasons: we don't care if someone
2656 * detects a monster by tunneling into it, and treat "tunnel air" as an
2657 * error, which DOES NOT spend player's energy. This is a classic MAnghack,
2658 * updated to newer V306 realities.
2659 *
2660 * The "semantics" of this command must be chosen before the player
2661 * is confused, and it must be verified against the new grid.
2662 */
do_cmd_alter(player_type * p_ptr,int dir)2663 void do_cmd_alter(player_type *p_ptr, int dir)
2664 {
2665 int Depth = p_ptr->dun_depth;
2666 int y, x;
2667
2668 int feat;
2669
2670 bool more = FALSE;
2671 bool spend = TRUE;
2672
2673 cave_type *c_ptr;
2674
2675 /* Check preventive inscription '^+' */
2676 __trap(p_ptr, CPI(p_ptr, '+'));
2677
2678 /* Get a direction */
2679 if (!VALID_DIR(dir)) return;
2680
2681 /* Apply confusion */
2682 confuse_dir((bool)p_ptr->confused, &dir);
2683
2684 /* Get location */
2685 y = p_ptr->py + ddy[dir];
2686 x = p_ptr->px + ddx[dir];
2687
2688 /* MEGA-HACK! DM HOOK! */
2689 if (p_ptr->master_hook[1])
2690 master_new_hook(p_ptr, 'a', y, x);
2691
2692 /* Get grid */
2693 c_ptr = &cave[Depth][y][x];
2694
2695 /* Original feature */
2696 feat = c_ptr->feat;
2697
2698 /* Must have knowledge to know feature XXX XXX */
2699 if (!(p_ptr->cave_flag[y][x] & (CAVE_MARK))) feat = FEAT_NONE;
2700
2701 /* Allow repeated command */
2702 if (p_ptr->command_arg)
2703 {
2704 /* Set repeat count */
2705 /*p_ptr->command_rep = p_ptr->command_arg - 1;*/
2706
2707 /* Redraw the state */
2708 p_ptr->redraw |= (PR_STATE);
2709
2710 /* Cancel the arg */
2711 p_ptr->command_arg = 0;
2712 }
2713
2714 /* Attack monsters */
2715 if (c_ptr->m_idx > 0)
2716 {
2717 /* Attack */
2718 py_attack(p_ptr, y, x);
2719 }
2720
2721 /* MAngband-specific: Open closed House doors */
2722 else if (feat >= FEAT_HOME_HEAD && feat <= FEAT_HOME_TAIL)
2723 {
2724 /* Open */
2725 more = do_cmd_open_aux(p_ptr, y, x);
2726 }
2727
2728 /* MAngband-specific: Open walls (House Creation) */
2729 else if (feat == FEAT_PERM_EXTRA)
2730 {
2731 /* Open */
2732 more = do_cmd_open_aux(p_ptr, y, x);
2733 }
2734
2735 /* Tunnel through walls */
2736 else if (feat >= FEAT_SECRET)
2737 {
2738 /* Tunnel */
2739 more = do_cmd_tunnel_aux(p_ptr, y, x);
2740 }
2741 #if 0
2742 /* Bash jammed doors */
2743 else if (feat >= FEAT_DOOR_HEAD + 0x08)
2744 {
2745 /* Bash */
2746 more = do_cmd_bash_aux(p_ptr, y, x);
2747 }
2748 #endif /* 0 */
2749 /* Open closed doors */
2750 else if (feat >= FEAT_DOOR_HEAD)
2751 {
2752 /* Open */
2753 more = do_cmd_open_aux(p_ptr, y, x);
2754 }
2755
2756 /* Disarm traps */
2757 else if (feat >= FEAT_TRAP_HEAD)
2758 {
2759 /* Disarm */
2760 more = do_cmd_disarm_aux(p_ptr, y, x, dir);
2761 }
2762 #if 0
2763 /* Close open doors */
2764 else if (feat == FEAT_OPEN)
2765 {
2766 /* Close */
2767 more = do_cmd_close_aux(y, x);
2768 }
2769 #endif
2770
2771 /* Oops */
2772 else
2773 {
2774 /* Oops */
2775 msg_print(p_ptr, "You spin around.");
2776 /* Do not spend energy. */
2777 spend = FALSE;
2778 }
2779
2780 if (spend)
2781 {
2782 /* Take a turn */
2783 p_ptr->energy -= level_speed(p_ptr->dun_depth);
2784 }
2785
2786 /* Cancel repetition unless we can continue */
2787 if (!more) disturb(p_ptr, 0, 0);
2788 }
2789
2790
2791
2792 /*
2793 * Find the index of some "spikes", if possible.
2794 *
2795 * XXX XXX XXX Let user choose a pile of spikes, perhaps?
2796 */
get_spike(player_type * p_ptr,int * ip)2797 static bool get_spike(player_type *p_ptr, int *ip)
2798 {
2799 int i;
2800
2801 /* Check every item in the pack */
2802 for (i = 0; i < INVEN_PACK; i++)
2803 {
2804 object_type *o_ptr = &(p_ptr->inventory[i]);
2805
2806 /* Check the "tval" code */
2807 if (o_ptr->tval == TV_SPIKE)
2808 {
2809 /* Save the spike index */
2810 (*ip) = i;
2811
2812 /* Success */
2813 return (TRUE);
2814 }
2815 }
2816
2817 /* Oops */
2818 return (FALSE);
2819 }
2820
2821
2822 /*
2823 * Jam a closed door with a spike
2824 *
2825 * This command may NOT be repeated
2826 */
do_cmd_spike(player_type * p_ptr,int dir)2827 void do_cmd_spike(player_type *p_ptr, int dir)
2828 {
2829 int Depth = p_ptr->dun_depth;
2830
2831 int y, x, item;
2832
2833 cave_type *c_ptr;
2834
2835 /* Check preventive inscription '^j' */
2836 __trap(p_ptr, CPI(p_ptr, 'j'));
2837
2838 /* Ghosts cannot spike */
2839 if ( (p_ptr->ghost || p_ptr->fruit_bat) && !(p_ptr->dm_flags & DM_GHOST_HANDS) )
2840 {
2841 /* Message */
2842 msg_print(p_ptr, "You cannot spike doors!");
2843
2844 return;
2845 }
2846
2847 /* Get a "repeated" direction */
2848 if (VALID_DIR(dir))
2849 {
2850 /* Get location */
2851 y = p_ptr->py + ddy[dir];
2852 x = p_ptr->px + ddx[dir];
2853
2854 /* Get grid and contents */
2855 c_ptr = &cave[Depth][y][x];
2856
2857 /* Require closed door */
2858 if (!((c_ptr->feat >= FEAT_DOOR_HEAD) &&
2859 (c_ptr->feat <= FEAT_DOOR_TAIL)))
2860 {
2861 /* Message */
2862 msg_print(p_ptr, "You see nothing there to spike.");
2863 }
2864
2865 /* Get a spike */
2866 else if (!get_spike(p_ptr, &item))
2867 {
2868 /* Message */
2869 msg_print(p_ptr, "You have no spikes!");
2870 }
2871
2872 /* Is a monster in the way? */
2873 else if (c_ptr->m_idx > 0)
2874 {
2875 /* Take a turn */
2876 p_ptr->energy -= level_speed(p_ptr->dun_depth);
2877
2878 /* Message */
2879 msg_print(p_ptr, "There is a monster in the way!");
2880
2881 /* Attack */
2882 py_attack(p_ptr, y, x);
2883 }
2884
2885 /* Go for it */
2886 else
2887 {
2888 /* Take a turn */
2889 p_ptr->energy -= level_speed(p_ptr->dun_depth);
2890
2891 /* Successful jamming */
2892 msg_print(p_ptr, "You jam the door with a spike.");
2893
2894 /* Convert "locked" to "stuck" XXX XXX XXX */
2895 if (c_ptr->feat < FEAT_DOOR_HEAD + 0x08) c_ptr->feat += 0x08;
2896
2897 /* Add one spike to the door */
2898 if (c_ptr->feat < FEAT_DOOR_TAIL) c_ptr->feat++;
2899
2900 /* Use up, and describe, a single spike, from the bottom */
2901 inven_item_increase(p_ptr, item, -1);
2902 inven_item_describe(p_ptr, item);
2903 inven_item_optimize(p_ptr, item);
2904 }
2905 }
2906 }
2907
2908 /*
2909 * Clicked somewhere on the dungeon.
2910 *
2911 * "mod" can contain any MCURSOR_XXX flag, except for
2912 * MCURSOR_EMB and MCURSOR_META (so buttons 1, 2, 3 and
2913 * modifiers CTRL, ALT, SHIFT).
2914 */
do_cmd_mouseclick(player_type * p_ptr,int mod,int y,int x)2915 void do_cmd_mouseclick(player_type *p_ptr, int mod, int y, int x)
2916 {
2917 /* Right now, we only support 1 mouse button */
2918 if (!(mod & MCURSOR_LMB)) return;
2919
2920 y = y + p_ptr->panel_row_min;
2921 x = x + p_ptr->panel_col_min;
2922
2923 if (x < p_ptr->panel_col_min) x = p_ptr->panel_col_min;
2924 if (y < p_ptr->panel_row_min) y = p_ptr->panel_row_min;
2925 if (x > p_ptr->panel_col_max) x = p_ptr->panel_col_max;
2926 if (y > p_ptr->panel_row_max) y = p_ptr->panel_row_max;
2927
2928 /* Hack -- execute '_' ? */
2929 if ((mod & MCURSOR_LMB) && (mod & MCURSOR_SHFT))
2930 {
2931 /* Grid offset is 0 (standing on) */
2932 if (p_ptr->px == x && p_ptr->py == y)
2933 {
2934 do_cmd_enterfeat(p_ptr);
2935 }
2936 return;
2937 }
2938
2939 /* Hack -- execute alter? */
2940 if ((mod & MCURSOR_LMB) && (mod & MCURSOR_KTRL))
2941 {
2942 /* Grid is nearby */
2943 if (ABS(p_ptr->px - x) <= 1 && ABS(p_ptr->py - y) <= 1)
2944 {
2945 int dir = motion_dir(p_ptr->py, p_ptr->px, y, x);
2946 do_cmd_alter(p_ptr, dir);
2947 }
2948 return;
2949 }
2950
2951 do_cmd_pathfind(p_ptr, y, x);
2952 }
2953
2954
2955 /*
2956 * Support code for the "Walk" and "Jump" commands
2957 */
do_cmd_walk(player_type * p_ptr,int dir,int pickup)2958 void do_cmd_walk(player_type *p_ptr, int dir, int pickup)
2959 {
2960 cave_type *c_ptr;
2961
2962 bool more = FALSE;
2963
2964 /* Check preventive inscription '^;' */
2965 __trap(p_ptr, CPI(p_ptr, ';'));
2966
2967 /* Make sure he hasn't just switched levels */
2968 if (p_ptr->new_level_flag) return;
2969
2970 /* Allow repeated command */
2971 if (p_ptr->command_arg)
2972 {
2973 /* Set repeat count */
2974 /*command_rep = command_arg - 1;*/
2975
2976 /* Redraw the state */
2977 p_ptr->redraw |= (PR_STATE);
2978
2979 /* Cancel the arg */
2980 p_ptr->command_arg = 0;
2981 }
2982
2983 /* Get a "repeated" direction */
2984 if (VALID_DIR(dir))
2985 {
2986 /* Hack -- handle confusion */
2987 if (p_ptr->confused)
2988 {
2989 dir = 5;
2990
2991 /* Prevent walking nowhere */
2992 while (dir == 5)
2993 dir = ddd[randint0(8)];
2994 }
2995
2996 /* Handle the "easy_alter" option */
2997 if (option_p(p_ptr,EASY_ALTER))
2998 {
2999 /* Get requested grid */
3000 c_ptr = &cave[p_ptr->dun_depth][p_ptr->py+ddy[dir]][p_ptr->px+ddx[dir]];
3001
3002 if ((p_ptr->cave_flag[p_ptr->py+ddy[dir]][p_ptr->px+ddx[dir]] & (CAVE_MARK)) &&
3003 (((c_ptr->feat >= FEAT_TRAP_HEAD) &&
3004 (c_ptr->feat <= FEAT_DOOR_TAIL)) ||
3005 ((c_ptr->feat >= FEAT_HOME_HEAD) &&
3006 (c_ptr->feat <= FEAT_HOME_TAIL))))
3007 {
3008 do_cmd_alter(p_ptr, dir);
3009 return;
3010 }
3011 }
3012
3013 /* Handle the "bump_open" option */
3014 /* Hack -- Same as "easy_alter", but ignores traps */
3015 if (option_p(p_ptr,BUMP_OPEN))
3016 {
3017 /* Get requested grid */
3018 c_ptr = &cave[p_ptr->dun_depth][p_ptr->py+ddy[dir]][p_ptr->px+ddx[dir]];
3019
3020 if ((p_ptr->cave_flag[p_ptr->py+ddy[dir]][p_ptr->px+ddx[dir]] & (CAVE_MARK)) &&
3021 (((c_ptr->feat >= FEAT_DOOR_HEAD) &&
3022 (c_ptr->feat <= FEAT_DOOR_TAIL)) ||
3023 ((c_ptr->feat >= FEAT_HOME_HEAD) &&
3024 (c_ptr->feat <= FEAT_HOME_TAIL))))
3025 {
3026 do_cmd_alter(p_ptr, dir);
3027 return;
3028 }
3029 }
3030
3031 /* Actually move the character */
3032 move_player(p_ptr, dir, pickup);
3033
3034 /* Hack -- don't spend energy if player attacked someone */
3035 /* Because we have already spent an appropriate amount elsewhere */
3036 if (!p_ptr->dealt_blows) {
3037
3038 /* Take a turn */
3039 p_ptr->energy -= level_speed(p_ptr->dun_depth);
3040
3041 }/* End Hack */
3042
3043 /* Allow more walking */
3044 more = TRUE;
3045 }
3046
3047 /* Cancel repeat unless we may continue */
3048 if (!more) disturb(p_ptr, 0, 0);
3049 }
3050
3051
3052
3053 /*
3054 * Start running.
3055 */
do_cmd_run(player_type * p_ptr,int dir)3056 int do_cmd_run(player_type *p_ptr, int dir)
3057 {
3058 cave_type *c_ptr;
3059
3060 /* Check preventive inscription '^.' */
3061 if (CPI(p_ptr, '.')) { msg_print(p_ptr, "The item's inscription prevents it."); return 0; }
3062
3063 /* Classic MAnghack #3. */
3064 /* Treat this as a walk request
3065 * -- instead of disallowing running when confused */
3066 if (p_ptr->confused)
3067 {
3068 /* BUT NOT IN TOWN ... */
3069 if (p_ptr->dun_depth)
3070 {
3071 do_cmd_walk(p_ptr, dir, option_p(p_ptr, ALWAYS_PICKUP));
3072 return 1;
3073 }
3074 }
3075
3076 if (p_ptr->confused)
3077 {
3078 msg_print(p_ptr, "You are too confused!");
3079 return 0;
3080 }
3081
3082 /* Ignore if we are already running in this direction */
3083 if (p_ptr->running && (dir == p_ptr->find_current) ) return 1;
3084
3085 /* Get a "repeated" direction */
3086 if (VALID_DIR(dir))
3087 {
3088 /* Make sure we have an empty space to run into */
3089 if (see_wall(p_ptr, dir, p_ptr->py, p_ptr->px) && p_ptr->energy >= level_speed(p_ptr->dun_depth))
3090 {
3091 /* Handle the "easy_alter" option */
3092 if (option_p(p_ptr,EASY_ALTER))
3093 {
3094 /* Get requested grid */
3095 c_ptr = &cave[p_ptr->dun_depth][p_ptr->py+ddy[dir]][p_ptr->px+ddx[dir]];
3096
3097 if ((p_ptr->cave_flag[p_ptr->py+ddy[dir]][p_ptr->px+ddx[dir]] & (CAVE_MARK)) &&
3098 (((c_ptr->feat >= FEAT_TRAP_HEAD) &&
3099 (c_ptr->feat <= FEAT_DOOR_TAIL)) ||
3100 ((c_ptr->feat >= FEAT_HOME_HEAD) &&
3101 (c_ptr->feat <= FEAT_HOME_TAIL))))
3102 {
3103 /* Check if we have enough energy to alter grid */
3104 if (p_ptr->energy >= level_speed(p_ptr->dun_depth))
3105 {
3106 /* If so, do it. */
3107 do_cmd_alter(p_ptr, dir);
3108 }
3109 return 1;
3110 }
3111 }
3112
3113 /* Handle the "bump_open" option */
3114 /* Hack -- same as "easy_alter", but ignores traps */
3115 if (option_p(p_ptr,BUMP_OPEN))
3116 {
3117 /* Get requested grid */
3118 c_ptr = &cave[p_ptr->dun_depth][p_ptr->py+ddy[dir]][p_ptr->px+ddx[dir]];
3119
3120 if ((p_ptr->cave_flag[p_ptr->py+ddy[dir]][p_ptr->px+ddx[dir]] & (CAVE_MARK)) &&
3121 (((c_ptr->feat >= FEAT_DOOR_HEAD) &&
3122 (c_ptr->feat <= FEAT_DOOR_TAIL)) ||
3123 ((c_ptr->feat >= FEAT_HOME_HEAD) &&
3124 (c_ptr->feat <= FEAT_HOME_TAIL))))
3125 {
3126 /* Check if we have enough energy to alter grid */
3127 if (p_ptr->energy >= level_speed(p_ptr->dun_depth))
3128 {
3129 /* If so, do it. */
3130 do_cmd_alter(p_ptr, dir);
3131 }
3132 return 1;
3133 }
3134 }
3135
3136 /* Message */
3137 msg_print(p_ptr, "You cannot run in that direction.");
3138
3139 /* Disturb */
3140 disturb(p_ptr, 0, 0);
3141
3142 return 1;
3143 }
3144
3145 /* Initialise running */
3146 p_ptr->run_request = dir;
3147 p_ptr->running = FALSE;
3148 p_ptr->ran_tiles = 0;
3149 }
3150 return 1;
3151 }
3152
3153
3154
3155 /*
3156 * Stay still. Search. Enter stores.
3157 * Pick up treasure if "pickup" is true.
3158 */
do_cmd_hold_or_stay(player_type * p_ptr,int pickup,int take_stairs)3159 void do_cmd_hold_or_stay(player_type *p_ptr, int pickup, int take_stairs)
3160 {
3161 int Depth = p_ptr->dun_depth;
3162 cave_type *c_ptr;
3163
3164 if (p_ptr->new_level_flag) return;
3165
3166 c_ptr = &cave[Depth][p_ptr->py][p_ptr->px];
3167
3168
3169 /* Allow repeated command */
3170 if (p_ptr->command_arg)
3171 {
3172 /* Set repeat count */
3173 /*command_rep = command_arg - 1;*/
3174
3175 /* Redraw the state */
3176 p_ptr->redraw |= (PR_STATE);
3177
3178 /* Cancel the arg */
3179 p_ptr->command_arg = 0;
3180 }
3181
3182
3183 /* We don't want any of this */
3184 #if 0
3185 /* Take a turn */
3186 p_ptr->energy -= level_speed(p_ptr->dun_depth);
3187
3188
3189 /* Spontaneous Searching */
3190 if ((p_ptr->skill_fos >= 50) || (0 == randint0(50 - p_ptr->skill_fos)))
3191 {
3192 search(p_ptr);
3193 }
3194
3195 /* Continuous Searching */
3196 if (p_ptr->searching)
3197 {
3198 search(p_ptr);
3199 }
3200 #endif
3201
3202
3203 /* Hack -- enter a store if we are on one */
3204 if ((c_ptr->feat >= FEAT_SHOP_HEAD) &&
3205 (c_ptr->feat <= FEAT_SHOP_TAIL))
3206 {
3207 /* Disturb */
3208 disturb(p_ptr, 0, 0);
3209
3210 /* Hack -- enter store */
3211 /*command_new = '_';*/
3212 }
3213
3214
3215 /* Try to Pick up anything under us */
3216 carry(p_ptr, pickup, 0);
3217
3218 /* Hack -- enter stairs if we are on one */
3219 if (take_stairs)
3220 {
3221 if (c_ptr->feat == FEAT_MORE)
3222 {
3223 do_cmd_go_down(p_ptr);
3224 }
3225 if (c_ptr->feat == FEAT_LESS)
3226 {
3227 do_cmd_go_up(p_ptr);
3228 }
3229 }
3230 }
3231
3232 /*
3233 * Hold still (always pickup and enter stairs)
3234 */
do_cmd_enterfeat(player_type * p_ptr)3235 void do_cmd_enterfeat(player_type *p_ptr)
3236 {
3237 /* Hold still (always pickup, enter stairs) */
3238 do_cmd_hold_or_stay(p_ptr, TRUE, TRUE);
3239 }
3240
3241 /*
3242 * Hold still (always pickup)
3243 */
do_cmd_hold(player_type * p_ptr)3244 void do_cmd_hold(player_type *p_ptr)
3245 {
3246 /* Hold still (always pickup) */
3247 do_cmd_hold_or_stay(p_ptr, TRUE, FALSE);
3248 }
3249
3250 /*
3251 * Stay still (usually do not pickup)
3252 */
do_cmd_stay(player_type * p_ptr)3253 void do_cmd_stay(player_type *p_ptr)
3254 {
3255 /* Stay still (usually do not pickup) */
3256 do_cmd_hold_or_stay(p_ptr, !option_p(p_ptr,ALWAYS_PICKUP), FALSE);
3257 }
3258
3259
3260
3261 /*
3262 * Toggle rest mode.
3263 */
do_cmd_toggle_rest(player_type * p_ptr)3264 void do_cmd_toggle_rest(player_type *p_ptr)
3265 {
3266 /* Set flag */
3267 p_ptr->resting = TRUE;
3268
3269 /* Make sure we aren't running */
3270 p_ptr->running = FALSE;
3271
3272 /* Take a lot of energy to enter "rest mode" */
3273 p_ptr->energy -= (level_speed(p_ptr->dun_depth));
3274
3275 /* Redraw */
3276 p_ptr->redraw |= (PR_STATE);
3277 }
3278
3279 /*
3280 * Resting allows a player to safely restore his hp -RAK-
3281 */
3282 #if 0
3283 void do_cmd_rest(void)
3284 {
3285 /* Prompt for time if needed */
3286 if (p_ptr->command_arg <= 0)
3287 {
3288 cptr p = "Rest (0-9999, '*' for HP/SP, '&' as needed): ";
3289
3290 char out_val[80];
3291
3292 /* Default */
3293 strcpy(out_val, "&");
3294
3295 /* Ask for duration */
3296 if (!get_string(p, out_val, 4)) return;
3297
3298 /* Rest until done */
3299 if (out_val[0] == '&')
3300 {
3301 p_ptr->command_arg = (-2);
3302 }
3303
3304 /* Rest a lot */
3305 else if (out_val[0] == '*')
3306 {
3307 p_ptr->command_arg = (-1);
3308 }
3309
3310 /* Rest some */
3311 else
3312 {
3313 p_ptr->command_arg = atoi(out_val);
3314 if (p_ptr->command_arg <= 0) return;
3315 }
3316 }
3317
3318
3319 /* Paranoia */
3320 if (p_ptr->command_arg > 9999) p_ptr->command_arg = 9999;
3321
3322
3323 /* Take a turn XXX XXX XXX (?) */
3324 energy -= level_speed(p_ptr->dun_depth);
3325
3326 /* Save the rest code */
3327 resting = p_ptr->command_arg;
3328
3329 /* Cancel searching */
3330 p_ptr->searching = FALSE;
3331
3332 /* Recalculate bonuses */
3333 p_ptr->update |= (PU_BONUS);
3334
3335 /* Redraw the state */
3336 p_ptr->redraw |= (PR_STATE);
3337
3338 /* Handle stuff */
3339 handle_stuff();
3340
3341 /* Refresh */
3342 Term_fresh();
3343 }
3344 #endif
3345
3346
3347 /*
3348 * Start running with pathfinder.
3349 *
3350 * Note that running while confused is not allowed.
3351 */
do_cmd_pathfind(player_type * p_ptr,int y,int x)3352 void do_cmd_pathfind(player_type *p_ptr, int y, int x)
3353 {
3354 /* Hack -- translate nearby grid into walk request */
3355 if (ABS(p_ptr->px - x) <= 1 && ABS(p_ptr->py - y) <= 1)
3356 {
3357 int dir = motion_dir(p_ptr->py, p_ptr->px, y, x);
3358 do_cmd_walk(p_ptr, dir, option_p(p_ptr, ALWAYS_PICKUP));
3359 return;
3360 }
3361
3362 /* Hack XXX XXX XXX */
3363 if (p_ptr->confused)
3364 {
3365 /* TODO: Maybe convert to walk request? */
3366 msg_print(p_ptr, "You are too confused!");
3367 return;
3368 }
3369
3370 if (findpath(p_ptr, y, x))
3371 {
3372 p_ptr->running_withpathfind = TRUE;
3373 p_ptr->run_request = -1;
3374 #if 0 /* In MAngband, we just schedule for later */
3375 // /* Calculate torch radius */
3376 // p_ptr->update |= (PU_TORCH);
3377 // run_step(p_ptr, 0);
3378 #endif
3379 }
3380 }
3381
3382
3383
3384
3385 /*
3386 * Determines the odds of an object breaking when thrown at a monster
3387 *
3388 * Note that artifacts never break, see the "drop_near()" function.
3389 */
breakage_chance(object_type * o_ptr)3390 static int breakage_chance(object_type *o_ptr)
3391 {
3392 /* Examine the item type */
3393 switch (o_ptr->tval)
3394 {
3395 /* Always break */
3396 case TV_FLASK:
3397 case TV_POTION:
3398 case TV_BOTTLE:
3399 case TV_FOOD:
3400 case TV_JUNK:
3401 {
3402 return (100);
3403 }
3404
3405 /* Often break */
3406 case TV_LITE:
3407 case TV_SCROLL:
3408 case TV_ARROW:
3409 case TV_SKELETON:
3410 {
3411 return (50);
3412 }
3413
3414 /* Sometimes break */
3415 case TV_WAND:
3416 case TV_SHOT:
3417 case TV_BOLT:
3418 case TV_SPIKE:
3419 {
3420 return (25);
3421 }
3422 }
3423
3424 /* Rarely break */
3425 return (10);
3426 }
3427
3428
3429 /*
3430 * Fire an object from the pack or floor.
3431 *
3432 * You may only fire items that "match" your missile launcher.
3433 *
3434 * You must use slings + pebbles/shots, bows + arrows, xbows + bolts.
3435 *
3436 * See "calc_bonuses()" for more calculations and such.
3437 *
3438 * Note that "firing" a missile is MUCH better than "throwing" it.
3439 *
3440 * Note: "unseen" monsters are very hard to hit.
3441 *
3442 * Objects are more likely to break if they "attempt" to hit a monster.
3443 *
3444 * Rangers (with Bows) and Anyone (with "Extra Shots") get extra shots.
3445 *
3446 * The "extra shot" code works by decreasing the amount of energy
3447 * required to make each shot, spreading the shots out over time.
3448 *
3449 * Note that when firing missiles, the launcher multiplier is applied
3450 * after all the bonuses are added in, making multipliers very useful.
3451 *
3452 * Note that Bows of "Extra Might" get extra range and an extra bonus
3453 * for the damage multiplier.
3454 *
3455 * Note that Bows of "Extra Shots" give an extra shot.
3456 */
do_cmd_fire(player_type * p_ptr,int item,int dir)3457 void do_cmd_fire(player_type *p_ptr, int item, int dir)
3458 {
3459 player_type *q_ptr;
3460 int Depth = p_ptr->dun_depth;
3461
3462 int i, j, y, x, ny, nx, ty, tx;
3463 int tdam, tdis, thits, tmul;
3464 int bonus, chance;
3465 int cur_dis, visible;
3466
3467 object_type throw_obj;
3468 object_type *o_ptr;
3469
3470 object_type *j_ptr;
3471
3472 bool hit_body = FALSE;
3473
3474 int missile_attr;
3475 int missile_char;
3476
3477 char o_name[80];
3478 bool magic = FALSE;
3479
3480 /* Check preventive inscription '^f' */
3481 __trap(p_ptr, CPI(p_ptr, 'f'));
3482
3483 /* Restrict ghosts */
3484 if ( (p_ptr->ghost || p_ptr->fruit_bat) && !(p_ptr->dm_flags & DM_GHOST_HANDS) )
3485 {
3486 msg_print(p_ptr, "You cannot shoot!");
3487 return;
3488 }
3489
3490 /* Get the "bow" (if any) */
3491 j_ptr = &(p_ptr->inventory[INVEN_BOW]);
3492
3493 /* Require a launcher */
3494 if (!j_ptr->tval)
3495 {
3496 msg_print(p_ptr, "You have nothing to fire with.");
3497 return;
3498 }
3499
3500
3501 /* Require proper missile */
3502 item_tester_tval = p_ptr->tval_ammo;
3503
3504 if (!item_tester_tval)
3505 {
3506 msg_print(p_ptr, "You have nothing to fire.");
3507 return;
3508 }
3509
3510 /* Access the item (if in the pack) */
3511 if (item >= 0)
3512 {
3513 o_ptr = &(p_ptr->inventory[item]);
3514 }
3515 else
3516 {
3517 item = -cave[p_ptr->dun_depth][p_ptr->py][p_ptr->px].o_idx;
3518 o_ptr = &o_list[0 - item];
3519 }
3520
3521 /* Check guard inscription '!f' */
3522 __trap(p_ptr, CGI(o_ptr, 'f'));
3523
3524 if (o_ptr->tval != p_ptr->tval_ammo)
3525 {
3526 msg_print(p_ptr, "You cannot fire that!");
3527 return;
3528 }
3529
3530 if (!o_ptr->tval)
3531 {
3532 msg_print(p_ptr, "You cannot fire that!");
3533 return;
3534 }
3535
3536 /* Magic ammo */
3537 if ((o_ptr->sval == SV_AMMO_MAGIC) || artifact_p(o_ptr))
3538 magic = TRUE;
3539
3540 /* Get a direction (or cancel) */
3541 p_ptr->command_dir = dir;
3542 if (!get_aim_dir(p_ptr, &dir)) return;
3543
3544 /* Create a "local missile object" */
3545 throw_obj = *o_ptr;
3546 throw_obj.number = 1;
3547
3548 if (!magic)
3549 {
3550 /* Reduce and describe inventory */
3551 if (item >= 0)
3552 {
3553 inven_item_increase(p_ptr, item, -1);
3554 inven_item_describe(p_ptr, item);
3555 inven_item_optimize(p_ptr, item);
3556 }
3557
3558 /* Reduce and describe floor item */
3559 else
3560 {
3561 floor_item_increase(0 - item, -1);
3562 floor_item_optimize(0 - item);
3563 floor_item_notify(p_ptr, 0 - item, TRUE);
3564 }
3565 }
3566
3567 /* Use the missile object */
3568 o_ptr = &throw_obj;
3569
3570 /* Sound */
3571 sound(p_ptr, MSG_SHOOT);
3572
3573 /* Describe the object */
3574 object_desc(p_ptr, o_name, sizeof(o_name), o_ptr, FALSE, 3);
3575
3576 /* Find the color and symbol for the object for throwing */
3577 missile_attr = object_attr_p(p_ptr, o_ptr);
3578 missile_char = object_char_p(p_ptr, o_ptr);
3579
3580
3581 /* Use the proper number of shots */
3582 thits = p_ptr->num_fire;
3583
3584 /* Use a base distance */
3585 tdis = 10;
3586
3587 /* Base damage from thrown object plus launcher bonus */
3588 tdam = damroll(o_ptr->dd, o_ptr->ds) + o_ptr->to_d + j_ptr->to_d;
3589
3590 /* Actually "fire" the object */
3591 bonus = (p_ptr->to_h + o_ptr->to_h + j_ptr->to_h);
3592 chance = (p_ptr->skill_thb + (bonus * BTH_PLUS_ADJ));
3593
3594 /* Assume a base multiplier */
3595 tmul = 1;
3596
3597 /* Analyze the launcher */
3598 switch (j_ptr->sval)
3599 {
3600 /* Sling and ammo */
3601 case SV_SLING:
3602 {
3603 tmul = 2;
3604 break;
3605 }
3606
3607 /* Short Bow and Arrow */
3608 case SV_SHORT_BOW:
3609 {
3610 tmul = 2;
3611 break;
3612 }
3613
3614 /* Long Bow and Arrow */
3615 case SV_LONG_BOW:
3616 {
3617 tmul = 3;
3618 break;
3619 }
3620
3621 /* Light Crossbow and Bolt */
3622 case SV_LIGHT_XBOW:
3623 {
3624 tmul = 3;
3625 break;
3626 }
3627
3628 /* Heavy Crossbow and Bolt */
3629 case SV_HEAVY_XBOW:
3630 {
3631 tmul = 4;
3632 break;
3633 }
3634 }
3635
3636 /* Get extra "power" from "extra might" */
3637 if (p_ptr->xtra_might) tmul++;
3638
3639 /* Boost the damage */
3640 tdam *= tmul;
3641
3642 /* Base range */
3643 tdis = 10 + 5 * tmul;
3644
3645
3646 /* Take a (partial) turn */
3647 p_ptr->energy -= (level_speed(p_ptr->dun_depth) / thits);
3648
3649
3650 /* Start at the player */
3651 y = p_ptr->py;
3652 x = p_ptr->px;
3653
3654 /* Predict the "target" location */
3655 tx = p_ptr->px + 99 * ddx[dir];
3656 ty = p_ptr->py + 99 * ddy[dir];
3657
3658 /* Check for "target request" */
3659 if ((dir == 5) && target_okay(p_ptr))
3660 {
3661 tx = p_ptr->target_col;
3662 ty = p_ptr->target_row;
3663 }
3664
3665
3666 /* Hack -- Handle stuff */
3667 handle_stuff(p_ptr);
3668
3669
3670 /* Travel until stopped */
3671 for (cur_dis = 0; cur_dis <= tdis; )
3672 {
3673 /* Hack -- Stop at the target */
3674 if ((y == ty) && (x == tx)) break;
3675
3676 /* Calculate the new location (see "project()") */
3677 ny = y;
3678 nx = x;
3679 mmove2(&ny, &nx, p_ptr->py, p_ptr->px, ty, tx);
3680
3681 /* Stopped by walls/doors */
3682 if (!cave_floor_bold(Depth, ny, nx)) break;
3683
3684 /* Advance the distance */
3685 cur_dis++;
3686
3687 /* Save the new location */
3688 x = nx;
3689 y = ny;
3690
3691 /* Save the old "player pointer" */
3692 q_ptr = p_ptr;
3693
3694 /* Display it for each player */
3695 for (i = 1; i <= NumPlayers; i++)
3696 {
3697 int dispx, dispy;
3698
3699 /* Use this player */
3700 p_ptr = Players[i];
3701
3702 /* If he's not here, skip him */
3703 if (p_ptr->dun_depth != Depth)
3704 continue;
3705
3706 /* The player can see the (on screen) missile */
3707 if (panel_contains(p_ptr, y, x) && player_can_see_bold(p_ptr, y, x))
3708 {
3709 /* Draw, Hilite, Fresh, Pause, Erase */
3710 dispy = y - p_ptr->panel_row_prt;
3711 dispx = x - p_ptr->panel_col_prt;
3712
3713 /* Remember the projectile */
3714 //p_ptr->scr_info[dispy][dispx].c = missile_char;
3715 //p_ptr->scr_info[dispy][dispx].a = missile_attr;
3716
3717 /* Tell the client */
3718 //Stream_tile(i, p_ptr, dispy, dispx);
3719
3720 /* Tell the client */
3721 (void)send_air_char(p_ptr, dispy, dispx, missile_attr, missile_char, cur_dis, 1);
3722
3723 /* Flush and wait */
3724 //if (cur_dis % tmul) Send_flush(i);
3725
3726 /* Restore */
3727 //lite_spot(i, y, x);
3728 }
3729
3730 /* The player cannot see the missile */
3731 else
3732 {
3733 /* Pause anyway, for consistancy */
3734 /*Term_xtra(TERM_XTRA_DELAY, msec);*/
3735 }
3736 }
3737
3738 /* Restore the player pointer */
3739 p_ptr = q_ptr;
3740
3741 /* Player here, hit him */
3742 if (cave[Depth][y][x].m_idx < 0)
3743 {
3744 cave_type *c_ptr = &cave[Depth][y][x];
3745
3746 q_ptr = Players[0 - c_ptr->m_idx];
3747
3748 /* AD hack cntd -- "pass over" if players aren't hostile */
3749 if (!pvp_okay(p_ptr, q_ptr, (p_ptr->target_who == c_ptr->m_idx ? 2 : 3) ))
3750 {
3751 continue;
3752 }
3753
3754 /* Check the visibility */
3755 visible = p_ptr->play_vis[0 - c_ptr->m_idx];
3756
3757 /* Note the collision */
3758 hit_body = TRUE;
3759
3760 /* Did we hit it (penalize range) */
3761 if (test_hit_fire(chance - cur_dis, q_ptr->ac + q_ptr->to_a, visible))
3762 {
3763 char pvp_name[80];
3764
3765 /* Get the name */
3766 my_strcpy(pvp_name, q_ptr->name, 80);
3767
3768 /* Handle unseen player */
3769 if (!visible)
3770 {
3771 /* Invisible player */
3772 msg_format(p_ptr, "The %s finds a mark.", o_name);
3773 sound(p_ptr, MSG_SHOOT_HIT);
3774 msg_format(q_ptr, "You are hit by a %s!", o_name);
3775 }
3776
3777 /* Handle visible player */
3778 else
3779 {
3780 /* Messages */
3781 msg_format(p_ptr, "The %s hits %s.", o_name, pvp_name);
3782 sound(p_ptr, MSG_SHOOT_HIT);
3783 msg_format(q_ptr, "%^s hits you with a %s.", p_ptr->name, o_name);
3784
3785 /* Track this player's health */
3786 health_track(p_ptr, c_ptr->m_idx);
3787 }
3788
3789 /* Apply special damage XXX XXX XXX */
3790 tdam = tot_dam_aux_player(o_ptr, tdam, q_ptr);
3791 tdam = critical_shot(p_ptr, o_ptr->weight, o_ptr->to_h, tdam);
3792
3793 /* No negative damage */
3794 if (tdam < 0) tdam = 0;
3795
3796 /* XXX Reduce damage by 1/3 */
3797 tdam = (tdam + 2) / 3;
3798
3799 /* Take damage */
3800 take_hit(q_ptr, tdam, p_ptr->name);
3801
3802 /* Stop looking */
3803 break;
3804 }
3805 }
3806
3807 /* Monster here, Try to hit it */
3808 if (cave[Depth][y][x].m_idx > 0)
3809 {
3810 cave_type *c_ptr = &cave[Depth][y][x];
3811
3812 monster_type *m_ptr = &m_list[c_ptr->m_idx];
3813 monster_race *r_ptr = &r_info[m_ptr->r_idx];
3814
3815 /* Check the visibility */
3816 visible = p_ptr->mon_vis[c_ptr->m_idx];
3817
3818 /* Note the collision */
3819 hit_body = TRUE;
3820
3821 /* Did we hit it (penalize range) */
3822 if (test_hit_fire(chance - cur_dis, r_ptr->ac, visible))
3823 {
3824 bool fear = FALSE;
3825
3826 /* Assume a default death */
3827 cptr note_dies = " dies.";
3828
3829 /* Some monsters get "destroyed" */
3830 if ((r_ptr->flags3 & RF3_DEMON) ||
3831 (r_ptr->flags3 & RF3_UNDEAD) ||
3832 (r_ptr->flags2 & RF2_STUPID) ||
3833 (strchr("Evg", r_ptr->d_char)))
3834 {
3835 /* Special note at death */
3836 note_dies = " is destroyed.";
3837 }
3838
3839
3840 /* Handle unseen monster */
3841 if (!visible)
3842 {
3843 /* Invisible monster */
3844 msg_format(p_ptr, "The %s finds a mark.", o_name);
3845 }
3846
3847 /* Handle visible monster */
3848 else
3849 {
3850 char m_name[80];
3851
3852 /* Get "the monster" or "it" */
3853 monster_desc(p_ptr, m_name, c_ptr->m_idx, 0);
3854
3855 /* Message */
3856 msg_format(p_ptr, "The %s hits %s.", o_name, m_name);
3857
3858 /* Hack -- Track this monster race */
3859 if (visible) monster_race_track(p_ptr, m_ptr->r_idx);
3860
3861 /* Hack -- Track this monster */
3862 if (visible) health_track(p_ptr, c_ptr->m_idx);
3863 }
3864
3865 /* Apply special damage XXX XXX XXX */
3866 tdam = tot_dam_aux(p_ptr, o_ptr, tdam, m_ptr, p_ptr->mon_vis[c_ptr->m_idx]);
3867 tdam = critical_shot(p_ptr, o_ptr->weight, o_ptr->to_h, tdam);
3868
3869 /* No negative damage */
3870 if (tdam < 0) tdam = 0;
3871
3872 /* Complex message */
3873 if (is_dm_p(p_ptr))
3874 {
3875 msg_format(p_ptr, "You do %d (out of %d) damage.",
3876 tdam, m_ptr->hp);
3877 }
3878
3879 /* Hit the monster, check for death */
3880 if (mon_take_hit(p_ptr, c_ptr->m_idx, tdam, &fear, note_dies))
3881 {
3882 /* Dead monster */
3883 }
3884
3885 /* No death */
3886 else
3887 {
3888 /* Message */
3889 message_pain(p_ptr, c_ptr->m_idx, tdam);
3890
3891 /* Take note */
3892 if (fear && visible && !(r_ptr->flags2 & RF2_WANDERER))
3893 {
3894 char m_name[80];
3895
3896 /* Sound */
3897 sound(p_ptr, MSG_FLEE);
3898
3899 /* Get the monster name (or "it") */
3900 monster_desc(p_ptr, m_name, c_ptr->m_idx, 0);
3901
3902 /* Message */
3903 msg_format(p_ptr, "%^s flees in terror!", m_name);
3904 }
3905 }
3906
3907 /* Stop looking */
3908 break;
3909 }
3910 }
3911 }
3912
3913 /* Chance of breakage (during attacks) */
3914 j = (hit_body ? breakage_chance(o_ptr) : 0);
3915
3916 /* Drop (or break) near that location */
3917 if (!magic) drop_near(o_ptr, j, Depth, y, x);
3918 }
3919
3920
3921
3922 /*
3923 * Throw an object from the pack or floor.
3924 *
3925 * Note: "unseen" monsters are very hard to hit.
3926 *
3927 * Should throwing a weapon do full damage? Should it allow the magic
3928 * to hit bonus of the weapon to have an effect? Should it ever cause
3929 * the item to be destroyed? Should it do any damage at all?
3930 */
do_cmd_throw(player_type * p_ptr,int item,int dir)3931 void do_cmd_throw(player_type *p_ptr, int item, int dir)
3932 {
3933 player_type *q_ptr;
3934 int Depth = p_ptr->dun_depth;
3935
3936 int i, j, y, x, ny, nx, ty, tx;
3937 int chance, tdam, tdis;
3938 int mul, div;
3939 int cur_dis, visible;
3940
3941 object_type throw_obj;
3942 object_type *o_ptr;
3943
3944 bool hit_body = FALSE;
3945
3946 int missile_attr;
3947 int missile_char;
3948 byte item_color;
3949
3950 char o_name[80];
3951
3952 /* Check preventive inscription '^v' */
3953 __trap(p_ptr, CPI(p_ptr, 'v'));
3954
3955 /*int msec = delay_factor * delay_factor * delay_factor;*/
3956
3957 /* Restrict ghosts */
3958 if ( ((p_ptr->ghost) || (p_ptr->fruit_bat && item >= 0)) && !(p_ptr->dm_flags & DM_GHOST_HANDS) )
3959 {
3960 msg_print(p_ptr, "You cannot throw things!");
3961 return;
3962 }
3963
3964 /* Access the item (if in the pack) */
3965 if (item >= 0)
3966 {
3967 o_ptr = &(p_ptr->inventory[item]);
3968 }
3969 else
3970 {
3971 item = -cave[p_ptr->dun_depth][p_ptr->py][p_ptr->px].o_idx;
3972 o_ptr = &o_list[0 - item];
3973 }
3974 if (!o_ptr->tval)
3975 {
3976 msg_print(p_ptr, "There is nothing there to throw");
3977 return;
3978 }
3979
3980 /* Check guard inscription '!v' */
3981 __trap(p_ptr, CGI(o_ptr, 'v'));
3982
3983 /* Never throw artifacts */
3984 if (true_artifact_p(o_ptr))
3985 {
3986 msg_print(p_ptr, "You can not throw this!");
3987 return;
3988 }
3989
3990 /* Get a direction (or cancel) */
3991 p_ptr->command_dir = dir;
3992 if (!get_aim_dir(p_ptr, &dir)) return;
3993
3994 /* Create a "local missile object" */
3995 throw_obj = *o_ptr;
3996 throw_obj.number = 1;
3997
3998 /* Distribute charges of wands, staves, or rods */
3999 distribute_charges(o_ptr, &throw_obj, 1);
4000
4001 /* Reduce and describe inventory */
4002 if (item >= 0)
4003 {
4004 inven_item_increase(p_ptr, item, -1);
4005 inven_item_describe(p_ptr, item);
4006 inven_item_optimize(p_ptr, item);
4007 }
4008
4009 /* Reduce and describe floor item */
4010 else
4011 {
4012 floor_item_increase(0 - item, -1);
4013 floor_item_optimize(0 - item);
4014 floor_item_notify(p_ptr, 0 - item, TRUE);
4015 }
4016
4017 /* Use the local object */
4018 o_ptr = &throw_obj;
4019
4020 /* Description */
4021 object_desc(p_ptr, o_name, sizeof(o_name), o_ptr, FALSE, 3);
4022
4023 /* Find the color and symbol for the object for throwing */
4024 missile_attr = object_attr_p(p_ptr, o_ptr);
4025 missile_char = object_char_p(p_ptr, o_ptr);
4026
4027
4028 /* Extract a "distance multiplier" */
4029 mul = 10;
4030
4031 /* Enforce a minimum "weight" of one pound */
4032 div = ((o_ptr->weight > 10) ? o_ptr->weight : 10);
4033
4034 /* Hack -- Distance -- Reward strength, penalize weight */
4035 tdis = (adj_str_blow[p_ptr->stat_ind[A_STR]] + 20) * mul / div;
4036
4037 /* Max distance of 10 */
4038 if (tdis > 10) tdis = 10;
4039
4040 /* Hack -- Base damage from thrown object */
4041 tdam = damroll(o_ptr->dd, o_ptr->ds) + o_ptr->to_d;
4042
4043 /* Chance of hitting */
4044 chance = (p_ptr->skill_tht + (p_ptr->to_h * BTH_PLUS_ADJ));
4045
4046
4047 /* Take a turn */
4048 p_ptr->energy -= level_speed(p_ptr->dun_depth);
4049
4050
4051 /* Start at the player */
4052 y = p_ptr->py;
4053 x = p_ptr->px;
4054
4055 /* Predict the "target" location */
4056 tx = p_ptr->px + 99 * ddx[dir];
4057 ty = p_ptr->py + 99 * ddy[dir];
4058
4059 /* Check for "target request" */
4060 if ((dir == 5) && target_okay(p_ptr))
4061 {
4062 tx = p_ptr->target_col;
4063 ty = p_ptr->target_row;
4064 }
4065
4066
4067 /* Hack -- Handle stuff */
4068 handle_stuff(p_ptr);
4069
4070
4071 /* Travel until stopped */
4072 for (cur_dis = 0; cur_dis <= tdis; )
4073 {
4074 /* Hack -- Stop at the target */
4075 if ((y == ty) && (x == tx)) break;
4076
4077 /* Calculate the new location (see "project()") */
4078 ny = y;
4079 nx = x;
4080 mmove2(&ny, &nx, p_ptr->py, p_ptr->px, ty, tx);
4081
4082 /* Stopped by walls/doors */
4083 if (!cave_floor_bold(Depth, ny, nx))
4084 {
4085 /* Special case: potion VS house door */
4086 if (o_ptr->tval == TV_POTION &&
4087 cave[Depth][ny][nx].feat >= FEAT_HOME_HEAD &&
4088 cave[Depth][ny][nx].feat <= FEAT_HOME_TAIL)
4089 {
4090 /* Break it */
4091 hit_body = TRUE;
4092
4093 /* Potion color should ignore player's awareness and visuals */
4094 item_color = k_info[o_ptr->k_idx].flavor ?
4095 flavor_info[k_info[o_ptr->k_idx].flavor].d_attr :
4096 k_info[o_ptr->k_idx].d_attr;
4097
4098 /* Find suitable color */
4099 for (i = FEAT_HOME_HEAD; i < FEAT_HOME_TAIL + 1; i++)
4100 {
4101 if (f_info[i].d_attr == item_color || f_info[i].d_attr == color_opposite(item_color))
4102 {
4103 /* Pick a house */
4104 if ((j = pick_house(Depth, ny, nx)) == -1) break;
4105
4106 /* Must own the house */
4107 if (!house_owned_by(p_ptr, j)) break;
4108
4109 /* Chance to fail */
4110 if (randint1(100) > p_ptr->sc) break;
4111
4112 /* Perform colorization */
4113 houses[j].strength = i - FEAT_HOME_HEAD;
4114 cave[Depth][ny][nx].feat = i;
4115 everyone_lite_spot(Depth, ny, nx);
4116
4117 /* Done */
4118 break;
4119 }
4120 }
4121 }
4122 break;
4123 }
4124
4125 /* Advance the distance */
4126 cur_dis++;
4127
4128 /* Save the new location */
4129 x = nx;
4130 y = ny;
4131
4132 /* Save the old "player pointer" */
4133 q_ptr = p_ptr;
4134
4135 /* Display it for each player */
4136 for (i = 1; i <= NumPlayers; i++)
4137 {
4138 int dispx, dispy;
4139
4140 /* Use this player */
4141 p_ptr = Players[i];
4142
4143 /* If he's not here, skip him */
4144 if (p_ptr->dun_depth != Depth)
4145 continue;
4146
4147 /* The player can see the (on screen) missile */
4148 if (panel_contains(p_ptr, y, x) && player_can_see_bold(p_ptr, y, x))
4149 {
4150 /* Draw, Hilite, Fresh, Pause, Erase */
4151 dispy = y - p_ptr->panel_row_prt;
4152 dispx = x - p_ptr->panel_col_prt;
4153
4154 /* Remember the projectile */
4155 //p_ptr->scr_info[dispy][dispx].c = missile_char;
4156 //p_ptr->scr_info[dispy][dispx].a = missile_attr;
4157
4158 /* Tell the client */
4159 //Stream_tile(i, p_ptr, dispy, dispx);
4160
4161 /* Tell the client */
4162 (void)send_air_char(p_ptr, dispy, dispx, missile_attr, missile_char, cur_dis, 1);
4163
4164 /* Flush and wait */
4165 //if (cur_dis % 2) Send_flush(i);
4166
4167 /* Restore */
4168 //lite_spot(i, y, x);
4169 }
4170
4171 /* The player cannot see the missile */
4172 else
4173 {
4174 /* Pause anyway, for consistancy */
4175 /*Term_xtra(TERM_XTRA_DELAY, msec);*/
4176 }
4177 }
4178
4179 /* Restore the player pointer */
4180 p_ptr = q_ptr;
4181
4182
4183 /* Player here, try to hit him */
4184 if (cave[Depth][y][x].m_idx < 0)
4185 {
4186 cave_type *c_ptr = &cave[Depth][y][x];
4187
4188 q_ptr = Players[0 - c_ptr->m_idx];
4189
4190 /* Check the visibility */
4191 visible = p_ptr->play_vis[0 - c_ptr->m_idx];
4192
4193 /* Note the collision */
4194 hit_body = TRUE;
4195
4196 /* Did we hit him (penalize range) */
4197 if (test_hit_fire(chance - cur_dis, q_ptr->ac + q_ptr->to_a, visible))
4198 {
4199 /* Handle unseen player */
4200 if (!visible)
4201 {
4202 /* Messages */
4203 msg_format(p_ptr, "The %s finds a mark!", o_name);
4204 msg_format(q_ptr, "You are hit by a %s!", o_name);
4205 }
4206
4207 /* Don't do damage if players aren't hostile */
4208 if (!pvp_okay(p_ptr, q_ptr, 0))
4209 {
4210 hit_body = FALSE;
4211
4212 /* Messages */
4213 if (visible)
4214 {
4215 msg_format(p_ptr, "%s shrugs off the %s.", q_ptr->name, o_name);
4216 msg_format(q_ptr, "%s throws you %s %s!", p_ptr->name,
4217 (is_a_vowel(o_name[0]) ? "an" : "a"), o_name);
4218 }
4219 /* Stop */
4220 break;
4221 }
4222
4223 /* Handle visible player */
4224 if (visible)
4225 {
4226 /* Messages */
4227 msg_format(p_ptr, "The %s hits %s.", o_name, q_ptr->name);
4228 msg_format(q_ptr, "%s hits you with %s %s!", p_ptr->name,
4229 (is_a_vowel(o_name[0]) ? "an" : "a"), o_name);
4230
4231 /* Track player's health */
4232 health_track(p_ptr, c_ptr->m_idx);
4233 }
4234
4235 /* Apply special damage XXX XXX XXX */
4236 tdam = tot_dam_aux_player(o_ptr, tdam, q_ptr);
4237 tdam = critical_shot(p_ptr, o_ptr->weight, o_ptr->to_h, tdam);
4238
4239 /* No negative damage */
4240 if (tdam < 0) tdam = 0;
4241
4242 /* XXX Reduce damage by 1/3 */
4243 tdam = (tdam + 2) / 3;
4244
4245 /* Take damage */
4246 take_hit(q_ptr, tdam, p_ptr->name);
4247
4248 /* Stop looking */
4249 break;
4250 }
4251 }
4252
4253 /* Monster here, Try to hit it */
4254 if (cave[Depth][y][x].m_idx > 0)
4255 {
4256 cave_type *c_ptr = &cave[Depth][y][x];
4257
4258 monster_type *m_ptr = &m_list[c_ptr->m_idx];
4259 monster_race *r_ptr = &r_info[m_ptr->r_idx];
4260
4261 /* Check the visibility */
4262 visible = p_ptr->mon_vis[c_ptr->m_idx];
4263
4264 /* Note the collision */
4265 hit_body = TRUE;
4266
4267 /* Did we hit it (penalize range) */
4268 if (test_hit_fire(chance - cur_dis, r_ptr->ac, visible))
4269 {
4270 bool fear = FALSE;
4271
4272 /* Assume a default death */
4273 cptr note_dies = " dies.";
4274
4275 /* Some monsters get "destroyed" */
4276 if ((r_ptr->flags3 & RF3_DEMON) ||
4277 (r_ptr->flags3 & RF3_UNDEAD) ||
4278 (r_ptr->flags2 & RF2_STUPID) ||
4279 (strchr("Evg", r_ptr->d_char)))
4280 {
4281 /* Special note at death */
4282 note_dies = " is destroyed.";
4283 }
4284
4285
4286 /* Handle unseen monster */
4287 if (!visible)
4288 {
4289 /* Invisible monster */
4290 msg_format(p_ptr, "The %s finds a mark.", o_name);
4291 }
4292
4293 /* Handle visible monster */
4294 else
4295 {
4296 char m_name[80];
4297
4298 /* Get "the monster" or "it" */
4299 monster_desc(p_ptr, m_name, c_ptr->m_idx, 0);
4300
4301 /* Message */
4302 msg_format(p_ptr, "The %s hits %s.", o_name, m_name);
4303
4304 /* Hack -- Track this monster race */
4305 if (visible) monster_race_track(p_ptr, m_ptr->r_idx);
4306
4307 /* Hack -- Track this monster */
4308 if (visible) health_track(p_ptr, c_ptr->m_idx);
4309 }
4310
4311 /* Apply special damage XXX XXX XXX */
4312 tdam = tot_dam_aux(p_ptr, o_ptr, tdam, m_ptr, p_ptr->mon_vis[c_ptr->m_idx]);
4313 tdam = critical_shot(p_ptr, o_ptr->weight, o_ptr->to_h, tdam);
4314
4315 /* No negative damage */
4316 if (tdam < 0) tdam = 0;
4317
4318 /* Complex message */
4319 if (is_dm_p(p_ptr))
4320 {
4321 msg_format(p_ptr, "You do %d (out of %d) damage.",
4322 tdam, m_ptr->hp);
4323 }
4324
4325 /* Hit the monster, check for death */
4326 if (mon_take_hit(p_ptr, c_ptr->m_idx, tdam, &fear, note_dies))
4327 {
4328 /* Dead monster */
4329 }
4330
4331 /* No death */
4332 else
4333 {
4334 /* Message */
4335 message_pain(p_ptr, c_ptr->m_idx, tdam);
4336
4337 /* Take note */
4338 if (fear && visible && !(r_ptr->flags2 & RF2_WANDERER))
4339 {
4340 char m_name[80];
4341
4342 /* Sound */
4343 sound(p_ptr, MSG_FLEE);
4344
4345 /* Get the monster name (or "it") */
4346 monster_desc(p_ptr, m_name, c_ptr->m_idx, 0);
4347
4348 /* Message */
4349 msg_format(p_ptr, "%^s flees in terror!", m_name);
4350 }
4351 }
4352
4353 /* Stop looking */
4354 break;
4355 }
4356 }
4357 }
4358
4359 /* Chance of breakage (during attacks) */
4360 j = (hit_body ? breakage_chance(o_ptr) : 0);
4361
4362 /* Hack -- newbies_cannot_drop -- break item when throwing */
4363 if ((p_ptr->lev == 1) && (cfg_newbies_cannot_drop))
4364 j = 100;
4365
4366 /* Drop (or break) near that location */
4367 drop_near(o_ptr, j, Depth, y, x);
4368 }
4369
4370
4371 /*
4372 * Buy a house. It is assumed that the player already knows the
4373 * price.
4374
4375 Hacked to sell houses for half price. -APD-
4376
4377 */
do_cmd_purchase_house(player_type * p_ptr,int dir)4378 void do_cmd_purchase_house(player_type *p_ptr, int dir)
4379 {
4380 int Depth = p_ptr->dun_depth;
4381
4382 int y, x, i, factor, price;
4383 cave_type *c_ptr;
4384
4385 /* Check preventive inscription '^h' */
4386 __trap(p_ptr, CPI(p_ptr, 'h'));
4387
4388 /* Ghosts cannot buy houses */
4389 if(!(p_ptr->dm_flags & DM_HOUSE_CONTROL)) {
4390 if ( (p_ptr->ghost) || (p_ptr->fruit_bat) )
4391 {
4392 /* Message */
4393 msg_print(p_ptr, "You cannot buy a house.");
4394
4395 return;
4396 }
4397 }
4398
4399 /* Check for no-direction -- confirmation (when selling house) */
4400 if (!VALID_DIR(dir))
4401 {
4402 i = p_ptr->current_house;
4403 p_ptr->current_house = -1;
4404
4405 if (i == -1)
4406 {
4407 /* No house, message */
4408 msg_print(p_ptr, "You see nothing to sell there.");
4409 return;
4410 }
4411
4412 /* Get requested grid */
4413 c_ptr = &cave[Depth][houses[i].door_y][houses[i].door_x];
4414
4415 /* Take player's CHR into account */
4416 factor = adj_chr_gold[p_ptr->stat_ind[A_CHR]];
4417 price = (unsigned long) houses[i].price * factor / 100;
4418
4419 if (house_owned(i))
4420 {
4421 /* Is it owned by this player? */
4422 if (house_owned_by(p_ptr, i))
4423 {
4424 /* house is no longer owned */
4425 disown_house(i);
4426
4427 msg_format(p_ptr, "You sell your house for %ld gold.", price/2);
4428
4429 /* Get the money */
4430 p_ptr->au += price / 2;
4431
4432 /* Redraw */
4433 p_ptr->redraw |= (PR_GOLD);
4434
4435 /* Done */
4436 return;
4437 }
4438 }
4439
4440 /* No house, message */
4441 msg_print(p_ptr, "You don't own this house.");
4442 return;
4443 }
4444
4445 /* Be sure we have a direction */
4446 if (VALID_DIR(dir))
4447 {
4448 /* Get requested direction */
4449 y = p_ptr->py + ddy[dir];
4450 x = p_ptr->px + ddx[dir];
4451
4452 /* Get requested grid */
4453 c_ptr = &cave[Depth][y][x];
4454
4455 /* Check for a house */
4456 if ((i = pick_house(Depth, y, x)) == -1)
4457 {
4458 /* No house, message */
4459 msg_print(p_ptr, "You see nothing to buy there.");
4460 return;
4461 }
4462
4463 /* Take player's CHR into account */
4464 factor = adj_chr_gold[p_ptr->stat_ind[A_CHR]];
4465 price = (unsigned long) houses[i].price * factor / 100;
4466
4467
4468 /* Check for already-owned house */
4469 if (house_owned(i))
4470 {
4471
4472 /* Is it owned by this player? */
4473 if (house_owned_by(p_ptr, i))
4474 {
4475 if (house_inside(p_ptr, i))
4476 {
4477 /* Hack -- Enter own store */
4478 /*command_new = '_';*/
4479 do_cmd_store(p_ptr, i);
4480 }
4481 else
4482 {
4483 /* Delay house transaction */
4484 p_ptr->current_house = i;
4485 /* Tell the client about the price */
4486 send_store_sell(p_ptr, price/2);
4487 }
4488 return;
4489 }
4490
4491 if (p_ptr->dm_flags & DM_HOUSE_CONTROL)
4492 {
4493 disown_house(i);
4494
4495 msg_format(p_ptr, "The house has been reset.");
4496
4497 return;
4498 }
4499
4500 /* Message */
4501 msg_print(p_ptr, "That house is already owned.");
4502
4503 /* No sale */
4504 return;
4505 }
4506
4507 if (Depth == 0)
4508 {
4509 /* houses in town are *ASTRONOMICAL* in price due to location, location, location. */
4510 price =(unsigned long)price *5L;
4511 }
4512
4513 /* Check for enough funds */
4514 if (price > p_ptr->au)
4515 {
4516 /* Not enough money, message */
4517 msg_print(p_ptr, "You do not have enough money.");
4518 return;
4519 }
4520
4521 /* Check if we have too many houses already */
4522 if( cfg_max_houses && houses_owned(p_ptr) >= cfg_max_houses )
4523 {
4524 /* Too many houses owned already */
4525 msg_print(p_ptr, "You own too many houses already.");
4526 return;
4527 }
4528
4529 /* Open the door */
4530 c_ptr->feat = FEAT_HOME_OPEN;
4531
4532 /* Reshow */
4533 everyone_lite_spot(Depth, y, x);
4534
4535 /* Take some of the player's money */
4536 p_ptr->au -= price;
4537
4538 /* The house is now owned */
4539 set_house_owner(p_ptr, i);
4540
4541 /* Redraw */
4542 p_ptr->redraw |= (PR_GOLD);
4543 }
4544 }
4545