Atrinik Server 2.5
server/item.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 
00033 static float weapon_speed_table[19] =
00034 {
00035     20.0f,  18.0f,  10.0f,  8.0f,   5.5f,   4.25f,  3.50f,  3.05f,  2.70f,  2.35f,
00036     2.15f,  1.95f,  1.80f,  1.60f,  1.52f,  1.44f,  1.32f,  1.25f,  1.20f
00037 };
00038 
00040 static char numbers[21][20] =
00041 {
00042     "no",
00043     "",
00044     "two",
00045     "three",
00046     "four",
00047     "five",
00048     "six",
00049     "seven",
00050     "eight",
00051     "nine",
00052     "ten",
00053     "eleven",
00054     "twelve",
00055     "thirteen",
00056     "fourteen",
00057     "fifteen",
00058     "sixteen",
00059     "seventeen",
00060     "eighteen",
00061     "nineteen",
00062     "twenty"
00063 };
00064 
00066 static char numbers_10[10][20] =
00067 {
00068     "zero",
00069     "ten",
00070     "twenty",
00071     "thirty",
00072     "forty",
00073     "fifty",
00074     "sixty",
00075     "seventy",
00076     "eighty",
00077     "ninety"
00078 };
00079 
00081 static char levelnumbers[21][20] =
00082 {
00083     "zeroth",
00084     "first",
00085     "second",
00086     "third",
00087     "fourth",
00088     "fifth",
00089     "sixth",
00090     "seventh",
00091     "eighth",
00092     "ninth",
00093     "tenth",
00094     "eleventh",
00095     "twelfth",
00096     "thirteenth",
00097     "fourteenth",
00098     "fifteenth",
00099     "sixteenth",
00100     "seventeenth",
00101     "eighteen",
00102     "nineteen",
00103     "twentieth"
00104 };
00105 
00107 static char levelnumbers_10[11][20] =
00108 {
00109     "zeroth",
00110     "tenth",
00111     "twentieth",
00112     "thirtieth",
00113     "fortieth",
00114     "fiftieth",
00115     "sixtieth",
00116     "seventieth",
00117     "eightieth",
00118     "ninetieth"
00119 };
00120 
00121 static char *describe_attack(object *op, int newline);
00122 static char *get_number(int i);
00123 
00132 static char *describe_attack(object *op, int newline)
00133 {
00134     static char buf[VERY_BIG_BUF];
00135     char buf1[VERY_BIG_BUF];
00136     int tmpvar, flag = 1;
00137 
00138     buf[0] = '\0';
00139 
00140     for (tmpvar = 0; tmpvar < NROFATTACKS; tmpvar++)
00141     {
00142         if (op->attack[tmpvar])
00143         {
00144             if (flag && !newline)
00145             {
00146                 strncat(buf, "(Attacks: ", sizeof(buf) - strlen(buf) - 1);
00147             }
00148 
00149             if (!newline)
00150             {
00151                 if (!flag)
00152                 {
00153                     strncat(buf, ", ", sizeof(buf) - strlen(buf) - 1);
00154                 }
00155 
00156                 snprintf(buf1, sizeof(buf1), "%s %+d%%", attack_name[tmpvar], op->attack[tmpvar]);
00157             }
00158             else
00159             {
00160                 snprintf(buf1, sizeof(buf1), "%s %+d%%\n", attack_name[tmpvar], op->attack[tmpvar]);
00161             }
00162 
00163             flag = 0;
00164             strncat(buf, buf1, sizeof(buf) - strlen(buf) - 1);
00165         }
00166     }
00167 
00168     if (!newline && !flag)
00169     {
00170         strncat(buf, ") ", sizeof(buf) - strlen(buf) - 1);
00171     }
00172 
00173     return buf;
00174 }
00175 
00184 char *describe_protections(object *op, int newline)
00185 {
00186     static char buf[VERY_BIG_BUF];
00187     char buf1[VERY_BIG_BUF];
00188     int tmpvar, flag = 1;
00189 
00190     buf[0] = '\0';
00191 
00192     for (tmpvar = 0; tmpvar < NROFATTACKS; tmpvar++)
00193     {
00194         if (op->protection[tmpvar])
00195         {
00196             if (flag && !newline)
00197             {
00198                 strncat(buf, "(Protections: ", sizeof(buf) - strlen(buf) - 1);
00199             }
00200 
00201             if (!newline)
00202             {
00203                 if (!flag)
00204                 {
00205                     strncat(buf, ", ", sizeof(buf) - strlen(buf) - 1);
00206                 }
00207 
00208                 snprintf(buf1, sizeof(buf1), "%s %+d%%", attack_name[tmpvar], op->protection[tmpvar]);
00209             }
00210             else
00211             {
00212                 snprintf(buf1, sizeof(buf1), "%s %d%%\n", attack_name[tmpvar], op->protection[tmpvar]);
00213             }
00214 
00215             flag = 0;
00216             strncat(buf, buf1, sizeof(buf) - strlen(buf) - 1);
00217         }
00218     }
00219 
00220     if (!newline && !flag)
00221     {
00222         strncat(buf, ") ", sizeof(buf) - strlen(buf) - 1);
00223     }
00224 
00225     return buf;
00226 }
00227 
00232 char *query_weight(object *op)
00233 {
00234     static char buf[10];
00235     int i = op->nrof ? (int) op->nrof * op->weight : op->weight + op->carrying;
00236 
00237     if (op->weight < 0)
00238     {
00239         return "      ";
00240     }
00241 
00242     if (i % 1000)
00243     {
00244         snprintf(buf, sizeof(buf), "%6.1f", (float) i / 1000.0f);
00245     }
00246     else
00247     {
00248         snprintf(buf, sizeof(buf), "%4d  ", i / 1000);
00249     }
00250 
00251     return buf;
00252 }
00253 
00258 char *get_levelnumber(int i)
00259 {
00260     static char buf[MAX_BUF];
00261 
00262     if (i > 99)
00263     {
00264         snprintf(buf, sizeof(buf), "%d.", i);
00265         return buf;
00266     }
00267 
00268     if (i < 21)
00269     {
00270         return levelnumbers[i];
00271     }
00272 
00273     if (!(i % 10))
00274     {
00275         return levelnumbers_10[i / 10];
00276     }
00277 
00278     strcpy(buf, numbers_10[i / 10]);
00279     strcat(buf, levelnumbers[i % 10]);
00280 
00281     return buf;
00282 }
00283 
00292 static char *get_number(int i)
00293 {
00294     if (i <= 20)
00295     {
00296         return numbers[i];
00297     }
00298     else
00299     {
00300         static char buf[MAX_BUF];
00301         snprintf(buf, sizeof(buf), "%d", i);
00302         return buf;
00303     }
00304 }
00305 
00312 char *query_short_name(object *op, object *caller)
00313 {
00314     static char buf[HUGE_BUF];
00315     char buf2[HUGE_BUF];
00316     size_t len = 0;
00317 
00318     buf[0] = '\0';
00319 
00320     if (!op || !op->name)
00321     {
00322         return buf;
00323     }
00324 
00325     if (op->nrof)
00326     {
00327         safe_strcat(buf, get_number(op->nrof), &len, sizeof(buf));
00328 
00329         if (op->nrof != 1)
00330         {
00331             safe_strcat(buf, " ", &len, sizeof(buf));
00332         }
00333 
00334         if (!QUERY_FLAG(op, FLAG_IS_NAMED))
00335         {
00336             /* Add the item race name */
00337             if (!IS_LIVE(op) && op->type != BASE_INFO)
00338             {
00339                 safe_strcat(buf, item_races[op->item_race], &len, sizeof(buf));
00340             }
00341 
00342             if (op->material_real && QUERY_FLAG(op, FLAG_IDENTIFIED))
00343             {
00344                 safe_strcat(buf, material_real[op->material_real].name, &len, sizeof(buf));
00345             }
00346         }
00347 
00348         safe_strcat(buf, op->name, &len, sizeof(buf));
00349 
00350         if (op->nrof != 1)
00351         {
00352             char *buf3 = strstr(buf, " of ");
00353 
00354             if (buf3)
00355             {
00356                 strcpy(buf2, buf3);
00357                 /* Also changes value in buf */
00358                 *buf3 = '\0';
00359             }
00360 
00361             len = strlen(buf);
00362 
00363             /* If buf3 is set, then this was a string that contained
00364              * something of something (potion of dexterity.)  The part before
00365              * the of gets made plural, so now we need to copy the rest
00366              * (after and including the " of "), to the buffer string. */
00367             if (buf3)
00368             {
00369                 safe_strcat(buf, buf2, &len, sizeof(buf));
00370             }
00371         }
00372     }
00373     /* If nrof is 0, the object is not mergable, and thus, op->name
00374      * should contain the name to be used. */
00375     else
00376     {
00377         if (!QUERY_FLAG(op, FLAG_IS_NAMED))
00378         {
00379             if (!IS_LIVE(op) && op->type != BASE_INFO)
00380             {
00381                 safe_strcat(buf, item_races[op->item_race], &len, sizeof(buf));
00382             }
00383 
00384             if (op->material_real && QUERY_FLAG(op, FLAG_IDENTIFIED))
00385             {
00386                 safe_strcat(buf, material_real[op->material_real].name, &len, sizeof(buf));
00387             }
00388         }
00389 
00390         safe_strcat(buf, op->name, &len, sizeof(buf));
00391     }
00392 
00393     switch (op->type)
00394     {
00395         case CONTAINER:
00396             if (QUERY_FLAG(op, FLAG_IDENTIFIED))
00397             {
00398                 if (op->title)
00399                 {
00400                     safe_strcat(buf, " ", &len, sizeof(buf));
00401                     safe_strcat(buf, op->title, &len, sizeof(buf));
00402                 }
00403             }
00404 
00405             if (op->sub_type >= ST1_CONTAINER_NORMAL_party)
00406             {
00407                 if (op->sub_type == ST1_CONTAINER_CORPSE_party)
00408                 {
00409                     if (op->slaying)
00410                     {
00411                         if (!caller || caller->type != PLAYER)
00412                         {
00413                             safe_strcat(buf, " (bounty of a party)", &len, sizeof(buf));
00414                         }
00415                         else if (CONTR(caller)->party && CONTR(caller)->party->name == op->slaying)
00416                         {
00417                             safe_strcat(buf, " (bounty of your party", &len, sizeof(buf));
00418 
00419                             /* A searched bounty */
00420                             if (QUERY_FLAG(op, FLAG_BEEN_APPLIED))
00421                             {
00422                                 safe_strcat(buf, ", searched", &len, sizeof(buf));
00423                             }
00424 
00425                             safe_strcat(buf, ")", &len, sizeof(buf));
00426                         }
00427                         /* It's a different party */
00428                         else
00429                         {
00430                             safe_strcat(buf, " (bounty of another party)", &len, sizeof(buf));
00431                         }
00432                     }
00433                     else if (QUERY_FLAG(op, FLAG_BEEN_APPLIED))
00434                     {
00435                         safe_strcat(buf, " (searched)", &len, sizeof(buf));
00436                     }
00437                 }
00438             }
00439             else if (op->sub_type >= ST1_CONTAINER_NORMAL_player)
00440             {
00441                 if (op->sub_type == ST1_CONTAINER_CORPSE_player)
00442                 {
00443                     if (op->slaying)
00444                     {
00445                         safe_strcat(buf, " (bounty of ", &len, sizeof(buf));
00446                         safe_strcat(buf, op->slaying, &len, sizeof(buf));
00447 
00448                         /* A searched bounty */
00449                         if ((caller && caller->name == op->slaying) && QUERY_FLAG(op, FLAG_BEEN_APPLIED))
00450                         {
00451                             safe_strcat(buf, ", searched", &len, sizeof(buf));
00452                         }
00453 
00454                         safe_strcat(buf,")", &len, sizeof(buf));
00455                     }
00456                     else if (QUERY_FLAG(op, FLAG_BEEN_APPLIED))
00457                     {
00458                         safe_strcat(buf, " (searched)", &len, sizeof(buf));
00459                     }
00460                 }
00461             }
00462 
00463             break;
00464 
00465         case SPELLBOOK:
00466             if (QUERY_FLAG(op, FLAG_IDENTIFIED) || QUERY_FLAG(op, FLAG_BEEN_APPLIED))
00467             {
00468                 if (!op->title)
00469                 {
00470                     safe_strcat(buf, " of ", &len, sizeof(buf));
00471 
00472                     if (op->slaying)
00473                     {
00474                         safe_strcat(buf, op->slaying, &len, sizeof(buf));
00475                     }
00476                     else
00477                     {
00478                         if (op->stats.sp == SP_NO_SPELL)
00479                         {
00480                             safe_strcat(buf, "nothing", &len, sizeof(buf));
00481                         }
00482                         else
00483                         {
00484                             safe_strcat(buf, spells[op->stats.sp].name, &len, sizeof(buf));
00485                         }
00486                     }
00487                 }
00488                 else
00489                 {
00490                     safe_strcat(buf, " ", &len, sizeof(buf));
00491                     safe_strcat(buf, op->title, &len, sizeof(buf));
00492                 }
00493             }
00494 
00495             break;
00496 
00497         case SCROLL:
00498         case WAND:
00499         case ROD:
00500         case HORN:
00501         case POTION:
00502             if (QUERY_FLAG(op, FLAG_IDENTIFIED) || QUERY_FLAG(op, FLAG_BEEN_APPLIED))
00503             {
00504                 if (!op->title)
00505                 {
00506                     if (op->stats.sp != SP_NO_SPELL)
00507                     {
00508                         safe_strcat(buf, " of ", &len, sizeof(buf));
00509                         safe_strcat(buf, spells[op->stats.sp].name, &len, sizeof(buf));
00510                     }
00511                     else
00512                     {
00513                         safe_strcat(buf, " of nothing", &len, sizeof(buf));
00514                     }
00515                 }
00516                 else
00517                 {
00518                     safe_strcat(buf, " ", &len, sizeof(buf));
00519                     safe_strcat(buf, op->title, &len, sizeof(buf));
00520                 }
00521 
00522                 sprintf(buf2, " (lvl %d)", op->level);
00523                 safe_strcat(buf, buf2, &len, sizeof(buf));
00524             }
00525 
00526             break;
00527 
00528         case SKILL:
00529         case AMULET:
00530         case RING:
00531             if (QUERY_FLAG(op, FLAG_IDENTIFIED))
00532             {
00533                 if (!op->title)
00534                 {
00535                     /* If ring has a title, full description isn't so useful */
00536                     char *s = describe_item(op);
00537 
00538                     if (s[0])
00539                     {
00540                         safe_strcat(buf, " ", &len, sizeof(buf));
00541                         safe_strcat(buf, s, &len, sizeof(buf));
00542                     }
00543                 }
00544                 else
00545                 {
00546                     safe_strcat(buf, " ", &len, sizeof(buf));
00547                     safe_strcat(buf, op->title, &len, sizeof(buf));
00548                 }
00549             }
00550 
00551             break;
00552 
00553         default:
00554             if (op->magic && (!need_identify(op) || QUERY_FLAG(op, FLAG_BEEN_APPLIED) || QUERY_FLAG(op, FLAG_IDENTIFIED)))
00555             {
00556                 if (!IS_LIVE(op) && op->type != BASE_INFO)
00557                 {
00558                     sprintf(buf2, " %+d", op->magic);
00559                     safe_strcat(buf, buf2, &len, sizeof(buf));
00560                 }
00561             }
00562 
00563             if (op->title && QUERY_FLAG(op, FLAG_IDENTIFIED))
00564             {
00565                 safe_strcat(buf, " ", &len, sizeof(buf));
00566                 safe_strcat(buf, op->title, &len, sizeof(buf));
00567             }
00568 
00569             if ((op->type == ARROW || op->type == WEAPON) && op->slaying && QUERY_FLAG(op, FLAG_IDENTIFIED))
00570             {
00571                 safe_strcat(buf, " ", &len, sizeof(buf));
00572                 safe_strcat(buf, op->slaying, &len, sizeof(buf));
00573             }
00574     }
00575 
00576     return buf;
00577 }
00578 
00592 char *query_name(object *op, object *caller)
00593 {
00594     static char buf[5][HUGE_BUF];
00595     static int use_buf = 0;
00596     size_t len = 0;
00597 
00598     use_buf++;
00599     use_buf %= 5;
00600 
00601     if (!op || !op->name)
00602     {
00603         buf[use_buf][0] = 0;
00604         return buf[use_buf];
00605     }
00606 
00607     safe_strcat(buf[use_buf], query_short_name(op, caller), &len, HUGE_BUF);
00608 
00609     if (QUERY_FLAG(op, FLAG_ONE_DROP))
00610     {
00611         safe_strcat(buf[use_buf], " (one-drop)", &len, HUGE_BUF);
00612     }
00613     else if (QUERY_FLAG(op, FLAG_QUEST_ITEM))
00614     {
00615         safe_strcat(buf[use_buf], " (quest)", &len, HUGE_BUF);
00616     }
00617 
00618     if (QUERY_FLAG(op, FLAG_INV_LOCKED))
00619     {
00620         safe_strcat(buf[use_buf], " *", &len, HUGE_BUF);
00621     }
00622 
00623     if (op->type == CONTAINER && QUERY_FLAG(op, FLAG_APPLIED))
00624     {
00625         if (op->attacked_by && op->attacked_by->type == PLAYER)
00626         {
00627             safe_strcat(buf[use_buf], " (open)", &len, HUGE_BUF);
00628         }
00629         else
00630         {
00631             safe_strcat(buf[use_buf], " (ready)", &len, HUGE_BUF);
00632         }
00633     }
00634 
00635     if (QUERY_FLAG(op, FLAG_IDENTIFIED) || QUERY_FLAG(op, FLAG_APPLIED))
00636     {
00637         if (QUERY_FLAG(op, FLAG_PERM_DAMNED))
00638         {
00639             safe_strcat(buf[use_buf], " (perm. damned)", &len, HUGE_BUF);
00640         }
00641         else if (QUERY_FLAG(op, FLAG_DAMNED))
00642         {
00643             safe_strcat(buf[use_buf], " (damned)", &len, HUGE_BUF);
00644         }
00645         else if (QUERY_FLAG(op, FLAG_PERM_CURSED))
00646         {
00647             safe_strcat(buf[use_buf], " (perm. cursed)", &len, HUGE_BUF);
00648         }
00649         else if (QUERY_FLAG(op, FLAG_CURSED))
00650         {
00651             safe_strcat(buf[use_buf], " (cursed)", &len, HUGE_BUF);
00652         }
00653     }
00654 
00655     if (QUERY_FLAG(op, FLAG_IS_MAGICAL) && QUERY_FLAG(op, FLAG_IDENTIFIED))
00656     {
00657         safe_strcat(buf[use_buf], " (magical)", &len, HUGE_BUF);
00658     }
00659 
00660     if (QUERY_FLAG(op, FLAG_APPLIED))
00661     {
00662         switch (op->type)
00663         {
00664             case BOW:
00665             case WAND:
00666             case ROD:
00667             case HORN:
00668                 safe_strcat(buf[use_buf], " (readied)", &len, HUGE_BUF);
00669                 break;
00670 
00671             case WEAPON:
00672                 safe_strcat(buf[use_buf], " (wielded)", &len, HUGE_BUF);
00673                 break;
00674 
00675             case ARMOUR:
00676             case HELMET:
00677             case SHIELD:
00678             case RING:
00679             case BOOTS:
00680             case GLOVES:
00681             case AMULET:
00682             case GIRDLE:
00683             case BRACERS:
00684             case CLOAK:
00685                 safe_strcat(buf[use_buf], " (worn)", &len, HUGE_BUF);
00686                 break;
00687 
00688             case CONTAINER:
00689                 safe_strcat(buf[use_buf], " (active)", &len, HUGE_BUF);
00690                 break;
00691 
00692             case SKILL:
00693             case SKILL_ITEM:
00694             default:
00695                 safe_strcat(buf[use_buf], " (applied)", &len, HUGE_BUF);
00696         }
00697     }
00698 
00699     if (QUERY_FLAG(op, FLAG_UNPAID))
00700     {
00701         safe_strcat(buf[use_buf], " (unpaid)", &len, HUGE_BUF);
00702     }
00703 
00704     return buf[use_buf];
00705 }
00706 
00712 char *query_material_name(object *op)
00713 {
00714     static char buf[MAX_BUF];
00715     size_t len;
00716 
00717     buf[0] = '\0';
00718     len = 0;
00719 
00720     if (!op->name)
00721     {
00722         return "(null)";
00723     }
00724 
00725     if (!QUERY_FLAG(op, FLAG_IS_NAMED))
00726     {
00727         /* Add the item race name */
00728         if (!IS_LIVE(op) && op->type != BASE_INFO)
00729         {
00730             safe_strcat(buf, item_races[op->item_race], &len, sizeof(buf));
00731         }
00732 
00733         if (op->material_real && QUERY_FLAG(op, FLAG_IDENTIFIED))
00734         {
00735             safe_strcat(buf, material_real[op->material_real].name, &len, sizeof(buf));
00736         }
00737     }
00738 
00739     safe_strcat(buf, op->name, &len, sizeof(buf));
00740 
00741     if (op->title && QUERY_FLAG(op, FLAG_IDENTIFIED))
00742     {
00743         safe_strcat(buf, " ", &len, sizeof(buf));
00744         safe_strcat(buf, op->title, &len, sizeof(buf));
00745     }
00746 
00747     return buf;
00748 }
00749 
00762 char *query_base_name(object *op, object *caller)
00763 {
00764     static char buf[MAX_BUF];
00765     char buf2[32];
00766     size_t len;
00767 
00768     buf[0] = '\0';
00769 
00770     if (op->name == NULL)
00771     {
00772         return "(null)";
00773     }
00774 
00775     if (!QUERY_FLAG(op, FLAG_IS_NAMED))
00776     {
00777         /* Add the item race name */
00778         if (!IS_LIVE(op) && op->type != BASE_INFO)
00779         {
00780             strcpy(buf, item_races[op->item_race]);
00781         }
00782 
00783         if (op->material_real && QUERY_FLAG(op, FLAG_IDENTIFIED))
00784         {
00785             strcat(buf, material_real[op->material_real].name);
00786         }
00787     }
00788 
00789     strcat(buf, op->name);
00790 
00791     /* To speed things up */
00792     if (!op->weight && !op->title && !is_magical(op))
00793     {
00794         return buf;
00795     }
00796 
00797     len = strlen(buf);
00798 
00799     switch (op->type)
00800     {
00801         case CONTAINER:
00802             if (QUERY_FLAG(op, FLAG_IDENTIFIED))
00803             {
00804                 if (op->title)
00805                 {
00806                     safe_strcat(buf, " ", &len, sizeof(buf));
00807                     safe_strcat(buf, op->title, &len, sizeof(buf));
00808                 }
00809             }
00810 
00811             if (op->sub_type >= ST1_CONTAINER_NORMAL_party)
00812             {
00813                 if (op->sub_type == ST1_CONTAINER_CORPSE_party)
00814                 {
00815                     if (op->slaying)
00816                     {
00817                         if (!caller || caller->type != PLAYER)
00818                         {
00819                             safe_strcat(buf, " (bounty of a party)", &len, sizeof(buf));
00820                         }
00821                         else if (CONTR(caller)->party && CONTR(caller)->party->name == op->slaying)
00822                         {
00823                             safe_strcat(buf, " (bounty of your party", &len, sizeof(buf));
00824 
00825                             /* A searched bounty */
00826                             if (QUERY_FLAG(op, FLAG_BEEN_APPLIED))
00827                             {
00828                                 safe_strcat(buf, ", searched", &len, sizeof(buf));
00829                             }
00830 
00831                             safe_strcat(buf, ")", &len, sizeof(buf));
00832                         }
00833                         /* It's a different party */
00834                         else
00835                         {
00836                             safe_strcat(buf, " (bounty of another party)", &len, sizeof(buf));
00837                         }
00838                     }
00839                     else if (QUERY_FLAG(op, FLAG_BEEN_APPLIED))
00840                     {
00841                         safe_strcat(buf, " (searched)", &len, sizeof(buf));
00842                     }
00843                 }
00844             }
00845             else if (op->sub_type >= ST1_CONTAINER_NORMAL_player)
00846             {
00847                 if (op->sub_type == ST1_CONTAINER_CORPSE_player)
00848                 {
00849                     if (op->slaying)
00850                     {
00851                         safe_strcat(buf, " (bounty of ", &len, sizeof(buf));
00852                         safe_strcat(buf, op->slaying, &len, sizeof(buf));
00853 
00854                         /* A searched bounty */
00855                         if ((caller && caller->name == op->slaying) && QUERY_FLAG(op, FLAG_BEEN_APPLIED))
00856                         {
00857                             safe_strcat(buf, ", searched", &len, sizeof(buf));
00858                         }
00859 
00860                         safe_strcat(buf, ")", &len, sizeof(buf));
00861                     }
00862                     else if (QUERY_FLAG(op, FLAG_BEEN_APPLIED))
00863                     {
00864                         safe_strcat(buf, " (searched)", &len, sizeof(buf));
00865                     }
00866                 }
00867             }
00868 
00869             break;
00870 
00871         case SPELLBOOK:
00872             if (QUERY_FLAG(op, FLAG_IDENTIFIED))
00873             {
00874                 if (!op->title)
00875                 {
00876                     safe_strcat(buf, " of ", &len, sizeof(buf));
00877 
00878                     if (op->slaying)
00879                     {
00880                         safe_strcat(buf, op->slaying, &len, sizeof(buf));
00881                     }
00882                     else
00883                     {
00884                         if (op->stats.sp == SP_NO_SPELL)
00885                         {
00886                             safe_strcat(buf, "nothing", &len, sizeof(buf));
00887                         }
00888                         else
00889                         {
00890                             safe_strcat(buf, spells[op->stats.sp].name, &len, sizeof(buf));
00891                         }
00892                     }
00893                 }
00894                 else
00895                 {
00896                     safe_strcat(buf, " ", &len, sizeof(buf));
00897                     safe_strcat(buf, op->title, &len, sizeof(buf));
00898                 }
00899             }
00900 
00901             break;
00902 
00903         case SCROLL:
00904         case WAND:
00905         case ROD:
00906         case HORN:
00907         case POTION:
00908             if (QUERY_FLAG(op, FLAG_IDENTIFIED))
00909             {
00910                 if (!op->title)
00911                 {
00912                     if (op->stats.sp != SP_NO_SPELL)
00913                     {
00914                         safe_strcat(buf, " of ", &len, sizeof(buf));
00915                         safe_strcat(buf, spells[op->stats.sp].name, &len, sizeof(buf));
00916                     }
00917                     else
00918                     {
00919                         safe_strcat(buf, " of nothing", &len, sizeof(buf));
00920                     }
00921                 }
00922                 else
00923                 {
00924                     safe_strcat(buf, " ", &len, sizeof(buf));
00925                     safe_strcat(buf, op->title, &len, sizeof(buf));
00926                 }
00927 
00928                 sprintf(buf2, " (lvl %d)", op->level);
00929                 safe_strcat(buf, buf2, &len, sizeof(buf));
00930             }
00931 
00932             break;
00933 
00934         case SKILL:
00935         case AMULET:
00936         case RING:
00937             if (QUERY_FLAG(op, FLAG_IDENTIFIED))
00938             {
00939                 if (!op->title)
00940                 {
00941                     /* If ring has a title, full description isn't so useful */
00942                     char *s = describe_item(op);
00943 
00944                     if (s[0])
00945                     {
00946                         safe_strcat (buf, " ", &len, sizeof(buf));
00947                         safe_strcat (buf, s, &len, sizeof(buf));
00948                     }
00949                 }
00950                 else
00951                 {
00952                     safe_strcat(buf, " ", &len, sizeof(buf));
00953                     safe_strcat(buf, op->title, &len, sizeof(buf));
00954                 }
00955             }
00956 
00957             break;
00958 
00959         default:
00960             if (op->magic && (!need_identify(op) || QUERY_FLAG(op, FLAG_BEEN_APPLIED) || QUERY_FLAG(op, FLAG_IDENTIFIED)))
00961             {
00962                 if (!IS_LIVE(op) && op->type != BASE_INFO)
00963                 {
00964                     sprintf(buf2, " %+d", op->magic);
00965                     safe_strcat(buf, buf2, &len, sizeof(buf));
00966                 }
00967             }
00968 
00969             if (op->title && QUERY_FLAG(op, FLAG_IDENTIFIED))
00970             {
00971                 safe_strcat(buf, " ", &len, sizeof(buf));
00972                 safe_strcat(buf, op->title, &len, sizeof(buf));
00973             }
00974 
00975             if ((op->type == ARROW || op->type == WEAPON) && op->slaying && QUERY_FLAG(op, FLAG_IDENTIFIED))
00976             {
00977                 safe_strcat(buf, " ", &len, sizeof(buf));
00978                 safe_strcat(buf, op->slaying, &len, sizeof(buf));
00979             }
00980     }
00981 
00982     return buf;
00983 }
00984 
00989 static void describe_terrain(object *op, char *retbuf)
00990 {
00991     if (op->terrain_flag & TERRAIN_AIRBREATH)
00992     {
00993         strcat(retbuf, "(air breathing)");
00994     }
00995 
00996     if (op->terrain_flag & TERRAIN_WATERWALK)
00997     {
00998         strcat(retbuf, "(water walking)");
00999     }
01000 
01001     if (op->terrain_flag & TERRAIN_FIREWALK)
01002     {
01003         strcat(retbuf, "(fire walking)");
01004     }
01005 
01006     if (op->terrain_flag & TERRAIN_CLOUDWALK)
01007     {
01008         strcat(retbuf, "(cloud walking)");
01009     }
01010 
01011     if (op->terrain_flag & TERRAIN_WATERBREATH)
01012     {
01013         strcat(retbuf, "(water breathing)");
01014     }
01015 
01016     if (op->terrain_flag & TERRAIN_FIREBREATH)
01017     {
01018         strcat(retbuf, "(fire breathing)");
01019     }
01020 }
01021 
01039 char *describe_item(object *op)
01040 {
01041     int attr,val, more_info = 0, id_true = 0;
01042     char buf[MAX_BUF];
01043     static char retbuf[VERY_BIG_BUF * 3];
01044 
01045     retbuf[0] = '\0';
01046 
01047     /* We start with players */
01048     if (op->type == PLAYER)
01049     {
01050         describe_terrain(op, retbuf);
01051 
01052         if (CONTR(op)->digestion)
01053         {
01054             if (CONTR(op)->digestion > 0)
01055             {
01056                 sprintf(buf, "(sustenance%+d)", CONTR(op)->digestion);
01057             }
01058             else if (CONTR(op)->digestion < 0)
01059             {
01060                 sprintf(buf, "(hunger%+d)", -CONTR(op)->digestion);
01061             }
01062 
01063             strcat(retbuf, buf);
01064         }
01065 
01066         if (CONTR(op)->gen_client_grace)
01067         {
01068             sprintf(buf, "(grace reg. %3.1f)", (float) CONTR(op)->gen_client_grace / 10);
01069             strcat(retbuf, buf);
01070         }
01071 
01072         if (CONTR(op)->gen_client_sp)
01073         {
01074             sprintf(buf, "(mana reg. %3.1f)", (float) CONTR(op)->gen_client_sp / 10);
01075             strcat(retbuf, buf);
01076         }
01077 
01078         if (CONTR(op)->gen_client_hp)
01079         {
01080             sprintf(buf, "(hp reg. %3.1f)", (float) CONTR(op)->gen_client_hp / 10);
01081             strcat(retbuf, buf);
01082         }
01083     }
01084     /* And then monsters */
01085     else if (QUERY_FLAG(op, FLAG_MONSTER))
01086     {
01087         describe_terrain(op, retbuf);
01088 
01089         if (QUERY_FLAG(op, FLAG_UNDEAD))
01090         {
01091             strcat(retbuf, "(undead)");
01092         }
01093 
01094         if (QUERY_FLAG(op, FLAG_CAN_PASS_THRU))
01095         {
01096             strcat(retbuf, "(pass through doors)");
01097         }
01098 
01099         if (QUERY_FLAG(op, FLAG_SEE_INVISIBLE))
01100         {
01101             strcat(retbuf, "(see invisible)");
01102         }
01103 
01104         if (QUERY_FLAG(op, FLAG_USE_WEAPON))
01105         {
01106             strcat(retbuf, "(wield weapon)");
01107         }
01108 
01109         if (QUERY_FLAG(op, FLAG_USE_BOW))
01110         {
01111             strcat(retbuf, "(archer)");
01112         }
01113 
01114         if (QUERY_FLAG(op, FLAG_USE_ARMOUR))
01115         {
01116             strcat(retbuf, "(wear armour)");
01117         }
01118 
01119         if (QUERY_FLAG(op, FLAG_CAST_SPELL))
01120         {
01121             strcat(retbuf, "(spellcaster)");
01122         }
01123 
01124         if (QUERY_FLAG(op, FLAG_FRIENDLY))
01125         {
01126             strcat(retbuf, "(friendly)");
01127         }
01128 
01129         if (QUERY_FLAG(op, FLAG_UNAGGRESSIVE))
01130         {
01131             strcat(retbuf, "(unaggressive)");
01132         }
01133 
01134         if (QUERY_FLAG(op, FLAG_HITBACK))
01135         {
01136             strcat(retbuf, "(hitback)");
01137         }
01138 
01139         if (FABS(op->speed) > MIN_ACTIVE_SPEED)
01140         {
01141             switch ((int) ((FABS(op->speed)) * 15))
01142             {
01143                 case 0:
01144                     strcat(retbuf, "(very slow movement)");
01145                     break;
01146 
01147                 case 1:
01148                     strcat(retbuf, "(slow movement)");
01149                     break;
01150 
01151                 case 2:
01152                     strcat(retbuf, "(normal movement)");
01153                     break;
01154 
01155                 case 3:
01156                 case 4:
01157                     strcat(retbuf, "(fast movement)");
01158                     break;
01159 
01160                 case 5:
01161                 case 6:
01162                     strcat(retbuf, "(very fast movement)");
01163                     break;
01164 
01165                 case 7:
01166                 case 8:
01167                 case 9:
01168                 case 10:
01169                     strcat(retbuf, "(extremely fast movement)");
01170                     break;
01171 
01172                 default:
01173                     strcat(retbuf, "(lightning fast movement)");
01174                     break;
01175             }
01176         }
01177     }
01178     /* Here we handle items */
01179     else
01180     {
01181         /* We only need calculate this once */
01182         if (QUERY_FLAG(op, FLAG_IDENTIFIED) || QUERY_FLAG(op, FLAG_BEEN_APPLIED) || !need_identify(op))
01183         {
01184             id_true = 1;
01185         }
01186 
01187         /* We only need to show the full details of an item if it is identified */
01188         if (id_true)
01189         {
01190             /* Terrain flags have no double use... If valid, show them */
01191             if (op->terrain_type)
01192             {
01193                 describe_terrain(op, retbuf);
01194             }
01195 
01196             /* Deal with special cases */
01197             switch (op->type)
01198             {
01199                 case WAND:
01200                 case ROD:
01201                 case HORN:
01202                     sprintf(buf, "(delay%+2.1fs)", ((float) op->last_grace / (1000000 / MAX_TIME)));
01203                     strcat(retbuf, buf);
01204 
01205                     break;
01206 
01207                 /* Armour type objects */
01208                 case ARMOUR:
01209                 case HELMET:
01210                 case SHIELD:
01211                 case BOOTS:
01212                 case GLOVES:
01213                 case GIRDLE:
01214                 case BRACERS:
01215                 case CLOAK:
01216                     if (ARMOUR_SPEED(op))
01217                     {
01218                         sprintf(buf, "(speed cap %1.2f)", ARMOUR_SPEED(op) / 10.0);
01219                         strcat(retbuf, buf);
01220                     }
01221 
01222                     /* Do this in all cases - otherwise it gets confusing - does that
01223                      * item have no penalty, or is it not fully identified for example. */
01224                     if (ARMOUR_SPELLS(op))
01225                     {
01226                         sprintf(buf, "(armour mana reg %d)", -1 * ARMOUR_SPELLS(op));
01227                         strcat(retbuf, buf);
01228                     }
01229 
01230                 case WEAPON:
01231                 case RING:
01232                 case AMULET:
01233                 case FORCE:
01234                     more_info = 1;
01235 
01236                 case BOW:
01237                 case ARROW:
01238                     if (op->type == BOW)
01239                     {
01240                         sprintf(buf, "(delay%+2.1fs)", ((float) op->stats.sp / (1000000 / MAX_TIME)));
01241                         strcat(retbuf, buf);
01242                     }
01243                     else if (op->type == ARROW)
01244                     {
01245                         sprintf(buf, "(delay%+2.1fs)", ((float) op->last_grace / (1000000 / MAX_TIME)));
01246                         strcat(retbuf, buf);
01247                     }
01248 
01249                     if (op->last_sp && !IS_ARMOR(op))
01250                     {
01251                         sprintf(buf, "(range%+d)", op->last_sp);
01252                         strcat(retbuf, buf);
01253                     }
01254 
01255                     if (op->stats.wc)
01256                     {
01257                         sprintf(buf, "(wc%+d)", op->stats.wc);
01258                         strcat(retbuf, buf);
01259                     }
01260 
01261                     if (op->stats.dam)
01262                     {
01263                         sprintf(buf, "(dam%+d)", op->stats.dam);
01264                         strcat(retbuf, buf);
01265                     }
01266 
01267                     if (op->stats.ac)
01268                     {
01269                         sprintf(buf, "(ac%+d)", op->stats.ac);
01270                         strcat(retbuf, buf);
01271                     }
01272 
01273                     if (op->type == WEAPON)
01274                     {
01275                         /* This is ugly to calculate because it's a curve that increases heavily
01276                          * with lower weapon_speed... So, we use a table */
01277                         int ws_temp = (int) (op->weapon_speed / 0.0025f);
01278 
01279                         if (ws_temp < 0)
01280                         {
01281                             ws_temp = 0;
01282                         }
01283                         else if (ws_temp > 18)
01284                         {
01285                             ws_temp = 18;
01286                         }
01287 
01288                         sprintf(buf, "(%3.2f sec)", weapon_speed_table[ws_temp]);
01289                         strcat(retbuf, buf);
01290 
01291                         if (op->level > 0)
01292                         {
01293                             sprintf(buf, "(improved %d/%d)", op->last_eat, op->level);
01294                             strcat(retbuf, buf);
01295                         }
01296                     }
01297 
01298                     break;
01299 
01300                 case FOOD:
01301                 case FLESH:
01302                 case DRINK:
01303                 {
01304                     int curse_multiplier = 1;
01305 
01306                     sprintf(buf, "(food%s%d)", op->stats.food >= 0 ? "+" : "", op->stats.food);
01307                     strcat(retbuf, buf);
01308 
01309                     if (QUERY_FLAG(op, FLAG_CURSED))
01310                     {
01311                         curse_multiplier = 2;
01312                     }
01313 
01314                     if (QUERY_FLAG(op, FLAG_DAMNED))
01315                     {
01316                         curse_multiplier = 3;
01317                     }
01318 
01319                     if (op->stats.hp)
01320                     {
01321                         snprintf(buf, sizeof(buf), "(hp%s%d)", curse_multiplier == 1 ? "+" : "", op->stats.hp * curse_multiplier);
01322                         strcat(retbuf, buf);
01323                     }
01324 
01325                     if (op->stats.sp)
01326                     {
01327                         snprintf(buf, sizeof(buf), "(mana%s%d)", curse_multiplier == 1 ? "+" : "", op->stats.sp * curse_multiplier);
01328                         strcat(retbuf, buf);
01329                     }
01330 
01331                     if (op->stats.grace)
01332                     {
01333                         snprintf(buf, sizeof(buf), "(grace%s%d)", curse_multiplier == 1 ? "+" : "", op->stats.grace * curse_multiplier);
01334                         strcat(retbuf, buf);
01335                     }
01336 
01337                     break;
01338                 }
01339 
01340                 case POTION:
01341                     if (op->last_sp)
01342                     {
01343                         sprintf(buf, "(range%+d)", op->last_sp);
01344                         strcat(retbuf, buf);
01345                     }
01346 
01347                     break;
01348 
01349                 case BOOK:
01350                     if (op->level)
01351                     {
01352                         sprintf(buf, "(lvl %d)", op->level);
01353                         strcat(retbuf, buf);
01354                     }
01355 
01356                     if (op->msg)
01357                     {
01358                         if (QUERY_FLAG(op, FLAG_NO_SKILL_IDENT))
01359                         {
01360                             strcat(retbuf, "(read)");
01361                         }
01362                         else
01363                         {
01364                             strcat(retbuf, "(unread)");
01365                         }
01366                     }
01367 
01368                 default:
01369                     return retbuf;
01370             }
01371 
01372             /* These count for every "normal" item player deals with - mostly equipment */
01373             for (attr = 0; attr < NUM_STATS; attr++)
01374             {
01375                 if ((val = get_attr_value(&(op->stats), attr)) != 0)
01376                 {
01377                     sprintf(buf, "(%s%+d)", short_stat_name[attr], val);
01378                     strcat(retbuf, buf);
01379                 }
01380             }
01381         }
01382     }
01383 
01384     /* Some special info for some identified items */
01385     if (id_true && more_info)
01386     {
01387         if (op->stats.sp)
01388         {
01389             sprintf(buf, "(mana reg.%+3.1f)", 0.4f * op->stats.sp);
01390             strcat(retbuf, buf);
01391         }
01392 
01393         if (op->stats.grace)
01394         {
01395             sprintf(buf, "(grace reg.%+3.1f)", 0.4f * op->stats.grace);
01396             strcat(retbuf, buf);
01397         }
01398 
01399         if (op->stats.hp)
01400         {
01401             sprintf(buf, "(hp reg.%+3.1f)", 0.4f * op->stats.hp);
01402             strcat(retbuf, buf);
01403         }
01404 
01405         if (op->stats.food)
01406         {
01407             if (op->stats.food > 0)
01408             {
01409                 sprintf(buf, "(sustenance%+d)", op->stats.food);
01410             }
01411             else if (op->stats.food < 0)
01412             {
01413                 sprintf(buf, "(hunger%+d)", -op->stats.food);
01414             }
01415 
01416             strcat(retbuf, buf);
01417         }
01418 
01419         if (op->stats.exp)
01420         {
01421             sprintf(buf, "(speed %+"FMT64")", op->stats.exp);
01422             strcat(retbuf, buf);
01423         }
01424     }
01425 
01426     /* Here we deal with all the special flags */
01427     if (id_true || QUERY_FLAG(op, FLAG_MONSTER) || op->type == PLAYER)
01428     {
01429         if (QUERY_FLAG(op, FLAG_SEE_INVISIBLE))
01430         {
01431             strcat(retbuf, "(see invisible)");
01432         }
01433 
01434         if (QUERY_FLAG(op, FLAG_MAKE_ETHEREAL))
01435         {
01436             strcat(retbuf, "(makes ethereal)");
01437         }
01438 
01439         if (QUERY_FLAG(op, FLAG_IS_ETHEREAL))
01440         {
01441             strcat(retbuf, "(ethereal)");
01442         }
01443 
01444         if (QUERY_FLAG(op, FLAG_MAKE_INVISIBLE))
01445         {
01446             strcat(retbuf, "(makes invisible)");
01447         }
01448 
01449         if (QUERY_FLAG(op, FLAG_IS_INVISIBLE))
01450         {
01451             strcat(retbuf, "(invisible)");
01452         }
01453 
01454         if (QUERY_FLAG(op, FLAG_XRAYS))
01455         {
01456             strcat(retbuf, "(xray-vision)");
01457         }
01458 
01459         if (QUERY_FLAG(op, FLAG_SEE_IN_DARK))
01460         {
01461             strcat(retbuf, "(infravision)");
01462         }
01463 
01464         if (QUERY_FLAG(op, FLAG_LIFESAVE))
01465         {
01466             strcat(retbuf, "(lifesaving)");
01467         }
01468 
01469         if (QUERY_FLAG(op, FLAG_REFL_SPELL))
01470         {
01471             strcat(retbuf, "(reflect spells)");
01472         }
01473 
01474         if (QUERY_FLAG(op, FLAG_REFL_MISSILE))
01475         {
01476             strcat(retbuf, "(reflect missiles)");
01477         }
01478 
01479         if (QUERY_FLAG(op, FLAG_STEALTH))
01480         {
01481             strcat(retbuf, "(stealth)");
01482         }
01483 
01484         if (QUERY_FLAG(op, FLAG_FLYING))
01485         {
01486             strcat(retbuf, "(levitate)");
01487         }
01488     }
01489 
01490     if (id_true)
01491     {
01492         if (op->slaying != NULL)
01493         {
01494             strcat(retbuf, "(slay ");
01495             strcat(retbuf, op->slaying);
01496             strcat(retbuf, ")");
01497         }
01498 
01499         strcat(retbuf, describe_attack(op, 0));
01500         strcat(retbuf, describe_protections(op, 0));
01501 
01502         DESCRIBE_PATH(retbuf, op->path_attuned, "Attuned");
01503         DESCRIBE_PATH(retbuf, op->path_repelled, "Repelled");
01504         DESCRIBE_PATH(retbuf, op->path_denied, "Denied");
01505 
01506         if (op->stats.maxhp && (op->type != HORN && op->type != ROD && op->type != WAND))
01507         {
01508             sprintf(buf, "(hp%+d)", op->stats.maxhp);
01509             strcat(retbuf, buf);
01510         }
01511 
01512         if (op->stats.maxsp)
01513         {
01514             sprintf(buf, "(mana%+d)", op->stats.maxsp);
01515             strcat(retbuf, buf);
01516         }
01517 
01518         if (op->stats.maxgrace)
01519         {
01520             sprintf(buf, "(grace%+d)", op->stats.maxgrace);
01521             strcat(retbuf, buf);
01522         }
01523 
01524         if (op->item_power)
01525         {
01526             sprintf(buf, "(item power%+d)", op->item_power);
01527             strcat(retbuf, buf);
01528         }
01529     }
01530 
01531     return retbuf;
01532 }
01533 
01538 int need_identify(object *op)
01539 {
01540     switch (op->type)
01541     {
01542         case RING:
01543         case WAND:
01544         case ROD:
01545         case HORN:
01546         case SCROLL:
01547         case SKILL:
01548         case SKILLSCROLL:
01549         case SPELLBOOK:
01550         case FOOD:
01551         case POTION:
01552         case BOW:
01553         case ARROW:
01554         case WEAPON:
01555         case ARMOUR:
01556         case SHIELD:
01557         case HELMET:
01558         case AMULET:
01559         case BOOTS:
01560         case GLOVES:
01561         case BRACERS:
01562         case GIRDLE:
01563         case CONTAINER:
01564         case DRINK:
01565         case FLESH:
01566         case INORGANIC:
01567         case CLOSE_CON:
01568         case CLOAK:
01569         case GEM:
01570         case JEWEL:
01571         case NUGGET:
01572         case PEARL:
01573         case POWER_CRYSTAL:
01574         case POISON:
01575         case BOOK:
01576         case LIGHT_APPLY:
01577         case LIGHT_REFILL:
01578             return 1;
01579     }
01580 
01581     return 0;
01582 }
01583 
01588 void identify(object *op)
01589 {
01590     object *pl;
01591 
01592     if (!op)
01593     {
01594         return;
01595     }
01596 
01597     SET_FLAG(op, FLAG_IDENTIFIED);
01598 
01599     if (op->type == POTION && op->arch != (archetype *) NULL)
01600     {
01601         FREE_AND_ADD_REF_HASH(op->name, op->arch->clone.name);
01602     }
01603     else if (op->type == SPELLBOOK && op->slaying != NULL)
01604     {
01605         if ((op->stats.sp = look_up_spell_name(op->slaying)) < 0)
01606         {
01607             char buf[256];
01608 
01609             op->stats.sp = -1;
01610             snprintf(buf, sizeof(buf), "Spell formula for %s", op->slaying);
01611             FREE_AND_COPY_HASH(op->name, buf);
01612         }
01613         else
01614         {
01615             /* Clear op->slaying since we no longer need it */
01616             FREE_AND_CLEAR_HASH(op->slaying);
01617         }
01618     }
01619 
01620     /* The shop identifies items before they hit the ground */
01621     if (op->map)
01622     {
01623         update_object(op, UP_OBJ_FACE);
01624     }
01625     else
01626     {
01627         pl = is_player_inv(op->env);
01628 
01629         /* A lot of the values can change from an update - might as well send
01630          * it all. */
01631         if (pl)
01632         {
01633             esrv_send_item(pl, op);
01634         }
01635     }
01636 }
01637 
01642 void set_trapped_flag(object *op)
01643 {
01644     object *tmp;
01645     int flag;
01646 
01647     if (!op)
01648     {
01649         return;
01650     }
01651 
01652     /* Player and monsters are not marked */
01653     if (op->type == PLAYER || op->type == MONSTER)
01654     {
01655         return;
01656     }
01657 
01658     flag = QUERY_FLAG(op, FLAG_IS_TRAPPED);
01659 
01660     for (tmp = op->inv; tmp != NULL; tmp = tmp->below)
01661     {
01662         /* Must be a rune AND visible */
01663         if (tmp->type == RUNE && tmp->stats.Cha <= 1)
01664         {
01665             SET_FLAG(op, FLAG_IS_TRAPPED);
01666 
01667             if (!flag)
01668             {
01669                 goto set_trapped_view;
01670             }
01671 
01672             return;
01673         }
01674     }
01675 
01676     /* Clean */
01677     CLEAR_FLAG(op, FLAG_IS_TRAPPED);
01678 
01679     if (!flag)
01680     {
01681         return;
01682     }
01683 
01684 set_trapped_view:
01685     /* Env object is on map */
01686     if (!op->env)
01687     {
01688         update_object(op, UP_OBJ_FACE);
01689     }
01690     /* Somewhere else - if visible, update */
01691     else
01692     {
01693         if (op->env->type == PLAYER || op->env->type == CONTAINER)
01694         {
01695             esrv_update_item(UPD_FLAGS, op->env, op);
01696         }
01697     }
01698 }