Crossfire Server, Branch 1.12  R12190
apply.c
Go to the documentation of this file.
00001 /*
00002  * static char *rcsid_apply_c =
00003  *   "$Id: apply.c 11578 2009-02-23 22:02:27Z lalo $";
00004  */
00005 /*
00006   CrossFire, A Multiplayer game for X-windows
00007 
00008   Copyright (C) 2006 Mark Wedel & Crossfire Development Team
00009   Copyright (C) 1992 Frank Tore Johansen
00010 
00011   This program is free software; you can redistribute it and/or modify
00012   it under the terms of the GNU General Public License as published by
00013   the Free Software Foundation; either version 2 of the License, or
00014   (at your option) any later version.
00015 
00016   This program is distributed in the hope that it will be useful,
00017   but WITHOUT ANY WARRANTY; without even the implied warranty of
00018   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00019   GNU General Public License for more details.
00020 
00021   You should have received a copy of the GNU General Public License
00022   along with this program; if not, write to the Free Software
00023   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
00024 
00025   The authors can be reached via e-mail to crossfire-devel@real-time.com
00026 */
00027 
00033 #include <global.h>
00034 #include <living.h>
00035 #include <spells.h>
00036 #include <skills.h>
00037 #include <tod.h>
00038 
00039 #ifndef __CEXTRACT__
00040 #include <sproto.h>
00041 #endif
00042 
00043 /* Want this regardless of rplay. */
00044 #include <sounds.h>
00045 
00046 /* need math lib for double-precision and pow() in dragon_eat_flesh() */
00047 #include <math.h>
00048 
00064 int transport_can_hold(const object *transport, const object *op, int nrof) {
00065     if ((op->weight*nrof+transport->carrying) > transport->weight_limit)
00066         return 0;
00067     else
00068         return 1;
00069 }
00070 
00081 int should_director_abort(object *op, object *victim) {
00082     int arch_flag, name_flag, race_flag;
00083     /* Get flags to determine what of arch, name, and race should be
00084      * checked. This is stored in subtype, and is a bitmask, the LSB
00085      * is the arch flag, the next is the name flag, and the last is
00086      * the race flag. Also note, if subtype is set to zero, that also
00087      * goes to defaults of all affecting it. Examples:
00088      * subtype 1: only arch
00089      * subtype 3: arch or name
00090      * subtype 5: arch or race
00091      * subtype 7: all three
00092      */
00093     if (op->subtype) {
00094         arch_flag = (op->subtype&1);
00095         name_flag = (op->subtype&2);
00096         race_flag = (op->subtype&4);
00097     } else {
00098         arch_flag = 1;
00099         name_flag = 1;
00100         race_flag = 1;
00101     }
00102     /* If the director has race set, only affect objects with a arch,
00103      * name or race that matches.
00104      */
00105     if ((op->race)
00106     && ((!(victim->arch && arch_flag && victim->arch->name) || strcmp(op->race, victim->arch->name)))
00107     && ((!(victim->name && name_flag) || strcmp(op->race, victim->name)))
00108     && ((!(victim->race && race_flag) || strcmp(op->race, victim->race)))) {
00109         return 1;
00110     }
00111 
00112     /* If the director has slaying set, only affect objects where none
00113      * of arch, name, or race match.
00114      */
00115     if ((op->slaying)
00116     && (((victim->arch && arch_flag && victim->arch->name && !strcmp(op->slaying, victim->arch->name)))
00117         || ((victim->name && name_flag && !strcmp(op->slaying, victim->name)))
00118         || ((victim->race && race_flag && !strcmp(op->slaying, victim->race))))) {
00119         return 1;
00120     }
00121     return 0;
00122 }
00123 
00131 void handle_apply_yield(object *tmp) {
00132     const char *yield;
00133 
00134     yield = get_ob_key_value(tmp, "on_use_yield");
00135     if (yield != NULL) {
00136         object *drop = create_archetype(yield);
00137         if (tmp->env) {
00138             drop = insert_ob_in_ob(drop, tmp->env);
00139         } else {
00140             drop->x = tmp->x;
00141             drop->y = tmp->y;
00142             insert_ob_in_map(drop, tmp->map, tmp, INS_BELOW_ORIGINATOR);
00143         }
00144     }
00145 }
00146 
00147 int check_weapon_power(const object *who, int improvs);
00148 
00160 int set_object_face_main(object *op) {
00161     int newface = op->arch->clone.face->number;
00162     sstring saved = get_ob_key_value(op, "face_closed");
00163 
00164     if (saved) {
00165         newface = find_face(saved, newface);
00166     }
00167     if (newface && op->face != &new_faces[newface]) {
00168         op->face = &new_faces[newface];
00169         return TRUE;
00170     }
00171     return FALSE;
00172 }
00173 
00185 static int set_object_face_other(object *op) {
00186     sstring custom;
00187     int newface = 0;
00188 
00189     if (op->face && op->other_arch && op->other_arch->clone.face)
00190         newface = op->other_arch->clone.face->number;
00191 
00192     if (op->face != op->arch->clone.face) {
00193         /* object has a custom face, save it so it gets correctly restored later. */
00194         set_ob_key_value(op, "face_closed", op->face->name, 1);
00195     }
00196 
00197     custom = get_ob_key_value(op, "face_opened");
00198     if (custom) {
00199         newface = find_face(custom, newface);
00200     }
00201 
00202     if (newface && op->face->number != newface) {
00203         op->face = &new_faces[newface];
00204         return TRUE;
00205     }
00206     return FALSE;
00207 }
00208 
00230 int apply_container(object *op, object *sack) {
00231     char name_sack[MAX_BUF], name_tmp[MAX_BUF];
00232     object *tmp = op->container;
00233 
00234     if (op->type != PLAYER)
00235         return 0; /* This might change */
00236 
00237     if (sack == NULL || sack->type != CONTAINER) {
00238         LOG(llevError, "apply_container: %s is not container!\n", sack ? sack->name : "NULL");
00239         return 0;
00240     }
00241 
00242     /* If we have a currently open container, then it needs
00243      * to be closed in all cases if we are opening this one up.
00244      * We then fall through if appropriate for openening the new
00245      * container.
00246      */
00247     if (op->container && QUERY_FLAG(sack, FLAG_APPLIED)) {
00248         if (op->container->env != op) { /* if container is on the ground */
00249             op->container->move_off = 0;
00250         }
00251         /* Lauwenmark: Handle for plugin close event */
00252         if (execute_event(tmp, EVENT_CLOSE, op, NULL, NULL, SCRIPT_FIX_ALL) != 0)
00253             return 1;
00254 
00255         query_name(op->container, name_tmp, MAX_BUF);
00256         draw_ext_info_format(NDI_UNIQUE, 0, op,
00257                              MSG_TYPE_APPLY, MSG_TYPE_APPLY_UNAPPLY,
00258                              "You close %s.",
00259                              "You close %s.",
00260                              name_tmp);
00261         CLEAR_FLAG(op->container, FLAG_APPLIED);
00262         op->container = NULL;
00263         if (set_object_face_main(tmp)) {
00264             esrv_update_item(UPD_FLAGS|UPD_FACE, op, tmp);
00265         } else {
00266             esrv_update_item(UPD_FLAGS, op, tmp);
00267         }
00268         if (tmp == sack)
00269             return 1;
00270     }
00271 
00272     query_name(sack, name_sack, MAX_BUF);
00273 
00274     /* If the player is trying to open it (which he must be doing
00275      * if we got here), and it is locked, check to see if player
00276      * has the equipment to open it.
00277      */
00278 
00279     if (sack->slaying) { /* it's locked */
00280         tmp = find_key(op, op, sack);
00281         if (tmp) {
00282             query_name(tmp, name_tmp, MAX_BUF);
00283             draw_ext_info_format(NDI_UNIQUE, 0, op,
00284                                  MSG_TYPE_APPLY, MSG_TYPE_APPLY_SUCCESS,
00285                                  "You unlock %s with %s.",
00286                                  "You unlock %s with %s.",
00287                                  name_sack, name_tmp);
00288         } else {
00289             draw_ext_info_format(NDI_UNIQUE, 0, op,
00290                                  MSG_TYPE_APPLY, MSG_TYPE_APPLY_ERROR,
00291                                  "You don't have the key to unlock %s.",
00292                                  "You don't have the key to unlock %s.",
00293                                  name_sack);
00294             return 0;
00295         }
00296     }
00297 
00298     /* By the time we get here, we have made sure any other container
00299      * has been closed and if this is a locked container, the player
00300      * has the key to open it.
00301      */
00302 
00303     /* There are really two cases - the sack is either on the ground,
00304      * or the sack is part of the player's inventory.  If on the ground,
00305      * we assume that the player is opening it, since if it was being
00306      * closed, that would have been taken care of above.
00307      */
00308 
00309 
00310     if (sack->env != op) {
00311         /* Hypothetical case - the player is trying to open a sack
00312          * that belongs to someone else.  This normally should not
00313          * happen, but a misbehaving client/player could
00314          * try to do it, so let's handle it gracefully.
00315          */
00316         if (sack->env) {
00317             draw_ext_info_format(NDI_UNIQUE, 0, op, MSG_TYPE_APPLY, MSG_TYPE_APPLY_ERROR,
00318                                  "You can't open %s",
00319                                  "You can't open %s",
00320                                  name_sack);
00321             return 0;
00322         }
00323 
00324         if (sack->nrof > 1) {
00325             object *left = get_split_ob(sack, sack->nrof-1, NULL, 0);
00326 
00327             insert_ob_in_map_at(left, sack->map, NULL, INS_NO_MERGE, sack->x, sack->y);
00328             /* recompute the name so it's nice */
00329             query_name(sack, name_sack, MAX_BUF);
00330         }
00331 
00332         /* set it so when the player walks off, we can unapply the sack */
00333         sack->move_off = MOVE_ALL;      /* trying force closing it */
00334 
00335         CLEAR_FLAG(sack, FLAG_APPLIED);
00336         draw_ext_info_format(NDI_UNIQUE, 0, op, MSG_TYPE_APPLY, MSG_TYPE_APPLY_SUCCESS,
00337                              "You open %s.",
00338                              "You open %s.",
00339                              name_sack);
00340         SET_FLAG(sack, FLAG_APPLIED);
00341         op->container = sack;
00342         if (set_object_face_other(sack)) {
00343             esrv_update_item(UPD_FLAGS|UPD_FACE, op, sack);
00344         } else {
00345             esrv_update_item(UPD_FLAGS, op, sack);
00346         }
00347         esrv_send_inventory(op, sack);
00348     } else { /* sack is in players inventory */
00349         if (QUERY_FLAG(sack, FLAG_APPLIED)) {  /* readied sack becoming open */
00350             CLEAR_FLAG(sack, FLAG_APPLIED);
00351             draw_ext_info_format(NDI_UNIQUE, 0, op, MSG_TYPE_APPLY, MSG_TYPE_APPLY_SUCCESS,
00352                                  "You open %s.",
00353                                  "You open %s.",
00354                                  name_sack);
00355             SET_FLAG(sack, FLAG_APPLIED);
00356             op->container = sack;
00357             if (set_object_face_other(sack)) {
00358                 esrv_update_item(UPD_FLAGS|UPD_FACE, op, sack);
00359             } else {
00360                 esrv_update_item(UPD_FLAGS, op, sack);
00361             }
00362             esrv_send_inventory(op, sack);
00363         } else {
00364             object *left = NULL;
00365 
00366             if (sack->nrof > 1) {
00367                 left = get_split_ob(sack, sack->nrof-1, NULL, 1);
00368             }
00369 
00370             CLEAR_FLAG(sack, FLAG_APPLIED);
00371             draw_ext_info_format(NDI_UNIQUE, 0, op, MSG_TYPE_APPLY, MSG_TYPE_APPLY_SUCCESS,
00372                                  "You readied %s.",
00373                                  "You readied %s.",
00374                                  name_sack);
00375             SET_FLAG(sack, FLAG_APPLIED);
00376             esrv_update_item(UPD_FLAGS, op, sack);
00377 
00378             if (left) {
00379                 insert_ob_in_ob(left, sack->env);
00380                 esrv_send_item(op, left);
00381             }
00382         }
00383     }
00384     return 1;
00385 }
00386 
00398 void do_learn_spell(object *op, object *spell, int special_prayer) {
00399     object *tmp;
00400 
00401     if (op->type != PLAYER) {
00402         LOG(llevError, "BUG: do_learn_spell(): not a player\n");
00403         return;
00404     }
00405 
00406     /* Upgrade special prayers to normal prayers */
00407     if ((tmp = check_spell_known(op, spell->name)) != NULL) {
00408         if (special_prayer && !QUERY_FLAG(tmp, FLAG_STARTEQUIP)) {
00409             LOG(llevError, "BUG: do_learn_spell(): spell already known, but not marked as startequip\n");
00410             return;
00411         }
00412         return;
00413     }
00414 
00415     play_sound_player_only(op->contr, SOUND_TYPE_SPELL, spell, 0, "learn");
00416     tmp = get_object();
00417     copy_object(spell, tmp);
00418     insert_ob_in_ob(tmp, op);
00419 
00420     if (special_prayer) {
00421         SET_FLAG(tmp, FLAG_STARTEQUIP);
00422     }
00423 
00424     draw_ext_info_format(NDI_UNIQUE, 0, op, MSG_TYPE_APPLY, MSG_TYPE_APPLY_SUCCESS,
00425                          "Type 'bind cast %s to store the spell in a key.",
00426                          "Type 'bind cast %s to store the spell in a key.",
00427                          spell->name);
00428 
00429     esrv_add_spells(op->contr, tmp);
00430 }
00431 
00440 void do_forget_spell(object *op, const char *spell) {
00441     object *spob;
00442 
00443     if (op->type != PLAYER) {
00444         LOG(llevError, "BUG: do_forget_spell(): not a player\n");
00445         return;
00446     }
00447     if ((spob = check_spell_known(op, spell)) == NULL) {
00448         LOG(llevError, "BUG: do_forget_spell(): spell not known\n");
00449         return;
00450     }
00451 
00452     draw_ext_info_format(NDI_UNIQUE|NDI_NAVY, 0, op, MSG_TYPE_APPLY, MSG_TYPE_APPLY_CURSED,
00453                          "You lose knowledge of %s.",
00454                          "You lose knowledge of %s.",
00455                          spell);
00456     player_unready_range_ob(op->contr, spob);
00457     esrv_remove_spell(op->contr, spob);
00458     remove_ob(spob);
00459     free_object(spob);
00460 }
00461 
00472 static int check_race_restrictions(object *who, object *item) {
00473     char buf[MAX_BUF];
00474     sstring restriction;
00475 
00476     if (who->type != PLAYER || QUERY_FLAG(who, FLAG_WIZ))
00477         return 1;
00478 
00479     restriction = get_ob_key_value(item, "race_restriction");
00480     if (!restriction)
00481         return 1;
00482 
00483     snprintf(buf, sizeof(buf), ":%s:", who->race);
00484     buf[sizeof(buf)-1] = '\0';
00485 
00486     if (strstr(restriction, buf) != NULL)
00487         return 1;
00488 
00489     query_name(item, buf, sizeof(buf));
00490     draw_ext_info_format(NDI_UNIQUE, 0, who, MSG_TYPE_APPLY, MSG_TYPE_APPLY_PROHIBITION, "Somehow you can't seem to use the %s.", NULL, buf);
00491 
00492     return 0;
00493 }
00494 
00512 int manual_apply(object *op, object *tmp, int aflag) {
00513     if (tmp->head)
00514         tmp = tmp->head;
00515 
00516     if (QUERY_FLAG(tmp, FLAG_UNPAID) && !QUERY_FLAG(tmp, FLAG_APPLIED)) {
00517         if (op->type == PLAYER) {
00518             draw_ext_info(NDI_UNIQUE, 0, op, MSG_TYPE_APPLY, MSG_TYPE_APPLY_ERROR,
00519                           "You should pay for it first.", NULL);
00520             return METHOD_SILENT_ERROR;
00521         }
00522         return 0;   /* monsters just skip unpaid items */
00523     }
00524 
00525     if (!check_race_restrictions(op, tmp))
00526         return METHOD_SILENT_ERROR;
00527 
00528     /* Lauwenmark: Handle for plugin apply event */
00529     if (execute_event(tmp, EVENT_APPLY, op, NULL, NULL, SCRIPT_FIX_ALL) != 0)
00530         return METHOD_OK;
00531 
00532     if (op->contr)
00533         play_sound_player_only(op->contr, SOUND_TYPE_ITEM, tmp, 0, "apply");
00534 
00535     return ob_apply(tmp, op, aflag);
00536 }
00537 
00557 int player_apply(object *pl, object *op, int aflag, int quiet) {
00558     int tmp;
00559 
00560     if (op->env == NULL && (pl->move_type&MOVE_FLYING)) {
00561         /* player is flying and applying object not in inventory */
00562         if (!QUERY_FLAG(pl, FLAG_WIZ) && !(op->move_type&MOVE_FLYING)) {
00563             draw_ext_info(NDI_UNIQUE, 0, pl, MSG_TYPE_APPLY, MSG_TYPE_APPLY_ERROR,
00564                           "But you are floating high above the ground!", NULL);
00565             return 0;
00566         }
00567     }
00568 
00569     /* Check for PLAYER to avoid a DM to disappear in a puff of smoke if
00570      * applied.
00571      */
00572     if (op->type != PLAYER
00573     && QUERY_FLAG(op, FLAG_WAS_WIZ)
00574     && !QUERY_FLAG(pl, FLAG_WAS_WIZ)) {
00575         play_sound_map(SOUND_TYPE_ITEM, op, 0, "evaporate");
00576         draw_ext_info(NDI_UNIQUE, 0, pl, MSG_TYPE_APPLY, MSG_TYPE_APPLY_ERROR,
00577                       "The object disappears in a puff of smoke!", NULL);
00578         draw_ext_info(NDI_UNIQUE, 0, pl, MSG_TYPE_APPLY, MSG_TYPE_APPLY_ERROR,
00579                       "It must have been an illusion.", NULL);
00580         remove_ob(op);
00581         free_object(op);
00582         return 1;
00583     }
00584 
00585     pl->contr->last_used = op;
00586     pl->contr->last_used_id = op->count;
00587 
00588     tmp = manual_apply(pl, op, aflag);
00589     if (!quiet) {
00590         if (tmp == METHOD_UNHANDLED) {
00591             char name[MAX_BUF];
00592 
00593             query_name(op, name, MAX_BUF);
00594             draw_ext_info_format(NDI_UNIQUE, 0, pl, MSG_TYPE_APPLY, MSG_TYPE_APPLY_ERROR,
00595                                  "I don't know how to apply the %s.",
00596                                  "I don't know how to apply the %s.",
00597                                  name);
00598         } else if (tmp == METHOD_ERROR)
00599             draw_ext_info_format(NDI_UNIQUE, 0, pl, MSG_TYPE_APPLY, MSG_TYPE_APPLY_ERROR,
00600                                  "You must get it first!\n", NULL);
00601         else if (tmp == METHOD_SILENT_ERROR)
00602             return tmp;
00603     }
00604     if (tmp == METHOD_OK) {
00605         if (op->anim_suffix != NULL)
00606             apply_anim_suffix(pl, op->anim_suffix);
00607     }
00608     return tmp;
00609 }
00610 
00619 void player_apply_below(object *pl) {
00620     object *tmp, *next;
00621     int floors;
00622 
00623     if (pl->contr->transport && pl->contr->transport->type == TRANSPORT) {
00624         ob_apply(pl->contr->transport, pl, 0);
00625         return;
00626     }
00627 
00628     /* If using a container, set the starting item to be the top
00629      * item in the container.  Otherwise, use the map.
00630      */
00631     tmp = (pl->container != NULL) ? pl->container->inv : pl->below;
00632 
00633     /* This is perhaps more complicated.  However, I want to make sure that
00634      * we don't use a corrupt pointer for the next object, so we get the
00635      * next object in the stack before applying.  This is can only be a
00636      * problem if player_apply() has a bug in that it uses the object but
00637      * does not return a proper value.
00638      */
00639     for (floors = 0; tmp != NULL; tmp = next) {
00640         next = tmp->below;
00641         if (QUERY_FLAG(tmp, FLAG_IS_FLOOR))
00642             floors++;
00643         else if (floors > 0)
00644             return;   /* process only floor objects after first floor object */
00645 
00646         /* If it is visible, player can apply it.  If it is applied by
00647          * person moving on it, also activate.  Added code to make it
00648          * so that at least one of players movement types be that which
00649          * the item needs.
00650          */
00651         if (!tmp->invisible || (tmp->move_on&pl->move_type)) {
00652             if (player_apply(pl, tmp, 0, 1) == METHOD_OK)
00653                 return;
00654         }
00655         if (floors >= 2)
00656             return;   /* process at most two floor objects */
00657     }
00658 }
00659 
00675 static int unapply_special(object *who, object *op, int aflags) {
00676     char name[MAX_BUF];
00677 
00678     if (op->type != LAMP)
00679         CLEAR_FLAG(op, FLAG_APPLIED);
00680     query_name(op, name, MAX_BUF);
00681     switch (op->type) {
00682     case WEAPON:
00683         if (!(aflags&AP_NOPRINT))
00684             draw_ext_info_format(NDI_UNIQUE, 0, who, MSG_TYPE_APPLY, MSG_TYPE_APPLY_UNAPPLY,
00685                                  "You unwield %s.",
00686                                  "You unwield %s.",
00687                                  name);
00688         (void)change_abil(who, op);
00689         if (QUERY_FLAG(who, FLAG_READY_WEAPON))
00690             CLEAR_FLAG(who, FLAG_READY_WEAPON);
00691         who->current_weapon = NULL;
00692         clear_skill(who);
00693         break;
00694 
00695     case SKILL:         /* allows objects to impart skills */
00696     case SKILL_TOOL:
00697         if (op != who->chosen_skill) {
00698             LOG(llevError, "BUG: apply_special(): applied skill is not a chosen skill\n");
00699         }
00700         if (who->type == PLAYER) {
00701             if (who->contr->shoottype == range_skill)
00702                 who->contr->shoottype = range_none;
00703             if (!op->invisible) {
00704                 if (!(aflags&AP_NOPRINT))
00705                     draw_ext_info_format(NDI_UNIQUE, 0, who, MSG_TYPE_APPLY, MSG_TYPE_APPLY_UNAPPLY,
00706                                          "You stop using the %s.",
00707                                          "You stop using the %s.",
00708                                          name);
00709             } else {
00710                 if (!(aflags&AP_NOPRINT))
00711                     draw_ext_info_format(NDI_UNIQUE, 0, who, MSG_TYPE_APPLY, MSG_TYPE_APPLY_UNAPPLY,
00712                                          "You can no longer use the skill: %s.",
00713                                          "You can no longer use the skill: %s.",
00714                                          op->skill);
00715             }
00716         }
00717         (void)change_abil(who, op);
00718         who->chosen_skill = NULL;
00719         CLEAR_FLAG(who, FLAG_READY_SKILL);
00720         break;
00721 
00722     case ARMOUR:
00723     case HELMET:
00724     case SHIELD:
00725     case RING:
00726     case BOOTS:
00727     case GLOVES:
00728     case AMULET:
00729     case GIRDLE:
00730     case BRACERS:
00731     case CLOAK:
00732         if (!(aflags&AP_NOPRINT))
00733             draw_ext_info_format(NDI_UNIQUE, 0, who, MSG_TYPE_APPLY, MSG_TYPE_APPLY_UNAPPLY,
00734                                  "You unwear %s.",
00735                                  "You unwear %s.",
00736                                  name);
00737         (void)change_abil(who, op);
00738         break;
00739 
00740     case BOW:
00741     case WAND:
00742     case ROD:
00743     case HORN:
00744         clear_skill(who);
00745         if (!(aflags&AP_NOPRINT))
00746             draw_ext_info_format(NDI_UNIQUE, 0, who, MSG_TYPE_APPLY, MSG_TYPE_APPLY_UNAPPLY,
00747                                  "You unready %s.",
00748                                  "You unready %s.",
00749                                  name);
00750         if (who->type == PLAYER) {
00751             who->contr->shoottype = range_none;
00752         } else {
00753             if (op->type == BOW)
00754                 CLEAR_FLAG(who, FLAG_READY_BOW);
00755             else
00756                 CLEAR_FLAG(who, FLAG_READY_RANGE);
00757         }
00758         break;
00759 
00760     case BUILDER:
00761         if (!(aflags&AP_NOPRINT))
00762             draw_ext_info_format(NDI_UNIQUE, 0, who, MSG_TYPE_APPLY, MSG_TYPE_APPLY_UNAPPLY,
00763                                  "You unready %s.",
00764                                  "You unready %s.",
00765                                  name);
00766         who->contr->shoottype = range_none;
00767         who->contr->ranges[range_builder] = NULL;
00768         break;
00769 
00770     default:
00771         if (!(aflags&AP_NOPRINT))
00772             draw_ext_info_format(NDI_UNIQUE, 0, who, MSG_TYPE_APPLY, MSG_TYPE_APPLY_UNAPPLY,
00773                                  "You unapply %s.",
00774                                  "You unapply %s.",
00775                                  name);
00776         break;
00777     }
00778 
00779     fix_object(who);
00780 
00781     if (!(aflags&AP_NO_MERGE)) {
00782         object *tmp;
00783 
00784         tmp = merge_ob(op, NULL);
00785         if (who->type == PLAYER) {
00786             if (tmp) {  /* it was merged */
00787                 op = tmp;
00788             }
00789             esrv_update_item(UPD_FLAGS, who, op);
00790         }
00791     }
00792     return 0;
00793 }
00794 
00814 static object *get_item_from_body_location(object *start, int loc) {
00815     object *tmp;
00816 
00817     if (!start)
00818         return NULL;
00819 
00820     for (tmp = start; tmp; tmp = tmp->below)
00821         if (QUERY_FLAG(tmp, FLAG_APPLIED)
00822         && tmp->body_info[loc]
00823         && (!tmp->invisible || tmp->type == SKILL))
00824             return tmp;
00825 
00826     return NULL;
00827 }
00828 
00850 static int unapply_for_ob(object *who, object *op, int aflags) {
00851     int i;
00852     object *tmp = NULL, *last;
00853     char name[MAX_BUF];
00854 
00855     /* If we are applying a shield or weapon, unapply any equipped shield
00856      * or weapons first - only allowed to use one weapon/shield at a time.
00857      */
00858     if (op->type == WEAPON || op->type == SHIELD) {
00859         for (tmp = who->inv; tmp; tmp = tmp->below) {
00860             if (QUERY_FLAG(tmp, FLAG_APPLIED) && tmp->type == op->type) {
00861                 if ((aflags&AP_IGNORE_CURSE)
00862                 || (aflags&AP_PRINT)
00863                 || (!QUERY_FLAG(tmp, FLAG_CURSED) && !QUERY_FLAG(tmp, FLAG_DAMNED))) {
00864                     if (aflags&AP_PRINT) {
00865                         query_name(tmp, name, MAX_BUF);
00866                         draw_ext_info(NDI_UNIQUE, 0, who, MSG_TYPE_APPLY, MSG_TYPE_APPLY_UNAPPLY,
00867                                       name, NULL);
00868                     } else
00869                         unapply_special(who, tmp, aflags);
00870                 } else {
00871                     /* In this case, we want to try and remove a
00872                      * cursed item. While we know it won't work, we
00873                      * want unapply_special to at least generate the
00874                      * message.
00875                      */
00876                     if (!(aflags&AP_NOPRINT)) {
00877                         query_name(tmp, name, MAX_BUF);
00878                         draw_ext_info_format(NDI_UNIQUE, 0, who, MSG_TYPE_APPLY, MSG_TYPE_APPLY_UNAPPLY,
00879                                              "No matter how hard you try, you just can't remove %s.",
00880                                              "No matter how hard you try, you just can't remove %s.",
00881                                              name);
00882                     }
00883                     return 1;
00884                 }
00885 
00886             }
00887         }
00888     }
00889 
00890     for (i = 0; i < NUM_BODY_LOCATIONS; i++) {
00891         /* this used up a slot that we need to free */
00892         if (op->body_info[i]) {
00893             last = who->inv;
00894 
00895             /* We do a while loop - may need to remove several items
00896              * in order to free up enough slots.
00897              */
00898             while ((who->body_used[i]+op->body_info[i]) < 0) {
00899                 tmp = get_item_from_body_location(last, i);
00900                 if (!tmp) {
00901                     return 1;
00902                 }
00903 
00904                 /* If just printing, we don't care about cursed status */
00905                 if ((aflags&AP_IGNORE_CURSE)
00906                 || (aflags&AP_PRINT)
00907                 || (!(QUERY_FLAG(tmp, FLAG_CURSED) || QUERY_FLAG(tmp, FLAG_DAMNED)))) {
00908                     if (aflags&AP_PRINT) {
00909                         query_name(tmp, name, MAX_BUF);
00910                         draw_ext_info(NDI_UNIQUE, 0, who, MSG_TYPE_APPLY, MSG_TYPE_APPLY_UNAPPLY,
00911                                       name, NULL);
00912                     } else
00913                         unapply_special(who, tmp, aflags);
00914                 } else {
00915                     /* Cursed item that we can't unequip - tell the player.
00916                      * Note this could be annoying if this is just one of a
00917                      * few, so it may not be critical (eg, putting on a
00918                      * ring and you have one cursed ring.)
00919                      */
00920                     if (!(aflags&AP_NOPRINT)) {
00921                         query_name(tmp, name, MAX_BUF);
00922                         draw_ext_info_format(NDI_UNIQUE, 0, who, MSG_TYPE_APPLY, MSG_TYPE_APPLY_UNAPPLY,
00923                                              "The %s just won't come off",
00924                                              "The %s just won't come off",
00925                                              name);
00926                     }
00927                 }
00928                 last = tmp->below;
00929             }
00930             /* if we got here, this slot is freed up - otherwise, if it
00931              * wasn't freed up, the return in the !tmp would have
00932              * kicked in.
00933              */
00934         } /* if op is using this body location */
00935     } /* for body lcoations */
00936     return 0;
00937 }
00938 
00955 int can_apply_object(object *who, object *op) {
00956     int i, retval = 0;
00957     object *tmp = NULL, *ws = NULL;
00958 
00959     /* Players have 2 'arm's, so they could in theory equip 2 shields or
00960      * 2 weapons, but we don't want to let them do that.  So if they are
00961      * trying to equip a weapon or shield, see if they already have one
00962      * in place and store that way.
00963      */
00964     if (op->type == WEAPON || op->type == SHIELD) {
00965         for (tmp = who->inv; tmp && !ws; tmp = tmp->below) {
00966             if (QUERY_FLAG(tmp, FLAG_APPLIED) && tmp->type == op->type) {
00967                 retval = CAN_APPLY_UNAPPLY;
00968                 ws = tmp;
00969             }
00970         }
00971     }
00972 
00973     for (i = 0; i < NUM_BODY_LOCATIONS; i++) {
00974         if (op->body_info[i]) {
00975             /* Item uses more slots than we have */
00976             if (FABS(op->body_info[i]) > who->body_info[i]) {
00977                 /* Could return now for efficiently - rest of info
00978                  * below isn't really needed.
00979                  */
00980                 retval |= CAN_APPLY_NEVER;
00981             } else if ((who->body_used[i]+op->body_info[i]) < 0) {
00982                 /* in this case, equipping this would use more free
00983                  * spots than we have.
00984                  */
00985                 object *tmp1;
00986 
00987                 /* if we have an applied weapon/shield, and unapply
00988                  * it would free enough slots to equip the new item,
00989                  * then just set this can continue.  We don't care
00990                  * about the logic below - if you have shield equipped
00991                  * and try to equip another shield, there is only one
00992                  * choice.  However, the check for the number of body
00993                  * locations does take into the account cases where what
00994                  * is being applied may be two handed for example.
00995                  */
00996                 if (ws) {
00997                     if ((who->body_used[i]-ws->body_info[i]+op->body_info[i]) >= 0) {
00998                         retval |= CAN_APPLY_UNAPPLY;
00999                         continue;
01000                     }
01001                 }
01002 
01003                 tmp1 = get_item_from_body_location(who->inv, i);
01004                 if (!tmp1) {
01005                     retval |= CAN_APPLY_NEVER;
01006                 } else {
01007                     /* need to unapply something.  However, if this
01008                      * something is different than we had found before,
01009                      * it means they need to apply multiple objects
01010                      */
01011                     retval |= CAN_APPLY_UNAPPLY;
01012                     if (!tmp)
01013                         tmp = tmp1;
01014                     else if (tmp != tmp1) {
01015                         retval |= CAN_APPLY_UNAPPLY_MULT;
01016                     }
01017                     /* This object isn't using up all the slots, so
01018                      * there must be another.  If so, and if the new
01019                      * item doesn't need all the slots, the player
01020                      * then has a choice.
01021                      */
01022                     if (((who->body_used[i]-tmp1->body_info[i]) != who->body_info[i])
01023                     && (FABS(op->body_info[i]) < who->body_info[i]))
01024                         retval |= CAN_APPLY_UNAPPLY_CHOICE;
01025 
01026                     /* Does unequipping 'tmp1' free up enough slots
01027                      * for this to be equipped?  If not, there must
01028                      * be something else to unapply.
01029                      */
01030                     if ((who->body_used[i]+op->body_info[i]-tmp1->body_info[i]) < 0)
01031                         retval |= CAN_APPLY_UNAPPLY_MULT;
01032                 }
01033             } /* if not enough free slots */
01034         } /* if this object uses location i */
01035     } /* for i -> num_body_locations loop */
01036 
01037     /* Do checks for can_use_weapon/shield/armour. */
01038     if (IS_WEAPON(op) && !QUERY_FLAG(who, FLAG_USE_WEAPON))
01039         retval |= CAN_APPLY_RESTRICTION;
01040     if (IS_SHIELD(op) && !QUERY_FLAG(who, FLAG_USE_SHIELD))
01041         retval |= CAN_APPLY_RESTRICTION;
01042     if (IS_ARMOR(op) && !QUERY_FLAG(who, FLAG_USE_ARMOUR))
01043         retval |= CAN_APPLY_RESTRICTION;
01044 
01045     if (who->type != PLAYER) {
01046         if ((op->type == WAND || op->type == HORN || op->type == ROD)
01047         && !QUERY_FLAG(who, FLAG_USE_RANGE))
01048             retval |= CAN_APPLY_RESTRICTION;
01049         if (op->type == BOW && !QUERY_FLAG(who, FLAG_USE_BOW))
01050             retval |= CAN_APPLY_RESTRICTION;
01051         if (op->type == RING && !QUERY_FLAG(who, FLAG_USE_RING))
01052             retval |= CAN_APPLY_RESTRICTION;
01053         if (op->type == BOW && !QUERY_FLAG(who, FLAG_USE_BOW))
01054             retval |= CAN_APPLY_RESTRICTION;
01055     }
01056     return retval;
01057 }
01058 
01076 int check_weapon_power(const object *who, int improvs) {
01077     /* Old code is below (commented out).  Basically, since weapons
01078      * are the only object players really have any control to improve,
01079      * it's a bit harsh to require high level in some combat skill,
01080      * so we just use overall level.
01081      */
01082 #if 1
01083     if (((who->level/5)+5) >= improvs)
01084         return 1;
01085     else
01086         return 0;
01087 
01088 #else
01089     int level = 0;
01090 
01091     /* The skill system hands out wc and dam bonuses to fighters
01092      * more generously than the old system (see fix_object). Thus
01093      * we need to curtail the power of player enchanted weapons.
01094      * I changed this to 1 improvement per "fighter" level/5 -b.t.
01095      * Note:  Nothing should break by allowing this ratio to be
01096      * different or using normal level - it is just a matter of play
01097      * balance.
01098      */
01099     if (who->type == PLAYER) {
01100         object *wc_obj = NULL;
01101 
01102         for (wc_obj = who->inv; wc_obj; wc_obj = wc_obj->below)
01103             if (wc_obj->type == SKILL && IS_COMBAT_SKILL(wc_obj->subtype)
01104             && wc_obj->level > level)
01105                 level = wc_obj->level;
01106 
01107         if (!level)  {
01108             LOG(llevError, "Error: Player: %s lacks wc experience object\n", who->name);
01109             level = who->level;
01110         }
01111     } else
01112         level = who->level;
01113 
01114     return (improvs <= ((level/5)+5));
01115 #endif
01116 }
01117 
01139 int apply_special(object *who, object *op, int aflags) {
01140     int basic_flag = aflags&AP_BASIC_FLAGS;
01141     object *tmp, *skop = NULL;
01142     int i;
01143     char name_op[MAX_BUF];
01144 
01145     if (who == NULL) {
01146         LOG(llevError, "apply_special() from object without environment.\n");
01147         return 1;
01148     }
01149 
01150     query_name(op, name_op, MAX_BUF);
01151 
01152     if (op->env != who)
01153         return 1;   /* op is not in inventory */
01154 
01155     /* trying to unequip op */
01156     if (QUERY_FLAG(op, FLAG_APPLIED)) {
01157         /* always apply, so no reason to unapply */
01158         if (basic_flag == AP_APPLY)
01159             return 0;
01160 
01161         if (!(aflags&AP_IGNORE_CURSE)
01162         && (QUERY_FLAG(op, FLAG_CURSED) || QUERY_FLAG(op, FLAG_DAMNED))) {
01163             if (!(aflags&AP_NOPRINT))
01164                 draw_ext_info_format(NDI_UNIQUE, 0, who, MSG_TYPE_APPLY, MSG_TYPE_APPLY_UNAPPLY,
01165                                      "No matter how hard you try, you just can't remove %s.",
01166                                      "No matter how hard you try, you just can't remove %s.",
01167                                      name_op);
01168             return 1;
01169         }
01170         return unapply_special(who, op, aflags);
01171     }
01172 
01173     if (basic_flag == AP_UNAPPLY)
01174         return 0;
01175 
01176     i = can_apply_object(who, op);
01177 
01178     /* Can't just apply this object.  Lets see what not and what to do */
01179     if (i) {
01180         if (i&CAN_APPLY_NEVER) {
01181             if (!(aflags&AP_NOPRINT))
01182                 draw_ext_info_format(NDI_UNIQUE, 0, who, MSG_TYPE_APPLY, MSG_TYPE_APPLY_BADBODY,
01183                                      "You don't have the body to use a %s",
01184                                      "You don't have the body to use a %s",
01185                                      name_op);
01186             return 1;
01187         } else if (i&CAN_APPLY_RESTRICTION) {
01188             if (!(aflags&AP_NOPRINT))
01189                 draw_ext_info_format(NDI_UNIQUE, 0, who, MSG_TYPE_APPLY, MSG_TYPE_APPLY_PROHIBITION,
01190                                      "You have a prohibition against using a %s",
01191                                      "You have a prohibition against using a %s",
01192                                      name_op);
01193             return 1;
01194         }
01195         if (who->type != PLAYER) {
01196             /* Some error, so don't try to equip something more */
01197             if (unapply_for_ob(who, op, aflags))
01198                 return 1;
01199         } else {
01200             if (who->contr->unapply == unapply_never
01201             || (i&CAN_APPLY_UNAPPLY_CHOICE && who->contr->unapply == unapply_nochoice)) {
01202                 if (!(aflags&AP_NOPRINT))
01203                     draw_ext_info(NDI_UNIQUE, 0, who, MSG_TYPE_APPLY, MSG_TYPE_APPLY_UNAPPLY,
01204                                   "You need to unapply some item(s):", NULL);
01205                 unapply_for_ob(who, op, AP_PRINT);
01206                 return 1;
01207             } else if (who->contr->unapply == unapply_always
01208             || !(i&CAN_APPLY_UNAPPLY_CHOICE)) {
01209                 i = unapply_for_ob(who, op, aflags);
01210                 if (i)
01211                     return 1;
01212             }
01213         }
01214     }
01215     if (op->skill && op->type != SKILL && op->type != SKILL_TOOL) {
01216         skop = find_skill_by_name(who, op->skill);
01217         if (!skop) {
01218             if (!(aflags&AP_NOPRINT))
01219                 draw_ext_info_format(NDI_UNIQUE, 0, who, MSG_TYPE_APPLY, MSG_TYPE_APPLY_ERROR,
01220                                      "You need the %s skill to use this item!",
01221                                      "You need the %s skill to use this item!",
01222                                      op->skill);
01223             return 1;
01224         } else {
01225             /* While experience will be credited properly, we want to
01226              * change the skill so that the dam and wc get updated
01227              */
01228             change_skill(who, skop, (aflags&AP_NOPRINT));
01229         }
01230     }
01231 
01232     if (who->type == PLAYER
01233     && op->item_power
01234     && (op->item_power+who->contr->item_power) > (settings.item_power_factor*who->level)) {
01235         if (!(aflags&AP_NOPRINT))
01236             draw_ext_info(NDI_UNIQUE, 0, who, MSG_TYPE_APPLY, MSG_TYPE_APPLY_ERROR,
01237                           "Equipping that combined with other items would consume your soul!", NULL);
01238         return 1;
01239     }
01240 
01241     /* If personalized blessings are activated, the weapon can bite
01242      * the wielder if he/she is not the one who initially blessed it.
01243      * Chances of being hurt depend on the experience amount
01244      * ("willpower") the object has, compared to the experience
01245      * amount of the wielder.
01246      */
01247     if (settings.personalized_blessings) {
01248         const char *owner = get_ob_key_value(op, "item_owner");
01249         if ((owner != NULL) && (strcmp(owner, who->name))) {
01250             const char *will = get_ob_key_value(op, "item_willpower");
01251             long item_will = 0;
01252             long margin = 0;
01253             const char *msg = NULL;
01254             int random_effect = 0;
01255             int damage_percentile = 0;
01256 
01257             if (will != NULL)
01258                 item_will = atol(will);
01259             if (item_will > who->stats.exp) {
01260                 draw_ext_info_format(NDI_UNIQUE, 0, who, MSG_TYPE_APPLY, MSG_TYPE_APPLY_ERROR,
01261                                      "This %s refuses to serve you - it keeps evading your hand !",
01262                                      "This %s refuses to serve you - it keeps evading your hand !",
01263                                      op->name);
01264                 return 1;
01265             }
01266             if (item_will != 0)
01267                 margin = who->stats.exp/item_will;
01268             else
01269                 margin = who->stats.exp;
01270             random_effect = (random_roll(0, 100, who, 1)-(margin*20));
01271             if (random_effect > 80) {
01272                 msg = "You don't know why, but you have the feeling that the %s is angry at you !";
01273                 damage_percentile = 60;
01274             } else if (random_effect > 60) {
01275                 msg = "The %s seems to look at you nastily !";
01276                 damage_percentile = 45;
01277             } else if (random_effect > 40) {
01278                 msg = "You have the strange feeling that the %s is annoyed...";
01279                 damage_percentile = 30;
01280             } else if (random_effect > 20) {
01281                 msg = "The %s seems tired, or bored, in a way. Very strange !";
01282                 damage_percentile = 15;
01283             } else if (random_effect > 0) {
01284                 msg = "You hear the %s sighing !";
01285                 damage_percentile = 0;
01286             }
01287             if (msg != NULL)
01288                 draw_ext_info_format(NDI_UNIQUE, 0, who, MSG_TYPE_APPLY, MSG_TYPE_APPLY_SUCCESS,
01289                                      msg, msg, op->name);
01290             if (damage_percentile > 0) {
01291                 int weapon_bite = (who->stats.hp*damage_percentile)/100;
01292                 if (weapon_bite < 1)
01293                     weapon_bite = 1;
01294                 who->stats.hp -= weapon_bite;
01295                 draw_ext_info_format(NDI_UNIQUE, 0, who, MSG_TYPE_VICTIM, MSG_TYPE_VICTIM_WAS_HIT,
01296                                      "You get a nasty bite in the hand !",
01297                                      "You get a nasty bite in the hand !");
01298             }
01299         }
01300     }
01301 
01302     /* Ok.  We are now at the state where we can apply the new object.
01303      * Note that we don't have the checks for can_use_...
01304      * below - that is already taken care of by can_apply_object.
01305      */
01306 
01307     if (op->nrof > 1)
01308         tmp = get_split_ob(op, op->nrof-1, NULL, 0);
01309     else
01310         tmp = NULL;
01311 
01312     switch (op->type) {
01313     case WEAPON: {
01314             int ownerlen = 0;
01315             char *quotepos = NULL;
01316 
01317             if (!check_weapon_power(who, op->last_eat)) {
01318                 if (!(aflags&AP_NOPRINT))
01319                     draw_ext_info(NDI_UNIQUE, 0, who, MSG_TYPE_APPLY,
01320                                   MSG_TYPE_APPLY_ERROR,
01321                                   "That weapon is too powerful for you to use.  It would consume your soul!",
01322                                   NULL);
01323 
01324                 if (tmp != NULL)
01325                     (void)insert_ob_in_ob(tmp, who);
01326                 return 1;
01327             }
01328             /* BUG? It seems the value of quotepos is never used. */
01329             if ((quotepos = strstr(op->name, "'")) != NULL) {
01330                 ownerlen = (strstr(op->name, "'")-op->name);
01331                 if (op->level && (strncmp(op->name, who->name, ownerlen))) {
01332                     /* if the weapon does not have the name as the
01333                      * character, can't use it. (Ragnarok's sword
01334                      * attempted to be used by Foo: won't work) */
01335                     if (!(aflags&AP_NOPRINT))
01336                         draw_ext_info(NDI_UNIQUE, 0, who, MSG_TYPE_APPLY, MSG_TYPE_APPLY_ERROR,
01337                                       "The weapon does not recognize you as its owner.", NULL);
01338                     if (tmp != NULL)
01339                         (void)insert_ob_in_ob(tmp, who);
01340                     return 1;
01341                 }
01342             }
01343             SET_FLAG(op, FLAG_APPLIED);
01344 
01345             if (skop)
01346                 change_skill(who, skop, 1);
01347             if (!QUERY_FLAG(who, FLAG_READY_WEAPON))
01348                 SET_FLAG(who, FLAG_READY_WEAPON);
01349 
01350             if (!(aflags&AP_NOPRINT))
01351                 draw_ext_info_format(NDI_UNIQUE, 0, who, MSG_TYPE_APPLY, MSG_TYPE_APPLY_SUCCESS,
01352                                      "You wield %s.", "You wield %s.",
01353                                      name_op);
01354 
01355             (void)change_abil(who, op);
01356             break;
01357         }
01358 
01359     case ARMOUR:
01360     case HELMET:
01361     case SHIELD:
01362     case BOOTS:
01363     case GLOVES:
01364     case GIRDLE:
01365     case BRACERS:
01366     case CLOAK:
01367     case RING:
01368     case AMULET:
01369         SET_FLAG(op, FLAG_APPLIED);
01370         if (!(aflags&AP_NOPRINT))
01371             draw_ext_info_format(NDI_UNIQUE, 0, who, MSG_TYPE_APPLY, MSG_TYPE_APPLY_SUCCESS,
01372                                  "You wear %s.",
01373                                  "You wear %s.",
01374                                  name_op);
01375         (void)change_abil(who, op);
01376         break;
01377 
01378         /* this part is needed for skill-tools */
01379     case SKILL:
01380     case SKILL_TOOL:
01381         if (who->chosen_skill) {
01382             LOG(llevError, "BUG: apply_special(): can't apply two skills\n");
01383             return 1;
01384         }
01385 
01386         if (who->type == PLAYER) {
01387             who->contr->shoottype = range_skill;
01388             who->contr->ranges[range_skill] = op;
01389             if (!op->invisible) {
01390                 if (!(aflags&AP_NOPRINT)) {
01391                     draw_ext_info_format(NDI_UNIQUE, 0, who, MSG_TYPE_APPLY, MSG_TYPE_APPLY_SUCCESS,
01392                                          "You ready %s.",
01393                                          "You ready %s.",
01394                                          name_op);
01395                     draw_ext_info_format(NDI_UNIQUE, 0, who, MSG_TYPE_APPLY, MSG_TYPE_APPLY_SUCCESS,
01396                                          "You can now use the skill: %s.",
01397                                          "You can now use the skill: %s.",
01398                                          op->skill);
01399                 }
01400             } else {
01401                 if (!(aflags&AP_NOPRINT))
01402                     draw_ext_info_format(NDI_UNIQUE, 0, who, MSG_TYPE_APPLY, MSG_TYPE_APPLY_SUCCESS,
01403                                          "Readied skill: %s.",
01404                                          "Readied skill: %s.",
01405                                          op->skill ? op->skill : op->name);
01406             }
01407         }
01408         SET_FLAG(op, FLAG_APPLIED);
01409         (void)change_abil(who, op);
01410         who->chosen_skill = op;
01411         SET_FLAG(who, FLAG_READY_SKILL);
01412         break;
01413 
01414     case BOW:
01415         if (!check_weapon_power(who, op->last_eat)) {
01416             if (!(aflags&AP_NOPRINT)) {
01417                 draw_ext_info(NDI_UNIQUE, 0, who, MSG_TYPE_APPLY, MSG_TYPE_APPLY_ERROR,
01418                               "That item is too powerful for you to use.",
01419                               NULL);
01420                 draw_ext_info(NDI_UNIQUE, 0, who, MSG_TYPE_APPLY, MSG_TYPE_APPLY_ERROR,
01421                               "It would consume your soul!.", NULL);
01422             }
01423             if (tmp != NULL)
01424                 (void)insert_ob_in_ob(tmp, who);
01425             return 1;
01426         }
01427         if (op->level && (strncmp(op->name, who->name, strlen(who->name)))) {
01428             if (!(aflags&AP_NOPRINT)) {
01429                 draw_ext_info(NDI_UNIQUE, 0, who, MSG_TYPE_APPLY, MSG_TYPE_APPLY_ERROR,
01430                               "The weapon does not recognize you as its owner.", NULL);
01431             }
01432             if (tmp != NULL)
01433                 (void)insert_ob_in_ob(tmp, who);
01434             return 1;
01435         }
01436         /*FALLTHROUGH*/
01437     case WAND:
01438     case ROD:
01439     case HORN:
01440         /* check for skill, alter player status */
01441         SET_FLAG(op, FLAG_APPLIED);
01442         if (skop)
01443             change_skill(who, skop, 0);
01444         if (!(aflags&AP_NOPRINT))
01445             draw_ext_info_format(NDI_UNIQUE, 0, who, MSG_TYPE_APPLY, MSG_TYPE_APPLY_SUCCESS,
01446                                  "You ready %s.",
01447                                  "You ready %s.",
01448                                  name_op);
01449         if (who->type == PLAYER) {
01450             if (op->type == BOW) {
01451                 (void)change_abil(who, op);
01452                 if (!(aflags&AP_NOPRINT))
01453                     draw_ext_info_format(NDI_UNIQUE, 0, who, MSG_TYPE_APPLY, MSG_TYPE_APPLY_SUCCESS,
01454                                          "You will now fire %s with %s.",
01455                                          "You will now fire %s with %s.",
01456                                          op->race ? op->race : "nothing",
01457                                          name_op);
01458                 who->contr->shoottype = range_bow;
01459             } else {
01460                 who->contr->shoottype = range_misc;
01461             }
01462         } else {
01463             if (op->type == BOW)
01464                 SET_FLAG(who, FLAG_READY_BOW);
01465             else
01466                 SET_FLAG(who, FLAG_READY_RANGE);
01467         }
01468         break;
01469 
01470     case BUILDER:
01471         if (who->contr->ranges[range_builder])
01472             unapply_special(who, who->contr->ranges[range_builder], 0);
01473         who->contr->shoottype = range_builder;
01474         who->contr->ranges[range_builder] = op;
01475         if (!(aflags&AP_NOPRINT))
01476             draw_ext_info_format(NDI_UNIQUE, 0, who, MSG_TYPE_APPLY, MSG_TYPE_APPLY_SUCCESS,
01477                                  "You ready your %s.",
01478                                  "You ready your %s.",
01479                                  name_op);
01480         break;
01481 
01482     default:
01483         draw_ext_info_format(NDI_UNIQUE, 0, who, MSG_TYPE_APPLY, MSG_TYPE_APPLY_SUCCESS,
01484                              "You apply %s.",
01485                              "You apply %s.",
01486                              name_op);
01487     } /* end of switch op->type */
01488 
01489     SET_FLAG(op, FLAG_APPLIED);
01490 
01491     if (tmp != NULL)
01492         tmp = insert_ob_in_ob(tmp, who);
01493 
01494     fix_object(who);
01495 
01496     /* We exclude spell casting objects.  The fire code will set the
01497      * been applied flag when they are used - until that point,
01498      * you don't know anything about them.
01499      */
01500     if (who->type == PLAYER && op->type != WAND && op->type != HORN && op->type != ROD)
01501         SET_FLAG(op, FLAG_BEEN_APPLIED);
01502 
01503     if (QUERY_FLAG(op, FLAG_CURSED) || QUERY_FLAG(op, FLAG_DAMNED)) {
01504         if (who->type == PLAYER) {
01505             draw_ext_info(NDI_UNIQUE, 0, who, MSG_TYPE_APPLY, MSG_TYPE_APPLY_CURSED,
01506                           "Oops, it feels deadly cold!", NULL);
01507             SET_FLAG(op, FLAG_KNOWN_CURSED);
01508         }
01509     }
01510     if (who->type == PLAYER) {
01511         esrv_update_item(UPD_NROF|UPD_FLAGS|UPD_WEIGHT, who, op);
01512     }
01513     return 0;
01514 }
01515 
01526 int auto_apply(object *op) {
01527     object *tmp = NULL, *tmp2;
01528     int i;
01529 
01530     switch (op->type) {
01531     case SHOP_FLOOR:
01532         if (!HAS_RANDOM_ITEMS(op))
01533             return 0;
01534         do {
01535             i = 10; /* let's give it 10 tries */
01536             while ((tmp = generate_treasure(op->randomitems, op->stats.exp ? (int)op->stats.exp : MAX(op->map->difficulty, 5))) == NULL
01537             && --i)
01538                 ;
01539             if (tmp == NULL)
01540                 return 0;
01541             if (QUERY_FLAG(tmp, FLAG_CURSED) || QUERY_FLAG(tmp, FLAG_DAMNED)) {
01542                 free_object(tmp);
01543                 tmp = NULL;
01544             }
01545         } while (!tmp);
01546         tmp->x = op->x;
01547         tmp->y = op->y;
01548         SET_FLAG(tmp, FLAG_UNPAID);
01549         insert_ob_in_map(tmp, op->map, NULL, 0);
01550         CLEAR_FLAG(op, FLAG_AUTO_APPLY);
01551         identify(tmp);
01552         break;
01553 
01554     case TREASURE:
01555         if (QUERY_FLAG(op, FLAG_IS_A_TEMPLATE))
01556             return 0;
01557         while ((op->stats.hp--) > 0)
01558             create_treasure(op->randomitems, op, op->map ? GT_ENVIRONMENT : 0, op->stats.exp ? (int)op->stats.exp : op->map == NULL ? 14 : op->map->difficulty, 0);
01559 
01560         /* If we generated an object and put it in this object's
01561          * inventory, move it to the parent object as the current
01562          * object is about to disappear.  An example of this item
01563          * is the random_ *stuff that is put inside other objects.
01564          */
01565         for (tmp = op->inv; tmp; tmp = tmp2) {
01566             tmp2 = tmp->below;
01567             remove_ob(tmp);
01568             if (op->env)
01569                 insert_ob_in_ob(tmp, op->env);
01570             else
01571                 free_object(tmp);
01572         }
01573         remove_ob(op);
01574         free_object(op);
01575         break;
01576     }
01577     return tmp ? 1 : 0;
01578 }
01579 
01590 void fix_auto_apply(mapstruct *m) {
01591     object *tmp, *above = NULL;
01592     int x, y;
01593 
01594     if (m == NULL)
01595         return;
01596 
01597     for (x = 0; x < MAP_WIDTH(m); x++)
01598         for (y = 0; y < MAP_HEIGHT(m); y++)
01599             for (tmp = GET_MAP_OB(m, x, y); tmp != NULL; tmp = above) {
01600                 above = tmp->above;
01601 
01602                 if (tmp->inv) {
01603                     object *invtmp, *invnext;
01604 
01605                     for (invtmp = tmp->inv; invtmp != NULL; invtmp = invnext) {
01606                         invnext = invtmp->below;
01607 
01608                         if (QUERY_FLAG(invtmp, FLAG_AUTO_APPLY))
01609                             auto_apply(invtmp);
01610                         else if (invtmp->type == TREASURE && HAS_RANDOM_ITEMS(invtmp)) {
01611                             while ((invtmp->stats.hp--) > 0)
01612                                 create_treasure(invtmp->randomitems, invtmp, 0, m->difficulty, 0);
01613                             invtmp->randomitems = NULL;
01614                         } else if (invtmp && invtmp->arch
01615                         && invtmp->type != TREASURE
01616                         && invtmp->type != SPELL
01617                         && invtmp->type != CLASS
01618                         && HAS_RANDOM_ITEMS(invtmp)) {
01619                             create_treasure(invtmp->randomitems, invtmp, 0, m->difficulty, 0);
01620                             /* Need to clear this so that we never try to
01621                              * create treasure again for this object
01622                              */
01623                             invtmp->randomitems = NULL;
01624                         }
01625                     }
01626                     /* This is really temporary - the code at the
01627                      * bottom will also set randomitems to null.
01628                      * The problem is there are bunches of maps/players
01629                      * already out there with items that have spells
01630                      * which haven't had the randomitems set
01631                      * to null yet.
01632                      * MSW 2004-05-13
01633                      *
01634                      * And if it's a spellbook, it's better to set
01635                      * randomitems to NULL too, else you get two spells
01636                      * in the book ^_-
01637                      * Ryo 2004-08-16
01638                      */
01639                     if (tmp->type == WAND
01640                     || tmp->type == ROD
01641                     || tmp->type == SCROLL
01642                     || tmp->type == HORN
01643                     || tmp->type == FIREWALL
01644                     || tmp->type == POTION
01645                     || tmp->type == ALTAR
01646                     || tmp->type == SPELLBOOK)
01647                         tmp->randomitems = NULL;
01648                 }
01649 
01650                 if (QUERY_FLAG(tmp, FLAG_AUTO_APPLY))
01651                     auto_apply(tmp);
01652                 else if ((tmp->type == TREASURE || (tmp->type == CONTAINER))
01653                 && HAS_RANDOM_ITEMS(tmp)) {
01654                     while ((tmp->stats.hp--) > 0)
01655                         create_treasure(tmp->randomitems, tmp, 0, m->difficulty, 0);
01656                     tmp->randomitems = NULL;
01657                 } else if (tmp->type == TIMED_GATE) {
01658                     object *head = tmp->head != NULL ? tmp->head : tmp;
01659 
01660                     if (QUERY_FLAG(head, FLAG_IS_LINKED)) {
01661                         tmp->speed = 0;
01662                         update_ob_speed(tmp);
01663                     }
01664                 }
01665                 /* This function can be called everytime a map is loaded,
01666                  * even when swapping back in.  As such, we don't want to
01667                  * create the treasure over and ove again, so after we
01668                  * generate the treasure, blank out randomitems so if it
01669                  * is swapped in again, it won't make anything. This is a
01670                  * problem for the above objects, because they have
01671                  * counters which say how many times to make the treasure.
01672                  */
01673                 else if (tmp
01674                 && tmp->arch
01675                 && tmp->type != PLAYER
01676                 && tmp->type != TREASURE
01677                 && tmp->type != SPELL
01678                 && tmp->type != PLAYER_CHANGER
01679                 && tmp->type != CLASS
01680                 && HAS_RANDOM_ITEMS(tmp)) {
01681                     create_treasure(tmp->randomitems, tmp, GT_APPLY, m->difficulty, 0);
01682                     tmp->randomitems = NULL;
01683                 }
01684             }
01685 
01686     for (x = 0; x < MAP_WIDTH(m); x++)
01687         for (y = 0; y < MAP_HEIGHT(m); y++)
01688             for (tmp = GET_MAP_OB(m, x, y); tmp != NULL; tmp = tmp->above)
01689                 if (tmp->above
01690                 && (tmp->type == TRIGGER_BUTTON || tmp->type == TRIGGER_PEDESTAL))
01691                     check_trigger(tmp, tmp->above);
01692 }
01693 
01708 void scroll_failure(object *op, int failure, int power) {
01709     if (abs(failure/4) > power)
01710         power = abs(failure/4); /* set minimum effect */
01711 
01712     if (failure <= -1 && failure > -15) {/* wonder */
01713         object *tmp;
01714 
01715         draw_ext_info(NDI_UNIQUE, 0, op, MSG_TYPE_APPLY, MSG_TYPE_APPLY_FAILURE,
01716                       "Your spell warps!", NULL);
01717         tmp = create_archetype(SPELL_WONDER);
01718         cast_wonder(op, op, 0, tmp);
01719         if (op->stats.sp < 0)
01720             /* For some reason the sp can become negative here. */
01721             op->stats.sp = 0;
01722         free_object(tmp);
01723         return;
01724     }
01725 
01726     if (settings.spell_failure_effects == TRUE) {
01727         if (failure <= -35 && failure > -60) { /* confusion */
01728             draw_ext_info(NDI_UNIQUE, 0, op, MSG_TYPE_APPLY, MSG_TYPE_APPLY_FAILURE,
01729                           "The magic recoils on you!", NULL);
01730             confuse_living(op, op, power);
01731             return;
01732         }
01733 
01734         if (failure <= -60 && failure > -70) {/* paralysis */
01735             draw_ext_info(NDI_UNIQUE, 0, op, MSG_TYPE_APPLY, MSG_TYPE_APPLY_FAILURE,
01736                           "The magic recoils and paralyzes you!", NULL);
01737             paralyze_living(op, op, power);
01738             return;
01739         }
01740 
01741         if (failure <= -70 && failure > -80) {/* blind */
01742             draw_ext_info(NDI_UNIQUE, 0, op, MSG_TYPE_APPLY, MSG_TYPE_APPLY_FAILURE,
01743                           "The magic recoils on you!", NULL);
01744             blind_living(op, op, power);
01745             return;
01746         }
01747 
01748         if (failure <= -80) {/* blast the immediate area */
01749             object *tmp;
01750 
01751             tmp = create_archetype(LOOSE_MANA);
01752             cast_magic_storm(op, tmp, power);
01753             draw_ext_info(NDI_UNIQUE, 0, op, MSG_TYPE_APPLY, MSG_TYPE_APPLY_FAILURE,
01754                           "You unlease uncontrolled mana!", NULL);
01755             free_object(tmp);
01756             return;
01757         }
01758     }
01759     /* Either no spell failure on this server, or wrong values,
01760      * in any case let's punish.
01761      */
01762     draw_ext_info(NDI_UNIQUE, 0, op, MSG_TYPE_APPLY, MSG_TYPE_APPLY_FAILURE,
01763                   "Your mana is drained!", NULL);
01764     op->stats.sp -= random_roll(0, power-1, op, PREFER_LOW);
01765     if (op->stats.sp < 0)
01766         op->stats.sp = 0;
01767 }
01768 
01776 void apply_changes_to_player(object *pl, object *change) {
01777     int excess_stat = 0;  /* if the stat goes over the maximum
01778                            * for the race, put the excess stat some
01779                            * where else.
01780                            */
01781 
01782     switch (change->type) {
01783     case CLASS: {
01784             living *stats = &(pl->contr->orig_stats);
01785             living *ns = &(change->stats);
01786             object *walk;
01787             int flag_change_face = 1;
01788 
01789             /* the following code assigns stats up to the stat max
01790              * for the race, and if the stat max is exceeded,
01791              * tries to randomly reassign the excess stat
01792              */
01793             int i, j;
01794             for (i = 0; i < NUM_STATS; i++) {
01795                 sint8 stat = get_attr_value(stats, i);
01796                 int race_bonus = get_attr_value(&(pl->arch->clone.stats), i);
01797 
01798                 stat += get_attr_value(ns, i);
01799                 if (stat > 20+race_bonus) {
01800                     excess_stat++;
01801                     stat = 20+race_bonus;
01802                 }
01803                 set_attr_value(stats, i, stat);
01804             }
01805 
01806             for (j = 0; excess_stat > 0 && j < 100; j++) {
01807                 /* try 100 times to assign excess stats */
01808                 int i = rndm(0, 6);
01809                 int stat = get_attr_value(stats, i);
01810                 int race_bonus = get_attr_value(&(pl->arch->clone.stats), i);
01811 
01812                 if (i == CHA)
01813                     continue; /* exclude cha from this */
01814                 if (stat < 20+race_bonus) {
01815                     change_attr_value(stats, i, 1);
01816                     excess_stat--;
01817                 }
01818             }
01819 
01820             /* insert the randomitems from the change's treasurelist into
01821              * the player ref: player.c
01822              */
01823             if (change->randomitems != NULL)
01824                 give_initial_items(pl, change->randomitems);
01825 
01826 
01827             /* set up the face, for some races. */
01828 
01829             /* first, look for the force object banning changing the
01830              * face.  Certain races never change face with class.
01831              */
01832             for (walk = pl->inv; walk != NULL; walk = walk->below)
01833                 if (!strcmp(walk->name, "NOCLASSFACECHANGE"))
01834                     flag_change_face = 0;
01835 
01836             if (flag_change_face) {
01837                 pl->animation_id = GET_ANIM_ID(change);
01838                 pl->face = change->face;
01839 
01840                 if (QUERY_FLAG(change, FLAG_ANIMATE))
01841                     SET_FLAG(pl, FLAG_ANIMATE);
01842                 else
01843                     CLEAR_FLAG(pl, FLAG_ANIMATE);
01844             }
01845 
01846             if (change->anim_suffix) {
01847                 char buf[MAX_BUF];
01848                 int anim;
01849 
01850                 snprintf(buf, MAX_BUF, "%s_%s", animations[pl->animation_id].name, change->anim_suffix);
01851                 anim = try_find_animation(buf);
01852                 if (anim) {
01853                     pl->animation_id = anim;
01854                     pl->anim_speed = -1;
01855                     CLEAR_FLAG(pl, FLAG_ANIMATE);
01856                     animate_object(pl, pl->facing);
01857                 }
01858             }
01859 
01860             /* check the special case of can't use weapons */
01861             /*if(QUERY_FLAG(change, FLAG_USE_WEAPON))
01862              *    CLEAR_FLAG(pl, FLAG_USE_WEAPON);
01863              */
01864             if (!strcmp(change->name, "monk"))
01865                 CLEAR_FLAG(pl, FLAG_USE_WEAPON);
01866 
01867             break;
01868         }
01869     }
01870 }
01871 
01872 void legacy_apply_container(object *op, object *sack) {
01873     apply_container(op, sack);
01874 }