home *** CD-ROM | disk | FTP | other *** search
/ InfoMagic Source Code 1993 July / THE_SOURCE_CODE_CD_ROM.iso / bsd_srcs / games / rogue / monster.c < prev    next >
Encoding:
C/C++ Source or Header  |  1991-04-08  |  19.4 KB  |  868 lines

  1. /*
  2.  * Copyright (c) 1988 The Regents of the University of California.
  3.  * All rights reserved.
  4.  *
  5.  * This code is derived from software contributed to Berkeley by
  6.  * Timothy C. Stoehr.
  7.  *
  8.  * Redistribution and use in source and binary forms, with or without
  9.  * modification, are permitted provided that the following conditions
  10.  * are met:
  11.  * 1. Redistributions of source code must retain the above copyright
  12.  *    notice, this list of conditions and the following disclaimer.
  13.  * 2. Redistributions in binary form must reproduce the above copyright
  14.  *    notice, this list of conditions and the following disclaimer in the
  15.  *    documentation and/or other materials provided with the distribution.
  16.  * 3. All advertising materials mentioning features or use of this software
  17.  *    must display the following acknowledgement:
  18.  *    This product includes software developed by the University of
  19.  *    California, Berkeley and its contributors.
  20.  * 4. Neither the name of the University nor the names of its contributors
  21.  *    may be used to endorse or promote products derived from this software
  22.  *    without specific prior written permission.
  23.  *
  24.  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
  25.  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  26.  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  27.  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
  28.  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  29.  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
  30.  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  31.  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  32.  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
  33.  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  34.  * SUCH DAMAGE.
  35.  */
  36.  
  37. #ifndef lint
  38. static char sccsid[] = "@(#)monster.c    5.3 (Berkeley) 6/1/90";
  39. #endif /* not lint */
  40.  
  41. /*
  42.  * monster.c
  43.  *
  44.  * This source herein may be modified and/or distributed by anybody who
  45.  * so desires, with the following restrictions:
  46.  *    1.)  No portion of this notice shall be removed.
  47.  *    2.)  Credit shall not be taken for the creation of this source.
  48.  *    3.)  This code is not to be traded, sold, or used for personal
  49.  *         gain or profit.
  50.  *
  51.  */
  52.  
  53. #include "rogue.h"
  54.  
  55. object level_monsters;
  56. boolean mon_disappeared;
  57.  
  58. char *m_names[] = {
  59.     "aquator",
  60.     "bat",
  61.     "centaur",
  62.     "dragon",
  63.     "emu",
  64.     "venus fly-trap",
  65.     "griffin",
  66.     "hobgoblin",
  67.     "ice monster",
  68.     "jabberwock",
  69.     "kestrel",
  70.     "leprechaun",
  71.     "medusa",
  72.     "nymph",
  73.     "orc",
  74.     "phantom",
  75.     "quagga",
  76.     "rattlesnake",
  77.     "snake",
  78.     "troll",
  79.     "black unicorn",
  80.     "vampire",
  81.     "wraith",
  82.     "xeroc",
  83.     "yeti",
  84.     "zombie"
  85. };
  86.  
  87. object mon_tab[MONSTERS] = {
  88.     {(ASLEEP|WAKENS|WANDERS|RUSTS),"0d0",25,'A',20,9,18,100,0,0,0,0,0},
  89.     {(ASLEEP|WANDERS|FLITS|FLIES),"1d3",10,'B',2,1,8,60,0,0,0,0,0},
  90.     {(ASLEEP|WANDERS),"3d3/2d5",32,'C',15,7,16,85,0,10,0,0,0},
  91.     {(ASLEEP|WAKENS|FLAMES),"4d6/4d9",145,'D',5000,21,126,100,0,90,0,0,0},
  92.     {(ASLEEP|WAKENS),"1d3",11,'E',2,1,7,65,0,0,0,0,0},
  93.     {(HOLDS|STATIONARY),"5d5",73,'F',91,12,126,80,0,0,0,0,0},
  94.     {(ASLEEP|WAKENS|WANDERS|FLIES),"5d5/5d5",115,'G',
  95.             2000,20,126,85,0,10,0,0,0},
  96.     {(ASLEEP|WAKENS|WANDERS),"1d3/1d2",15,'H',3,1,10,67,0,0,0,0,0},
  97.     {(ASLEEP|FREEZES),"0d0",15,'I',5,2,11,68,0,0,0,0,0},
  98.     {(ASLEEP|WANDERS),"3d10/4d5",132,'J',3000,21,126,100,0,0,0,0,0},
  99.     {(ASLEEP|WAKENS|WANDERS|FLIES),"1d4",10,'K',2,1,6,60,0,0,0,0,0},
  100.     {(ASLEEP|STEALS_GOLD),"0d0",25,'L',21,6,16,75,0,0,0,0,0},
  101.     {(ASLEEP|WAKENS|WANDERS|CONFUSES),"4d4/3d7",97,'M',
  102.             250,18,126,85,0,25,0,0,0},
  103.     {(ASLEEP|STEALS_ITEM),"0d0",25,'N',39,10,19,75,0,100,0,0,0},
  104.     {(ASLEEP|WANDERS|WAKENS|SEEKS_GOLD),"1d6",25,'O',5,4,13,70,0,10,0,0,0},
  105.     {(ASLEEP|INVISIBLE|WANDERS|FLITS),"5d4",76,'P',120,15,24,80,0,50,0,0,0},
  106.     {(ASLEEP|WAKENS|WANDERS),"3d5",30,'Q',20,8,17,78,0,20,0,0,0},
  107.     {(ASLEEP|WAKENS|WANDERS|STINGS),"2d5",19,'R',10,3,12,70,0,0,0,0,0},
  108.     {(ASLEEP|WAKENS|WANDERS),"1d3",8,'S',2,1,9,50,0,0,0,0,0},
  109.     {(ASLEEP|WAKENS|WANDERS),"4d6/1d4",75,'T',125,13,22,75,0,33,0,0,0},
  110.     {(ASLEEP|WAKENS|WANDERS),"4d10",90,'U',
  111.             200,17,26,85,0,33,0,0,0},
  112.     {(ASLEEP|WAKENS|WANDERS|DRAINS_LIFE),"1d14/1d4",55,'V',
  113.             350,19,126,85,0,18,0,0,0},
  114.     {(ASLEEP|WANDERS|DROPS_LEVEL),"2d8",45,'W',55,14,23,75,0,0,0,0,0},
  115.     {(ASLEEP|IMITATES),"4d6",42,'X',110,16,25,75,0,0,0,0,0},
  116.     {(ASLEEP|WANDERS),"3d6",35,'Y',50,11,20,80,0,20,0,0,0},
  117.     {(ASLEEP|WAKENS|WANDERS),"1d7",21,'Z',8,5,14,69,0,0,0,0,0}
  118. };
  119.  
  120. extern short cur_level;
  121. extern short cur_room, party_room;
  122. extern short blind, halluc, haste_self;
  123. extern boolean detect_monster, see_invisible, r_see_invisible;
  124. extern short stealthy;
  125.  
  126. put_mons()
  127. {
  128.     short i;
  129.     short n;
  130.     object *monster;
  131.     short row, col;
  132.  
  133.     n = get_rand(4, 6);
  134.  
  135.     for (i = 0; i < n; i++) {
  136.         monster = gr_monster((object *) 0, 0);
  137.         if ((monster->m_flags & WANDERS) && coin_toss()) {
  138.             wake_up(monster);
  139.         }
  140.         gr_row_col(&row, &col, (FLOOR | TUNNEL | STAIRS | OBJECT));
  141.         put_m_at(row, col, monster);
  142.     }
  143. }
  144.  
  145. object *
  146. gr_monster(monster, mn)
  147. register object *monster;
  148. register mn;
  149. {
  150.     if (!monster) {
  151.         monster = alloc_object();
  152.  
  153.         for (;;) {
  154.             mn = get_rand(0, MONSTERS-1);
  155.             if ((cur_level >= mon_tab[mn].first_level) &&
  156.             (cur_level <= mon_tab[mn].last_level)) {
  157.                 break;
  158.             }
  159.         }
  160.     }
  161.     *monster = mon_tab[mn];
  162.     if (monster->m_flags & IMITATES) {
  163.         monster->disguise = gr_obj_char();
  164.     }
  165.     if (cur_level > (AMULET_LEVEL + 2)) {
  166.         monster->m_flags |= HASTED;
  167.     }
  168.     monster->trow = NO_ROOM;
  169.     return(monster);
  170. }
  171.  
  172. mv_mons()
  173. {
  174.     register object *monster, *next_monster;
  175.     boolean flew;
  176.  
  177.     if (haste_self % 2) {
  178.         return;
  179.     }
  180.  
  181.     monster = level_monsters.next_monster;
  182.  
  183.     while (monster) {
  184.         next_monster = monster->next_monster;
  185.         mon_disappeared = 0;
  186.         if (monster->m_flags & HASTED) {
  187.             mv_1_monster(monster, rogue.row, rogue.col);
  188.             if (mon_disappeared) {
  189.                 goto NM;
  190.             }
  191.         } else if (monster->m_flags & SLOWED) {
  192.             monster->slowed_toggle = !monster->slowed_toggle;
  193.             if (monster->slowed_toggle) {
  194.                 goto NM;
  195.             }
  196.         }
  197.         if ((monster->m_flags & CONFUSED) && move_confused(monster)) {
  198.             goto NM;
  199.         }
  200.         flew = 0;
  201.         if (    (monster->m_flags & FLIES) &&
  202.                 !(monster->m_flags & NAPPING) &&
  203.                 !mon_can_go(monster, rogue.row, rogue.col)) {
  204.             flew = 1;
  205.             mv_1_monster(monster, rogue.row, rogue.col);
  206.             if (mon_disappeared) {
  207.                 goto NM;
  208.             }
  209.         }
  210.         if (!(flew && mon_can_go(monster, rogue.row, rogue.col))) {
  211.             mv_1_monster(monster, rogue.row, rogue.col);
  212.         }
  213. NM:        monster = next_monster;
  214.     }
  215. }
  216.  
  217. party_monsters(rn, n)
  218. int rn, n;
  219. {
  220.     short i, j;
  221.     short row, col;
  222.     object *monster;
  223.     boolean found;
  224.  
  225.     n += n;
  226.  
  227.     for (i = 0; i < MONSTERS; i++) {
  228.         mon_tab[i].first_level -= (cur_level % 3);
  229.     }
  230.     for (i = 0; i < n; i++) {
  231.         if (no_room_for_monster(rn)) {
  232.             break;
  233.         }
  234.         for (j = found = 0; ((!found) && (j < 250)); j++) {
  235.             row = get_rand(rooms[rn].top_row+1,
  236.                 rooms[rn].bottom_row-1);
  237.             col = get_rand(rooms[rn].left_col+1,
  238.                 rooms[rn].right_col-1);
  239.             if ((!(dungeon[row][col] & MONSTER)) &&
  240.                 (dungeon[row][col] & (FLOOR | TUNNEL))) {
  241.                 found = 1;
  242.             }
  243.         }
  244.         if (found) {
  245.             monster = gr_monster((object *) 0, 0);
  246.             if (!(monster->m_flags & IMITATES)) {
  247.                 monster->m_flags |= WAKENS;
  248.             }
  249.             put_m_at(row, col, monster);
  250.         }
  251.     }
  252.     for (i = 0; i < MONSTERS; i++) {
  253.         mon_tab[i].first_level += (cur_level % 3);
  254.     }
  255. }
  256.  
  257. gmc_row_col(row, col)
  258. register row, col;
  259. {
  260.     register object *monster;
  261.  
  262.     if (monster = object_at(&level_monsters, row, col)) {
  263.         if ((!(detect_monster || see_invisible || r_see_invisible) &&
  264.             (monster->m_flags & INVISIBLE)) || blind) {
  265.             return(monster->trail_char);
  266.         }
  267.         if (monster->m_flags & IMITATES) {
  268.             return(monster->disguise);
  269.         }
  270.         return(monster->m_char);
  271.     } else {
  272.         return('&');    /* BUG if this ever happens */
  273.     }
  274. }
  275.  
  276. gmc(monster)
  277. object *monster;
  278. {
  279.     if ((!(detect_monster || see_invisible || r_see_invisible) &&
  280.         (monster->m_flags & INVISIBLE))
  281.         || blind) {
  282.         return(monster->trail_char);
  283.     }
  284.     if (monster->m_flags & IMITATES) {
  285.         return(monster->disguise);
  286.     }
  287.     return(monster->m_char);
  288. }
  289.  
  290. mv_1_monster(monster, row, col)
  291. register object *monster;
  292. short row, col;
  293. {
  294.     short i, n;
  295.     boolean tried[6];
  296.  
  297.     if (monster->m_flags & ASLEEP) {
  298.         if (monster->m_flags & NAPPING) {
  299.             if (--monster->nap_length <= 0) {
  300.                 monster->m_flags &= (~(NAPPING | ASLEEP));
  301.             }
  302.             return;
  303.         }
  304.         if ((monster->m_flags & WAKENS) &&
  305.              rogue_is_around(monster->row, monster->col) &&
  306.              rand_percent(((stealthy > 0) ?
  307.                  (WAKE_PERCENT / (STEALTH_FACTOR + stealthy)) :
  308.                 WAKE_PERCENT))) {
  309.             wake_up(monster);
  310.         }
  311.         return;
  312.     } else if (monster->m_flags & ALREADY_MOVED) {
  313.         monster->m_flags &= (~ALREADY_MOVED);
  314.         return;
  315.     }
  316.     if ((monster->m_flags & FLITS) && flit(monster)) {
  317.         return;
  318.     }
  319.     if ((monster->m_flags & STATIONARY) &&
  320.         (!mon_can_go(monster, rogue.row, rogue.col))) {
  321.         return;
  322.     }
  323.     if (monster->m_flags & FREEZING_ROGUE) {
  324.         return;
  325.     }
  326.     if ((monster->m_flags & CONFUSES) && m_confuse(monster)) {
  327.         return;
  328.     }
  329.     if (mon_can_go(monster, rogue.row, rogue.col)) {
  330.         mon_hit(monster);
  331.         return;
  332.     }
  333.     if ((monster->m_flags & FLAMES) && flame_broil(monster)) {
  334.         return;
  335.     }
  336.     if ((monster->m_flags & SEEKS_GOLD) && seek_gold(monster)) {
  337.         return;
  338.     }
  339.     if ((monster->trow == monster->row) &&
  340.            (monster->tcol == monster->col)) {
  341.         monster->trow = NO_ROOM;
  342.     } else if (monster->trow != NO_ROOM) {
  343.         row = monster->trow;
  344.         col = monster->tcol;
  345.     }
  346.     if (monster->row > row) {
  347.         row = monster->row - 1;
  348.     } else if (monster->row < row) {
  349.         row = monster->row + 1;
  350.     }
  351.     if ((dungeon[row][monster->col] & DOOR) &&
  352.          mtry(monster, row, monster->col)) {
  353.         return;
  354.     }
  355.     if (monster->col > col) {
  356.         col = monster->col - 1;
  357.     } else if (monster->col < col) {
  358.         col = monster->col + 1;
  359.     }
  360.     if ((dungeon[monster->row][col] & DOOR) &&
  361.          mtry(monster, monster->row, col)) {
  362.         return;
  363.     }
  364.     if (mtry(monster, row, col)) {
  365.         return;
  366.     }
  367.  
  368.     for (i = 0; i <= 5; i++) tried[i] = 0;
  369.  
  370.     for (i = 0; i < 6; i++) {
  371. NEXT_TRY:    n = get_rand(0, 5);
  372.         switch(n) {
  373.         case 0:
  374.             if (!tried[n] && mtry(monster, row, monster->col-1)) {
  375.                 goto O;
  376.             }
  377.             break;
  378.         case 1:
  379.             if (!tried[n] && mtry(monster, row, monster->col)) {
  380.                 goto O;
  381.             }
  382.             break;
  383.         case 2:
  384.             if (!tried[n] && mtry(monster, row, monster->col+1)) {
  385.                 goto O;
  386.             }
  387.             break;
  388.         case 3:
  389.             if (!tried[n] && mtry(monster, monster->row-1, col)) {
  390.                 goto O;
  391.             }
  392.             break;
  393.         case 4:
  394.             if (!tried[n] && mtry(monster, monster->row, col)) {
  395.                 goto O;
  396.             }
  397.             break;
  398.         case 5:
  399.             if (!tried[n] && mtry(monster, monster->row+1, col)) {
  400.                 goto O;
  401.             }
  402.             break;
  403.         }
  404.         if (!tried[n]) {
  405.             tried[n] = 1;
  406.         } else {
  407.             goto NEXT_TRY;
  408.         }
  409.     }
  410. O:
  411.     if ((monster->row == monster->o_row) && (monster->col == monster->o_col)) {
  412.         if (++(monster->o) > 4) {
  413.             if ((monster->trow == NO_ROOM) &&
  414.                     (!mon_sees(monster, rogue.row, rogue.col))) {
  415.                 monster->trow = get_rand(1, (DROWS - 2));
  416.                 monster->tcol = get_rand(0, (DCOLS - 1));
  417.             } else {
  418.                 monster->trow = NO_ROOM;
  419.                 monster->o = 0;
  420.             }
  421.         }
  422.     } else {
  423.         monster->o_row = monster->row;
  424.         monster->o_col = monster->col;
  425.         monster->o = 0;
  426.     }
  427. }
  428.  
  429. mtry(monster, row, col)
  430. register object *monster;
  431. register short row, col;
  432. {
  433.     if (mon_can_go(monster, row, col)) {
  434.         move_mon_to(monster, row, col);
  435.         return(1);
  436.     }
  437.     return(0);
  438. }
  439.  
  440. move_mon_to(monster, row, col)
  441. register object *monster;
  442. register short row, col;
  443. {
  444.     short c;
  445.     register mrow, mcol;
  446.  
  447.     mrow = monster->row;
  448.     mcol = monster->col;
  449.  
  450.     dungeon[mrow][mcol] &= ~MONSTER;
  451.     dungeon[row][col] |= MONSTER;
  452.  
  453.     c = mvinch(mrow, mcol);
  454.  
  455.     if ((c >= 'A') && (c <= 'Z')) {
  456.         if (!detect_monster) {
  457.             mvaddch(mrow, mcol, monster->trail_char);
  458.         } else {
  459.             if (rogue_can_see(mrow, mcol)) {
  460.                 mvaddch(mrow, mcol, monster->trail_char);
  461.             } else {
  462.                 if (monster->trail_char == '.') {
  463.                     monster->trail_char = ' ';
  464.                 }
  465.                 mvaddch(mrow, mcol, monster->trail_char);
  466.             }
  467.         }
  468.     }
  469.     monster->trail_char = mvinch(row, col);
  470.     if (!blind && (detect_monster || rogue_can_see(row, col))) {
  471.         if ((!(monster->m_flags & INVISIBLE) ||
  472.             (detect_monster || see_invisible || r_see_invisible))) {
  473.             mvaddch(row, col, gmc(monster));
  474.         }
  475.     }
  476.     if ((dungeon[row][col] & DOOR) &&
  477.         (get_room_number(row, col) != cur_room) &&
  478.         (dungeon[mrow][mcol] == FLOOR) && !blind) {
  479.             mvaddch(mrow, mcol, ' ');
  480.     }
  481.     if (dungeon[row][col] & DOOR) {
  482.             dr_course(monster, ((dungeon[mrow][mcol] & TUNNEL) ? 1 : 0),
  483.                 row, col);
  484.     } else {
  485.         monster->row = row;
  486.         monster->col = col;
  487.     }
  488. }
  489.  
  490. mon_can_go(monster, row, col)
  491. register object *monster;
  492. register short row, col;
  493. {
  494.     object *obj;
  495.     short dr, dc;
  496.  
  497.     dr = monster->row - row;    /* check if move distance > 1 */
  498.     if ((dr >= 2) || (dr <= -2)) {
  499.         return(0);
  500.     }
  501.     dc = monster->col - col;
  502.     if ((dc >= 2) || (dc <= -2)) {
  503.         return(0);
  504.     }
  505.     if ((!dungeon[monster->row][col]) || (!dungeon[row][monster->col])) {
  506.         return(0);
  507.     }
  508.     if ((!is_passable(row, col)) || (dungeon[row][col] & MONSTER)) {
  509.         return(0);
  510.     }
  511.     if ((monster->row!=row)&&(monster->col!=col)&&((dungeon[row][col]&DOOR) ||
  512.         (dungeon[monster->row][monster->col]&DOOR))) {
  513.         return(0);
  514.     }
  515.     if (!(monster->m_flags & (FLITS | CONFUSED | CAN_FLIT)) &&
  516.         (monster->trow == NO_ROOM)) {
  517.         if ((monster->row < rogue.row) && (row < monster->row)) return(0);
  518.         if ((monster->row > rogue.row) && (row > monster->row)) return(0);
  519.         if ((monster->col < rogue.col) && (col < monster->col)) return(0);
  520.         if ((monster->col > rogue.col) && (col > monster->col)) return(0);
  521.     }
  522.     if (dungeon[row][col] & OBJECT) {
  523.         obj = object_at(&level_objects, row, col);
  524.         if ((obj->what_is == SCROL) && (obj->which_kind == SCARE_MONSTER)) {
  525.             return(0);
  526.         }
  527.     }
  528.     return(1);
  529. }
  530.  
  531. wake_up(monster)
  532. object *monster;
  533. {
  534.     if (!(monster->m_flags & NAPPING)) {
  535.         monster->m_flags &= (~(ASLEEP | IMITATES | WAKENS));
  536.     }
  537. }
  538.  
  539. wake_room(rn, entering, row, col)
  540. short rn;
  541. boolean entering;
  542. short row, col;
  543. {
  544.     object *monster;
  545.     short wake_percent;
  546.     boolean in_room;
  547.  
  548.     wake_percent = (rn == party_room) ? PARTY_WAKE_PERCENT : WAKE_PERCENT;
  549.     if (stealthy > 0) {
  550.         wake_percent /= (STEALTH_FACTOR + stealthy);
  551.     }
  552.  
  553.     monster = level_monsters.next_monster;
  554.  
  555.     while (monster) {
  556.         in_room = (rn == get_room_number(monster->row, monster->col));
  557.         if (in_room) {
  558.             if (entering) {
  559.                 monster->trow = NO_ROOM;
  560.             } else {
  561.                 monster->trow = row;
  562.                 monster->tcol = col;
  563.             }
  564.         }
  565.         if ((monster->m_flags & WAKENS) &&
  566.             (rn == get_room_number(monster->row, monster->col))) {
  567.             if (rand_percent(wake_percent)) {
  568.                 wake_up(monster);
  569.             }
  570.         }
  571.         monster = monster->next_monster;
  572.     }
  573. }
  574.  
  575. char *
  576. mon_name(monster)
  577. object *monster;
  578. {
  579.     short ch;
  580.  
  581.     if (blind || ((monster->m_flags & INVISIBLE) &&
  582.         !(detect_monster || see_invisible || r_see_invisible))) {
  583.         return("something");
  584.     }
  585.     if (halluc) {
  586.         ch = get_rand('A', 'Z') - 'A';
  587.         return(m_names[ch]);
  588.     }
  589.     ch = monster->m_char - 'A';
  590.     return(m_names[ch]);
  591. }
  592.  
  593. rogue_is_around(row, col)
  594. register row, col;
  595. {
  596.     short rdif, cdif, retval;
  597.  
  598.     rdif = row - rogue.row;
  599.     cdif = col - rogue.col;
  600.  
  601.     retval = (rdif >= -1) && (rdif <= 1) && (cdif >= -1) && (cdif <= 1);
  602.     return(retval);
  603. }
  604.  
  605. wanderer()
  606. {
  607.     object *monster;
  608.     short row, col, i;
  609.     boolean found = 0;
  610.  
  611.     for (i = 0; ((i < 15) && (!found)); i++) {
  612.         monster = gr_monster((object *) 0, 0);
  613.         if (!(monster->m_flags & (WAKENS | WANDERS))) {
  614.             free_object(monster);
  615.         } else {
  616.             found = 1;
  617.         }
  618.     }
  619.     if (found) {
  620.         found = 0;
  621.         wake_up(monster);
  622.         for (i = 0; ((i < 25) && (!found)); i++) {
  623.             gr_row_col(&row, &col, (FLOOR | TUNNEL | STAIRS | OBJECT));
  624.             if (!rogue_can_see(row, col)) {
  625.                 put_m_at(row, col, monster);
  626.                 found = 1;
  627.             }
  628.         }
  629.         if (!found) {
  630.             free_object(monster);
  631.         }
  632.     }
  633. }
  634.  
  635. show_monsters()
  636. {
  637.     object *monster;
  638.  
  639.     detect_monster = 1;
  640.  
  641.     if (blind) {
  642.         return;
  643.     }
  644.     monster = level_monsters.next_monster;
  645.  
  646.     while (monster) {
  647.         mvaddch(monster->row, monster->col, monster->m_char);
  648.         if (monster->m_flags & IMITATES) {
  649.             monster->m_flags &= (~IMITATES);
  650.             monster->m_flags |= WAKENS;
  651.         }
  652.         monster = monster->next_monster;
  653.     }
  654. }
  655.  
  656. create_monster()
  657. {
  658.     short row, col;
  659.     short i;
  660.     boolean found = 0;
  661.     object *monster;
  662.  
  663.     row = rogue.row;
  664.     col = rogue.col;
  665.  
  666.     for (i = 0; i < 9; i++) {
  667.         rand_around(i, &row, &col);
  668.         if (((row == rogue.row) && (col = rogue.col)) ||
  669.                 (row < MIN_ROW) || (row > (DROWS-2)) ||
  670.                 (col < 0) || (col > (DCOLS-1))) {
  671.             continue;
  672.         }
  673.         if ((!(dungeon[row][col] & MONSTER)) &&
  674.               (dungeon[row][col] & (FLOOR|TUNNEL|STAIRS|DOOR))) {
  675.             found = 1;
  676.             break;
  677.         }
  678.     }
  679.     if (found) {
  680.         monster = gr_monster((object *) 0, 0);
  681.         put_m_at(row, col, monster);
  682.         mvaddch(row, col, gmc(monster));
  683.         if (monster->m_flags & (WANDERS | WAKENS)) {
  684.             wake_up(monster);
  685.         }
  686.     } else {
  687.         message("you hear a faint cry of anguish in the distance", 0);
  688.     }
  689. }
  690.  
  691. put_m_at(row, col, monster)
  692. short row, col;
  693. object *monster;
  694. {
  695.     monster->row = row;
  696.     monster->col = col;
  697.     dungeon[row][col] |= MONSTER;
  698.     monster->trail_char = mvinch(row, col);
  699.     (void) add_to_pack(monster, &level_monsters, 0);
  700.     aim_monster(monster);
  701. }
  702.  
  703. aim_monster(monster)
  704. object *monster;
  705. {
  706.     short i, rn, d, r;
  707.  
  708.     rn = get_room_number(monster->row, monster->col);
  709.     r = get_rand(0, 12);
  710.  
  711.     for (i = 0; i < 4; i++) {
  712.         d = (r + i) % 4;
  713.         if (rooms[rn].doors[d].oth_room != NO_ROOM) {
  714.             monster->trow = rooms[rn].doors[d].door_row;
  715.             monster->tcol = rooms[rn].doors[d].door_col;
  716.             break;
  717.         }
  718.     }
  719. }
  720.  
  721. rogue_can_see(row, col)
  722. register row, col;
  723. {
  724.     register retval;
  725.  
  726.     retval = !blind &&
  727.             (((get_room_number(row, col) == cur_room) &&
  728.                     !(rooms[cur_room].is_room & R_MAZE)) ||
  729.             rogue_is_around(row, col));
  730.  
  731.     return(retval);
  732. }
  733.  
  734. move_confused(monster)
  735. object *monster;
  736. {
  737.     short i, row, col;
  738.  
  739.     if (!(monster->m_flags & ASLEEP)) {
  740.         if (--monster->moves_confused <= 0) {
  741.             monster->m_flags &= (~CONFUSED);
  742.         }
  743.         if (monster->m_flags & STATIONARY) {
  744.             return(coin_toss() ? 1 : 0);
  745.         } else if (rand_percent(15)) {
  746.             return(1);
  747.         }
  748.         row = monster->row;
  749.         col = monster->col;
  750.  
  751.         for (i = 0; i < 9; i++) {
  752.             rand_around(i, &row, &col);
  753.             if ((row == rogue.row) && (col == rogue.col)) {
  754.                 return(0);
  755.             }
  756.             if (mtry(monster, row, col)) {
  757.                 return(1);
  758.             }
  759.         }
  760.     }
  761.     return(0);
  762. }
  763.  
  764. flit(monster)
  765. object *monster;
  766. {
  767.     short i, row, col;
  768.  
  769.     if (!rand_percent(FLIT_PERCENT + ((monster->m_flags & FLIES) ? 20 : 0))) {
  770.         return(0);
  771.     }
  772.     if (rand_percent(10)) {
  773.         return(1);
  774.     }
  775.     row = monster->row;
  776.     col = monster->col;
  777.  
  778.     for (i = 0; i < 9; i++) {
  779.         rand_around(i, &row, &col);
  780.         if ((row == rogue.row) && (col == rogue.col)) {
  781.             continue;
  782.         }
  783.         if (mtry(monster, row, col)) {
  784.             return(1);
  785.         }
  786.     }
  787.     return(1);
  788. }
  789.  
  790. gr_obj_char()
  791. {
  792.     short r;
  793.     char *rs = "%!?]=/):*";
  794.  
  795.     r = get_rand(0, 8);
  796.  
  797.     return(rs[r]);
  798. }
  799.  
  800. no_room_for_monster(rn)
  801. int rn;
  802. {
  803.     short i, j;
  804.  
  805.     for (i = rooms[rn].top_row+1; i < rooms[rn].bottom_row; i++) {
  806.         for (j = rooms[rn].left_col+1; j < rooms[rn].right_col; j++) {
  807.             if (!(dungeon[i][j] & MONSTER)) {
  808.                 return(0);
  809.             }
  810.         }
  811.     }
  812.     return(1);
  813. }
  814.  
  815. aggravate()
  816. {
  817.     object *monster;
  818.  
  819.     message("you hear a high pitched humming noise", 0);
  820.  
  821.     monster = level_monsters.next_monster;
  822.  
  823.     while (monster) {
  824.         wake_up(monster);
  825.         monster->m_flags &= (~IMITATES);
  826.         if (rogue_can_see(monster->row, monster->col)) {
  827.             mvaddch(monster->row, monster->col, monster->m_char);
  828.         }
  829.         monster = monster->next_monster;
  830.     }
  831. }
  832.  
  833. boolean
  834. mon_sees(monster, row, col)
  835. object *monster;
  836. {
  837.     short rn, rdif, cdif, retval;
  838.  
  839.     rn = get_room_number(row, col);
  840.  
  841.     if (    (rn != NO_ROOM) &&
  842.             (rn == get_room_number(monster->row, monster->col)) &&
  843.             !(rooms[rn].is_room & R_MAZE)) {
  844.         return(1);
  845.     }
  846.     rdif = row - monster->row;
  847.     cdif = col - monster->col;
  848.  
  849.     retval = (rdif >= -1) && (rdif <= 1) && (cdif >= -1) && (cdif <= 1);
  850.     return(retval);
  851. }
  852.  
  853. mv_aquatars()
  854. {
  855.     object *monster;
  856.  
  857.     monster = level_monsters.next_monster;
  858.  
  859.     while (monster) {
  860.         if ((monster->m_char == 'A') &&
  861.             mon_can_go(monster, rogue.row, rogue.col)) {
  862.             mv_1_monster(monster, rogue.row, rogue.col);
  863.             monster->m_flags |= ALREADY_MOVED;
  864.         }
  865.         monster = monster->next_monster;
  866.     }
  867. }
  868.