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