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