|
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 00030 #include <global.h> 00031 00032 /* need math lib for double-precision and pow() in dragon_eat_flesh() */ 00033 #include <math.h> 00034 00035 static int is_legal_2ways_exit(object* op, object *exit); 00036 00056 void move_apply(object *trap, object *victim, object *originator, int flags) 00057 { 00058 static int recursion_depth = 0; 00059 00060 /* move_apply() is the most likely candidate for causing unwanted and 00061 * possibly unlimited recursion. */ 00062 /* The following was changed because it was causing perfectly correct 00063 * maps to fail. 1) it's not an error to recurse: 00064 * rune detonates, summoning monster. monster lands on nearby rune. 00065 * nearby rune detonates. This sort of recursion is expected and 00066 * proper. This code was causing needless crashes. */ 00067 if (recursion_depth >= 500) 00068 { 00069 LOG(llevDebug, "move_apply(): aborting recursion [trap arch %s, name %s; victim arch %s, name %s]\n", trap->arch->name, trap->name, victim->arch->name, victim->name); 00070 return; 00071 } 00072 00073 if (trap->head) 00074 { 00075 trap = trap->head; 00076 } 00077 00078 /* Trigger the TRIGGER event */ 00079 if (trigger_event(EVENT_TRIGGER, victim, trap, originator, NULL, 0, 0, 0, SCRIPT_FIX_NOTHING)) 00080 { 00081 return; 00082 } 00083 00084 recursion_depth++; 00085 00086 switch (trap->type) 00087 { 00088 /* these objects can trigger other objects connected to them. 00089 * We need to check them at map loading time and other special 00090 * events to be sure to have a 100% working map state. */ 00091 case BUTTON: 00092 case PEDESTAL: 00093 update_button(trap); 00094 break; 00095 00096 case TRIGGER_BUTTON: 00097 case TRIGGER_PEDESTAL: 00098 case TRIGGER_ALTAR: 00099 check_trigger(trap, victim); 00100 break; 00101 00102 case CHECK_INV: 00103 check_inv(victim, trap); 00104 break; 00105 00106 /* these objects trigger to but they are "instant". 00107 * We don't need to check them when loading. */ 00108 case ALTAR: 00109 /* sacrifice victim on trap */ 00110 apply_altar(trap, victim, originator); 00111 break; 00112 00113 case CONVERTER: 00114 if (!(flags & MOVE_APPLY_VANISHED)) 00115 { 00116 convert_item(victim, trap); 00117 } 00118 00119 break; 00120 00121 /* should be walk_on/fly_on only */ 00122 case SPINNER: 00123 if (victim->direction) 00124 { 00125 victim->direction = absdir(victim->direction + trap->direction); 00126 update_turn_face(victim); 00127 } 00128 00129 break; 00130 00131 case DIRECTOR: 00132 if (victim->direction) 00133 { 00134 victim->direction = trap->direction; 00135 update_turn_face(victim); 00136 } 00137 00138 break; 00139 00140 /* no need to hit anything */ 00141 case MMISSILE: 00142 if (IS_LIVE(victim) && !(flags&MOVE_APPLY_VANISHED)) 00143 { 00144 tag_t trap_tag = trap->count; 00145 hit_player(victim, trap->stats.dam, trap, AT_MAGIC); 00146 00147 if (!was_destroyed(trap, trap_tag)) 00148 { 00149 remove_ob(trap); 00150 } 00151 00152 check_walk_off(trap, NULL, MOVE_APPLY_VANISHED); 00153 } 00154 00155 break; 00156 00157 case THROWN_OBJ: 00158 if (trap->inv == NULL || (flags & MOVE_APPLY_VANISHED)) 00159 { 00160 break; 00161 } 00162 00163 /* fallthrough */ 00164 case ARROW: 00165 /* bad bug: monster throw a object, make a step forwards, step on object , 00166 * trigger this here and get hit by own missile - and will be own enemy. 00167 * Victim then is his own enemy and will start to kill herself (this is 00168 * removed) but we have not synced victim and his missile. To avoid senseless 00169 * action, we avoid hits here */ 00170 if ((IS_LIVE(victim) && trap->speed) && trap->owner != victim) 00171 { 00172 hit_with_arrow(trap, victim); 00173 } 00174 00175 break; 00176 00177 case BULLET: 00178 if ((QUERY_FLAG(victim, FLAG_NO_PASS) || IS_LIVE(victim)) && !(flags & MOVE_APPLY_VANISHED)) 00179 { 00180 check_fired_arch(trap); 00181 } 00182 00183 break; 00184 00185 case TRAPDOOR: 00186 { 00187 int max, sound_was_played; 00188 object *ab; 00189 00190 if ((flags & MOVE_APPLY_VANISHED)) 00191 { 00192 break; 00193 } 00194 00195 if (!trap->value) 00196 { 00197 sint32 tot; 00198 00199 for (ab = trap->above, tot = 0; ab != NULL; ab = ab->above) 00200 { 00201 if (!QUERY_FLAG(ab, FLAG_FLYING)) 00202 { 00203 tot += (ab->nrof ? ab->nrof : 1) * ab->weight + ab->carrying; 00204 } 00205 } 00206 00207 if (!(trap->value = (tot > trap->weight) ? 1 : 0)) 00208 { 00209 break; 00210 } 00211 00212 SET_ANIMATION(trap, (NUM_ANIMATIONS(trap) / NUM_FACINGS(trap)) * trap->direction + trap->value); 00213 update_object(trap, UP_OBJ_FACE); 00214 } 00215 00216 for (ab = trap->above, max = 100, sound_was_played = 0; --max && ab && !QUERY_FLAG(ab, FLAG_FLYING); ab = ab->above) 00217 { 00218 if (!sound_was_played) 00219 { 00220 play_sound_map(trap->map, CMD_SOUND_EFFECT, "fallhole.ogg", trap->x, trap->y, 0, 0); 00221 sound_was_played = 1; 00222 } 00223 00224 if (ab->type == PLAYER) 00225 { 00226 new_draw_info(0, COLOR_WHITE, ab, "You fall into a trapdoor!"); 00227 } 00228 00229 transfer_ob(ab, EXIT_X(trap), EXIT_Y(trap), trap->last_sp, ab, trap); 00230 } 00231 00232 break; 00233 } 00234 00235 case PIT: 00236 /* Pit not open? */ 00237 if ((flags & MOVE_APPLY_VANISHED) || trap->stats.wc > 0) 00238 { 00239 break; 00240 } 00241 00242 play_sound_map(victim->map, CMD_SOUND_EFFECT, "fallhole.ogg", victim->x, victim->y, 0, 0); 00243 00244 if (victim->type == PLAYER) 00245 { 00246 new_draw_info(0, COLOR_WHITE, victim, "You fall through the hole!\n"); 00247 } 00248 00249 transfer_ob(victim->head ? victim->head : victim, EXIT_X(trap), EXIT_Y(trap), trap->last_sp, victim, trap); 00250 00251 break; 00252 00253 case EXIT: 00254 /* If no map path specified, we assume it is the map path of the exit. */ 00255 if (!EXIT_PATH(trap)) 00256 { 00257 FREE_AND_ADD_REF_HASH(EXIT_PATH(trap), trap->map->path); 00258 } 00259 00260 if (!(flags & MOVE_APPLY_VANISHED) && victim->type == PLAYER && EXIT_PATH(trap) && EXIT_Y(trap) != -1 && EXIT_X(trap) != -1) 00261 { 00262 /* Basically, don't show exits leading to random maps the players output. */ 00263 if (trap->msg && strncmp(EXIT_PATH(trap), "/!", 2) && strncmp(EXIT_PATH(trap), "/random/", 8)) 00264 { 00265 new_draw_info(0, COLOR_NAVY, victim, trap->msg); 00266 } 00267 00268 enter_exit(victim, trap); 00269 } 00270 00271 break; 00272 00273 case SHOP_MAT: 00274 if (!(flags & MOVE_APPLY_VANISHED)) 00275 { 00276 apply_shop_mat(trap, victim); 00277 } 00278 00279 break; 00280 00281 /* Drop a certain amount of gold, and have one item identified */ 00282 case IDENTIFY_ALTAR: 00283 if (!(flags & MOVE_APPLY_VANISHED)) 00284 { 00285 apply_identify_altar(victim, trap, originator); 00286 } 00287 00288 break; 00289 00290 case SIGN: 00291 /* Only player should be able read signs */ 00292 if (victim->type == PLAYER) 00293 { 00294 apply_sign(victim, trap); 00295 } 00296 00297 break; 00298 00299 case CONTAINER: 00300 if (victim->type == PLAYER) 00301 { 00302 (void) esrv_apply_container(victim, trap); 00303 } 00304 00305 break; 00306 00307 case RUNE: 00308 if (!(flags & MOVE_APPLY_VANISHED) && trap->level && IS_LIVE(victim)) 00309 { 00310 spring_trap(trap, victim); 00311 } 00312 00313 break; 00314 00315 #if 0 00316 /* we don't have this atm. */ 00317 case DEEP_SWAMP: 00318 if (!(flags & MOVE_APPLY_VANISHED)) 00319 { 00320 walk_on_deep_swamp(trap, victim); 00321 } 00322 00323 break; 00324 #endif 00325 } 00326 00327 recursion_depth--; 00328 } 00329 00339 object *find_special_prayer_mark(object *op, int spell) 00340 { 00341 object *tmp; 00342 00343 for (tmp = op->inv; tmp; tmp = tmp->below) 00344 { 00345 if (tmp->type == FORCE && tmp->slaying && strcmp(tmp->slaying, "special prayer") == 0 && tmp->stats.sp == spell) 00346 { 00347 return tmp; 00348 } 00349 } 00350 00351 return NULL; 00352 } 00353 00358 static void insert_special_prayer_mark(object *op, int spell) 00359 { 00360 object *force = get_archetype("force"); 00361 force->speed = 0; 00362 update_ob_speed(force); 00363 FREE_AND_COPY_HASH(force->slaying, "special prayer"); 00364 force->stats.sp = spell; 00365 insert_ob_in_ob(force, op); 00366 } 00367 00373 void do_learn_spell(object *op, int spell, int special_prayer) 00374 { 00375 object *tmp = find_special_prayer_mark(op, spell); 00376 00377 if (op->type != PLAYER) 00378 { 00379 LOG(llevBug, "do_learn_spell(): not a player ->%s\n", op->name); 00380 return; 00381 } 00382 00383 /* Upgrade special prayers to normal prayers */ 00384 if (check_spell_known(op, spell)) 00385 { 00386 new_draw_info_format(0, COLOR_WHITE, op, "You already know the spell '%s'!", spells[spell].name); 00387 00388 if (special_prayer || !tmp) 00389 { 00390 LOG(llevBug, "do_learn_spell(): spell already known, but can't upgrade it\n"); 00391 return; 00392 } 00393 00394 remove_ob(tmp); 00395 return; 00396 } 00397 00398 /* Learn new spell/prayer */ 00399 if (tmp) 00400 { 00401 LOG(llevBug, "do_learn_spell(): spell unknown, but special prayer mark present\n"); 00402 remove_ob(tmp); 00403 } 00404 00405 play_sound_player_only(CONTR(op), CMD_SOUND_EFFECT, "learnspell.ogg", 0, 0, 0, 0); 00406 CONTR(op)->known_spells[CONTR(op)->nrofknownspells++] = spell; 00407 00408 if (CONTR(op)->nrofknownspells == 1) 00409 { 00410 CONTR(op)->chosen_spell = spell; 00411 } 00412 00413 /* For god-given spells the player gets a reminder-mark inserted, that 00414 * this spell must be removed on changing cults! */ 00415 if (special_prayer) 00416 { 00417 insert_special_prayer_mark(op, spell); 00418 } 00419 00420 send_spelllist_cmd(op, spells[spell].name, SPLIST_MODE_ADD); 00421 new_draw_info_format(0, COLOR_WHITE, op, "You have learned the spell %s!", spells[spell].name); 00422 } 00423 00428 void do_forget_spell(object *op, int spell) 00429 { 00430 object *tmp; 00431 int i; 00432 00433 if (op->type != PLAYER) 00434 { 00435 LOG(llevBug, "do_forget_spell(): Not a player: %s (%d).\n", query_name(op, NULL), spell); 00436 return; 00437 } 00438 00439 if (!check_spell_known(op, spell)) 00440 { 00441 LOG(llevBug, "do_forget_spell(): Spell %d not known.\n", spell); 00442 return; 00443 } 00444 00445 play_sound_player_only(CONTR(op), CMD_SOUND_EFFECT, "lose_some.ogg", 0, 0, 0, 0); 00446 new_draw_info_format(0, COLOR_WHITE, op, "You lose knowledge of %s.", spells[spell].name); 00447 00448 send_spelllist_cmd(op, spells[spell].name, SPLIST_MODE_REMOVE); 00449 tmp = find_special_prayer_mark(op, spell); 00450 00451 if (tmp) 00452 { 00453 remove_ob(tmp); 00454 } 00455 00456 for (i = 0; i < CONTR(op)->nrofknownspells; i++) 00457 { 00458 if (CONTR(op)->known_spells[i] == spell) 00459 { 00460 CONTR(op)->known_spells[i] = CONTR(op)->known_spells[--CONTR(op)->nrofknownspells]; 00461 return; 00462 } 00463 } 00464 00465 LOG(llevBug, "do_forget_spell(): Couldn't find spell %d.\n", spell); 00466 } 00467 00483 static int is_legal_2ways_exit(object *op, object *exit_ob) 00484 { 00485 object *tmp, *exit_owner; 00486 player *pp; 00487 mapstruct *exitmap; 00488 00489 /* This is not a two way, so it is legal */ 00490 if (exit_ob->stats.exp != 1) 00491 { 00492 return 1; 00493 } 00494 00495 /* To know if an exit has a correspondant, we look at 00496 * all the exits in destination and try to find one with same path as 00497 * the current exit's position */ 00498 if (!strncmp(EXIT_PATH(exit_ob), settings.localdir, strlen(settings.localdir))) 00499 { 00500 exitmap = ready_map_name(EXIT_PATH(exit_ob), MAP_NAME_SHARED | MAP_PLAYER_UNIQUE); 00501 } 00502 else 00503 { 00504 exitmap = ready_map_name(EXIT_PATH(exit_ob), MAP_NAME_SHARED); 00505 } 00506 00507 if (exitmap) 00508 { 00509 tmp = get_map_ob(exitmap, EXIT_X(exit_ob), EXIT_Y(exit_ob)); 00510 00511 if (!tmp) 00512 { 00513 return 0; 00514 } 00515 00516 for ((tmp = get_map_ob(exitmap, EXIT_X(exit_ob), EXIT_Y(exit_ob))); tmp; tmp = tmp->above) 00517 { 00518 /* Not an exit */ 00519 if (tmp->type != EXIT) 00520 { 00521 continue; 00522 } 00523 00524 /* Not a valid exit */ 00525 if (!EXIT_PATH(tmp)) 00526 { 00527 continue; 00528 } 00529 00530 /* Not in the same place */ 00531 if ((EXIT_X(tmp) != exit_ob->x) || (EXIT_Y(tmp) != exit_ob->y)) 00532 { 00533 continue; 00534 } 00535 00536 /* Not in the same map */ 00537 if (!exit_ob->race && exit_ob->map->path == EXIT_PATH(tmp)) 00538 { 00539 continue; 00540 } 00541 00542 /* From here we have found the exit is valid. However we do 00543 * here the check of the exit owner. It is important for the 00544 * town portals to prevent strangers from visiting your apartments */ 00545 /* No owner, free for all! */ 00546 if (!exit_ob->race) 00547 { 00548 return 1; 00549 } 00550 00551 exit_owner = NULL; 00552 00553 for (pp = first_player; pp; pp = pp->next) 00554 { 00555 if (!pp->ob) 00556 { 00557 continue; 00558 } 00559 00560 if (pp->ob->name != exit_ob->race) 00561 { 00562 continue; 00563 } 00564 00565 /* We found a player which correspond to the player name */ 00566 exit_owner = pp->ob; 00567 break; 00568 } 00569 00570 /* No more owner */ 00571 if (!exit_owner) 00572 { 00573 return 0; 00574 } 00575 00576 /* It is your exit */ 00577 if (CONTR(exit_owner) == CONTR(op)) 00578 { 00579 return 1; 00580 } 00581 00582 if (exit_owner && CONTR(op) && (!CONTR(exit_owner)->party || CONTR(exit_owner)->party != CONTR(op)->party)) 00583 { 00584 return 0; 00585 } 00586 00587 return 1; 00588 } 00589 } 00590 00591 return 0; 00592 } 00593 00606 int manual_apply(object *op, object *tmp, int aflag) 00607 { 00608 if (tmp->head) 00609 { 00610 tmp = tmp->head; 00611 } 00612 00613 if (op->type == PLAYER) 00614 { 00615 CONTR(op)->praying = 0; 00616 } 00617 00618 if (QUERY_FLAG(tmp, FLAG_UNPAID) && !QUERY_FLAG(tmp, FLAG_APPLIED)) 00619 { 00620 if (op->type == PLAYER) 00621 { 00622 new_draw_info(0, COLOR_WHITE, op, "You should pay for it first."); 00623 return 1; 00624 } 00625 /* Monsters just skip unpaid items */ 00626 else 00627 { 00628 return 0; 00629 } 00630 } 00631 00632 /* Monsters must not apply random chests, nor magic_mouths with a counter */ 00633 if (op->type != PLAYER && tmp->type == TREASURE) 00634 { 00635 return 0; 00636 } 00637 00638 /* Trigger the APPLY event */ 00639 if (!(aflag & AP_NO_EVENT) && trigger_event(EVENT_APPLY, op, tmp, NULL, NULL, aflag, 0, 0, SCRIPT_FIX_ACTIVATOR)) 00640 { 00641 return 1; 00642 } 00643 00644 /* Trigger the map-wide apply event. */ 00645 if (!(aflag & AP_NO_EVENT) && op->map && op->map->events) 00646 { 00647 int retval = trigger_map_event(MEVENT_APPLY, op->map, op, tmp, NULL, NULL, aflag); 00648 00649 if (retval) 00650 { 00651 return retval - 1; 00652 } 00653 } 00654 00655 aflag &= ~AP_NO_EVENT; 00656 00657 /* Control apply by controlling a set exp object level or player exp level */ 00658 if (tmp->item_level) 00659 { 00660 int tmp_lev; 00661 00662 if (tmp->item_skill) 00663 { 00664 tmp_lev = find_skill_exp_level(op, tmp->item_skill); 00665 } 00666 else 00667 { 00668 tmp_lev = op->level; 00669 } 00670 00671 if (tmp->item_level > tmp_lev) 00672 { 00673 new_draw_info(0, COLOR_WHITE, op, "The item level is too high to apply."); 00674 return 1; 00675 } 00676 } 00677 00678 switch (tmp->type) 00679 { 00680 case HOLY_ALTAR: 00681 new_draw_info_format(0, COLOR_WHITE, op, "You touch the %s.", tmp->name); 00682 00683 if (change_skill(op, SK_PRAYING)) 00684 { 00685 pray_at_altar(op, tmp); 00686 } 00687 else 00688 { 00689 new_draw_info(0, COLOR_WHITE, op, "Nothing happens. It seems you miss the right skill."); 00690 } 00691 00692 return 1; 00693 break; 00694 00695 case HANDLE: 00696 new_draw_info_format(0, COLOR_WHITE, op, "You turn the %s.", tmp->name); 00697 play_sound_map(op->map, CMD_SOUND_EFFECT, "pull.ogg", op->x, op->y, 0, 0); 00698 tmp->value = tmp->value ? 0 : 1; 00699 SET_ANIMATION(tmp, ((NUM_ANIMATIONS(tmp) / NUM_FACINGS(tmp)) * tmp->direction) + tmp->value); 00700 update_object(tmp, UP_OBJ_FACE); 00701 push_button(tmp); 00702 00703 return 1; 00704 00705 case TRIGGER: 00706 if (check_trigger(tmp, op)) 00707 { 00708 new_draw_info_format(0, COLOR_WHITE, op, "You turn the %s.", tmp->name); 00709 play_sound_map(tmp->map, CMD_SOUND_EFFECT, "pull.ogg", tmp->x, tmp->y, 0, 0); 00710 } 00711 else 00712 { 00713 new_draw_info_format(0, COLOR_WHITE, op, "The %s doesn't move.", tmp->name); 00714 } 00715 00716 return 1; 00717 00718 case EXIT: 00719 if (op->type != PLAYER || !tmp->map) 00720 { 00721 return 0; 00722 } 00723 00724 /* If no map path specified, we assume it is the map path of the exit. */ 00725 if (!EXIT_PATH(tmp)) 00726 { 00727 FREE_AND_ADD_REF_HASH(EXIT_PATH(tmp), tmp->map->path); 00728 } 00729 00730 if (!EXIT_PATH(tmp) || !is_legal_2ways_exit(op, tmp) || (EXIT_Y(tmp) == -1 && EXIT_X(tmp) == -1)) 00731 { 00732 new_draw_info_format(0, COLOR_WHITE, op, "The %s is closed.", query_name(tmp, NULL)); 00733 } 00734 else 00735 { 00736 /* Don't display messages for random maps. */ 00737 if (tmp->msg && strncmp(EXIT_PATH(tmp), "/!", 2) && strncmp(EXIT_PATH(tmp), "/random/", 8)) 00738 { 00739 new_draw_info(0, COLOR_NAVY, op, tmp->msg); 00740 } 00741 00742 enter_exit(op, tmp); 00743 } 00744 00745 return 1; 00746 00747 case SIGN: 00748 apply_sign(op, tmp); 00749 return 1; 00750 00751 case BOOK: 00752 if (op->type == PLAYER) 00753 { 00754 apply_book(op, tmp); 00755 return 1; 00756 } 00757 00758 return 0; 00759 00760 case SKILLSCROLL: 00761 if (op->type == PLAYER) 00762 { 00763 apply_skillscroll(op, tmp); 00764 return 1; 00765 } 00766 00767 return 0; 00768 00769 case SPELLBOOK: 00770 if (op->type == PLAYER) 00771 { 00772 apply_spellbook(op, tmp); 00773 return 1; 00774 } 00775 00776 return 0; 00777 00778 case SCROLL: 00779 apply_scroll(op, tmp); 00780 return 1; 00781 00782 case POTION: 00783 (void) apply_potion(op, tmp); 00784 return 1; 00785 00786 case LIGHT_APPLY: 00787 apply_player_light(op, tmp); 00788 return 1; 00789 00790 case LIGHT_REFILL: 00791 apply_player_light_refill(op, tmp); 00792 return 1; 00793 00794 /* Eneq(@csd.uu.se): Handle apply on containers. */ 00795 case CLOSE_CON: 00796 if (op->type == PLAYER) 00797 { 00798 (void) esrv_apply_container(op, tmp->env); 00799 } 00800 00801 return 1; 00802 00803 case CONTAINER: 00804 if (op->type == PLAYER) 00805 { 00806 (void) esrv_apply_container(op, tmp); 00807 } 00808 00809 return 1; 00810 00811 case TREASURE: 00812 apply_treasure(op, tmp); 00813 return 1; 00814 00815 case WEAPON: 00816 case ARMOUR: 00817 case BOOTS: 00818 case GLOVES: 00819 case AMULET: 00820 case GIRDLE: 00821 case BRACERS: 00822 case SHIELD: 00823 case HELMET: 00824 case RING: 00825 case CLOAK: 00826 case WAND: 00827 case ROD: 00828 case HORN: 00829 case SKILL: 00830 case BOW: 00831 case SKILL_ITEM: 00832 /* Not in inventory */ 00833 if (tmp->env != op) 00834 { 00835 return 2; 00836 } 00837 00838 (void) apply_special(op, tmp, aflag); 00839 return 1; 00840 00841 case DRINK: 00842 case FOOD: 00843 case FLESH: 00844 apply_food(op, tmp); 00845 return 1; 00846 00847 case POISON: 00848 apply_poison(op, tmp); 00849 return 1; 00850 00851 case SAVEBED: 00852 if (op->type == PLAYER) 00853 { 00854 apply_savebed(op); 00855 return 1; 00856 } 00857 00858 return 0; 00859 00860 case ARMOUR_IMPROVER: 00861 if (op->type == PLAYER) 00862 { 00863 apply_armour_improver(op, tmp); 00864 return 1; 00865 } 00866 00867 return 0; 00868 00869 case WEAPON_IMPROVER: 00870 apply_weapon_improver(op, tmp); 00871 return 1; 00872 00873 case CLOCK: 00874 if (op->type == PLAYER) 00875 { 00876 timeofday_t tod; 00877 00878 get_tod(&tod); 00879 new_draw_info_format(0, COLOR_WHITE, op, "It is %d minute%s past %d o'clock %s.", tod.minute, ((tod.minute == 1) ? "" : "s"), ((tod.hour % (HOURS_PER_DAY / 2) == 0) ? (HOURS_PER_DAY / 2) : ((tod.hour) % (HOURS_PER_DAY / 2))), ((tod.hour >= (HOURS_PER_DAY / 2)) ? "pm" : "am")); 00880 play_sound_player_only(CONTR(op), CMD_SOUND_EFFECT, "clock.ogg", 0, 0, 0, 0); 00881 return 1; 00882 } 00883 00884 return 0; 00885 00886 case POWER_CRYSTAL: 00887 apply_power_crystal(op, tmp); 00888 return 1; 00889 00890 /* For lighting torches/lanterns/etc */ 00891 case LIGHTER: 00892 if (op->type == PLAYER) 00893 { 00894 apply_lighter(op, tmp); 00895 return 1; 00896 } 00897 00898 return 0; 00899 00900 case COMPASS: 00901 if (op->type == PLAYER) 00902 { 00903 const char *direction_names[] = {"north", "northeast", "east", "southeast", "south", "southwest", "west", "northwest"}; 00904 00905 new_draw_info_format(0, COLOR_WHITE, op, "You are facing %s.", direction_names[absdir(op->facing) - 1]); 00906 return 1; 00907 } 00908 00909 return 0; 00910 00911 /* So the below default case doesn't execute for these objects, 00912 * even if they have message. */ 00913 case DOOR: 00914 return 0; 00915 00916 /* Nothing from the above... but show a message if it has one. */ 00917 default: 00918 if (tmp->msg) 00919 { 00920 new_draw_info(0, COLOR_WHITE, op, tmp->msg); 00921 return 1; 00922 } 00923 00924 return 0; 00925 } 00926 } 00927 00941 int player_apply(object *pl, object *op, int aflag, int quiet) 00942 { 00943 int tmp; 00944 00945 if (op->env == NULL && QUERY_FLAG(pl, FLAG_FLYING)) 00946 { 00947 /* Player is flying and applying object not in inventory */ 00948 if (!QUERY_FLAG(pl, FLAG_WIZ) && !QUERY_FLAG(op, FLAG_FLYING) && !QUERY_FLAG(op, FLAG_FLY_ON)) 00949 { 00950 new_draw_info(0, COLOR_WHITE, pl, "But you are floating high above the ground!"); 00951 return 0; 00952 } 00953 } 00954 00955 if (op->type != PLAYER && QUERY_FLAG(op, FLAG_WAS_WIZ) && !QUERY_FLAG(pl, FLAG_WAS_WIZ)) 00956 { 00957 play_sound_map(pl->map, CMD_SOUND_EFFECT, "explosion.ogg", pl->x, pl->y, 0, 0); 00958 new_draw_info(0, COLOR_WHITE, pl, "The object disappears in a puff of smoke!"); 00959 new_draw_info(0, COLOR_WHITE, pl, "It must have been an illusion."); 00960 remove_ob(op); 00961 check_walk_off(op, NULL, MOVE_APPLY_VANISHED); 00962 return 1; 00963 } 00964 00965 tmp = manual_apply(pl, op, aflag); 00966 00967 if (!quiet) 00968 { 00969 if (tmp == 0) 00970 { 00971 new_draw_info_format(0, COLOR_WHITE, pl, "I don't know how to apply the %s.", query_name(op, NULL)); 00972 } 00973 else if (tmp == 2) 00974 { 00975 new_draw_info_format(0, COLOR_WHITE, pl, "You must get it first!\n"); 00976 } 00977 } 00978 00979 return tmp; 00980 } 00981 00988 void player_apply_below(object *pl) 00989 { 00990 object *tmp, *next; 00991 int floors; 00992 00993 if (pl->type != PLAYER) 00994 { 00995 LOG(llevBug, "player_apply_below() called for non player object >%s<\n", query_name(pl, NULL)); 00996 return; 00997 } 00998 00999 tmp = pl->below; 01000 01001 /* This is perhaps more complicated. However, I want to make sure that 01002 * we don't use a corrupt pointer for the next object, so we get the 01003 * next object in the stack before applying. This is can only be a 01004 * problem if player_apply() has a bug in that it uses the object but does 01005 * not return a proper value. */ 01006 for (floors = 0; tmp != NULL; tmp = next) 01007 { 01008 next = tmp->below; 01009 01010 if (QUERY_FLAG(tmp, FLAG_IS_FLOOR)) 01011 { 01012 floors++; 01013 } 01014 /* Process only floor objects after first floor object */ 01015 else if (floors > 0) 01016 { 01017 return; 01018 } 01019 01020 if (!IS_INVISIBLE(tmp, pl) || QUERY_FLAG(tmp, FLAG_WALK_ON) || QUERY_FLAG(tmp, FLAG_FLY_ON)) 01021 { 01022 if (player_apply(pl, tmp, 0, 1) == 1) 01023 { 01024 return; 01025 } 01026 } 01027 01028 /* Process at most two floor objects */ 01029 if (floors >= 2) 01030 { 01031 return; 01032 } 01033 } 01034 } 01035 01041 static int apply_check_item_power(object *who, const object *op) 01042 { 01043 if (who->type != PLAYER) 01044 { 01045 return 1; 01046 } 01047 01048 if (op->item_power == 0 || op->item_power + CONTR(who)->item_power <= settings.item_power_factor * who->level) 01049 { 01050 return 1; 01051 } 01052 01053 new_draw_info(0, COLOR_WHITE, who, "Equipping that combined with other items would consume your soul!"); 01054 01055 return 0; 01056 } 01057 01071 int apply_special(object *who, object *op, int aflags) 01072 { 01073 int basic_flag = aflags & AP_BASIC_FLAGS; 01074 int tmp_flag = 0, i; 01075 object *tmp; 01076 char buf[HUGE_BUF]; 01077 01078 if (who == NULL) 01079 { 01080 LOG(llevBug, "apply_special() from object without environment.\n"); 01081 return 1; 01082 } 01083 01084 /* op is not in inventory */ 01085 if (op->env != who) 01086 { 01087 return 1; 01088 } 01089 01090 /* Needs to be initialized */ 01091 buf[0] = '\0'; 01092 01093 if (!QUERY_FLAG(op, FLAG_APPLIED)) 01094 { 01095 if (!apply_check_item_power(who, op)) 01096 { 01097 return 1; 01098 } 01099 } 01100 else 01101 { 01102 /* Always apply, so no reason to unapply */ 01103 if (basic_flag == AP_APPLY) 01104 { 01105 return 0; 01106 } 01107 01108 if (!(aflags & AP_IGNORE_CURSE) && (QUERY_FLAG(op, FLAG_CURSED) || QUERY_FLAG(op, FLAG_DAMNED))) 01109 { 01110 new_draw_info_format(0, COLOR_WHITE, who, "No matter how hard you try, you just can't remove it!"); 01111 return 1; 01112 } 01113 01114 if (QUERY_FLAG(op, FLAG_PERM_CURSED)) 01115 { 01116 SET_FLAG(op, FLAG_CURSED); 01117 } 01118 01119 if (QUERY_FLAG(op, FLAG_PERM_DAMNED)) 01120 { 01121 SET_FLAG(op, FLAG_DAMNED); 01122 } 01123 01124 CLEAR_FLAG(op, FLAG_APPLIED); 01125 01126 switch (op->type) 01127 { 01128 case WEAPON: 01129 (void) change_abil(who, op); 01130 CLEAR_FLAG(who, FLAG_READY_WEAPON); 01131 snprintf(buf, sizeof(buf), "You unwield %s.", query_name(op, NULL)); 01132 break; 01133 01134 /* Allows objects to impart skills */ 01135 case SKILL: 01136 if (op != who->chosen_skill) 01137 { 01138 LOG(llevBug, "apply_special(): applied skill is not chosen skill\n"); 01139 } 01140 01141 if (who->type == PLAYER) 01142 { 01143 CONTR(who)->shoottype = range_none; 01144 01145 if (!IS_INVISIBLE(op, who)) 01146 { 01147 /* It's a tool, need to unlink it */ 01148 unlink_skill(op); 01149 new_draw_info_format(0, COLOR_WHITE, who, "You stop using the %s.", query_name(op, NULL)); 01150 new_draw_info_format(0, COLOR_WHITE, who, "You can no longer use the skill: %s.", skills[op->stats.sp].name); 01151 } 01152 } 01153 01154 (void) change_abil(who, op); 01155 who->chosen_skill = NULL; 01156 buf[0] = '\0'; 01157 break; 01158 01159 case ARMOUR: 01160 case HELMET: 01161 case SHIELD: 01162 case RING: 01163 case BOOTS: 01164 case GLOVES: 01165 case AMULET: 01166 case GIRDLE: 01167 case BRACERS: 01168 case CLOAK: 01169 change_abil(who, op); 01170 snprintf(buf, sizeof(buf), "You unwear %s.", query_name(op, NULL)); 01171 break; 01172 01173 case BOW: 01174 case WAND: 01175 case ROD: 01176 case HORN: 01177 snprintf(buf, sizeof(buf), "You unready %s.", query_name(op, NULL)); 01178 01179 if (who->type == PLAYER) 01180 { 01181 CONTR(who)->shoottype = range_none; 01182 } 01183 01184 break; 01185 01186 default: 01187 snprintf(buf, sizeof(buf), "You unapply %s.", query_name(op, NULL)); 01188 break; 01189 } 01190 01191 if (buf[0] != '\0' && who->type == PLAYER) 01192 { 01193 new_draw_info(0, COLOR_WHITE, who, buf); 01194 } 01195 01196 fix_player(who); 01197 01198 if (!(aflags & AP_NO_MERGE)) 01199 { 01200 tag_t del_tag = op->count; 01201 object *cont = op->env; 01202 tmp = merge_ob(op, NULL); 01203 01204 if (who->type == PLAYER) 01205 { 01206 /* It was merged */ 01207 if (tmp) 01208 { 01209 esrv_del_item(CONTR(who), del_tag, cont); 01210 op = tmp; 01211 } 01212 01213 esrv_send_item (who, op); 01214 } 01215 } 01216 01217 return 0; 01218 } 01219 01220 if (basic_flag == AP_UNAPPLY) 01221 { 01222 return 0; 01223 } 01224 01225 i = 0; 01226 01227 if (op->type == WAND || op->type == ROD || op->type == HORN) 01228 { 01229 tmp_flag = 1; 01230 } 01231 01232 /* This goes through and checks to see if the player already has 01233 * something of that type applied - if so, unapply it. */ 01234 for (tmp = who->inv; tmp != NULL; tmp = tmp->below) 01235 { 01236 if ((tmp->type == op->type || (tmp_flag && (tmp->type == WAND || tmp->type == ROD || tmp->type == HORN))) && QUERY_FLAG(tmp, FLAG_APPLIED) && tmp != op) 01237 { 01238 if (tmp->type == RING && !i) 01239 { 01240 i = 1; 01241 } 01242 else if (apply_special(who, tmp, 0)) 01243 { 01244 return 1; 01245 } 01246 } 01247 } 01248 01249 if (op->nrof > 1) 01250 { 01251 tmp = get_split_ob(op, op->nrof - 1, NULL, 0); 01252 } 01253 else 01254 { 01255 tmp = NULL; 01256 } 01257 01258 switch (op->type) 01259 { 01260 case WEAPON: 01261 { 01262 if (!QUERY_FLAG(who, FLAG_USE_WEAPON)) 01263 { 01264 new_draw_info_format(0, COLOR_WHITE, who, "You can't use %s.", query_name(op, NULL)); 01265 01266 if (tmp != NULL) 01267 { 01268 (void) insert_ob_in_ob(tmp, who); 01269 } 01270 01271 return 1; 01272 } 01273 01274 if (!check_weapon_power(who, op->last_eat)) 01275 { 01276 new_draw_info(0, COLOR_WHITE, who, "That weapon is too powerful for you to use.\nIt would consume your soul!"); 01277 01278 if (tmp != NULL) 01279 { 01280 (void) insert_ob_in_ob(tmp, who); 01281 } 01282 01283 return 1; 01284 } 01285 01286 if (op->level && (strncmp(op->name, who->name, strlen(who->name)))) 01287 { 01288 /* If the weapon does not have the name as the character, 01289 * can't use it (Ragnarok's sword attempted to be used by 01290 * Foo: won't work). */ 01291 new_draw_info(0, COLOR_WHITE, who, "The weapon does not recognize you as its owner."); 01292 01293 if (tmp != NULL) 01294 { 01295 (void) insert_ob_in_ob(tmp, who); 01296 } 01297 01298 return 1; 01299 } 01300 01301 /* If we have applied a shield, don't allow applying of polearm or two-handed weapons */ 01302 if ((op->sub_type >= WEAP_POLE_IMPACT || op->sub_type >= WEAP_2H_IMPACT) && who->type == PLAYER && CONTR(who) && CONTR(who)->equipment[PLAYER_EQUIP_SHIELD]) 01303 { 01304 new_draw_info(0, COLOR_WHITE, who, "You can't wield this weapon and a shield."); 01305 01306 if (tmp != NULL) 01307 { 01308 (void) insert_ob_in_ob(tmp, who); 01309 } 01310 01311 return 1; 01312 } 01313 01314 if (!check_skill_to_apply(who, op)) 01315 { 01316 if (tmp != NULL) 01317 { 01318 (void) insert_ob_in_ob(tmp,who); 01319 } 01320 01321 return 1; 01322 } 01323 01324 snprintf(buf, sizeof(buf), "You wield %s.", query_name(op, NULL)); 01325 SET_FLAG(op, FLAG_APPLIED); 01326 SET_FLAG(who, FLAG_READY_WEAPON); 01327 (void) change_abil(who, op); 01328 break; 01329 } 01330 01331 case SHIELD: 01332 /* Don't allow polearm or two-handed weapons with a shield */ 01333 if ((who->type == PLAYER && CONTR(who) && CONTR(who)->equipment[PLAYER_EQUIP_WEAPON]) && (CONTR(who)->equipment[PLAYER_EQUIP_WEAPON]->sub_type >= WEAP_POLE_IMPACT || CONTR(who)->equipment[PLAYER_EQUIP_WEAPON]->sub_type >= WEAP_2H_IMPACT)) 01334 { 01335 new_draw_info(0, COLOR_WHITE, who, "You can't use a shield with your current weapon."); 01336 01337 if (tmp != NULL) 01338 { 01339 (void) insert_ob_in_ob(tmp, who); 01340 } 01341 01342 return 1; 01343 } 01344 01345 case ARMOUR: 01346 case HELMET: 01347 case BOOTS: 01348 case GLOVES: 01349 case GIRDLE: 01350 case BRACERS: 01351 case CLOAK: 01352 if (!QUERY_FLAG(who, FLAG_USE_ARMOUR)) 01353 { 01354 new_draw_info_format(0, COLOR_WHITE, who, "You can't use %s.", query_name(op, NULL)); 01355 01356 if (tmp != NULL) 01357 { 01358 (void) insert_ob_in_ob(tmp, who); 01359 } 01360 01361 return 1; 01362 } 01363 01364 case RING: 01365 case AMULET: 01366 snprintf(buf, sizeof(buf), "You wear %s.", query_name(op, NULL)); 01367 SET_FLAG(op, FLAG_APPLIED); 01368 (void) change_abil(who, op); 01369 break; 01370 01371 /* This part is needed for skill-tools */ 01372 case SKILL: 01373 if (who->chosen_skill) 01374 { 01375 LOG(llevBug, "apply_special(): can't apply two skills\n"); 01376 return 1; 01377 } 01378 01379 if (who->type == PLAYER) 01380 { 01381 CONTR(who)->shoottype = range_skill; 01382 01383 if (!IS_INVISIBLE(op, who)) 01384 { 01385 /* for tools */ 01386 if (op->exp_obj) 01387 { 01388 LOG(llevBug, "apply_special(SKILL): found unapplied tool with experience object\n"); 01389 } 01390 else 01391 { 01392 (void) link_player_skill(who, op); 01393 } 01394 01395 new_draw_info_format(0, COLOR_WHITE, who, "You ready %s.", query_name(op, NULL)); 01396 new_draw_info_format(0, COLOR_WHITE, who, "You can now use the skill: %s.", skills[op->stats.sp].name); 01397 } 01398 else 01399 { 01400 send_ready_skill(who, skills[op->stats.sp].name); 01401 } 01402 } 01403 01404 SET_FLAG(op, FLAG_APPLIED); 01405 (void) change_abil(who, op); 01406 who->chosen_skill = op; 01407 buf[0] = '\0'; 01408 break; 01409 01410 case WAND: 01411 case ROD: 01412 case HORN: 01413 case BOW: 01414 if (!check_skill_to_apply(who, op)) 01415 { 01416 return 1; 01417 } 01418 01419 new_draw_info_format(0, COLOR_WHITE, who, "You ready %s.", query_name(op, NULL)); 01420 SET_FLAG(op, FLAG_APPLIED); 01421 01422 if (op->type == BOW) 01423 { 01424 new_draw_info_format(0, COLOR_WHITE, who, "You will now fire %s with %s.", op->race ? op->race : "nothing", query_name(op, NULL)); 01425 } 01426 01427 break; 01428 01429 default: 01430 snprintf(buf, sizeof(buf), "You apply %s.", query_name(op, NULL)); 01431 } 01432 01433 if (!QUERY_FLAG(op, FLAG_APPLIED)) 01434 { 01435 SET_FLAG(op, FLAG_APPLIED); 01436 } 01437 01438 if (buf[0] != '\0') 01439 { 01440 new_draw_info(0, COLOR_WHITE, who, buf); 01441 } 01442 01443 if (tmp != NULL) 01444 { 01445 tmp = insert_ob_in_ob(tmp, who); 01446 } 01447 01448 fix_player(who); 01449 01450 if (op->type != WAND && who->type == PLAYER) 01451 { 01452 SET_FLAG(op, FLAG_BEEN_APPLIED); 01453 } 01454 01455 if (QUERY_FLAG(op, FLAG_PERM_CURSED)) 01456 { 01457 SET_FLAG(op, FLAG_CURSED); 01458 } 01459 01460 if (QUERY_FLAG(op, FLAG_PERM_DAMNED)) 01461 { 01462 SET_FLAG(op, FLAG_DAMNED); 01463 } 01464 01465 if (QUERY_FLAG(op, FLAG_CURSED) || QUERY_FLAG(op, FLAG_DAMNED)) 01466 { 01467 if (who->type == PLAYER) 01468 { 01469 new_draw_info(0, COLOR_WHITE, who, "Oops, it feels deadly cold!"); 01470 } 01471 } 01472 01473 if (who->type == PLAYER) 01474 { 01475 /* If multiple objects were applied, update both slots */ 01476 if (tmp) 01477 { 01478 esrv_send_item(who, tmp); 01479 } 01480 01481 esrv_send_item(who, op); 01482 } 01483 01484 return 0; 01485 } 01486 01494 int monster_apply_special(object *who, object *op, int aflags) 01495 { 01496 if (QUERY_FLAG(op, FLAG_UNPAID) && !QUERY_FLAG(op, FLAG_APPLIED)) 01497 { 01498 return 1; 01499 } 01500 01501 return apply_special(who, op, aflags); 01502 }
1.7.4