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

# User Rev Content
1 root 1.1 /*
2     * static char *rcsid_monster_c =
3 root 1.3 * "$Id$";
4 root 1.1 */
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 elmex 1.6 int dir, diff, pre_att_dir; /* elmex: pre_att_dir remembers the direction before attack movement */
297 root 1.1 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 root 1.2 if (execute_event (op, EVENT_MOVE, op->enemy, 0, 0, SCRIPT_FIX_ALL))
385     return 0;
386    
387 root 1.1 /* 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 elmex 1.6 pre_att_dir = dir; /* remember the original direction */
536    
537 root 1.1 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 elmex 1.6 {
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 root 1.1 return 0;
584 elmex 1.6 }
585 root 1.1
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 1.6 /* 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 root 1.1 /*
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 elmex 1.4 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 root 1.1 }
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 root 1.5 if (execute_event(cobj, EVENT_SAY,op,NULL,txt,SCRIPT_FIX_ALL)!=0)
1672 root 1.1 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