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