Atrinik Server 2.5
server/apply.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 
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 }