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