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