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