Atrinik Server 2.5
server/living.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 
00031 #include <global.h>
00032 
00034 #define ENCUMBRANCE_LIMIT 65.0f
00035 
00038 int dam_bonus[MAX_STAT + 1] =
00039 {
00040     -5, -4, -4, -3, -3, -3, -2, -2, -2, -1, -1,
00041     0, 0, 0, 0, 0,
00042     1, 1, 2, 2, 3, 3, 3, 4, 4, 5, 6, 7, 8, 10, 12
00043 };
00044 
00046 int thaco_bonus[MAX_STAT + 1] =
00047 {
00048     -5, -4, -4, -3, -3, -3, -2, -2, -2, -1, -1,
00049     0, 0, 0, 0, 0,
00050     1, 1, 2, 2, 3, 3, 3, 4, 4, 5, 5, 5, 6, 7, 8
00051 };
00052 
00055 static float con_bonus[MAX_STAT + 1] =
00056 {
00057     -0.8f, -0.6f, -0.5f, -0.4f, -0.35f, -0.3f, -0.25f, -0.2f, -0.15f, -0.11f, -0.07f,
00058     0.0f, 0.0f, 0.0f, 0.0f, 0.0f,
00059     0.1f, 0.15f, 0.2f, 0.25f, 0.3f, 0.35f, 0.4f, 0.45f, 0.5f, 0.55f, 0.6f, 0.7f, 0.8f, 0.9f, 1.0f
00060 };
00061 
00064 static float pow_bonus[MAX_STAT + 1] =
00065 {
00066     -0.8f, -0.6f, -0.5f, -0.4f, -0.35f, -0.3f, -0.25f, -0.2f, -0.15f, -0.11f, -0.07f,
00067     0.0f, 0.0f, 0.0f, 0.0f, 0.0f,
00068     0.1f, 0.2f, 0.3f, 0.4f, 0.5f, 0.6f, 0.7f, 0.8f, 0.9f, 1.0f, 1.1f, 1.4f, 1.6f, 1.8f, 2.0f
00069 };
00070 
00073 static float wis_bonus[MAX_STAT + 1] =
00074 {
00075     -0.8f, -0.6f, -0.5f, -0.4f, -0.35f, -0.3f, -0.25f, -0.2f, -0.15f, -0.11f, -0.07f,
00076     0.0f, 0.0f, 0.0f, 0.0f, 0.0f,
00077     0.1f, 0.2f, 0.3f, 0.4f, 0.5f, 0.6f, 0.7f, 0.8f, 0.9f, 1.0f, 1.1f, 1.4f, 1.6f, 1.8f, 2.0f
00078 };
00079 
00089 float cha_bonus[MAX_STAT + 1] =
00090 {
00091     -0.15f,
00092     -0.10f, -0.08f,-0.05f, -0.03f, -0.02f,
00093     -0.01f, -0.005f, -0.003f, -0.001f, 0.0f,
00094     0.0f, 0.0f, 0.0f, 0.005f, 0.010f,
00095     0.015f, 0.02f, 0.025f, 0.03f, 0.035f,
00096     0.04f, 0.045f, 0.05f, 0.055f, 0.06f,
00097     0.065f, 0.07f, 0.08f, 0.09f, 0.1f
00098 };
00099 
00102 float speed_bonus[MAX_STAT + 1] =
00103 {
00104     -0.4f, -0.4f, -0.3f, -0.3f, -0.2f,
00105     -0.2f, -0.2f, -0.1f, -0.1f, -0.1f,
00106     -0.05f, 0.0, 0.0f, 0.0f, 0.025f, 0.05f,
00107     0.075f, 0.1f, 0.125f, 0.15f, 0.175f, 0.2f,
00108     0.225f, 0.25f, 0.275f, 0.3f,
00109     0.325f, 0.35f, 0.4f, 0.45f, 0.5f
00110 };
00111 
00120 uint32 weight_limit[MAX_STAT + 1] =
00121 {
00122     20000,
00123     25000,  30000,  35000,  40000,  50000,
00124     60000,  70000,  80000,  90000,  100000,
00125     110000, 120000, 130000, 140000, 150000,
00126     165000, 180000, 195000, 210000, 225000,
00127     240000, 255000, 270000, 285000, 300000,
00128     325000, 350000, 375000, 400000, 450000
00129 };
00130 
00134 int learn_spell[MAX_STAT + 1] =
00135 {
00136     0, 0, 0, 1, 2, 4, 8, 12, 16, 25, 36, 45, 55, 65, 70, 75, 80, 85, 90, 95, 100, 100, 100, 100, 100,
00137     100, 100, 100, 100, 100, 100
00138 };
00139 
00142 int cleric_chance[MAX_STAT + 1] =
00143 {
00144     100, 100, 100, 100, 90,
00145     80, 70, 60, 50, 40,
00146     30, 20, 10, 9, 8,
00147     7, 6, 5, 4, 3,
00148     2, 1, 0, 0, 0,
00149     0, 0, 0, 0, 0,
00150     0
00151 };
00152 
00155 int savethrow[MAXLEVEL + 1] =
00156 {
00157     18,
00158     18, 17, 16, 15, 14, 14, 13, 13, 12, 12, 12, 11, 11, 11, 11, 10, 10, 10, 10, 9,
00159     9, 9, 9, 9, 8, 8, 8, 8, 8, 8, 7, 7, 7, 7, 7, 7, 7, 6, 6, 6,
00160     6, 6, 6, 6, 6, 5, 5, 5, 5, 5, 5, 5, 5, 5, 4, 4, 4, 4, 4, 4,
00161     4, 4, 4, 4, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 2, 2, 2, 2, 2,
00162     2, 2, 2, 2, 2, 2, 2, 2, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
00163     1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1
00164 };
00165 
00167 static const char *const drain_msg[NUM_STATS] =
00168 {
00169     "Oh no! You are weakened!",
00170     "You're feeling clumsy!",
00171     "You feel less healthy",
00172     "You suddenly begin to lose your memory!",
00173     "Your face gets distorted!",
00174     "Watch out, your mind is going!",
00175     "Your spirit feels drained!"
00176 };
00177 
00179 const char *const restore_msg[NUM_STATS] =
00180 {
00181     "You feel your strength return.",
00182     "You feel your agility return.",
00183     "You feel your health return.",
00184     "You feel your wisdom return.",
00185     "You feel your charisma return.",
00186     "You feel your memory return.",
00187     "You feel your spirits return."
00188 };
00189 
00191 static const char *const gain_msg[NUM_STATS] =
00192 {
00193     "You feel stronger.",
00194     "You feel more agile.",
00195     "You feel healthy.",
00196     "You feel wiser.",
00197     "You seem to look better.",
00198     "You feel smarter.",
00199     "You feel more potent."
00200 };
00201 
00203 const char *const lose_msg[NUM_STATS] =
00204 {
00205     "You feel weaker!",
00206     "You feel clumsy!",
00207     "You feel less healthy!",
00208     "You lose some of your memory!",
00209     "You look ugly!",
00210     "You feel stupid!",
00211     "You feel less potent!"
00212 };
00213 
00215 const char *const statname[NUM_STATS] =
00216 {
00217     "strength",
00218     "dexterity",
00219     "constitution",
00220     "wisdom",
00221     "charisma",
00222     "intelligence",
00223     "power"
00224 };
00225 
00227 const char *const short_stat_name[NUM_STATS] =
00228 {
00229     "Str",
00230     "Dex",
00231     "Con",
00232     "Wis",
00233     "Cha",
00234     "Int",
00235     "Pow"
00236 };
00237 
00244 void set_attr_value(living *stats, int attr, sint8 value)
00245 {
00246     switch (attr)
00247     {
00248         case STR:
00249             stats->Str = value;
00250             break;
00251 
00252         case DEX:
00253             stats->Dex = value;
00254             break;
00255 
00256         case CON:
00257             stats->Con = value;
00258             break;
00259 
00260         case WIS:
00261             stats->Wis = value;
00262             break;
00263 
00264         case POW:
00265             stats->Pow = value;
00266             break;
00267 
00268         case CHA:
00269             stats->Cha = value;
00270             break;
00271 
00272         case INT:
00273             stats->Int = value;
00274             break;
00275     }
00276 }
00277 
00287 void change_attr_value(living *stats, int attr, sint8 value)
00288 {
00289     sint16 result;
00290 
00291     if (value == 0)
00292     {
00293         return;
00294     }
00295 
00296     result = get_attr_value(stats, attr) + value;
00297 
00298     /* Prevent possible overflow of the stat. */
00299     if (result > SINT8_MAX || result < SINT8_MIN)
00300     {
00301         return;
00302     }
00303 
00304     set_attr_value(stats, attr, result);
00305 }
00306 
00313 sint8 get_attr_value(living *stats, int attr)
00314 {
00315     switch (attr)
00316     {
00317         case STR:
00318             return stats->Str;
00319 
00320         case DEX:
00321             return stats->Dex;
00322 
00323         case CON:
00324             return stats->Con;
00325 
00326         case WIS:
00327             return stats->Wis;
00328 
00329         case CHA:
00330             return stats->Cha;
00331 
00332         case INT:
00333             return stats->Int;
00334 
00335         case POW:
00336             return stats->Pow;
00337     }
00338 
00339     return 0;
00340 }
00341 
00346 void check_stat_bounds(living *stats)
00347 {
00348     int i, v;
00349 
00350     for (i = 0; i < NUM_STATS; i++)
00351     {
00352         v = get_attr_value(stats, i);
00353 
00354         if (v > MAX_STAT)
00355         {
00356             set_attr_value(stats, i, MAX_STAT);
00357         }
00358         else if (v < MIN_STAT)
00359         {
00360             set_attr_value(stats, i, MIN_STAT);
00361         }
00362     }
00363 }
00364 
00373 int change_abil(object *op, object *tmp)
00374 {
00375     int flag = QUERY_FLAG(tmp, FLAG_APPLIED) ? 1 : -1, i, j, success = 0;
00376     object refop;
00377     int potion_max = 0;
00378 
00379     /* Remember what object was like before it was changed. Note that
00380      * refop is a local copy of op only to be used for detecting changes
00381      * found by fix_player. refop is not a real object. */
00382     memcpy(&refop, op, sizeof(object));
00383 
00384     if (op->type == PLAYER)
00385     {
00386         if (tmp->type == POTION)
00387         {
00388             for (j = 0; j < NUM_STATS; j++)
00389             {
00390                 i = get_attr_value(&(CONTR(op)->orig_stats), j);
00391 
00392                 /* Check to see if stats are within limits such that this can be
00393                  * applied. */
00394                 if (((i + flag * get_attr_value(&(tmp->stats), j)) <= (20 + tmp->stats.sp + get_attr_value(&(op->arch->clone.stats), j))) && i > 0)
00395                 {
00396                     change_attr_value(&(CONTR(op)->orig_stats), j, (sint8) (flag * get_attr_value(&(tmp->stats), j)));
00397                     /* Fix it up for super potions */
00398                     tmp->stats.sp = 0;
00399                 }
00400                 else
00401                 {
00402                     /* Potion is useless - player has already hit the natural maximum */
00403                     potion_max = 1;
00404                 }
00405             }
00406 
00407             /* This section of code ups the characters normal stats also.  I am not
00408              * sure if this is strictly necessary, being that fix_player probably
00409              * recalculates this anyway. */
00410             for (j = 0; j < NUM_STATS; j++)
00411             {
00412                 change_attr_value(&(op->stats), j, (sint8) (flag * get_attr_value(&(tmp->stats), j)));
00413             }
00414 
00415             check_stat_bounds(&(op->stats));
00416         }
00417     }
00418 
00419     /* Reset attributes that fix_player doesn't reset since it doesn't search
00420      * everything to set */
00421     if (flag == -1)
00422     {
00423         op->path_attuned &= ~tmp->path_attuned, op->path_repelled &= ~tmp->path_repelled, op->path_denied &= ~tmp->path_denied;
00424     }
00425 
00426     /* call fix_player since op object could have whatever attribute due
00427      * to multiple items.  if fix_player always has to be called after
00428      * change_ability then might as well call it from here */
00429     fix_player(op);
00430 
00431     if (tmp->attack[ATNR_CONFUSION])
00432     {
00433         success = 1;
00434 
00435         if (flag > 0)
00436         {
00437             new_draw_info(0, COLOR_WHITE, op, "Your hands begin to glow red.");
00438         }
00439         else
00440         {
00441             new_draw_info(0, COLOR_GRAY, op, "Your hands stop glowing red.");
00442         }
00443     }
00444 
00445     if (QUERY_FLAG(op, FLAG_LIFESAVE) != QUERY_FLAG(&refop, FLAG_LIFESAVE))
00446     {
00447         success = 1;
00448 
00449         if (flag > 0)
00450         {
00451             new_draw_info(0, COLOR_WHITE, op, "You feel very protected.");
00452         }
00453         else
00454         {
00455             new_draw_info(0, COLOR_GRAY, op, "You don't feel protected anymore.");
00456         }
00457     }
00458 
00459     if (QUERY_FLAG(op, FLAG_REFL_MISSILE) != QUERY_FLAG(&refop, FLAG_REFL_MISSILE))
00460     {
00461         success = 1;
00462 
00463         if (flag > 0)
00464         {
00465             new_draw_info(0, COLOR_WHITE, op, "A magic force shimmers around you.");
00466         }
00467         else
00468         {
00469             new_draw_info(0, COLOR_GRAY, op, "The magic force fades away.");
00470         }
00471     }
00472 
00473     if (QUERY_FLAG(op, FLAG_REFL_SPELL) != QUERY_FLAG(&refop, FLAG_REFL_SPELL))
00474     {
00475         success = 1;
00476 
00477         if (flag > 0)
00478         {
00479             new_draw_info(0, COLOR_WHITE, op, "You feel more safe now, somehow.");
00480         }
00481         else
00482         {
00483             new_draw_info(0, COLOR_GRAY, op, "Suddenly you feel less safe, somehow.");
00484         }
00485     }
00486 
00487     if (QUERY_FLAG(tmp, FLAG_FLYING))
00488     {
00489         if (flag > 0)
00490         {
00491             success = 1;
00492 
00493             /* If we're already flying then fly higher */
00494             if (QUERY_FLAG(op, FLAG_FLYING) == QUERY_FLAG(&refop, FLAG_FLYING))
00495             {
00496                 new_draw_info(0, COLOR_WHITE, op, "You float a little higher in the air.");
00497             }
00498             else
00499             {
00500                 new_draw_info(0, COLOR_GRAY, op, "You start to float in the air!");
00501 
00502                 SET_MULTI_FLAG(op, FLAG_FLYING);
00503 
00504                 if (op->speed > 1)
00505                 {
00506                     op->speed = 1;
00507                 }
00508             }
00509         }
00510         else
00511         {
00512             success = 1;
00513 
00514             /* If we're already flying then fly lower */
00515             if (QUERY_FLAG(op, FLAG_FLYING) == QUERY_FLAG(&refop, FLAG_FLYING))
00516             {
00517                 new_draw_info(0, COLOR_WHITE, op, "You float a little lower in the air.");
00518             }
00519             else
00520             {
00521                 new_draw_info(0, COLOR_GRAY, op, "You float down to the ground.");
00522                 check_walk_on(op, op, 0);
00523             }
00524         }
00525     }
00526 
00527     /* Becoming UNDEAD... a special treatment for this flag. Only those not
00528      * originally undead may change their status */
00529     if (!QUERY_FLAG(&op->arch->clone, FLAG_UNDEAD))
00530     {
00531         if (QUERY_FLAG(op, FLAG_UNDEAD) != QUERY_FLAG(&refop, FLAG_UNDEAD))
00532         {
00533             success = 1;
00534 
00535             if (flag > 0)
00536             {
00537                 FREE_AND_COPY_HASH(op->race, "undead");
00538                 new_draw_info(0, COLOR_GRAY, op, "Your lifeforce drains away!");
00539             }
00540             else
00541             {
00542                 FREE_AND_CLEAR_HASH(op->race);
00543 
00544                 if (op->arch->clone.race)
00545                 {
00546                     FREE_AND_COPY_HASH(op->race, op->arch->clone.race);
00547                 }
00548 
00549                 new_draw_info(0, COLOR_WHITE, op, "Your lifeforce returns!");
00550             }
00551         }
00552     }
00553 
00554     if (QUERY_FLAG(op, FLAG_STEALTH) != QUERY_FLAG(&refop, FLAG_STEALTH))
00555     {
00556         success = 1;
00557 
00558         if (flag > 0)
00559         {
00560             new_draw_info(0, COLOR_WHITE, op, "You walk more quietly.");
00561         }
00562         else
00563         {
00564             new_draw_info(0, COLOR_GRAY, op, "You walk more noisily.");
00565         }
00566     }
00567 
00568     if (QUERY_FLAG(op, FLAG_SEE_INVISIBLE) != QUERY_FLAG(&refop, FLAG_SEE_INVISIBLE))
00569     {
00570         success = 1;
00571 
00572         if (flag > 0)
00573         {
00574             new_draw_info(0, COLOR_WHITE, op, "You see invisible things.");
00575         }
00576         else
00577         {
00578             new_draw_info(0, COLOR_GRAY, op, "Your vision becomes less clear.");
00579         }
00580     }
00581 
00582     if (QUERY_FLAG(op, FLAG_IS_INVISIBLE) != QUERY_FLAG(&refop, FLAG_IS_INVISIBLE))
00583     {
00584         success = 1;
00585 
00586         if (flag > 0)
00587         {
00588             new_draw_info(0, COLOR_WHITE, op, "You become transparent.");
00589         }
00590         else
00591         {
00592             new_draw_info(0, COLOR_GRAY, op, "You can see yourself.");
00593         }
00594     }
00595 
00596     /* Blinded you can tell if more blinded since blinded player has minimal
00597      * vision */
00598     if (QUERY_FLAG(tmp, FLAG_BLIND))
00599     {
00600         success = 1;
00601 
00602         if (flag > 0)
00603         {
00604             if (QUERY_FLAG(op, FLAG_WIZ))
00605             {
00606                 new_draw_info(0, COLOR_GRAY, op, "Your mortal self is blinded.");
00607             }
00608             else
00609             {
00610                 new_draw_info(0, COLOR_GRAY, op, "You are blinded.");
00611                 SET_FLAG(op, FLAG_BLIND);
00612 
00613                 if (op->type == PLAYER)
00614                 {
00615                     CONTR(op)->update_los = 1;
00616                 }
00617             }
00618         }
00619         else
00620         {
00621             if (QUERY_FLAG(op, FLAG_WIZ))
00622             {
00623                 new_draw_info(0, COLOR_WHITE, op, "Your mortal self can now see again.");
00624             }
00625             else
00626             {
00627                 new_draw_info(0, COLOR_WHITE, op, "Your vision returns.");
00628                 CLEAR_FLAG(op, FLAG_BLIND);
00629 
00630                 if (op->type == PLAYER)
00631                 {
00632                     CONTR(op)->update_los = 1;
00633                 }
00634             }
00635         }
00636     }
00637 
00638     if (QUERY_FLAG(op, FLAG_SEE_IN_DARK) != QUERY_FLAG(&refop, FLAG_SEE_IN_DARK))
00639     {
00640         success = 1;
00641 
00642         if (flag > 0)
00643         {
00644             new_draw_info(0, COLOR_WHITE, op, "Your vision is better in the dark.");
00645         }
00646         else
00647         {
00648             new_draw_info(0, COLOR_GRAY, op, "You see less well in the dark.");
00649         }
00650     }
00651 
00652     if (QUERY_FLAG(op, FLAG_XRAYS) != QUERY_FLAG(&refop, FLAG_XRAYS))
00653     {
00654         success = 1;
00655 
00656         if (flag > 0)
00657         {
00658             if (QUERY_FLAG(op, FLAG_WIZ))
00659             {
00660                 new_draw_info(0, COLOR_WHITE, op, "Your vision becomes a little clearer.");
00661             }
00662             else
00663             {
00664                 new_draw_info(0, COLOR_GRAY, op, "Everything becomes transparent.");
00665 
00666                 if (op->type == PLAYER)
00667                 {
00668                     CONTR(op)->update_los = 1;
00669                 }
00670             }
00671         }
00672         else
00673         {
00674             if (QUERY_FLAG(op, FLAG_WIZ))
00675             {
00676                 new_draw_info(0, COLOR_WHITE, op, "Your vision becomes a bit out of focus.");
00677             }
00678             else
00679             {
00680                 new_draw_info(0, COLOR_GRAY, op, "Everything suddenly looks very solid.");
00681 
00682                 if (op->type == PLAYER)
00683                 {
00684                     CONTR(op)->update_los = 1;
00685                 }
00686             }
00687         }
00688     }
00689 
00690     if ((tmp->stats.hp || tmp->stats.maxhp) && op->type == PLAYER)
00691     {
00692         success = 1;
00693 
00694         if ((flag * tmp->stats.hp) > 0 || (flag * tmp->stats.maxhp) > 0)
00695         {
00696             new_draw_info(0, COLOR_WHITE, op, "You feel much more healthy!");
00697         }
00698         else
00699         {
00700             new_draw_info(0, COLOR_GRAY, op, "You feel much less healthy!");
00701         }
00702     }
00703 
00704     if ((tmp->stats.sp || tmp->stats.maxsp) && op->type == PLAYER && tmp->type != SKILL)
00705     {
00706         success = 1;
00707 
00708         if ((flag * tmp->stats.sp) > 0 || (flag * tmp->stats.maxsp) > 0)
00709         {
00710             new_draw_info(0, COLOR_WHITE, op, "You feel one with the powers of magic!");
00711         }
00712         else
00713         {
00714             new_draw_info(0, COLOR_GRAY, op, "You suddenly feel very mundane.");
00715         }
00716     }
00717 
00718     if ((tmp->stats.grace || tmp->stats.maxgrace) && op->type == PLAYER)
00719     {
00720         success = 1;
00721 
00722         if ((flag * tmp->stats.grace) > 0 || (flag * tmp->stats.maxgrace) > 0)
00723         {
00724             new_draw_info(0, COLOR_WHITE, op, "You feel closer to your deity!");
00725         }
00726         else
00727         {
00728             new_draw_info(0, COLOR_GRAY, op, "You suddenly feel less holy.");
00729         }
00730     }
00731 
00732     if (tmp->stats.food && op->type == PLAYER && tmp->type != POISONING && tmp->type != POTION_EFFECT)
00733     {
00734         success = 1;
00735 
00736         if ((tmp->stats.food * flag) > 0)
00737         {
00738             new_draw_info(0, COLOR_WHITE, op, "You feel your digestion slowing down.");
00739         }
00740         else
00741         {
00742             new_draw_info(0, COLOR_GRAY, op, "You feel your digestion speeding up.");
00743         }
00744     }
00745 
00746     /* Messages for changed protections */
00747     for (i = 0; i < NROFATTACKS; i++)
00748     {
00749         if (op->protection[i] != refop.protection[i])
00750         {
00751             success = 1;
00752 
00753             if (op->protection[i] > refop.protection[i])
00754             {
00755                 new_draw_info_format(0, COLOR_GREEN, op, "Your protection to %s rises to %d%%.", attack_name[i], op->protection[i]);
00756             }
00757             else
00758             {
00759                 new_draw_info_format(0, COLOR_BLUE, op, "Your protection to %s drops to %d%%.", attack_name[i], op->protection[i]);
00760             }
00761         }
00762     }
00763 
00764     /* If the attuned/repelled/denied paths changed, we need to update the
00765      * spell list. */
00766     if (op->path_attuned != refop.path_attuned || op->path_repelled != refop.path_repelled || op->path_denied != refop.path_denied)
00767     {
00768         send_spelllist_cmd(op, NULL, SPLIST_MODE_UPDATE);
00769     }
00770 
00771     if (tmp->type != EXPERIENCE && !potion_max)
00772     {
00773         for (j = 0; j < NUM_STATS; j++)
00774         {
00775             if ((i = get_attr_value(&(tmp->stats), j)) != 0)
00776             {
00777                 success = 1;
00778 
00779                 if ((i * flag) > 0)
00780                 {
00781                     new_draw_info(0, COLOR_WHITE, op, gain_msg[j]);
00782                 }
00783                 else
00784                 {
00785                     new_draw_info(0, COLOR_GRAY, op, lose_msg[j]);
00786                 }
00787             }
00788         }
00789     }
00790 
00791     return success;
00792 }
00793 
00797 void drain_stat(object *op)
00798 {
00799     drain_specific_stat(op, rndm(1, NUM_STATS) - 1);
00800 }
00801 
00806 void drain_specific_stat(object *op, int deplete_stats)
00807 {
00808     object *tmp;
00809     archetype *at = find_archetype("depletion");
00810 
00811     if (!at)
00812     {
00813         LOG(llevBug, "Couldn't find archetype depletion.\n");
00814         return;
00815     }
00816     else
00817     {
00818         tmp = present_arch_in_ob(at, op);
00819 
00820         if (!tmp)
00821         {
00822             tmp = arch_to_object(at);
00823             tmp = insert_ob_in_ob(tmp, op);
00824             SET_FLAG(tmp, FLAG_APPLIED);
00825         }
00826     }
00827 
00828     new_draw_info(0, COLOR_WHITE, op, drain_msg[deplete_stats]);
00829     change_attr_value(&tmp->stats, deplete_stats, -1);
00830     fix_player(op);
00831 }
00832 
00843 void fix_player(object *op)
00844 {
00845     int ring_count = 0, skill_level_max = 1;
00846     int tmp_item, old_glow, max_boni_hp = 0, max_boni_sp = 0, max_boni_grace = 0;
00847     float tmp_con;
00848     int i, j, inv_flag, inv_see_flag, light, weapon_weight, best_wc, best_ac, wc, ac;
00849     int protect_boni[NROFATTACKS], protect_mali[NROFATTACKS], protect_exact_boni[NROFATTACKS], protect_exact_mali[NROFATTACKS];
00850     int potion_protection_bonus[NROFATTACKS], potion_protection_malus[NROFATTACKS], potion_attack[NROFATTACKS];
00851     object *grace_obj = NULL, *mana_obj = NULL, *hp_obj = NULL, *wc_obj = NULL, *tmp, *skill_weapon = NULL;
00852     float f,max = 9, added_speed = 0, bonus_speed = 0, speed_reduce_from_disease = 1;
00853     player *pl;
00854 
00855     if (QUERY_FLAG(op, FLAG_NO_FIX_PLAYER))
00856     {
00857         return;
00858     }
00859 
00860     if (QUERY_FLAG(op, FLAG_MONSTER) && op->type != PLAYER)
00861     {
00862         fix_monster(op);
00863         return;
00864     }
00865 
00866     /* For secure */
00867     if (op->type != PLAYER)
00868     {
00869         return;
00870     }
00871 
00872     pl = CONTR(op);
00873     inv_flag = inv_see_flag = weapon_weight = best_wc = best_ac = wc = ac = 0;
00874 
00875     op->stats.Str = pl->orig_stats.Str;
00876     op->stats.Dex = pl->orig_stats.Dex;
00877     op->stats.Con = pl->orig_stats.Con;
00878     op->stats.Int = pl->orig_stats.Int;
00879     op->stats.Wis = pl->orig_stats.Wis;
00880     op->stats.Pow = pl->orig_stats.Pow;
00881     op->stats.Cha = pl->orig_stats.Cha;
00882 
00883     pl->selected_weapon = pl->skill_weapon = NULL;
00884     pl->digestion = 3;
00885     pl->gen_hp = 1;
00886     pl->gen_sp = 1;
00887     pl->gen_grace = 1;
00888     pl->gen_sp_armour = 0;
00889     pl->item_power = 0;
00890     /* The used skills for fast access */
00891     pl->set_skill_weapon = NO_SKILL_READY;
00892     pl->set_skill_archery = NO_SKILL_READY;
00893 
00894     pl->encumbrance = 0;
00895 
00896     /* For players, we adjust with the values */
00897     ac = op->arch->clone.stats.ac;
00898     wc = op->arch->clone.stats.wc;
00899     op->stats.wc = wc;
00900     op->stats.ac = ac;
00901     op->stats.dam = op->arch->clone.stats.dam;
00902 
00903     op->stats.maxhp = op->arch->clone.stats.maxhp;
00904     op->stats.maxsp = op->arch->clone.stats.maxsp;
00905     op->stats.maxgrace = op->arch->clone.stats.maxgrace;
00906 
00907     pl->levhp[1] = (char) op->stats.maxhp;
00908     pl->levsp[1] = (char) op->stats.maxsp;
00909     pl->levgrace[1] = (char) op->stats.maxgrace;
00910 
00911     op->stats.wc_range = op->arch->clone.stats.wc_range;
00912 
00913     old_glow = op->glow_radius;
00914     light = op->arch->clone.glow_radius;
00915 
00916     op->speed = op->arch->clone.speed;
00917     op->weapon_speed = op->arch->clone.weapon_speed;
00918     op->path_attuned = op->arch->clone.path_attuned;
00919     op->path_repelled = op->arch->clone.path_repelled;
00920     op->path_denied = op->arch->clone.path_denied;
00921     /* Reset terrain moving abilities */
00922     op->terrain_flag = op->arch->clone.terrain_flag;
00923 
00924     /* Only adjust skills which have no own level/exp values */
00925     if (op->chosen_skill && !op->chosen_skill->last_eat && op->chosen_skill->exp_obj)
00926     {
00927         op->chosen_skill->level = op->chosen_skill->exp_obj->level;
00928     }
00929 
00930     FREE_AND_CLEAR_HASH(op->slaying);
00931 
00932     if (QUERY_FLAG(op, FLAG_IS_INVISIBLE))
00933     {
00934         inv_flag = 1;
00935     }
00936 
00937     if (QUERY_FLAG(op, FLAG_SEE_INVISIBLE))
00938     {
00939         inv_see_flag = 1;
00940     }
00941 
00942     if (!QUERY_FLAG(&op->arch->clone, FLAG_XRAYS))
00943     {
00944         CLEAR_FLAG(op, FLAG_XRAYS);
00945     }
00946 
00947     if (!QUERY_FLAG(&op->arch->clone, FLAG_CAN_PASS_THRU))
00948     {
00949         CLEAR_MULTI_FLAG(op, FLAG_CAN_PASS_THRU);
00950     }
00951 
00952     if (!QUERY_FLAG(&op->arch->clone, FLAG_IS_ETHEREAL))
00953     {
00954         CLEAR_MULTI_FLAG(op, FLAG_IS_ETHEREAL);
00955     }
00956 
00957     if (!QUERY_FLAG(&op->arch->clone, FLAG_IS_INVISIBLE))
00958     {
00959         CLEAR_MULTI_FLAG(op, FLAG_IS_INVISIBLE);
00960     }
00961 
00962     if (!QUERY_FLAG(&op->arch->clone, FLAG_SEE_INVISIBLE))
00963     {
00964         CLEAR_FLAG(op, FLAG_SEE_INVISIBLE);
00965     }
00966 
00967     if (!QUERY_FLAG(&op->arch->clone, FLAG_LIFESAVE))
00968     {
00969         CLEAR_FLAG(op, FLAG_LIFESAVE);
00970     }
00971 
00972     if (!QUERY_FLAG(&op->arch->clone, FLAG_STEALTH))
00973     {
00974         CLEAR_FLAG(op, FLAG_STEALTH);
00975     }
00976 
00977     if (!QUERY_FLAG(&op->arch->clone, FLAG_BLIND))
00978     {
00979         CLEAR_FLAG(op, FLAG_BLIND);
00980     }
00981 
00982     if (!QUERY_FLAG(&op->arch->clone, FLAG_FLYING))
00983     {
00984         CLEAR_MULTI_FLAG(op, FLAG_FLYING);
00985     }
00986 
00987     if (!QUERY_FLAG(&op->arch->clone, FLAG_REFL_SPELL))
00988     {
00989         CLEAR_FLAG(op, FLAG_REFL_SPELL);
00990     }
00991 
00992     if (!QUERY_FLAG(&op->arch->clone, FLAG_REFL_MISSILE))
00993     {
00994         CLEAR_FLAG(op, FLAG_REFL_MISSILE);
00995     }
00996 
00997     if (!QUERY_FLAG(&op->arch->clone, FLAG_UNDEAD))
00998     {
00999         CLEAR_FLAG(op, FLAG_UNDEAD);
01000     }
01001 
01002     if (!QUERY_FLAG(&op->arch->clone, FLAG_SEE_IN_DARK))
01003     {
01004         CLEAR_FLAG(op, FLAG_SEE_IN_DARK);
01005     }
01006 
01007     memset(&protect_boni, 0, sizeof(protect_boni));
01008     memset(&protect_mali, 0, sizeof(protect_mali));
01009     memset(&protect_exact_boni, 0, sizeof(protect_exact_boni));
01010     memset(&protect_exact_mali, 0, sizeof(protect_exact_mali));
01011     memset(&potion_protection_bonus, 0, sizeof(potion_protection_bonus));
01012     memset(&potion_protection_malus, 0, sizeof(potion_protection_malus));
01013     memset(&potion_attack, 0, sizeof(potion_attack));
01014 
01015     /* Initializing player arrays from the values in player archetype clone:  */
01016     memset(&pl->equipment, 0, sizeof(pl->equipment));
01017     memcpy(&op->protection, &op->arch->clone.protection, sizeof(op->protection));
01018     memcpy(&op->attack, &op->arch->clone.attack, sizeof(op->attack));
01019 
01020     /* Now we browse the inventory... There is not only our equipment -
01021      * there are all our skills, forces and hidden system objects. */
01022     for (tmp = op->inv; tmp != NULL; tmp = tmp->below)
01023     {
01024         /* Add here more types we can and must skip. */
01025         if (tmp->type == SCROLL || tmp->type == POTION || tmp->type == CONTAINER || tmp->type == CLOSE_CON || tmp->type == LIGHT_REFILL || tmp->type == WAND || tmp->type == ROD || tmp->type == HORN)
01026         {
01027             continue;
01028         }
01029 
01030         /* This is needed, because our applied light can be overruled by a light giving
01031          * object like holy glowing aura force or something */
01032         if (tmp->glow_radius > light)
01033         {
01034             /* Don't use this item when it is a 'not applied LIGHT_APPLY' */
01035             if (tmp->type != LIGHT_APPLY || QUERY_FLAG(tmp, FLAG_APPLIED))
01036             {
01037                 light = tmp->glow_radius;
01038             }
01039         }
01040 
01041         if (tmp->type == EXPERIENCE)
01042         {
01043             if (tmp->level > skill_level_max && !QUERY_FLAG(tmp, FLAG_STAND_STILL))
01044             {
01045                 skill_level_max = tmp->level;
01046             }
01047         }
01048         /* All skills, not only the applied ones */
01049         else if (tmp->type == SKILL)
01050         {
01051             /* Let's remember the best bare hand skill */
01052             if (tmp->stats.dam > 0)
01053             {
01054                 if (!skill_weapon || skill_weapon->stats.dam < tmp->stats.dam)
01055                 {
01056                     skill_weapon = tmp;
01057                 }
01058             }
01059 
01060             /* Save in table for quick access */
01061             pl->skill_ptr[tmp->stats.sp] = tmp;
01062         }
01063         else if (tmp->type == QUEST_CONTAINER)
01064         {
01065             pl->quest_container = tmp;
01066         }
01067 
01068         /* This checks all applied items in the inventory */
01069         if (QUERY_FLAG(tmp, FLAG_APPLIED))
01070         {
01071             /* Still applied stuff */
01072             switch (tmp->type)
01073             {
01074                 case LIGHT_APPLY:
01075                     if (tmp->glow_radius > light)
01076                     {
01077                         light = tmp->glow_radius;
01078                     }
01079 
01080                     break;
01081 
01082                 case SKILL_ITEM:
01083                     pl->equipment[PLAYER_EQUIP_SKILL_ITEM] = tmp;
01084                     break;
01085 
01086                 case WEAPON:
01087                     pl->equipment[PLAYER_EQUIP_WEAPON] = tmp;
01088                     /* Our weapon */
01089                     pl->selected_weapon = tmp;
01090                     i = tmp->sub_type % 4;
01091 
01092                     if (i == WEAP_1H_IMPACT)
01093                     {
01094                         pl->set_skill_weapon = SK_MELEE_WEAPON;
01095                     }
01096                     else if (i == WEAP_1H_SLASH)
01097                     {
01098                         pl->set_skill_weapon = SK_SLASH_WEAP;
01099                     }
01100                     else if (i == WEAP_1H_CLEAVE)
01101                     {
01102                         pl->set_skill_weapon = SK_CLEAVE_WEAP;
01103                     }
01104                     else
01105                     {
01106                         pl->set_skill_weapon = SK_PIERCE_WEAP;
01107                     }
01108 
01109                     op->weapon_speed = tmp->weapon_speed;
01110 
01111                     if (!op->weapon_speed)
01112                     {
01113                         LOG(llevBug, "monster/player %s applied weapon %s without weapon speed!\n", op->name, tmp->name);
01114                     }
01115 
01116                     wc += (tmp->stats.wc + tmp->magic);
01117 
01118                     if (tmp->stats.ac && tmp->stats.ac + tmp->magic > 0)
01119                     {
01120                         ac += tmp->stats.ac + tmp->magic;
01121                     }
01122 
01123                     op->stats.dam += (tmp->stats.dam + tmp->magic);
01124                     weapon_weight = tmp->weight;
01125 
01126                     if (tmp->slaying)
01127                     {
01128                         FREE_AND_COPY_HASH(op->slaying, tmp->slaying);
01129                     }
01130 
01131                     pl->encumbrance += (sint16) (3 * tmp->weight / 1000);
01132                     pl->digestion += tmp->stats.food;
01133                     pl->gen_sp += tmp->stats.sp;
01134                     pl->gen_grace += tmp->stats.grace;
01135                     pl->gen_hp += tmp->stats.hp;
01136                     pl->gen_sp_armour += tmp->last_heal;
01137                     pl->item_power += tmp->item_power;
01138 
01139                     for (i = 0; i < NUM_STATS; i++)
01140                     {
01141                         change_attr_value(&(op->stats), i, get_attr_value(&(tmp->stats), i));
01142                     }
01143 
01144                     break;
01145 
01146                 /* All armours + rings and amulets */
01147                 case RING:
01148                     pl->equipment[PLAYER_EQUIP_RRING + ring_count] = tmp;
01149                     ring_count++;
01150                     goto fix_player_no_armour;
01151 
01152                 case AMULET:
01153                     pl->equipment[PLAYER_EQUIP_AMULET] = tmp;
01154                     goto fix_player_no_armour;
01155 
01156                 case BRACERS:
01157                     pl->equipment[PLAYER_EQUIP_BRACER] = tmp;
01158                     goto fix_player_jump1;
01159 
01160                 case ARMOUR:
01161                     pl->equipment[PLAYER_EQUIP_MAIL] = tmp;
01162                     pl->encumbrance += (int) tmp->weight / 1000;
01163                     goto fix_player_jump1;
01164 
01165                 case SHIELD:
01166                     pl->equipment[PLAYER_EQUIP_SHIELD] = tmp;
01167                     pl->encumbrance += (int) tmp->weight / 2000;
01168                     goto fix_player_jump1;
01169 
01170                 case GIRDLE:
01171                     pl->equipment[PLAYER_EQUIP_GIRDLE] = tmp;
01172                     goto fix_player_jump1;
01173 
01174                 case HELMET:
01175                     pl->equipment[PLAYER_EQUIP_HELM] = tmp;
01176                     goto fix_player_jump1;
01177 
01178                 case BOOTS:
01179                     pl->equipment[PLAYER_EQUIP_BOOTS] = tmp;
01180                     goto fix_player_jump1;
01181 
01182                 case GLOVES:
01183                     pl->equipment[PLAYER_EQUIP_GAUNTLET] = tmp;
01184                     goto fix_player_jump1;
01185 
01186                 case CLOAK:
01187                     pl->equipment[PLAYER_EQUIP_CLOAK] = tmp;
01188 
01189 fix_player_jump1:
01190                     /* Used for ALL armours except rings and amulets */
01191                     if (ARMOUR_SPEED(tmp) && (float) ARMOUR_SPEED(tmp) / 10.0f < max)
01192                     {
01193                         max = ARMOUR_SPEED(tmp) / 10.0f;
01194                     }
01195 
01196 fix_player_no_armour:
01197                     max_boni_hp += tmp->stats.maxhp;
01198                     max_boni_sp += tmp->stats.maxsp;
01199                     max_boni_grace += tmp->stats.maxgrace;
01200                     pl->digestion += tmp->stats.food;
01201                     pl->gen_sp += tmp->stats.sp;
01202                     pl->gen_grace += tmp->stats.grace;
01203                     pl->gen_hp += tmp->stats.hp;
01204                     pl->gen_sp_armour += tmp->last_heal;
01205                     pl->item_power += tmp->item_power;
01206 
01207                     for (i = 0; i < NUM_STATS; i++)
01208                     {
01209                         change_attr_value(&(op->stats), i, get_attr_value(&(tmp->stats), i));
01210                     }
01211 
01212                     if (tmp->stats.wc)
01213                     {
01214                         wc += (tmp->stats.wc + tmp->magic);
01215                     }
01216 
01217                     if (tmp->stats.dam)
01218                     {
01219                         op->stats.dam += (tmp->stats.dam + tmp->magic);
01220                     }
01221 
01222                     if (tmp->stats.ac)
01223                     {
01224                         ac += (tmp->stats.ac + tmp->magic);
01225                     }
01226 
01227                     break;
01228 
01229                 case BOW:
01230                     pl->equipment[PLAYER_EQUIP_BOW] = tmp;
01231 
01232                     /* As a special bonus range weapons can be permanently applied and
01233                      * will add stat bonus */
01234                     for (i = 0; i < NUM_STATS; i++)
01235                     {
01236                         change_attr_value(&(op->stats), i, get_attr_value(&(tmp->stats), i));
01237                     }
01238 
01239                     if (tmp->sub_type == RANGE_WEAP_BOW)
01240                     {
01241                         pl->set_skill_archery = SK_MISSILE_WEAPON;
01242                     }
01243                     else if (tmp->sub_type == RANGE_WEAP_XBOWS)
01244                     {
01245                         pl->set_skill_archery = SK_XBOW_WEAP;
01246                     }
01247                     else
01248                     {
01249                         pl->set_skill_archery = SK_SLING_WEAP;
01250                     }
01251 
01252                     break;
01253 
01254                 /* No protection from potion effect - resist only! */
01255                 case POTION_EFFECT:
01256                     for (i = 0; i < NUM_STATS; i++)
01257                     {
01258                         change_attr_value(&(op->stats), i, get_attr_value(&(tmp->stats), i));
01259                     }
01260 
01261                     /* Collect highest bonus & malus - only highest one counts,
01262                      * no adding potion effects of same resist */
01263                     for (i = 0; i < NROFATTACKS; i++)
01264                     {
01265                         /* Collect highest/lowest resistance */
01266                         if (tmp->protection[i] > potion_protection_bonus[i])
01267                         {
01268                             potion_protection_bonus[i] = tmp->protection[i];
01269                         }
01270                         else if (tmp->protection[i] < potion_protection_malus[i])
01271                         {
01272                             potion_protection_malus[i] = tmp->protection[i];
01273                         }
01274 
01275                         if (tmp->attack[i] > potion_attack[i])
01276                         {
01277                             potion_attack[i] = tmp->attack[i];
01278                         }
01279                     }
01280 
01281                     break;
01282 
01283                 case EXPERIENCE:
01284                     if (tmp->stats.Str && !wc_obj)
01285                     {
01286                         wc_obj = tmp;
01287                     }
01288 
01289                     if (tmp->stats.Con && !hp_obj)
01290                     {
01291                         hp_obj = tmp;
01292                     }
01293 
01294                     /* For spellpoint determination */
01295                     if (tmp->stats.Pow && !mana_obj)
01296                     {
01297                         mana_obj = tmp;
01298                     }
01299 
01300                     if (tmp->stats.Wis && !grace_obj)
01301                     {
01302                         grace_obj = tmp;
01303                     }
01304 
01305                     break;
01306 
01307                 /* Skills modifying the character */
01308                 case SKILL:
01309                     /* Skill is a 'weapon' */
01310                     if (tmp->stats.dam > 0)
01311                     {
01312                         wc += tmp->stats.wc;
01313                         ac += tmp->stats.ac;
01314                         op->weapon_speed = tmp->weapon_speed;
01315                         weapon_weight = tmp->weight;
01316                         op->stats.dam += tmp->stats.dam;
01317                     }
01318                     else
01319                     {
01320                         op->stats.dam += tmp->stats.dam;
01321                         wc += tmp->stats.wc;
01322                         ac += tmp->stats.ac;
01323                     }
01324 
01325                     if (tmp->slaying)
01326                     {
01327                         FREE_AND_COPY_HASH(op->slaying, tmp->slaying);
01328                     }
01329 
01330                     pl->encumbrance += (int) 3 * tmp->weight / 1000;
01331                     break;
01332 
01333                 case CLASS:
01334                     /* Copy some values from the class object to the
01335                      * player. */
01336                     for (i = 0; i < NUM_STATS; i++)
01337                     {
01338                         change_attr_value(&op->stats, i, get_attr_value(&tmp->stats, i));
01339                     }
01340 
01341                     wc += tmp->stats.wc;
01342                     op->stats.dam += tmp->stats.dam;
01343                     ac += tmp->stats.ac;
01344                     op->stats.maxhp += tmp->stats.maxhp;
01345                     op->stats.maxsp += tmp->stats.maxsp;
01346                     op->stats.maxgrace += tmp->stats.maxgrace;
01347                     CONTR(op)->class_ob = tmp;
01348                     break;
01349 
01350                 case FORCE:
01351                     if (ARMOUR_SPEED(tmp) && (float)ARMOUR_SPEED(tmp) / 10.0f < max)
01352                     {
01353                         max = ARMOUR_SPEED(tmp) / 10.0f;
01354                     }
01355 
01356                     for (i = 0; i < NUM_STATS; i++)
01357                     {
01358                         change_attr_value(&(op->stats), i, get_attr_value(&(tmp->stats), i));
01359                     }
01360 
01361                     if (tmp->stats.wc)
01362                     {
01363                         wc += (tmp->stats.wc + tmp->magic);
01364                     }
01365 
01366                     if (tmp->stats.dam)
01367                     {
01368                         op->stats.dam += (tmp->stats.dam + tmp->magic);
01369                     }
01370 
01371                     if (tmp->stats.ac)
01372                     {
01373                         ac += (tmp->stats.ac + tmp->magic);
01374                     }
01375 
01376                     if (tmp->stats.maxhp)
01377                     {
01378                         op->stats.maxhp += tmp->stats.maxhp;
01379                     }
01380 
01381                     if (tmp->stats.maxsp)
01382                     {
01383                         op->stats.maxsp += tmp->stats.maxsp;
01384                     }
01385 
01386                     if (tmp->stats.maxgrace)
01387                     {
01388                         op->stats.maxgrace += tmp->stats.maxgrace;
01389                     }
01390 
01391                     goto fix_player_jump_resi;
01392 
01393                 case DISEASE:
01394                 case SYMPTOM:
01395                     speed_reduce_from_disease = (float) tmp->last_sp / 100.0f;
01396 
01397                     if (speed_reduce_from_disease == 0.0f)
01398                     {
01399                         speed_reduce_from_disease = 1.0f;
01400                     }
01401 
01402                 case POISONING:
01403                     for (i = 0; i < NUM_STATS; i++)
01404                     {
01405                         change_attr_value(&op->stats, i, get_attr_value(&tmp->stats, i));
01406                     }
01407 
01408                 case BLINDNESS:
01409                 case CONFUSION:
01410 fix_player_jump_resi:
01411 
01412                     for (i = 0; i < NROFATTACKS; i++)
01413                     {
01414                         if (tmp->protection[i] > protect_exact_boni[i])
01415                         {
01416                             protect_exact_boni[i] = tmp->protection[i];
01417                         }
01418                         else if (tmp->protection[i] < 0)
01419                         {
01420                             protect_exact_mali[i] += (-tmp->protection[i]);
01421                         }
01422 
01423                         if (tmp->type != DISEASE && tmp->type != SYMPTOM && tmp->type != POISONING)
01424                         {
01425                             if (tmp->attack[i] > 0)
01426                             {
01427                                 if ((op->attack[i] + tmp->attack[i]) <= 120)
01428                                 {
01429                                     op->attack[i] += tmp->attack[i];
01430                                 }
01431                                 else
01432                                 {
01433                                     op->attack[i] = 120;
01434                                 }
01435                             }
01436                         }
01437                     }
01438 
01439                     break;
01440 
01441                 /* Catch items which are applied but should not be -
01442                  * or we forgot to catch them here. */
01443                 default:
01444                     LOG(llevDebug, "fix_player(): unexpected applied object %s (%d)(clear flag now!)\n", query_name(tmp, NULL), tmp->type);
01445                     CLEAR_FLAG(tmp, FLAG_APPLIED);
01446                     break;
01447             }
01448 
01449             /* We just add a given terrain */
01450             op->terrain_flag |= tmp->terrain_type;
01451             op->path_attuned |= tmp->path_attuned;
01452             op->path_repelled |= tmp->path_repelled;
01453             op->path_denied |= tmp->path_denied;
01454 
01455             if (QUERY_FLAG(tmp, FLAG_LIFESAVE))
01456             {
01457                 SET_FLAG(op, FLAG_LIFESAVE);
01458             }
01459 
01460             if (QUERY_FLAG(tmp, FLAG_REFL_SPELL))
01461             {
01462                 SET_FLAG(op, FLAG_REFL_SPELL);
01463             }
01464 
01465             if (QUERY_FLAG(tmp, FLAG_REFL_MISSILE))
01466             {
01467                 SET_FLAG(op, FLAG_REFL_MISSILE);
01468             }
01469 
01470             if (QUERY_FLAG(tmp, FLAG_STEALTH))
01471             {
01472                 SET_FLAG(op, FLAG_STEALTH);
01473             }
01474 
01475             if (QUERY_FLAG(tmp, FLAG_UNDEAD) && !QUERY_FLAG(&op->arch->clone, FLAG_UNDEAD))
01476             {
01477                 SET_FLAG(op, FLAG_UNDEAD);
01478             }
01479 
01480             if (QUERY_FLAG(tmp, FLAG_XRAYS))
01481             {
01482                 SET_FLAG(op, FLAG_XRAYS);
01483             }
01484 
01485             if (QUERY_FLAG(tmp, FLAG_BLIND))
01486             {
01487                 SET_FLAG(op, FLAG_BLIND);
01488             }
01489 
01490             if (QUERY_FLAG(tmp, FLAG_SEE_IN_DARK))
01491             {
01492                 SET_FLAG(op, FLAG_SEE_IN_DARK);
01493             }
01494 
01495             if (QUERY_FLAG(tmp, FLAG_SEE_INVISIBLE))
01496             {
01497                 SET_FLAG(op, FLAG_SEE_INVISIBLE);
01498             }
01499 
01500             if (QUERY_FLAG(tmp, FLAG_MAKE_INVISIBLE))
01501             {
01502                 SET_MULTI_FLAG(op, FLAG_IS_INVISIBLE);
01503             }
01504 
01505             if (QUERY_FLAG(tmp, FLAG_CAN_PASS_THRU))
01506             {
01507                 SET_MULTI_FLAG(op, FLAG_CAN_PASS_THRU);
01508             }
01509 
01510             if (QUERY_FLAG(tmp, FLAG_MAKE_ETHEREAL))
01511             {
01512                 SET_MULTI_FLAG(op, FLAG_CAN_PASS_THRU);
01513                 SET_MULTI_FLAG(op, FLAG_IS_ETHEREAL);
01514             }
01515 
01516             if (QUERY_FLAG(tmp, FLAG_FLYING))
01517             {
01518                 SET_MULTI_FLAG(op, FLAG_FLYING);
01519 
01520                 if (!QUERY_FLAG(op, FLAG_WIZ))
01521                 {
01522                     max = 1;
01523                 }
01524             }
01525 
01526             /* Slow penalty */
01527             if (tmp->stats.exp && tmp->type != EXPERIENCE && tmp->type != SKILL)
01528             {
01529                 if (tmp->stats.exp > 0)
01530                 {
01531                     added_speed += (float) tmp->stats.exp / 3.0f;
01532                     bonus_speed += 1.0f + (float) tmp->stats.exp / 3.0f;
01533                 }
01534                 else
01535                 {
01536                     added_speed += (float) tmp->stats.exp;
01537                 }
01538             }
01539         }
01540     }
01541 
01542     /* Now collect all our real armour stuff - this will now add *after* all force
01543      * or non potion effects effecting resist, attack or protection - also this will
01544      * give us a sorted adding.
01545      * But the most important point is that we calculate *here* and only here the equipment
01546      * quality modifier for players.
01547      * Note, that for bows/arrows the calculation is done "on the fly" when the
01548      * throw/fire object is created! */
01549     for (j = 0; j < PLAYER_EQUIP_MAX; j++)
01550     {
01551         if (pl->equipment[j])
01552         {
01553             tmp = pl->equipment[j];
01554             tmp_con = (float) tmp->item_condition / 100.0f;
01555 
01556             /* Only quality adjustment for *positive* values! */
01557             for (i = 0; i < NROFATTACKS; i++)
01558             {
01559                 if (tmp->protection[i] > 0)
01560                 {
01561                     tmp_item = (int) ((float) tmp->protection[i] * tmp_con);
01562                     protect_boni[i] += ((100 - protect_boni[i]) * tmp_item) / 100;
01563                 }
01564                 else if (tmp->protection[i] < 0)
01565                 {
01566                     protect_mali[i] += ((100 - protect_mali[i]) * (-tmp->protection[i])) / 100;
01567                 }
01568 
01569                 if (tmp->type != BOW)
01570                 {
01571                     if (tmp->attack[i] > 0)
01572                     {
01573                         tmp_item = (int) ((float) tmp->attack[i] * tmp_con);
01574 
01575                         if ((op->attack[i] + tmp_item) <= 120)
01576                         {
01577                             op->attack[i] += tmp_item;
01578                         }
01579                         else
01580                         {
01581                             op->attack[i] = 120;
01582                         }
01583                     }
01584                 }
01585             }
01586         }
01587     }
01588 
01589     /* Now we add in all our values... we add in our potions effects as well as
01590      * our attack boni and/or protections. */
01591     for (j = 1, i = 0; i < NROFATTACKS; i++, j <<= 1)
01592     {
01593         if (potion_attack[i])
01594         {
01595             if ((op->attack[i] + potion_attack[i]) > 120)
01596             {
01597                 op->attack[i] = 120;
01598             }
01599             else
01600             {
01601                 op->attack[i] += potion_attack[i];
01602             }
01603         }
01604     }
01605 
01606     /* Add protection bonuses.
01607      * Ensure that protection is between 0 - 100. */
01608     for (i = 0; i < NROFATTACKS; i++)
01609     {
01610         int ptemp;
01611 
01612         /* Add in the potion protections. */
01613         if (potion_protection_bonus[i] > 0)
01614         {
01615             protect_boni[i] += ((100 - protect_boni[i]) * potion_protection_bonus[i]) / 100;
01616         }
01617 
01618         if (potion_protection_malus[i] < 0)
01619         {
01620             protect_mali[i] += ((100 - protect_mali[i]) * (-potion_protection_malus[i])) / 100;
01621         }
01622 
01623         ptemp = protect_boni[i] + protect_exact_boni[i] - protect_mali[i] - protect_exact_mali[i];
01624 
01625         if (ptemp < -100)
01626         {
01627             op->protection[i] = -100;
01628         }
01629         else if (ptemp > 100)
01630         {
01631             op->protection[i] = 100;
01632         }
01633         else
01634         {
01635             op->protection[i] = ptemp;
01636         }
01637     }
01638 
01639     check_stat_bounds(&(op->stats));
01640 
01641     /* Now the speed thing... */
01642     op->speed += speed_bonus[op->stats.Dex];
01643 
01644     if (added_speed >= 0)
01645     {
01646         op->speed += added_speed / 10.0f;
01647     }
01648     /* Something wrong here...: */
01649     else
01650     {
01651         op->speed /= 1.0f - added_speed;
01652     }
01653 
01654     if (op->speed > max)
01655     {
01656         op->speed = max;
01657     }
01658 
01659     /* Calculate real speed */
01660     op->speed += bonus_speed / 10.0f;
01661 
01662     /* Put a lower limit on speed. Note with this speed, you move once every
01663      * 100 ticks or so. This amounts to once every 12 seconds of realtime. */
01664     op->speed = op->speed * speed_reduce_from_disease;
01665 
01666     /* Don't reduce under this value */
01667     if (op->speed < 0.01f)
01668     {
01669         op->speed = 0.01f;
01670     }
01671     else
01672     {
01673         /* Max kg we can carry */
01674         f = ((float) weight_limit[op->stats.Str] / 100.0f) * ENCUMBRANCE_LIMIT;
01675 
01676         if (((sint32) f) <= op->carrying)
01677         {
01678             if (op->carrying >= (sint32) weight_limit[op->stats.Str])
01679             {
01680                 op->speed = 0.01f;
01681             }
01682             else
01683             {
01684                 /* Total encumbrance weight part */
01685                 f = ((float) weight_limit[op->stats.Str] - f);
01686                 /* Value from 0.0 to 1.0 encumbrance */
01687                 f = ((float) weight_limit[op->stats.Str] - op->carrying) / f;
01688 
01689                 if (f < 0.0f)
01690                 {
01691                     f = 0.0f;
01692                 }
01693                 else if (f > 1.0f)
01694                 {
01695                     f = 1.0f;
01696                 }
01697 
01698                 op->speed *= f;
01699 
01700                 if (op->speed < 0.01f)
01701                 {
01702                     op->speed = 0.01f;
01703                 }
01704             }
01705         }
01706     }
01707 
01708     update_ob_speed(op);
01709     op->weapon_speed_add = op->weapon_speed;
01710 
01711     op->glow_radius = light;
01712 
01713     /* We must do -old_gow + light */
01714     if (op->map && old_glow != light)
01715     {
01716         adjust_light_source(op->map, op->x, op->y, light - old_glow);
01717     }
01718 
01719     /* *3 is base */
01720     op->stats.maxhp += op->arch->clone.stats.maxhp + op->arch->clone.stats.maxhp;
01721     op->stats.maxsp += op->arch->clone.stats.maxsp + op->arch->clone.stats.maxsp;
01722     op->stats.maxgrace += op->arch->clone.stats.maxgrace + op->arch->clone.stats.maxgrace;
01723 
01724     for (i = 1; i <= op->level; i++)
01725     {
01726         op->stats.maxhp += pl->levhp[i];
01727     }
01728 
01729     if (mana_obj)
01730     {
01731         for (i = 1; i <= mana_obj->level; i++)
01732         {
01733             op->stats.maxsp += pl->levsp[i];
01734         }
01735     }
01736 
01737     if (grace_obj)
01738     {
01739         for (i = 1; i <= grace_obj->level; i++)
01740         {
01741             op->stats.maxgrace += pl->levgrace[i];
01742         }
01743     }
01744 
01745     /* Now adjust with the % of the stats mali/boni. */
01746     op->stats.maxhp += (int) ((float) op->stats.maxhp * con_bonus[op->stats.Con]) + max_boni_hp;
01747     op->stats.maxsp += (int) ((float) op->stats.maxsp * pow_bonus[op->stats.Pow]) + max_boni_sp;
01748     op->stats.maxgrace += (int) ((float) op->stats.maxgrace * wis_bonus[op->stats.Wis]) + max_boni_grace;
01749 
01750     /* HP/SP/Grace adjustments coming from class-defining object. */
01751     if (CONTR(op)->class_ob)
01752     {
01753         if (CONTR(op)->class_ob->stats.hp)
01754         {
01755             op->stats.maxhp += ((float) op->stats.maxhp / 100.0f) * (float) CONTR(op)->class_ob->stats.hp;
01756         }
01757 
01758         if (CONTR(op)->class_ob->stats.sp)
01759         {
01760             op->stats.maxsp += ((float) op->stats.maxsp / 100.0f) * (float) CONTR(op)->class_ob->stats.sp;
01761         }
01762 
01763         if (CONTR(op)->class_ob->stats.grace)
01764         {
01765             op->stats.maxgrace += ((float) op->stats.maxgrace / 100.0f) * (float) CONTR(op)->class_ob->stats.grace;
01766         }
01767     }
01768 
01769     if (op->stats.maxhp < 1)
01770     {
01771         op->stats.maxhp = 1;
01772     }
01773 
01774     if (op->stats.maxsp < 1)
01775     {
01776         op->stats.maxsp = 1;
01777     }
01778 
01779     if (op->stats.maxgrace < 1)
01780     {
01781         op->stats.maxgrace = 1;
01782     }
01783 
01784     if (op->stats.hp == -1)
01785     {
01786         op->stats.hp = op->stats.maxhp;
01787     }
01788 
01789     if (op->stats.sp == -1)
01790     {
01791         op->stats.sp = op->stats.maxsp;
01792     }
01793 
01794     if (op->stats.grace == -1)
01795     {
01796         op->stats.grace = op->stats.maxgrace;
01797     }
01798 
01799     /* Cap the pools to <= max */
01800     if (op->stats.hp > op->stats.maxhp)
01801     {
01802         op->stats.hp = op->stats.maxhp;
01803     }
01804 
01805     if (op->stats.sp > op->stats.maxsp)
01806     {
01807         op->stats.sp = op->stats.maxsp;
01808     }
01809 
01810     if (op->stats.grace > op->stats.maxgrace)
01811     {
01812         op->stats.grace = op->stats.maxgrace;
01813     }
01814 
01815     op->stats.ac = ac + skill_level_max;
01816 
01817     /* No weapon in our hand - we must use our hands */
01818     if (pl->set_skill_weapon == NO_SKILL_READY)
01819     {
01820         f = 1.0f;
01821 
01822         if (skill_weapon)
01823         {
01824             /* Now we must add this special skill attack */
01825             for (i = 0; i < NROFATTACKS; i++)
01826             {
01827                 if (op->attack[i] + skill_weapon->attack[i] > 120)
01828                 {
01829                     op->attack[i] = 120;
01830                 }
01831                 else
01832                 {
01833                     op->attack[i] += skill_weapon->attack[i];
01834                 }
01835             }
01836 
01837             pl->skill_weapon = skill_weapon;
01838             op->stats.wc = wc + skill_weapon->level;
01839             op->stats.dam = (sint16) ((float) op->stats.dam * LEVEL_DAMAGE(skill_weapon->level));
01840         }
01841         else
01842         {
01843             LOG(llevBug, "fix_player(): player %s has no hth skill!\n", op->name);
01844         }
01845     }
01846     /* Weapon in hand */
01847     else
01848     {
01849         f = (float) (pl->equipment[PLAYER_EQUIP_WEAPON]->item_condition) / 100.0f;
01850 
01851         /* Weapon without the skill applied... */
01852         if (!pl->skill_ptr[pl->set_skill_weapon])
01853         {
01854             LOG(llevBug, "fix_player(): player %s has weapon selected but not the skill #%d!!!\n", op->name, pl->set_skill_weapon);
01855         }
01856         else
01857         {
01858             op->stats.wc = wc + pl->skill_ptr[pl->set_skill_weapon]->level;
01859             op->stats.dam = (sint16) ((float) op->stats.dam * LEVEL_DAMAGE(pl->skill_ptr[pl->set_skill_weapon]->level));
01860         }
01861     }
01862 
01863     /* Now the last adds - stat bonus to damage and WC */
01864     op->stats.dam += dam_bonus[op->stats.Str];
01865 
01866     if (op->stats.dam < 0)
01867     {
01868         op->stats.dam = 0;
01869     }
01870 
01871     CONTR(op)->client_dam = (sint16) ((float) op->stats.dam * f);
01872     op->stats.wc += thaco_bonus[op->stats.Dex];
01873 
01874     /* For the client */
01875     pl->weapon_sp = (char) (op->weapon_speed / 0.0025f);
01876 
01877     if (!pl->quest_container)
01878     {
01879         object *quest_container = get_archetype(QUEST_CONTAINER_ARCHETYPE);
01880 
01881         LOG(llevBug, "fix_player(): Player %s had no quest container, fixing.\n", op->name);
01882         insert_ob_in_ob(quest_container, op);
01883         pl->quest_container = quest_container;
01884     }
01885 
01886     if (QUERY_FLAG(op, FLAG_IS_INVISIBLE))
01887     {
01888         /* We must reinsert us in the invisible chain */
01889         if (!inv_flag)
01890         {
01891             update_object(op, UP_OBJ_LAYER);
01892         }
01893     }
01894     /* And !FLAG_IS_INVISIBLE */
01895     else if (inv_flag)
01896     {
01897         update_object(op, UP_OBJ_LAYER);
01898     }
01899 
01900     if (QUERY_FLAG(op, FLAG_SEE_INVISIBLE))
01901     {
01902         if (!inv_see_flag)
01903         {
01904             pl->socket.update_tile = 0;
01905         }
01906     }
01907     /* And !FLAG_SEE_INVISIBLE */
01908     else if (inv_see_flag)
01909     {
01910         pl->socket.update_tile = 0;
01911     }
01912 }
01913 
01917 void fix_monster(object *op)
01918 {
01919     object *base, *tmp;
01920     float tmp_add;
01921 
01922     if (op->head)
01923     {
01924         return;
01925     }
01926 
01927     /* Will insert or/and return base info */
01928     base = insert_base_info_object(op);
01929 
01930     CLEAR_FLAG(op, FLAG_READY_BOW);
01931 
01932     op->stats.maxhp = (base->stats.maxhp * (op->level + 3) + (op->level / 2) * base->stats.maxhp) / 10;
01933     op->stats.maxsp = base->stats.maxsp * (op->level + 1);
01934     op->stats.maxgrace = base->stats.maxgrace * (op->level + 1);
01935 
01936     if (op->stats.hp == -1)
01937     {
01938         op->stats.hp = op->stats.maxhp;
01939     }
01940 
01941     if (op->stats.sp == -1)
01942     {
01943         op->stats.sp = op->stats.maxsp;
01944     }
01945 
01946     if (op->stats.grace == -1)
01947     {
01948         op->stats.grace = op->stats.maxgrace;
01949     }
01950 
01951     /* Cap the pools to <= max */
01952     if (op->stats.hp > op->stats.maxhp)
01953     {
01954         op->stats.hp = op->stats.maxhp;
01955     }
01956 
01957     if (op->stats.sp > op->stats.maxsp)
01958     {
01959         op->stats.sp = op->stats.maxsp;
01960     }
01961 
01962     if (op->stats.grace > op->stats.maxgrace)
01963     {
01964         op->stats.grace = op->stats.maxgrace;
01965     }
01966 
01967     op->stats.ac = base->stats.ac + op->level;
01968     /* + level / 4 to catch up the equipment improvements of
01969      * the players in armour items. */
01970     op->stats.wc = base->stats.wc + op->level + (op->level / 4);
01971     op->stats.dam = base->stats.dam;
01972 
01973     if (base->stats.wc_range)
01974     {
01975         op->stats.wc_range = base->stats.wc_range;
01976     }
01977     /* Default value if not set in arch */
01978     else
01979     {
01980         op->stats.wc_range = 20;
01981     }
01982 
01983     for (tmp = op->inv; tmp; tmp = tmp->below)
01984     {
01985         /* Check for bow and use it! */
01986         if (tmp->type == BOW)
01987         {
01988             if (QUERY_FLAG(op, FLAG_USE_BOW))
01989             {
01990                 SET_FLAG(tmp, FLAG_APPLIED);
01991                 SET_FLAG(op, FLAG_READY_BOW);
01992             }
01993             else
01994             {
01995                 CLEAR_FLAG(tmp, FLAG_APPLIED);
01996             }
01997         }
01998         else if (QUERY_FLAG(op, FLAG_USE_ARMOUR) && IS_ARMOR(tmp) && check_good_armour(op, tmp))
01999         {
02000             SET_FLAG(tmp, FLAG_APPLIED);
02001         }
02002         else if (QUERY_FLAG(op, FLAG_USE_WEAPON) && tmp->type == WEAPON && check_good_weapon(op, tmp))
02003         {
02004             SET_FLAG(tmp, FLAG_APPLIED);
02005         }
02006 
02007         if (QUERY_FLAG(tmp, FLAG_APPLIED))
02008         {
02009             int i;
02010 
02011             if (tmp->type == WEAPON)
02012             {
02013                 op->stats.dam += tmp->stats.dam;
02014                 op->stats.wc += tmp->stats.wc;
02015             }
02016             else if (IS_ARMOR(tmp))
02017             {
02018                 for (i = 0; i < NROFATTACKS; i++)
02019                 {
02020                     op->protection[i] = MIN(op->protection[i] + tmp->protection[i], 15);
02021                 }
02022 
02023                 op->stats.ac += tmp->stats.ac;
02024             }
02025         }
02026     }
02027 
02028     if ((tmp_add = LEVEL_DAMAGE(op->level / 3) - 0.75f) < 0)
02029     {
02030         tmp_add = 0;
02031     }
02032 
02033     if (op->more && QUERY_FLAG(op, FLAG_FRIENDLY))
02034     {
02035         SET_MULTI_FLAG(op, FLAG_FRIENDLY);
02036     }
02037 
02038     op->stats.dam = (sint16) (((float) op->stats.dam * ((LEVEL_DAMAGE(op->level < 0 ? 0 : op->level) + tmp_add) * (0.925f + 0.05 * (op->level / 10)))) / 10.0f);
02039 
02040     /* Add a special decrease of power for monsters level 1-5 */
02041     if (op->level <= 5)
02042     {
02043         float d = 1.0f - ((0.35f / 5.0f) * (float) (6 - op->level));
02044 
02045         op->stats.dam = (int) ((float) op->stats.dam * d);
02046 
02047         if (op->stats.dam < 1)
02048         {
02049             op->stats.dam = 1;
02050         }
02051 
02052         op->stats.maxhp = (int) ((float) op->stats.maxhp * d);
02053 
02054         if (op->stats.maxhp < 1)
02055         {
02056             op->stats.maxhp = 1;
02057         }
02058 
02059         if (op->stats.hp > op->stats.maxhp)
02060         {
02061             op->stats.hp = op->stats.maxhp;
02062         }
02063     }
02064 
02065     set_mobile_speed(op, 0);
02066 }
02067 
02072 object *insert_base_info_object(object *op)
02073 {
02074     object *tmp, *head = op;
02075 
02076     if (op->head)
02077     {
02078         head = op->head;
02079     }
02080 
02081     if (op->type == PLAYER)
02082     {
02083         LOG(llevBug, "insert_base_info_object() Try to inserting base_info in player %s!\n", query_name(head, NULL));
02084         return NULL;
02085     }
02086 
02087     if ((tmp = find_base_info_object(head)))
02088     {
02089         return tmp;
02090     }
02091 
02092     tmp = get_object();
02093     tmp->arch = op->arch;
02094     /* Copy without putting it on active list */
02095     copy_object(head, tmp, 1);
02096     tmp->type = BASE_INFO;
02097     tmp->speed_left = tmp->speed;
02098     /* Ensure this object will not be active in any way */
02099     tmp->speed = 0.0f;
02100     tmp->face = base_info_archetype->clone.face;
02101     SET_FLAG(tmp, FLAG_NO_DROP);
02102     CLEAR_FLAG(tmp, FLAG_ANIMATE);
02103     CLEAR_FLAG(tmp, FLAG_FRIENDLY);
02104     CLEAR_FLAG(tmp, FLAG_ALIVE);
02105     CLEAR_FLAG(tmp, FLAG_MONSTER);
02106     /* And put it in the mob */
02107     insert_ob_in_ob(tmp, head);
02108 
02109     /* Store position (for returning home after aggro is lost...) */
02110     tmp->x = op->x;
02111     tmp->y = op->y;
02112     FREE_AND_ADD_REF_HASH(tmp->slaying, op->map->path);
02113 
02114     return tmp;
02115 }
02116 
02121 object *find_base_info_object(object *op)
02122 {
02123     object *tmp;
02124 
02125     for (tmp = op->inv; tmp; tmp = tmp->below)
02126     {
02127         if (tmp->type == BASE_INFO)
02128         {
02129             return tmp;
02130         }
02131     }
02132 
02133     return NULL;
02134 }
02135 
02145 void set_mobile_speed(object *op, int idx)
02146 {
02147     object *base;
02148     float speed, tmp;
02149 
02150     base = insert_base_info_object(op);
02151 
02152     speed = base->speed_left;
02153 
02154     tmp = op->speed;
02155 
02156     if (idx)
02157     {
02158         op->speed = speed * idx;
02159     }
02160     /* We will generate the speed by setting of the monster */
02161     else
02162     {
02163         /* If not slowed... */
02164         if (!QUERY_FLAG(op, FLAG_SLOW_MOVE))
02165         {
02166             speed += base->speed_left;
02167         }
02168 
02169         /* Valid enemy - monster is fighting! */
02170         if (OBJECT_VALID(op->enemy, op->enemy_count))
02171         {
02172             speed += base->speed_left * 2;
02173         }
02174 
02175         op->speed = speed;
02176     }
02177 
02178     /* Update speed if needed */
02179     if ((tmp && !op->speed) || (!tmp && op->speed))
02180     {
02181         update_ob_speed(op);
02182     }
02183 }