ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/deliantra/server/server/monster.c
Revision: 1.6
Committed: Sat Apr 22 15:10:08 2006 UTC (18 years, 1 month ago) by elmex
Content type: text/plain
Branch: MAIN
Changes since 1.5: +13 -1 lines
Log Message:
Distant attack movement (attack_movement 1) let the monster nearly always run away
from you. This causes the monster to look away from you nearly all the time.
Now the direction before the distant attack direction-change occurs is remebered and
the monsters direciton is set to the remembered value after it moved.

File Contents

# Content
1 /*
2 * static char *rcsid_monster_c =
3 * "$Id$";
4 */
5
6 /*
7 CrossFire, A Multiplayer game for X-windows
8
9 Copyright (C) 2002 Mark Wedel & Crossfire Development Team
10 Copyright (C) 1992 Frank Tore Johansen
11
12 This program is free software; you can redistribute it and/or modify
13 it under the terms of the GNU General Public License as published by
14 the Free Software Foundation; either version 2 of the License, or
15 (at your option) any later version.
16
17 This program is distributed in the hope that it will be useful,
18 but WITHOUT ANY WARRANTY; without even the implied warranty of
19 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 GNU General Public License for more details.
21
22 You should have received a copy of the GNU General Public License
23 along with this program; if not, write to the Free Software
24 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
25
26 The authors can be reached via e-mail at crossfire-devel@real-time.com
27 */
28
29 #include <global.h>
30 #ifndef __CEXTRACT__
31 #include <sproto.h>
32 #include <spells.h>
33 #include <skills.h>
34 #endif
35
36
37 #define MIN_MON_RADIUS 3 /* minimum monster detection radius */
38
39
40 /* checks npc->enemy and returns that enemy if still valid,
41 * NULL otherwise.
42 * this is map tile aware.
43 * If this returns an enemy, the range vector rv should also be
44 * set to sane values.
45 */
46 object *check_enemy(object *npc, rv_vector *rv) {
47
48 /* if this is pet, let him attack the same enemy as his owner
49 * TODO: when there is no ower enemy, try to find a target,
50 * which CAN attack the owner. */
51 if ((npc->attack_movement & HI4) == PETMOVE)
52 {
53 if (npc->owner == NULL)
54 npc->enemy = NULL;
55 else if (npc->enemy == NULL)
56 npc->enemy = npc->owner->enemy;
57 }
58
59 /* periodically, a monster mayu change its target. Also, if the object
60 * has been destroyed, etc, clear the enemy.
61 * TODO: this should be changed, because it invokes to attack forced or
62 * attacked monsters to leave the attacker alone, before it is destroyed
63 */
64 /* i had removed the random target leave, this invokes problems with friendly
65 * objects, getting attacked and defending herself - they don't try to attack
66 * again then but perhaps get attack on and on
67 * If we include a aggravated flag in , we can handle evil vs evil and good vs good
68 * too. */
69
70 if(npc->enemy)
71 {
72 /* I broke these if's apart to better be able to see what
73 * the grouping checks are. Code is the same.
74 */
75 if ( QUERY_FLAG(npc->enemy,FLAG_REMOVED) ||
76 QUERY_FLAG(npc->enemy,FLAG_FREED) ||
77 !on_same_map(npc, npc->enemy) ||
78 npc == npc->enemy ||
79 QUERY_FLAG(npc, FLAG_NEUTRAL) ||
80 QUERY_FLAG(npc->enemy, FLAG_NEUTRAL))
81 npc->enemy = NULL;
82
83 else if (QUERY_FLAG(npc, FLAG_FRIENDLY) && (
84 (QUERY_FLAG(npc->enemy, FLAG_FRIENDLY) && !(should_arena_attack(npc, npc->owner, npc->enemy))) ||
85 ((npc->enemy->type == PLAYER) && !(should_arena_attack(npc, npc->owner, npc->enemy)))
86 || npc->enemy == npc->owner))
87 npc->enemy = NULL;
88
89
90 else if (!QUERY_FLAG(npc, FLAG_FRIENDLY) &&
91 (!QUERY_FLAG(npc->enemy, FLAG_FRIENDLY) && npc->enemy->type!=PLAYER))
92 npc->enemy=NULL;
93
94 /* I've noticed that pets could sometimes get an arrow as the
95 * target enemy - this code below makes sure the enemy is something
96 * that should be attacked. My guess is that the arrow hits
97 * the creature/owner, and so the creature then takes that
98 * as the enemy to attack.
99 */
100 else if (!QUERY_FLAG(npc->enemy, FLAG_MONSTER) &&
101 !QUERY_FLAG(npc->enemy,FLAG_GENERATOR) &&
102 npc->enemy->type!=PLAYER && npc->enemy->type != GOLEM)
103 npc->enemy=NULL;
104
105 }
106 return can_detect_enemy(npc,npc->enemy,rv)?npc->enemy:NULL;
107 }
108
109 /* Returns the nearest living creature (monster or generator).
110 * Modified to deal with tiled maps properly.
111 * Also fixed logic so that monsters in the lower directions were more
112 * likely to be skipped - instead of just skipping the 'start' number
113 * of direction, revisit them after looking at all the other spaces.
114 *
115 * Note that being this may skip some number of spaces, it will
116 * not necessarily find the nearest living creature - it basically
117 * chooses one from within a 3 space radius, and since it skips
118 * the first few directions, it could very well choose something
119 * 3 spaces away even though something directly north is closer.
120 *
121 * this function is map tile aware.
122 */
123 object *find_nearest_living_creature(object *npc) {
124 int i,mflags;
125 sint16 nx,ny;
126 mapstruct *m;
127 object *tmp;
128 int search_arr[SIZEOFFREE];
129
130 get_search_arr(search_arr);
131 for(i=0;i<SIZEOFFREE;i++) {
132 /* modified to implement smart searching using search_arr
133 * guidance array to determine direction of search order
134 */
135 nx = npc->x + freearr_x[search_arr[i]];
136 ny = npc->y + freearr_y[search_arr[i]];
137 m = npc->map;
138
139 mflags = get_map_flags(m, &m, nx, ny, &nx, &ny);
140 if (mflags & P_OUT_OF_MAP) continue;
141
142 if (mflags & P_IS_ALIVE) {
143 tmp=get_map_ob(m,nx,ny);
144 while(tmp!=NULL && !QUERY_FLAG(tmp,FLAG_MONSTER)&&
145 !QUERY_FLAG(tmp,FLAG_GENERATOR ) && tmp->type!=PLAYER)
146 tmp=tmp->above;
147
148 if (!tmp) {
149 LOG(llevDebug,"find_nearest_living_creature: map %s (%d,%d) has is_alive set but did not find a monster?\n",
150 m->path, nx, ny);
151 }
152 else {
153 if(can_see_monsterP(m,nx,ny,i))
154 return tmp;
155 }
156 } /* is something living on this space */
157 }
158 return NULL; /* nothing found */
159 }
160
161
162 /* Tries to find an enmy for npc. We pass the range vector since
163 * our caller will find the information useful.
164 * Currently, only move_monster calls this function.
165 * Fix function so that we always make calls to get_rangevector
166 * if we have a valid target - function as not doing so in
167 * many cases.
168 */
169
170 object *find_enemy(object *npc, rv_vector *rv)
171 {
172 object *attacker, *tmp=NULL;
173
174 attacker = npc->attacked_by; /* save this for later use. This can be a attacker. */
175 npc->attacked_by = NULL; /* always clear the attacker entry */
176
177 /* if we berserk, we don't care about others - we attack all we can find */
178 if(QUERY_FLAG(npc,FLAG_BERSERK)) {
179 tmp = find_nearest_living_creature(npc);
180 if (tmp) get_rangevector(npc, tmp, rv, 0);
181 return tmp;
182 }
183
184 /* Here is the main enemy selection.
185 * We want this: if there is an enemy, attack him until its not possible or
186 * one of both is dead.
187 * If we have no enemy and we are...
188 * a monster: try to find a player, a pet or a friendly monster
189 * a friendly: only target a monster which is targeting you first or targeting a player
190 * a neutral: fight a attacker (but there should be none), then do nothing
191 * a pet: attack player enemy or a monster
192 */
193
194 /* pet move */
195 if ((npc->attack_movement & HI4) == PETMOVE) {
196 tmp= get_pet_enemy(npc,rv);
197 if (tmp) get_rangevector(npc, tmp, rv, 0);
198 return tmp;
199 }
200
201 /* we check our old enemy. */
202 if((tmp=check_enemy(npc, rv))==NULL)
203 {
204 if(attacker) /* if we have an attacker, check him */
205 {
206 /* we want be sure this is the right one! */
207 if(attacker->count == npc->attacked_by_count)
208 {
209 /* TODO: thats not finished */
210 /* we don't want a fight evil vs evil or good against non evil */
211
212 if( QUERY_FLAG(npc, FLAG_NEUTRAL) || QUERY_FLAG(attacker, FLAG_NEUTRAL) || /* neutral */
213 (QUERY_FLAG(npc, FLAG_FRIENDLY) && QUERY_FLAG(attacker, FLAG_FRIENDLY)) ||
214 (!QUERY_FLAG(npc, FLAG_FRIENDLY) &&
215 (!QUERY_FLAG(attacker, FLAG_FRIENDLY) && attacker->type!=PLAYER)) )
216 CLEAR_FLAG(npc,FLAG_SLEEP); /* skip it, but lets wakeup */
217 else if(on_same_map(npc, attacker)) /* thats the only thing we must know... */
218 {
219 CLEAR_FLAG(npc,FLAG_SLEEP); /* well, NOW we really should wake up! */
220 npc->enemy = attacker;
221 return attacker; /* yes, we face our attacker! */
222 }
223 }
224 }
225
226 /* we have no legal enemy or attacker, so we try to target a new one */
227 if(!QUERY_FLAG(npc, FLAG_UNAGGRESSIVE) && !QUERY_FLAG(npc, FLAG_FRIENDLY) &&
228 !QUERY_FLAG(npc, FLAG_NEUTRAL))
229 {
230 npc->enemy = get_nearest_player(npc);
231 if (npc->enemy)
232 tmp = check_enemy(npc,rv);
233 }
234
235 }
236
237 return tmp;
238 }
239
240 /* Sees if this monster should wake up.
241 * Currently, this is only called from move_monster, and
242 * if enemy is set, then so should be rv.
243 * returns 1 if the monster should wake up, 0 otherwise.
244 */
245
246 int check_wakeup(object *op, object *enemy, rv_vector *rv) {
247 int radius = op->stats.Wis>MIN_MON_RADIUS?op->stats.Wis:MIN_MON_RADIUS;
248
249 /* Trim work - if no enemy, no need to do anything below */
250 if (!enemy) return 0;
251
252 /* blinded monsters can only find nearby objects to attack */
253 if(QUERY_FLAG(op, FLAG_BLIND))
254 radius = MIN_MON_RADIUS;
255
256 /* This covers the situation where the monster is in the dark
257 * and has an enemy. If the enemy has no carried light (or isnt
258 * glowing!) then the monster has trouble finding the enemy.
259 * Remember we already checked to see if the monster can see in
260 * the dark. */
261
262 else if(op->map && op->map->darkness>0 && enemy && !enemy->invisible &&
263 !stand_in_light(enemy) &&
264 (!QUERY_FLAG(op,FLAG_SEE_IN_DARK) || !QUERY_FLAG(op,FLAG_SEE_INVISIBLE))) {
265 int dark = radius/(op->map->darkness);
266 radius = (dark>MIN_MON_RADIUS)?(dark+1):MIN_MON_RADIUS;
267 }
268 else if(!QUERY_FLAG(op,FLAG_SLEEP)) return 1;
269
270 /* enemy should already be on this map, so don't really need to check
271 * for that.
272 */
273 if (rv->distance < (QUERY_FLAG(enemy, FLAG_STEALTH)?(radius/2)+1:radius)) {
274 CLEAR_FLAG(op,FLAG_SLEEP);
275 return 1;
276 }
277 return 0;
278 }
279
280 int move_randomly(object *op) {
281 int i;
282
283 /* Give up to 15 chances for a monster to move randomly */
284 for(i=0;i<15;i++) {
285 if(move_object(op,RANDOM()%8+1))
286 return 1;
287 }
288 return 0;
289 }
290
291 /*
292 * Move-monster returns 1 if the object has been freed, otherwise 0.
293 */
294
295 int move_monster(object *op) {
296 int dir, diff, pre_att_dir; /* elmex: pre_att_dir remembers the direction before attack movement */
297 object *owner, *enemy, *part, *oph=op;
298 rv_vector rv;
299
300 /* Monsters not on maps don't do anything. These monsters are things
301 * Like royal guards in city dwellers inventories.
302 */
303 if (!op->map) return 0;
304
305 /* for target facing, we copy this value here for fast access */
306 if(oph->head) /* force update the head - one arch one pic */
307 oph = oph->head;
308
309 if (QUERY_FLAG(op, FLAG_NO_ATTACK)) /* we never ever attack */
310 enemy = op->enemy = NULL;
311 else if((enemy= find_enemy(op, &rv)))
312 {
313 /* we have an enemy, just tell him we want him dead */
314 enemy->attacked_by = op; /* our ptr */
315 enemy->attacked_by_count = op->count; /* our tag */
316 }
317
318 if ( QUERY_FLAG(op, FLAG_SLEEP) || QUERY_FLAG(op, FLAG_BLIND) ||
319 ((op->map->darkness>0) && !QUERY_FLAG(op,FLAG_SEE_IN_DARK) &&
320 !QUERY_FLAG(op,FLAG_SEE_INVISIBLE))) {
321 if(!check_wakeup(op,enemy,&rv))
322 return 0;
323 }
324
325 /* check if monster pops out of hidden spot */
326 if(op->hide) do_hidden_move(op);
327
328 if(op->pick_up)
329 monster_check_pickup(op);
330
331 if(op->will_apply)
332 monster_apply_below(op); /* Check for items to apply below */
333
334 /* generate hp, if applicable */
335 if(op->stats.Con > 0 && op->stats.hp < op->stats.maxhp) {
336
337 /* last heal is in funny units. Dividing by speed puts
338 * the regeneration rate on a basis of time instead of
339 * #moves the monster makes. The scaling by 8 is
340 * to capture 8th's of a hp fraction regens
341 *
342 * Cast to sint32 before comparing to maxhp since otherwise an (sint16)
343 * overflow might produce monsters with negative hp.
344 */
345
346 op->last_heal+= (int)((float)(8*op->stats.Con)/FABS(op->speed));
347 op->stats.hp = MIN((sint32)op->stats.hp+op->last_heal/32, op->stats.maxhp); /* causes Con/4 hp/tick */
348 op->last_heal%=32;
349
350 /* So if the monster has gained enough HP that they are no longer afraid */
351 if (QUERY_FLAG(op,FLAG_RUN_AWAY) &&
352 op->stats.hp >= (signed short)(((float)op->run_away/(float)100)*
353 (float)op->stats.maxhp))
354 CLEAR_FLAG(op, FLAG_RUN_AWAY);
355
356 if(op->stats.hp>op->stats.maxhp)
357 op->stats.hp=op->stats.maxhp;
358 }
359
360 /* generate sp, if applicable */
361 if(op->stats.Pow > 0 && op->stats.sp < op->stats.maxsp) {
362
363 /* last_sp is in funny units. Dividing by speed puts
364 * the regeneration rate on a basis of time instead of
365 * #moves the monster makes. The scaling by 8 is
366 * to capture 8th's of a sp fraction regens
367 *
368 * Cast to sint32 before comparing to maxhp since otherwise an (sint16)
369 * overflow might produce monsters with negative sp.
370 */
371
372 op->last_sp+= (int)((float)(8*op->stats.Pow)/FABS(op->speed));
373 op->stats.sp = MIN(op->stats.sp+op->last_sp/128, op->stats.maxsp); /* causes Pow/16 sp/tick */
374 op->last_sp%=128;
375 }
376
377 /* this should probably get modified by many more values.
378 * (eg, creatures resistance to fear, level, etc. )
379 */
380 if(QUERY_FLAG(op, FLAG_SCARED) &&!(RANDOM()%20)) {
381 CLEAR_FLAG(op,FLAG_SCARED); /* Time to regain some "guts"... */
382 }
383
384 if (execute_event (op, EVENT_MOVE, op->enemy, 0, 0, SCRIPT_FIX_ALL))
385 return 0;
386
387 /* If we don't have an enemy, do special movement or the like */
388 if(!enemy) {
389 if(QUERY_FLAG(op, FLAG_ONLY_ATTACK)) {
390 remove_ob(op);
391 free_object(op);
392 return 1;
393 }
394
395 /* Probably really a bug for a creature to have both
396 * stand still and a movement type set.
397 */
398 if(!QUERY_FLAG(op, FLAG_STAND_STILL)) {
399 if (op->attack_movement & HI4)
400 {
401 switch (op->attack_movement & HI4) {
402 case (PETMOVE):
403 pet_move (op);
404 break;
405
406 case (CIRCLE1):
407 circ1_move (op);
408 break;
409
410 case (CIRCLE2):
411 circ2_move (op);
412 break;
413
414 case (PACEV):
415 pace_movev(op);
416 break;
417
418 case (PACEH):
419 pace_moveh(op);
420 break;
421
422 case (PACEV2):
423 pace2_movev (op);
424 break;
425
426 case (PACEH2):
427 pace2_moveh (op);
428 break;
429
430 case (RANDO):
431 rand_move (op);
432 break;
433
434 case (RANDO2):
435 move_randomly (op);
436 break;
437 }
438 return 0;
439 }
440 else if (QUERY_FLAG(op,FLAG_RANDOM_MOVE))
441 (void) move_randomly(op);
442
443 } /* stand still */
444 return 0;
445 } /* no enemy */
446
447 /* We have an enemy. Block immediately below is for pets */
448 if((op->attack_movement&HI4) == PETMOVE && (owner = get_owner(op)) != NULL && !on_same_map(op,owner))
449 {
450 follow_owner(op, owner);
451 /* If the pet was unable to follow the owner, free it */
452 if(QUERY_FLAG(op, FLAG_REMOVED) && FABS(op->speed) > MIN_ACTIVE_SPEED) {
453 remove_friendly_object(op);
454 free_object(op);
455 return 1;
456 }
457 return 0;
458 }
459
460 /* doppleganger code to change monster facing to that of the nearest
461 * player. Hmm. The code is here, but no monster in the current
462 * arch set uses it.
463 */
464 if ( (op->race != NULL)&& strcmp(op->race,"doppleganger") == 0)
465 {
466 op->face = enemy->face;
467 if (op->name)
468 free_string(op->name);
469 add_refcount(op->name = enemy->name);
470 }
471
472 /* Calculate range information for closest body part - this
473 * is used for the 'skill' code, which isn't that smart when
474 * it comes to figuring it out - otherwise, giants throw boulders
475 * into themselves.
476 */
477 get_rangevector(op, enemy, &rv, 0);
478
479 /* Move the check for scared up here - if the monster was scared,
480 * we were not doing any of the logic below, so might as well save
481 * a few cpu cycles.
482 */
483 if (!QUERY_FLAG(op, FLAG_SCARED))
484 {
485 rv_vector rv1;
486
487 /* now we test every part of an object .... this is a real ugly piece of code */
488 for (part=op; part!=NULL; part=part->more) {
489 get_rangevector(part, enemy, &rv1, 0x1);
490 dir=rv1.direction;
491
492 /* hm, not sure about this part - in original was a scared flag here too
493 * but that we test above... so can be old code here
494 */
495 if(QUERY_FLAG(op,FLAG_RUN_AWAY))
496 dir=absdir(dir+4);
497 if(QUERY_FLAG(op,FLAG_CONFUSED))
498 dir = absdir(dir + RANDOM()%3 + RANDOM()%3 - 2);
499
500 if(QUERY_FLAG(op,FLAG_CAST_SPELL) && !(RANDOM()%3)) {
501 if(monster_cast_spell(op,part,enemy,dir,&rv1))
502 return 0;
503 }
504
505 if(QUERY_FLAG(op,FLAG_READY_SCROLL) && !(RANDOM()%3)) {
506 if(monster_use_scroll(op,part,enemy,dir,&rv1))
507 return 0;
508 }
509
510 if(QUERY_FLAG(op,FLAG_READY_RANGE)&&!(RANDOM()%3)) {
511 if(monster_use_range(op,part,enemy,dir))
512 return 0;
513 }
514 if(QUERY_FLAG(op,FLAG_READY_SKILL)&&!(RANDOM()%3)) {
515 if(monster_use_skill(op,rv.part,enemy,rv.direction))
516 return 0;
517 }
518 if(QUERY_FLAG(op,FLAG_READY_BOW)&&!(RANDOM()%2)) {
519 if(monster_use_bow(op,part,enemy,dir))
520 return 0;
521 }
522 } /* for processing of all parts */
523 } /* If not scared */
524
525
526 part = rv.part;
527 dir=rv.direction;
528
529 if(QUERY_FLAG(op, FLAG_SCARED) || QUERY_FLAG(op,FLAG_RUN_AWAY))
530 dir=absdir(dir+4);
531
532 if(QUERY_FLAG(op,FLAG_CONFUSED))
533 dir = absdir(dir + RANDOM()%3 + RANDOM()%3 - 2);
534
535 pre_att_dir = dir; /* remember the original direction */
536
537 if ((op->attack_movement & LO4) && !QUERY_FLAG(op, FLAG_SCARED))
538 {
539 switch (op->attack_movement & LO4) {
540 case DISTATT:
541 dir = dist_att (dir,op,enemy,part,&rv);
542 break;
543
544 case RUNATT:
545 dir = run_att (dir,op,enemy,part,&rv);
546 break;
547
548 case HITRUN:
549 dir = hitrun_att(dir,op,enemy);
550 break;
551
552 case WAITATT:
553 dir = wait_att (dir,op,enemy,part,&rv);
554 break;
555
556 case RUSH: /* default - monster normally moves towards player */
557 case ALLRUN:
558 break;
559
560 case DISTHIT:
561 dir = disthit_att (dir,op,enemy,part,&rv);
562 break;
563
564 case WAIT2:
565 dir = wait_att2 (dir,op,enemy,part,&rv);
566 break;
567
568 default:
569 LOG(llevDebug,"Illegal low mon-move: %d\n",op->attack_movement & LO4);
570 }
571 }
572
573 if (!dir)
574 return 0;
575
576 if (!QUERY_FLAG(op,FLAG_STAND_STILL)) {
577 if(move_object(op,dir)) /* Can the monster move directly toward player? */
578 {
579 /* elmex: Turn our monster after it moved if it has DISTATT attack */
580 if ((op->attack_movement & LO4) == DISTATT)
581 op->direction = pre_att_dir;
582
583 return 0;
584 }
585
586 if(QUERY_FLAG(op, FLAG_SCARED) || !can_hit(part,enemy,&rv)
587 || QUERY_FLAG(op,FLAG_RUN_AWAY)) {
588
589 /* Try move around corners if !close */
590 int maxdiff = (QUERY_FLAG(op, FLAG_ONLY_ATTACK) || RANDOM()&1) ? 1 : 2;
591 for(diff = 1; diff <= maxdiff; diff++) {
592 /* try different detours */
593 int m = 1-(RANDOM()&2); /* Try left or right first? */
594 if(move_object(op,absdir(dir + diff*m)) ||
595 move_object(op,absdir(dir - diff*m)))
596 return 0;
597 }
598 }
599 } /* if monster is not standing still */
600
601 /* elmex: Turn our monster after it moved if it has DISTATT attack */
602 if ((op->attack_movement & LO4) == DISTATT)
603 op->direction = pre_att_dir;
604
605 /*
606 * Eneq(@csd.uu.se): Patch to make RUN_AWAY or SCARED monsters move a random
607 * direction if they can't move away.
608 */
609 if (!QUERY_FLAG(op, FLAG_ONLY_ATTACK)&&(QUERY_FLAG(op,FLAG_RUN_AWAY)||QUERY_FLAG(op, FLAG_SCARED)))
610 if(move_randomly(op))
611 return 0;
612
613 /*
614 * Try giving the monster a new enemy - the player that is closest
615 * to it. In this way, it won't just keep trying to get to a target
616 * that is inaccessible.
617 * This could be more clever - it should go through a list of several
618 * enemies, as it is now, you could perhaps get situations where there
619 * are two players flanking the monster at close distance, but which
620 * the monster can't get to, and a third one at a far distance that
621 * the monster could get to - as it is, the monster won't look at that
622 * third one.
623 */
624 if (!QUERY_FLAG(op, FLAG_FRIENDLY) && enemy == op->enemy)
625 {
626 object *nearest_player = get_nearest_player(op);
627 if (nearest_player && nearest_player != enemy && !can_hit(part,enemy,&rv)) {
628 op->enemy = NULL;
629 enemy = nearest_player;
630 }
631 }
632
633 if(!QUERY_FLAG(op, FLAG_SCARED)&&can_hit(part,enemy,&rv))
634 {
635 /* The adjustement to wc that was here before looked totally bogus -
636 * since wc can in fact get negative, that would mean by adding
637 * the current wc, the creature gets better? Instead, just
638 * add a fixed amount - nasty creatures that are runny away should
639 * still be pretty nasty.
640 */
641 if(QUERY_FLAG(op,FLAG_RUN_AWAY))
642 {
643 part->stats.wc+=10;
644 (void)skill_attack(enemy,part,0,NULL, NULL);
645 part->stats.wc-=10;
646 }
647 else
648 (void)skill_attack(enemy,part,0,NULL, NULL);
649 } /* if monster is in attack range */
650
651 if(QUERY_FLAG(part,FLAG_FREED)) /* Might be freed by ghost-attack or hit-back */
652 return 1;
653
654 if(QUERY_FLAG(op, FLAG_ONLY_ATTACK))
655 {
656 remove_ob(op);
657 free_object(op);
658 return 1;
659 }
660 return 0;
661 }
662 int can_hit(object *ob1,object *ob2, rv_vector *rv) {
663 object *more;
664 rv_vector rv1;
665
666 if(QUERY_FLAG(ob1,FLAG_CONFUSED)&&!(RANDOM()%3))
667 return 0;
668
669 if (abs(rv->distance_x)<2&&abs(rv->distance_y)<2) return 1;
670
671 /* check all the parts of ob2 - just because we can't get to
672 * its head doesn't mean we don't want to pound its feet
673 */
674 for (more = ob2->more; more!=NULL; more = more->more) {
675 get_rangevector(ob1, more, &rv1, 0);
676 if (abs(rv1.distance_x)<2&&abs(rv1.distance_y)<2) return 1;
677 }
678 return 0;
679
680 }
681
682 /* Returns 1 is monster should cast spell sp at an enemy
683 * Returns 0 if the monster should not cast this spell.
684 *
685 * Note that this function does not check to see if the monster can
686 * in fact cast the spell (sp dependencies and what not.) That is because
687 * this function is also sued to see if the monster should use spell items
688 * (rod/horn/wand/scroll).
689 * Note that there are certainly other offensive spells that could be
690 * included, but I decided to leave out the spells that may kill more
691 * monsters than players (eg, disease).
692 *
693 * This could be a lot smarter - if there are few monsters around,
694 * then disease might not be as bad. Likewise, if the monster is damaged,
695 * the right type of healing spell could be useful.
696 */
697
698 static int monster_should_cast_spell(object *monster, object *spell_ob)
699 {
700 if (spell_ob->subtype == SP_BOLT || spell_ob->subtype == SP_BULLET ||
701 spell_ob->subtype == SP_EXPLOSION || spell_ob->subtype == SP_CONE ||
702 spell_ob->subtype == SP_BOMB || spell_ob->subtype == SP_SMITE ||
703 spell_ob->subtype == SP_MAGIC_MISSILE || spell_ob->subtype == SP_SUMMON_GOLEM ||
704 spell_ob->subtype == SP_MAGIC_WALL || spell_ob->subtype == SP_SUMMON_MONSTER ||
705 spell_ob->subtype == SP_MOVING_BALL || spell_ob->subtype == SP_SWARM ||
706 spell_ob->subtype == SP_INVISIBLE)
707
708 return 1;
709
710 return 0;
711 }
712
713
714 #define MAX_KNOWN_SPELLS 20
715
716 /* Returns a randomly selected spell. This logic is still
717 * less than ideal. This code also only seems to deal with
718 * wizard spells, as the check is against sp, and not grace.
719 * can mosnters know cleric spells?
720 */
721 object *monster_choose_random_spell(object *monster) {
722 object *altern[MAX_KNOWN_SPELLS];
723 object *tmp;
724 int i=0;
725
726 for(tmp=monster->inv;tmp!=NULL;tmp=tmp->below)
727 if (tmp->type==SPELLBOOK || tmp->type==SPELL) {
728 /* Check and see if it's actually a useful spell.
729 * If its a spellbook, the spell is actually the inventory item.
730 * if it is a spell, then it is just the object itself.
731 */
732 if (monster_should_cast_spell(monster, (tmp->type==SPELLBOOK)?tmp->inv:tmp)) {
733 altern[i++]=tmp;
734 if(i==MAX_KNOWN_SPELLS)
735 break;
736 }
737 }
738 if(!i)
739 return NULL;
740 return altern[RANDOM()%i];
741 }
742
743 /* This checks to see if the monster should cast a spell/ability.
744 * it returns true if the monster casts a spell, 0 if he doesn't.
745 * head is the head of the monster.
746 * part is the part of the monster we are checking against.
747 * pl is the target.
748 * dir is the direction to case.
749 * rv is the vector which describes where the enemy is.
750 */
751
752 int monster_cast_spell(object *head, object *part,object *pl,int dir, rv_vector *rv) {
753 object *spell_item;
754 object *owner;
755 rv_vector rv1;
756
757 /* If you want monsters to cast spells over friends, this spell should
758 * be removed. It probably should be in most cases, since monsters still
759 * don't care about residual effects (ie, casting a cone which may have a
760 * clear path to the player, the side aspects of the code will still hit
761 * other monsters)
762 */
763 if(!(dir=path_to_player(part,pl,0)))
764 return 0;
765
766 if(QUERY_FLAG(head,FLAG_FRIENDLY) && (owner = get_owner(head)) != NULL) {
767 get_rangevector(head, owner, &rv1, 0x1);
768 if(dirdiff(dir,rv1.direction) < 2) {
769 return 0; /* Might hit owner with spell */
770 }
771 }
772
773 if(QUERY_FLAG(head,FLAG_CONFUSED))
774 dir = absdir(dir + RANDOM()%3 + RANDOM()%3 - 2);
775
776 /* If the monster hasn't already chosen a spell, choose one
777 * I'm not sure if it really make sense to pre-select spells (events
778 * could be different by the time the monster goes again).
779 */
780 if(head->spellitem==NULL) {
781 if((spell_item=monster_choose_random_spell(head))==NULL) {
782 LOG(llevMonster,"Turned off spells in %s\n",head->name);
783 CLEAR_FLAG(head, FLAG_CAST_SPELL); /* Will be turned on when picking up book */
784 return 0;
785 }
786 if (spell_item->type == SPELLBOOK) {
787 if (!spell_item->inv) {
788 LOG(llevError,"spellbook %s does not contain a spell?\n", spell_item->name);
789 return 0;
790 }
791 spell_item=spell_item->inv;
792 }
793 }
794 else
795 spell_item=head->spellitem;
796
797 if (!spell_item) return 0;
798
799 /* Best guess this is a defensive/healing spell */
800 if (spell_item->range<=1 || spell_item->stats.dam < 0)
801 dir = 0;
802
803 /* Monster doesn't have enough spell-points */
804 if(head->stats.sp<SP_level_spellpoint_cost(head,spell_item, SPELL_MANA))
805 return 0;
806
807 if(head->stats.grace<SP_level_spellpoint_cost(head,spell_item, SPELL_GRACE))
808 return 0;
809
810 head->stats.sp-=SP_level_spellpoint_cost(head,spell_item, SPELL_MANA);
811 head->stats.grace-=SP_level_spellpoint_cost(head,spell_item, SPELL_GRACE);
812
813 /* set this to null, so next time monster will choose something different */
814 head->spellitem = NULL;
815
816 return cast_spell(part,part,dir, spell_item, NULL);
817 }
818
819
820 int monster_use_scroll(object *head, object *part,object *pl,int dir, rv_vector *rv) {
821 object *scroll;
822 object *owner;
823 rv_vector rv1;
824
825 /* If you want monsters to cast spells over friends, this spell should
826 * be removed. It probably should be in most cases, since monsters still
827 * don't care about residual effects (ie, casting a cone which may have a
828 * clear path to the player, the side aspects of the code will still hit
829 * other monsters)
830 */
831 if(!(dir=path_to_player(part,pl,0)))
832 return 0;
833
834 if(QUERY_FLAG(head,FLAG_FRIENDLY) && (owner = get_owner(head)) != NULL) {
835 get_rangevector(head, owner, &rv1, 0x1);
836 if(dirdiff(dir,rv1.direction) < 2) {
837 return 0; /* Might hit owner with spell */
838 }
839 }
840
841 if(QUERY_FLAG(head,FLAG_CONFUSED))
842 dir = absdir(dir + RANDOM()%3 + RANDOM()%3 - 2);
843
844 for (scroll=head->inv; scroll; scroll=scroll->below)
845 if (scroll->type == SCROLL && monster_should_cast_spell(head, scroll->inv)) break;
846
847 /* Used up all his scrolls, so nothing do to */
848 if (!scroll) {
849 CLEAR_FLAG(head, FLAG_READY_SCROLL);
850 return 0;
851 }
852
853 /* Spell should be cast on caster (ie, heal, strength) */
854 if (scroll->inv->range==0)
855 dir = 0;
856
857 apply_scroll(part, scroll, dir);
858 return 1;
859 }
860
861 /* monster_use_skill()-implemented 95-04-28 to allow monster skill use.
862 * Note that monsters do not need the skills SK_MELEE_WEAPON and
863 * SK_MISSILE_WEAPON to make those respective attacks, if we
864 * required that we would drastically increase the memory
865 * requirements of CF!!
866 *
867 * The skills we are treating here are all but those. -b.t.
868 *
869 * At the moment this is only useful for throwing, perhaps for
870 * stealing. TODO: This should be more integrated in the game. -MT, 25.11.01
871 */
872
873 int monster_use_skill(object *head, object *part, object *pl,int dir) {
874 object *skill, *owner;
875
876 if(!(dir=path_to_player(part,pl,0)))
877 return 0;
878
879 if(QUERY_FLAG(head,FLAG_FRIENDLY) && (owner = get_owner(head)) != NULL) {
880 int dir2 = find_dir_2(head->x-owner->x, head->y-owner->y);
881 if(dirdiff(dir,dir2) < 1)
882 return 0; /* Might hit owner with skill -thrown rocks for example ?*/
883 }
884 if(QUERY_FLAG(head,FLAG_CONFUSED))
885 dir = absdir(dir + RANDOM()%3 + RANDOM()%3 - 2);
886
887 /* skill selection - monster will use the next unused skill.
888 * well...the following scenario will allow the monster to
889 * toggle between 2 skills. One day it would be nice to make
890 * more skills available to monsters.
891 */
892
893 for(skill=head->inv;skill!=NULL;skill=skill->below)
894 if(skill->type==SKILL && skill!=head->chosen_skill) {
895 head->chosen_skill=skill;
896 break;
897 }
898
899 if(!skill && !head->chosen_skill) {
900 LOG(llevDebug,"Error: Monster %s (%d) has FLAG_READY_SKILL without skill.\n",
901 head->name,head->count);
902 CLEAR_FLAG(head, FLAG_READY_SKILL);
903 return 0;
904 }
905 /* use skill */
906 return do_skill(head, part, head->chosen_skill,dir,NULL);
907 }
908
909 /* Monster will use a ranged spell attack. */
910
911 int monster_use_range(object *head,object *part,object *pl,int dir)
912 {
913 object *wand, *owner;
914 int at_least_one = 0;
915
916 if(!(dir=path_to_player(part,pl,0)))
917 return 0;
918
919 if(QUERY_FLAG(head,FLAG_FRIENDLY) && (owner = get_owner(head)) != NULL) {
920 int dir2 = find_dir_2(head->x-owner->x, head->y-owner->y);
921 if(dirdiff(dir,dir2) < 2)
922 return 0; /* Might hit owner with spell */
923 }
924 if(QUERY_FLAG(head,FLAG_CONFUSED))
925 dir = absdir(dir + RANDOM()%3 + RANDOM()%3 - 2);
926
927 for(wand=head->inv;wand!=NULL;wand=wand->below)
928 {
929 if (wand->type == WAND)
930 {
931 /* Found a wand, let's see if it has charges left */
932 at_least_one = 1;
933 if( wand->stats.food<=0 )
934 continue;
935
936 cast_spell( head, wand, dir, wand->inv, NULL );
937
938 if ( !( --wand->stats.food ) )
939 {
940 if ( wand->arch )
941 {
942 CLEAR_FLAG(wand, FLAG_ANIMATE);
943 wand->face = wand->arch->clone.face;
944 wand->speed = 0;
945 update_ob_speed(wand);
946 }
947 }
948 /* Success */
949 return 1;
950 }
951 else if ( wand->type == ROD || wand->type==HORN ) {
952 /* Found rod/horn, let's use it if possible */
953 at_least_one = 1;
954 if( wand->stats.hp < MAX( wand->inv->stats.sp, wand->inv->stats.grace ) )
955 continue;
956
957 /* drain charge before casting spell - can be a case where the
958 * spell destroys the monster, and rod, so if done after, results
959 * in crash.
960 */
961 drain_rod_charge( wand );
962 cast_spell( head, wand, dir, wand->inv, NULL );
963
964 /* Success */
965 return 1;
966 }
967 }
968
969 if ( at_least_one )
970 return 0;
971
972 LOG(llevError,"Error: Monster %s (%d) HAS_READY_RANG() without wand/horn/rod.\n",
973 head->name,head->count);
974 CLEAR_FLAG(head, FLAG_READY_RANGE);
975 return 0;
976 }
977
978 int monster_use_bow(object *head, object *part, object *pl, int dir) {
979 object *owner;
980
981 if(!(dir=path_to_player(part,pl,0)))
982 return 0;
983 if(QUERY_FLAG(head,FLAG_CONFUSED))
984 dir = absdir(dir + RANDOM()%3 + RANDOM()%3 - 2);
985
986 if(QUERY_FLAG(head,FLAG_FRIENDLY) && (owner = get_owner(head)) != NULL) {
987 int dir2 = find_dir_2(head->x-owner->x, head->y-owner->y);
988 if(dirdiff(dir,dir2) < 1)
989 return 0; /* Might hit owner with arrow */
990 }
991
992 /* in server/player.c */
993 return fire_bow(head, part, NULL, dir, 0, part->x, part->y);
994
995 }
996
997 /* Checks if putting on 'item' will make 'who' do more
998 * damage. This is a very simplistic check - also checking things
999 * like speed and ac are also relevant.
1000 *
1001 * return true if item is a better object.
1002 */
1003
1004 int check_good_weapon(object *who, object *item) {
1005 object *other_weap;
1006 int val=0, i;
1007
1008 for(other_weap=who->inv;other_weap!=NULL;other_weap=other_weap->below)
1009 if(other_weap->type==item->type&&QUERY_FLAG(other_weap,FLAG_APPLIED))
1010 break;
1011
1012 if(other_weap==NULL) /* No other weapons */
1013 return 1;
1014
1015 /* Rather than go through and apply the new one, and see if it is
1016 * better, just do some simple checks
1017 * Put some multipliers for things that hvae several effects,
1018 * eg, magic affects both damage and wc, so it has more weight
1019 */
1020
1021 val = item->stats.dam - other_weap->stats.dam;
1022 val += (item->magic - other_weap->magic) * 3;
1023 /* Monsters don't really get benefits from things like regen rates
1024 * from items. But the bonus for their stats are very important.
1025 */
1026 for (i=0; i<NUM_STATS; i++)
1027 val += (get_attr_value(&item->stats, i) - get_attr_value(&other_weap->stats, i))*2;
1028
1029 if (val > 0) return 1;
1030 else return 0;
1031
1032 }
1033
1034 int check_good_armour(object *who, object *item) {
1035 object *other_armour;
1036 int val=0,i;
1037
1038 for (other_armour = who->inv; other_armour != NULL;
1039 other_armour = other_armour->below)
1040 if (other_armour->type == item->type && QUERY_FLAG(other_armour,FLAG_APPLIED))
1041 break;
1042
1043 if (other_armour == NULL) /* No other armour, use the new */
1044 return 1;
1045
1046 /* Like above function , see which is better */
1047 val = item->stats.ac - other_armour->stats.ac;
1048 val = (item->resist[ATNR_PHYSICAL] - other_armour->resist[ATNR_PHYSICAL])/5;
1049 val += (item->magic - other_armour->magic) * 3;
1050
1051 /* for the other protections, do weigh them very much in the equation -
1052 * it is the armor protection which is most important, because there is
1053 * no good way to know what the player may attack the monster with.
1054 * So if the new item has better protection than the old, give that higher
1055 * value. If the reverse, then decrease the value of this item some.
1056 */
1057 for (i=1; i <NROFATTACKS; i++) {
1058 if (item->resist[i] > other_armour->resist[i]) val++;
1059 else if (item->resist[i] < other_armour->resist[i]) val--;
1060 }
1061
1062 /* Very few armours have stats, so not much need to worry about those. */
1063
1064 if (val > 0) return 1;
1065 else return 0;
1066
1067 }
1068
1069 /*
1070 * monster_check_pickup(): checks for items that monster can pick up.
1071 *
1072 * Vick's (vick@bern.docs.uu.se) fix 921030 for the sweeper blob.
1073 * Each time the blob passes over some treasure, it will
1074 * grab it a.s.a.p.
1075 *
1076 * Eneq(@csd.uu.se): This can now be defined in the archetypes, added code
1077 * to handle this.
1078 *
1079 * This function was seen be continueing looping at one point (tmp->below
1080 * became a recursive loop. It may be better to call monster_check_apply
1081 * after we pick everything up, since that function may call others which
1082 * affect stacking on this space.
1083 */
1084
1085 void monster_check_pickup(object *monster) {
1086 object *tmp,*next;
1087 int next_tag;
1088
1089 for(tmp=monster->below;tmp!=NULL;tmp=next) {
1090 next=tmp->below;
1091 next_tag = next ? next->count : 0;
1092 if (monster_can_pick(monster,tmp)) {
1093 remove_ob(tmp);
1094 tmp = insert_ob_in_ob(tmp,monster);
1095 (void) monster_check_apply(monster,tmp);
1096 }
1097 /* We could try to re-establish the cycling, of the space, but probably
1098 * not a big deal to just bail out.
1099 */
1100 if (next && was_destroyed(next, next_tag)) return;
1101 }
1102 }
1103
1104 /*
1105 * monster_can_pick(): If the monster is interested in picking up
1106 * the item, then return 0. Otherwise 0.
1107 * Instead of pick_up, flags for "greed", etc, should be used.
1108 * I've already utilized flags for bows, wands, rings, etc, etc. -Frank.
1109 */
1110
1111 int monster_can_pick(object *monster, object *item) {
1112 int flag=0;
1113 int i;
1114
1115 if(!can_pick(monster,item))
1116 return 0;
1117
1118 if(QUERY_FLAG(item,FLAG_UNPAID))
1119 return 0;
1120
1121 if (monster->pick_up&64) /* All */
1122 flag=1;
1123
1124 else switch(item->type) {
1125 case MONEY:
1126 case GEM:
1127 flag=monster->pick_up&2;
1128 break;
1129
1130 case FOOD:
1131 flag=monster->pick_up&4;
1132 break;
1133
1134 case WEAPON:
1135 flag=(monster->pick_up&8)||QUERY_FLAG(monster,FLAG_USE_WEAPON);
1136 break;
1137
1138 case ARMOUR:
1139 case SHIELD:
1140 case HELMET:
1141 case BOOTS:
1142 case GLOVES:
1143 case GIRDLE:
1144 flag=(monster->pick_up&16)||QUERY_FLAG(monster,FLAG_USE_ARMOUR);
1145 break;
1146
1147 case SKILL:
1148 flag=QUERY_FLAG(monster,FLAG_CAN_USE_SKILL);
1149 break;
1150
1151 case RING:
1152 flag=QUERY_FLAG(monster,FLAG_USE_RING);
1153 break;
1154
1155 case WAND:
1156 case HORN:
1157 case ROD:
1158 flag=QUERY_FLAG(monster,FLAG_USE_RANGE);
1159 break;
1160
1161 case SPELLBOOK:
1162 flag=(monster->arch!=NULL&&QUERY_FLAG((&monster->arch->clone),FLAG_CAST_SPELL));
1163 break;
1164
1165 case SCROLL:
1166 flag = QUERY_FLAG(monster,FLAG_USE_SCROLL);
1167 break;
1168
1169 case BOW:
1170 case ARROW:
1171 flag=QUERY_FLAG(monster,FLAG_USE_BOW);
1172 break;
1173 }
1174 /* Simplistic check - if the monster has a location to equip it, he will
1175 * pick it up. Note that this doesn't handle cases where an item may
1176 * use several locations.
1177 */
1178 for (i=0; i < NUM_BODY_LOCATIONS; i++) {
1179 if (monster->body_info[i] && item->body_info[i]) {
1180 flag=1;
1181 break;
1182 }
1183 }
1184
1185 if (((!(monster->pick_up&32))&&flag) || ((monster->pick_up&32)&&(!flag)))
1186 return 1;
1187 return 0;
1188 }
1189
1190 /*
1191 * monster_apply_below():
1192 * Vick's (vick@bern.docs.uu.se) @921107 -> If a monster who's
1193 * eager to apply things, encounters something apply-able,
1194 * then make him apply it
1195 */
1196
1197 void monster_apply_below(object *monster) {
1198 object *tmp, *next;
1199
1200 for(tmp=monster->below;tmp!=NULL;tmp=next) {
1201 next=tmp->below;
1202 switch (tmp->type) {
1203 case CF_HANDLE:
1204 case TRIGGER:
1205 if (monster->will_apply&1)
1206 manual_apply(monster,tmp,0);
1207 break;
1208
1209 case TREASURE:
1210 if (monster->will_apply&2)
1211 manual_apply(monster,tmp,0);
1212 break;
1213
1214 }
1215 if (QUERY_FLAG (tmp, FLAG_IS_FLOOR))
1216 break;
1217 }
1218 }
1219
1220 /*
1221 * monster_check_apply() is meant to be called after an item is
1222 * inserted in a monster.
1223 * If an item becomes outdated (monster found a better item),
1224 * a pointer to that object is returned, so it can be dropped.
1225 * (so that other monsters can pick it up and use it)
1226 * Note that as things are now, monsters never drop something -
1227 * they can pick up all that they can use.
1228 */
1229
1230 /* Sept 96, fixed this so skills will be readied -b.t.*/
1231
1232 void monster_check_apply(object *mon, object *item) {
1233
1234 int flag = 0;
1235
1236 if(item->type==SPELLBOOK&&
1237 mon->arch!=NULL&&(QUERY_FLAG((&mon->arch->clone),FLAG_CAST_SPELL))) {
1238 SET_FLAG(mon, FLAG_CAST_SPELL);
1239 return;
1240 }
1241
1242 /* If for some reason, this item is already applied, no more work to do */
1243 if(QUERY_FLAG(item,FLAG_APPLIED)) return;
1244
1245 /* Might be better not to do this - if the monster can fire a bow,
1246 * it is possible in his wanderings, he will find one to use. In
1247 * which case, it would be nice to have ammo for it.
1248 */
1249 if(QUERY_FLAG(mon,FLAG_USE_BOW) && item->type==ARROW) {
1250 /* Check for the right kind of bow */
1251 object *bow;
1252 for(bow=mon->inv;bow!=NULL;bow=bow->below)
1253 if(bow->type==BOW && bow->race==item->race) {
1254 SET_FLAG(mon, FLAG_READY_BOW);
1255 LOG(llevMonster,"Found correct bow for arrows.\n");
1256 return; /* nothing more to do for arrows */
1257 }
1258 }
1259
1260 if (item->type == TREASURE && mon->will_apply & WILL_APPLY_TREASURE) flag=1;
1261 /* Eating food gets hp back */
1262 else if (item->type == FOOD && mon->will_apply & WILL_APPLY_FOOD) flag=1;
1263 else if (item->type == SCROLL && QUERY_FLAG(mon, FLAG_USE_SCROLL)) {
1264 if (!item->inv)
1265 LOG(llevDebug,"Monster %d having scroll %d with empty inventory!", mon->count, item->count);
1266 else if (monster_should_cast_spell(mon, item->inv))
1267 SET_FLAG(mon, FLAG_READY_SCROLL);
1268 /* Don't use it right now */
1269 return;
1270 }
1271 else if (item->type == WEAPON) flag = check_good_weapon(mon,item);
1272 else if (IS_ARMOR(item)) flag = check_good_armour(mon,item);
1273 /* Should do something more, like make sure this is a better item */
1274 else if (item->type == RING)
1275 flag=1;
1276 else if ( item->type==WAND || item->type == ROD || item->type==HORN )
1277 {
1278 /* We never really 'ready' the wand/rod/horn, because that would mean the
1279 * weapon would get undone.
1280 */
1281 if (!(can_apply_object(mon, item) & CAN_APPLY_NOT_MASK))
1282 {
1283 SET_FLAG(mon, FLAG_READY_RANGE);
1284 SET_FLAG(item, FLAG_APPLIED);
1285 }
1286 return;
1287 }
1288 else if (item->type == BOW) {
1289 /* We never really 'ready' the bow, because that would mean the
1290 * weapon would get undone.
1291 */
1292 if (!(can_apply_object(mon, item) & CAN_APPLY_NOT_MASK))
1293 SET_FLAG(mon, FLAG_READY_BOW);
1294 return;
1295 }
1296 else if ( item->type == SKILL )
1297 {
1298 /*
1299 * skills are specials: monsters must have the 'FLAG_READY_SKILL' flag set,
1300 * else they can't use the skill...
1301 * Skills also don't need to get applied, so return now.
1302 */
1303 SET_FLAG(mon, FLAG_READY_SKILL);
1304 return;
1305 }
1306
1307
1308 /* if we don't match one of the above types, return now.
1309 * can_apply_object will say that we can apply things like flesh,
1310 * bolts, and whatever else, because it only checks against the
1311 * body_info locations.
1312 */
1313 if (!flag) return;
1314
1315 /* Check to see if the monster can use this item. If not, no need
1316 * to do further processing. Note that can_apply_object already checks
1317 * for the CAN_USE flags.
1318 */
1319 if (can_apply_object(mon, item) & CAN_APPLY_NOT_MASK) return;
1320
1321 /* should only be applying this item, not unapplying it.
1322 * also, ignore status of curse so they can take off old armour.
1323 * monsters have some advantages after all.
1324 */
1325 manual_apply(mon, item, AP_APPLY | AP_IGNORE_CURSE);
1326
1327 return;
1328 }
1329
1330 void npc_call_help(object *op) {
1331 int x,y, mflags;
1332 object *npc;
1333 sint16 sx, sy;
1334 mapstruct *m;
1335
1336 for(x = -3; x < 4; x++)
1337 for(y = -3; y < 4; y++) {
1338 m = op->map;
1339 sx = op->x + x;
1340 sy = op->y + y;
1341 mflags = get_map_flags(m, &m, sx, sy, &sx, &sy);
1342 /* If nothing alive on this space, no need to search the space. */
1343 if ((mflags & P_OUT_OF_MAP) || !(mflags & P_IS_ALIVE))
1344 continue;
1345
1346 for(npc = get_map_ob(m,sx,sy);npc!=NULL;npc=npc->above)
1347 if(QUERY_FLAG(npc, FLAG_ALIVE)&&QUERY_FLAG(npc, FLAG_UNAGGRESSIVE))
1348 npc->enemy = op->enemy;
1349 }
1350 }
1351
1352
1353 int dist_att (int dir , object *ob, object *enemy, object *part, rv_vector *rv) {
1354
1355 if (can_hit(part,enemy,rv))
1356 return dir;
1357 if (rv->distance < 10)
1358 return absdir(dir+4);
1359 else if (rv->distance>18)
1360 return dir;
1361 return 0;
1362 }
1363
1364 int run_att (int dir, object *ob, object *enemy,object *part, rv_vector *rv) {
1365
1366 if ((can_hit (part,enemy,rv) && ob->move_status <20) || ob->move_status <20) {
1367 ob->move_status++;
1368 return (dir);
1369 }
1370 else if (ob->move_status >20)
1371 ob->move_status = 0;
1372 return absdir (dir+4);
1373 }
1374
1375 int hitrun_att (int dir, object *ob,object *enemy) {
1376 if (ob->move_status ++ < 25)
1377 return dir;
1378 else if (ob->move_status <50)
1379 return absdir (dir+4);
1380 else
1381 ob->move_status = 0;
1382 return absdir(dir+4);
1383 }
1384
1385 int wait_att (int dir, object *ob,object *enemy,object *part,rv_vector *rv) {
1386
1387 int inrange = can_hit (part, enemy,rv);
1388
1389 if (ob->move_status || inrange)
1390 ob->move_status++;
1391
1392 if (ob->move_status == 0)
1393 return 0;
1394 else if (ob->move_status <10)
1395 return dir;
1396 else if (ob->move_status <15)
1397 return absdir(dir+4);
1398 ob->move_status = 0;
1399 return 0;
1400 }
1401
1402 int disthit_att (int dir, object *ob, object *enemy, object *part,rv_vector *rv) {
1403
1404 /* The logic below here looked plain wrong before. Basically, what should
1405 * happen is that if the creatures hp percentage falls below run_away,
1406 * the creature should run away (dir+4)
1407 * I think its wrong for a creature to have a zero maxhp value, but
1408 * at least one map has this set, and whatever the map contains, the
1409 * server should try to be resilant enough to avoid the problem
1410 */
1411 if (ob->stats.maxhp && (ob->stats.hp*100)/ob->stats.maxhp < ob->run_away)
1412 return absdir(dir+4);
1413 return dist_att (dir,ob,enemy,part,rv);
1414 }
1415
1416 int wait_att2 (int dir, object *ob,object *enemy,object *part, rv_vector *rv) {
1417 if (rv->distance < 9)
1418 return absdir (dir+4);
1419 return 0;
1420 }
1421
1422 void circ1_move (object *ob) {
1423 static int circle [12] = {3,3,4,5,5,6,7,7,8,1,1,2};
1424 if(++ob->move_status > 11)
1425 ob->move_status = 0;
1426 if (!(move_object(ob,circle[ob->move_status])))
1427 (void) move_object(ob,RANDOM()%8+1);
1428 }
1429
1430 void circ2_move (object *ob) {
1431 static int circle[20] = {3,3,3,4,4,5,5,5,6,6,7,7,7,8,8,1,1,1,2,2};
1432 if(++ob->move_status > 19)
1433 ob->move_status = 0;
1434 if(!(move_object(ob,circle[ob->move_status])))
1435 (void) move_object(ob,RANDOM()%8+1);
1436 }
1437
1438 void pace_movev(object *ob) {
1439 if (ob->move_status++ > 6)
1440 ob->move_status = 0;
1441 if (ob->move_status < 4)
1442 (void) move_object (ob,5);
1443 else
1444 (void) move_object(ob,1);
1445 }
1446
1447 void pace_moveh (object *ob) {
1448 if (ob->move_status++ > 6)
1449 ob->move_status = 0;
1450 if (ob->move_status < 4)
1451 (void) move_object(ob,3);
1452 else
1453 (void) move_object(ob,7);
1454 }
1455
1456 void pace2_movev (object *ob) {
1457 if (ob->move_status ++ > 16)
1458 ob->move_status = 0;
1459 if (ob->move_status <6)
1460 (void) move_object (ob,5);
1461 else if (ob->move_status < 8)
1462 return;
1463 else if (ob->move_status <13)
1464 (void) move_object (ob,1);
1465 else return;
1466 }
1467
1468 void pace2_moveh (object *ob) {
1469 if (ob->move_status ++ > 16)
1470 ob->move_status = 0;
1471 if (ob->move_status <6)
1472 (void) move_object (ob,3);
1473 else if (ob->move_status < 8)
1474 return;
1475 else if (ob->move_status <13)
1476 (void) move_object (ob,7);
1477 else return;
1478 }
1479
1480 void rand_move (object *ob) {
1481 int i;
1482 if (ob->move_status <1 || ob->move_status >8 ||
1483 !(move_object(ob,ob->move_status|| ! (RANDOM()% 9))))
1484 for (i = 0; i < 5; i++)
1485 if (move_object(ob,ob->move_status = RANDOM()%8+1))
1486 return;
1487 }
1488
1489 void check_earthwalls(object *op, mapstruct *m, int x, int y) {
1490 object *tmp;
1491 for (tmp = get_map_ob(m, x, y); tmp!=NULL; tmp=tmp->above) {
1492 if (tmp->type == EARTHWALL) {
1493 hit_player(tmp,op->stats.dam,op,AT_PHYSICAL,1);
1494 return;
1495 }
1496 }
1497 }
1498
1499 void check_doors(object *op, mapstruct *m, int x, int y) {
1500 object *tmp;
1501 for (tmp = get_map_ob(m, x, y); tmp!=NULL; tmp=tmp->above) {
1502 if (tmp->type == DOOR) {
1503 hit_player(tmp,1000,op,AT_PHYSICAL,1);
1504 return;
1505 }
1506 }
1507 }
1508
1509 /* This replaces all the msglang stuff about which seems to be a lot of
1510 * unneeded complication - since the setup of that data is never re-used
1511 * (say 'hi' to monster, then 'yes', it would re-do the entire parse-message)
1512 * it seems to me to make more sense to just have simple function that returns
1513 * the 'text' portion of the message that it matches - this savees us a bunch
1514 * of malloc's and free's, as well as that setup.
1515 * This function takes the message to be parsed in 'msg', the text to
1516 * match in 'match', and returns the portion of the message. This
1517 * returned portion is in a malloc'd buf that should be freed.
1518 * Returns NULL if no match is found.
1519 * The player is passed too, so that quest-related messages can be checked too.
1520 */
1521 static char *find_matching_message(object* pl, const char *msg, const char *match)
1522 {
1523 const char *cp=msg, *cp1, *cp2;
1524 char *cp3, regex[MAX_BUF], gotmatch=0;
1525
1526 while (1) {
1527 if (strncmp(cp, "@match ", 7)) {
1528 LOG(llevDebug,"find_matching_message: Invalid message %s", msg);
1529 return NULL;
1530 }
1531 else {
1532 /* Find the end of the line, and copy the regex portion into it */
1533 cp2 = strchr(cp+7, '\n');
1534 strncpy(regex, cp+7, (cp2 - cp -7 ));
1535 regex[cp2 - cp -7] = 0;
1536
1537 /* Find the next match command */
1538 cp1 = strstr(cp+6, "\n@match");
1539
1540 /* Got a match - handle * as special case - proper regex would be .*,
1541 * but lots of messages don't use that form.
1542 */
1543 if (regex[0] == '*') gotmatch=1;
1544 else {
1545 char *pipe, *pnext=NULL;
1546 /* need to parse all the | seperators. Our re_cmp isn't
1547 * realy a fully blown regex parser.
1548 */
1549 for (pipe=regex; pipe != NULL; pipe = pnext) {
1550 pnext = strchr(pipe, '|');
1551 if (pnext) {
1552 *pnext = 0;
1553 pnext ++;
1554 }
1555 if (re_cmp(match, pipe)) {
1556 gotmatch = 1;
1557 break;
1558 }
1559 }
1560 }
1561 if (gotmatch) {
1562 if (cp1) {
1563 cp3 = malloc(cp1 - cp2 + 1);
1564 strncpy(cp3, cp2+1, cp1 - cp2);
1565 cp3[cp1 - cp2] = 0;
1566 }
1567 else { /* if no next match, just want the rest of the string */
1568 cp3 = strdup_local(cp2+1);
1569 }
1570 return cp3;
1571 }
1572 gotmatch = 0;
1573 if (cp1) cp = cp1 + 1;
1574 else return NULL;
1575 }
1576 }
1577 /* Should never get reached */
1578 }
1579
1580 /* This function looks for an object or creature that is listening.
1581 * I've disabled the bit that has only the first npc monster listen -
1582 * we'll see how this works out. only the first npc listens, which
1583 * is sort of bogus since it uses the free_arr which has a preference
1584 * to certain directions.
1585 *
1586 * There is a rare even that the orig_map is used for - basically, if
1587 * a player says the magic word that gets him teleported off the map,
1588 * it can result in the new map putting the object count too high,
1589 * which forces the swap out of some other map. In some cases, the
1590 * map the player was just on now gets swapped out - thus, the
1591 * object on that map are no longer in memory. So check to see if the
1592 * players map changes, and if so, don't process any further.
1593 * If it does change, most likely we don't care about the results
1594 * of further conversation. Also, depending on the value of i,
1595 * the conversation would continue on the new map, which probably isn't
1596 * what is really wanted either.
1597 */
1598 void communicate(object *op, const char *txt) {
1599 object *npc;
1600 int i, mflags;
1601 sint16 x, y;
1602 mapstruct *mp, *orig_map = op->map;
1603
1604 int flag=1; /*hasn't spoken to a NPC yet*/
1605 for(i = 0; i <= SIZEOFFREE2; i++) {
1606
1607 mp = op->map;
1608 x = op->x + freearr_x[i];
1609 y = op->y + freearr_y[i];
1610
1611 mflags = get_map_flags(mp, &mp, x, y, &x, &y);
1612 if (mflags & P_OUT_OF_MAP) continue;
1613
1614 for(npc = get_map_ob(mp,x,y); npc != NULL; npc = npc->above) {
1615 if (npc->type == MAGIC_EAR) {
1616 (void) talk_to_wall(op, npc, txt); /* Maybe exit after 1. success? */
1617 if (orig_map != op->map) {
1618 LOG(llevDebug,"Warning: Forced to swap out very recent map - MAX_OBJECTS should probably be increased\n");
1619 return;
1620 }
1621 }
1622 else if (flag) {
1623 #if 0
1624 if (talk_to_npc(op, npc,txt))
1625 flag=0; /* Can be crowded */
1626 #else
1627 talk_to_npc(op, npc,txt);
1628 #endif
1629 if (orig_map != op->map) {
1630 LOG(llevDebug,"Warning: Forced to swap out very recent map - MAX_OBJECTS should probably be increased\n");
1631 return;
1632 }
1633 }
1634 }
1635 }
1636 }
1637
1638 static int do_talk_npc(object* op, object* npc, object* override, const char* txt)
1639 {
1640 char* cp;
1641 char buf[MAX_BUF];
1642
1643 if(override->msg == NULL || *override->msg != '@')
1644 return 0;
1645
1646 cp = find_matching_message(op, override->msg, txt);
1647 if (cp) {
1648 sprintf(buf,"%s says:",query_name(npc));
1649 new_info_map(NDI_NAVY|NDI_UNIQUE, npc->map,buf);
1650 new_info_map(NDI_NAVY | NDI_UNIQUE, npc->map, cp);
1651 quest_apply_items(override,op->contr);
1652 free(cp);
1653 return 1;
1654 }
1655 return 0;
1656 }
1657
1658 int talk_to_npc(object *op, object *npc, const char *txt) {
1659 object *cobj;
1660
1661 /* Move this commone area up here - shouldn't cost much extra cpu
1662 * time, and makes the function more readable */
1663 /* Lauwenmark: Handle for plugin say event */
1664 if (op==npc) return 0;
1665 if (execute_event(npc, EVENT_SAY,op,NULL,txt,SCRIPT_FIX_ALL)!=0)
1666 return 0;
1667 /* Lauwenmark - Here we let the objects inside inventories hear and answer, too. */
1668 /* This allows the existence of "intelligent" weapons you can discuss with */
1669 for(cobj=npc->inv;cobj!=NULL; cobj = cobj->below)
1670 {
1671 if (execute_event(cobj, EVENT_SAY,op,NULL,txt,SCRIPT_FIX_ALL)!=0)
1672 return 0;
1673 }
1674 for ( cobj = npc->inv; cobj; cobj = cobj->below )
1675 if ( quest_is_override_compatible( cobj, op ) )
1676 if ( do_talk_npc( op, npc, cobj, txt ) )
1677 return 1;
1678 return do_talk_npc( op, npc, npc, txt );
1679 }
1680
1681 static int do_talk_wall(object* pl, object* npc, object* override, const char* txt)
1682 {
1683 char* cp;
1684 if(override->msg == NULL || *override->msg != '@')
1685 return 0;
1686
1687 cp = find_matching_message(pl, override->msg, txt);
1688 if (!cp)
1689 return 0;
1690
1691 new_info_map(NDI_NAVY | NDI_UNIQUE, npc->map,cp);
1692 use_trigger(npc);
1693 quest_apply_items(npc, pl->contr);
1694 free(cp);
1695
1696 return 1;
1697 }
1698
1699 int talk_to_wall(object* pl, object *npc, const char *txt) {
1700
1701 object* inv;
1702
1703 for ( inv = npc->inv; inv; inv = inv->below)
1704 if ( quest_is_override_compatible(inv, pl ) )
1705 if ( do_talk_wall( pl, npc, inv, txt ) )
1706 return 1;
1707
1708 return do_talk_wall( pl, npc, npc, txt );;
1709 }
1710
1711 /* find_mon_throw_ob() - modeled on find_throw_ob
1712 * This is probably overly simplistic as it is now - We want
1713 * monsters to throw things like chairs and other pieces of
1714 * furniture, even if they are not good throwable objects.
1715 * Probably better to have the monster throw a throwable object
1716 * first, then throw any non equipped weapon.
1717 */
1718
1719 object *find_mon_throw_ob( object *op ) {
1720 object *tmp = NULL;
1721
1722 if(op->head) tmp=op->head; else tmp=op;
1723
1724 /* New throw code: look through the inventory. Grap the first legal is_thrown
1725 * marked item and throw it to the enemy.
1726 */
1727
1728 for(tmp=op->inv;tmp;tmp=tmp->below) {
1729
1730 /* Can't throw invisible objects or items that are applied */
1731 if(tmp->invisible || QUERY_FLAG(tmp,FLAG_APPLIED)) continue;
1732
1733 if(QUERY_FLAG(tmp,FLAG_IS_THROWN))
1734 break;
1735
1736 }
1737
1738 #ifdef DEBUG_THROW
1739 LOG(llevDebug,"%s chooses to throw: %s (%d)\n",op->name,
1740 !(tmp)?"(nothing)":query_name(tmp),tmp?tmp->count:-1);
1741 #endif
1742
1743 return tmp;
1744 }
1745
1746 /* determine if we can 'detect' the enemy. Check for walls blocking the
1747 * los. Also, just because its hidden/invisible, we may be sensitive/smart
1748 * enough (based on Wis & Int) to figure out where the enemy is. -b.t.
1749 * modified by MSW to use the get_rangevector so that map tiling works
1750 * properly. I also so odd code in place that checked for x distance
1751 * OR y distance being within some range - that seemed wrong - both should
1752 * be within the valid range. MSW 2001-08-05
1753 * Returns 0 if enemy can not be detected, 1 if it is detected
1754 */
1755
1756 int can_detect_enemy (object *op, object *enemy, rv_vector *rv) {
1757 int radius = MIN_MON_RADIUS, hide_discovery;
1758
1759 /* null detection for any of these condtions always */
1760 if(!op || !enemy || !op->map || !enemy->map)
1761 return 0;
1762
1763 /* If the monster (op) has no way to get to the enemy, do nothing */
1764 if (!on_same_map(op, enemy))
1765 return 0;
1766
1767 get_rangevector(op, enemy, rv, 0);
1768
1769 /* Monsters always ignore the DM */
1770 if ( ( op->type != PLAYER ) && QUERY_FLAG( enemy, FLAG_WIZ ) )
1771 return 0;
1772
1773 /* simple check. Should probably put some range checks in here. */
1774 if(can_see_enemy(op,enemy)) return 1;
1775
1776 /* The rest of this is for monsters. Players are on their own for
1777 * finding enemies!
1778 */
1779 if(op->type==PLAYER) return 0;
1780
1781 /* Quality invisible? Bah, we wont see them w/o SEE_INVISIBLE
1782 * flag (which was already checked) in can_see_enmy (). Lets get out of here
1783 */
1784 if(enemy->invisible && (!enemy->contr || (!enemy->contr->tmp_invis && !enemy->contr->hidden)))
1785 return 0;
1786
1787 /* use this for invis also */
1788 hide_discovery = op->stats.Int/5;
1789
1790 /* Determine Detection radii */
1791 if(!enemy->hide) /* to detect non-hidden (eg dark/invis enemy) */
1792 radius = (op->stats.Wis/5)+1>MIN_MON_RADIUS?(op->stats.Wis/5)+1:MIN_MON_RADIUS;
1793 else { /* a level/INT/Dex adjustment for hiding */
1794 object *sk_hide;
1795 int bonus = (op->level/2) + (op->stats.Int/5);
1796
1797 if(enemy->type==PLAYER) {
1798 if((sk_hide = find_skill_by_number(enemy,SK_HIDING)))
1799 bonus -= sk_hide->level;
1800 else {
1801 LOG(llevError,"can_detect_enemy() got hidden player w/o hiding skill!\n");
1802 make_visible(enemy);
1803 radius=radius<MIN_MON_RADIUS?MIN_MON_RADIUS:radius;
1804 }
1805 }
1806 else /* enemy is not a player */
1807 bonus -= enemy->level;
1808
1809 radius += bonus/5;
1810 hide_discovery += bonus*5;
1811 } /* else creature has modifiers for hiding */
1812
1813 /* Radii stealth adjustment. Only if you are stealthy
1814 * will you be able to sneak up closer to creatures */
1815 if(QUERY_FLAG(enemy,FLAG_STEALTH))
1816 radius = radius/2, hide_discovery = hide_discovery/3;
1817
1818 /* Radii adjustment for enemy standing in the dark */
1819 if(op->map->darkness>0 && !stand_in_light(enemy)) {
1820 /* on dark maps body heat can help indicate location with infravision
1821 * undead don't have body heat, so no benefit detecting them.
1822 */
1823 if(QUERY_FLAG(op,FLAG_SEE_IN_DARK) && !is_true_undead(enemy))
1824 radius += op->map->darkness/2;
1825 else
1826 radius -= op->map->darkness/2;
1827
1828 /* op next to a monster (and not in complete darkness)
1829 * the monster should have a chance to see you.
1830 */
1831 if(radius<MIN_MON_RADIUS && op->map->darkness<5 && rv->distance<=1)
1832 radius = MIN_MON_RADIUS;
1833 } /* if on dark map */
1834
1835 /* Lets not worry about monsters that have incredible detection
1836 * radii, we only need to worry here about things the player can
1837 * (potentially) see. This is 13, as that is the maximum size the player
1838 * may have for their map - in that way, creatures at the edge will
1839 * do something. Note that the distance field in the
1840 * vector is real distance, so in theory this should be 18 to
1841 * find that.
1842 */
1843 if(radius>13) radius = 13;
1844
1845 /* Enemy in range! Now test for detection */
1846 if ((int) rv->distance <= radius) {
1847 /* ah, we are within range, detected? take cases */
1848 if(!enemy->invisible) /* enemy in dark squares... are seen! */
1849 return 1;
1850
1851 /* hidden or low-quality invisible */
1852 if(enemy->hide && (rv->distance <= 1) && (RANDOM()%100<=hide_discovery)) {
1853 make_visible(enemy);
1854 /* inform players of new status */
1855 if(enemy->type==PLAYER && player_can_view(enemy,op))
1856 new_draw_info_format(NDI_UNIQUE,0, enemy,
1857 "You are discovered by %s!",op->name);
1858 return 1; /* detected enemy */
1859 }
1860 else if (enemy->invisible) {
1861 /* Change this around - instead of negating the invisible, just
1862 * return true so that the mosnter that managed to detect you can
1863 * do something to you. Decreasing the duration of invisible
1864 * doesn't make a lot of sense IMO, as a bunch of stupid creatures
1865 * can then basically negate the spell. The spell isn't negated -
1866 * they just know where you are!
1867 */
1868 if ((RANDOM() % 50) <= hide_discovery) {
1869 if (enemy->type == PLAYER) {
1870 new_draw_info_format(NDI_UNIQUE,0, enemy,
1871 "You see %s noticing your position.", query_name(op));
1872 }
1873 return 1;
1874 }
1875 }
1876 } /* within range */
1877
1878 /* Wasn't detected above, so still hidden */
1879 return 0;
1880 }
1881
1882 /* determine if op stands in a lighted square. This is not a very
1883 * intellegent algorithm. For one thing, we ignore los here, SO it
1884 * is possible for a bright light to illuminate a player on the
1885 * other side of a wall (!).
1886 */
1887
1888 int stand_in_light( object *op) {
1889 sint16 nx,ny;
1890 mapstruct *m;
1891
1892
1893 if(!op) return 0;
1894 if(op->glow_radius > 0) return 1;
1895
1896 if(op->map) {
1897 int x, y, x1, y1;
1898
1899
1900
1901 /* Check the spaces with the max light radius to see if any of them
1902 * have lights, and if any of them light the player enough, then return 1.
1903 */
1904 for (x = op->x - MAX_LIGHT_RADII; x <= op->x + MAX_LIGHT_RADII; x++) {
1905 for (y = op->y - MAX_LIGHT_RADII; y <= op->y + MAX_LIGHT_RADII; y++) {
1906 m = op->map;
1907 nx = x;
1908 ny = y;
1909
1910 if (get_map_flags(m, &m, nx, ny, &nx, &ny) & P_OUT_OF_MAP) continue;
1911
1912 x1 = abs(x - op->x)*abs(x - op->x);
1913 y1 = abs(y - op->y)*abs(y - op->y);
1914 if (isqrt(x1 + y1) < GET_MAP_LIGHT(m, nx, ny)) return 1;
1915 }
1916 }
1917 }
1918 return 0;
1919 }
1920
1921
1922 /* assuming no walls/barriers, lets check to see if its *possible*
1923 * to see an enemy. Note, "detection" is different from "seeing".
1924 * See can_detect_enemy() for more details. -b.t.
1925 * return 0 if can't be seen, 1 if can be
1926 */
1927
1928 int can_see_enemy (object *op, object *enemy) {
1929 object *looker = op->head?op->head:op;
1930
1931 /* safety */
1932 if(!looker||!enemy||!QUERY_FLAG(looker,FLAG_ALIVE))
1933 return 0;
1934
1935 /* we dont give a full treatment of xrays here (shorter range than normal,
1936 * see through walls). Should we change the code elsewhere to make you
1937 * blind even if you can xray?
1938 */
1939 if(QUERY_FLAG(looker,FLAG_BLIND) && !QUERY_FLAG(looker,FLAG_XRAYS))
1940 return 0;
1941
1942 /* checking for invisible things */
1943 if(enemy->invisible) {
1944 /* HIDDEN ENEMY. by definition, you can't see hidden stuff!
1945 * However,if you carry any source of light, then the hidden
1946 * creature is seeable (and stupid) */
1947
1948 if(has_carried_lights(enemy)) {
1949 if(enemy->hide) {
1950 make_visible(enemy);
1951 new_draw_info(NDI_UNIQUE,0, enemy,
1952 "Your light reveals your hiding spot!");
1953 }
1954 return 1;
1955 } else if (enemy->hide) return 0;
1956
1957 /* Invisible enemy. Break apart the check for invis undead/invis looker
1958 * into more simple checks - the QUERY_FLAG doesn't return 1/0 values,
1959 * and making it a conditional makes the code pretty ugly.
1960 */
1961 if (!QUERY_FLAG(looker,FLAG_SEE_INVISIBLE)) {
1962 if (makes_invisible_to(enemy, looker)) return 0;
1963 }
1964 } else if(looker->type==PLAYER) /* for players, a (possible) shortcut */
1965 if(player_can_view(looker,enemy)) return 1;
1966
1967 /* ENEMY IN DARK MAP. Without infravision, the enemy is not seen
1968 * unless they carry a light or stand in light. Darkness doesnt
1969 * inhibit the undead per se (but we should give their archs
1970 * CAN_SEE_IN_DARK, this is just a safety
1971 * we care about the enemy maps status, not the looker.
1972 * only relevant for tiled maps, but it is possible that the
1973 * enemy is on a bright map and the looker on a dark - in that
1974 * case, the looker can still see the enemy
1975 */
1976 if(enemy->map->darkness>0&&!stand_in_light(enemy)
1977 &&(!QUERY_FLAG(looker,FLAG_SEE_IN_DARK)||
1978 !is_true_undead(looker)||!QUERY_FLAG(looker,FLAG_XRAYS)))
1979 return 0;
1980
1981 return 1;
1982 }
1983