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