1 /*
2 * File: direct.cc
3 * Summary: Functions used when picking squares.
4 * Written by: Linley Henzell
5 *
6 * Change History (most recent first):
7 *
8 * <5> 01/08/01 GDL complete rewrite of direction()
9 * <4> 11/23/99 LRH Looking at monsters now
10 * displays more info
11 * <3> 5/12/99 BWR changes to allow for space selection of target.
12 * CR, ESC, and 't' in targeting.
13 * <2> 5/09/99 JDJ look_around no longer prints a prompt.
14 * <1> -/--/-- LRH Created
15 */
16
17 #include "AppHdr.h"
18 #include "direct.h"
19
20 #include <stdlib.h>
21 #include <string.h>
22 #include <stdio.h>
23
24 #ifdef DOS
25 #include <conio.h>
26 #endif
27
28 #include "externs.h"
29
30 #include "debug.h"
31 #include "describe.h"
32 #include "itemname.h"
33 #include "monstuff.h"
34 #include "mon-util.h"
35 #include "player.h"
36 #include "shopping.h"
37 #include "stuff.h"
38 #include "spells4.h"
39 #include "view.h"
40
41 #ifdef USE_MACROS
42 #include "macro.h"
43 #endif
44
45 // x and y offsets in the following order:
46 // SW, S, SE, W, E, NW, N, NE
47 static const char xcomp[9] = { -1, 0, 1, -1, 0, 1, -1, 0, 1 };
48 static const char ycomp[9] = { 1, 1, 1, 0, 0, 0, -1, -1, -1 };
49 static const char dirchars[19] = { "b1j2n3h4.5l6y7k8u9" };
50 static const char DOSidiocy[10] = { "OPQKSMGHI" };
51 static const char *aim_prompt = "Aim (move cursor or -/+/=, change mode with CTRL-F, select with . or >)";
52
53 static void describe_cell(int mx, int my);
54 static char mons_find( unsigned char xps, unsigned char yps,
55 FixedVector<char, 2> &mfp, char direction,
56 int mode = TARG_ANY );
57
58 //---------------------------------------------------------------
59 //
60 // direction
61 //
62 // input: restricts : DIR_NONE accepts keypad dir or targetting
63 // DIR_TARGET must use targetting.
64 // DIR_DIR must use keypad direction
65 //
66 //
67 // outputs: dist structure:
68 //
69 // isValid a valid target or direction was chosen
70 // isCancel player hit 'escape'
71 // isTarget targetting was used
72 // tx,ty target x,y or logical beam extension to
73 // edge of map if keypad direction used.
74 // dx,dy direction delta if keypad used {-1,0,1}
75 //
76 // SYNOPSIS:
77 //
78 // gets a direction, or any of the follwing:
79 //
80 // * go to targetting mode
81 // +,= go to targetting mode, next monster
82 // - " , prev monster
83 // t,p auto-select previous target
84 //
85 //
86 // targetting mode is handled by look_around()
87 //---------------------------------------------------------------
direction(struct dist & moves,int restrict,int mode)88 void direction( struct dist &moves, int restrict, int mode )
89 {
90 bool dirChosen = false;
91 bool targChosen = false;
92 int dir = 0;
93
94 // init
95 moves.isValid = false;
96 moves.isTarget = false;
97 moves.isMe = false;
98 moves.isCancel = false;
99 moves.dx = moves.dy = 0;
100 moves.tx = moves.ty = 0;
101
102 // XXX. this is ALWAYS in relation to the player. But a bit of a hack
103 // nonetheless! --GDL
104 gotoxy( 18, 9 );
105
106 int keyin = getch();
107
108 if (keyin == 0) // DOS idiocy (emulated by win32 console)
109 {
110 keyin = getch(); // grrr.
111 if (keyin == '*')
112 {
113 targChosen = true;
114 dir = 0;
115 }
116 else
117 {
118 if (strchr(DOSidiocy, keyin) == NULL)
119 return;
120 dirChosen = true;
121 dir = (int)(strchr(DOSidiocy, keyin) - DOSidiocy);
122 }
123 }
124 else
125 {
126 if (strchr( dirchars, keyin ) != NULL)
127 {
128 dirChosen = true;
129 dir = (int)(strchr(dirchars, keyin) - dirchars) / 2;
130 }
131 else
132 {
133 switch (keyin)
134 {
135 case CONTROL('F'):
136 mode = (mode + 1) % TARG_NUM_MODES;
137
138 snprintf( info, INFO_SIZE, "Targeting mode is now: %s",
139 (mode == TARG_ANY) ? "any" :
140 (mode == TARG_ENEMY) ? "enemies"
141 : "friends" );
142
143 mpr( info );
144
145 targChosen = true;
146 dir = 0;
147 break;
148
149 case '-':
150 targChosen = true;
151 dir = -1;
152 break;
153
154 case '*':
155 targChosen = true;
156 dir = 0;
157 break;
158
159 case '+':
160 case '=':
161 targChosen = true;
162 dir = 1;
163 break;
164
165 case 't':
166 case 'p':
167 targChosen = true;
168 dir = 2;
169 break;
170
171 case ESCAPE:
172 moves.isCancel = true;
173 return;
174
175 default:
176 break;
177 }
178 }
179 }
180
181 // at this point, we know exactly the input - validate
182 if (!(targChosen || dirChosen) || (targChosen && restrict == DIR_DIR))
183 {
184 mpr("What an unusual direction.");
185 return;
186 }
187
188 // special case: they typed a dir key, but they're in target-only mode
189 if (dirChosen && restrict == DIR_TARGET)
190 {
191 mpr(aim_prompt);
192 look_around( moves, false, dir, mode );
193 return;
194 }
195
196 if (targChosen)
197 {
198 if (dir < 2)
199 {
200 mpr(aim_prompt);
201 moves.prev_target = dir;
202 look_around( moves, false, -1, mode );
203 if (moves.prev_target != -1) // -1 means they pressed 'p'
204 return;
205 }
206
207 // chose to aim at previous target. do we have one?
208 if (you.prev_targ == MHITNOT || you.prev_targ == MHITYOU)
209 {
210 mpr("You haven't got a target.");
211 return;
212 }
213
214 // we have a valid previous target (maybe)
215 struct monsters *montarget = &menv[you.prev_targ];
216
217 if (!mons_near(montarget) || !player_monster_visible( montarget ))
218 {
219 mpr("You can't see that creature any more.");
220 return;
221 }
222 else
223 {
224 moves.isValid = true;
225 moves.isTarget = true;
226 moves.tx = montarget->x;
227 moves.ty = montarget->y;
228 }
229 return;
230 }
231
232 // at this point, we have a direction, and direction is allowed.
233 moves.isValid = true;
234 moves.isTarget = false;
235 moves.dx = xcomp[dir];
236 moves.dy = ycomp[dir];
237 if (xcomp[dir] == 0 && ycomp[dir] == 0)
238 moves.isMe = true;
239
240 // now the tricky bit - extend the target x,y out to map edge.
241 int mx, my;
242 mx = my = 0;
243
244 if (moves.dx > 0)
245 mx = (GXM - 1) - you.x_pos;
246 if (moves.dx < 0)
247 mx = you.x_pos;
248
249 if (moves.dy > 0)
250 my = (GYM - 1) - you.y_pos;
251 if (moves.dy < 0)
252 my = you.y_pos;
253
254 if (!(mx == 0 || my == 0))
255 {
256 if (mx < my)
257 my = mx;
258 else
259 mx = my;
260 }
261 moves.tx = you.x_pos + moves.dx * mx;
262 moves.ty = you.y_pos + moves.dy * my;
263 }
264
265 //---------------------------------------------------------------
266 //
267 // look_around
268 //
269 // Accessible by the x key and when using cursor aiming. Lets you
270 // find out what symbols mean, and is the way to access monster
271 // descriptions.
272 //
273 // input: dist.prev_target : -1 is last monster
274 // 0 is no monster selected
275 // 1 is next monster
276 //
277 // input: first_move is -1 if no initial cursor move, otherwise
278 // make 1 move in that direction.
279 //
280 //
281 // output: if dist.prev_target is -1 on OUTPUT, it means that
282 // player selected 'p' ot 't' for last targetted monster.
283 //
284 // otherwise, usual dist fields are filled in (dx and dy are
285 // always zero coming back from this function)
286 //
287 //---------------------------------------------------------------
288
look_around(struct dist & moves,bool justLooking,int first_move,int mode)289 void look_around(struct dist &moves, bool justLooking, int first_move, int mode)
290 {
291 int keyin = 0;
292 bool dirChosen = false;
293 bool targChosen = false;
294 int dir = 0;
295 int cx = 17;
296 int cy = 9;
297 int newcx, newcy;
298 int mx, my; // actual map x,y (scratch)
299 int mid; // monster id (scratch)
300 FixedVector < char, 2 > monsfind_pos;
301
302 monsfind_pos[0] = you.x_pos;
303 monsfind_pos[1] = you.y_pos;
304
305 message_current_target();
306
307 // setup initial keystroke
308 if (first_move >= 0)
309 keyin = (int)'1' + first_move;
310 if (moves.prev_target == -1)
311 keyin = '-';
312 if (moves.prev_target == 1)
313 keyin = '+';
314 // reset
315 moves.prev_target = 0;
316
317 // loop until some exit criteria reached
318 while(true)
319 {
320 dirChosen = false;
321 targChosen = false;
322 newcx = cx;
323 newcy = cy;
324
325 // move cursor to current position
326 gotoxy(cx+1, cy);
327
328 if (keyin == 0)
329 keyin = getch();
330
331 // DOS idiocy
332 if (keyin == 0)
333 {
334 // get the extended key
335 keyin = getch();
336
337 // look for CR - change to '5' to indicate selection
338 if (keyin == 13)
339 keyin = 'S';
340
341 if (strchr(DOSidiocy, keyin) == NULL)
342 break;
343 dirChosen = true;
344 dir = (int)(strchr(DOSidiocy, keyin) - DOSidiocy);
345 }
346 else
347 {
348 if (strchr(dirchars, keyin) != NULL)
349 {
350 dirChosen = true;
351 dir = (int)(strchr(dirchars, keyin) - dirchars) / 2;
352 }
353 else
354 {
355 // handle non-directional keys
356 switch (keyin)
357 {
358 case CONTROL('F'):
359 mode = (mode + 1) % TARG_NUM_MODES;
360
361 snprintf( info, INFO_SIZE, "Targeting mode is now: %s",
362 (mode == TARG_ANY) ? "any" :
363 (mode == TARG_ENEMY) ? "enemies"
364 : "friends" );
365
366 mpr( info );
367 targChosen = true;
368 break;
369
370 case '-':
371 if (mons_find( cx, cy, monsfind_pos, -1, mode ) == 0)
372 flush_input_buffer( FLUSH_ON_FAILURE );
373 else
374 {
375 newcx = monsfind_pos[0];
376 newcy = monsfind_pos[1];
377 }
378 targChosen = true;
379 break;
380
381 case '+':
382 case '=':
383 if (mons_find( cx, cy, monsfind_pos, 1, mode ) == 0)
384 flush_input_buffer( FLUSH_ON_FAILURE );
385 else
386 {
387 newcx = monsfind_pos[0];
388 newcy = monsfind_pos[1];
389 }
390 targChosen = true;
391 break;
392
393 case 't':
394 case 'p':
395 moves.prev_target = -1;
396 break;
397
398 case '?':
399 targChosen = true;
400 mx = you.x_pos + cx - 17;
401 my = you.y_pos + cy - 9;
402 mid = mgrd[mx][my];
403
404 if (mid == NON_MONSTER)
405 break;
406
407 #if (!DEBUG_DIAGNOSTICS)
408 if (!player_monster_visible( &menv[mid] ))
409 break;
410 #endif
411
412 describe_monsters( menv[ mid ].type, mid );
413 redraw_screen();
414 mesclr( true );
415 // describe the cell again.
416 describe_cell(you.x_pos + cx - 17, you.y_pos + cy - 9);
417 break;
418
419 case '\r':
420 case '\n':
421 case '>':
422 case ' ':
423 case '.':
424 dirChosen = true;
425 dir = 4;
426 break;
427
428 case ESCAPE:
429 moves.isCancel = true;
430 mesclr( true );
431 return;
432
433 default:
434 break;
435 }
436 }
437 }
438
439 // now we have parsed the input character completely. Reset & Evaluate:
440 keyin = 0;
441 if (!targChosen && !dirChosen)
442 break;
443
444 // check for SELECTION
445 if (dirChosen && dir == 4)
446 {
447 // RULE: cannot target what you cannot see
448 if (env.show[cx - 8][cy] == 0 && !(cx == 17 && cy == 9))
449 {
450 if (!justLooking)
451 mpr("Sorry, you can't target what you can't see.");
452 return;
453 }
454
455 moves.isValid = true;
456 moves.isTarget = true;
457 moves.tx = you.x_pos + cx - 17;
458 moves.ty = you.y_pos + cy - 9;
459
460 if (moves.tx == you.x_pos && moves.ty == you.y_pos)
461 moves.isMe = true;
462 else
463 {
464 // try to set you.previous target
465 mx = you.x_pos + cx - 17;
466 my = you.y_pos + cy - 9;
467 mid = mgrd[mx][my];
468
469 if (mid == NON_MONSTER)
470 break;
471
472 if (!player_monster_visible( &(menv[mid]) ))
473 break;
474
475 you.prev_targ = mid;
476 }
477 break;
478 }
479
480 // check for MOVE
481 if (dirChosen)
482 {
483 newcx = cx + xcomp[dir];
484 newcy = cy + ycomp[dir];
485 }
486
487 // bounds check for newcx, newcy
488 if (newcx < 9) newcx = 9;
489 if (newcx > 25) newcx = 25;
490 if (newcy < 1) newcy = 1;
491 if (newcy > 17) newcy = 17;
492
493 // no-op if the cursor doesn't move.
494 if (newcx == cx && newcy == cy)
495 continue;
496
497 // CURSOR MOVED - describe new cell.
498 cx = newcx;
499 cy = newcy;
500 mesclr( true );
501 if (env.show[cx - 8][cy] == 0 && !(cx == 17 && cy == 9))
502 {
503 mpr("You can't see that place.");
504 continue;
505 }
506 describe_cell(you.x_pos + cx - 17, you.y_pos + cy - 9);
507 } // end WHILE
508
509 mesclr( true );
510 } // end look_around()
511
512 //---------------------------------------------------------------
513 //
514 // mons_find
515 //
516 // Finds the next monster (moving in a spiral outwards from the
517 // player, so closer monsters are chosen first; starts to player's
518 // left) and puts its coordinates in mfp. Returns 1 if it found
519 // a monster, zero otherwise. If direction is -1, goes backwards.
520 //
521 //---------------------------------------------------------------
mons_find(unsigned char xps,unsigned char yps,FixedVector<char,2> & mfp,char direction,int mode)522 static char mons_find( unsigned char xps, unsigned char yps,
523 FixedVector<char, 2> &mfp, char direction, int mode )
524 {
525 unsigned char temp_xps = xps;
526 unsigned char temp_yps = yps;
527 char x_change = 0;
528 char y_change = 0;
529
530 int i, j;
531
532 if (direction == 1 && temp_xps == 9 && temp_yps == 17)
533 return (0); // end of spiral
534
535 while (temp_xps >= 8 && temp_xps <= 25 && temp_yps <= 17) // yps always >= 0
536 {
537 if (direction == -1 && temp_xps == 17 && temp_yps == 9)
538 return (0); // can't go backwards from you
539
540 if (direction == 1)
541 {
542 if (temp_xps == 8)
543 {
544 x_change = 0;
545 y_change = -1;
546 }
547 else if (temp_xps - 17 == 0 && temp_yps - 9 == 0)
548 {
549 x_change = -1;
550 y_change = 0;
551 }
552 else if (abs(temp_xps - 17) <= abs(temp_yps - 9))
553 {
554 if (temp_xps - 17 >= 0 && temp_yps - 9 <= 0)
555 {
556 if (abs(temp_xps - 17) > abs(temp_yps - 9 + 1))
557 {
558 x_change = 0;
559 y_change = -1;
560 if (temp_xps - 17 > 0)
561 y_change = 1;
562 goto finished_spiralling;
563 }
564 }
565 x_change = -1;
566 if (temp_yps - 9 < 0)
567 x_change = 1;
568 y_change = 0;
569 }
570 else
571 {
572 x_change = 0;
573 y_change = -1;
574 if (temp_xps - 17 > 0)
575 y_change = 1;
576 }
577 } // end if (direction == 1)
578 else
579 {
580 /*
581 This part checks all eight surrounding squares to find the
582 one that leads on to the present square.
583 */
584 for (i = -1; i < 2; i++)
585 {
586 for (j = -1; j < 2; j++)
587 {
588 if (i == 0 && j == 0)
589 continue;
590
591 if (temp_xps + i == 8)
592 {
593 x_change = 0;
594 y_change = -1;
595 }
596 else if (temp_xps + i - 17 == 0 && temp_yps + j - 9 == 0)
597 {
598 x_change = -1;
599 y_change = 0;
600 }
601 else if (abs(temp_xps + i - 17) <= abs(temp_yps + j - 9))
602 {
603 const int xi = temp_xps + i - 17;
604 const int yj = temp_yps + j - 9;
605
606 if (xi >= 0 && yj <= 0)
607 {
608 if (abs(xi) > abs(yj + 1))
609 {
610 x_change = 0;
611 y_change = -1;
612 if (xi > 0)
613 y_change = 1;
614 goto finished_spiralling;
615 }
616 }
617
618 x_change = -1;
619 if (yj < 0)
620 x_change = 1;
621 y_change = 0;
622 }
623 else
624 {
625 x_change = 0;
626 y_change = -1;
627 if (temp_xps + i - 17 > 0)
628 y_change = 1;
629 }
630
631 if (temp_xps + i + x_change == temp_xps
632 && temp_yps + j + y_change == temp_yps)
633 {
634 goto finished_spiralling;
635 }
636 }
637 }
638 } // end else
639
640
641 finished_spiralling:
642 x_change *= direction;
643 y_change *= direction;
644
645 temp_xps += x_change;
646 if (temp_yps + y_change <= 17) // it can wrap, unfortunately
647 temp_yps += y_change;
648
649 const int targ_x = you.x_pos + temp_xps - 17;
650 const int targ_y = you.y_pos + temp_yps - 9;
651
652 // We don't want to be looking outside the bounds of the arrays:
653 if (temp_xps > 25 || temp_xps < 8 || temp_yps > 17 || temp_yps < 1)
654 continue;
655
656 if (targ_x < 0 || targ_x >= GXM || targ_y < 0 || targ_y >= GYM)
657 continue;
658
659 const int targ_mon = mgrd[ targ_x ][ targ_y ];
660
661 if (targ_mon != NON_MONSTER
662 && env.show[temp_xps - 8][temp_yps] != 0
663 && player_monster_visible( &(menv[targ_mon]) )
664 && !mons_is_mimic( menv[targ_mon].type )
665 && (mode == TARG_ANY
666 || (mode == TARG_FRIEND && mons_friendly( &menv[targ_mon] ))
667 || (mode == TARG_ENEMY && !mons_friendly( &menv[targ_mon] ))))
668 {
669 //mpr("Found something!");
670 //more();
671 mfp[0] = temp_xps;
672 mfp[1] = temp_yps;
673 return (1);
674 }
675 }
676
677 return (0);
678 }
679
describe_cell(int mx,int my)680 static void describe_cell(int mx, int my)
681 {
682 int trf; // used for trap type??
683 char str_pass[ ITEMNAME_SIZE ];
684 bool mimic_item = false;
685
686 if (mgrd[mx][my] != NON_MONSTER)
687 {
688 int i = mgrd[mx][my];
689
690 if (grd[mx][my] == DNGN_SHALLOW_WATER)
691 {
692 if (!player_monster_visible(&menv[i]) && !mons_flies(&menv[i]))
693 {
694 mpr("There is a strange disturbance in the water here.");
695 }
696 }
697
698 #if DEBUG_DIAGNOSTICS
699 if (!player_monster_visible( &menv[i] ))
700 mpr( "There is a non-visible monster here.", MSGCH_DIAGNOSTICS );
701 #else
702 if (!player_monster_visible( &menv[i] ))
703 goto look_clouds;
704 #endif
705
706 const int mon_wep = menv[i].inv[MSLOT_WEAPON];
707 const int mon_arm = menv[i].inv[MSLOT_ARMOUR];
708
709 strcpy(info, ptr_monam( &(menv[i]), DESC_CAP_A ));
710 strcat(info, ".");
711 mpr(info);
712
713 if (menv[i].type != MONS_DANCING_WEAPON && mon_wep != NON_ITEM)
714 {
715 snprintf( info, INFO_SIZE, "%s is wielding ", mons_pronoun( menv[i].type,
716 PRONOUN_CAP ));
717 it_name(mon_wep, DESC_NOCAP_A, str_pass);
718 strcat(info, str_pass);
719
720 // 2-headed ogres can wield 2 weapons
721 if ((menv[i].type == MONS_TWO_HEADED_OGRE
722 || menv[i].type == MONS_ETTIN)
723 && menv[i].inv[MSLOT_MISSILE] != NON_ITEM)
724 {
725 strcat( info, " and " );
726 it_name(menv[i].inv[MSLOT_MISSILE], DESC_NOCAP_A, str_pass);
727 strcat(info, str_pass);
728 strcat(info, ".");
729
730 mpr(info);
731 }
732 else
733 {
734 strcat(info, ".");
735 mpr(info);
736 }
737 }
738
739 if (mon_arm != NON_ITEM)
740 {
741 it_name( mon_arm, DESC_PLAIN, str_pass );
742 snprintf( info, INFO_SIZE, "%s is wearing %s.",
743 mons_pronoun( menv[i].type, PRONOUN_CAP ),
744 str_pass );
745
746 mpr( info );
747 }
748
749
750 if (menv[i].type == MONS_HYDRA)
751 {
752 snprintf( info, INFO_SIZE, "It has %d heads.", menv[i].number );
753 mpr( info );
754 }
755
756 print_wounds(&menv[i]);
757
758
759 if (mons_is_mimic( menv[i].type ))
760 mimic_item = true;
761 else if (!mons_flag(menv[i].type, M_NO_EXP_GAIN))
762 {
763 if (menv[i].behaviour == BEH_SLEEP)
764 {
765 strcpy(info, mons_pronoun(menv[i].type, PRONOUN_CAP));
766 strcat(info, " doesn't appear to have noticed you.");
767 mpr(info);
768 }
769 // wandering hostile with no target in LOS
770 else if (menv[i].behaviour == BEH_WANDER && !mons_friendly(&menv[i])
771 && menv[i].foe == MHITNOT)
772 {
773 // special case: batty monsters get set to BEH_WANDER as
774 // part of their special behaviour.
775 if (!testbits(menv[i].flags, MF_BATTY))
776 {
777 strcpy(info, mons_pronoun(menv[i].type, PRONOUN_CAP));
778 strcat(info, " doesn't appear to be interested in you.");
779 mpr(info);
780 }
781 }
782 }
783
784 if (menv[i].attitude == ATT_FRIENDLY)
785 {
786 strcpy(info, mons_pronoun(menv[i].type, PRONOUN_CAP));
787 strcat(info, " is friendly.");
788 mpr(info);
789 }
790
791 for (int p = 0; p < NUM_MON_ENCHANTS; p++)
792 {
793 strcpy(info, mons_pronoun(menv[i].type, PRONOUN_CAP));
794 switch (menv[i].enchantment[p])
795 {
796 case ENCH_YOUR_ROT_I:
797 case ENCH_YOUR_ROT_II:
798 case ENCH_YOUR_ROT_III:
799 case ENCH_YOUR_ROT_IV:
800 strcat(info, " is rotting away."); //jmf: "covered in sores"?
801 break;
802 case ENCH_BACKLIGHT_I:
803 case ENCH_BACKLIGHT_II:
804 case ENCH_BACKLIGHT_III:
805 case ENCH_BACKLIGHT_IV:
806 strcat(info, " is softly glowing.");
807 break;
808 case ENCH_SLOW:
809 strcat(info, " is moving slowly.");
810 break;
811 case ENCH_HASTE:
812 strcat(info, " is moving very quickly.");
813 break;
814 case ENCH_CONFUSION:
815 strcat(info, " appears to be bewildered and confused.");
816 break;
817 case ENCH_INVIS:
818 strcat(info, " is slightly transparent.");
819 break;
820 case ENCH_CHARM:
821 strcat(info, " is in your thrall.");
822 break;
823 case ENCH_YOUR_STICKY_FLAME_I:
824 case ENCH_YOUR_STICKY_FLAME_II:
825 case ENCH_YOUR_STICKY_FLAME_III:
826 case ENCH_YOUR_STICKY_FLAME_IV:
827 case ENCH_STICKY_FLAME_I:
828 case ENCH_STICKY_FLAME_II:
829 case ENCH_STICKY_FLAME_III:
830 case ENCH_STICKY_FLAME_IV:
831 strcat(info, " is covered in liquid flames.");
832 break;
833 default:
834 info[0] = '\0';
835 break;
836 } // end switch
837 if (info[0])
838 mpr(info);
839 }
840
841 #if DEBUG_DIAGNOSTICS
842 stethoscope(i);
843 #endif
844 }
845
846 #if (!DEBUG_DIAGNOSTICS)
847 // removing warning
848 look_clouds:
849 #endif
850 if (env.cgrid[mx][my] != EMPTY_CLOUD)
851 {
852 const char cloud_inspected = env.cgrid[mx][my];
853
854 const char cloud_type = env.cloud[ cloud_inspected ].type;
855
856 strcpy(info, "There is a cloud of ");
857 strcat(info,
858 (cloud_type == CLOUD_FIRE
859 || cloud_type == CLOUD_FIRE_MON) ? "flame" :
860 (cloud_type == CLOUD_STINK
861 || cloud_type == CLOUD_STINK_MON) ? "noxious fumes" :
862 (cloud_type == CLOUD_COLD
863 || cloud_type == CLOUD_COLD_MON) ? "freezing vapour" :
864 (cloud_type == CLOUD_POISON
865 || cloud_type == CLOUD_POISON_MON) ? "poison gases" :
866 (cloud_type == CLOUD_GREY_SMOKE
867 || cloud_type == CLOUD_GREY_SMOKE_MON) ? "grey smoke" :
868 (cloud_type == CLOUD_BLUE_SMOKE
869 || cloud_type == CLOUD_BLUE_SMOKE_MON) ? "blue smoke" :
870 (cloud_type == CLOUD_PURP_SMOKE
871 || cloud_type == CLOUD_PURP_SMOKE_MON) ? "purple smoke" :
872 (cloud_type == CLOUD_STEAM
873 || cloud_type == CLOUD_STEAM_MON) ? "steam" :
874 (cloud_type == CLOUD_MIASMA
875 || cloud_type == CLOUD_MIASMA_MON) ? "foul pestilence" :
876 (cloud_type == CLOUD_BLACK_SMOKE
877 || cloud_type == CLOUD_BLACK_SMOKE_MON) ? "black smoke"
878 : "buggy goodness");
879 strcat(info, " here.");
880 mpr(info);
881 }
882
883 int targ_item = igrd[ mx ][ my ];
884
885 if (targ_item != NON_ITEM)
886 {
887 // If a mimic is on this square, we pretend its the first item -- bwr
888 if (mimic_item)
889 mpr("There is something else lying underneath.");
890 else
891 {
892 if (mitm[ targ_item ].base_type == OBJ_GOLD)
893 {
894 mpr( "A pile of gold coins." );
895 }
896 else
897 {
898 strcpy(info, "You see ");
899 it_name( targ_item, DESC_NOCAP_A, str_pass);
900 strcat(info, str_pass);
901 strcat(info, " here.");
902 mpr(info);
903 }
904
905 if (mitm[ targ_item ].link != NON_ITEM)
906 mpr("There is something else lying underneath.");
907 }
908 }
909
910 switch (grd[mx][my])
911 {
912 case DNGN_STONE_WALL:
913 mpr("A stone wall.");
914 break;
915 case DNGN_ROCK_WALL:
916 case DNGN_SECRET_DOOR:
917 if (you.level_type == LEVEL_PANDEMONIUM)
918 mpr("A wall of the weird stuff which makes up Pandemonium.");
919 else
920 mpr("A rock wall.");
921 break;
922 case DNGN_PERMAROCK_WALL:
923 mpr("An unnaturally hard rock wall.");
924 break;
925 case DNGN_CLOSED_DOOR:
926 mpr("A closed door.");
927 break;
928 case DNGN_METAL_WALL:
929 mpr("A metal wall.");
930 break;
931 case DNGN_GREEN_CRYSTAL_WALL:
932 mpr("A wall of green crystal.");
933 break;
934 case DNGN_ORCISH_IDOL:
935 mpr("An orcish idol.");
936 break;
937 case DNGN_WAX_WALL:
938 mpr("A wall of solid wax.");
939 break;
940 case DNGN_SILVER_STATUE:
941 mpr("A silver statue.");
942 break;
943 case DNGN_GRANITE_STATUE:
944 mpr("A granite statue.");
945 break;
946 case DNGN_ORANGE_CRYSTAL_STATUE:
947 mpr("An orange crystal statue.");
948 break;
949 case DNGN_LAVA:
950 mpr("Some lava.");
951 break;
952 case DNGN_DEEP_WATER:
953 mpr("Some deep water.");
954 break;
955 case DNGN_SHALLOW_WATER:
956 mpr("Some shallow water.");
957 break;
958 case DNGN_UNDISCOVERED_TRAP:
959 case DNGN_FLOOR:
960 mpr("Floor.");
961 break;
962 case DNGN_OPEN_DOOR:
963 mpr("An open door.");
964 break;
965 case DNGN_ROCK_STAIRS_DOWN:
966 mpr("A rock staircase leading down.");
967 break;
968 case DNGN_STONE_STAIRS_DOWN_I:
969 case DNGN_STONE_STAIRS_DOWN_II:
970 case DNGN_STONE_STAIRS_DOWN_III:
971 mpr("A stone staircase leading down.");
972 break;
973 case DNGN_ROCK_STAIRS_UP:
974 mpr("A rock staircase leading upwards.");
975 break;
976 case DNGN_STONE_STAIRS_UP_I:
977 case DNGN_STONE_STAIRS_UP_II:
978 case DNGN_STONE_STAIRS_UP_III:
979 mpr("A stone staircase leading up.");
980 break;
981 case DNGN_ENTER_HELL:
982 mpr("A gateway to hell.");
983 break;
984 case DNGN_BRANCH_STAIRS:
985 mpr("A staircase to a branch level.");
986 break;
987 case DNGN_TRAP_MECHANICAL:
988 case DNGN_TRAP_MAGICAL:
989 case DNGN_TRAP_III:
990 for (trf = 0; trf < MAX_TRAPS; trf++)
991 {
992 if (env.trap[trf].x == mx
993 && env.trap[trf].y == my)
994 {
995 break;
996 }
997
998 if (trf == MAX_TRAPS - 1)
999 {
1000 mpr("Error - couldn't find that trap.");
1001 error_message_to_player();
1002 break;
1003 }
1004 }
1005
1006 switch (env.trap[trf].type)
1007 {
1008 case TRAP_DART:
1009 mpr("A dart trap.");
1010 break;
1011 case TRAP_ARROW:
1012 mpr("An arrow trap.");
1013 break;
1014 case TRAP_SPEAR:
1015 mpr("A spear trap.");
1016 break;
1017 case TRAP_AXE:
1018 mpr("An axe trap.");
1019 break;
1020 case TRAP_TELEPORT:
1021 mpr("A teleportation trap.");
1022 break;
1023 case TRAP_AMNESIA:
1024 mpr("An amnesia trap.");
1025 break;
1026 case TRAP_BLADE:
1027 mpr("A blade trap.");
1028 break;
1029 case TRAP_BOLT:
1030 mpr("A bolt trap.");
1031 break;
1032 case TRAP_ZOT:
1033 mpr("A Zot trap.");
1034 break;
1035 case TRAP_NEEDLE:
1036 mpr("A needle trap.");
1037 break;
1038 default:
1039 mpr("An undefined trap. Huh?");
1040 error_message_to_player();
1041 break;
1042 }
1043 break;
1044 case DNGN_ENTER_SHOP:
1045 mpr(shop_name(mx, my));
1046 break;
1047 case DNGN_ENTER_LABYRINTH:
1048 mpr("A labyrinth entrance.");
1049 break;
1050 case DNGN_ENTER_DIS:
1051 mpr("A gateway to the Iron City of Dis.");
1052 break;
1053 case DNGN_ENTER_GEHENNA:
1054 mpr("A gateway to Gehenna.");
1055 break;
1056 case DNGN_ENTER_COCYTUS:
1057 mpr("A gateway to the freezing wastes of Cocytus.");
1058 break;
1059 case DNGN_ENTER_TARTARUS:
1060 mpr("A gateway to the decaying netherworld of Tartarus.");
1061 break;
1062 case DNGN_ENTER_ABYSS:
1063 mpr("A gateway to the infinite Abyss.");
1064 break;
1065 case DNGN_EXIT_ABYSS:
1066 mpr("A gateway leading out of the Abyss.");
1067 break;
1068 case DNGN_STONE_ARCH:
1069 mpr("An empty arch of ancient stone.");
1070 break;
1071 case DNGN_ENTER_PANDEMONIUM:
1072 mpr("A gate leading to the halls of Pandemonium.");
1073 break;
1074 case DNGN_EXIT_PANDEMONIUM:
1075 mpr("A gate leading out of Pandemonium.");
1076 break;
1077 case DNGN_TRANSIT_PANDEMONIUM:
1078 mpr("A gate leading to another region of Pandemonium.");
1079 break;
1080 case DNGN_ENTER_ORCISH_MINES:
1081 mpr("A staircase to the Orcish Mines.");
1082 break;
1083 case DNGN_ENTER_HIVE:
1084 mpr("A staircase to the Hive.");
1085 break;
1086 case DNGN_ENTER_LAIR:
1087 mpr("A staircase to the Lair.");
1088 break;
1089 case DNGN_ENTER_SLIME_PITS:
1090 mpr("A staircase to the Slime Pits.");
1091 break;
1092 case DNGN_ENTER_VAULTS:
1093 mpr("A staircase to the Vaults.");
1094 break;
1095 case DNGN_ENTER_CRYPT:
1096 mpr("A staircase to the Crypt.");
1097 break;
1098 case DNGN_ENTER_HALL_OF_BLADES:
1099 mpr("A staircase to the Hall of Blades.");
1100 break;
1101 case DNGN_ENTER_ZOT:
1102 mpr("A gate to the Realm of Zot.");
1103 break;
1104 case DNGN_ENTER_TEMPLE:
1105 mpr("A staircase to the Ecumenical Temple.");
1106 break;
1107 case DNGN_ENTER_SNAKE_PIT:
1108 mpr("A staircase to the Snake Pit.");
1109 break;
1110 case DNGN_ENTER_ELVEN_HALLS:
1111 mpr("A staircase to the Elven Halls.");
1112 break;
1113 case DNGN_ENTER_TOMB:
1114 mpr("A staircase to the Tomb.");
1115 break;
1116 case DNGN_ENTER_SWAMP:
1117 mpr("A staircase to the Swamp.");
1118 break;
1119 case DNGN_RETURN_FROM_ORCISH_MINES:
1120 case DNGN_RETURN_FROM_HIVE:
1121 case DNGN_RETURN_FROM_LAIR:
1122 case DNGN_RETURN_FROM_VAULTS:
1123 case DNGN_RETURN_FROM_TEMPLE:
1124 mpr("A staircase back to the Dungeon.");
1125 break;
1126 case DNGN_RETURN_FROM_SLIME_PITS:
1127 case DNGN_RETURN_FROM_SNAKE_PIT:
1128 case DNGN_RETURN_FROM_SWAMP:
1129 mpr("A staircase back to the Lair.");
1130 break;
1131 case DNGN_RETURN_FROM_CRYPT:
1132 case DNGN_RETURN_FROM_HALL_OF_BLADES:
1133 mpr("A staircase back to the Vaults.");
1134 break;
1135 case DNGN_RETURN_FROM_ELVEN_HALLS:
1136 mpr("A staircase back to the Mines.");
1137 break;
1138 case DNGN_RETURN_FROM_TOMB:
1139 mpr("A staircase back to the Crypt.");
1140 break;
1141 case DNGN_RETURN_FROM_ZOT:
1142 mpr("A gate leading back out of this place.");
1143 break;
1144 case DNGN_ALTAR_ZIN:
1145 mpr("A glowing white marble altar of Zin.");
1146 break;
1147 case DNGN_ALTAR_SHINING_ONE:
1148 mpr("A glowing golden altar of the Shining One.");
1149 break;
1150 case DNGN_ALTAR_KIKUBAAQUDGHA:
1151 mpr("An ancient bone altar of Kikubaaqudgha.");
1152 break;
1153 case DNGN_ALTAR_YREDELEMNUL:
1154 mpr("A basalt altar of Yredelemnul.");
1155 break;
1156 case DNGN_ALTAR_XOM:
1157 mpr("A shimmering altar of Xom.");
1158 break;
1159 case DNGN_ALTAR_VEHUMET:
1160 mpr("A shining altar of Vehumet.");
1161 break;
1162 case DNGN_ALTAR_OKAWARU:
1163 mpr("An iron altar of Okawaru.");
1164 break;
1165 case DNGN_ALTAR_MAKHLEB:
1166 mpr("A burning altar of Makhleb.");
1167 break;
1168 case DNGN_ALTAR_SIF_MUNA:
1169 mpr("A deep blue altar of Sif Muna.");
1170 break;
1171 case DNGN_ALTAR_TROG:
1172 mpr("A bloodstained altar of Trog.");
1173 break;
1174 case DNGN_ALTAR_NEMELEX_XOBEH:
1175 mpr("A sparkling altar of Nemelex Xobeh.");
1176 break;
1177 case DNGN_ALTAR_ELYVILON:
1178 mpr("A silver altar of Elyvilon.");
1179 break;
1180 case DNGN_BLUE_FOUNTAIN:
1181 mpr("A fountain of clear blue water.");
1182 break;
1183 case DNGN_SPARKLING_FOUNTAIN:
1184 mpr("A fountain of sparkling water.");
1185 break;
1186 case DNGN_DRY_FOUNTAIN_I:
1187 case DNGN_DRY_FOUNTAIN_II:
1188 case DNGN_DRY_FOUNTAIN_IV:
1189 case DNGN_DRY_FOUNTAIN_VI:
1190 case DNGN_DRY_FOUNTAIN_VIII:
1191 case DNGN_PERMADRY_FOUNTAIN:
1192 mpr("A dry fountain.");
1193 break;
1194 }
1195 }
1196