monster.c revision 1.4 1 1.4 lukem /* $NetBSD: monster.c,v 1.4 1997/10/12 11:45:28 lukem 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.4 lukem __RCSID("$NetBSD: monster.c,v 1.4 1997/10/12 11:45:28 lukem 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.1 cgd char *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.4 lukem object *monster, *next_monster;
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.1 cgd NM: monster = next_monster;
217 1.1 cgd }
218 1.1 cgd }
219 1.1 cgd
220 1.4 lukem void
221 1.1 cgd party_monsters(rn, n)
222 1.4 lukem int rn, n;
223 1.1 cgd {
224 1.1 cgd short i, j;
225 1.1 cgd short row, col;
226 1.1 cgd object *monster;
227 1.1 cgd boolean found;
228 1.1 cgd
229 1.4 lukem row = col = 0;
230 1.1 cgd n += n;
231 1.1 cgd
232 1.1 cgd for (i = 0; i < MONSTERS; i++) {
233 1.1 cgd mon_tab[i].first_level -= (cur_level % 3);
234 1.1 cgd }
235 1.1 cgd for (i = 0; i < n; i++) {
236 1.1 cgd if (no_room_for_monster(rn)) {
237 1.1 cgd break;
238 1.1 cgd }
239 1.1 cgd for (j = found = 0; ((!found) && (j < 250)); j++) {
240 1.1 cgd row = get_rand(rooms[rn].top_row+1,
241 1.1 cgd rooms[rn].bottom_row-1);
242 1.1 cgd col = get_rand(rooms[rn].left_col+1,
243 1.1 cgd rooms[rn].right_col-1);
244 1.1 cgd if ((!(dungeon[row][col] & MONSTER)) &&
245 1.1 cgd (dungeon[row][col] & (FLOOR | TUNNEL))) {
246 1.1 cgd found = 1;
247 1.1 cgd }
248 1.1 cgd }
249 1.1 cgd if (found) {
250 1.1 cgd monster = gr_monster((object *) 0, 0);
251 1.1 cgd if (!(monster->m_flags & IMITATES)) {
252 1.1 cgd monster->m_flags |= WAKENS;
253 1.1 cgd }
254 1.1 cgd put_m_at(row, col, monster);
255 1.1 cgd }
256 1.1 cgd }
257 1.1 cgd for (i = 0; i < MONSTERS; i++) {
258 1.1 cgd mon_tab[i].first_level += (cur_level % 3);
259 1.1 cgd }
260 1.1 cgd }
261 1.1 cgd
262 1.4 lukem char
263 1.1 cgd gmc_row_col(row, col)
264 1.4 lukem int row, col;
265 1.1 cgd {
266 1.4 lukem object *monster;
267 1.1 cgd
268 1.4 lukem if ((monster = object_at(&level_monsters, row, col)) != NULL) {
269 1.1 cgd if ((!(detect_monster || see_invisible || r_see_invisible) &&
270 1.1 cgd (monster->m_flags & INVISIBLE)) || blind) {
271 1.1 cgd return(monster->trail_char);
272 1.1 cgd }
273 1.1 cgd if (monster->m_flags & IMITATES) {
274 1.1 cgd return(monster->disguise);
275 1.1 cgd }
276 1.1 cgd return(monster->m_char);
277 1.1 cgd } else {
278 1.1 cgd return('&'); /* BUG if this ever happens */
279 1.1 cgd }
280 1.1 cgd }
281 1.1 cgd
282 1.4 lukem char
283 1.1 cgd gmc(monster)
284 1.4 lukem object *monster;
285 1.1 cgd {
286 1.1 cgd if ((!(detect_monster || see_invisible || r_see_invisible) &&
287 1.1 cgd (monster->m_flags & INVISIBLE))
288 1.1 cgd || blind) {
289 1.1 cgd return(monster->trail_char);
290 1.1 cgd }
291 1.1 cgd if (monster->m_flags & IMITATES) {
292 1.1 cgd return(monster->disguise);
293 1.1 cgd }
294 1.1 cgd return(monster->m_char);
295 1.1 cgd }
296 1.1 cgd
297 1.4 lukem void
298 1.1 cgd mv_1_monster(monster, row, col)
299 1.4 lukem object *monster;
300 1.4 lukem short row, col;
301 1.1 cgd {
302 1.1 cgd short i, n;
303 1.1 cgd boolean tried[6];
304 1.1 cgd
305 1.1 cgd if (monster->m_flags & ASLEEP) {
306 1.1 cgd if (monster->m_flags & NAPPING) {
307 1.1 cgd if (--monster->nap_length <= 0) {
308 1.1 cgd monster->m_flags &= (~(NAPPING | ASLEEP));
309 1.1 cgd }
310 1.1 cgd return;
311 1.1 cgd }
312 1.1 cgd if ((monster->m_flags & WAKENS) &&
313 1.1 cgd rogue_is_around(monster->row, monster->col) &&
314 1.1 cgd rand_percent(((stealthy > 0) ?
315 1.1 cgd (WAKE_PERCENT / (STEALTH_FACTOR + stealthy)) :
316 1.1 cgd WAKE_PERCENT))) {
317 1.1 cgd wake_up(monster);
318 1.1 cgd }
319 1.1 cgd return;
320 1.1 cgd } else if (monster->m_flags & ALREADY_MOVED) {
321 1.1 cgd monster->m_flags &= (~ALREADY_MOVED);
322 1.1 cgd return;
323 1.1 cgd }
324 1.1 cgd if ((monster->m_flags & FLITS) && flit(monster)) {
325 1.1 cgd return;
326 1.1 cgd }
327 1.1 cgd if ((monster->m_flags & STATIONARY) &&
328 1.1 cgd (!mon_can_go(monster, rogue.row, rogue.col))) {
329 1.1 cgd return;
330 1.1 cgd }
331 1.1 cgd if (monster->m_flags & FREEZING_ROGUE) {
332 1.1 cgd return;
333 1.1 cgd }
334 1.1 cgd if ((monster->m_flags & CONFUSES) && m_confuse(monster)) {
335 1.1 cgd return;
336 1.1 cgd }
337 1.1 cgd if (mon_can_go(monster, rogue.row, rogue.col)) {
338 1.1 cgd mon_hit(monster);
339 1.1 cgd return;
340 1.1 cgd }
341 1.1 cgd if ((monster->m_flags & FLAMES) && flame_broil(monster)) {
342 1.1 cgd return;
343 1.1 cgd }
344 1.1 cgd if ((monster->m_flags & SEEKS_GOLD) && seek_gold(monster)) {
345 1.1 cgd return;
346 1.1 cgd }
347 1.1 cgd if ((monster->trow == monster->row) &&
348 1.1 cgd (monster->tcol == monster->col)) {
349 1.1 cgd monster->trow = NO_ROOM;
350 1.1 cgd } else if (monster->trow != NO_ROOM) {
351 1.1 cgd row = monster->trow;
352 1.1 cgd col = monster->tcol;
353 1.1 cgd }
354 1.1 cgd if (monster->row > row) {
355 1.1 cgd row = monster->row - 1;
356 1.1 cgd } else if (monster->row < row) {
357 1.1 cgd row = monster->row + 1;
358 1.1 cgd }
359 1.1 cgd if ((dungeon[row][monster->col] & DOOR) &&
360 1.1 cgd mtry(monster, row, monster->col)) {
361 1.1 cgd return;
362 1.1 cgd }
363 1.1 cgd if (monster->col > col) {
364 1.1 cgd col = monster->col - 1;
365 1.1 cgd } else if (monster->col < col) {
366 1.1 cgd col = monster->col + 1;
367 1.1 cgd }
368 1.1 cgd if ((dungeon[monster->row][col] & DOOR) &&
369 1.1 cgd mtry(monster, monster->row, col)) {
370 1.1 cgd return;
371 1.1 cgd }
372 1.1 cgd if (mtry(monster, row, col)) {
373 1.1 cgd return;
374 1.1 cgd }
375 1.1 cgd
376 1.1 cgd for (i = 0; i <= 5; i++) tried[i] = 0;
377 1.1 cgd
378 1.1 cgd for (i = 0; i < 6; i++) {
379 1.1 cgd NEXT_TRY: n = get_rand(0, 5);
380 1.1 cgd switch(n) {
381 1.1 cgd case 0:
382 1.1 cgd if (!tried[n] && mtry(monster, row, monster->col-1)) {
383 1.1 cgd goto O;
384 1.1 cgd }
385 1.1 cgd break;
386 1.1 cgd case 1:
387 1.1 cgd if (!tried[n] && mtry(monster, row, monster->col)) {
388 1.1 cgd goto O;
389 1.1 cgd }
390 1.1 cgd break;
391 1.1 cgd case 2:
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 3:
397 1.1 cgd if (!tried[n] && mtry(monster, monster->row-1, col)) {
398 1.1 cgd goto O;
399 1.1 cgd }
400 1.1 cgd break;
401 1.1 cgd case 4:
402 1.1 cgd if (!tried[n] && mtry(monster, monster->row, col)) {
403 1.1 cgd goto O;
404 1.1 cgd }
405 1.1 cgd break;
406 1.1 cgd case 5:
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 }
412 1.1 cgd if (!tried[n]) {
413 1.1 cgd tried[n] = 1;
414 1.1 cgd } else {
415 1.1 cgd goto NEXT_TRY;
416 1.1 cgd }
417 1.1 cgd }
418 1.1 cgd O:
419 1.1 cgd if ((monster->row == monster->o_row) && (monster->col == monster->o_col)) {
420 1.1 cgd if (++(monster->o) > 4) {
421 1.1 cgd if ((monster->trow == NO_ROOM) &&
422 1.1 cgd (!mon_sees(monster, rogue.row, rogue.col))) {
423 1.1 cgd monster->trow = get_rand(1, (DROWS - 2));
424 1.1 cgd monster->tcol = get_rand(0, (DCOLS - 1));
425 1.1 cgd } else {
426 1.1 cgd monster->trow = NO_ROOM;
427 1.1 cgd monster->o = 0;
428 1.1 cgd }
429 1.1 cgd }
430 1.1 cgd } else {
431 1.1 cgd monster->o_row = monster->row;
432 1.1 cgd monster->o_col = monster->col;
433 1.1 cgd monster->o = 0;
434 1.1 cgd }
435 1.1 cgd }
436 1.1 cgd
437 1.4 lukem int
438 1.1 cgd mtry(monster, row, col)
439 1.4 lukem object *monster;
440 1.4 lukem short row, col;
441 1.1 cgd {
442 1.1 cgd if (mon_can_go(monster, row, col)) {
443 1.1 cgd move_mon_to(monster, row, col);
444 1.1 cgd return(1);
445 1.1 cgd }
446 1.1 cgd return(0);
447 1.1 cgd }
448 1.1 cgd
449 1.4 lukem void
450 1.1 cgd move_mon_to(monster, row, col)
451 1.4 lukem object *monster;
452 1.4 lukem short row, col;
453 1.1 cgd {
454 1.1 cgd short c;
455 1.4 lukem int mrow, mcol;
456 1.1 cgd
457 1.1 cgd mrow = monster->row;
458 1.1 cgd mcol = monster->col;
459 1.1 cgd
460 1.1 cgd dungeon[mrow][mcol] &= ~MONSTER;
461 1.1 cgd dungeon[row][col] |= MONSTER;
462 1.1 cgd
463 1.1 cgd c = mvinch(mrow, mcol);
464 1.1 cgd
465 1.1 cgd if ((c >= 'A') && (c <= 'Z')) {
466 1.1 cgd if (!detect_monster) {
467 1.1 cgd mvaddch(mrow, mcol, monster->trail_char);
468 1.1 cgd } else {
469 1.1 cgd if (rogue_can_see(mrow, mcol)) {
470 1.1 cgd mvaddch(mrow, mcol, monster->trail_char);
471 1.1 cgd } else {
472 1.1 cgd if (monster->trail_char == '.') {
473 1.1 cgd monster->trail_char = ' ';
474 1.1 cgd }
475 1.1 cgd mvaddch(mrow, mcol, monster->trail_char);
476 1.1 cgd }
477 1.1 cgd }
478 1.1 cgd }
479 1.1 cgd monster->trail_char = mvinch(row, col);
480 1.1 cgd if (!blind && (detect_monster || rogue_can_see(row, col))) {
481 1.1 cgd if ((!(monster->m_flags & INVISIBLE) ||
482 1.1 cgd (detect_monster || see_invisible || r_see_invisible))) {
483 1.1 cgd mvaddch(row, col, gmc(monster));
484 1.1 cgd }
485 1.1 cgd }
486 1.1 cgd if ((dungeon[row][col] & DOOR) &&
487 1.1 cgd (get_room_number(row, col) != cur_room) &&
488 1.1 cgd (dungeon[mrow][mcol] == FLOOR) && !blind) {
489 1.1 cgd mvaddch(mrow, mcol, ' ');
490 1.1 cgd }
491 1.1 cgd if (dungeon[row][col] & DOOR) {
492 1.1 cgd dr_course(monster, ((dungeon[mrow][mcol] & TUNNEL) ? 1 : 0),
493 1.1 cgd row, col);
494 1.1 cgd } else {
495 1.1 cgd monster->row = row;
496 1.1 cgd monster->col = col;
497 1.1 cgd }
498 1.1 cgd }
499 1.1 cgd
500 1.4 lukem int
501 1.1 cgd mon_can_go(monster, row, col)
502 1.4 lukem object *monster;
503 1.4 lukem short row, col;
504 1.1 cgd {
505 1.1 cgd object *obj;
506 1.1 cgd short dr, dc;
507 1.1 cgd
508 1.1 cgd dr = monster->row - row; /* check if move distance > 1 */
509 1.1 cgd if ((dr >= 2) || (dr <= -2)) {
510 1.1 cgd return(0);
511 1.1 cgd }
512 1.1 cgd dc = monster->col - col;
513 1.1 cgd if ((dc >= 2) || (dc <= -2)) {
514 1.1 cgd return(0);
515 1.1 cgd }
516 1.1 cgd if ((!dungeon[monster->row][col]) || (!dungeon[row][monster->col])) {
517 1.1 cgd return(0);
518 1.1 cgd }
519 1.1 cgd if ((!is_passable(row, col)) || (dungeon[row][col] & MONSTER)) {
520 1.1 cgd return(0);
521 1.1 cgd }
522 1.1 cgd if ((monster->row!=row)&&(monster->col!=col)&&((dungeon[row][col]&DOOR) ||
523 1.1 cgd (dungeon[monster->row][monster->col]&DOOR))) {
524 1.1 cgd return(0);
525 1.1 cgd }
526 1.1 cgd if (!(monster->m_flags & (FLITS | CONFUSED | CAN_FLIT)) &&
527 1.1 cgd (monster->trow == NO_ROOM)) {
528 1.1 cgd if ((monster->row < rogue.row) && (row < monster->row)) return(0);
529 1.1 cgd if ((monster->row > rogue.row) && (row > monster->row)) return(0);
530 1.1 cgd if ((monster->col < rogue.col) && (col < monster->col)) return(0);
531 1.1 cgd if ((monster->col > rogue.col) && (col > monster->col)) return(0);
532 1.1 cgd }
533 1.1 cgd if (dungeon[row][col] & OBJECT) {
534 1.1 cgd obj = object_at(&level_objects, row, col);
535 1.1 cgd if ((obj->what_is == SCROL) && (obj->which_kind == SCARE_MONSTER)) {
536 1.1 cgd return(0);
537 1.1 cgd }
538 1.1 cgd }
539 1.1 cgd return(1);
540 1.1 cgd }
541 1.1 cgd
542 1.4 lukem void
543 1.1 cgd wake_up(monster)
544 1.4 lukem object *monster;
545 1.1 cgd {
546 1.1 cgd if (!(monster->m_flags & NAPPING)) {
547 1.1 cgd monster->m_flags &= (~(ASLEEP | IMITATES | WAKENS));
548 1.1 cgd }
549 1.1 cgd }
550 1.1 cgd
551 1.4 lukem void
552 1.1 cgd wake_room(rn, entering, row, col)
553 1.4 lukem short rn;
554 1.4 lukem boolean entering;
555 1.4 lukem short row, col;
556 1.1 cgd {
557 1.1 cgd object *monster;
558 1.1 cgd short wake_percent;
559 1.1 cgd boolean in_room;
560 1.1 cgd
561 1.1 cgd wake_percent = (rn == party_room) ? PARTY_WAKE_PERCENT : WAKE_PERCENT;
562 1.1 cgd if (stealthy > 0) {
563 1.1 cgd wake_percent /= (STEALTH_FACTOR + stealthy);
564 1.1 cgd }
565 1.1 cgd
566 1.1 cgd monster = level_monsters.next_monster;
567 1.1 cgd
568 1.1 cgd while (monster) {
569 1.1 cgd in_room = (rn == get_room_number(monster->row, monster->col));
570 1.1 cgd if (in_room) {
571 1.1 cgd if (entering) {
572 1.1 cgd monster->trow = NO_ROOM;
573 1.1 cgd } else {
574 1.1 cgd monster->trow = row;
575 1.1 cgd monster->tcol = col;
576 1.1 cgd }
577 1.1 cgd }
578 1.1 cgd if ((monster->m_flags & WAKENS) &&
579 1.1 cgd (rn == get_room_number(monster->row, monster->col))) {
580 1.1 cgd if (rand_percent(wake_percent)) {
581 1.1 cgd wake_up(monster);
582 1.1 cgd }
583 1.1 cgd }
584 1.1 cgd monster = monster->next_monster;
585 1.1 cgd }
586 1.1 cgd }
587 1.1 cgd
588 1.1 cgd char *
589 1.1 cgd mon_name(monster)
590 1.4 lukem object *monster;
591 1.1 cgd {
592 1.1 cgd short ch;
593 1.1 cgd
594 1.1 cgd if (blind || ((monster->m_flags & INVISIBLE) &&
595 1.1 cgd !(detect_monster || see_invisible || r_see_invisible))) {
596 1.1 cgd return("something");
597 1.1 cgd }
598 1.1 cgd if (halluc) {
599 1.1 cgd ch = get_rand('A', 'Z') - 'A';
600 1.1 cgd return(m_names[ch]);
601 1.1 cgd }
602 1.1 cgd ch = monster->m_char - 'A';
603 1.1 cgd return(m_names[ch]);
604 1.1 cgd }
605 1.1 cgd
606 1.4 lukem int
607 1.1 cgd rogue_is_around(row, col)
608 1.4 lukem int row, col;
609 1.1 cgd {
610 1.1 cgd short rdif, cdif, retval;
611 1.1 cgd
612 1.1 cgd rdif = row - rogue.row;
613 1.1 cgd cdif = col - rogue.col;
614 1.1 cgd
615 1.1 cgd retval = (rdif >= -1) && (rdif <= 1) && (cdif >= -1) && (cdif <= 1);
616 1.1 cgd return(retval);
617 1.1 cgd }
618 1.1 cgd
619 1.4 lukem void
620 1.1 cgd wanderer()
621 1.1 cgd {
622 1.1 cgd object *monster;
623 1.1 cgd short row, col, i;
624 1.1 cgd boolean found = 0;
625 1.1 cgd
626 1.1 cgd for (i = 0; ((i < 15) && (!found)); i++) {
627 1.1 cgd monster = gr_monster((object *) 0, 0);
628 1.1 cgd if (!(monster->m_flags & (WAKENS | WANDERS))) {
629 1.1 cgd free_object(monster);
630 1.1 cgd } else {
631 1.1 cgd found = 1;
632 1.1 cgd }
633 1.1 cgd }
634 1.1 cgd if (found) {
635 1.1 cgd found = 0;
636 1.1 cgd wake_up(monster);
637 1.1 cgd for (i = 0; ((i < 25) && (!found)); i++) {
638 1.1 cgd gr_row_col(&row, &col, (FLOOR | TUNNEL | STAIRS | OBJECT));
639 1.1 cgd if (!rogue_can_see(row, col)) {
640 1.1 cgd put_m_at(row, col, monster);
641 1.1 cgd found = 1;
642 1.1 cgd }
643 1.1 cgd }
644 1.1 cgd if (!found) {
645 1.1 cgd free_object(monster);
646 1.1 cgd }
647 1.1 cgd }
648 1.1 cgd }
649 1.1 cgd
650 1.4 lukem void
651 1.1 cgd show_monsters()
652 1.1 cgd {
653 1.1 cgd object *monster;
654 1.1 cgd
655 1.1 cgd detect_monster = 1;
656 1.1 cgd
657 1.1 cgd if (blind) {
658 1.1 cgd return;
659 1.1 cgd }
660 1.1 cgd monster = level_monsters.next_monster;
661 1.1 cgd
662 1.1 cgd while (monster) {
663 1.1 cgd mvaddch(monster->row, monster->col, monster->m_char);
664 1.1 cgd if (monster->m_flags & IMITATES) {
665 1.1 cgd monster->m_flags &= (~IMITATES);
666 1.1 cgd monster->m_flags |= WAKENS;
667 1.1 cgd }
668 1.1 cgd monster = monster->next_monster;
669 1.1 cgd }
670 1.1 cgd }
671 1.1 cgd
672 1.4 lukem void
673 1.1 cgd create_monster()
674 1.1 cgd {
675 1.1 cgd short row, col;
676 1.1 cgd short i;
677 1.1 cgd boolean found = 0;
678 1.1 cgd object *monster;
679 1.1 cgd
680 1.1 cgd row = rogue.row;
681 1.1 cgd col = rogue.col;
682 1.1 cgd
683 1.1 cgd for (i = 0; i < 9; i++) {
684 1.1 cgd rand_around(i, &row, &col);
685 1.1 cgd if (((row == rogue.row) && (col = rogue.col)) ||
686 1.1 cgd (row < MIN_ROW) || (row > (DROWS-2)) ||
687 1.1 cgd (col < 0) || (col > (DCOLS-1))) {
688 1.1 cgd continue;
689 1.1 cgd }
690 1.1 cgd if ((!(dungeon[row][col] & MONSTER)) &&
691 1.1 cgd (dungeon[row][col] & (FLOOR|TUNNEL|STAIRS|DOOR))) {
692 1.1 cgd found = 1;
693 1.1 cgd break;
694 1.1 cgd }
695 1.1 cgd }
696 1.1 cgd if (found) {
697 1.1 cgd monster = gr_monster((object *) 0, 0);
698 1.1 cgd put_m_at(row, col, monster);
699 1.1 cgd mvaddch(row, col, gmc(monster));
700 1.1 cgd if (monster->m_flags & (WANDERS | WAKENS)) {
701 1.1 cgd wake_up(monster);
702 1.1 cgd }
703 1.1 cgd } else {
704 1.1 cgd message("you hear a faint cry of anguish in the distance", 0);
705 1.1 cgd }
706 1.1 cgd }
707 1.1 cgd
708 1.4 lukem void
709 1.1 cgd put_m_at(row, col, monster)
710 1.4 lukem short row, col;
711 1.4 lukem object *monster;
712 1.1 cgd {
713 1.1 cgd monster->row = row;
714 1.1 cgd monster->col = col;
715 1.1 cgd dungeon[row][col] |= MONSTER;
716 1.1 cgd monster->trail_char = mvinch(row, col);
717 1.1 cgd (void) add_to_pack(monster, &level_monsters, 0);
718 1.1 cgd aim_monster(monster);
719 1.1 cgd }
720 1.1 cgd
721 1.4 lukem void
722 1.1 cgd aim_monster(monster)
723 1.4 lukem object *monster;
724 1.1 cgd {
725 1.1 cgd short i, rn, d, r;
726 1.1 cgd
727 1.1 cgd rn = get_room_number(monster->row, monster->col);
728 1.1 cgd r = get_rand(0, 12);
729 1.1 cgd
730 1.1 cgd for (i = 0; i < 4; i++) {
731 1.1 cgd d = (r + i) % 4;
732 1.1 cgd if (rooms[rn].doors[d].oth_room != NO_ROOM) {
733 1.1 cgd monster->trow = rooms[rn].doors[d].door_row;
734 1.1 cgd monster->tcol = rooms[rn].doors[d].door_col;
735 1.1 cgd break;
736 1.1 cgd }
737 1.1 cgd }
738 1.1 cgd }
739 1.1 cgd
740 1.4 lukem int
741 1.1 cgd rogue_can_see(row, col)
742 1.4 lukem int row, col;
743 1.1 cgd {
744 1.4 lukem int retval;
745 1.1 cgd
746 1.1 cgd retval = !blind &&
747 1.1 cgd (((get_room_number(row, col) == cur_room) &&
748 1.1 cgd !(rooms[cur_room].is_room & R_MAZE)) ||
749 1.1 cgd rogue_is_around(row, col));
750 1.1 cgd
751 1.1 cgd return(retval);
752 1.1 cgd }
753 1.1 cgd
754 1.4 lukem int
755 1.1 cgd move_confused(monster)
756 1.4 lukem object *monster;
757 1.1 cgd {
758 1.1 cgd short i, row, col;
759 1.1 cgd
760 1.1 cgd if (!(monster->m_flags & ASLEEP)) {
761 1.1 cgd if (--monster->moves_confused <= 0) {
762 1.1 cgd monster->m_flags &= (~CONFUSED);
763 1.1 cgd }
764 1.1 cgd if (monster->m_flags & STATIONARY) {
765 1.1 cgd return(coin_toss() ? 1 : 0);
766 1.1 cgd } else if (rand_percent(15)) {
767 1.1 cgd return(1);
768 1.1 cgd }
769 1.1 cgd row = monster->row;
770 1.1 cgd col = monster->col;
771 1.1 cgd
772 1.1 cgd for (i = 0; i < 9; i++) {
773 1.1 cgd rand_around(i, &row, &col);
774 1.1 cgd if ((row == rogue.row) && (col == rogue.col)) {
775 1.1 cgd return(0);
776 1.1 cgd }
777 1.1 cgd if (mtry(monster, row, col)) {
778 1.1 cgd return(1);
779 1.1 cgd }
780 1.1 cgd }
781 1.1 cgd }
782 1.1 cgd return(0);
783 1.1 cgd }
784 1.1 cgd
785 1.4 lukem int
786 1.1 cgd flit(monster)
787 1.4 lukem object *monster;
788 1.1 cgd {
789 1.1 cgd short i, row, col;
790 1.1 cgd
791 1.1 cgd if (!rand_percent(FLIT_PERCENT + ((monster->m_flags & FLIES) ? 20 : 0))) {
792 1.1 cgd return(0);
793 1.1 cgd }
794 1.1 cgd if (rand_percent(10)) {
795 1.1 cgd return(1);
796 1.1 cgd }
797 1.1 cgd row = monster->row;
798 1.1 cgd col = monster->col;
799 1.1 cgd
800 1.1 cgd for (i = 0; i < 9; i++) {
801 1.1 cgd rand_around(i, &row, &col);
802 1.1 cgd if ((row == rogue.row) && (col == rogue.col)) {
803 1.1 cgd continue;
804 1.1 cgd }
805 1.1 cgd if (mtry(monster, row, col)) {
806 1.1 cgd return(1);
807 1.1 cgd }
808 1.1 cgd }
809 1.1 cgd return(1);
810 1.1 cgd }
811 1.1 cgd
812 1.4 lukem char
813 1.1 cgd gr_obj_char()
814 1.1 cgd {
815 1.1 cgd short r;
816 1.1 cgd char *rs = "%!?]=/):*";
817 1.1 cgd
818 1.1 cgd r = get_rand(0, 8);
819 1.1 cgd
820 1.1 cgd return(rs[r]);
821 1.1 cgd }
822 1.1 cgd
823 1.4 lukem int
824 1.1 cgd no_room_for_monster(rn)
825 1.4 lukem int rn;
826 1.1 cgd {
827 1.1 cgd short i, j;
828 1.1 cgd
829 1.1 cgd for (i = rooms[rn].top_row+1; i < rooms[rn].bottom_row; i++) {
830 1.1 cgd for (j = rooms[rn].left_col+1; j < rooms[rn].right_col; j++) {
831 1.1 cgd if (!(dungeon[i][j] & MONSTER)) {
832 1.1 cgd return(0);
833 1.1 cgd }
834 1.1 cgd }
835 1.1 cgd }
836 1.1 cgd return(1);
837 1.1 cgd }
838 1.1 cgd
839 1.4 lukem void
840 1.1 cgd aggravate()
841 1.1 cgd {
842 1.1 cgd object *monster;
843 1.1 cgd
844 1.1 cgd message("you hear a high pitched humming noise", 0);
845 1.1 cgd
846 1.1 cgd monster = level_monsters.next_monster;
847 1.1 cgd
848 1.1 cgd while (monster) {
849 1.1 cgd wake_up(monster);
850 1.1 cgd monster->m_flags &= (~IMITATES);
851 1.1 cgd if (rogue_can_see(monster->row, monster->col)) {
852 1.1 cgd mvaddch(monster->row, monster->col, monster->m_char);
853 1.1 cgd }
854 1.1 cgd monster = monster->next_monster;
855 1.1 cgd }
856 1.1 cgd }
857 1.1 cgd
858 1.1 cgd boolean
859 1.1 cgd mon_sees(monster, row, col)
860 1.4 lukem object *monster;
861 1.1 cgd {
862 1.1 cgd short rn, rdif, cdif, retval;
863 1.1 cgd
864 1.1 cgd rn = get_room_number(row, col);
865 1.1 cgd
866 1.1 cgd if ( (rn != NO_ROOM) &&
867 1.1 cgd (rn == get_room_number(monster->row, monster->col)) &&
868 1.1 cgd !(rooms[rn].is_room & R_MAZE)) {
869 1.1 cgd return(1);
870 1.1 cgd }
871 1.1 cgd rdif = row - monster->row;
872 1.1 cgd cdif = col - monster->col;
873 1.1 cgd
874 1.1 cgd retval = (rdif >= -1) && (rdif <= 1) && (cdif >= -1) && (cdif <= 1);
875 1.1 cgd return(retval);
876 1.1 cgd }
877 1.1 cgd
878 1.4 lukem void
879 1.1 cgd mv_aquatars()
880 1.1 cgd {
881 1.1 cgd object *monster;
882 1.1 cgd
883 1.1 cgd monster = level_monsters.next_monster;
884 1.1 cgd
885 1.1 cgd while (monster) {
886 1.1 cgd if ((monster->m_char == 'A') &&
887 1.1 cgd mon_can_go(monster, rogue.row, rogue.col)) {
888 1.1 cgd mv_1_monster(monster, rogue.row, rogue.col);
889 1.1 cgd monster->m_flags |= ALREADY_MOVED;
890 1.1 cgd }
891 1.1 cgd monster = monster->next_monster;
892 1.1 cgd }
893 1.1 cgd }
894