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