Crossfire Server, Branch 1.12  R12190
monster.c
Go to the documentation of this file.
00001 /*
00002  * static char *rcsid_monster_c =
00003  *    "$Id: monster.c 11644 2009-04-15 06:24:55Z mwedel $";
00004  */
00005 
00006 /*
00007     CrossFire, A Multiplayer game for X-windows
00008 
00009     Copyright (C) 2002-2007 Mark Wedel & Crossfire Development Team
00010     Copyright (C) 1992 Frank Tore Johansen
00011 
00012     This program is free software; you can redistribute it and/or modify
00013     it under the terms of the GNU General Public License as published by
00014     the Free Software Foundation; either version 2 of the License, or
00015     (at your option) any later version.
00016 
00017     This program is distributed in the hope that it will be useful,
00018     but WITHOUT ANY WARRANTY; without even the implied warranty of
00019     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00020     GNU General Public License for more details.
00021 
00022     You should have received a copy of the GNU General Public License
00023     along with this program; if not, write to the Free Software
00024     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
00025 
00026     The authors can be reached via e-mail at crossfire-devel@real-time.com
00027 */
00028 
00035 #include <assert.h>
00036 #include <global.h>
00037 #ifndef __CEXTRACT__
00038 #include <sproto.h>
00039 #include <spells.h>
00040 #include <skills.h>
00041 #endif
00042 
00043 static int can_hit(object *ob1, object *ob2, rv_vector *rv);
00044 static int monster_cast_spell(object *head, object *part, object *pl, int dir, rv_vector *rv);
00045 static int monster_use_scroll(object *head, object *part, object *pl, int dir, rv_vector *rv);
00046 static int monster_use_skill(object *head, object *part, object *pl, int dir);
00047 static int monster_use_range(object *head, object *part, object *pl, int dir);
00048 static int monster_use_bow(object *head, object *part, object *pl, int dir);
00049 static void monster_check_pickup(object *monster);
00050 static int monster_can_pick(object *monster, object *item);
00051 static void monster_apply_below(object *monster);
00052 static int dist_att(int dir, object *ob, object *enemy, object *part, rv_vector *rv);
00053 static int run_att(int dir, object *ob, object *enemy, object *part, rv_vector *rv);
00054 static int hitrun_att(int dir, object *ob, object *enemy);
00055 static int wait_att(int dir, object *ob, object *enemy, object *part, rv_vector *rv);
00056 static int disthit_att(int dir, object *ob, object *enemy, object *part, rv_vector *rv);
00057 static int wait_att2(int dir, object *ob, object *enemy, object *part, rv_vector *rv);
00058 static void circ1_move(object *ob);
00059 static void circ2_move(object *ob);
00060 static void pace_movev(object *ob);
00061 static void pace_moveh(object *ob);
00062 static void pace2_movev(object *ob);
00063 static void pace2_moveh(object *ob);
00064 static void rand_move(object *ob);
00065 static int talk_to_npc(object *op, object *npc, const char *txt, int *talked);
00066 
00067 #define MIN_MON_RADIUS 3 /* minimum monster detection radius */
00068 
00083 object *check_enemy(object *npc, rv_vector *rv) {
00084     /* if this is pet, let him attack the same enemy as his owner
00085      * TODO: when there is no ower enemy, try to find a target,
00086      * which CAN attack the owner. */
00087     if ((npc->attack_movement&HI4) == PETMOVE) {
00088         if (npc->owner == NULL)
00089             npc->enemy = NULL;
00090         else if (npc->enemy == NULL)
00091             npc->enemy = npc->owner->enemy;
00092     }
00093 
00094     /* periodically, a monster mayu change its target.  Also, if the object
00095      * has been destroyed, etc, clear the enemy.
00096      * TODO: this should be changed, because it invokes to attack forced or
00097      * attacked monsters to leave the attacker alone, before it is destroyed
00098      */
00099     /* i had removed the random target leave, this invokes problems with friendly
00100      * objects, getting attacked and defending herself - they don't try to attack
00101      * again then but perhaps get attack on and on
00102      * If we include a aggravated flag in , we can handle evil vs evil and good vs good
00103      * too. */
00104 
00105     if (npc->enemy) {
00106         /* I broke these if's apart to better be able to see what
00107          * the grouping checks are.  Code is the same.
00108          */
00109         if (QUERY_FLAG(npc->enemy, FLAG_REMOVED)
00110         || QUERY_FLAG(npc->enemy, FLAG_FREED)
00111         || !on_same_map(npc, npc->enemy)
00112         || npc == npc->enemy
00113         || QUERY_FLAG(npc, FLAG_NEUTRAL)
00114         || QUERY_FLAG(npc->enemy, FLAG_NEUTRAL))
00115             npc->enemy = NULL;
00116 
00117         else if (QUERY_FLAG(npc, FLAG_FRIENDLY) && (
00118                 (QUERY_FLAG(npc->enemy, FLAG_FRIENDLY) && !(should_arena_attack(npc, npc->owner, npc->enemy)))
00119                 || ((npc->enemy->type == PLAYER) && !(should_arena_attack(npc, npc->owner, npc->enemy)))
00120                 || npc->enemy == npc->owner))
00121             npc->enemy = NULL;
00122         else if (!QUERY_FLAG(npc, FLAG_FRIENDLY)
00123         && (!QUERY_FLAG(npc->enemy, FLAG_FRIENDLY) && npc->enemy->type != PLAYER))
00124             npc->enemy = NULL;
00125 
00126         /* I've noticed that pets could sometimes get an arrow as the
00127          * target enemy - this code below makes sure the enemy is something
00128          * that should be attacked.  My guess is that the arrow hits
00129          * the creature/owner, and so the creature then takes that
00130          * as the enemy to attack.
00131          */
00132         else if (!QUERY_FLAG(npc->enemy, FLAG_MONSTER)
00133         && !QUERY_FLAG(npc->enemy, FLAG_GENERATOR)
00134         && npc->enemy->type != PLAYER
00135         && npc->enemy->type != GOLEM)
00136             npc->enemy = NULL;
00137 
00138     }
00139     return can_detect_enemy(npc, npc->enemy, rv) ? npc->enemy : NULL;
00140 }
00141 
00162 object *find_nearest_living_creature(object *npc) {
00163     int i, mflags;
00164     sint16 nx, ny;
00165     mapstruct *m;
00166     object *tmp;
00167     int search_arr[SIZEOFFREE];
00168 
00169     get_search_arr(search_arr);
00170     for (i = 0; i < SIZEOFFREE; i++) {
00171         /* modified to implement smart searching using search_arr
00172          * guidance array to determine direction of search order
00173          */
00174         nx = npc->x+freearr_x[search_arr[i]];
00175         ny = npc->y+freearr_y[search_arr[i]];
00176         m = npc->map;
00177 
00178         mflags = get_map_flags(m, &m, nx, ny, &nx, &ny);
00179         if (mflags&P_OUT_OF_MAP)
00180             continue;
00181 
00182         if (mflags&P_IS_ALIVE) {
00183             tmp = GET_MAP_OB(m, nx, ny);
00184             while (tmp != NULL
00185             && !QUERY_FLAG(tmp, FLAG_MONSTER)
00186             && !QUERY_FLAG(tmp, FLAG_GENERATOR)
00187             && tmp->type != PLAYER)
00188                 tmp = tmp->above;
00189 
00190             if (!tmp) {
00191                 LOG(llevDebug, "find_nearest_living_creature: map %s (%d,%d) has is_alive set but did not find a monster?\n", m->path, nx, ny);
00192             } else {
00193                 if (can_see_monsterP(m, nx, ny, i))
00194                     return tmp;
00195             }
00196         } /* is something living on this space */
00197     }
00198     return NULL;  /* nothing found */
00199 }
00200 
00216 static object *find_enemy(object *npc, rv_vector *rv) {
00217     object *attacker, *tmp = NULL;
00218 
00219     attacker = npc->attacked_by; /* save this for later use. This can be a attacker. */
00220     npc->attacked_by = NULL;     /* always clear the attacker entry */
00221 
00222     /* if we berserk, we don't care about others - we attack all we can find */
00223     if (QUERY_FLAG(npc, FLAG_BERSERK)) {
00224         tmp = find_nearest_living_creature(npc);
00225         if (tmp)
00226             get_rangevector(npc, tmp, rv, 0);
00227         return tmp;
00228     }
00229 
00230     /* Here is the main enemy selection.
00231      * We want this: if there is an enemy, attack him until its not possible or
00232      * one of both is dead.
00233      * If we have no enemy and we are...
00234      * a monster: try to find a player, a pet or a friendly monster
00235      * a friendly: only target a monster which is targeting you first or targeting a player
00236      * a neutral: fight a attacker (but there should be none), then do nothing
00237      * a pet: attack player enemy or a monster
00238      */
00239 
00240     /* pet move */
00241     if ((npc->attack_movement&HI4) == PETMOVE) {
00242         tmp = get_pet_enemy(npc, rv);
00243         if (tmp)
00244             get_rangevector(npc, tmp, rv, 0);
00245         return tmp;
00246     }
00247 
00248     /* we check our old enemy. */
00249     if ((tmp = check_enemy(npc, rv)) == NULL) {
00250         if (attacker) { /* if we have an attacker, check him */
00251             /* we want be sure this is the right one! */
00252             if (attacker->count == npc->attacked_by_count) {
00253                 /* TODO: thats not finished */
00254                 /* we don't want a fight evil vs evil or good against non evil */
00255                 if (QUERY_FLAG(npc, FLAG_NEUTRAL)
00256                 || QUERY_FLAG(attacker, FLAG_NEUTRAL) /* neutral */
00257                 || (QUERY_FLAG(npc, FLAG_FRIENDLY) && QUERY_FLAG(attacker, FLAG_FRIENDLY))
00258                 || (!QUERY_FLAG(npc, FLAG_FRIENDLY) && (!QUERY_FLAG(attacker, FLAG_FRIENDLY) && attacker->type != PLAYER)))
00259                     CLEAR_FLAG(npc, FLAG_SLEEP); /* skip it, but lets wakeup */
00260                 else if (on_same_map(npc, attacker)) { /* thats the only thing we must know... */
00261                     CLEAR_FLAG(npc, FLAG_SLEEP); /* well, NOW we really should wake up! */
00262                     npc->enemy = attacker;
00263                     get_rangevector(npc, attacker, rv, 0);
00264                     return attacker; /* yes, we face our attacker! */
00265                 }
00266             }
00267         }
00268 
00269         /* we have no legal enemy or attacker, so we try to target a new one */
00270         if (!QUERY_FLAG(npc, FLAG_UNAGGRESSIVE)
00271         && !QUERY_FLAG(npc, FLAG_FRIENDLY)
00272         && !QUERY_FLAG(npc, FLAG_NEUTRAL)) {
00273             npc->enemy = get_nearest_player(npc);
00274             if (npc->enemy)
00275                 tmp = check_enemy(npc, rv);
00276         }
00277 
00278     }
00279 
00280     return tmp;
00281 }
00282 
00298 static int check_wakeup(object *op, object *enemy, rv_vector *rv) {
00299     int radius = MAX(op->stats.Wis, MIN_MON_RADIUS);
00300 
00301     /* Trim work - if no enemy, no need to do anything below */
00302     if (!enemy)
00303         return 0;
00304 
00305     /* blinded monsters can only find nearby objects to attack */
00306     if (QUERY_FLAG(op, FLAG_BLIND))
00307         radius = MIN_MON_RADIUS;
00308 
00309     /* This covers the situation where the monster is in the dark
00310      * and has an enemy. If the enemy has no carried light (or isnt
00311      * glowing!) then the monster has trouble finding the enemy.
00312      * Remember we already checked to see if the monster can see in
00313      * the dark. */
00314     else if (op->map
00315     && op->map->darkness > 0
00316     && enemy
00317     && !enemy->invisible
00318     && !stand_in_light(enemy)
00319     && (!QUERY_FLAG(op, FLAG_SEE_IN_DARK) || !QUERY_FLAG(op, FLAG_SEE_INVISIBLE))) {
00320         int dark = radius/(op->map->darkness);
00321 
00322         radius = (dark > MIN_MON_RADIUS) ? (dark+1) : MIN_MON_RADIUS;
00323     } else if (!QUERY_FLAG(op, FLAG_SLEEP))
00324         return 1;
00325 
00326     /* enemy should already be on this map, so don't really need to check
00327      * for that.
00328      */
00329     if (rv->distance < (QUERY_FLAG(enemy, FLAG_STEALTH) ? (radius/2)+1 : radius)) {
00330         CLEAR_FLAG(op, FLAG_SLEEP);
00331         return 1;
00332     }
00333     return 0;
00334 }
00335 
00344 static int move_randomly(object *op) {
00345     int i;
00346 
00347     /* Give up to 15 chances for a monster to move randomly */
00348     for (i = 0; i < 15; i++) {
00349         if (move_object(op, RANDOM()%8+1))
00350             return 1;
00351     }
00352     return 0;
00353 }
00354 
00355 #define MAX_EXPLORE 5000
00356 
00371 int compute_path(object *source, object *target, int default_dir) {
00372     char *path;
00373     int explore_x[MAX_EXPLORE], explore_y[MAX_EXPLORE];
00374     int current = 0, dir, max = 1, size, x, y, check_dir;
00375 
00376     if (target->map != source->map)
00377         return default_dir;
00378 
00379     /*    printf("compute_path (%d, %d) => (%d, %d)\n", source->x, source->y, target->x, target->y);*/
00380 
00381     size = source->map->width*source->map->height;
00382     path = calloc(size, sizeof(char));
00383     if (path == NULL) {
00384         fatal(OUT_OF_MEMORY);
00385     }
00386     explore_x[0] = target->x;
00387     explore_y[0] = target->y;
00388 
00389     while (current < max) {
00390         for (check_dir = 0; check_dir < 8; check_dir++) {
00391             dir = absdir(default_dir+check_dir);
00392             x = explore_x[current]+freearr_x[dir];
00393             y = explore_y[current]+freearr_y[dir];
00394 
00395             if (x == source->x && y == source->y) {
00396                 /*          LOG(llevDebug, "compute_path => %d\n", absdir(dir+4));*/
00397                 free(path);
00398                 return absdir(dir+4);
00399             }
00400 
00401             if (OUT_OF_REAL_MAP(source->map, x, y))
00402                 continue;
00403             if (ob_blocked(source, source->map, x, y))
00404                 continue;
00405 
00406             assert(source->map->height*x+y >= 0);
00407             assert(source->map->height*x+y < size);
00408 
00409             if (path[source->map->height*x+y] == 0) {
00410                 assert(max < MAX_EXPLORE);
00411                 explore_x[max] = x;
00412                 explore_y[max] = y;
00413 
00414                 path[source->map->height*x+y] = absdir(dir+4);
00415                 /*                printf("explore[%d] => (%d, %d) %d\n", max, x, y, path[source->map->height*x+y]);*/
00416                 max++;
00417                 if (max == MAX_EXPLORE) {
00418                     free(path);
00419                     return default_dir;
00420                 }
00421             }
00422         }
00423         current++;
00424     }
00425 
00426     free(path);
00427     return default_dir;
00428 }
00429 
00436 static void monster_do_living(object *op) {
00437     assert(QUERY_FLAG(op, FLAG_MONSTER));
00438 
00439     /*  generate hp, if applicable */
00440     if (op->stats.Con > 0 && op->stats.hp < op->stats.maxhp) {
00441         /* last heal is in funny units.  Dividing by speed puts
00442          * the regeneration rate on a basis of time instead of
00443          * #moves the monster makes.  The scaling by 8 is
00444          * to capture 8th's of a hp fraction regens
00445          *
00446          * Cast to sint32 before comparing to maxhp since otherwise an (sint16)
00447          * overflow might produce monsters with negative hp.
00448          */
00449 
00450         op->last_heal += (int)((float)(8*op->stats.Con)/FABS(op->speed));
00451         op->stats.hp = MIN((sint32)op->stats.hp+op->last_heal/32, op->stats.maxhp); /* causes Con/4 hp/tick */
00452         op->last_heal %= 32;
00453 
00454         /* So if the monster has gained enough HP that they are no longer afraid */
00455         if (QUERY_FLAG(op, FLAG_RUN_AWAY)
00456         && op->stats.hp >= (signed short)(((float)op->run_away/(float)100)*(float)op->stats.maxhp))
00457             CLEAR_FLAG(op, FLAG_RUN_AWAY);
00458 
00459         if (op->stats.hp > op->stats.maxhp)
00460             op->stats.hp = op->stats.maxhp;
00461     }
00462 
00463     /* generate sp, if applicable */
00464     if (op->stats.Pow > 0 && op->stats.sp < op->stats.maxsp) {
00465         /*  last_sp is in funny units.  Dividing by speed puts
00466          * the regeneration rate on a basis of time instead of
00467          * #moves the monster makes.  The scaling by 8 is
00468          * to capture 8th's of a sp fraction regens
00469          *
00470          * Cast to sint32 before comparing to maxhp since otherwise an (sint16)
00471          * overflow might produce monsters with negative sp.
00472          */
00473 
00474         op->last_sp += (int)((float)(8*op->stats.Pow)/FABS(op->speed));
00475         op->stats.sp = MIN(op->stats.sp+op->last_sp/128, op->stats.maxsp);  /* causes Pow/16 sp/tick */
00476         op->last_sp %= 128;
00477     }
00478 
00479     /* this should probably get modified by many more values.
00480     * (eg, creatures resistance to fear, level, etc. )
00481     */
00482     if (QUERY_FLAG(op, FLAG_SCARED) && !(RANDOM()%20)) {
00483         CLEAR_FLAG(op, FLAG_SCARED); /* Time to regain some "guts"... */
00484     }
00485 }
00486 
00495 static int monster_move_no_enemy(object *op) {
00496     assert(QUERY_FLAG(op, FLAG_MONSTER));
00497 
00498     if (QUERY_FLAG(op, FLAG_ONLY_ATTACK))  {
00499         remove_ob(op);
00500         free_object(op);
00501         return 1;
00502     }
00503 
00504     /* Probably really a bug for a creature to have both
00505        * stand still and a movement type set.
00506            */
00507     if (!QUERY_FLAG(op, FLAG_STAND_STILL))  {
00508         if (op->attack_movement&HI4) {
00509             switch (op->attack_movement&HI4) {
00510             case(PETMOVE):
00511                 pet_move(op);
00512                 break;
00513 
00514             case(CIRCLE1):
00515                 circ1_move(op);
00516                 break;
00517 
00518             case(CIRCLE2):
00519                 circ2_move(op);
00520                 break;
00521 
00522             case(PACEV):
00523                 pace_movev(op);
00524                 break;
00525 
00526             case(PACEH):
00527                 pace_moveh(op);
00528                 break;
00529 
00530             case(PACEV2):
00531                 pace2_movev(op);
00532                 break;
00533 
00534             case(PACEH2):
00535                 pace2_moveh(op);
00536                 break;
00537 
00538             case(RANDO):
00539                 rand_move(op);
00540                 break;
00541 
00542             case(RANDO2):
00543                 move_randomly(op);
00544                 break;
00545             }
00546             return 0;
00547         } else if (QUERY_FLAG(op, FLAG_RANDOM_MOVE))
00548             move_randomly(op);
00549 
00550     } /* stand still */
00551 
00552     return 0;
00553 }
00554 
00566 int move_monster(object *op) {
00567     int dir, diff;
00568     object *owner, *enemy, *part, *oph = op;
00569     rv_vector rv;
00570 
00571     /* Monsters not on maps don't do anything.  These monsters are things
00572      * Like royal guards in city dwellers inventories.
00573      */
00574     if (!op->map)
00575         return 0;
00576 
00577     /* for target facing, we copy this value here for fast access */
00578     if (oph->head)          /* force update the head - one arch one pic */
00579         oph = oph->head;
00580 
00581     if (QUERY_FLAG(op, FLAG_NO_ATTACK))  /* we never ever attack */
00582         enemy = op->enemy = NULL;
00583     else if ((enemy = find_enemy(op, &rv))) {
00584         /* we have an enemy, just tell him we want him dead */
00585         enemy->attacked_by = op;       /* our ptr */
00586         enemy->attacked_by_count = op->count; /* our tag */
00587     }
00588 
00589     if (QUERY_FLAG(op, FLAG_SLEEP)
00590     || QUERY_FLAG(op, FLAG_BLIND)
00591     || ((op->map->darkness > 0) && !QUERY_FLAG(op, FLAG_SEE_IN_DARK) && !QUERY_FLAG(op, FLAG_SEE_INVISIBLE))) {
00592         if (!check_wakeup(op, enemy, &rv))
00593             return 0;
00594     }
00595 
00596     /* check if monster pops out of hidden spot */
00597     if (op->hide)
00598         do_hidden_move(op);
00599 
00600     if (op->pick_up)
00601         monster_check_pickup(op);
00602 
00603     if (op->will_apply)
00604         monster_apply_below(op); /* Check for items to apply below */
00605 
00606     monster_do_living(op);
00607 
00608     /* If we don't have an enemy, do special movement or the like */
00609     if (!enemy) {
00610         return monster_move_no_enemy(op);
00611     } /* no enemy */
00612 
00613     /* We have an enemy.  Block immediately below is for pets */
00614     if ((op->attack_movement&HI4) == PETMOVE && (owner = get_owner(op)) != NULL && !on_same_map(op, owner)) {
00615         follow_owner(op, owner);
00616         /* If the pet was unable to follow the owner, free it */
00617         if (QUERY_FLAG(op, FLAG_REMOVED) && FABS(op->speed) > MIN_ACTIVE_SPEED) {
00618             remove_friendly_object(op);
00619             free_object(op);
00620             return 1;
00621         }
00622         return 0;
00623     }
00624 
00625     /* doppleganger code to change monster facing to that of the nearest
00626      * player.  Hmm.  The code is here, but no monster in the current
00627      * arch set uses it.
00628      */
00629     if ((op->race != NULL)&& strcmp(op->race, "doppleganger") == 0) {
00630         op->face = enemy->face;
00631         if (op->name)
00632             free_string(op->name);
00633         add_refcount(op->name = enemy->name);
00634     }
00635 
00636     /* Calculate range information for closest body part - this
00637      * is used for the 'skill' code, which isn't that smart when
00638      * it comes to figuring it out - otherwise, giants throw boulders
00639      * into themselves.
00640      */
00641     get_rangevector(op, enemy, &rv, 0);
00642     if (op->direction != rv.direction) {
00643         op->direction = rv.direction;
00644         op->facing = op->direction;
00645         if (op->animation_id)
00646             animate_object(op, op->direction);
00647     }
00648 
00649     /* Move the check for scared up here - if the monster was scared,
00650      * we were not doing any of the logic below, so might as well save
00651      * a few cpu cycles.
00652      */
00653     if (!QUERY_FLAG(op, FLAG_SCARED)) {
00654         rv_vector rv1;
00655 
00656         /* now we test every part of an object .... this is a real ugly piece of code */
00657         for (part = op; part != NULL; part = part->more) {
00658             get_rangevector(part, enemy, &rv1, 0x1);
00659             dir = rv1.direction;
00660 
00661             /* hm, not sure about this part - in original was a scared flag here too
00662              * but that we test above... so can be old code here
00663              */
00664             if (QUERY_FLAG(op, FLAG_RUN_AWAY))
00665                 dir = absdir(dir+4);
00666             if (QUERY_FLAG(op, FLAG_CONFUSED))
00667                 dir = absdir(dir+RANDOM()%3+RANDOM()%3-2);
00668 
00669             if (QUERY_FLAG(op, FLAG_CAST_SPELL) && !(RANDOM()%3)) {
00670                 if (monster_cast_spell(op, part, enemy, dir, &rv1))
00671                     return 0;
00672             }
00673 
00674             if (QUERY_FLAG(op, FLAG_READY_SCROLL) && !(RANDOM()%3)) {
00675                 if (monster_use_scroll(op, part, enemy, dir, &rv1))
00676                     return 0;
00677             }
00678 
00679             if (QUERY_FLAG(op, FLAG_READY_RANGE) && !(RANDOM()%3)) {
00680                 if (monster_use_range(op, part, enemy, dir))
00681                     return 0;
00682             }
00683             if (QUERY_FLAG(op, FLAG_READY_SKILL) && !(RANDOM()%3)) {
00684                 if (monster_use_skill(op, rv.part, enemy, rv.direction))
00685                     return 0;
00686             }
00687             if (QUERY_FLAG(op, FLAG_READY_BOW) && !(RANDOM()%2)) {
00688                 if (monster_use_bow(op, part, enemy, dir))
00689                     return 0;
00690             }
00691         } /* for processing of all parts */
00692     } /* If not scared */
00693 
00694 
00695     /* code below is for when we didn't use a range attack or a skill, so
00696      * either move or hit with hth attack. */
00697 
00698     part = rv.part;
00699     dir = rv.direction;
00700 
00701     if (QUERY_FLAG(op, FLAG_SCARED) || QUERY_FLAG(op, FLAG_RUN_AWAY))
00702         dir = absdir(dir+4);
00703     else if (!can_hit(part, enemy, &rv))
00704         dir = compute_path(op, enemy, rv.direction);
00705 
00706     if (QUERY_FLAG(op, FLAG_CONFUSED))
00707         dir = absdir(dir+RANDOM()%3+RANDOM()%3-2);
00708 
00709     if ((op->attack_movement&LO4) && !QUERY_FLAG(op, FLAG_SCARED)) {
00710         switch (op->attack_movement&LO4) {
00711         case DISTATT:
00712             dir = dist_att(dir, op, enemy, part, &rv);
00713             break;
00714 
00715         case RUNATT:
00716             dir = run_att(dir, op, enemy, part, &rv);
00717             break;
00718 
00719         case HITRUN:
00720             dir = hitrun_att(dir, op, enemy);
00721             break;
00722 
00723         case WAITATT:
00724             dir = wait_att(dir, op, enemy, part, &rv);
00725             break;
00726 
00727         case RUSH: /* default - monster normally moves towards player */
00728         case ALLRUN:
00729             break;
00730 
00731         case DISTHIT:
00732             dir = disthit_att(dir, op, enemy, part, &rv);
00733             break;
00734 
00735         case WAIT2:
00736             dir = wait_att2(dir, op, enemy, part, &rv);
00737             break;
00738 
00739         default:
00740             LOG(llevDebug, "Illegal low mon-move: %d\n", op->attack_movement&LO4);
00741         }
00742     }
00743 
00744     if (!dir)
00745         return 0;
00746 
00747     if (!QUERY_FLAG(op, FLAG_STAND_STILL)) {
00748         if (move_object(op, dir)) /* Can the monster move directly toward player? */
00749             return 0;
00750 
00751         if (QUERY_FLAG(op, FLAG_SCARED)
00752         || !can_hit(part, enemy, &rv)
00753         || QUERY_FLAG(op, FLAG_RUN_AWAY)) {
00754             /* Try move around corners if !close */
00755             int maxdiff = (QUERY_FLAG(op, FLAG_ONLY_ATTACK) || RANDOM()&1) ? 1 : 2;
00756             for (diff = 1; diff <= maxdiff; diff++) {
00757                 /* try different detours */
00758                 int m = 1-(RANDOM()&2);          /* Try left or right first? */
00759                 if (move_object(op, absdir(dir+diff*m))
00760                 || move_object(op, absdir(dir-diff*m)))
00761                     return 0;
00762             }
00763         }
00764     } /* if monster is not standing still */
00765 
00766     /*
00767      * Eneq(@csd.uu.se): Patch to make RUN_AWAY or SCARED monsters move a random
00768      * direction if they can't move away.
00769      */
00770     if (!QUERY_FLAG(op, FLAG_ONLY_ATTACK)
00771     && (QUERY_FLAG(op, FLAG_RUN_AWAY) || QUERY_FLAG(op, FLAG_SCARED)))
00772         if (move_randomly(op))
00773             return 0;
00774 
00775     /*
00776      * Try giving the monster a new enemy - the player that is closest
00777      * to it.  In this way, it won't just keep trying to get to a target
00778      * that is inaccessible.
00779      * This could be more clever - it should go through a list of several
00780      * enemies, as it is now, you could perhaps get situations where there
00781      * are two players flanking the monster at close distance, but which
00782      * the monster can't get to, and a third one at a far distance that
00783      * the monster could get to - as it is, the monster won't look at that
00784      * third one.
00785      */
00786     if (!QUERY_FLAG(op, FLAG_FRIENDLY) && enemy == op->enemy) {
00787         object *nearest_player = get_nearest_player(op);
00788 
00789         if (nearest_player && nearest_player != enemy && !can_hit(part, enemy, &rv)) {
00790             op->enemy = NULL;
00791             enemy = nearest_player;
00792         }
00793     }
00794 
00795     if (!QUERY_FLAG(op, FLAG_SCARED) && can_hit(part, enemy, &rv)) {
00796         /* The adjustement to wc that was here before looked totally bogus -
00797          * since wc can in fact get negative, that would mean by adding
00798          * the current wc, the creature gets better?  Instead, just
00799          * add a fixed amount - nasty creatures that are runny away should
00800          * still be pretty nasty.
00801          */
00802         if (QUERY_FLAG(op, FLAG_RUN_AWAY)) {
00803             part->stats.wc += 10;
00804             (void)skill_attack(enemy, part, 0, NULL, NULL);
00805             part->stats.wc -= 10;
00806         } else
00807             (void)skill_attack(enemy, part, 0, NULL, NULL);
00808     } /* if monster is in attack range */
00809 
00810     if (QUERY_FLAG(part, FLAG_FREED))   /* Might be freed by ghost-attack or hit-back */
00811         return 1;
00812 
00813     if (QUERY_FLAG(op, FLAG_ONLY_ATTACK)) {
00814         remove_ob(op);
00815         free_object(op);
00816         return 1;
00817     }
00818     return 0;
00819 }
00820 
00835 static int can_hit(object *ob1, object *ob2, rv_vector *rv) {
00836     object *more;
00837     rv_vector rv1;
00838 
00839     if (QUERY_FLAG(ob1, FLAG_CONFUSED)&&!(RANDOM()%3))
00840         return 0;
00841 
00842     if (abs(rv->distance_x) < 2 && abs(rv->distance_y) < 2)
00843         return 1;
00844 
00845     /* check all the parts of ob2 - just because we can't get to
00846      * its head doesn't mean we don't want to pound its feet
00847      */
00848     for (more = ob2->more; more != NULL; more = more->more) {
00849         get_rangevector(ob1, more, &rv1, 0);
00850         if (abs(rv1.distance_x) < 2 && abs(rv1.distance_y) < 2)
00851             return 1;
00852     }
00853     return 0;
00854 }
00855 
00880 static int monster_should_cast_spell(object *monster, object *spell_ob) {
00881     if (spell_ob->subtype == SP_BOLT
00882     || spell_ob->subtype == SP_BULLET
00883     || spell_ob->subtype == SP_EXPLOSION
00884     || spell_ob->subtype == SP_CONE
00885     || spell_ob->subtype == SP_BOMB
00886     || spell_ob->subtype == SP_SMITE
00887     || spell_ob->subtype == SP_MAGIC_MISSILE
00888     || spell_ob->subtype == SP_SUMMON_GOLEM
00889     || spell_ob->subtype == SP_MAGIC_WALL
00890     || spell_ob->subtype == SP_SUMMON_MONSTER
00891     || spell_ob->subtype == SP_MOVING_BALL
00892     || spell_ob->subtype == SP_SWARM
00893     || spell_ob->subtype == SP_INVISIBLE)
00894         return 1;
00895 
00896     return 0;
00897 }
00898 
00900 #define MAX_KNOWN_SPELLS 20
00901 
00917 static object *monster_choose_random_spell(object *monster) {
00918     object *altern[MAX_KNOWN_SPELLS];
00919     object *tmp;
00920     int i = 0;
00921 
00922     for (tmp = monster->inv; tmp != NULL; tmp = tmp->below)
00923         if (tmp->type == SPELLBOOK || tmp->type == SPELL) {
00924             /* Check and see if it's actually a useful spell.
00925              * If its a spellbook, the spell is actually the inventory item.
00926              * if it is a spell, then it is just the object itself.
00927              */
00928             if (monster_should_cast_spell(monster, (tmp->type == SPELLBOOK) ? tmp->inv : tmp)) {
00929                 altern[i++] = tmp;
00930                 if (i == MAX_KNOWN_SPELLS)
00931                     break;
00932             }
00933         }
00934     if (!i)
00935         return NULL;
00936     return altern[RANDOM()%i];
00937 }
00938 
00957 static int monster_cast_spell(object *head, object *part, object *pl, int dir, rv_vector *rv) {
00958     object *spell_item;
00959     object *owner;
00960     rv_vector rv1;
00961 
00962     /* If you want monsters to cast spells over friends, this spell should
00963      * be removed.  It probably should be in most cases, since monsters still
00964      * don't care about residual effects (ie, casting a cone which may have a
00965      * clear path to the player, the side aspects of the code will still hit
00966      * other monsters)
00967      */
00968     if (!(dir = path_to_player(part, pl, 0)))
00969         return 0;
00970 
00971     if (QUERY_FLAG(head, FLAG_FRIENDLY) && (owner = get_owner(head)) != NULL) {
00972         get_rangevector(head, owner, &rv1, 0x1);
00973         if (dirdiff(dir, rv1.direction) < 2) {
00974             return 0; /* Might hit owner with spell */
00975         }
00976     }
00977 
00978     if (QUERY_FLAG(head, FLAG_CONFUSED))
00979         dir = absdir(dir+RANDOM()%3+RANDOM()%3-2);
00980 
00981     /* If the monster hasn't already chosen a spell, choose one
00982      * I'm not sure if it really make sense to pre-select spells (events
00983      * could be different by the time the monster goes again).
00984      */
00985     if (head->spellitem == NULL) {
00986         if ((spell_item = monster_choose_random_spell(head)) == NULL) {
00987             LOG(llevMonster, "Turned off spells in %s\n", head->name);
00988             CLEAR_FLAG(head, FLAG_CAST_SPELL); /* Will be turned on when picking up book */
00989             return 0;
00990         }
00991         if (spell_item->type == SPELLBOOK) {
00992             if (!spell_item->inv) {
00993                 LOG(llevError, "spellbook %s does not contain a spell?\n", spell_item->name);
00994                 return 0;
00995             }
00996             spell_item = spell_item->inv;
00997         }
00998     } else
00999         spell_item = head->spellitem;
01000 
01001     if (!spell_item)
01002         return 0;
01003 
01004     /* Best guess this is a defensive/healing spell */
01005     if (spell_item->range <= 1 || spell_item->stats.dam < 0)
01006         dir = 0;
01007 
01008     /* Monster doesn't have enough spell-points */
01009     if (head->stats.sp < SP_level_spellpoint_cost(head, spell_item, SPELL_MANA))
01010         return 0;
01011 
01012     if (head->stats.grace < SP_level_spellpoint_cost(head, spell_item, SPELL_GRACE))
01013         return 0;
01014 
01015     head->stats.sp -= SP_level_spellpoint_cost(head, spell_item, SPELL_MANA);
01016     head->stats.grace -= SP_level_spellpoint_cost(head, spell_item, SPELL_GRACE);
01017 
01018     /* set this to null, so next time monster will choose something different */
01019     head->spellitem = NULL;
01020 
01021     return cast_spell(part, part, dir, spell_item, NULL);
01022 }
01023 
01040 static int monster_use_scroll(object *head, object *part, object *pl, int dir, rv_vector *rv) {
01041     object *scroll;
01042     object *owner;
01043     rv_vector rv1;
01044 
01045     /* If you want monsters to cast spells over friends, this spell should
01046      * be removed.  It probably should be in most cases, since monsters still
01047      * don't care about residual effects (ie, casting a cone which may have a
01048      * clear path to the player, the side aspects of the code will still hit
01049      * other monsters)
01050      */
01051     if (!(dir = path_to_player(part, pl, 0)))
01052         return 0;
01053 
01054     if (QUERY_FLAG(head, FLAG_FRIENDLY) && (owner = get_owner(head)) != NULL) {
01055         get_rangevector(head, owner, &rv1, 0x1);
01056         if (dirdiff(dir, rv1.direction) < 2) {
01057             return 0; /* Might hit owner with spell */
01058         }
01059     }
01060 
01061     if (QUERY_FLAG(head, FLAG_CONFUSED))
01062         dir = absdir(dir+RANDOM()%3+RANDOM()%3-2);
01063 
01064     for (scroll = head->inv; scroll; scroll = scroll->below)
01065         if (scroll->type == SCROLL && monster_should_cast_spell(head, scroll->inv))
01066             break;
01067 
01068     /* Used up all his scrolls, so nothing do to */
01069     if (!scroll) {
01070         CLEAR_FLAG(head, FLAG_READY_SCROLL);
01071         return 0;
01072     }
01073 
01074     /* Spell should be cast on caster (ie, heal, strength) */
01075     if (scroll->inv->range == 0)
01076         dir = 0;
01077 
01078     /* Face the direction that we want to cast. */
01079     head->direction = dir;
01080     head->facing = head->direction;
01081     if (head->animation_id)
01082         animate_object(head, head->direction);
01083 
01084     ob_apply(scroll, part, 0);
01085     return 1;
01086 }
01087 
01115 static int monster_use_skill(object *head, object *part, object *pl, int dir) {
01116     object *skill, *owner;
01117 
01118     if (!(dir = path_to_player(part, pl, 0)))
01119         return 0;
01120 
01121     if (QUERY_FLAG(head, FLAG_FRIENDLY) && (owner = get_owner(head)) != NULL) {
01122         int dir2 = find_dir_2(head->x-owner->x, head->y-owner->y);
01123         if (dirdiff(dir, dir2) < 1)
01124             return 0; /* Might hit owner with skill -thrown rocks for example ?*/
01125     }
01126     if (QUERY_FLAG(head, FLAG_CONFUSED))
01127         dir = absdir(dir+RANDOM()%3+RANDOM()%3-2);
01128 
01129     /* skill selection - monster will use the next unused skill.
01130      * well...the following scenario will allow the monster to
01131      * toggle between 2 skills. One day it would be nice to make
01132      * more skills available to monsters.
01133      */
01134 
01135     for (skill = head->inv; skill != NULL; skill = skill->below)
01136         if (skill->type == SKILL && skill != head->chosen_skill) {
01137             head->chosen_skill = skill;
01138             break;
01139         }
01140 
01141     if (!skill && !head->chosen_skill) {
01142         LOG(llevDebug, "Error: Monster %s (%d) has FLAG_READY_SKILL without skill.\n", head->name, head->count);
01143         CLEAR_FLAG(head, FLAG_READY_SKILL);
01144         return 0;
01145     }
01146     /* use skill */
01147     return do_skill(head, part, head->chosen_skill, dir, NULL);
01148 }
01149 
01164 static int monster_use_range(object *head, object *part, object *pl, int dir) {
01165     object *wand, *owner;
01166     int at_least_one = 0;
01167 
01168     if (!(dir = path_to_player(part, pl, 0)))
01169         return 0;
01170 
01171     if (QUERY_FLAG(head, FLAG_FRIENDLY) && (owner = get_owner(head)) != NULL) {
01172         int dir2 = find_dir_2(head->x-owner->x, head->y-owner->y);
01173         if (dirdiff(dir, dir2) < 2)
01174             return 0; /* Might hit owner with spell */
01175     }
01176     if (QUERY_FLAG(head, FLAG_CONFUSED))
01177         dir = absdir(dir+RANDOM()%3+RANDOM()%3-2);
01178 
01179     for (wand = head->inv; wand != NULL; wand = wand->below) {
01180         if (wand->type == WAND) {
01181             /* Found a wand, let's see if it has charges left */
01182             at_least_one = 1;
01183             if (wand->stats.food <= 0)
01184                 continue;
01185 
01186             cast_spell(head, wand, dir, wand->inv, NULL);
01187             drain_wand_charge(wand);
01188 
01189             /* Success */
01190             return 1;
01191         } else if (wand->type == ROD || wand->type == HORN) {
01192             /* Found rod/horn, let's use it if possible */
01193             at_least_one = 1;
01194             if (wand->stats.hp < MAX(wand->inv->stats.sp, wand->inv->stats.grace))
01195                 continue;
01196 
01197             /* drain charge before casting spell - can be a case where the
01198              * spell destroys the monster, and rod, so if done after, results
01199              * in crash.
01200              */
01201             drain_rod_charge(wand);
01202             cast_spell(head, wand, dir, wand->inv, NULL);
01203 
01204             /* Success */
01205             return 1;
01206         }
01207     }
01208 
01209     if (at_least_one)
01210         return 0;
01211 
01212     LOG(llevError, "Error: Monster %s (%d) HAS_READY_RANG() without wand/horn/rod.\n", head->name, head->count);
01213     CLEAR_FLAG(head, FLAG_READY_RANGE);
01214     return 0;
01215 }
01216 
01233 static int monster_use_bow(object *head, object *part, object *pl, int dir) {
01234     object *owner;
01235     rv_vector rv;
01236     sint16 x, y;
01237     mapstruct *map;
01238 
01239     get_rangevector(part, pl, &rv, 1);
01240     if (rv.distance > 100)
01241         /* Too far */
01242         return 0;
01243     if (rv.distance_x != 0 && rv.distance_y != 0 && abs(rv.distance_x) != abs(rv.distance_y))
01244         /* Player must be on same horizontal, vertical or diagonal line. */
01245         return 0;
01246     dir = absdir(find_dir_2(rv.distance_x, rv.distance_y)+4);
01247 
01248     if (QUERY_FLAG(head, FLAG_FRIENDLY))
01249         owner = get_owner(head);
01250     else
01251         owner = NULL;
01252 
01253     /* The monster can possibly fire, let's see if the path is ok for an arrow. */
01254     x = part->x;
01255     y = part->y;
01256     map = part->map;
01257     while (x != pl->x || y != pl->y || map != pl->map) {
01258         x += freearr_x[dir];
01259         y += freearr_y[dir];
01260         map = get_map_from_coord(map, &x, &y);
01261         if (!map) {
01262             LOG(llevError, "monster_use_bow: no map but still path exists??\n");
01263             return 0;
01264         }
01265         if ((GET_MAP_MOVE_BLOCK(map, x, y)&MOVE_FLY_LOW) == MOVE_FLY_LOW)
01266             return 0;
01267         if (owner && owner->x == x && owner->y == y && owner->map == map)
01268             /* Don't hit owner! */
01269             return 0;
01270     }
01271 
01272     /* Finally, path is clear, can fire. */
01273 
01274     if (QUERY_FLAG(head, FLAG_CONFUSED))
01275         dir = absdir(dir+RANDOM()%3+RANDOM()%3-2);
01276 
01277     /* in server/player.c */
01278     return fire_bow(head, NULL, dir, 0, part->x, part->y);
01279 }
01280 
01293 static int check_good_weapon(object *who, object *item) {
01294     object *other_weap;
01295     int val = 0, i;
01296 
01297     for (other_weap = who->inv; other_weap != NULL; other_weap = other_weap->below)
01298         if (other_weap->type == item->type && QUERY_FLAG(other_weap, FLAG_APPLIED))
01299             break;
01300 
01301     if (other_weap == NULL) /* No other weapons */
01302         return 1;
01303 
01304     /* Rather than go through and apply the new one, and see if it is
01305      * better, just do some simple checks
01306      * Put some multipliers for things that hvae several effects,
01307      * eg, magic affects both damage and wc, so it has more weight
01308      */
01309 
01310     val = item->stats.dam-other_weap->stats.dam;
01311     val += (item->magic-other_weap->magic)*3;
01312     /* Monsters don't really get benefits from things like regen rates
01313      * from items.  But the bonus for their stats are very important.
01314      */
01315     for (i = 0; i < NUM_STATS; i++)
01316         val += (get_attr_value(&item->stats, i)-get_attr_value(&other_weap->stats, i))*2;
01317 
01318     if (val > 0)
01319         return 1;
01320     else
01321         return 0;
01322 }
01323 
01336 static int check_good_armour(object *who, object *item) {
01337     object *other_armour;
01338     int val = 0, i;
01339 
01340     for (other_armour = who->inv; other_armour != NULL; other_armour = other_armour->below)
01341         if (other_armour->type == item->type && QUERY_FLAG(other_armour, FLAG_APPLIED))
01342             break;
01343 
01344     if (other_armour == NULL) /* No other armour, use the new */
01345         return 1;
01346 
01347     /* Like above function , see which is better */
01348     val = item->stats.ac-other_armour->stats.ac;
01349     val = (item->resist[ATNR_PHYSICAL]-other_armour->resist[ATNR_PHYSICAL])/5;
01350     val += (item->magic-other_armour->magic)*3;
01351 
01352     /* for the other protections, do weigh them very much in the equation -
01353      * it is the armor protection which is most important, because there is
01354      * no good way to know what the player may attack the monster with.
01355      * So if the new item has better protection than the old, give that higher
01356      * value.  If the reverse, then decrease the value of this item some.
01357      */
01358     for (i = 1; i < NROFATTACKS; i++) {
01359         if (item->resist[i] > other_armour->resist[i])
01360             val++;
01361         else if (item->resist[i] < other_armour->resist[i])
01362             val--;
01363     }
01364 
01365     /* Very few armours have stats, so not much need to worry about those. */
01366 
01367     if (val > 0)
01368         return 1;
01369     else
01370         return 0;
01371 
01372 }
01373 
01393 static void monster_check_pickup(object *monster) {
01394     object *tmp, *next;
01395     int next_tag;
01396 
01397     for (tmp = monster->below; tmp != NULL; tmp = next) {
01398         next = tmp->below;
01399         next_tag = next ? next->count : 0;
01400         if (monster_can_pick(monster, tmp)) {
01401             remove_ob(tmp);
01402             tmp = insert_ob_in_ob(tmp, monster);
01403             (void)monster_check_apply(monster, tmp);
01404         }
01405         /* We could try to re-establish the cycling, of the space, but probably
01406          * not a big deal to just bail out.
01407          */
01408         if (next && was_destroyed(next, next_tag))
01409             return;
01410     }
01411 }
01412 
01413 /*
01414  * monster_can_pick(): If the monster is interested in picking up
01415  * the item, then return 0.  Otherwise 0.
01416  * Instead of pick_up, flags for "greed", etc, should be used.
01417  * I've already utilized flags for bows, wands, rings, etc, etc. -Frank.
01418  */
01419 
01420 static int monster_can_pick(object *monster, object *item) {
01421     int flag = 0;
01422     int i;
01423 
01424     if (!can_pick(monster, item))
01425         return 0;
01426 
01427     if (QUERY_FLAG(item, FLAG_UNPAID))
01428         return 0;
01429 
01430     if (monster->pick_up&64)           /* All */
01431         flag = 1;
01432 
01433     else {
01434         if (IS_WEAPON(item))
01435             flag = (monster->pick_up&8) || QUERY_FLAG(monster, FLAG_USE_WEAPON);
01436         else if (IS_ARMOR(item))
01437             flag = (monster->pick_up&16) || QUERY_FLAG(monster, FLAG_USE_ARMOUR);
01438         else if (IS_SHIELD(item))
01439             flag = (monster->pick_up&16) || QUERY_FLAG(monster, FLAG_USE_SHIELD);
01440         else switch (item->type) {
01441             case MONEY:
01442             case GEM:
01443                 flag = monster->pick_up&2;
01444                 break;
01445 
01446             case FOOD:
01447                 flag = monster->pick_up&4;
01448                 break;
01449 
01450             case SKILL:
01451                 flag = QUERY_FLAG(monster, FLAG_CAN_USE_SKILL);
01452                 break;
01453 
01454             case RING:
01455                 flag = QUERY_FLAG(monster, FLAG_USE_RING);
01456                 break;
01457 
01458             case WAND:
01459             case HORN:
01460             case ROD:
01461                 flag = QUERY_FLAG(monster, FLAG_USE_RANGE);
01462                 break;
01463 
01464             case SPELLBOOK:
01465                 flag = (monster->arch != NULL && QUERY_FLAG((&monster->arch->clone), FLAG_CAST_SPELL));
01466                 break;
01467 
01468             case SCROLL:
01469                 flag = QUERY_FLAG(monster, FLAG_USE_SCROLL);
01470                 break;
01471 
01472             case BOW:
01473             case ARROW:
01474                 flag = QUERY_FLAG(monster, FLAG_USE_BOW);
01475                 break;
01476             }
01477         /* Simplistic check - if the monster has a location to equip it, he will
01478          * pick it up.  Note that this doesn't handle cases where an item may
01479          * use several locations.
01480          */
01481         for (i = 0; i < NUM_BODY_LOCATIONS; i++) {
01482             if (monster->body_info[i] && item->body_info[i]) {
01483                 flag = 1;
01484                 break;
01485             }
01486         }
01487     }
01488 
01489     if (((!(monster->pick_up&32)) && flag) || ((monster->pick_up&32) && (!flag)))
01490         return 1;
01491     return 0;
01492 }
01493 
01494 /*
01495  * monster_apply_below():
01496  * Vick's (vick@bern.docs.uu.se) @921107 -> If a monster who's
01497  * eager to apply things, encounters something apply-able,
01498  * then make him apply it
01499  */
01500 static void monster_apply_below(object *monster) {
01501     object *tmp, *next;
01502 
01503     for (tmp = monster->below; tmp != NULL; tmp = next) {
01504         next = tmp->below;
01505         switch (tmp->type) {
01506         case CF_HANDLE:
01507         case TRIGGER:
01508             if (monster->will_apply&WILL_APPLY_HANDLE)
01509                 manual_apply(monster, tmp, 0);
01510             break;
01511 
01512         case TREASURE:
01513             if (monster->will_apply&WILL_APPLY_TREASURE)
01514                 manual_apply(monster, tmp, 0);
01515             break;
01516         }
01517         if (QUERY_FLAG(tmp, FLAG_IS_FLOOR))
01518             break;
01519     }
01520 }
01521 
01522 /*
01523  * monster_check_apply() is meant to be called after an item is
01524  * inserted in a monster.
01525  * If an item becomes outdated (monster found a better item),
01526  * a pointer to that object is returned, so it can be dropped.
01527  * (so that other monsters can pick it up and use it)
01528  * Note that as things are now, monsters never drop something -
01529  * they can pick up all that they can use.
01530  */
01531 
01532 /* Sept 96, fixed this so skills will be readied -b.t.*/
01533 
01534 void monster_check_apply(object *mon, object *item) {
01535     int flag = 0;
01536 
01537     if (item->type == SPELLBOOK
01538     && mon->arch != NULL
01539     && (QUERY_FLAG((&mon->arch->clone), FLAG_CAST_SPELL))) {
01540         SET_FLAG(mon, FLAG_CAST_SPELL);
01541         return;
01542     }
01543 
01544     /* If for some reason, this item is already applied, no more work to do */
01545     if (QUERY_FLAG(item, FLAG_APPLIED))
01546         return;
01547 
01548     /* Might be better not to do this - if the monster can fire a bow,
01549      * it is possible in his wanderings, he will find one to use.  In
01550      * which case, it would be nice to have ammo for it.
01551      */
01552     if (QUERY_FLAG(mon, FLAG_USE_BOW) && item->type == ARROW) {
01553         /* Check for the right kind of bow */
01554         object *bow;
01555 
01556         for (bow = mon->inv; bow != NULL; bow = bow->below)
01557             if (bow->type == BOW && bow->race == item->race) {
01558                 SET_FLAG(mon, FLAG_READY_BOW);
01559                 LOG(llevMonster, "Found correct bow for arrows.\n");
01560                 return;     /* nothing more to do for arrows */
01561             }
01562     }
01563 
01564     if (item->type == TREASURE && mon->will_apply&WILL_APPLY_TREASURE)
01565         flag = 1;
01566     /* Eating food gets hp back */
01567     else if (item->type == FOOD && mon->will_apply&WILL_APPLY_FOOD)
01568         flag = 1;
01569     else if (item->type == SCROLL && QUERY_FLAG(mon, FLAG_USE_SCROLL)) {
01570         if (!item->inv)
01571             LOG(llevDebug, "Monster %d having scroll %d with empty inventory!\n", mon->count, item->count);
01572         else if (monster_should_cast_spell(mon, item->inv))
01573             SET_FLAG(mon, FLAG_READY_SCROLL);
01574         /* Don't use it right now */
01575         return;
01576     } else if (item->type == WEAPON)
01577         flag = check_good_weapon(mon, item);
01578     else if (IS_ARMOR(item) || IS_SHIELD(item))
01579         flag = check_good_armour(mon, item);
01580     /* Should do something more, like make sure this is a better item */
01581     else if (item->type == RING)
01582         flag = 1;
01583     else if (item->type == WAND || item->type == ROD || item->type == HORN) {
01584         /* We never really 'ready' the wand/rod/horn, because that would mean the
01585         * weapon would get undone.
01586         */
01587         if (!(can_apply_object(mon, item)&CAN_APPLY_NOT_MASK)) {
01588             SET_FLAG(mon, FLAG_READY_RANGE);
01589             SET_FLAG(item, FLAG_APPLIED);
01590         }
01591         return;
01592     } else if (item->type == BOW) {
01593         /* We never really 'ready' the bow, because that would mean the
01594         * weapon would get undone.
01595         */
01596         if (!(can_apply_object(mon, item)&CAN_APPLY_NOT_MASK))
01597             SET_FLAG(mon, FLAG_READY_BOW);
01598         return;
01599     } else if (item->type == SKILL) {
01600         /*
01601          * skills are specials: monsters must have the 'FLAG_READY_SKILL' flag set,
01602          * else they can't use the skill...
01603          * Skills also don't need to get applied, so return now.
01604          */
01605         SET_FLAG(mon, FLAG_READY_SKILL);
01606         return;
01607     }
01608 
01609     /* if we don't match one of the above types, return now.
01610      * can_apply_object will say that we can apply things like flesh,
01611      * bolts, and whatever else, because it only checks against the
01612      * body_info locations.
01613      */
01614     if (!flag)
01615         return;
01616 
01617     /* Check to see if the monster can use this item.  If not, no need
01618      * to do further processing.  Note that can_apply_object already checks
01619      * for the CAN_USE flags.
01620      */
01621     if (can_apply_object(mon, item)&CAN_APPLY_NOT_MASK)
01622         return;
01623 
01624     /* should only be applying this item, not unapplying it.
01625      * also, ignore status of curse so they can take off old armour.
01626      * monsters have some advantages after all.
01627      */
01628     manual_apply(mon, item, AP_APPLY|AP_IGNORE_CURSE);
01629     return;
01630 }
01631 
01632 void npc_call_help(object *op) {
01633     int x, y, mflags;
01634     object *npc;
01635     sint16 sx, sy;
01636     mapstruct *m;
01637 
01638     for (x = -3; x < 4; x++)
01639         for (y = -3; y < 4; y++) {
01640             m = op->map;
01641             sx = op->x+x;
01642             sy = op->y+y;
01643             mflags = get_map_flags(m, &m, sx, sy, &sx, &sy);
01644             /* If nothing alive on this space, no need to search the space. */
01645             if ((mflags&P_OUT_OF_MAP) || !(mflags&P_IS_ALIVE))
01646                 continue;
01647 
01648             for (npc = GET_MAP_OB(m, sx, sy); npc != NULL; npc = npc->above)
01649                 if (QUERY_FLAG(npc, FLAG_ALIVE) && QUERY_FLAG(npc, FLAG_UNAGGRESSIVE))
01650                     npc->enemy = op->enemy;
01651         }
01652 }
01653 
01654 static int dist_att(int dir, object *ob, object *enemy, object *part, rv_vector *rv) {
01655     if (can_hit(part, enemy, rv))
01656         return dir;
01657     if (rv->distance < 10)
01658         return absdir(dir+4);
01659     else if (rv->distance > 18)
01660         return dir;
01661     return 0;
01662 }
01663 
01664 static int run_att(int dir, object *ob, object *enemy, object *part, rv_vector *rv) {
01665     if ((can_hit(part, enemy, rv) && ob->move_status < 20) || ob->move_status < 20) {
01666         ob->move_status++;
01667         return (dir);
01668     } else if (ob->move_status > 20)
01669         ob->move_status = 0;
01670     return absdir(dir+4);
01671 }
01672 
01673 static int hitrun_att(int dir, object *ob, object *enemy) {
01674     if (ob->move_status++ < 25)
01675         return dir;
01676     else if (ob->move_status < 50)
01677         return absdir(dir+4);
01678     else
01679         ob->move_status = 0;
01680     return absdir(dir+4);
01681 }
01682 
01683 static int wait_att(int dir, object *ob, object *enemy, object *part, rv_vector *rv) {
01684     int inrange = can_hit(part, enemy, rv);
01685 
01686     if (ob->move_status || inrange)
01687         ob->move_status++;
01688 
01689     if (ob->move_status == 0)
01690         return 0;
01691     else if (ob->move_status < 10)
01692         return dir;
01693     else if (ob->move_status < 15)
01694         return absdir(dir+4);
01695     ob->move_status = 0;
01696     return 0;
01697 }
01698 
01699 static int disthit_att(int dir, object *ob, object *enemy, object *part, rv_vector *rv) {
01700     /* The logic below here looked plain wrong before.  Basically, what should
01701      * happen is that if the creatures hp percentage falls below run_away,
01702      * the creature should run away (dir+4)
01703      * I think its wrong for a creature to have a zero maxhp value, but
01704      * at least one map has this set, and whatever the map contains, the
01705      * server should try to be resilant enough to avoid the problem
01706      */
01707     if (ob->stats.maxhp && (ob->stats.hp*100)/ob->stats.maxhp < ob->run_away)
01708         return absdir(dir+4);
01709     return dist_att(dir, ob, enemy, part, rv);
01710 }
01711 
01712 static int wait_att2(int dir, object *ob, object *enemy, object *part, rv_vector *rv) {
01713     if (rv->distance < 9)
01714         return absdir(dir+4);
01715     return 0;
01716 }
01717 
01718 static void circ1_move(object *ob) {
01719     static const int circle [12] = { 3, 3, 4, 5, 5, 6, 7, 7, 8, 1, 1, 2 };
01720 
01721     if (++ob->move_status > 11)
01722         ob->move_status = 0;
01723     if (!(move_object(ob, circle[ob->move_status])))
01724         (void)move_object(ob, RANDOM()%8+1);
01725 }
01726 
01727 static void circ2_move(object *ob) {
01728     static const int circle[20] = { 3, 3, 3, 4, 4, 5, 5, 5, 6, 6, 7, 7, 7, 8, 8, 1, 1, 1, 2, 2 };
01729 
01730     if (++ob->move_status > 19)
01731         ob->move_status = 0;
01732     if (!(move_object(ob, circle[ob->move_status])))
01733         (void)move_object(ob, RANDOM()%8+1);
01734 }
01735 
01736 static void pace_movev(object *ob) {
01737     if (ob->move_status++ > 6)
01738         ob->move_status = 0;
01739     if (ob->move_status < 4)
01740         (void)move_object(ob, 5);
01741     else
01742         (void)move_object(ob, 1);
01743 }
01744 
01745 static void pace_moveh(object *ob) {
01746     if (ob->move_status++ > 6)
01747         ob->move_status = 0;
01748     if (ob->move_status < 4)
01749         (void)move_object(ob, 3);
01750     else
01751         (void)move_object(ob, 7);
01752 }
01753 
01754 static void pace2_movev(object *ob) {
01755     if (ob->move_status++ > 16)
01756         ob->move_status = 0;
01757     if (ob->move_status < 6)
01758         (void)move_object(ob, 5);
01759     else if (ob->move_status < 8)
01760         return;
01761     else if (ob->move_status < 13)
01762         (void)move_object(ob, 1);
01763     else
01764         return;
01765 }
01766 
01767 static void pace2_moveh(object *ob) {
01768     if (ob->move_status++ > 16)
01769         ob->move_status = 0;
01770     if (ob->move_status < 6)
01771         (void)move_object(ob, 3);
01772     else if (ob->move_status < 8)
01773         return;
01774     else if (ob->move_status < 13)
01775         (void)move_object(ob, 7);
01776     else
01777         return;
01778 }
01779 
01780 static void rand_move(object *ob) {
01781     int i;
01782 
01783     if (ob->move_status < 1
01784     || ob->move_status > 8
01785     || !(move_object(ob, ob->move_status || !(RANDOM()%9))))
01786         for (i = 0; i < 5; i++)
01787             if (move_object(ob, ob->move_status = RANDOM()%8+1))
01788                 return;
01789 }
01790 
01791 void check_earthwalls(object *op, mapstruct *m, int x, int y) {
01792     object *tmp;
01793 
01794     for (tmp = GET_MAP_OB(m, x, y); tmp != NULL; tmp = tmp->above) {
01795         if (tmp->type == EARTHWALL) {
01796             hit_player(tmp, op->stats.dam, op, AT_PHYSICAL, 1);
01797             return;
01798         }
01799     }
01800 }
01801 
01802 void check_doors(object *op, mapstruct *m, int x, int y) {
01803     object *tmp;
01804 
01805     for (tmp = GET_MAP_OB(m, x, y); tmp != NULL; tmp = tmp->above) {
01806         if (tmp->type == DOOR) {
01807             hit_player(tmp, 1000, op, AT_PHYSICAL, 1);
01808             return;
01809         }
01810     }
01811 }
01812 
01831 void communicate(object *op, const char *txt) {
01832     object *npc;
01833     int i, mflags, talked = 0;
01834     sint16 x, y;
01835     mapstruct *mp, *orig_map = op->map;
01836     char buf[MAX_BUF];
01837 
01838     snprintf(buf, sizeof(buf), "%s says: %s", op->name, txt);
01839     if (op->type == PLAYER) {
01840         ext_info_map(NDI_WHITE, op->map, MSG_TYPE_COMMUNICATION, MSG_TYPE_COMMUNICATION_SAY, buf, NULL);
01841     }
01842 
01843     /* Note that this loop looks pretty inefficient to me - we look and try to talk
01844      * to every object within 2 spaces.  It would seem that if we trim this down to
01845      * only try to talk to objects with npc->msg set, things would be a lot more efficient,
01846      * but I'm not sure if there are any objects out there that don't have a message and instead
01847      * rely sorely on events - MSW 2009-04-14
01848      */
01849     for (i = 0; i <= SIZEOFFREE2; i++) {
01850         mp = op->map;
01851         x = op->x+freearr_x[i];
01852         y = op->y+freearr_y[i];
01853 
01854         mflags = get_map_flags(mp, &mp, x, y, &x, &y);
01855         if (mflags&P_OUT_OF_MAP)
01856             continue;
01857 
01858         for (npc = GET_MAP_OB(mp, x, y); npc != NULL; npc = npc->above) {
01859             talk_to_npc(op, npc, txt, &talked);
01860             if (orig_map != op->map) {
01861                 LOG(llevDebug, "Warning: Forced to swap out very recent map - MAX_OBJECTS should probably be increased\n");
01862                 return;
01863             }
01864         }
01865     }
01866 
01867     /* if talked is set, then the talk_to_npc() wrote out this information, so
01868      * don't do it again.
01869      */
01870     if (!talked) {
01871     }
01872 }
01873 
01883 static int do_talk_npc(object *op, object *npc, const char *txt, int *talked) {
01884     char buf[MAX_BUF];
01885     struct_dialog_reply *reply;
01886     struct_dialog_message *message;
01887 
01888     if (!get_dialog_message(npc, txt, &message, &reply))
01889         return 0;
01890 
01891     if (reply) {
01892         snprintf(buf, sizeof(buf), "%s %s: %s", op->name, (reply->type == rt_reply ? "replies" : "asks"), reply->message);
01893         ext_info_map(NDI_WHITE, op->map, MSG_TYPE_COMMUNICATION, MSG_TYPE_COMMUNICATION_SAY, buf, NULL);
01894         *talked = 1;
01895     }
01896 #if 0
01897     /* let the caller handle this reply - no reason we need to.  Leaving this in for the
01898      * time being, as I don't completely understand what all of this is trying to do.
01899      * MSW 2009-04-14
01900      */
01901 
01902     else if (!*talked) {
01903         *talked = 1;
01904         snprintf(buf, sizeof(buf), "%s says: %s", op->name, txt);
01905         ext_info_map(NDI_WHITE, op->map, MSG_TYPE_COMMUNICATION, MSG_TYPE_COMMUNICATION_SAY, buf, NULL);
01906     }
01907 #endif
01908 
01909     if (npc->type == MAGIC_EAR) {
01910         ext_info_map(NDI_NAVY|NDI_UNIQUE, npc->map, MSG_TYPE_DIALOG, MSG_TYPE_DIALOG_MAGIC_MOUTH, message->message, NULL);
01911         use_trigger(npc);
01912     } else {
01913         npc_say(npc, message->message);
01914         reply = message->replies;
01915 
01916         if (reply) {
01917             draw_ext_info(NDI_WHITE, 0, op, MSG_TYPE_COMMUNICATION, MSG_TYPE_COMMUNICATION_SAY, "Replies:", NULL);
01918             while (reply) {
01919                 draw_ext_info_format(NDI_WHITE, 0, op, MSG_TYPE_COMMUNICATION, MSG_TYPE_COMMUNICATION_SAY, " - %s: %s", NULL, reply->reply, reply->message);
01920                 reply = reply->next;
01921             }
01922         }
01923     }
01924 
01925     return 1;
01926 }
01927 
01933 void npc_say(object *npc, const char *cp) {
01934     char buf[HUGE_BUF], name[MAX_BUF];
01935 
01936     query_name(npc, name, sizeof(name));
01937     snprintf(buf, sizeof(buf), "%s says: %s", name, cp);
01938     ext_info_map(NDI_NAVY|NDI_UNIQUE, npc->map, MSG_TYPE_DIALOG, MSG_TYPE_DIALOG_NPC,
01939                  buf, buf);
01940 }
01941 
01952 static int talk_to_npc(object *op, object *npc, const char *txt, int *talked) {
01953     object *cobj;
01954 
01955     /* Move this commone area up here - shouldn't cost much extra cpu
01956      * time, and makes the function more readable */
01957     /* Lauwenmark: Handle for plugin say event */
01958     if (execute_event(npc, EVENT_SAY, op, NULL, txt, SCRIPT_FIX_ALL) != 0)
01959         return 0;
01960     /* Lauwenmark - Here we let the objects inside inventories hear and answer, too. */
01961     /* This allows the existence of "intelligent" weapons you can discuss with */
01962     for (cobj = npc->inv; cobj != NULL; cobj = cobj->below) {
01963         if (execute_event(cobj, EVENT_SAY, npc, NULL, txt, SCRIPT_FIX_ALL) != 0)
01964             return 0;
01965     }
01966     if (op == npc)
01967         return 0;
01968     return do_talk_npc(op, npc, txt, talked);
01969 }
01970 
01971 /* find_mon_throw_ob() - modeled on find_throw_ob
01972  * This is probably overly simplistic as it is now - We want
01973  * monsters to throw things like chairs and other pieces of
01974  * furniture, even if they are not good throwable objects.
01975  * Probably better to have the monster throw a throwable object
01976  * first, then throw any non equipped weapon.
01977  */
01978 object *find_mon_throw_ob(object *op) {
01979     object *tmp = NULL;
01980 
01981     if (op->head)
01982         tmp = op->head;
01983     else
01984         tmp = op;
01985 
01986     /* New throw code: look through the inventory. Grap the first legal is_thrown
01987      * marked item and throw it to the enemy.
01988      */
01989 
01990     for (tmp = op->inv; tmp; tmp = tmp->below) {
01991         /* Can't throw invisible objects or items that are applied */
01992         if (tmp->invisible || QUERY_FLAG(tmp, FLAG_APPLIED))
01993             continue;
01994 
01995         if (QUERY_FLAG(tmp, FLAG_IS_THROWN))
01996             break;
01997     }
01998 
01999 #ifdef DEBUG_THROW
02000     {
02001         char what[MAX_BUF];
02002 
02003         query_name(tmp, what, MAX_BUF);
02004         LOG(llevDebug, "%s chooses to throw: %s (%d)\n", op->name, !(tmp) ? "(nothing)" : what, tmp ? tmp->count : -1);
02005     }
02006 #endif
02007 
02008     return tmp;
02009 }
02010 
02011 /* determine if we can 'detect' the enemy. Check for walls blocking the
02012  * los. Also, just because its hidden/invisible, we may be sensitive/smart
02013  * enough (based on Wis & Int) to figure out where the enemy is. -b.t.
02014  * modified by MSW to use the get_rangevector so that map tiling works
02015  * properly.  I also so odd code in place that checked for x distance
02016  * OR y distance being within some range - that seemed wrong - both should
02017  * be within the valid range. MSW 2001-08-05
02018  * Returns 0 if enemy can not be detected, 1 if it is detected
02019  */
02020 int can_detect_enemy(object *op, object *enemy, rv_vector *rv) {
02021     int radius = MIN_MON_RADIUS, hide_discovery;
02022 
02023     /* null detection for any of these condtions always */
02024     if (!op || !enemy || !op->map || !enemy->map)
02025         return 0;
02026 
02027     /* If the monster (op) has no way to get to the enemy, do nothing */
02028     if (!on_same_map(op, enemy))
02029         return 0;
02030 
02031     get_rangevector(op, enemy, rv, 0);
02032 
02033     /* Monsters always ignore the DM */
02034     if ((op->type != PLAYER) && QUERY_FLAG(enemy, FLAG_WIZ))
02035         return 0;
02036 
02037     /* simple check.  Should probably put some range checks in here. */
02038     if (can_see_enemy(op, enemy))
02039         return 1;
02040 
02041     /* The rest of this is for monsters. Players are on their own for
02042      * finding enemies!
02043      */
02044     if (op->type == PLAYER)
02045         return 0;
02046 
02047     /* Quality invisible? Bah, we wont see them w/o SEE_INVISIBLE
02048      * flag (which was already checked) in can_see_enmy (). Lets get out of here
02049      */
02050     if (enemy->invisible && (!enemy->contr || (!enemy->contr->tmp_invis && !enemy->contr->hidden)))
02051         return 0;
02052 
02053     /* use this for invis also */
02054     hide_discovery = op->stats.Int/5;
02055 
02056     /* Determine Detection radii */
02057     if (!enemy->hide) /* to detect non-hidden (eg dark/invis enemy) */
02058         radius = MAX((op->stats.Wis/5)+1, MIN_MON_RADIUS);
02059     else { /* a level/INT/Dex adjustment for hiding */
02060         object *sk_hide;
02061         int bonus = (op->level/2)+(op->stats.Int/5);
02062 
02063         if (enemy->type == PLAYER) {
02064             if ((sk_hide = find_skill_by_number(enemy, SK_HIDING)))
02065                 bonus -= sk_hide->level;
02066             else {
02067                 LOG(llevError, "can_detect_enemy() got hidden player w/o hiding skill!\n");
02068                 make_visible(enemy);
02069                 radius = MAX(radius, MIN_MON_RADIUS);
02070             }
02071         } else /* enemy is not a player */
02072             bonus -= enemy->level;
02073 
02074         radius += bonus/5;
02075         hide_discovery += bonus*5;
02076     } /* else creature has modifiers for hiding */
02077 
02078     /* Radii stealth adjustment. Only if you are stealthy
02079     * will you be able to sneak up closer to creatures */
02080     if (QUERY_FLAG(enemy, FLAG_STEALTH))
02081         radius = radius/2, hide_discovery = hide_discovery/3;
02082 
02083     /* Radii adjustment for enemy standing in the dark */
02084     if (op->map->darkness > 0 && !stand_in_light(enemy)) {
02085         /* on dark maps body heat can help indicate location with infravision
02086          * undead don't have body heat, so no benefit detecting them.
02087          */
02088         if (QUERY_FLAG(op, FLAG_SEE_IN_DARK) && !is_true_undead(enemy))
02089             radius += op->map->darkness/2;
02090         else
02091             radius -= op->map->darkness/2;
02092 
02093         /* op next to a monster (and not in complete darkness)
02094          * the monster should have a chance to see you.
02095          */
02096         if (radius < MIN_MON_RADIUS && op->map->darkness < 5 && rv->distance <= 1)
02097             radius = MIN_MON_RADIUS;
02098     } /* if on dark map */
02099 
02100     /* Lets not worry about monsters that have incredible detection
02101      * radii, we only need to worry here about things the player can
02102      * (potentially) see.  This is 13, as that is the maximum size the player
02103      * may have for their map - in that way, creatures at the edge will
02104      * do something.  Note that the distance field in the
02105      * vector is real distance, so in theory this should be 18 to
02106      * find that.
02107      */
02108     if (radius > 13)
02109         radius = 13;
02110 
02111     /* Enemy in range! Now test for detection */
02112     if ((int)rv->distance <= radius) {
02113         /* ah, we are within range, detected? take cases */
02114         if (!enemy->invisible) /* enemy in dark squares... are seen! */
02115             return 1;
02116 
02117         /* hidden or low-quality invisible */
02118         if (enemy->hide && (rv->distance <= 1) && (RANDOM()%100 <= hide_discovery)) {
02119             make_visible(enemy);
02120             /* inform players of new status */
02121             if (enemy->type == PLAYER && player_can_view(enemy, op))
02122                 draw_ext_info_format(NDI_UNIQUE, 0, enemy, MSG_TYPE_SKILL, MSG_TYPE_SKILL_FAILURE,
02123                                      "You are discovered by %s!",
02124                                      "You are discovered by %s!",
02125                                      op->name);
02126             return 1; /* detected enemy */
02127         } else if (enemy->invisible) {
02128             /* Change this around - instead of negating the invisible, just
02129              * return true so that the mosnter that managed to detect you can
02130              * do something to you.  Decreasing the duration of invisible
02131              * doesn't make a lot of sense IMO, as a bunch of stupid creatures
02132              * can then basically negate the spell.  The spell isn't negated -
02133              * they just know where you are!
02134              */
02135             if ((RANDOM()%50) <= hide_discovery) {
02136                 if (enemy->type == PLAYER) {
02137                     char name[MAX_BUF];
02138 
02139                     query_name(op, name, MAX_BUF);
02140                     draw_ext_info_format(NDI_UNIQUE, 0, enemy, MSG_TYPE_SKILL, MSG_TYPE_SKILL_FAILURE,
02141                                          "You see %s noticing your position.",
02142                                          "You see %s noticing your position.",
02143                                          name);
02144                 }
02145                 return 1;
02146             }
02147         }
02148     } /* within range */
02149 
02150     /* Wasn't detected above, so still hidden */
02151     return 0;
02152 }
02153 
02154 /* determine if op stands in a lighted square. This is not a very
02155  * intellegent algorithm. For one thing, we ignore los here, SO it
02156  * is possible for a bright light to illuminate a player on the
02157  * other side of a wall (!).
02158  */
02159 int stand_in_light(object *op) {
02160     sint16 nx, ny;
02161     mapstruct *m;
02162 
02163     if (!op)
02164         return 0;
02165     if (op->glow_radius > 0)
02166         return 1;
02167 
02168     if (op->map) {
02169         int x, y, x1, y1;
02170 
02171         /* Check the spaces with the max light radius to see if any of them
02172          * have lights, and if any of them light the player enough, then return 1.
02173          */
02174         for (x = op->x-MAX_LIGHT_RADII; x <= op->x+MAX_LIGHT_RADII; x++) {
02175             for (y = op->y-MAX_LIGHT_RADII; y <= op->y+MAX_LIGHT_RADII; y++) {
02176                 m = op->map;
02177                 nx = x;
02178                 ny = y;
02179 
02180                 if (get_map_flags(m, &m, nx, ny, &nx, &ny)&P_OUT_OF_MAP)
02181                     continue;
02182 
02183                 x1 = abs(x-op->x)*abs(x-op->x);
02184                 y1 = abs(y-op->y)*abs(y-op->y);
02185                 if (isqrt(x1+y1) < GET_MAP_LIGHT(m, nx, ny))
02186                     return 1;
02187             }
02188         }
02189     }
02190     return 0;
02191 }
02192 
02193 /*
02194  * assuming no walls/barriers, lets check to see if its *possible*
02195  * to see an enemy. Note, "detection" is different from "seeing".
02196  * See can_detect_enemy() for more details. -b.t.
02197  * return 0 if can't be seen, 1 if can be
02198  */
02199 int can_see_enemy(object *op, object *enemy) {
02200     object *looker = op->head ? op->head : op;
02201 
02202     /* safety */
02203     if (!looker || !enemy || !QUERY_FLAG(looker, FLAG_ALIVE))
02204         return 0;
02205 
02206     /* we dont give a full treatment of xrays here (shorter range than normal,
02207      * see through walls). Should we change the code elsewhere to make you
02208      * blind even if you can xray?
02209      */
02210     if (QUERY_FLAG(looker, FLAG_BLIND) && !QUERY_FLAG(looker, FLAG_XRAYS))
02211         return 0;
02212 
02213     /* checking for invisible things */
02214     if (enemy->invisible) {
02215         /* HIDDEN ENEMY. by definition, you can't see hidden stuff!
02216          * However, if you carry any source of light, then the hidden
02217          * creature is seeable (and stupid) */
02218         if (has_carried_lights(enemy)) {
02219             if (enemy->hide) {
02220                 make_visible(enemy);
02221                 draw_ext_info(NDI_UNIQUE, 0, enemy, MSG_TYPE_SKILL, MSG_TYPE_SKILL_FAILURE,
02222                               "Your light reveals your hiding spot!",
02223                               NULL);
02224             }
02225             return 1;
02226         } else if (enemy->hide)
02227             return 0;
02228 
02229         /* Invisible enemy.  Break apart the check for invis undead/invis looker
02230          * into more simple checks - the QUERY_FLAG doesn't return 1/0 values,
02231          * and making it a conditional makes the code pretty ugly.
02232          */
02233         if (!QUERY_FLAG(looker, FLAG_SEE_INVISIBLE)) {
02234             if (makes_invisible_to(enemy, looker))
02235                 return 0;
02236         }
02237     } else if (looker->type == PLAYER) /* for players, a (possible) shortcut */
02238         if (player_can_view(looker, enemy))
02239             return 1;
02240 
02241     /* ENEMY IN DARK MAP. Without infravision, the enemy is not seen
02242      * unless they carry a light or stand in light. Darkness doesnt
02243      * inhibit the undead per se (but we should give their archs
02244      * CAN_SEE_IN_DARK, this is just a safety
02245      * we care about the enemy maps status, not the looker.
02246      * only relevant for tiled maps, but it is possible that the
02247      * enemy is on a bright map and the looker on a dark - in that
02248      * case, the looker can still see the enemy
02249      */
02250     if (enemy->map->darkness > 0
02251     && !stand_in_light(enemy)
02252     && (!QUERY_FLAG(looker, FLAG_SEE_IN_DARK) || !is_true_undead(looker) || !QUERY_FLAG(looker, FLAG_XRAYS)))
02253         return 0;
02254 
02255     return 1;
02256 }