Atrinik Server 2.5
types/monster.c
Go to the documentation of this file.
00001 /************************************************************************
00002 *            Atrinik, a Multiplayer Online Role Playing Game            *
00003 *                                                                       *
00004 *    Copyright (C) 2009-2011 Alex Tokar and Atrinik Development Team    *
00005 *                                                                       *
00006 * Fork from Daimonin (Massive Multiplayer Online Role Playing Game)     *
00007 * and Crossfire (Multiplayer game for X-windows).                       *
00008 *                                                                       *
00009 * This program is free software; you can redistribute it and/or modify  *
00010 * it under the terms of the GNU General Public License as published by  *
00011 * the Free Software Foundation; either version 2 of the License, or     *
00012 * (at your option) any later version.                                   *
00013 *                                                                       *
00014 * This program is distributed in the hope that it will be useful,       *
00015 * but WITHOUT ANY WARRANTY; without even the implied warranty of        *
00016 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
00017 * GNU General Public License for more details.                          *
00018 *                                                                       *
00019 * You should have received a copy of the GNU General Public License     *
00020 * along with this program; if not, write to the Free Software           *
00021 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.             *
00022 *                                                                       *
00023 * The author can be reached at admin@atrinik.org                        *
00024 ************************************************************************/
00025 
00032 #include <global.h>
00033 
00034 extern spell_struct spells[NROFREALSPELLS];
00035 
00036 static int can_detect_enemy(object *op, object *enemy, rv_vector *rv);
00037 static object *find_nearest_enemy(object *ob);
00038 static int move_randomly(object *op);
00039 static int can_hit(object *ob1, rv_vector *rv);
00040 static object *monster_choose_random_spell(object *monster, uint32 flags);
00041 static int monster_cast_spell(object *head, object *part, int dir, rv_vector *rv, uint32 flags);
00042 static int monster_use_bow(object *head, object *part, int dir);
00043 static int dist_att(int dir, object *part, rv_vector *rv);
00044 static int run_att(int dir, object *ob, object *part, rv_vector *rv);
00045 static int hitrun_att(int dir, object *ob);
00046 static int wait_att(int dir, object *ob, object *part, rv_vector *rv);
00047 static int disthit_att(int dir, object *ob, object *part, rv_vector *rv);
00048 static int wait_att2(int dir, rv_vector *rv);
00049 static void circ1_move(object *ob);
00050 static void circ2_move(object *ob);
00051 static void pace_movev(object *ob);
00052 static void pace_moveh(object *ob);
00053 static void pace2_movev(object *ob);
00054 static void pace2_moveh(object *ob);
00055 static void rand_move(object *ob);
00056 static int talk_to_wall(object *op, object *npc, char *txt);
00057 
00072 void set_npc_enemy(object *npc, object *enemy, rv_vector *rv)
00073 {
00074     object *aggro_wp;
00075     rv_vector rv2;
00076 
00077     /* Do nothing if new enemy == old enemy */
00078     if (enemy == npc->enemy && (enemy == NULL || enemy->count == npc->enemy_count))
00079     {
00080         return;
00081     }
00082 
00083     /* Players don't need waypoints, speed updates or aggro counters */
00084     if (npc->type == PLAYER)
00085     {
00086         npc->enemy = enemy;
00087 
00088         if (enemy)
00089         {
00090             npc->enemy_count = enemy->count;
00091         }
00092 
00093         return;
00094     }
00095 
00096     /* Non-aggro-waypoint related stuff */
00097     if (enemy)
00098     {
00099         if (rv == NULL)
00100         {
00101             rv = &rv2;
00102         }
00103 
00104         get_rangevector(npc, enemy, rv, RV_DIAGONAL_DISTANCE);
00105         npc->enemy_count = enemy->count;
00106 
00107         /* important: that's our "we lose aggro count" - reset to zero here */
00108         npc->last_eat = 0;
00109 
00110         /* Monster has changed status from normal to attack - let's hear it! */
00111         if (npc->enemy == NULL && !QUERY_FLAG(npc, FLAG_FRIENDLY))
00112         {
00113             play_sound_map(npc->map, CMD_SOUND_EFFECT, "growl.ogg", npc->x, npc->y, 0, 0);
00114         }
00115 
00116         if (QUERY_FLAG(npc, FLAG_UNAGGRESSIVE))
00117         {
00118             /* The unaggressives look after themselves 8) */
00119             CLEAR_FLAG(npc, FLAG_UNAGGRESSIVE);
00120         }
00121     }
00122     else
00123     {
00124         object *base = insert_base_info_object(npc);
00125         object *wp = get_active_waypoint(npc);
00126 
00127         if (base && !wp && wp_archetype)
00128         {
00129             object *return_wp = get_return_waypoint(npc);
00130 
00131 #ifdef DEBUG_PATHFINDING
00132             LOG(llevDebug, "set_npc_enemy(): %s lost aggro and is returning home (%s:%d,%d)\n", STRING_OBJ_NAME(npc), base->slaying, base->x, base->y);
00133 #endif
00134             if (!return_wp)
00135             {
00136                 return_wp = arch_to_object(wp_archetype);
00137                 insert_ob_in_ob(return_wp, npc);
00138                 return_wp->owner = npc;
00139                 return_wp->ownercount = npc->count;
00140                 FREE_AND_ADD_REF_HASH(return_wp->name, shstr_cons.home);
00141                 /* mark as return-home wp */
00142                 SET_FLAG(return_wp, FLAG_REFLECTING);
00143                 /* mark as best-effort wp */
00144                 SET_FLAG(return_wp, FLAG_NO_ATTACK);
00145             }
00146 
00147             return_wp->stats.hp = base->x;
00148             return_wp->stats.sp = base->y;
00149             FREE_AND_ADD_REF_HASH(return_wp->slaying, base->slaying);
00150             /* Activate wp */
00151             SET_FLAG(return_wp, FLAG_CURSED);
00152             /* reset best-effort timer */
00153             return_wp->stats.Int = 0;
00154 
00155             /* setup move_type to use waypoints */
00156             return_wp->move_type = npc->move_type;
00157             npc->move_type = (npc->move_type & LO4) | WPOINT;
00158 
00159             wp = return_wp;
00160         }
00161 
00162         /* TODO: add a little pause to the active waypoint */
00163     }
00164 
00165     npc->enemy = enemy;
00166     /* Update speed */
00167     set_mobile_speed(npc, 0);
00168 
00169     /* Setup aggro waypoint */
00170     if (!wp_archetype)
00171     {
00172 #ifdef DEBUG_PATHFINDING
00173         LOG(llevDebug, "set_npc_enemy(): Aggro waypoints disabled\n");
00174 #endif
00175         return;
00176     }
00177 
00178     /* TODO: check intelligence against lower limit to allow pathfind */
00179     aggro_wp = get_aggro_waypoint(npc);
00180 
00181     /* Create a new aggro wp for npc? */
00182     if (!aggro_wp && enemy)
00183     {
00184         aggro_wp = arch_to_object(wp_archetype);
00185         insert_ob_in_ob(aggro_wp, npc);
00186         /* Mark as aggro WP */
00187         SET_FLAG(aggro_wp, FLAG_DAMNED);
00188         aggro_wp->owner = npc;
00189 #ifdef DEBUG_PATHFINDING
00190         LOG(llevDebug, "set_npc_enemy(): created wp for '%s'\n", STRING_OBJ_NAME(npc));
00191 #endif
00192     }
00193 
00194     /* Set up waypoint target (if we actually got a waypoint) */
00195     if (aggro_wp)
00196     {
00197         if (enemy)
00198         {
00199             aggro_wp->enemy_count = npc->enemy_count;
00200             aggro_wp->enemy = enemy;
00201             FREE_AND_ADD_REF_HASH(aggro_wp->name, enemy->name);
00202 #ifdef DEBUG_PATHFINDING
00203             LOG(llevDebug, "set_npc_enemy(): got wp for '%s' -> '%s'\n", npc->name, enemy->name);
00204 #endif
00205         }
00206         else
00207         {
00208             aggro_wp->enemy = NULL;
00209 #ifdef DEBUG_PATHFINDING
00210             LOG(llevDebug, "set_npc_enemy(): cleared aggro wp for '%s'\n", npc->name);
00211 #endif
00212         }
00213     }
00214 }
00215 
00221 object *check_enemy(object *npc, rv_vector *rv)
00222 {
00223     if (npc->enemy == NULL)
00224     {
00225         return NULL;
00226     }
00227 
00228     if (!OBJECT_VALID(npc->enemy, npc->enemy_count) || npc == npc->enemy || !IS_LIVE(npc->enemy) || is_friend_of(npc, npc->enemy))
00229     {
00230         set_npc_enemy(npc, NULL, NULL);
00231         return NULL;
00232     }
00233 
00234     return can_detect_enemy(npc, npc->enemy, rv) ? npc->enemy : NULL;
00235 }
00236 
00243 object *find_enemy(object *npc, rv_vector *rv)
00244 {
00245     object *tmp = NULL;
00246 
00247     /* If we are berserk, we don't care about others - we attack all we can
00248      * find. */
00249     if (QUERY_FLAG(npc, FLAG_BERSERK))
00250     {
00251         /* Always clear the attacker entry */
00252         npc->attacked_by = NULL;
00253         tmp = find_nearest_enemy(npc);
00254 
00255         if (tmp)
00256         {
00257             get_rangevector(npc, tmp, rv, 0);
00258         }
00259 
00260         return tmp;
00261     }
00262 
00263     tmp = check_enemy(npc, rv);
00264 
00265     if (!tmp)
00266     {
00267         /* If we have an attacker, check him */
00268         if (OBJECT_VALID(npc->attacked_by, npc->attacked_by_count) && !IS_INVISIBLE(npc->attacked_by, npc) && !QUERY_FLAG(npc->attacked_by, FLAG_INVULNERABLE))
00269         {
00270             /* We don't want a fight evil vs evil or good against non evil. */
00271             if (is_friend_of(npc, npc->attacked_by))
00272             {
00273                 /* Skip it, but let's wake up */
00274                 CLEAR_FLAG(npc, FLAG_SLEEP);
00275             }
00276             /* The only thing we must know... */
00277             else if (on_same_map(npc, npc->attacked_by))
00278             {
00279                 CLEAR_FLAG(npc, FLAG_SLEEP);
00280                 set_npc_enemy(npc, npc->attacked_by, rv);
00281                 /* Always clear the attacker entry */
00282                 npc->attacked_by = NULL;
00283 
00284                 /* Face our attacker */
00285                 return npc->enemy;
00286             }
00287         }
00288 
00289         /* We have no legal enemy or attacker, so we try to target a new
00290          * one. */
00291         if (!QUERY_FLAG(npc, FLAG_UNAGGRESSIVE))
00292         {
00293             tmp = find_nearest_enemy(npc);
00294 
00295             if (tmp != npc->enemy)
00296             {
00297                 set_npc_enemy(npc, tmp, rv);
00298             }
00299         }
00300         else if (npc->enemy)
00301         {
00302             /* Make sure to clear the enemy, even if FLAG_UNAGRESSIVE is true */
00303             set_npc_enemy(npc, NULL, NULL);
00304         }
00305     }
00306 
00307     /* Always clear the attacker entry */
00308     npc->attacked_by = NULL;
00309     return tmp;
00310 }
00311 
00320 static int can_detect_enemy(object *op, object *enemy, rv_vector *rv)
00321 {
00322     /* Will check for legal maps too */
00323     if (!op || !enemy || !on_same_map(op, enemy))
00324     {
00325         return 0;
00326     }
00327 
00328     /* We check for sys_invisible and normal */
00329     if (IS_INVISIBLE(enemy, op) || QUERY_FLAG(enemy, FLAG_INVULNERABLE))
00330     {
00331         return 0;
00332     }
00333 
00334     if (!get_rangevector(op, enemy, rv, 0))
00335     {
00336         return 0;
00337     }
00338 
00339     /* If our enemy is too far away ... */
00340     if ((int) rv->distance >= MAX(MAX_AGGRO_RANGE, op->stats.Wis))
00341     {
00342         /* Then start counting until our mob loses aggro... */
00343         if (++op->last_eat > MAX_AGGRO_TIME)
00344         {
00345             set_npc_enemy(op, NULL, NULL);
00346             return 0;
00347         }
00348     }
00349     /* Our mob is aggroed again - because target is in range again */
00350     else
00351     {
00352         op->last_eat = 0;
00353     }
00354 
00355     return 1;
00356 }
00357 
00362 int move_monster(object *op)
00363 {
00364     int dir, special_dir = 0, diff;
00365     object *enemy, *part;
00366     rv_vector rv;
00367 
00368     if (op->head)
00369     {
00370         LOG(llevBug, "move_monster(): called from tail part. (%s -- %s)\n", query_name(op, NULL), op->arch->name);
00371         return 0;
00372     }
00373 
00374     /* Monsters not on maps don't do anything. */
00375     if (!op->map)
00376     {
00377         return 0;
00378     }
00379 
00380     /* If we are here, we're never paralyzed anymore */
00381     CLEAR_FLAG(op, FLAG_PARALYZED);
00382 
00383     /* For target facing, we copy this value here for fast access */
00384     op->anim_enemy_dir = -1;
00385     op->anim_moving_dir = -1;
00386 
00387     /* Here is the heart of the mob attack and target area.
00388      * find_enemy() checks the old enemy or gets us a new one. */
00389 
00390     /* We never ever attack */
00391     if (QUERY_FLAG(op, FLAG_NO_ATTACK))
00392     {
00393         if (op->enemy)
00394         {
00395             set_npc_enemy(op, NULL, NULL);
00396         }
00397 
00398         enemy = NULL;
00399     }
00400     else if ((enemy = find_enemy(op, &rv)))
00401     {
00402         CLEAR_FLAG(op, FLAG_SLEEP);
00403         op->anim_enemy_dir = rv.direction;
00404 
00405         if (!enemy->attacked_by || (enemy->attacked_by && enemy->attacked_by_distance > (int) rv.distance))
00406         {
00407             /* We have an enemy, just tell him we want him dead */
00408             enemy->attacked_by = op;
00409             enemy->attacked_by_count = op->count;
00410             /* Now the attacked foe knows how near we are */
00411             enemy->attacked_by_distance = (sint16) rv.distance;
00412         }
00413     }
00414 
00415     /* Generate hp, if applicable */
00416     if (op->stats.Con && op->stats.hp < op->stats.maxhp)
00417     {
00418         if (++op->last_heal > 5)
00419         {
00420             op->last_heal = 0;
00421             op->stats.hp += op->stats.Con;
00422 
00423             if (op->stats.hp > op->stats.maxhp)
00424             {
00425                 op->stats.hp = op->stats.maxhp;
00426             }
00427         }
00428 
00429         /* So if the monster has gained enough HP that they are no longer afraid */
00430         if (QUERY_FLAG(op, FLAG_RUN_AWAY) && op->stats.hp >= (signed short) (((float) op->run_away / (float) 100) * (float) op->stats.maxhp))
00431         {
00432             CLEAR_FLAG(op, FLAG_RUN_AWAY);
00433         }
00434     }
00435 
00436     /* Generate sp, if applicable */
00437     if (op->stats.Pow && op->stats.sp < op->stats.maxsp)
00438     {
00439         op->last_sp += (int) ((float) (8 * op->stats.Pow) / FABS(op->speed));
00440         /* causes Pow/16 sp/tick */
00441         op->stats.sp += op->last_sp / 128;
00442         op->last_sp %= 128;
00443 
00444         if (op->stats.sp > op->stats.maxsp)
00445         {
00446             op->stats.sp = op->stats.maxsp;
00447         }
00448     }
00449 
00450     /* Time to regain some "guts"... */
00451     if (QUERY_FLAG(op, FLAG_SCARED) && rndm_chance(20))
00452     {
00453         CLEAR_FLAG(op, FLAG_SCARED);
00454     }
00455 
00456     if (op->behavior & BEHAVIOR_SPELL_FRIENDLY)
00457     {
00458         if (op->last_grace)
00459         {
00460             op->last_grace--;
00461         }
00462 
00463         if (op->stats.Dex && rndm_chance(op->stats.Dex))
00464         {
00465             if (QUERY_FLAG(op, FLAG_CAST_SPELL) && !op->last_grace)
00466             {
00467                 if (monster_cast_spell(op, op, 0, NULL, SPELL_DESC_FRIENDLY))
00468                 {
00469                     /* Add monster casting delay */
00470                     op->last_grace += op->magic;
00471                 }
00472             }
00473         }
00474     }
00475 
00476     /* If we don't have an enemy, do special movement or the like */
00477     if (!enemy)
00478     {
00479         if (QUERY_FLAG(op, FLAG_ONLY_ATTACK))
00480         {
00481             remove_ob(op);
00482             check_walk_off(op, NULL, MOVE_APPLY_DEFAULT);
00483             return 1;
00484         }
00485 
00486         if (!QUERY_FLAG(op, FLAG_STAND_STILL))
00487         {
00488             if (op->move_type & HI4)
00489             {
00490                 switch (op->move_type & HI4)
00491                 {
00492                     case CIRCLE1:
00493                         circ1_move(op);
00494                         break;
00495 
00496                     case CIRCLE2:
00497                         circ2_move(op);
00498                         break;
00499 
00500                     case PACEV:
00501                         pace_movev(op);
00502                         break;
00503 
00504                     case PACEH:
00505                         pace_moveh(op);
00506                         break;
00507 
00508                     case PACEV2:
00509                         pace2_movev(op);
00510                         break;
00511 
00512                     case PACEH2:
00513                         pace2_moveh(op);
00514                         break;
00515 
00516                     case RANDO:
00517                         rand_move(op);
00518                         break;
00519 
00520                     case RANDO2:
00521                         move_randomly(op);
00522                         break;
00523 
00524                     case WPOINT:
00525                         waypoint_move(op, get_active_waypoint(op));
00526                         break;
00527                 }
00528 
00529                 return 0;
00530             }
00531             else if (QUERY_FLAG(op, FLAG_RANDOM_MOVE))
00532             {
00533                 move_randomly(op);
00534             }
00535         }
00536 
00537         return 0;
00538     }
00539 
00540     part = rv.part;
00541     dir = rv.direction;
00542 
00543     /* Move the check for scared up here - if the monster was scared,
00544      * we were not doing any of the logic below, so might as well save
00545      * a few CPU cycles. */
00546     if (!QUERY_FLAG(op, FLAG_SCARED))
00547     {
00548         if (op->last_grace)
00549         {
00550             op->last_grace--;
00551         }
00552 
00553         if (op->stats.Dex && rndm_chance(op->stats.Dex))
00554         {
00555             if (QUERY_FLAG(op, FLAG_CAST_SPELL) && !op->last_grace)
00556             {
00557                 if (monster_cast_spell(op, part, dir, &rv, SPELL_DESC_DIRECTION | SPELL_DESC_ENEMY | SPELL_DESC_SELF))
00558                 {
00559                     /* Add monster casting delay */
00560                     op->last_grace += op->magic;
00561                     return 0;
00562                 }
00563             }
00564 
00565             if (QUERY_FLAG(op, FLAG_READY_BOW) && rndm_chance(4))
00566             {
00567                 if (monster_use_bow(op, part, dir) && rndm_chance(2))
00568                 {
00569                     return 0;
00570                 }
00571             }
00572         }
00573     }
00574 
00575     if (QUERY_FLAG(op, FLAG_SCARED) || QUERY_FLAG(op, FLAG_RUN_AWAY))
00576     {
00577         dir = absdir(dir + 4);
00578     }
00579 
00580     if (QUERY_FLAG(op, FLAG_CONFUSED))
00581     {
00582         dir = get_randomized_dir(dir);
00583     }
00584 
00585     if (!QUERY_FLAG(op, FLAG_SCARED))
00586     {
00587         if (op->attack_move_type & LO4)
00588         {
00589             switch (op->attack_move_type & LO4)
00590             {
00591                 case DISTATT:
00592                     special_dir = dist_att(dir, part, &rv);
00593                     break;
00594 
00595                 case RUNATT:
00596                     special_dir = run_att(dir, op, part, &rv);
00597                     break;
00598 
00599                 case HITRUN:
00600                     special_dir = hitrun_att(dir, op);
00601                     break;
00602 
00603                 case WAITATT:
00604                     special_dir = wait_att(dir, op, part, &rv);
00605                     break;
00606 
00607                 case RUSH:
00608                 case ALLRUN:
00609                     special_dir = dir;
00610                     break;
00611 
00612                 case DISTHIT:
00613                     special_dir = disthit_att(dir, op, part, &rv);
00614                     break;
00615 
00616                 case WAIT2:
00617                     special_dir = wait_att2(dir, &rv);
00618                     break;
00619 
00620                 default:
00621                     LOG(llevDebug, "Illegal low mon-move: %d\n", op->attack_move_type & LO4);
00622             }
00623 
00624             if (!special_dir)
00625             {
00626                 return 0;
00627             }
00628         }
00629     }
00630 
00631     /* Try to move closer to enemy, or follow whatever special attack behavior is */
00632     if (!QUERY_FLAG(op, FLAG_STAND_STILL) && (QUERY_FLAG(op, FLAG_SCARED) || QUERY_FLAG(op, FLAG_RUN_AWAY) || !can_hit(part, &rv) || ((op->attack_move_type & LO4) && special_dir != dir)))
00633     {
00634         object *aggro_wp = get_aggro_waypoint(op);
00635 
00636         /* TODO: make (intelligent) monsters go to last known position of enemy if out of range/sight */
00637 
00638         /* If special attack move -> follow it instead of going towards enemy */
00639         if (((op->attack_move_type & LO4) && special_dir != dir))
00640         {
00641             aggro_wp = NULL;
00642             dir = special_dir;
00643         }
00644 
00645         /* If valid aggro wp (and no special attack), and not scared, use it for movement */
00646         if (aggro_wp && aggro_wp->enemy && aggro_wp->enemy == op->enemy && rv.distance > 1 && !QUERY_FLAG(op, FLAG_SCARED) && !QUERY_FLAG(op, FLAG_RUN_AWAY))
00647         {
00648             waypoint_move(op, aggro_wp);
00649             return 0;
00650         }
00651         else
00652         {
00653             int maxdiff = (QUERY_FLAG(op, FLAG_ONLY_ATTACK) || RANDOM() & 1) ? 1 : 2;
00654 
00655             /* Can the monster move directly toward player? */
00656             if (move_object(op, dir))
00657             {
00658                 return 0;
00659             }
00660 
00661             /* Try move around corners if !close */
00662             for (diff = 1; diff <= maxdiff; diff++)
00663             {
00664                 /* try different detours */
00665                 /* Try left or right first? */
00666                 int m = 1 - (RANDOM() & 2);
00667 
00668                 if (move_object(op, absdir(dir + diff * m)) || move_object(op, absdir(dir - diff * m)))
00669                 {
00670                     return 0;
00671                 }
00672             }
00673         }
00674     }
00675 
00676     /* Eneq(@csd.uu.se): Patch to make RUN_AWAY or SCARED monsters move a random
00677      * direction if they can't move away. */
00678     if (!QUERY_FLAG(op, FLAG_ONLY_ATTACK) && (QUERY_FLAG(op, FLAG_RUN_AWAY) || QUERY_FLAG(op, FLAG_SCARED)))
00679     {
00680         if (move_randomly(op))
00681         {
00682             return 0;
00683         }
00684     }
00685 
00686     /* Hit enemy if possible */
00687     if (!QUERY_FLAG(op, FLAG_SCARED) && !QUERY_FLAG(enemy, FLAG_REMOVED) && can_hit(part, &rv))
00688     {
00689         if (QUERY_FLAG(op, FLAG_RUN_AWAY))
00690         {
00691             part->stats.wc -= 10;
00692 
00693             /* As long we are > 0, we are not ready to swing */
00694             if (op->weapon_speed_left <= 0)
00695             {
00696                 skill_attack(enemy, part, 0, NULL);
00697                 op->weapon_speed_left += FABS((int) op->weapon_speed_left) + 1;
00698             }
00699 
00700             part->stats.wc += 10;
00701         }
00702         else
00703         {
00704             /* As long we are > 0, we are not ready to swing */
00705             if (op->weapon_speed_left <= 0)
00706             {
00707                 skill_attack(enemy, part, 0, NULL);
00708                 op->weapon_speed_left += FABS((int) op->weapon_speed_left) + 1;
00709             }
00710         }
00711     }
00712 
00713     /* Might be freed by ghost-attack or hit-back */
00714     if (OBJECT_FREE(part))
00715     {
00716         return 1;
00717     }
00718 
00719     if (QUERY_FLAG(op, FLAG_ONLY_ATTACK))
00720     {
00721         destruct_ob(op);
00722         return 1;
00723     }
00724 
00725     return 0;
00726 }
00727 
00736 static int can_detect_target(object *op, object *target, int range, int srange, rv_vector *rv)
00737 {
00738     /* We check for sys_invisible and normal */
00739     if (IS_INVISIBLE(target, op) || QUERY_FLAG(target, FLAG_INVULNERABLE))
00740     {
00741         return 0;
00742     }
00743 
00744     if (!get_rangevector(op, target, rv, 0))
00745     {
00746         return 0;
00747     }
00748 
00749     if (QUERY_FLAG(target, FLAG_STEALTH) && !QUERY_FLAG(op, FLAG_XRAYS))
00750     {
00751         if (srange < (int) rv->distance)
00752         {
00753             return 0;
00754         }
00755     }
00756     else
00757     {
00758         if (range < (int) rv->distance)
00759         {
00760             return 0;
00761         }
00762     }
00763 
00764     return 1;
00765 }
00766 
00771 static object *find_nearest_enemy(object *ob)
00772 {
00773     object *tmp;
00774     int aggro_range, aggro_stealth;
00775     rv_vector rv;
00776     int i, j, xt, yt;
00777     mapstruct *m;
00778 
00779     aggro_range = ob->stats.Wis;
00780 
00781     if (ob->enemy || ob->attacked_by)
00782     {
00783         aggro_range += 3;
00784     }
00785 
00786     if (QUERY_FLAG(ob, FLAG_SLEEP) || QUERY_FLAG(ob, FLAG_BLIND))
00787     {
00788         aggro_range /= 2;
00789         aggro_stealth = aggro_range - 2;
00790     }
00791     else
00792     {
00793         aggro_stealth = aggro_range - 2;
00794     }
00795 
00796     if (aggro_stealth < MIN_MON_RADIUS)
00797     {
00798         aggro_stealth = MIN_MON_RADIUS;
00799     }
00800 
00801     for (i = -aggro_range; i <= aggro_range; i++)
00802     {
00803         for (j = -aggro_range; j <= aggro_range; j++)
00804         {
00805             xt = ob->x + i;
00806             yt = ob->y + j;
00807 
00808             if (!(m = get_map_from_coord2(ob->map, &xt, &yt)))
00809             {
00810                 continue;
00811             }
00812 
00813             /* Nothing alive here? Move on... */
00814             if (!(GET_MAP_FLAGS(m, xt, yt) & (P_IS_ALIVE | P_IS_PLAYER)))
00815             {
00816                 continue;
00817             }
00818 
00819             for (tmp = GET_MAP_OB(m, xt, yt); tmp; tmp = tmp->above)
00820             {
00821                 /* Get head. */
00822                 if (tmp->head)
00823                 {
00824                     tmp = tmp->head;
00825                 }
00826 
00827                 /* Skip the monster looking for enemy and not alive objects. */
00828                 if (tmp == ob || !IS_LIVE(tmp))
00829                 {
00830                     continue;
00831                 }
00832 
00833                 /* Now check the friend status, whether we can reach the enemy, and LOS. */
00834                 if (!is_friend_of(ob, tmp) && can_detect_target(ob, tmp, aggro_range, aggro_stealth, &rv) && obj_in_line_of_sight(tmp, &rv))
00835                 {
00836                     return tmp;
00837                 }
00838             }
00839         }
00840     }
00841 
00842     return NULL;
00843 }
00844 
00849 static int move_randomly(object *op)
00850 {
00851     int i, r;
00852     int dirs[8] = {1, 2, 3, 4, 5, 6, 7, 8};
00853     mapstruct *basemap = NULL;
00854     rv_vector rv;
00855 
00856     if (op->item_race || op->item_level)
00857     {
00858         object *base = find_base_info_object(op);
00859 
00860         if ((basemap = ready_map_name(base->slaying, MAP_NAME_SHARED)))
00861         {
00862             if (!get_rangevector_from_mapcoords(basemap, base->x, base->y, op->map, op->x, op->y, &rv, RV_NO_DISTANCE))
00863             {
00864                 basemap = NULL;
00865             }
00866         }
00867     }
00868 
00869     /* Give up to 8 chances for a monster to move randomly */
00870     for (i = 0; i < 8; i++)
00871     {
00872         int t = dirs[i];
00873 
00874         /* Perform a single random shuffle of the remaining directions */
00875         r = i + (RANDOM() % (8 - i));
00876         dirs[i] = dirs[r];
00877         dirs[r] = t;
00878 
00879         r = dirs[i];
00880 
00881         /* Check x and y direction of possible move against limit parameters */
00882         if (basemap)
00883         {
00884             if (abs(rv.distance_x + freearr_x[r]) > op->item_race)
00885             {
00886                 continue;
00887             }
00888 
00889             if (abs(rv.distance_y + freearr_y[r]) > op->item_level)
00890             {
00891                 continue;
00892             }
00893         }
00894 
00895         if (HAS_EVENT(op, EVENT_AI))
00896         {
00897             int ret = trigger_event(EVENT_AI, NULL, op, NULL, NULL, EVENT_AI_RANDOM_MOVE, r, 0, SCRIPT_FIX_NOTHING);
00898 
00899             /* Cancel random movement. */
00900             if (ret == 1)
00901             {
00902                 return 0;
00903             }
00904             /* Keep trying. */
00905             else if (ret == 2)
00906             {
00907                 continue;
00908             }
00909         }
00910 
00911         if (move_object(op, r))
00912         {
00913             return 1;
00914         }
00915     }
00916 
00917     return 0;
00918 }
00919 
00925 static int can_hit(object *ob1, rv_vector *rv)
00926 {
00927     if (QUERY_FLAG(ob1, FLAG_CONFUSED) && !(RANDOM() % 3))
00928     {
00929         return 0;
00930     }
00931 
00932     return abs(rv->distance_x) < 2 && abs(rv->distance_y) < 2;
00933 }
00934 
00935 #define MAX_KNOWN_SPELLS 20
00936 
00942 static object *monster_choose_random_spell(object *monster, uint32 flags)
00943 {
00944     object *altern[MAX_KNOWN_SPELLS], *tmp;
00945     spell_struct *spell;
00946     int i = 0, j;
00947 
00948     for (tmp = monster->inv; tmp != NULL; tmp = tmp->below)
00949     {
00950         if (tmp->type == ABILITY || tmp->type == SPELLBOOK)
00951         {
00952             /* Check and see if it's actually a useful spell */
00953             if ((spell = find_spell(tmp->stats.sp)) != NULL && !(spell->path & (PATH_INFO | PATH_TRANSMUTE | PATH_TRANSFER | PATH_LIGHT)) && spell->flags & flags)
00954             {
00955                 if (tmp->stats.maxsp)
00956                 {
00957                     for (j = 0; i < MAX_KNOWN_SPELLS && j < tmp->stats.maxsp; j++)
00958                     {
00959                         altern[i++] = tmp;
00960                     }
00961                 }
00962                 else
00963                 {
00964                     altern[i++] = tmp;
00965                 }
00966 
00967                 if (i == MAX_KNOWN_SPELLS)
00968                 {
00969                     break;
00970                 }
00971             }
00972 
00973         }
00974     }
00975 
00976     if (!i)
00977     {
00978         return NULL;
00979     }
00980 
00981     return altern[rndm(1, i) - 1];
00982 }
00983 
00989 static int monster_spell_useful(object *target, int spell_id)
00990 {
00991     switch (spell_id)
00992     {
00993         case SP_MINOR_HEAL:
00994         case SP_GREATER_HEAL:
00995             return target->stats.hp != target->stats.maxhp;
00996     }
00997 
00998     return 1;
00999 }
01000 
01010 static int monster_cast_spell(object *head, object *part, int dir, rv_vector *rv, uint32 flags)
01011 {
01012     object *spell_item, *target = NULL;
01013     spell_struct *sp;
01014     int sp_typ, ability;
01015 
01016     if ((spell_item = monster_choose_random_spell(head, flags)) == NULL)
01017     {
01018         LOG(llevDebug, "monster_cast_spell: No spell found! Turned off spells in %s (%s) (%d,%d)\n", query_name(head, NULL), head->map ? (head->map->name ? head->map->name : "<no map name>") : "<no map!>", head->x, head->y );
01019         /* Will be turned on when picking up book */
01020         CLEAR_FLAG(head, FLAG_CAST_SPELL);
01021         return 0;
01022     }
01023 
01024     /* Only considering long range spells if we're not looking for friendly target. */
01025     if (spell_item->stats.hp != -1 && rv)
01026     {
01027         /* Alternate long-range spell: check how far away enemy is */
01028         if (rv->distance > 6)
01029         {
01030             sp_typ = spell_item->stats.hp;
01031         }
01032         else
01033         {
01034             sp_typ = spell_item->stats.sp;
01035         }
01036     }
01037     else
01038     {
01039         sp_typ = spell_item->stats.sp;
01040 
01041         /* Not looking for friendly target, but this is a friendly spell, and it's not the
01042          * same as long range one? */
01043         if (rv && spells[sp_typ].flags & SPELL_DESC_FRIENDLY && sp_typ != spell_item->stats.hp)
01044         {
01045             return 0;
01046         }
01047     }
01048 
01049     if (sp_typ == -1 || (sp = find_spell(sp_typ)) == NULL)
01050     {
01051         LOG(llevDebug, "monster_cast_spell: Can't find spell #%d for mob %s (%s) (%d,%d)\n", sp_typ, query_name(head, NULL), head->map ? (head->map->name ? head->map->name : "<no map name>") : "<no map!>", head->x, head->y);
01052         return 0;
01053     }
01054 
01055     /* Monster doesn't have enough spellpoints */
01056     if (head->stats.sp < SP_level_spellpoint_cost(head, sp_typ, -1))
01057     {
01058         return 0;
01059     }
01060 
01061     /* Spell should be cast on caster (ie, heal, strength) */
01062     if (sp->flags & SPELL_DESC_SELF)
01063     {
01064         dir = 0;
01065 
01066         if (rv && !monster_spell_useful(head, sp_typ))
01067         {
01068             return 0;
01069         }
01070     }
01071 
01072     if (!rv)
01073     {
01074         int i, j, xt, yt;
01075         object *tmp;
01076         mapstruct *m;
01077 
01078         for (i = -sp->range; !target && i <= sp->range; i++)
01079         {
01080             for (j = -sp->range; !target && j <= sp->range; j++)
01081             {
01082                 xt = head->x + i;
01083                 yt = head->y + j;
01084 
01085                 if (!(m = get_map_from_coord2(head->map, &xt, &yt)))
01086                 {
01087                     continue;
01088                 }
01089 
01090                 /* Nothing alive here? Move on... */
01091                 if (!(GET_MAP_FLAGS(m, xt, yt) & (P_IS_ALIVE | P_IS_PLAYER)))
01092                 {
01093                     continue;
01094                 }
01095 
01096                 for (tmp = GET_MAP_OB(m, xt, yt); tmp; tmp = tmp->above)
01097                 {
01098                     /* Get head. */
01099                     if (tmp->head)
01100                     {
01101                         tmp = tmp->head;
01102                     }
01103 
01104                     /* Skip the monster and not alive objects. */
01105                     if (tmp == head || !IS_LIVE(tmp))
01106                     {
01107                         continue;
01108                     }
01109 
01110                     if (is_friend_of(head, tmp) && monster_spell_useful(tmp, sp_typ))
01111                     {
01112                         target = tmp;
01113                         break;
01114                     }
01115                 }
01116             }
01117         }
01118 
01119         if (!target)
01120         {
01121             return 0;
01122         }
01123     }
01124 
01125     ability = (spell_item->type == ABILITY && QUERY_FLAG(spell_item, FLAG_IS_MAGICAL));
01126 
01127     head->stats.sp -= SP_level_spellpoint_cost(head, sp_typ, -1);
01128     /* Add default cast time from spell force to monster */
01129     head->last_grace += spell_item->last_grace;
01130 
01131     /* If we're casting this spell on another object, we need to adjust some
01132      * parameters accordingly... */
01133     if (target)
01134     {
01135         return cast_spell(target, part, dir, sp_typ, ability, CAST_NPC, NULL);
01136     }
01137 
01138     /* Otherwise a normal cast. */
01139     return cast_spell(part, part, dir, sp_typ, ability, CAST_NORMAL, NULL);
01140 }
01141 
01148 static int monster_use_bow(object *head, object *part, int dir)
01149 {
01150     object *bow, *arrow;
01151     int tag;
01152 
01153     for (bow = head->inv; bow != NULL; bow = bow->below)
01154     {
01155         if (bow->type == BOW && QUERY_FLAG(bow, FLAG_APPLIED))
01156         {
01157             break;
01158         }
01159     }
01160 
01161     if (bow == NULL)
01162     {
01163         LOG(llevBug, "Monster %s (%d) HAS_READY_BOW() without bow.\n", query_name(head, NULL), head->count);
01164         CLEAR_FLAG(head, FLAG_READY_BOW);
01165         return 0;
01166     }
01167 
01168     if ((arrow = find_arrow(head, bow->race)) == NULL)
01169     {
01170         /* Out of arrows */
01171         manual_apply(head, bow, 0);
01172         CLEAR_FLAG(head, FLAG_READY_BOW);
01173         return 0;
01174     }
01175 
01176     /* An infinite arrow, dupe it. */
01177     if (QUERY_FLAG(arrow, FLAG_SYS_OBJECT))
01178     {
01179         object *new_arrow = get_object();
01180         copy_object(arrow, new_arrow, 0);
01181         CLEAR_FLAG(new_arrow, FLAG_SYS_OBJECT);
01182         new_arrow->nrof = 0;
01183 
01184         /* Setup the self destruction */
01185         new_arrow->stats.food = 20;
01186         arrow = new_arrow;
01187     }
01188     else
01189     {
01190         arrow = get_split_ob(arrow, 1, NULL, 0);
01191     }
01192 
01193     set_owner(arrow, head);
01194     arrow->direction = dir;
01195     arrow->x = part->x, arrow->y = part->y;
01196     arrow->speed = 1;
01197     update_ob_speed(arrow);
01198     arrow->speed_left = 0;
01199     SET_ANIMATION(arrow, (NUM_ANIMATIONS(arrow) / NUM_FACINGS(arrow)) * dir);
01200     arrow->level = head->level;
01201     /* Save original wc and dam */
01202     arrow->last_heal = arrow->stats.wc;
01203     arrow->stats.hp = arrow->stats.dam;
01204     arrow->stats.dam += bow->stats.dam + bow->magic + arrow->magic;
01205     arrow->stats.dam = FABS((int) ((float) (arrow->stats.dam * LEVEL_DAMAGE(head->level))));
01206     arrow->stats.wc = 10 + (bow->magic + bow->stats.wc + arrow->magic + arrow->stats.wc + head->level);
01207     arrow->stats.wc_range = bow->stats.wc_range;
01208     arrow->map = head->map;
01209     /* We use fixed value for mobs */
01210     arrow->last_sp = 12;
01211     SET_FLAG(arrow, FLAG_FLYING);
01212     SET_FLAG(arrow, FLAG_IS_MISSILE);
01213     SET_FLAG(arrow, FLAG_FLY_ON);
01214     SET_FLAG(arrow, FLAG_WALK_ON);
01215     tag = arrow->count;
01216     arrow->stats.grace = arrow->last_sp;
01217     arrow->stats.maxgrace = 60 + (RANDOM() % 12);
01218     play_sound_map(arrow->map, CMD_SOUND_EFFECT, "throw.ogg", arrow->x, arrow->y, 0, 0);
01219 
01220     if (!insert_ob_in_map(arrow, head->map, head, 0))
01221     {
01222         return 1;
01223     }
01224 
01225     if (!was_destroyed(arrow, tag))
01226     {
01227         move_arrow(arrow);
01228     }
01229 
01230     return 1;
01231 }
01232 
01239 static int dist_att(int dir, object *part, rv_vector *rv)
01240 {
01241     if (can_hit(part, rv))
01242     {
01243         return dir;
01244     }
01245 
01246     if (rv->distance < 10)
01247     {
01248         return absdir(dir + 4);
01249     }
01250     else if (rv->distance > 18)
01251     {
01252         return dir;
01253     }
01254 
01255     return 0;
01256 }
01257 
01265 static int run_att(int dir, object *ob, object *part, rv_vector *rv)
01266 {
01267     if ((can_hit(part, rv) && ob->move_status < 20) || ob->move_status < 20)
01268     {
01269         ob->move_status++;
01270         return dir;
01271     }
01272     else if (ob->move_status > 20)
01273     {
01274         ob->move_status = 0;
01275     }
01276 
01277     return absdir(dir + 4);
01278 }
01279 
01285 static int hitrun_att(int dir, object *ob)
01286 {
01287     if (ob->move_status++ < 25)
01288     {
01289         return dir;
01290     }
01291     else if (ob->move_status < 50)
01292     {
01293         return absdir(dir + 4);
01294     }
01295     else
01296     {
01297         ob->move_status = 0;
01298     }
01299 
01300     return absdir(dir + 4);
01301 }
01302 
01310 static int wait_att(int dir, object *ob, object *part, rv_vector *rv)
01311 {
01312     if (ob->move_status || can_hit(part, rv))
01313     {
01314         ob->move_status++;
01315     }
01316 
01317     if (ob->move_status == 0)
01318     {
01319         return 0;
01320     }
01321     else if (ob->move_status < 10)
01322     {
01323         return dir;
01324     }
01325     else if (ob->move_status < 15)
01326     {
01327         return absdir(dir + 4);
01328     }
01329 
01330     ob->move_status = 0;
01331     return 0;
01332 }
01333 
01341 static int disthit_att(int dir, object *ob, object *part, rv_vector *rv)
01342 {
01343     if (ob->stats.maxhp && (ob->stats.hp * 100) / ob->stats.maxhp < ob->run_away)
01344     {
01345         return absdir(dir + 4);
01346     }
01347 
01348     return dist_att(dir, part, rv);
01349 }
01350 
01356 static int wait_att2(int dir, rv_vector *rv)
01357 {
01358     if (rv->distance < 9)
01359     {
01360         return absdir(dir + 4);
01361     }
01362 
01363     return 0;
01364 }
01365 
01369 static void circ1_move(object *ob)
01370 {
01371     static const int circle[12] = {3, 3, 4, 5, 5, 6, 7, 7, 8, 1, 1, 2};
01372 
01373     if (++ob->move_status > 11)
01374     {
01375         ob->move_status = 0;
01376     }
01377 
01378     if (!(move_object(ob, circle[ob->move_status])))
01379     {
01380         move_object(ob, rndm(1, 8));
01381     }
01382 }
01383 
01387 static void circ2_move(object *ob)
01388 {
01389     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};
01390 
01391     if (++ob->move_status > 19)
01392     {
01393         ob->move_status = 0;
01394     }
01395 
01396     if (!(move_object(ob, circle[ob->move_status])))
01397     {
01398         move_object(ob, rndm(1, 8));
01399     }
01400 }
01401 
01405 static void pace_movev(object *ob)
01406 {
01407     if (ob->move_status++ > 6)
01408     {
01409         ob->move_status = 0;
01410     }
01411 
01412     if (ob->move_status < 4)
01413     {
01414         move_object(ob, 5);
01415     }
01416     else
01417     {
01418         move_object(ob, 1);
01419     }
01420 }
01421 
01425 static void pace_moveh(object *ob)
01426 {
01427     if (ob->move_status++ > 6)
01428     {
01429         ob->move_status = 0;
01430     }
01431 
01432     if (ob->move_status < 4)
01433     {
01434         move_object(ob, 3);
01435     }
01436     else
01437     {
01438         move_object(ob, 7);
01439     }
01440 }
01441 
01445 static void pace2_movev(object *ob)
01446 {
01447     if (ob->move_status++ > 16)
01448     {
01449         ob->move_status = 0;
01450     }
01451 
01452     if (ob->move_status < 6)
01453     {
01454         move_object(ob, 5);
01455     }
01456     else if (ob->move_status < 8)
01457     {
01458         return;
01459     }
01460     else if (ob->move_status < 13)
01461     {
01462         move_object(ob, 1);
01463     }
01464 }
01465 
01469 static void pace2_moveh(object *ob)
01470 {
01471     if (ob->move_status++ > 16)
01472     {
01473         ob->move_status = 0;
01474     }
01475 
01476     if (ob->move_status < 6)
01477     {
01478         move_object(ob, 3);
01479     }
01480     else if (ob->move_status < 8)
01481     {
01482         return;
01483     }
01484     else if (ob->move_status < 13)
01485     {
01486         move_object(ob, 7);
01487     }
01488 }
01489 
01493 static void rand_move(object *ob)
01494 {
01495     int i;
01496 
01497     if (ob->move_status < 1 || ob->move_status > 8 || !(move_object(ob, ob->move_status || rndm_chance(9))))
01498     {
01499         for (i = 0; i < 5; i++)
01500         {
01501             if (move_object(ob, ob->move_status = rndm(1, 8)))
01502             {
01503                 return;
01504             }
01505         }
01506     }
01507 }
01508 
01513 void communicate(object *op, char *txt)
01514 {
01515     object *npc;
01516     mapstruct *m;
01517     int i, xt, yt;
01518     char buf[HUGE_BUF];
01519 
01520     if (!txt)
01521     {
01522         return;
01523     }
01524 
01525     /* Makes it possible to do something like this in Python:
01526      * monster.Communicate("/dance") */
01527     if (*txt == '/' && op->type != PLAYER)
01528     {
01529         CommArray_s *csp;
01530         char *cp;
01531 
01532         /* Sanity check: all commands must begin with a slash, and there must be
01533          * something else after the slash. */
01534         if (txt[0] != '/' || !txt[1])
01535         {
01536             LOG(llevBug, "communicate(): %s attempted an illegal command '%s'.\n", op->name, txt);
01537             return;
01538         }
01539 
01540         /* Jump over the slash. */
01541         txt++;
01542 
01543         /* Remove the command from the parameters. */
01544         cp = strchr(txt, ' ');
01545 
01546         if (cp)
01547         {
01548             *(cp++) = '\0';
01549             cp = cleanup_string(cp);
01550 
01551             if (cp && *cp == '\0')
01552             {
01553                 cp = NULL;
01554             }
01555         }
01556 
01557         csp = find_command_element(txt, CommunicationCommands, CommunicationCommandSize);
01558 
01559         if (csp)
01560         {
01561             csp->func(op, cp);
01562             return;
01563         }
01564 
01565         return;
01566     }
01567 
01568     snprintf(buf, sizeof(buf), "%s says: %s", query_name(op, NULL), txt);
01569 
01570     if (op->type == PLAYER)
01571     {
01572         new_info_map(NDI_PLAYER | NDI_SAY, COLOR_WHITE, op->map, op->x, op->y, MAP_INFO_NORMAL, buf);
01573     }
01574     else
01575     {
01576         new_info_map(0, COLOR_WHITE, op->map, op->x, op->y, MAP_INFO_NORMAL, buf);
01577     }
01578 
01579     for (i = 0; i <= SIZEOFFREE2; i++)
01580     {
01581         xt = op->x + freearr_x[i];
01582         yt = op->y + freearr_y[i];
01583 
01584         if (!(m = get_map_from_coord(op->map, &xt, &yt)))
01585         {
01586             continue;
01587         }
01588 
01589         /* Check to see if we have magic ear or monster here. */
01590         if (!(GET_MAP_FLAGS(m, xt, yt) & (P_MAGIC_EAR | P_IS_ALIVE)))
01591         {
01592             continue;
01593         }
01594 
01595         for (npc = get_map_ob(m, xt, yt); npc; npc = npc->above)
01596         {
01597             /* Avoid talking to self. */
01598             if (op != npc)
01599             {
01600                 /* The ear. */
01601                 if (npc->type == MAGIC_EAR)
01602                 {
01603                     talk_to_wall(op, npc, txt);
01604                 }
01605                 else if (QUERY_FLAG(npc, FLAG_ALIVE))
01606                 {
01607                     talk_to_npc(op, npc, txt);
01608                 }
01609             }
01610         }
01611     }
01612 }
01613 
01621 static char *find_matching_message(const char *msg, const char *match)
01622 {
01623     const char *cp = msg, *cp1, *cp2;
01624     char regex[MAX_BUF], *cp3;
01625     int gotmatch = 0;
01626 
01627     while (1)
01628     {
01629         if (strncmp(cp, "@match ", 7))
01630         {
01631             LOG(llevDebug, "find_matching_message(): Invalid message: %s\n", msg);
01632             return NULL;
01633         }
01634         else
01635         {
01636             /* Find the end of the line, and copy the regex portion into it */
01637             cp2 = strchr(cp + 7, '\n');
01638 
01639             if (!cp2)
01640             {
01641                 LOG(llevDebug, "find_matching_message(): Found empty match response: %s\n", msg);
01642                 return NULL;
01643             }
01644 
01645             strncpy(regex, cp + 7, (cp2 - cp - 7));
01646             regex[cp2 - cp - 7] = '\0';
01647 
01648             /* Find the next match command */
01649             cp1 = strstr(cp + 6, "\n@match");
01650 
01651             /* Got a match - handle * as special case. */
01652             if (regex[0] == '*')
01653             {
01654                 gotmatch = 1;
01655             }
01656             else
01657             {
01658                 char *pipe_sep, *pnext = NULL;
01659 
01660                 /* Need to parse all the | separators.  Our re_cmp isn't
01661                  * really a fully blown regex parser. */
01662                 for (pipe_sep = regex; pipe_sep; pipe_sep = pnext)
01663                 {
01664                     pnext = strchr(pipe_sep, '|');
01665 
01666                     if (pnext)
01667                     {
01668                         *pnext = '\0';
01669                         pnext ++;
01670                     }
01671 
01672                     if (re_cmp(match, pipe_sep))
01673                     {
01674                         gotmatch = 1;
01675                         break;
01676                     }
01677                 }
01678             }
01679 
01680             if (gotmatch)
01681             {
01682                 if (cp1)
01683                 {
01684                     cp3 = malloc(cp1 - cp2 + 1);
01685                     strncpy(cp3, cp2 + 1, cp1 - cp2);
01686                     cp3[cp1 - cp2 - 1] = '\0';
01687                 }
01688                 /* If no next match, just want the rest of the string */
01689                 else
01690                 {
01691                     cp3 = strdup_local(cp2 + 1);
01692                 }
01693 
01694                 return cp3;
01695             }
01696 
01697             gotmatch = 0;
01698 
01699             if (cp1)
01700             {
01701                 cp = cp1 + 1;
01702             }
01703             else
01704             {
01705                 return NULL;
01706             }
01707         }
01708     }
01709 }
01710 
01720 int talk_to_npc(object *op, object *npc, char *txt)
01721 {
01722     object *cobj;
01723     char *cp;
01724 
01725     if (HAS_EVENT(npc, EVENT_SAY))
01726     {
01727         /* Trigger the SAY event */
01728         trigger_event(EVENT_SAY, op, npc, NULL, txt, 0, 0, 0, SCRIPT_FIX_ACTIVATOR);
01729         return 0;
01730     }
01731 
01732     /* Here we let the objects inside inventories hear and answer, too.
01733      * This allows the existence of "intelligent" weapons you can discuss
01734      * with. */
01735     for (cobj = npc->inv; cobj; cobj = cobj->below)
01736     {
01737         if (HAS_EVENT(cobj, EVENT_SAY))
01738         {
01739             /* Trigger the SAY event */
01740             trigger_event(EVENT_SAY, op, cobj, npc, txt, 0, 0, 0, SCRIPT_FIX_ACTIVATOR);
01741             return 0;
01742         }
01743     }
01744 
01745     if (!npc->msg || *npc->msg != '@')
01746     {
01747         return 0;
01748     }
01749 
01750     cp = find_matching_message(npc->msg, txt);
01751 
01752     if (cp)
01753     {
01754         char buf[MAX_BUF];
01755 
01756         if (op->type == PLAYER)
01757         {
01758             new_draw_info_format(0, COLOR_NAVY, op, "\n%s says:\n%s", query_name(npc, NULL), cp);
01759             snprintf(buf, sizeof(buf), "%s talks to %s.", query_name(npc, NULL), query_name(op, NULL));
01760             new_info_map_except(0, COLOR_WHITE, op->map, op->x, op->y, MAP_INFO_NORMAL, op, op, buf);
01761         }
01762         else
01763         {
01764             snprintf(buf, sizeof(buf), "\n%s says: %s", query_name(npc, NULL), cp);
01765             new_info_map_except(0, COLOR_WHITE, op->map, op->x, op->y, MAP_INFO_NORMAL, op, op, buf);
01766         }
01767 
01768         free(cp);
01769 
01770         return 1;
01771     }
01772 
01773     return 0;
01774 }
01775 
01782 static int talk_to_wall(object *op, object *npc, char *txt)
01783 {
01784     char *cp;
01785 
01786     if (!npc->msg || *npc->msg != '@')
01787     {
01788         return 0;
01789     }
01790 
01791     cp = find_matching_message(npc->msg, txt);
01792 
01793     if (!cp)
01794     {
01795         return 0;
01796     }
01797 
01798     if (QUERY_FLAG(npc, FLAG_XRAYS))
01799     {
01800         new_info_map(0, COLOR_NAVY, npc->map, npc->x, npc->y, MAP_INFO_NORMAL, cp);
01801     }
01802     else
01803     {
01804         new_draw_info(0, COLOR_NAVY, op, cp);
01805     }
01806 
01807     use_trigger(npc);
01808     free(cp);
01809 
01810     return 1;
01811 }
01812 
01820 int faction_is_friend_of(object *mon, object *pl)
01821 {
01822     shstr *faction, *faction_rep;
01823     sint64 pl_rep, rep;
01824 
01825     faction = object_get_value(mon, "faction");
01826 
01827     if (!faction)
01828     {
01829         return -1;
01830     }
01831 
01832     faction_rep = object_get_value(mon, "faction_rep");
01833 
01834     if (!faction_rep)
01835     {
01836         return -1;
01837     }
01838 
01839     rep = atoll(faction_rep);
01840     pl_rep = player_faction_reputation(CONTR(pl), faction);
01841 
01842     if (rep < 0)
01843     {
01844         return pl_rep <= rep ? 0 : -1;
01845     }
01846     else if (rep > 0)
01847     {
01848         return pl_rep >= rep ? 1 : -1;
01849     }
01850 
01851     return -1;
01852 }
01853 
01859 int is_friend_of(object *op, object *obj)
01860 {
01861     uint8 friend = 0;
01862     sint8 faction_friend = -1;
01863 
01864     /* We are obviously friends with ourselves. */
01865     if (op == obj)
01866     {
01867         return 1;
01868     }
01869 
01870     /* TODO: Add a few other odd types here, such as god and golem */
01871     if (!obj->type == PLAYER || !obj->type == MONSTER || !op->type == PLAYER || !op->type == MONSTER)
01872     {
01873         return 0;
01874     }
01875 
01876     /* Berserk */
01877     if (QUERY_FLAG(op, FLAG_BERSERK))
01878     {
01879         return 0;
01880     }
01881 
01882     /* If on PVP area, they won't be friendly */
01883     if (pvp_area(op, obj))
01884     {
01885         return 0;
01886     }
01887 
01888     if ((op->type == MONSTER && op->enemy && OBJECT_VALID(op->enemy, op->enemy_count) && obj == op->enemy) || (obj->type == MONSTER && obj->enemy && OBJECT_VALID(obj->enemy, obj->enemy_count) && op == obj->enemy))
01889     {
01890         return 0;
01891     }
01892 
01893     if (QUERY_FLAG(op, FLAG_FRIENDLY) || op->type == PLAYER)
01894     {
01895         if (!QUERY_FLAG(obj, FLAG_MONSTER) || QUERY_FLAG(obj, FLAG_FRIENDLY) || obj->type == PLAYER)
01896         {
01897             friend = 1;
01898         }
01899     }
01900     else
01901     {
01902         if (!QUERY_FLAG(obj, FLAG_FRIENDLY) && obj->type != PLAYER)
01903         {
01904             friend = 1;
01905         }
01906     }
01907 
01908     /* Check factions. */
01909     if (op->type == PLAYER)
01910     {
01911         faction_friend = faction_is_friend_of(obj, op);
01912     }
01913     else if (obj->type == PLAYER)
01914     {
01915         faction_friend = faction_is_friend_of(op, obj);
01916     }
01917 
01918     if (faction_friend != -1)
01919     {
01920         friend = faction_friend;
01921     }
01922 
01923     return friend;
01924 }
01925 
01931 int check_good_weapon(object *who, object *item)
01932 {
01933     object *other_weap;
01934     int val = 0, i;
01935 
01936     /* Cursed or damned; never better. */
01937     if (QUERY_FLAG(item, FLAG_CURSED) || QUERY_FLAG(item, FLAG_DAMNED))
01938     {
01939         return 0;
01940     }
01941 
01942     for (other_weap = who->inv; other_weap; other_weap = other_weap->below)
01943     {
01944         if (other_weap->type == item->type && QUERY_FLAG(other_weap, FLAG_APPLIED))
01945         {
01946             break;
01947         }
01948     }
01949 
01950     /* No other weapons */
01951     if (other_weap == NULL)
01952     {
01953         return 1;
01954     }
01955 
01956     val = item->stats.dam - other_weap->stats.dam;
01957     val += (item->magic - other_weap->magic) * 3;
01958 
01959     /* Monsters don't really get benefits from things like regen rates
01960      * from items. But the bonus for their stats are very important. */
01961     for (i = 0; i < NUM_STATS; i++)
01962     {
01963         val += (get_attr_value(&item->stats, i) - get_attr_value(&other_weap->stats, i)) * 2;
01964     }
01965 
01966     if (val > 0)
01967     {
01968         CLEAR_FLAG(other_weap, FLAG_APPLIED);
01969         return 1;
01970     }
01971 
01972     return 0;
01973 }
01974 
01980 int check_good_armour(object *who, object *item)
01981 {
01982     object *other_armour;
01983     int val = 0, i;
01984 
01985     /* Cursed or damned; never better. */
01986     if (QUERY_FLAG(item, FLAG_CURSED) || QUERY_FLAG(item, FLAG_DAMNED))
01987     {
01988         return 0;
01989     }
01990 
01991     for (other_armour = who->inv; other_armour; other_armour = other_armour->below)
01992     {
01993         if (other_armour->type == item->type && QUERY_FLAG(other_armour, FLAG_APPLIED))
01994         {
01995             break;
01996         }
01997     }
01998 
01999     /* No other armour, use the new */
02000     if (other_armour == NULL)
02001     {
02002         return 1;
02003     }
02004 
02005     /* See which is better */
02006     val = item->stats.ac - other_armour->stats.ac;
02007     val += (item->magic - other_armour->magic) * 3;
02008 
02009     for (i = 0; i < NROFATTACKS; i++)
02010     {
02011         if (item->protection[i] > other_armour->protection[i])
02012         {
02013             val++;
02014         }
02015         else if (item->protection[i] < other_armour->protection[i])
02016         {
02017             val--;
02018         }
02019     }
02020 
02021     if (val > 0)
02022     {
02023         CLEAR_FLAG(other_armour, FLAG_APPLIED);
02024         return 1;
02025     }
02026 
02027     return 0;
02028 }