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