HANDLER.C
上传用户:kesirui
上传日期:2007-01-07
资源大小:263k
文件大小:35k
源码类别:

Internet/网络编程

开发平台:

WINDOWS

  1. /***************************************************************************
  2.  *  Original Diku Mud copyright (C) 1990, 1991 by Sebastian Hammer,        *
  3.  *  Michael Seifert, Hans Henrik St{rfeldt, Tom Madsen, and Katja Nyboe.   *
  4.  *                                                                         *
  5.  *  Merc Diku Mud improvments copyright (C) 1992, 1993 by Michael          *
  6.  *  Chastain, Michael Quan, and Mitchell Tse.                              *
  7.  *                                                                         *
  8.  *  In order to use any part of this Merc Diku Mud, you must comply with   *
  9.  *  both the original Diku license in 'license.doc' as well the Merc       *
  10.  *  license in 'license.txt'.  In particular, you may not remove either of *
  11.  *  these copyright notices.                                               *
  12.  *                                                                         *
  13.  *  Much time and thought has gone into this software and you are          *
  14.  *  benefitting.  We hope that you share your changes too.  What goes      *
  15.  *  around, comes around.                                                  *
  16.  ***************************************************************************/
  17. #if defined(macintosh)
  18. #include <types.h>
  19. #else
  20. #include <sys/types.h>
  21. #endif
  22. #include <ctype.h>
  23. #include <stdio.h>
  24. #include <string.h>
  25. #include <time.h>
  26. #include "merc.h"
  27. AFFECT_DATA * affect_free;
  28. /*
  29.  * Local functions.
  30.  */
  31. void affect_modify args( ( CHAR_DATA *ch, AFFECT_DATA *paf, bool fAdd ) );
  32. /*
  33.  * Retrieve a character's trusted level for permission checking.
  34.  */
  35. int get_trust( CHAR_DATA *ch )
  36. {
  37.     if ( ch->desc != NULL && ch->desc->original != NULL )
  38. ch = ch->desc->original;
  39.     if ( ch->trust != 0 )
  40. return ch->trust;
  41.     if ( IS_NPC(ch) && ch->level >= LEVEL_HERO )
  42. return LEVEL_HERO - 1;
  43.     else
  44. return ch->level;
  45. }
  46. /*
  47.  * Retrieve a character's age.
  48.  */
  49. int get_age( CHAR_DATA *ch )
  50. {
  51.     return 17 + ( ch->played + (int) (current_time - ch->logon) ) / 14400;
  52.     /* 12240 assumes 30 second hours, 24 hours a day, 20 day - Kahn */
  53. }
  54. /*
  55.  * Retrieve character's current strength.
  56.  */
  57. int get_curr_str( CHAR_DATA *ch )
  58. {
  59.     int max;
  60.     if ( IS_NPC(ch) )
  61. return 13;
  62.     if ( class_table[ch->class].attr_prime == APPLY_STR )
  63. max = 25;
  64.     else
  65. max = 22;
  66.     return URANGE( 3, ch->pcdata->perm_str + ch->pcdata->mod_str, max );
  67. }
  68. /*
  69.  * Retrieve character's current intelligence.
  70.  */
  71. int get_curr_int( CHAR_DATA *ch )
  72. {
  73.     int max;
  74.     if ( IS_NPC(ch) )
  75. return 13;
  76.     if ( class_table[ch->class].attr_prime == APPLY_INT )
  77. max = 25;
  78.     else
  79. max = 22;
  80.     return URANGE( 3, ch->pcdata->perm_int + ch->pcdata->mod_int, max );
  81. }
  82. /*
  83.  * Retrieve character's current wisdom.
  84.  */
  85. int get_curr_wis( CHAR_DATA *ch )
  86. {
  87.     int max;
  88.     if ( IS_NPC(ch) )
  89. return 13;
  90.     if ( class_table[ch->class].attr_prime == APPLY_WIS )
  91. max = 25;
  92.     else
  93. max = 22;
  94.     return URANGE( 3, ch->pcdata->perm_wis + ch->pcdata->mod_wis, max );
  95. }
  96. /*
  97.  * Retrieve character's current dexterity.
  98.  */
  99. int get_curr_dex( CHAR_DATA *ch )
  100. {
  101.     int max;
  102.     if ( IS_NPC(ch) )
  103. return 13;
  104.     if ( class_table[ch->class].attr_prime == APPLY_DEX )
  105. max = 25;
  106.     else
  107. max = 22;
  108.     return URANGE( 3, ch->pcdata->perm_dex + ch->pcdata->mod_dex, max );
  109. }
  110. /*
  111.  * Retrieve character's current constitution.
  112.  */
  113. int get_curr_con( CHAR_DATA *ch )
  114. {
  115.     int max;
  116.     if ( IS_NPC(ch) )
  117. return 13;
  118.     if ( class_table[ch->class].attr_prime == APPLY_CON )
  119. max = 25;
  120.     else
  121. max = 22;
  122.     return URANGE( 3, ch->pcdata->perm_con + ch->pcdata->mod_con, max );
  123. }
  124. /*
  125.  * Retrieve a character's carry capacity.
  126.  */
  127. int can_carry_n( CHAR_DATA *ch )
  128. {
  129.     if ( !IS_NPC(ch) && ch->level >= LEVEL_IMMORTAL )
  130. return 1000;
  131.     if ( IS_NPC(ch) && IS_SET(ch->act, ACT_PET) )
  132. return 0;
  133.     return MAX_WEAR + 2 * get_curr_dex( ch ) / 2;
  134. }
  135. /*
  136.  * Retrieve a character's carry capacity.
  137.  */
  138. int can_carry_w( CHAR_DATA *ch )
  139. {
  140.     if ( !IS_NPC(ch) && ch->level >= LEVEL_IMMORTAL )
  141. return 1000000;
  142.     if ( IS_NPC(ch) && IS_SET(ch->act, ACT_PET) )
  143. return 0;
  144.     return str_app[get_curr_str(ch)].carry;
  145. }
  146. /*
  147.  * See if a string is one of the names of an object.
  148.  */
  149. /*
  150.  * New is_name sent in by Alander.
  151.  */
  152. bool is_name( const char *str, char *namelist )
  153. {
  154.     char name[MAX_INPUT_LENGTH];
  155.     for ( ; ; )
  156.     {
  157. namelist = one_argument( namelist, name );
  158. if ( name[0] == '' )
  159.     return FALSE;
  160. if ( !str_cmp( str, name ) )
  161.     return TRUE;
  162.     }
  163. }
  164. /*
  165.  * Apply or remove an affect to a character.
  166.  */
  167. void affect_modify( CHAR_DATA *ch, AFFECT_DATA *paf, bool fAdd )
  168. {
  169.     OBJ_DATA *wield;
  170.     int mod;
  171.     mod = paf->modifier;
  172.     if ( fAdd )
  173.     {
  174. SET_BIT( ch->affected_by, paf->bitvector );
  175.     }
  176.     else
  177.     {
  178. REMOVE_BIT( ch->affected_by, paf->bitvector );
  179. mod = 0 - mod;
  180.     }
  181.     if ( IS_NPC(ch) )
  182. return;
  183.     switch ( paf->location )
  184.     {
  185.     default:
  186. bug( "Affect_modify: unknown location %d.", paf->location );
  187. return;
  188.     case APPLY_NONE: break;
  189.     case APPLY_STR:           ch->pcdata->mod_str += mod; break;
  190.     case APPLY_DEX:           ch->pcdata->mod_dex += mod; break;
  191.     case APPLY_INT:           ch->pcdata->mod_int += mod; break;
  192.     case APPLY_WIS:           ch->pcdata->mod_wis += mod; break;
  193.     case APPLY_CON:           ch->pcdata->mod_con += mod; break;
  194.     case APPLY_SEX:           ch->sex += mod;
  195.        // @@@ This next bit is from the net...
  196.        if ( ch->sex < 0 || ch->sex > 2 )
  197.           ch->sex = 0;
  198.        break;
  199.     case APPLY_CLASS: break;
  200.     case APPLY_LEVEL: break;
  201.     case APPLY_AGE: break;
  202.     case APPLY_HEIGHT: break;
  203.     case APPLY_WEIGHT: break;
  204.     case APPLY_MANA:          ch->max_mana += mod; break;
  205.     case APPLY_HIT:           ch->max_hit += mod; break;
  206.     case APPLY_MOVE:          ch->max_move += mod; break;
  207.     case APPLY_GOLD: break;
  208.     case APPLY_EXP: break;
  209.     case APPLY_AC:            ch->armor += mod; break;
  210.     case APPLY_HITROLL:       ch->hitroll += mod; break;
  211.     case APPLY_DAMROLL:       ch->damroll += mod; break;
  212.     case APPLY_SAVING_PARA:   ch->saving_throw += mod; break;
  213.     case APPLY_SAVING_ROD:    ch->saving_throw += mod; break;
  214.     case APPLY_SAVING_PETRI:  ch->saving_throw += mod; break;
  215.     case APPLY_SAVING_BREATH: ch->saving_throw += mod; break;
  216.     case APPLY_SAVING_SPELL:  ch->saving_throw += mod; break;
  217.     // Don't fault on TFC zones
  218.     case APPLY_CHARISMA:     break;
  219.     case APPLY_LUC:          break;     case APPLY_NOSTEAL:      break;     case APPLY_NOSLEEP:      break;     case APPLY_NOSUMMON:     break;     case APPLY_NOCHARM:      break;     case APPLY_NOSEXCHANGE:  break;     case APPLY_TRUESEE:      break;     case APPLY_NOINFO:       break;
  220.     }
  221.     /*
  222.      * Check for weapon wielding.
  223.      * Guard against recursion (for weapons with affects).
  224.      */
  225.     if ( ( wield = get_eq_char( ch, WEAR_WIELD ) ) != NULL
  226.     &&   get_obj_weight(wield) > str_app[get_curr_str(ch)].wield )
  227.     {
  228. static int depth;
  229. if ( depth == 0 )
  230. {
  231.     depth++;
  232.     act( "You drop $p.", ch, wield, NULL, TO_CHAR );
  233.     act( "$n drops $p.", ch, wield, NULL, TO_ROOM );
  234.     obj_from_char( wield );
  235.     obj_to_room( wield, ch->in_room );
  236.     depth--;
  237. }
  238.     }
  239.     return;
  240. }
  241. /*
  242.  * Give an affect to a char.
  243.  */
  244. void affect_to_char( CHAR_DATA *ch, AFFECT_DATA *paf )
  245. {
  246.     AFFECT_DATA *paf_new;
  247.     if ( affect_free == NULL )
  248.     {
  249. paf_new = alloc_perm( sizeof(*paf_new) );
  250.     }
  251.     else
  252.     {
  253. paf_new = affect_free;
  254. affect_free = affect_free->next;
  255.     }
  256.     *paf_new = *paf;
  257.     paf_new->next = ch->affected;
  258.     ch->affected = paf_new;
  259.     affect_modify( ch, paf_new, TRUE );
  260.     return;
  261. }
  262. /*
  263.  * Remove an affect from a char.
  264.  */
  265. void affect_remove( CHAR_DATA *ch, AFFECT_DATA *paf )
  266. {
  267.     if ( ch->affected == NULL )
  268.     {
  269. bug( "Affect_remove: no affect.", 0 );
  270. return;
  271.     }
  272.     affect_modify( ch, paf, FALSE );
  273.     if ( paf == ch->affected )
  274.     {
  275. ch->affected = paf->next;
  276.     }
  277.     else
  278.     {
  279. AFFECT_DATA *prev;
  280. for ( prev = ch->affected; prev != NULL; prev = prev->next )
  281. {
  282.     if ( prev->next == paf )
  283.     {
  284. prev->next = paf->next;
  285. break;
  286.     }
  287. }
  288. if ( prev == NULL )
  289. {
  290.     bug( "Affect_remove: cannot find paf.", 0 );
  291.     return;
  292. }
  293.     }
  294.     paf->next = affect_free;
  295.     affect_free = paf->next;
  296.     return;
  297. }
  298. /*
  299.  * Strip all affects of a given sn.
  300.  */
  301. void affect_strip( CHAR_DATA *ch, int sn )
  302. {
  303.     AFFECT_DATA *paf;
  304.     AFFECT_DATA *paf_next;
  305.     for ( paf = ch->affected; paf != NULL; paf = paf_next )
  306.     {
  307. paf_next = paf->next;
  308. if ( paf->type == sn )
  309.     affect_remove( ch, paf );
  310.     }
  311.     return;
  312. }
  313. /*
  314.  * Return true if a char is affected by a spell.
  315.  */
  316. bool is_affected( CHAR_DATA *ch, int sn )
  317. {
  318.     AFFECT_DATA *paf;
  319.     for ( paf = ch->affected; paf != NULL; paf = paf->next )
  320.     {
  321. if ( paf->type == sn )
  322.     return TRUE;
  323.     }
  324.     return FALSE;
  325. }
  326. /*
  327.  * Add or enhance an affect.
  328.  */
  329. void affect_join( CHAR_DATA *ch, AFFECT_DATA *paf )
  330. {
  331.     AFFECT_DATA *paf_old;
  332.     bool found;
  333.     found = FALSE;
  334.     for ( paf_old = ch->affected; paf_old != NULL; paf_old = paf_old->next )
  335.     {
  336. if ( paf_old->type == paf->type )
  337. {
  338.     paf->duration += paf_old->duration;
  339.     paf->modifier += paf_old->modifier;
  340.     affect_remove( ch, paf_old );
  341.     break;
  342. }
  343.     }
  344.     affect_to_char( ch, paf );
  345.     return;
  346. }
  347. /*
  348.  * Move a char out of a room.
  349.  */
  350. void char_from_room( CHAR_DATA *ch )
  351. {
  352.     OBJ_DATA *obj;
  353.     if ( ch->in_room == NULL )
  354.     {
  355. bug( "Char_from_room: NULL.", 0 );
  356. return;
  357.     }
  358.     if ( !IS_NPC(ch) )
  359. --ch->in_room->area->nplayer;
  360.     if ( ( obj = get_eq_char( ch, WEAR_LIGHT ) ) != NULL
  361.     &&   obj->item_type == ITEM_LIGHT
  362.     &&   obj->value[2] != 0
  363.     &&   ch->in_room->light > 0 )
  364. --ch->in_room->light;
  365.     if ( ch == ch->in_room->people )
  366.     {
  367. ch->in_room->people = ch->next_in_room;
  368.     }
  369.     else
  370.     {
  371. CHAR_DATA *prev;
  372. for ( prev = ch->in_room->people; prev; prev = prev->next_in_room )
  373. {
  374.     if ( prev->next_in_room == ch )
  375.     {
  376. prev->next_in_room = ch->next_in_room;
  377. break;
  378.     }
  379. }
  380. if ( prev == NULL )
  381.     bug( "Char_from_room: ch not found.", 0 );
  382.     }
  383.     ch->in_room      = NULL;
  384.     ch->next_in_room = NULL;
  385.     return;
  386. }
  387. /*
  388.  * Move a char into a room.
  389.  */
  390. void char_to_room( CHAR_DATA *ch, ROOM_INDEX_DATA *pRoomIndex )
  391. {
  392.     OBJ_DATA *obj;
  393.     if ( pRoomIndex == NULL )
  394.     {
  395. bug( "Char_to_room: NULL.", 0 );
  396. return;
  397.     }
  398.     ch->in_room = pRoomIndex;
  399.     ch->next_in_room = pRoomIndex->people;
  400.     pRoomIndex->people = ch;
  401.     if ( !IS_NPC(ch) )
  402. ++ch->in_room->area->nplayer;
  403.     if ( ( obj = get_eq_char( ch, WEAR_LIGHT ) ) != NULL
  404.     &&   obj->item_type == ITEM_LIGHT
  405.     &&   obj->value[2] != 0 )
  406. ++ch->in_room->light;
  407.     return;
  408. }
  409. /*
  410.  * Give an obj to a char.
  411.  */
  412. void obj_to_char( OBJ_DATA *obj, CHAR_DATA *ch )
  413. {
  414.     obj->next_content  = ch->carrying;
  415.     ch->carrying  = obj;
  416.     obj->carried_by  = ch;
  417.     obj->in_room  = NULL;
  418.     obj->in_obj  = NULL;
  419.     ch->carry_number += get_obj_number( obj );
  420.     ch->carry_weight += get_obj_weight( obj );
  421. }
  422. /*
  423.  * Take an obj from its character.
  424.  */
  425. void obj_from_char( OBJ_DATA *obj )
  426. {
  427.     CHAR_DATA *ch;
  428.     if ( ( ch = obj->carried_by ) == NULL )
  429.     {
  430. bug( "Obj_from_char: null ch.", 0 );
  431. return;
  432.     }
  433.     if ( obj->wear_loc != WEAR_NONE )
  434. unequip_char( ch, obj );
  435.     if ( ch->carrying == obj )
  436.     {
  437. ch->carrying = obj->next_content;
  438.     }
  439.     else
  440.     {
  441. OBJ_DATA *prev;
  442. for ( prev = ch->carrying; prev != NULL; prev = prev->next_content )
  443. {
  444.     if ( prev->next_content == obj )
  445.     {
  446. prev->next_content = obj->next_content;
  447. break;
  448.     }
  449. }
  450. if ( prev == NULL )
  451.     bug( "Obj_from_char: obj not in list.", 0 );
  452.     }
  453.     obj->carried_by  = NULL;
  454.     obj->next_content  = NULL;
  455.     ch->carry_number -= get_obj_number( obj );
  456.     ch->carry_weight -= get_obj_weight( obj );
  457.     return;
  458. }
  459. /*
  460.  * Find the ac value of an obj, including position effect.
  461.  */
  462. int apply_ac( OBJ_DATA *obj, int iWear )
  463. {
  464.     if ( obj->item_type != ITEM_ARMOR )
  465. return 0;
  466.     switch ( iWear )
  467.     {
  468.     case WEAR_BODY: return 3 * obj->value[0];
  469.     case WEAR_HEAD: return 2 * obj->value[0];
  470.     case WEAR_LEGS: return 2 * obj->value[0];
  471.     case WEAR_FEET: return     obj->value[0];
  472.     case WEAR_HANDS: return     obj->value[0];
  473.     case WEAR_ARMS: return     obj->value[0];
  474.     case WEAR_SHIELD: return     obj->value[0];
  475.     case WEAR_FINGER_L: return     obj->value[0];
  476.     case WEAR_FINGER_R: return     obj->value[0];
  477.     case WEAR_NECK_1: return     obj->value[0];
  478.     case WEAR_NECK_2: return     obj->value[0];
  479.     case WEAR_ABOUT: return 2 * obj->value[0];
  480.     case WEAR_WAIST: return     obj->value[0];
  481.     case WEAR_WRIST_L: return     obj->value[0];
  482.     case WEAR_WRIST_R: return     obj->value[0];
  483.     case WEAR_HOLD: return     obj->value[0];
  484.     }
  485.     return 0;
  486. }
  487. /*
  488.  * Find a piece of eq on a character.
  489.  */
  490. OBJ_DATA *get_eq_char( CHAR_DATA *ch, int iWear )
  491. {
  492.     OBJ_DATA *obj;
  493.     for ( obj = ch->carrying; obj != NULL; obj = obj->next_content )
  494.     {
  495. if ( obj->wear_loc == iWear )
  496.     return obj;
  497.     }
  498.     return NULL;
  499. }
  500. /*
  501.  * Equip a char with an obj.
  502.  */
  503. void equip_char( CHAR_DATA *ch, OBJ_DATA *obj, int iWear )
  504. {
  505.     AFFECT_DATA *paf;
  506.     if ( get_eq_char( ch, iWear ) != NULL )
  507.     {
  508. bug( "Equip_char: already equipped (%d).", iWear );
  509. return;
  510.     }
  511.     if ( ( IS_OBJ_STAT(obj, ITEM_ANTI_EVIL)    && IS_EVIL(ch)    )
  512.     ||   ( IS_OBJ_STAT(obj, ITEM_ANTI_GOOD)    && IS_GOOD(ch)    )
  513.     ||   ( IS_OBJ_STAT(obj, ITEM_ANTI_NEUTRAL) && IS_NEUTRAL(ch) ) )
  514.     {
  515. /*
  516.  * Thanks to Morgenes for the bug fix here!
  517.  */
  518. act( "You are zapped by $p and drop it.", ch, obj, NULL, TO_CHAR );
  519. act( "$n is zapped by $p and drops it.",  ch, obj, NULL, TO_ROOM );
  520. obj_from_char( obj );
  521. obj_to_room( obj, ch->in_room );
  522. return;
  523.     }
  524.     ch->armor       -= apply_ac( obj, iWear );
  525.     obj->wear_loc  = iWear;
  526.     for ( paf = obj->pIndexData->affected; paf != NULL; paf = paf->next )
  527. affect_modify( ch, paf, TRUE );
  528.     for ( paf = obj->affected; paf != NULL; paf = paf->next )
  529. affect_modify( ch, paf, TRUE );
  530.     if ( obj->item_type == ITEM_LIGHT
  531.     &&   obj->value[2] != 0
  532.     &&   ch->in_room != NULL )
  533. ++ch->in_room->light;
  534.     return;
  535. }
  536. /*
  537.  * Unequip a char with an obj.
  538.  */
  539. void unequip_char( CHAR_DATA *ch, OBJ_DATA *obj )
  540. {
  541.     AFFECT_DATA *paf;
  542.     if ( obj->wear_loc == WEAR_NONE )
  543.     {
  544. bug( "Unequip_char: already unequipped.", 0 );
  545. return;
  546.     }
  547.     ch->armor += apply_ac( obj, obj->wear_loc );
  548.     obj->wear_loc  = -1;
  549.     for ( paf = obj->pIndexData->affected; paf != NULL; paf = paf->next )
  550. affect_modify( ch, paf, FALSE );
  551.     for ( paf = obj->affected; paf != NULL; paf = paf->next )
  552. affect_modify( ch, paf, FALSE );
  553.     if ( obj->item_type == ITEM_LIGHT
  554.     &&   obj->value[2] != 0
  555.     &&   ch->in_room != NULL
  556.     &&   ch->in_room->light > 0 )
  557. --ch->in_room->light;
  558.     return;
  559. }
  560. /*
  561.  * Count occurrences of an obj in a list.
  562.  */
  563. int count_obj_list( OBJ_INDEX_DATA *pObjIndex, OBJ_DATA *list )
  564. {
  565.     OBJ_DATA *obj;
  566.     int nMatch;
  567.     nMatch = 0;
  568.     for ( obj = list; obj != NULL; obj = obj->next_content )
  569.     {
  570. if ( obj->pIndexData == pObjIndex )
  571.     nMatch++;
  572.     }
  573.     return nMatch;
  574. }
  575. /*
  576.  * Move an obj out of a room.
  577.  */
  578. void obj_from_room( OBJ_DATA *obj )
  579. {
  580.     ROOM_INDEX_DATA *in_room;
  581.     if ( ( in_room = obj->in_room ) == NULL )
  582.     {
  583. bug( "obj_from_room: NULL.", 0 );
  584. return;
  585.     }
  586.     if ( obj == in_room->contents )
  587.     {
  588. in_room->contents = obj->next_content;
  589.     }
  590.     else
  591.     {
  592. OBJ_DATA *prev;
  593. for ( prev = in_room->contents; prev; prev = prev->next_content )
  594. {
  595.     if ( prev->next_content == obj )
  596.     {
  597. prev->next_content = obj->next_content;
  598. break;
  599.     }
  600. }
  601. if ( prev == NULL )
  602. {
  603.     bug( "Obj_from_room: obj not found.", 0 );
  604.     return;
  605. }
  606.     }
  607.     obj->in_room      = NULL;
  608.     obj->next_content = NULL;
  609.     return;
  610. }
  611. /*
  612.  * Move an obj into a room.
  613.  */
  614. void obj_to_room( OBJ_DATA *obj, ROOM_INDEX_DATA *pRoomIndex )
  615. {
  616.     obj->next_content = pRoomIndex->contents;
  617.     pRoomIndex->contents = obj;
  618.     obj->in_room = pRoomIndex;
  619.     obj->carried_by = NULL;
  620.     obj->in_obj = NULL;
  621.     return;
  622. }
  623. /*
  624.  * Move an object into an object.
  625.  */
  626. void obj_to_obj( OBJ_DATA *obj, OBJ_DATA *obj_to )
  627. {
  628.     obj->next_content = obj_to->contains;
  629.     obj_to->contains = obj;
  630.     obj->in_obj = obj_to;
  631.     obj->in_room = NULL;
  632.     obj->carried_by = NULL;
  633.     for ( ; obj_to != NULL; obj_to = obj_to->in_obj )
  634.     {
  635. if ( obj_to->carried_by != NULL )
  636. {
  637. //     obj_to->carried_by->carry_number += get_obj_number( obj );
  638.     obj_to->carried_by->carry_weight += get_obj_weight( obj );
  639. }
  640.     }
  641.     return;
  642. }
  643. /*
  644.  * Move an object out of an object.
  645.  */
  646. void obj_from_obj( OBJ_DATA *obj )
  647. {
  648.     OBJ_DATA *obj_from;
  649.     if ( ( obj_from = obj->in_obj ) == NULL )
  650.     {
  651. bug( "Obj_from_obj: null obj_from.", 0 );
  652. return;
  653.     }
  654.     if ( obj == obj_from->contains )
  655.     {
  656. obj_from->contains = obj->next_content;
  657.     }
  658.     else
  659.     {
  660. OBJ_DATA *prev;
  661. for ( prev = obj_from->contains; prev; prev = prev->next_content )
  662. {
  663.     if ( prev->next_content == obj )
  664.     {
  665. prev->next_content = obj->next_content;
  666. break;
  667.     }
  668. }
  669. if ( prev == NULL )
  670. {
  671.     bug( "Obj_from_obj: obj not found.", 0 );
  672.     return;
  673. }
  674.     }
  675.     obj->next_content = NULL;
  676.     obj->in_obj       = NULL;
  677.     for ( ; obj_from != NULL; obj_from = obj_from->in_obj )
  678.     {
  679. if ( obj_from->carried_by != NULL )
  680. {
  681. //     obj_from->carried_by->carry_number -= get_obj_number( obj );
  682.     obj_from->carried_by->carry_weight -= get_obj_weight( obj );
  683. }
  684.     }
  685.     return;
  686. }
  687. /*
  688.  * Extract an obj from the world.
  689.  */
  690. void extract_obj( OBJ_DATA *obj )
  691. {
  692.     OBJ_DATA *obj_content;
  693.     OBJ_DATA *obj_next;
  694.     if ( obj->in_room != NULL )
  695. obj_from_room( obj );
  696.     else if ( obj->carried_by != NULL )
  697. obj_from_char( obj );
  698.     else if ( obj->in_obj != NULL )
  699. obj_from_obj( obj );
  700.     for ( obj_content = obj->contains; obj_content; obj_content = obj_next )
  701.     {
  702. obj_next = obj_content->next_content;
  703. extract_obj( obj->contains );
  704.     }
  705.     if ( object_list == obj )
  706.     {
  707. object_list = obj->next;
  708.     }
  709.     else
  710.     {
  711. OBJ_DATA *prev;
  712. for ( prev = object_list; prev != NULL; prev = prev->next )
  713. {
  714.     if ( prev->next == obj )
  715.     {
  716. prev->next = obj->next;
  717. break;
  718.     }
  719. }
  720. if ( prev == NULL )
  721. {
  722.     bug( "Extract_obj: obj %d not found.", obj->pIndexData->vnum );
  723.     return;
  724. }
  725.     }
  726.     {
  727. AFFECT_DATA *paf;
  728. AFFECT_DATA *paf_next;
  729. for ( paf = obj->affected; paf != NULL; paf = paf_next )
  730. {
  731.     paf_next    = paf->next;
  732.     paf->next   = affect_free;
  733.     affect_free = paf;
  734. }
  735.     }
  736.     {
  737. EXTRA_DESCR_DATA *ed;
  738. EXTRA_DESCR_DATA *ed_next;
  739. for ( ed = obj->extra_descr; ed != NULL; ed = ed_next )
  740. {
  741.     ed_next = ed->next;
  742.     free_string( ed->description );
  743.     free_string( ed->keyword     );
  744.     extra_descr_free = ed;
  745. }
  746.     }
  747.     free_string( obj->name        );
  748.     free_string( obj->description );
  749.     free_string( obj->short_descr );
  750.     --obj->pIndexData->count;
  751.     obj->next = obj_free;
  752.     obj_free = obj;
  753.     return;
  754. }
  755. /*
  756.  * Extract a char from the world.
  757.  */
  758. void extract_char( CHAR_DATA *ch, bool fPull )
  759. {
  760.     CHAR_DATA *wch;
  761.     OBJ_DATA *obj;
  762.     OBJ_DATA *obj_next;
  763.     if ( ch->in_room == NULL )
  764.     {
  765. bug( "Extract_char: NULL.", 0 );
  766. return;
  767.     }
  768.     if ( fPull )
  769. die_follower( ch );
  770.     stop_fighting( ch, TRUE );
  771.     for ( obj = ch->carrying; obj != NULL; obj = obj_next )
  772.     {
  773. obj_next = obj->next_content;
  774. extract_obj( obj );
  775.     }
  776.     
  777.     char_from_room( ch );
  778.     if ( !fPull )
  779.     {
  780. /* char_to_room( ch, get_room_index( ROOM_VNUM_ALTAR ) );*/
  781. char_to_room( ch, get_room_index( race_table[ch->race].city_temple ) );
  782. return;
  783.     }
  784.     if ( IS_NPC(ch) )
  785. --ch->pIndexData->count;
  786.     if ( ch->desc != NULL && ch->desc->original != NULL )
  787. do_return( ch, "" );
  788.     for ( wch = char_list; wch != NULL; wch = wch->next )
  789.     {
  790. if ( wch->reply == ch )
  791.     wch->reply = NULL;
  792.     }
  793.     if ( ch == char_list )
  794.     {
  795.        char_list = ch->next;
  796.     }
  797.     else
  798.     {
  799. CHAR_DATA *prev;
  800. for ( prev = char_list; prev != NULL; prev = prev->next )
  801. {
  802.     if ( prev->next == ch )
  803.     {
  804. prev->next = ch->next;
  805. break;
  806.     }
  807. }
  808. if ( prev == NULL )
  809. {
  810.     bug( "Extract_char: char not found.", 0 );
  811.     return;
  812. }
  813.     }
  814.     if ( ch->desc )
  815. ch->desc->character = NULL;
  816.     free_char( ch );
  817.     return;
  818. }
  819. /*
  820.  * Find a char in the room.
  821.  */
  822. CHAR_DATA *get_char_room( CHAR_DATA *ch, char *argument )
  823. {
  824.     char arg[MAX_INPUT_LENGTH];
  825.     CHAR_DATA *rch;
  826.     int number;
  827.     int count;
  828.     number = number_argument( argument, arg );
  829.     count  = 0;
  830.     if ( !str_cmp( arg, "self" ) )
  831. return ch;
  832.     for ( rch = ch->in_room->people; rch != NULL; rch = rch->next_in_room )
  833.     {
  834. if ( !can_see( ch, rch ) || !is_name( arg, rch->name ) )
  835.     continue;
  836. if ( ++count == number )
  837.     return rch;
  838.     }
  839.     return NULL;
  840. }
  841. /*
  842.  * Find a char in the world.
  843.  */
  844. CHAR_DATA *get_char_world( CHAR_DATA *ch, char *argument )
  845. {
  846.     char arg[MAX_INPUT_LENGTH];
  847.     CHAR_DATA *wch;
  848.     int number;
  849.     int count;
  850.     if ( ( wch = get_char_room( ch, argument ) ) != NULL )
  851. return wch;
  852.     number = number_argument( argument, arg );
  853.     count  = 0;
  854.     for ( wch = char_list; wch != NULL ; wch = wch->next )
  855.     {
  856. if ( !can_see( ch, wch ) || !is_name( arg, wch->name ) )
  857.     continue;
  858. if ( ++count == number )
  859.     return wch;
  860.     }
  861.     return NULL;
  862. }
  863. /*
  864.  * Find some object with a given index data.
  865.  * Used by area-reset 'P' command.
  866.  */
  867. OBJ_DATA *get_obj_type( OBJ_INDEX_DATA *pObjIndex )
  868. {
  869.     OBJ_DATA *obj;
  870.     for ( obj = object_list; obj != NULL; obj = obj->next )
  871.     {
  872. if ( obj->pIndexData == pObjIndex )
  873.     return obj;
  874.     }
  875.     return NULL;
  876. }
  877. /*
  878.  * Find an obj in a list.
  879.  */
  880. OBJ_DATA *get_obj_list( CHAR_DATA *ch, char *argument, OBJ_DATA *list )
  881. {
  882.     char arg[MAX_INPUT_LENGTH];
  883.     OBJ_DATA *obj;
  884.     int number;
  885.     int count;
  886.     number = number_argument( argument, arg );
  887.     count  = 0;
  888.     for ( obj = list; obj != NULL; obj = obj->next_content )
  889.     {
  890. if ( can_see_obj( ch, obj ) && is_name( arg, obj->name ) )
  891. {
  892.     if ( ++count == number )
  893. return obj;
  894. }
  895.     }
  896.     return NULL;
  897. }
  898. /*
  899.  * Find an obj in player's inventory.
  900.  */
  901. OBJ_DATA *get_obj_carry( CHAR_DATA *ch, char *argument )
  902. {
  903.     char arg[MAX_INPUT_LENGTH];
  904.     OBJ_DATA *obj;
  905.     int number;
  906.     int count;
  907.     number = number_argument( argument, arg );
  908.     count  = 0;
  909.     for ( obj = ch->carrying; obj != NULL; obj = obj->next_content )
  910.     {
  911. if ( obj->wear_loc == WEAR_NONE
  912. &&   can_see_obj( ch, obj )
  913. &&   is_name( arg, obj->name ) )
  914. {
  915.     if ( ++count == number )
  916. return obj;
  917. }
  918.     }
  919.     return NULL;
  920. }
  921. /*
  922.  * Find an obj in player's equipment.
  923.  */
  924. OBJ_DATA *get_obj_wear( CHAR_DATA *ch, char *argument )
  925. {
  926.     char arg[MAX_INPUT_LENGTH];
  927.     OBJ_DATA *obj;
  928.     int number;
  929.     int count;
  930.     number = number_argument( argument, arg );
  931.     count  = 0;
  932.     for ( obj = ch->carrying; obj != NULL; obj = obj->next_content )
  933.     {
  934. if ( obj->wear_loc != WEAR_NONE
  935. &&   can_see_obj( ch, obj )
  936. &&   is_name( arg, obj->name ) )
  937. {
  938.     if ( ++count == number )
  939. return obj;
  940. }
  941.     }
  942.     return NULL;
  943. }
  944. /*
  945.  * Find an obj in the room or in inventory.
  946.  */
  947. OBJ_DATA *get_obj_here( CHAR_DATA *ch, char *argument )
  948. {
  949.     OBJ_DATA *obj;
  950.     obj = get_obj_list( ch, argument, ch->in_room->contents );
  951.     if ( obj != NULL )
  952. return obj;
  953.     if ( ( obj = get_obj_carry( ch, argument ) ) != NULL )
  954. return obj;
  955.     if ( ( obj = get_obj_wear( ch, argument ) ) != NULL )
  956. return obj;
  957.     return NULL;
  958. }
  959. /*
  960.  * Find an obj in the world.
  961.  */
  962. OBJ_DATA *get_obj_world( CHAR_DATA *ch, char *argument )
  963. {
  964.     char arg[MAX_INPUT_LENGTH];
  965.     OBJ_DATA *obj;
  966.     int number;
  967.     int count;
  968.     if ( ( obj = get_obj_here( ch, argument ) ) != NULL )
  969. return obj;
  970.     number = number_argument( argument, arg );
  971.     count  = 0;
  972.     for ( obj = object_list; obj != NULL; obj = obj->next )
  973.     {
  974. if ( can_see_obj( ch, obj ) && is_name( arg, obj->name ) )
  975. {
  976.     if ( ++count == number )
  977. return obj;
  978. }
  979.     }
  980.     return NULL;
  981. }
  982. /*
  983.  * Create a 'money' obj.
  984.  */
  985. OBJ_DATA *create_money( int amount )
  986. {
  987.     char buf[MAX_STRING_LENGTH];
  988.     OBJ_DATA *obj;
  989.     if ( amount <= 0 )
  990.     {
  991. bug( "Create_money: zero or negative money %d.", amount );
  992. amount = 1;
  993.     }
  994.     if ( amount == 1 )
  995.     {
  996. obj = create_object( get_obj_index( OBJ_VNUM_MONEY_ONE ), 0 );
  997.     }
  998.     else
  999.     {
  1000. obj = create_object( get_obj_index( OBJ_VNUM_MONEY_SOME ), 0 );
  1001. sprintf( buf, obj->short_descr, amount );
  1002. free_string( obj->short_descr );
  1003. obj->short_descr = str_dup( buf );
  1004. obj->value[0] = amount;
  1005.     }
  1006.     return obj;
  1007. }
  1008. /*
  1009.  * Return # of objects which an object counts as.
  1010.  * Thanks to Tony Chamberlain for the correct recursive code here.
  1011.  */
  1012. int get_obj_number( OBJ_DATA *obj )
  1013. {
  1014. /*
  1015.     int number;
  1016.     number = 0;
  1017.     if ( obj->item_type == ITEM_CONTAINER )
  1018.       for ( obj = obj->contains; obj != NULL; obj = obj->next_content )
  1019. number += get_obj_number( obj );
  1020.     else
  1021. number = 1;
  1022.     return number;
  1023. */
  1024.     return 1;
  1025. }
  1026. /*
  1027.  * Return weight of an object, including weight of contents.
  1028.  */
  1029. int get_obj_weight( OBJ_DATA *obj )
  1030. {
  1031.     int weight;
  1032.     weight = obj->weight;
  1033.     for ( obj = obj->contains; obj != NULL; obj = obj->next_content )
  1034. weight += get_obj_weight( obj );
  1035.     return weight;
  1036. }
  1037. /*
  1038.  * True if room is dark.
  1039.  */
  1040. bool room_is_dark( ROOM_INDEX_DATA *pRoomIndex )
  1041. {
  1042.     if ( pRoomIndex->light > 0 )
  1043. return FALSE;
  1044.     if ( IS_SET(pRoomIndex->room_flags, ROOM_DARK) )
  1045. return TRUE;
  1046.     if ( pRoomIndex->sector_type == SECT_INSIDE
  1047.     ||   pRoomIndex->sector_type == SECT_CITY )
  1048. return FALSE;
  1049.     if ( weather_info.sunlight == SUN_SET
  1050.     ||   weather_info.sunlight == SUN_DARK )
  1051. return TRUE;
  1052.     return FALSE;
  1053. }
  1054. /*
  1055.  * True if room is private.
  1056.  */
  1057. bool room_is_private( ROOM_INDEX_DATA *pRoomIndex )
  1058. {
  1059.     CHAR_DATA *rch;
  1060.     int count;
  1061.     count = 0;
  1062.     for ( rch = pRoomIndex->people; rch != NULL; rch = rch->next_in_room )
  1063. count++;
  1064.     if ( IS_SET(pRoomIndex->room_flags, ROOM_PRIVATE)  && count >= 2 )
  1065. return TRUE;
  1066.     if ( IS_SET(pRoomIndex->room_flags, ROOM_SOLITARY) && count >= 1 )
  1067. return TRUE;
  1068.     return FALSE;
  1069. }
  1070. /*
  1071.  * True if char can see victim.
  1072.  */
  1073. bool can_see( CHAR_DATA *ch, CHAR_DATA *victim )
  1074. {
  1075.     if ( ch == victim )
  1076. return TRUE;
  1077.     
  1078.     if ( !IS_NPC(victim)
  1079.     &&   IS_SET(victim->act, PLR_WIZINVIS)
  1080.     &&   get_trust( ch ) < get_trust( victim ) )
  1081. return FALSE;
  1082.     if ( !IS_NPC(ch) && IS_SET(ch->act, PLR_HOLYLIGHT) )
  1083. return TRUE;
  1084.     if ( IS_AFFECTED(ch, AFF_BLIND) )
  1085. return FALSE;
  1086.     if ( room_is_dark( ch->in_room ) && !IS_AFFECTED(ch, AFF_INFRARED) )
  1087. return FALSE;
  1088.     if ( IS_AFFECTED(victim, AFF_INVISIBLE)
  1089.     &&   !IS_AFFECTED(ch, AFF_DETECT_INVIS) )
  1090. return FALSE;
  1091.     if ( IS_AFFECTED(victim, AFF_HIDE)
  1092.     &&   !IS_AFFECTED(ch, AFF_DETECT_HIDDEN)
  1093.     &&   victim->fighting == NULL
  1094.     &&   ( IS_NPC(ch) ? !IS_NPC(victim) : IS_NPC(victim) ) )
  1095. return FALSE;
  1096.     return TRUE;
  1097. }
  1098. /*
  1099.  * True if char can see obj.
  1100.  */
  1101. bool can_see_obj( CHAR_DATA *ch, OBJ_DATA *obj )
  1102. {
  1103.     if ( !IS_NPC(ch) && IS_SET(ch->act, PLR_HOLYLIGHT) )
  1104. return TRUE;
  1105.     if ( obj->item_type == ITEM_POTION )
  1106. return TRUE;
  1107.     if ( IS_AFFECTED( ch, AFF_BLIND ) )
  1108. return FALSE;
  1109.     if ( obj->item_type == ITEM_LIGHT && obj->value[2] != 0 )
  1110. return TRUE;
  1111.     if ( room_is_dark( ch->in_room ) && !IS_AFFECTED(ch, AFF_INFRARED) )
  1112. return FALSE;
  1113.     if ( IS_SET(obj->extra_flags, ITEM_INVIS)
  1114.     &&   !IS_AFFECTED(ch, AFF_DETECT_INVIS) )
  1115. return FALSE;
  1116.     return TRUE;
  1117. }
  1118. /*
  1119.  * True if char can drop obj.
  1120.  */
  1121. bool can_drop_obj( CHAR_DATA *ch, OBJ_DATA *obj )
  1122. {
  1123.     if ( !IS_SET(obj->extra_flags, ITEM_NODROP) )
  1124. return TRUE;
  1125.     if ( !IS_NPC(ch) && ch->level >= LEVEL_IMMORTAL )
  1126. return TRUE;
  1127.     return FALSE;
  1128. }
  1129. /*
  1130.  * Return ascii name of an item type.
  1131.  */
  1132. char *item_type_name( OBJ_DATA *obj )
  1133. {
  1134.     switch ( obj->item_type )
  1135.     {
  1136.     case ITEM_LIGHT: return "light";
  1137.     case ITEM_SCROLL: return "scroll";
  1138.     case ITEM_WAND: return "wand";
  1139.     case ITEM_STAFF: return "staff";
  1140.     case ITEM_WEAPON: return "weapon";
  1141.     case ITEM_TREASURE: return "treasure";
  1142.     case ITEM_ARMOR: return "armor";
  1143.     case ITEM_POTION: return "potion";
  1144.     case ITEM_FURNITURE: return "furniture";
  1145.     case ITEM_TRASH: return "trash";
  1146.     case ITEM_CONTAINER: return "container";
  1147.     case ITEM_DRINK_CON: return "drink container";
  1148.     case ITEM_KEY: return "key";
  1149.     case ITEM_FOOD: return "food";
  1150.     case ITEM_MONEY: return "money";
  1151.     case ITEM_BOAT: return "boat";
  1152.     case ITEM_CORPSE_NPC: return "npc corpse";
  1153.     case ITEM_CORPSE_PC: return "pc corpse";
  1154.     case ITEM_FOUNTAIN: return "fountain";
  1155.     case ITEM_PILL: return "pill";
  1156.     }
  1157.     bug( "Item_type_name: unknown type %d.", obj->item_type );
  1158.     return "(unknown)";
  1159. }
  1160. /*
  1161.  * Return ascii name of an affect location.
  1162.  */
  1163. char *affect_loc_name( int location )
  1164. {
  1165.     switch ( location )
  1166.     {
  1167.     case APPLY_NONE: return "none";
  1168.     case APPLY_STR: return "strength";
  1169.     case APPLY_DEX: return "dexterity";
  1170.     case APPLY_INT: return "intelligence";
  1171.     case APPLY_WIS: return "wisdom";
  1172.     case APPLY_CON: return "constitution";
  1173.     case APPLY_SEX: return "sex";
  1174.     case APPLY_CLASS: return "class";
  1175.     case APPLY_LEVEL: return "level";
  1176.     case APPLY_AGE: return "age";
  1177.     case APPLY_MANA: return "mana";
  1178.     case APPLY_HIT: return "hp";
  1179.     case APPLY_MOVE: return "moves";
  1180.     case APPLY_GOLD: return "gold";
  1181.     case APPLY_EXP: return "experience";
  1182.     case APPLY_AC: return "armor class";
  1183.     case APPLY_HITROLL: return "hit roll";
  1184.     case APPLY_DAMROLL: return "damage roll";
  1185.     case APPLY_SAVING_PARA: return "save vs paralysis";
  1186.     case APPLY_SAVING_ROD: return "save vs rod";
  1187.     case APPLY_SAVING_PETRI: return "save vs petrification";
  1188.     case APPLY_SAVING_BREATH: return "save vs breath";
  1189.     case APPLY_SAVING_SPELL: return "save vs spell";
  1190.     // Don't fault on TFC zones
  1191.     case APPLY_CHARISMA:     return "chr";
  1192.     case APPLY_LUC:          return "luck";     case APPLY_NOSTEAL:      return "anti-theft";     case APPLY_NOSLEEP:      return "nosleep";     // steadfastness?     case APPLY_NOSUMMON:     return "blocking";     case APPLY_NOCHARM:      return "nocharm";     // steadfastness?     case APPLY_NOSEXCHANGE:  return "familiarity";     case APPLY_TRUESEE:      return "true seeing";     case APPLY_NOINFO:       return "obscurement";
  1193.     }
  1194.     bug( "Affect_location_name: unknown location %d.", location );
  1195.     return "(unknown)";
  1196. }
  1197. /*
  1198.  * Return ascii name of an affect bit vector.
  1199.  */
  1200. char *affect_bit_name( int vector )
  1201. {
  1202.     static char buf[512];
  1203.     buf[0] = '';
  1204.     if ( vector & AFF_BLIND         ) strcat( buf, " blind"         );
  1205.     if ( vector & AFF_INVISIBLE     ) strcat( buf, " invisible"     );
  1206.     if ( vector & AFF_DETECT_EVIL   ) strcat( buf, " detect_evil"   );
  1207.     if ( vector & AFF_DETECT_INVIS  ) strcat( buf, " detect_invis"  );
  1208.     if ( vector & AFF_DETECT_MAGIC  ) strcat( buf, " detect_magic"  );
  1209.     if ( vector & AFF_DETECT_HIDDEN ) strcat( buf, " detect_hidden" );
  1210.     if ( vector & AFF_HOLD          ) strcat( buf, " hold"          );
  1211.     if ( vector & AFF_SANCTUARY     ) strcat( buf, " sanctuary"     );
  1212.     if ( vector & AFF_FAERIE_FIRE   ) strcat( buf, " faerie_fire"   );
  1213.     if ( vector & AFF_INFRARED      ) strcat( buf, " infrared"      );
  1214.     if ( vector & AFF_CURSE         ) strcat( buf, " curse"         );
  1215.     if ( vector & AFF_FLAMING       ) strcat( buf, " flaming"       );
  1216.     if ( vector & AFF_POISON        ) strcat( buf, " poison"        );
  1217.     if ( vector & AFF_PROTECT       ) strcat( buf, " protect"       );
  1218.     if ( vector & AFF_PARALYSIS     ) strcat( buf, " paralysis"     );
  1219.     if ( vector & AFF_SLEEP         ) strcat( buf, " sleep"         );
  1220.     if ( vector & AFF_SNEAK         ) strcat( buf, " sneak"         );
  1221.     if ( vector & AFF_HIDE          ) strcat( buf, " hide"          );
  1222.     if ( vector & AFF_CHARM         ) strcat( buf, " charm"         );
  1223.     if ( vector & AFF_FLYING        ) strcat( buf, " flying"        );
  1224.     if ( vector & AFF_PASS_DOOR     ) strcat( buf, " pass_door"     );
  1225.     return ( buf[0] != '' ) ? buf+1 : "none";
  1226. }
  1227. /*
  1228.  * Return ascii name of extra flags vector.
  1229.  */
  1230. char *extra_bit_name( int extra_flags )
  1231. {
  1232.     static char buf[512];
  1233.     buf[0] = '';
  1234.     if ( extra_flags & ITEM_GLOW         ) strcat( buf, " glow"         );
  1235.     if ( extra_flags & ITEM_HUM          ) strcat( buf, " hum"          );
  1236.     if ( extra_flags & ITEM_DARK         ) strcat( buf, " dark"         );
  1237.     if ( extra_flags & ITEM_LOCK         ) strcat( buf, " lock"         );
  1238.     if ( extra_flags & ITEM_EVIL         ) strcat( buf, " evil"         );
  1239.     if ( extra_flags & ITEM_INVIS        ) strcat( buf, " invis"        );
  1240.     if ( extra_flags & ITEM_MAGIC        ) strcat( buf, " magic"        );
  1241.     if ( extra_flags & ITEM_NODROP       ) strcat( buf, " nodrop"       );
  1242.     if ( extra_flags & ITEM_BLESS        ) strcat( buf, " bless"        );
  1243.     if ( extra_flags & ITEM_ANTI_GOOD    ) strcat( buf, " anti-good"    );
  1244.     if ( extra_flags & ITEM_ANTI_EVIL    ) strcat( buf, " anti-evil"    );
  1245.     if ( extra_flags & ITEM_ANTI_NEUTRAL ) strcat( buf, " anti-neutral" );
  1246.     if ( extra_flags & ITEM_NOREMOVE     ) strcat( buf, " noremove"     );
  1247.     if ( extra_flags & ITEM_INVENTORY    ) strcat( buf, " inventory"    );
  1248.     if ( extra_flags & 16384    ) strcat( buf, " metallic"    ); // @@@
  1249.     if ( extra_flags & ~(ITEM_GLOW|ITEM_HUM|ITEM_DARK|ITEM_LOCK|ITEM_EVIL|
  1250.           ITEM_INVIS|ITEM_MAGIC|ITEM_NODROP|ITEM_BLESS|ITEM_ANTI_GOOD|
  1251.           ITEM_ANTI_EVIL|ITEM_ANTI_NEUTRAL|ITEM_NOREMOVE|ITEM_INVENTORY|16384))
  1252.        strcat( buf, " (and unknown bits)" ); // @@@
  1253.     return ( buf[0] != '' ) ? buf+1 : "none";
  1254. }