Mercurial > hg > early-roguelike
comparison xrogue/chase.c @ 133:e6179860cb76
Import XRogue 8.0 from the Roguelike Restoration Project (r1490)
author | John "Elwin" Edwards |
---|---|
date | Tue, 21 Apr 2015 08:55:20 -0400 |
parents | |
children | f54901b9c39b |
comparison
equal
deleted
inserted
replaced
124:d10fc4a065ac | 133:e6179860cb76 |
---|---|
1 /* | |
2 chase.c - Code for one object to chase another | |
3 | |
4 XRogue: Expeditions into the Dungeons of Doom | |
5 Copyright (C) 1991 Robert Pietkivitch | |
6 All rights reserved. | |
7 | |
8 Based on "Advanced Rogue" | |
9 Copyright (C) 1984, 1985 Michael Morgan, Ken Dalka and AT&T | |
10 All rights reserved. | |
11 | |
12 Based on "Rogue: Exploring the Dungeons of Doom" | |
13 Copyright (C) 1980, 1981 Michael Toy, Ken Arnold and Glenn Wichman | |
14 All rights reserved. | |
15 | |
16 See the file LICENSE.TXT for full copyright and licensing information. | |
17 */ | |
18 | |
19 #include <ctype.h> | |
20 #include <curses.h> | |
21 #include <limits.h> | |
22 #include "rogue.h" | |
23 | |
24 /* | |
25 * Canblink checks if the monster can teleport (blink). If so, it will | |
26 * try to blink the monster next to the player. | |
27 */ | |
28 | |
29 bool | |
30 can_blink(tp) | |
31 register struct thing *tp; | |
32 { | |
33 register int y, x, index=9; | |
34 coord tryp; /* To hold the coordinates for use in diag_ok */ | |
35 bool spots[9], found_one=FALSE; | |
36 | |
37 /* | |
38 * First, can the monster even blink? And if so, there is only a 50% | |
39 * chance that it will do so. And it won't blink if it is running or | |
40 * held. | |
41 */ | |
42 if (off(*tp, CANBLINK) || (on(*tp, ISHELD)) || | |
43 on(*tp, ISFLEE) || | |
44 tp->t_action == A_FREEZE || | |
45 (rnd(12) < 6)) return(FALSE); | |
46 | |
47 | |
48 /* Initialize the spots as illegal */ | |
49 do { | |
50 spots[--index] = FALSE; | |
51 } while (index > 0); | |
52 | |
53 /* Find a suitable spot next to the player */ | |
54 for (y=hero.y-1; y<hero.y+2; y++) | |
55 for (x=hero.x-1; x<hero.x+2; x++, index++) { | |
56 /* Make sure x coordinate is in range and that we are | |
57 * not at the player's position | |
58 */ | |
59 if (x<0 || x >= cols || index == 4) continue; | |
60 | |
61 /* Is it OK to move there? */ | |
62 if (step_ok(y, x, NOMONST, tp) && | |
63 (!isatrap(mvwinch(cw, y, x)) || | |
64 rnd(10) >= tp->t_stats.s_intel || | |
65 on(*tp, ISFLY))) { | |
66 /* OK, we can go here. But don't go there if | |
67 * monster can't get at player from there | |
68 */ | |
69 tryp.y = y; | |
70 tryp.x = x; | |
71 if (diag_ok(&tryp, &hero, tp)) { | |
72 spots[index] = TRUE; | |
73 found_one = TRUE; | |
74 } | |
75 } | |
76 } | |
77 | |
78 /* If we found one, go to it */ | |
79 if (found_one) { | |
80 unsigned char rch; /* What's really where the creatures moves to */ | |
81 | |
82 /* Find a legal spot */ | |
83 while (spots[index=rnd(9)] == FALSE) continue; | |
84 | |
85 /* Get the coordinates */ | |
86 y = hero.y + (index/3) - 1; | |
87 x = hero.x + (index % 3) - 1; | |
88 | |
89 /* Move the monster from the old space */ | |
90 mvwaddch(cw, tp->t_pos.y, tp->t_pos.x, tp->t_oldch); | |
91 | |
92 /* Move it to the new space */ | |
93 tp->t_oldch = mvwinch(cw, y, x); | |
94 | |
95 /* Display the creature if our hero can see it */ | |
96 if (cansee(y, x) && | |
97 off(*tp, ISINWALL) && | |
98 !invisible(tp)) | |
99 mvwaddch(cw, y, x, tp->t_type); | |
100 | |
101 /* Fix the monster window */ | |
102 mvwaddch(mw, tp->t_pos.y, tp->t_pos.x, ' '); /* Clear old position */ | |
103 mvwaddch(mw, y, x, tp->t_type); | |
104 | |
105 /* Record the new position */ | |
106 tp->t_pos.y = y; | |
107 tp->t_pos.x = x; | |
108 | |
109 /* If the monster is on a trap, trap it */ | |
110 rch = mvinch(y, x); | |
111 if (isatrap(rch)) { | |
112 if (cansee(y, x)) tp->t_oldch = rch; | |
113 be_trapped(tp, &(tp->t_pos)); | |
114 } | |
115 } | |
116 | |
117 return(found_one); | |
118 } | |
119 | |
120 /* | |
121 * Can_shoot determines if the monster (er) has a direct line of shot | |
122 * at the prey (ee). If so, it returns the direction in which to shoot. | |
123 */ | |
124 | |
125 int | |
126 can_shoot(er, ee, shoot_dir) | |
127 register coord *er, *ee, *shoot_dir; | |
128 { | |
129 /* | |
130 * They must be in the same room or very close (at door) | |
131 */ | |
132 if (roomin(er) != roomin(ee) && DISTANCE(er->y,er->x,ee->y,ee->x) > 1) | |
133 { | |
134 shoot_dir->x = shoot_dir->y = 0; | |
135 return(-1); | |
136 } | |
137 | |
138 /* Do we have a straight shot? */ | |
139 if (!straight_shot(er->y, er->x, ee->y, ee->x, shoot_dir)) | |
140 { | |
141 shoot_dir->x = shoot_dir->y = 0; | |
142 return(-2); | |
143 } | |
144 else | |
145 return(0); | |
146 } | |
147 | |
148 /* | |
149 * chase: | |
150 * Find the spot for the chaser(er) to move closer to the | |
151 * chasee(ee). Rer is the room of the chaser, and ree is the | |
152 * room of the creature being chased (chasee). | |
153 */ | |
154 | |
155 chase(tp, ee, rer, ree, flee) | |
156 register struct thing *tp; | |
157 register coord *ee; | |
158 register struct room *rer, *ree; | |
159 bool flee; /* True if destination (ee) is player and monster is running away | |
160 * or the player is in a wall and the monster can't get to it | |
161 */ | |
162 { | |
163 int dist, thisdist, monst_dist = INT_MAX; | |
164 register coord *er = &tp->t_pos; | |
165 struct thing *prey; /* What we are chasing */ | |
166 coord ch_ret; /* Where chasing takes you */ | |
167 unsigned char ch, mch; | |
168 bool next_player = FALSE; | |
169 | |
170 /* | |
171 * set the distance from the chas(er) to the chas(ee) here and then | |
172 * we won't have to reset it unless the chas(er) moves (instead of shoots) | |
173 */ | |
174 dist = DISTANCE(er->y, er->x, ee->y, ee->x); | |
175 | |
176 /* | |
177 * See if our destination is a monster or player. If so, make "prey" point | |
178 * to it. | |
179 */ | |
180 if (ce(hero, *ee)) prey = &player; /* Is it the player? */ | |
181 else if (tp->t_dest && ce(*(tp->t_dest), *ee)) { /* Is it a monster? */ | |
182 struct linked_list *item; | |
183 | |
184 /* What is the monster we're chasing? */ | |
185 item = find_mons(ee->y, ee->x); | |
186 if (item != NULL) prey = THINGPTR(item); | |
187 else prey = NULL; | |
188 } | |
189 else prey = NULL; | |
190 | |
191 /* We will use at least one movement period */ | |
192 tp->t_no_move = movement(tp); | |
193 if (on(*tp, ISFLY)) /* If the creature is flying, speed it up */ | |
194 tp->t_no_move /= 2; | |
195 | |
196 /* | |
197 * If the thing is confused or it can't see the player, | |
198 * let it move randomly. | |
199 */ | |
200 if ((on(*tp, ISHUH) && rnd(10) < 8) || | |
201 (prey && on(*prey, ISINVIS) && off(*tp, CANSEE))) { /* invisible prey */ | |
202 /* | |
203 * get a valid random move | |
204 */ | |
205 tp->t_newpos = rndmove(tp); | |
206 dist = DISTANCE(tp->t_newpos.y, tp->t_newpos.x, ee->y, ee->x); | |
207 } | |
208 | |
209 /* | |
210 * Otherwise, find the empty spot next to the chaser that is | |
211 * closest to the chasee. | |
212 */ | |
213 else { | |
214 register int ey, ex, x, y; | |
215 int dist_to_old = INT_MIN; /* Dist from goal to old position */ | |
216 | |
217 /* | |
218 * This will eventually hold where we move to get closer | |
219 * If we can't find an empty spot, we stay where we are. | |
220 */ | |
221 dist = flee ? 0 : INT_MAX; | |
222 ch_ret = *er; | |
223 | |
224 /* Are we at our goal already? */ | |
225 if (!flee && ce(ch_ret, *ee)) { | |
226 turn_off(*tp, ISRUN); /* So stop running! */ | |
227 return; | |
228 } | |
229 | |
230 ey = er->y + 1; | |
231 ex = er->x + 1; | |
232 | |
233 /* Check all possible moves */ | |
234 for (x = er->x - 1; x <= ex; x++) { | |
235 if (x < 0 || x >= cols) /* Don't try off the board */ | |
236 continue; | |
237 for (y = er->y - 1; y <= ey; y++) { | |
238 coord tryp; | |
239 | |
240 if ((y < 1) || (y >= lines - 2)) /* Don't try off the board */ | |
241 continue; | |
242 | |
243 /* Don't try the player if not going after the player */ | |
244 if ((flee || !ce(hero, *ee) || on(*tp, ISFRIENDLY)) && | |
245 x == hero.x && y == hero.y) { | |
246 next_player = TRUE; | |
247 continue; | |
248 } | |
249 | |
250 tryp.x = x; | |
251 tryp.y = y; | |
252 | |
253 /* Is there a monster on this spot closer to our goal? | |
254 * Don't look in our spot or where we were. | |
255 */ | |
256 if (!ce(tryp, *er) && !ce(tryp, tp->t_oldpos) && | |
257 isalpha(mch = mvwinch(mw, y, x))) { | |
258 int test_dist; | |
259 | |
260 test_dist = DISTANCE(y, x, ee->y, ee->x); | |
261 if (test_dist <= 25 && /* Let's be fairly close */ | |
262 test_dist < monst_dist) { | |
263 /* Could we really move there? */ | |
264 mvwaddch(mw, y, x, ' '); /* Temporarily blank monst */ | |
265 if (diag_ok(er, &tryp, tp)) monst_dist = test_dist; | |
266 mvwaddch(mw, y, x, mch); /* Restore monster */ | |
267 } | |
268 } | |
269 | |
270 /* Can we move onto the spot? */ | |
271 if (!diag_ok(er, &tryp, tp)) continue; | |
272 | |
273 ch = mvwinch(cw, y, x); /* Screen character */ | |
274 | |
275 /* | |
276 * Stepping on player is NOT okay if we are fleeing. | |
277 * If we are friendly to the player and there is a monster | |
278 * in the way that is not of our race, it is okay to move | |
279 * there. | |
280 */ | |
281 if (step_ok(y, x, FIGHTOK, tp) && | |
282 (off(*tp, ISFLEE) || ch != PLAYER)) | |
283 { | |
284 /* | |
285 * If it is a trap, an intelligent monster may not | |
286 * step on it (unless our hero is on top!) | |
287 */ | |
288 if ((isatrap(ch)) && | |
289 (rnd(10) < tp->t_stats.s_intel) && | |
290 (!on(*tp, ISFLY)) && | |
291 (y != hero.y || x != hero.x)) | |
292 continue; | |
293 | |
294 /* | |
295 * OK -- this place counts | |
296 */ | |
297 thisdist = DISTANCE(y, x, ee->y, ee->x); | |
298 | |
299 /* Adjust distance if we are being shot at */ | |
300 if (tp->t_wasshot && tp->t_stats.s_intel > 5 && | |
301 prey != NULL) { | |
302 /* Move out of line of sight */ | |
303 if (straight_shot(tryp.y, tryp.x, ee->y, ee->x, (coord *)NULL)) { | |
304 if (flee) thisdist -= SHOTPENALTY; | |
305 else thisdist += SHOTPENALTY; | |
306 } | |
307 | |
308 /* But do we want to leave the room? */ | |
309 else if (rer && rer == ree && ch == DOOR) | |
310 thisdist += DOORPENALTY; | |
311 } | |
312 | |
313 /* Don't move to the last position if we can help it | |
314 * (unless out prey just moved there) | |
315 */ | |
316 if (ce(tryp, tp->t_oldpos) && (flee || !ce(tryp, hero))) | |
317 dist_to_old = thisdist; | |
318 | |
319 else if ((flee && (thisdist > dist)) || | |
320 (!flee && (thisdist < dist))) | |
321 { | |
322 ch_ret = tryp; | |
323 dist = thisdist; | |
324 } | |
325 } | |
326 } | |
327 } | |
328 | |
329 /* If we aren't trying to get the player, but he is in our way, | |
330 * hit him (unless we have been turned or are friendly). next_player | |
331 * being TRUE -> we are next to the player but don't want to hit him. | |
332 * | |
333 * If we are friendly to the player, following him, and standing next | |
334 * to him, we will try to help him out in battle. | |
335 */ | |
336 if (next_player && off(*tp, WASTURNED)) { | |
337 if (off(*tp, ISFRIENDLY) && | |
338 ((flee && ce(ch_ret, *er)) || | |
339 (!flee && DISTANCE(er->y, er->x, ee->y, ee->x) < dist)) && | |
340 step_ok(tp->t_dest->y, tp->t_dest->x, NOMONST, tp)) { | |
341 /* Okay to hit player */ | |
342 debug("Switching to hero."); | |
343 tp->t_newpos = hero; | |
344 tp->t_action = A_MOVE; | |
345 return; | |
346 } | |
347 else if (on(*tp, ISFRIENDLY) && !flee && ce(*ee, hero)) { | |
348 /* | |
349 * Look all around the player. If there is a fightable | |
350 * creature next to both of us, hit it. Otherwise, if | |
351 * there is a fightable creature next to the player, try | |
352 * to move next to it. | |
353 */ | |
354 dist = INT_MAX; | |
355 for (x = hero.x - 1; x <= hero.x + 1; x++) { | |
356 if (x < 0 || x >= cols) /* Don't try off the board */ | |
357 continue; | |
358 for (y = hero.y - 1; y <= hero.y + 1; y++) { | |
359 if ((y < 1) || (y >= lines - 2)) /* Stay on the board */ | |
360 continue; | |
361 | |
362 /* Is there a fightable monster here? */ | |
363 if (isalpha(mvwinch(mw, y, x)) && | |
364 step_ok(y, x, FIGHTOK, tp) && | |
365 off(*tp, ISSTONE)) { | |
366 thisdist = DISTANCE(er->y, er->x, y, x); | |
367 if (thisdist < dist) { | |
368 dist = thisdist; | |
369 ch_ret.y = y; | |
370 ch_ret.x = x; | |
371 } | |
372 } | |
373 } | |
374 } | |
375 | |
376 /* Are we next to a bad guy? */ | |
377 if (dist <= 2) { /* Get him! */ | |
378 tp->t_newpos = ch_ret; | |
379 tp->t_action = A_MOVE; | |
380 } | |
381 | |
382 /* Try to move to the bad guy */ | |
383 else if (dist < INT_MAX) | |
384 chase(tp, &ch_ret, | |
385 roomin(&tp->t_pos), roomin(&ch_ret), FALSE); | |
386 | |
387 else tp->t_action = A_NIL; | |
388 | |
389 return; | |
390 } | |
391 } | |
392 | |
393 /* | |
394 * If we have decided that we can move onto a monster (we are | |
395 * friendly to the player, go to it. | |
396 */ | |
397 if (!ce(ch_ret, *er) && isalpha(mvwinch(mw, ch_ret.y, ch_ret.x))) { | |
398 debug("Attack monster"); | |
399 tp->t_newpos = ch_ret; | |
400 tp->t_action = A_MOVE; | |
401 return; | |
402 } | |
403 | |
404 /* If we can't get closer to the player (if that's our goal) | |
405 * because other monsters are in the way, just stay put | |
406 */ | |
407 if (!flee && ce(hero, *ee) && monst_dist < INT_MAX && | |
408 DISTANCE(er->y, er->x, hero.y, hero.x) < dist) { | |
409 tp->t_action = A_NIL; /* do nothing for awhile */ | |
410 return; | |
411 } | |
412 | |
413 /* Do we want to go back to the last position? */ | |
414 else if (dist_to_old != INT_MIN && /* It is possible to move back */ | |
415 ((flee && dist == 0) || /* No other possible moves */ | |
416 (!flee && dist == INT_MAX))) { | |
417 /* Do we move back or just stay put (default)? */ | |
418 dist = DISTANCE(er->y, er->x, ee->y, ee->x); /* Current distance */ | |
419 if (!flee || (flee && (dist_to_old > dist))) ch_ret = tp->t_oldpos; | |
420 } | |
421 | |
422 /* Record the new destination */ | |
423 tp->t_newpos = ch_ret; | |
424 } | |
425 | |
426 /* | |
427 * Do we want to fight or move? If our selected destination (ch_ret) | |
428 * is our hero, then we want to fight. Otherwise, we want to move. | |
429 */ | |
430 if (ce(tp->t_newpos, hero)) { | |
431 /* Fight! (or sell) */ | |
432 if (on(*tp, CANSELL)) { | |
433 tp->t_action = A_SELL; | |
434 tp->t_no_move += movement(tp); /* takes a little time to sell */ | |
435 } | |
436 else { | |
437 tp->t_action = A_ATTACK; | |
438 | |
439 /* | |
440 * Try to find a weapon to wield. Wield_weap will return a | |
441 * projector if weapon is a projectile (eg. bow for arrow). | |
442 * If weapon is NULL (the case here), it will try to find | |
443 * a suitable weapon. | |
444 * | |
445 * Add in rest of time. Fight is | |
446 * movement() + weap_move() + FIGHTBASE | |
447 */ | |
448 tp->t_using = wield_weap((struct object *)NULL, tp); | |
449 if (tp->t_using == NULL) | |
450 tp->t_no_move += weap_move(tp, (struct object *)NULL); | |
451 else | |
452 tp->t_no_move += weap_move(tp, OBJPTR(tp->t_using)); | |
453 | |
454 if (on(*tp, ISHASTE)) | |
455 tp->t_no_move += FIGHTBASE/2; | |
456 else if (on(*tp, ISSLOW)) | |
457 tp->t_no_move += FIGHTBASE*2; | |
458 else | |
459 tp->t_no_move += FIGHTBASE; | |
460 } | |
461 } | |
462 else { | |
463 /* Move */ | |
464 tp->t_action = A_MOVE; | |
465 | |
466 /* | |
467 * Check if the creature is not next to the player. If it | |
468 * is not and has held or suffocated the player, then stop it! | |
469 * Note that this code should more appropriately appear in | |
470 * the area that actually moves the monster, but for now it | |
471 * is okay here because the player can't move while held or | |
472 * suffocating. | |
473 */ | |
474 if (dist > 2) { | |
475 if (on(*tp, DIDHOLD)) { | |
476 turn_off(*tp, DIDHOLD); | |
477 turn_on(*tp, CANHOLD); | |
478 if (--hold_count == 0) | |
479 turn_off(player, ISHELD); | |
480 } | |
481 | |
482 /* If monster was suffocating, stop it */ | |
483 if (on(*tp, DIDSUFFOCATE)) { | |
484 turn_off(*tp, DIDSUFFOCATE); | |
485 turn_on(*tp, CANSUFFOCATE); | |
486 extinguish(suffocate); | |
487 msg("You can breathe again.....Whew!"); | |
488 } | |
489 } | |
490 } | |
491 } | |
492 | |
493 /* | |
494 * do_chase: | |
495 * Make one thing chase another. | |
496 */ | |
497 | |
498 do_chase(th) | |
499 register struct thing *th; | |
500 { | |
501 register struct room *orig_rer, /* Original room of chaser */ | |
502 *new_room; /* new room of monster */ | |
503 unsigned char floor, rch, sch; | |
504 coord old_pos, /* Old position of monster */ | |
505 ch_ret; /* Where we want to go */ | |
506 | |
507 if (on(*th, NOMOVE)) return; | |
508 | |
509 ch_ret = th->t_newpos; /* Record our desired new position */ | |
510 | |
511 /* | |
512 * Make sure we have an open spot (no other monster's gotten in our way, | |
513 * someone didn't just drop a scare monster there, our prey didn't just | |
514 * get there, etc.) | |
515 */ | |
516 if (!step_ok(th->t_newpos.y, th->t_newpos.x, FIGHTOK, th)) { | |
517 /* | |
518 * Most monsters get upset now. Guardians are all friends, | |
519 * and we don't want to see 50 messages in a row! | |
520 */ | |
521 if (th->t_stats.s_intel > 4 && | |
522 off(*th, ISUNDEAD) && | |
523 off(*th, ISGUARDIAN) && | |
524 off(*th, AREMANY) && | |
525 off(*th, ISHUH) && | |
526 off(*th, ISCHARMED) && | |
527 off(player, ISBLIND) && | |
528 cansee(unc(th->t_pos)) && | |
529 !invisible(th) && (rnd(15) < 5)) { | |
530 switch (rnd(10)) { | |
531 case 0: case 1: | |
532 msg("%s lashes out at you! ",prname(monster_name(th),TRUE)); | |
533 when 2: case 3: | |
534 msg("%s scrambles around. ",prname(monster_name(th), TRUE)); | |
535 otherwise: | |
536 msg("%s motions angrily. ", prname(monster_name(th), TRUE)); | |
537 } | |
538 } | |
539 return; | |
540 } | |
541 else if (ce(th->t_newpos, hero) || /* Player just got in our way */ | |
542 isalpha(mvwinch(mw, th->t_newpos.y, th->t_newpos.x))) { | |
543 bool fightplayer = ce(th->t_newpos, hero); | |
544 | |
545 /* If we were turned or are friendly, we just have to sit here! */ | |
546 if (fightplayer && (on(*th, WASTURNED) || on(*th, ISFRIENDLY))) return; | |
547 | |
548 /* Do we want to sell something? */ | |
549 if (fightplayer && on(*th, CANSELL)) { | |
550 th->t_action = A_SELL; | |
551 th->t_no_move += movement(th); /* takes a little time to sell */ | |
552 return; | |
553 } | |
554 | |
555 /* Let's hit him */ | |
556 th->t_action = A_ATTACK; | |
557 | |
558 /* | |
559 * Try to find a weapon to wield. Wield_weap will return a | |
560 * projector if weapon is a projectile (eg. bow for arrow). | |
561 * If weapon is NULL (the case here), it will try to find | |
562 * a suitable weapon. | |
563 */ | |
564 th->t_using = wield_weap((struct object *)NULL, th); | |
565 /* | |
566 * add in rest of time | |
567 */ | |
568 if (th->t_using == NULL) | |
569 th->t_no_move += weap_move(th, (struct object *)NULL); | |
570 else | |
571 th->t_no_move += weap_move(th, OBJPTR(th->t_using)); | |
572 if (on(*th, ISHASTE)) | |
573 th->t_no_move += FIGHTBASE/2; | |
574 else if (on(*th, ISSLOW)) | |
575 th->t_no_move += FIGHTBASE*2; | |
576 else | |
577 th->t_no_move += FIGHTBASE; | |
578 return; | |
579 } | |
580 | |
581 /* | |
582 * Blank out the old position and record the new position -- | |
583 * the blanking must be done first in case the positions are the same. | |
584 */ | |
585 mvwaddch(mw, th->t_pos.y, th->t_pos.x, ' '); | |
586 mvwaddch(mw, ch_ret.y, ch_ret.x, th->t_type); | |
587 | |
588 /* Get new and old rooms of monster */ | |
589 new_room = roomin(&ch_ret); | |
590 orig_rer = roomin(&th->t_pos); | |
591 | |
592 /* Store the critter's old position and update the current one */ | |
593 old_pos = th->t_pos; | |
594 th->t_pos = ch_ret; | |
595 floor = (roomin(&ch_ret) == NULL) ? PASSAGE : FLOOR; | |
596 | |
597 /* If we have a scavenger, it can pick something up */ | |
598 if (off(*th, ISGUARDIAN)) { | |
599 register struct linked_list *n_item, *o_item; | |
600 register int item_count = 0; | |
601 bool want_something = FALSE; | |
602 | |
603 while ((n_item = find_obj(ch_ret.y, ch_ret.x)) != NULL) { | |
604 register struct object *n_obj, *o_obj; | |
605 bool wants_it; | |
606 | |
607 /* Does this monster want anything? */ | |
608 if (want_something == FALSE) { | |
609 if (on(*th, ISSCAVENGE) || on(*th, CARRYFOOD) || | |
610 on(*th, CARRYGOLD) || on(*th, CARRYSCROLL) || | |
611 on(*th, CARRYPOTION) || on(*th, CARRYRING) || | |
612 on(*th, CARRYSTICK) || on(*th, CARRYMISC) || | |
613 on(*th, CARRYWEAPON) || on(*th, CARRYARMOR) || | |
614 on(*th, CARRYDAGGER)) { | |
615 want_something = TRUE; | |
616 | |
617 /* | |
618 * Blank the area. We have to do it only before the | |
619 * first item in case an item gets dropped in same | |
620 * place. We don't want to blank it out after it get | |
621 * dropped. | |
622 */ | |
623 mvaddch(ch_ret.y, ch_ret.x, floor); | |
624 | |
625 /* Were we specifically after something here? */ | |
626 if (ce(*th->t_dest, ch_ret)) { | |
627 /* If we're mean, we go after the hero */ | |
628 if (on(*th, ISMEAN)) runto(th, &hero); | |
629 | |
630 /* Otherwise just go back to sleep */ | |
631 else { | |
632 turn_off(*th, ISRUN); | |
633 th->t_dest = NULL; | |
634 } | |
635 } | |
636 } | |
637 else break; | |
638 } | |
639 | |
640 item_count++; /* Count the number of items */ | |
641 | |
642 /* | |
643 * see if he's got one of this group already | |
644 */ | |
645 o_item = NULL; | |
646 n_obj = OBJPTR(n_item); | |
647 detach(lvl_obj, n_item); | |
648 | |
649 /* See if he wants it */ | |
650 if (n_obj->o_type == SCROLL && n_obj->o_which == S_SCARE && | |
651 th->t_stats.s_intel < 16) | |
652 wants_it = FALSE; /* Most monsters don't want a scare monster */ | |
653 else if (on(*th, ISSCAVENGE)) wants_it = TRUE; | |
654 else { | |
655 wants_it = FALSE; /* Default case */ | |
656 switch (n_obj->o_type) { | |
657 case FOOD: if(on(*th, CARRYFOOD)) wants_it = TRUE; | |
658 when GOLD: if(on(*th, CARRYGOLD)) wants_it = TRUE; | |
659 when SCROLL:if(on(*th, CARRYSCROLL)) wants_it = TRUE; | |
660 when POTION:if(on(*th, CARRYPOTION)) wants_it = TRUE; | |
661 when RING: if(on(*th, CARRYRING)) wants_it = TRUE; | |
662 when STICK: if(on(*th, CARRYSTICK)) wants_it = TRUE; | |
663 when MM: if(on(*th, CARRYMISC)) wants_it = TRUE; | |
664 when ARMOR: if(on(*th, CARRYARMOR)) wants_it = TRUE; | |
665 when WEAPON:if(on(*th, CARRYWEAPON) || | |
666 (on(*th,CARRYDAGGER)&&n_obj->o_which==DAGGER)) | |
667 wants_it = TRUE; | |
668 } | |
669 } | |
670 /* | |
671 * The quartermaster doesn't sell cursed stuff so he won't | |
672 * pick it up | |
673 */ | |
674 if (on(*th, CANSELL) && (n_obj->o_flags & ISCURSED)) | |
675 wants_it = FALSE; | |
676 | |
677 /* If he doesn't want it, throw it away */ | |
678 if (wants_it == FALSE) { | |
679 fall(n_item, FALSE); | |
680 continue; | |
681 } | |
682 | |
683 /* Otherwise, let's pick it up */ | |
684 if (n_obj->o_group) { | |
685 for(o_item = th->t_pack; o_item != NULL; o_item = next(o_item)){ | |
686 o_obj = OBJPTR(o_item); | |
687 if (o_obj->o_group == n_obj->o_group) { | |
688 o_obj->o_count += n_obj->o_count; | |
689 o_discard(n_item); | |
690 break; | |
691 } | |
692 } | |
693 } | |
694 if (o_item == NULL) { /* didn't find it */ | |
695 attach(th->t_pack, n_item); | |
696 } | |
697 } | |
698 | |
699 /* If there was anything here, we may have to update the screen */ | |
700 if (item_count) { | |
701 if (cansee(ch_ret.y, ch_ret.x)) | |
702 mvwaddch(cw, ch_ret.y, ch_ret.x, mvinch(ch_ret.y, ch_ret.x)); | |
703 updpack(TRUE, th); /* Update the monster's encumberance, too */ | |
704 } | |
705 } | |
706 | |
707 rch = mvwinch(stdscr, old_pos.y, old_pos.x); | |
708 if (th->t_oldch == floor && rch != floor && !isatrap(rch)) | |
709 mvwaddch(cw, old_pos.y, old_pos.x, rch); | |
710 else | |
711 mvwaddch(cw, old_pos.y, old_pos.x, th->t_oldch); | |
712 sch = mvwinch(cw, ch_ret.y, ch_ret.x); /* What player sees */ | |
713 rch = mvwinch(stdscr, ch_ret.y, ch_ret.x); /* What's really there */ | |
714 | |
715 /* If we have a tunneling monster, it may be making a tunnel */ | |
716 if (on(*th, CANTUNNEL) && | |
717 (rch==SECRETDOOR || rch==WALL || rch==VERTWALL || rch==HORZWALL)) { | |
718 unsigned char nch; /* The new look to the tunnel */ | |
719 | |
720 if (rch == WALL && levtype == OUTSIDE) nch = FLOOR; | |
721 else if (rch == WALL) nch = PASSAGE; | |
722 else if (levtype == MAZELEV || levtype == OUTSIDE) nch = FLOOR; | |
723 else nch = DOOR; | |
724 addch(nch); | |
725 | |
726 if (cansee(ch_ret.y, ch_ret.x)) sch = nch; /* Can player see this? */ | |
727 | |
728 /* Does this make a new exit? */ | |
729 if (rch == VERTWALL || rch == HORZWALL) { | |
730 struct linked_list *newroom; | |
731 coord *exit; | |
732 | |
733 newroom = new_item(sizeof(coord)); | |
734 exit = DOORPTR(newroom); | |
735 *exit = ch_ret; | |
736 attach(new_room->r_exit, newroom); | |
737 } | |
738 } | |
739 | |
740 /* Mark if the monster is inside a wall */ | |
741 if (isrock(mvinch(ch_ret.y, ch_ret.x))) turn_on(*th, ISINWALL); | |
742 else turn_off(*th, ISINWALL); | |
743 | |
744 /* If the monster can illuminate rooms, check for a change */ | |
745 if (on(*th, HASFIRE)) { | |
746 register struct linked_list *fire_item; | |
747 | |
748 /* Is monster entering a room? */ | |
749 if (orig_rer != new_room && new_room != NULL) { | |
750 fire_item = creat_item(); /* Get an item-only structure */ | |
751 ldata(fire_item) = (char *) th; | |
752 | |
753 attach(new_room->r_fires, fire_item); | |
754 new_room->r_flags |= HASFIRE; | |
755 | |
756 if (cansee(ch_ret.y, ch_ret.x) && next(new_room->r_fires) == NULL) | |
757 light(&hero); | |
758 } | |
759 | |
760 /* Is monster leaving a room? */ | |
761 if (orig_rer != new_room && orig_rer != NULL) { | |
762 /* Find the bugger in the list and delete him */ | |
763 for (fire_item = orig_rer->r_fires; fire_item != NULL; | |
764 fire_item = next(fire_item)) { | |
765 if (THINGPTR(fire_item) == th) { /* Found him! */ | |
766 detach(orig_rer->r_fires, fire_item); | |
767 destroy_item(fire_item); | |
768 if (orig_rer->r_fires == NULL) { | |
769 orig_rer->r_flags &= ~HASFIRE; | |
770 if (cansee(old_pos.y, old_pos.x)) | |
771 light(&old_pos); | |
772 } | |
773 break; | |
774 } | |
775 } | |
776 } | |
777 } | |
778 | |
779 /* If monster is entering player's room and player can see it, | |
780 * stop the player's running. | |
781 */ | |
782 if (new_room != orig_rer && new_room != NULL && | |
783 new_room == roomin(th->t_dest) && cansee(unc(ch_ret)) && | |
784 (off(*th, ISINVIS) || on(player, CANSEE)) && | |
785 (off(*th, ISSHADOW) || on(player, CANSEE)) && | |
786 (off(*th, CANSURPRISE) || ISWEARING(R_ALERT))) { | |
787 running = FALSE; | |
788 if (fight_flush) flushinp(); | |
789 } | |
790 | |
791 th->t_oldch = sch; | |
792 | |
793 /* Let's display those creatures that we can see. */ | |
794 if (cansee(unc(ch_ret)) && | |
795 off(*th, ISINWALL) && | |
796 !invisible(th)) | |
797 mvwaddch(cw, ch_ret.y, ch_ret.x, th->t_type); | |
798 | |
799 /* Record monster's last position (if new one is different) */ | |
800 if (!ce(ch_ret, old_pos)) th->t_oldpos = old_pos; | |
801 | |
802 /* If the monster is on a trap, trap it */ | |
803 sch = mvinch(ch_ret.y, ch_ret.x); | |
804 if (isatrap(sch)) { | |
805 if (cansee(ch_ret.y, ch_ret.x)) th->t_oldch = sch; | |
806 be_trapped(th, &ch_ret); | |
807 } | |
808 } | |
809 | |
810 /* | |
811 * Get_hurl returns the weapon that the monster will "throw" if he has one | |
812 */ | |
813 | |
814 struct linked_list * | |
815 get_hurl(tp) | |
816 register struct thing *tp; | |
817 { | |
818 struct linked_list *arrow=NULL, *bolt=NULL, *rock=NULL, | |
819 *spear = NULL, *dagger=NULL, *dart=NULL, *aklad=NULL; | |
820 register struct linked_list *pitem; | |
821 register struct object *obj; | |
822 bool bow=FALSE, crossbow=FALSE, sling=FALSE; | |
823 | |
824 for (pitem=tp->t_pack; pitem; pitem=next(pitem)) { | |
825 obj = OBJPTR(pitem); | |
826 if (obj->o_type == WEAPON) | |
827 switch (obj->o_which) { | |
828 case BOW: bow = TRUE; | |
829 when CROSSBOW: crossbow = TRUE; | |
830 when SLING: sling = TRUE; | |
831 when ROCK: rock = pitem; | |
832 when ARROW: arrow = pitem; | |
833 when BOLT: bolt = pitem; | |
834 when SPEAR: spear = pitem; | |
835 when DAGGER: | |
836 /* Don't throw the dagger if it's our last one */ | |
837 if (obj->o_count > 1) dagger = pitem; | |
838 when DART: dart = pitem; | |
839 } | |
840 else if (obj->o_type == RELIC && | |
841 obj->o_which == AXE_AKLAD) | |
842 aklad = pitem; | |
843 } | |
844 | |
845 /* Do we have that all-powerful Aklad Axe? */ | |
846 if (aklad) return(aklad); | |
847 | |
848 /* Use crossbow bolt if possible */ | |
849 if (crossbow && bolt) return(bolt); | |
850 if (bow && arrow) return(arrow); | |
851 if (spear) return(spear); | |
852 if (dagger) return(dagger); | |
853 if (sling && rock) return(rock); | |
854 if (dart) return(dart); | |
855 return(NULL); | |
856 } | |
857 | |
858 /* | |
859 * runto: | |
860 * Set a monster running after something | |
861 */ | |
862 | |
863 runto(runner, spot) | |
864 register struct thing *runner; | |
865 coord *spot; | |
866 { | |
867 if (on(*runner, ISSTONE)) | |
868 return; | |
869 | |
870 /* If we are chasing a new creature, forget about thrown weapons */ | |
871 if (runner->t_dest && !ce(*runner->t_dest, *spot)) runner->t_wasshot=FALSE; | |
872 | |
873 /* | |
874 * Start the beastie running | |
875 */ | |
876 runner->t_dest = spot; | |
877 turn_on(*runner, ISRUN); | |
878 turn_off(*runner, ISDISGUISE); | |
879 } | |
880 | |
881 /* | |
882 * straight_shot: | |
883 * See if there is a straight line of sight between the two | |
884 * given coordinates. If shooting is not NULL, it is a pointer | |
885 * to a structure which should be filled with the direction | |
886 * to shoot (if there is a line of sight). If shooting, monsters | |
887 * get in the way. Otherwise, they do not. | |
888 */ | |
889 | |
890 bool | |
891 straight_shot(ery, erx, eey, eex, shooting) | |
892 register int ery, erx, eey, eex; | |
893 register coord *shooting; | |
894 { | |
895 register int dy, dx; /* Deltas */ | |
896 unsigned char ch; | |
897 | |
898 /* Does the monster have a straight shot at prey */ | |
899 if ((ery != eey) && (erx != eex) && | |
900 (abs(ery - eey) != abs(erx - eex))) return(FALSE); | |
901 | |
902 /* Get the direction to shoot */ | |
903 if (eey > ery) dy = 1; | |
904 else if (eey == ery) dy = 0; | |
905 else dy = -1; | |
906 | |
907 if (eex > erx) dx = 1; | |
908 else if (eex == erx) dx = 0; | |
909 else dx = -1; | |
910 | |
911 /* Make sure we have free area all the way to the player */ | |
912 ery += dy; | |
913 erx += dx; | |
914 while ((ery != eey) || (erx != eex)) { | |
915 switch (ch = winat(ery, erx)) { | |
916 case VERTWALL: | |
917 case HORZWALL: | |
918 case WALL: | |
919 case DOOR: | |
920 case SECRETDOOR: | |
921 case FOREST: | |
922 return(FALSE); | |
923 default: | |
924 if (shooting && isalpha(ch)) return(FALSE); | |
925 } | |
926 ery += dy; | |
927 erx += dx; | |
928 } | |
929 | |
930 if (shooting) { /* If we are shooting -- put in the directions */ | |
931 shooting->y = dy; | |
932 shooting->x = dx; | |
933 } | |
934 return(TRUE); | |
935 } | |
936 |