|
Atrinik Server 2.5
|
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 }
1.7.4