/**************************************************************************** * Eldhamud Codebase V2.2 * * ------------------------------------------------------------------------ * * EldhaMUD code (C) 2003-2008 by Robert Powell (Tommi) * * ------------------------------------------------------------------------ * * Original SMAUG 1.4a written by Thoric (Derek Snider) with Altrag, * * Blodkai, Haus, Narn, Scryn, Swordbearer, Tricops, Gorog, Rennard, * * Grishnakh, Fireblade, and Nivek. * * * * Original MERC 2.1 code by Hatchet, Furey, and Kahn. * * * * Original DikuMUD code by: Hans Staerfeldt, Katja Nyboe, Tom Madsen, * * Michael Seifert, and Sebastian Hammer. * * ------------------------------------------------------------------------ * * Object manipulation module * ****************************************************************************/ #include <stdio.h> #include <string.h> #include <time.h> #include "./Headers/mud.h" #include "./Headers/bet.h" /*double sqrt( double x );*/ /* * External functions */ void do_token_redeem ( CHAR_DATA * ch, OBJ_DATA * obj ); /* * Local functions. */ void get_obj args ( ( CHAR_DATA * ch, OBJ_DATA * obj, OBJ_DATA * container ) ); bool remove_obj args ( ( CHAR_DATA * ch, int iWear, bool fReplace ) ); void wear_obj args ( ( CHAR_DATA * ch, OBJ_DATA * obj, bool fReplace, short wear_bit ) ); char *get_chance_verb args ( ( OBJ_DATA * obj ) ); char *get_ed_number args ( ( OBJ_DATA * obj, int number ) ); OBJ_DATA *recursive_note_find args ( ( OBJ_DATA * obj, char *argument ) ); /* * how resistant an object is to damage -Thoric */ short get_obj_resistance ( OBJ_DATA * obj ) { short resist; resist = number_fuzzy ( MAX_ITEM_IMPACT ); /* * magical items are more resistant */ if ( IS_OBJ_STAT ( obj, ITEM_MAGIC ) ) resist += number_fuzzy ( 12 ); /* * metal objects are definately stronger */ if ( IS_OBJ_STAT ( obj, ITEM_METAL ) ) resist += number_fuzzy ( 5 ); /* * organic objects are most likely weaker */ if ( IS_OBJ_STAT ( obj, ITEM_ORGANIC ) ) resist -= number_fuzzy ( 5 ); /* * blessed objects should have a little bonus */ if ( IS_OBJ_STAT ( obj, ITEM_BLESS ) ) resist += number_fuzzy ( 5 ); /* * lets make store inventory pretty tough */ if ( IS_OBJ_STAT ( obj, ITEM_INVENTORY ) ) resist += 20; /* * okay... let's add some bonus/penalty for item level... */ resist += ( obj->level / 5 ); /* * and lasty... take armor or weapon's condition into consideration */ if ( obj->item_type == ITEM_ARMOR || obj->item_type == ITEM_WEAPON ) resist += ( obj->value[0] / 2 ); return URANGE ( 10, resist, 99 ); } void get_obj ( CHAR_DATA * ch, OBJ_DATA * obj, OBJ_DATA * container ) { CLAN_DATA *clan; int weight; int amt; /* gold per-race multipliers */ if ( !CAN_WEAR ( obj, ITEM_TAKE ) && ( ch->level < 31 ) ) { send_to_char ( "You can't take that.\r\n", ch ); return; } if ( IS_SET ( obj->magic_flags, ITEM_PKDISARMED ) && !IS_NPC ( ch ) ) { if ( CAN_PKILL ( ch ) && !get_timer ( ch, TIMER_PKILLED ) ) { if ( ch->level - obj->value[5] > 5 || obj->value[5] - ch->level > 5 ) { send_to_char_color ( "\r\n&bA godly force freezes your outstretched hand.\r\n", ch ); return; } else { REMOVE_BIT ( obj->magic_flags, ITEM_PKDISARMED ); obj->value[5] = 0; } } else { send_to_char_color ( "\r\n&BA godly force freezes your outstretched hand.\r\n", ch ); return; } } if ( IS_OBJ_STAT ( obj, ITEM_PROTOTYPE ) && !can_take_proto ( ch ) ) { send_to_char ( "A godly force prevents you from getting close to it.\r\n", ch ); return; } if ( ch->carry_number + get_obj_number ( obj ) > can_carry_n ( ch ) ) { act ( AT_PLAIN, "$d: you can't carry that many items.", ch, NULL, obj->name, TO_CHAR ); return; } if ( IS_OBJ_STAT ( obj, ITEM_COVERING ) ) weight = obj->weight; else weight = get_obj_weight ( obj ); if ( ch->carry_weight + weight > can_carry_w ( ch ) ) { act ( AT_PLAIN, "$d: you can't carry that much weight.", ch, NULL, obj->name, TO_CHAR ); return; } if ( container ) { if ( container->item_type == ITEM_KEYRING && !IS_OBJ_STAT ( container, ITEM_COVERING ) ) { act ( AT_ACTION, "You remove $p from $P", ch, obj, container, TO_CHAR ); act ( AT_ACTION, "$n removes $p from $P", ch, obj, container, TO_ROOM ); } else { act ( AT_ACTION, IS_OBJ_STAT ( container, ITEM_COVERING ) ? "You get $p from beneath $P." : "You get $p from $P", ch, obj, container, TO_CHAR ); act ( AT_ACTION, IS_OBJ_STAT ( container, ITEM_COVERING ) ? "$n gets $p from beneath $P." : "$n gets $p from $P", ch, obj, container, TO_ROOM ); } if ( IS_OBJ_STAT ( container, ITEM_CLANCORPSE ) && !IS_NPC ( ch ) && str_cmp ( container->name + 7, ch->name ) ) container->value[5]++; obj_from_obj ( obj ); } else { act ( AT_ACTION, "You get $p.", ch, obj, container, TO_CHAR ); act ( AT_ACTION, "$n gets $p.", ch, obj, container, TO_ROOM ); obj_from_room ( obj ); if ( obj->timer > 0 ) { obj->timer = 0; } } /* * Clan storeroom checks */ if ( xIS_SET ( ch->in_room->room_flags, ROOM_CLANSTOREROOM ) && ( !container || container->carried_by == NULL ) ) { /* * if (!char_died) save_char_obj(ch); */ for ( clan = first_clan; clan; clan = clan->next ) if ( clan->storeroom == ch->in_room->vnum ) save_clan_storeroom ( ch, clan ); } if ( char_died ( ch ) ) return; if ( obj->item_type == ITEM_MONEY ) { amt = obj->value[0]; ch->gold += amt; extract_obj ( obj ); } else { obj = obj_to_char ( obj, ch ); } if ( char_died ( ch ) || obj_extracted ( obj ) ) return; oprog_get_trigger ( ch, obj ); return; } void do_get ( CHAR_DATA * ch, char *argument ) { char arg1[MAX_INPUT_LENGTH]; char arg2[MAX_INPUT_LENGTH]; OBJ_DATA *obj; OBJ_DATA *obj_next; OBJ_DATA *container; short number; bool found; argument = one_argument ( argument, arg1 ); if ( is_number ( arg1 ) ) { number = atoi ( arg1 ); if ( number < 1 ) { send_to_char ( "That was easy...\r\n", ch ); return; } if ( ( ch->carry_number + number ) > can_carry_n ( ch ) ) { send_to_char ( "You can't carry that many.\r\n", ch ); return; } argument = one_argument ( argument, arg1 ); } else number = 0; argument = one_argument ( argument, arg2 ); /* * munch optional words */ if ( !str_cmp ( arg2, "from" ) && argument[0] != STRING_NULL ) argument = one_argument ( argument, arg2 ); /* * Get type. */ if ( arg1[0] == STRING_NULL ) { send_to_char ( "Get what?\r\n", ch ); return; } if ( arg2[0] == STRING_NULL ) { if ( number <= 1 && str_cmp ( arg1, "all" ) && str_prefix ( "all.", arg1 ) ) { /* * 'get obj' */ obj = get_obj_list ( ch, arg1, ch->in_room->first_content ); if ( !obj ) { act ( AT_PLAIN, "I see no $T here.", ch, NULL, arg1, TO_CHAR ); return; } separate_obj ( obj ); get_obj ( ch, obj, NULL ); if ( char_died ( ch ) ) return; save_house_by_vnum ( ch->in_room->vnum ); /* House Object Saving */ if ( IS_SET ( sysdata.save_flags, SV_GET ) ) save_char_obj ( ch ); } else { short cnt = 0; bool fAll; char *chk; if ( xIS_SET ( ch->in_room->room_flags, ROOM_DONATION ) ) { send_to_char ( "The gods frown upon such a display of greed!\r\n", ch ); return; } if ( !str_cmp ( arg1, "all" ) ) fAll = TRUE; else fAll = FALSE; if ( number > 1 ) chk = arg1; else chk = &arg1[4]; /* * 'get all' or 'get all.obj' */ found = FALSE; for ( obj = ch->in_room->last_content; obj; obj = obj_next ) { obj_next = obj->prev_content; if ( ( fAll || nifty_is_name ( chk, obj->name ) ) && can_see_obj ( ch, obj ) ) { if ( IS_OBJ_STAT ( obj, ITEM_ONMAP ) ) { if ( ch->map != obj->map || ch->x != obj->x || ch->y != obj->y ) { found = FALSE; continue; } } found = TRUE; if ( number && ( cnt + obj->count ) > number ) split_obj ( obj, number - cnt ); cnt += obj->count; get_obj ( ch, obj, NULL ); if ( char_died ( ch ) || ch->carry_number >= can_carry_n ( ch ) || ch->carry_weight >= can_carry_w ( ch ) || ( number && cnt >= number ) ) { if ( IS_SET ( sysdata.save_flags, SV_GET ) && !char_died ( ch ) ) save_char_obj ( ch ); return; } } } if ( !found ) { if ( fAll ) send_to_char ( "I see nothing here.\r\n", ch ); else act ( AT_PLAIN, "I see no $T here.", ch, NULL, chk, TO_CHAR ); } else { save_house_by_vnum ( ch->in_room->vnum ); /* House Object Saving */ if ( IS_SET ( sysdata.save_flags, SV_GET ) ) save_char_obj ( ch ); } } } else { /* * 'get ... container' */ if ( !str_cmp ( arg2, "all" ) || !str_prefix ( "all.", arg2 ) ) { send_to_char ( "You can't do that.\r\n", ch ); return; } if ( ( container = get_obj_here ( ch, arg2 ) ) == NULL ) { act ( AT_PLAIN, "I see no $T here.", ch, NULL, arg2, TO_CHAR ); return; } switch ( container->item_type ) { default: if ( !IS_OBJ_STAT ( container, ITEM_COVERING ) ) { send_to_char ( "That's not a container.\r\n", ch ); return; } if ( ch->carry_weight + container->weight > can_carry_w ( ch ) ) { send_to_char ( "It's too heavy for you to lift.\r\n", ch ); return; } break; case ITEM_CONTAINER: case ITEM_CORPSE_NPC: case ITEM_KEYRING: case ITEM_QUIVER: break; case ITEM_CORPSE_PC: { char name[MAX_INPUT_LENGTH]; CHAR_DATA *gch; char *pd; if ( IS_NPC ( ch ) ) { send_to_char ( "You can't do that.\r\n", ch ); return; } pd = container->short_descr; pd = one_argument ( pd, name ); pd = one_argument ( pd, name ); pd = one_argument ( pd, name ); pd = one_argument ( pd, name ); if ( IS_OBJ_STAT ( container, ITEM_CLANCORPSE ) && !IS_NPC ( ch ) && ( get_timer ( ch, TIMER_PKILLED ) > 0 ) && str_cmp ( name, ch->name ) ) { send_to_char ( "You cannot loot from that corpse...yet.\r\n", ch ); return; } /* * Killer/owner loot only if die to pkill blow --Blod */ /* * Added check for immortal so IMMS can get things out of * * corpses --Shaddai */ if ( IS_OBJ_STAT ( container, ITEM_CLANCORPSE ) && !IS_NPC ( ch ) && !IS_IMMORTAL ( ch ) && container->action_desc[0] != STRING_NULL && str_cmp ( name, ch->name ) && str_cmp ( container->action_desc, ch->name ) ) { send_to_char ( "You did not inflict the death blow upon this corpse.\r\n", ch ); return; } if ( IS_OBJ_STAT ( container, ITEM_CLANCORPSE ) && !IS_NPC ( ch ) && str_cmp ( name, ch->name ) && container->value[5] >= 3 ) { send_to_char ( "Frequent looting has left this corpse protected by the gods.\r\n", ch ); return; } if ( IS_OBJ_STAT ( container, ITEM_CLANCORPSE ) && !IS_NPC ( ch ) && IS_SET ( ch->pcdata->flags, PCFLAG_DEADLY ) && container->value[4] - ch->level < 6 && container->value[4] - ch->level > -6 ) break; if ( str_cmp ( name, ch->name ) && !IS_IMMORTAL ( ch ) ) { bool fGroup; fGroup = FALSE; for ( gch = first_char; gch; gch = gch->next ) { if ( !IS_NPC ( gch ) && is_same_group ( ch, gch ) && !str_cmp ( name, gch->name ) ) { fGroup = TRUE; break; } } if ( !fGroup ) { send_to_char ( "That's someone else's corpse.\r\n", ch ); return; } } } } if ( !IS_OBJ_STAT ( container, ITEM_COVERING ) && IS_SET ( container->value[1], CONT_CLOSED ) ) { act ( AT_PLAIN, "The $d is closed.", ch, NULL, container->name, TO_CHAR ); return; } if ( number <= 1 && str_cmp ( arg1, "all" ) && str_prefix ( "all.", arg1 ) ) { /* * 'get obj container' */ obj = get_obj_list ( ch, arg1, container->first_content ); if ( !obj ) { act ( AT_PLAIN, IS_OBJ_STAT ( container, ITEM_COVERING ) ? "I see nothing like that beneath the $T." : "I see nothing like that in the $T.", ch, NULL, arg2, TO_CHAR ); return; } separate_obj ( obj ); get_obj ( ch, obj, container ); if ( char_died ( ch ) ) return; if ( IS_SET ( sysdata.save_flags, SV_GET ) ) save_char_obj ( ch ); } else { int cnt = 0; bool fAll; char *chk; /* * 'get all container' or 'get all.obj container' */ if ( IS_OBJ_STAT ( container, ITEM_DONATION ) ) { send_to_char ( "The gods frown upon such an act of greed!\r\n", ch ); return; } if ( IS_OBJ_STAT ( container, ITEM_CLANCORPSE ) && !IS_IMMORTAL ( ch ) && !IS_NPC ( ch ) && str_cmp ( ch->name, container->name + 7 ) ) { send_to_char ( "The gods frown upon such wanton greed!\r\n", ch ); return; } if ( !str_cmp ( arg1, "all" ) ) fAll = TRUE; else fAll = FALSE; if ( number > 1 ) chk = arg1; else chk = &arg1[4]; found = FALSE; for ( obj = container->first_content; obj; obj = obj_next ) { obj_next = obj->next_content; if ( ( fAll || nifty_is_name ( chk, obj->name ) ) && can_see_obj ( ch, obj ) ) { found = TRUE; if ( number && ( cnt + obj->count ) > number ) split_obj ( obj, number - cnt ); cnt += obj->count; get_obj ( ch, obj, container ); if ( char_died ( ch ) || ch->carry_number >= can_carry_n ( ch ) || ch->carry_weight >= can_carry_w ( ch ) || ( number && cnt >= number ) ) { if ( found && IS_SET ( sysdata.save_flags, SV_GET ) ) save_char_obj ( ch ); return; } } } if ( !found ) { if ( fAll ) { if ( container->item_type == ITEM_KEYRING && !IS_OBJ_STAT ( container, ITEM_COVERING ) ) act ( AT_PLAIN, "The $T holds no keys.", ch, NULL, arg2, TO_CHAR ); else act ( AT_PLAIN, IS_OBJ_STAT ( container, ITEM_COVERING ) ? "I see nothing beneath the $T." : "I see nothing in the $T.", ch, NULL, arg2, TO_CHAR ); } else { if ( container->item_type == ITEM_KEYRING && !IS_OBJ_STAT ( container, ITEM_COVERING ) ) act ( AT_PLAIN, "The $T does not hold that key.", ch, NULL, arg2, TO_CHAR ); else act ( AT_PLAIN, IS_OBJ_STAT ( container, ITEM_COVERING ) ? "I see nothing like that beneath the $T." : "I see nothing like that in the $T.", ch, NULL, arg2, TO_CHAR ); } } if ( char_died ( ch ) ) return; if ( found && IS_SET ( sysdata.save_flags, SV_GET ) ) save_char_obj ( ch ); } } return; } void do_put ( CHAR_DATA * ch, char *argument ) { char arg1[MAX_INPUT_LENGTH]; char arg2[MAX_INPUT_LENGTH]; OBJ_DATA *container; OBJ_DATA *obj; OBJ_DATA *obj_next; CLAN_DATA *clan; short count; int number; bool save_char = FALSE; argument = one_argument ( argument, arg1 ); if ( is_number ( arg1 ) ) { number = atoi ( arg1 ); if ( number < 1 ) { send_to_char ( "That was easy...\r\n", ch ); return; } argument = one_argument ( argument, arg1 ); } else number = 0; argument = one_argument ( argument, arg2 ); /* * munch optional words */ if ( ( !str_cmp ( arg2, "into" ) || !str_cmp ( arg2, "inside" ) || !str_cmp ( arg2, "in" ) || !str_cmp ( arg2, "under" ) || !str_cmp ( arg2, "onto" ) || !str_cmp ( arg2, "on" ) ) && argument[0] != STRING_NULL ) argument = one_argument ( argument, arg2 ); if ( arg1[0] == STRING_NULL || arg2[0] == STRING_NULL ) { send_to_char ( "Put what in what?\r\n", ch ); return; } if ( !str_cmp ( arg2, "all" ) || !str_prefix ( "all.", arg2 ) ) { send_to_char ( "You can't do that.\r\n", ch ); return; } if ( ( container = get_obj_here ( ch, arg2 ) ) == NULL ) { act ( AT_PLAIN, "I see no $T here.", ch, NULL, arg2, TO_CHAR ); return; } if ( !container->carried_by && IS_SET ( sysdata.save_flags, SV_PUT ) ) save_char = TRUE; if ( IS_OBJ_STAT ( container, ITEM_COVERING ) ) { if ( ch->carry_weight + container->weight > can_carry_w ( ch ) ) { send_to_char ( "It's too heavy for you to lift.\r\n", ch ); return; } } else { if ( container->item_type != ITEM_CONTAINER && container->item_type != ITEM_KEYRING && container->item_type != ITEM_QUIVER ) { send_to_char ( "That's not a container.\r\n", ch ); return; } if ( IS_SET ( container->value[1], CONT_CLOSED ) ) { act ( AT_PLAIN, "The $d is closed.", ch, NULL, container->name, TO_CHAR ); return; } } if ( number <= 1 && str_cmp ( arg1, "all" ) && str_prefix ( "all.", arg1 ) ) { /* * 'put obj container' */ if ( ( obj = get_obj_carry ( ch, arg1 ) ) == NULL ) { send_to_char ( "You do not have that item.\r\n", ch ); return; } if ( obj == container ) { send_to_char ( "You can't fold it into itself.\r\n", ch ); return; } if ( !can_drop_obj ( ch, obj ) ) { send_to_char ( "You can't let go of it.\r\n", ch ); return; } if ( container->item_type == ITEM_KEYRING && obj->item_type != ITEM_KEY ) { send_to_char ( "That's not a key.\r\n", ch ); return; } if ( container->item_type == ITEM_QUIVER && obj->item_type != ITEM_PROJECTILE ) { send_to_char ( "That's not a projectile.\r\n", ch ); return; } if ( ( IS_OBJ_STAT ( container, ITEM_COVERING ) && ( get_obj_weight ( obj ) / obj->count ) > ( ( get_obj_weight ( container ) / container->count ) - container->weight ) ) ) { send_to_char ( "It won't fit under there.\r\n", ch ); return; } /* * note use of get_real_obj_weight */ if ( ( get_real_obj_weight ( obj ) / obj->count ) + ( get_real_obj_weight ( container ) / container->count ) > container->value[0] ) { send_to_char ( "It won't fit.\r\n", ch ); return; } separate_obj ( obj ); separate_obj ( container ); obj_from_char ( obj ); obj = obj_to_obj ( obj, container ); if ( char_died ( ch ) ) return; count = obj->count; obj->count = 1; if ( container->item_type == ITEM_KEYRING && !IS_OBJ_STAT ( container, ITEM_COVERING ) ) { act ( AT_ACTION, "$n slips $p onto $P.", ch, obj, container, TO_ROOM ); act ( AT_ACTION, "You slip $p onto $P.", ch, obj, container, TO_CHAR ); } else { act ( AT_ACTION, IS_OBJ_STAT ( container, ITEM_COVERING ) ? "$n hides $p beneath $P." : "$n puts $p in $P.", ch, obj, container, TO_ROOM ); act ( AT_ACTION, IS_OBJ_STAT ( container, ITEM_COVERING ) ? "You hide $p beneath $P." : "You put $p in $P.", ch, obj, container, TO_CHAR ); } obj->count = count; if ( save_char ) save_char_obj ( ch ); /* * Clan storeroom check */ if ( xIS_SET ( ch->in_room->room_flags, ROOM_CLANSTOREROOM ) && container->carried_by == NULL ) { /* * if (!char_died && !save_char ) save_char_obj(ch); */ for ( clan = first_clan; clan; clan = clan->next ) if ( clan->storeroom == ch->in_room->vnum ) save_clan_storeroom ( ch, clan ); } } else { bool found = FALSE; int cnt = 0; bool fAll; char *chk; if ( !str_cmp ( arg1, "all" ) ) fAll = TRUE; else fAll = FALSE; if ( number > 1 ) chk = arg1; else chk = &arg1[4]; separate_obj ( container ); /* * 'put all container' or 'put all.obj container' */ for ( obj = ch->first_carrying; obj; obj = obj_next ) { obj_next = obj->next_content; if ( ( fAll || nifty_is_name ( chk, obj->name ) ) && can_see_obj ( ch, obj ) && obj->wear_loc == WEAR_NONE && obj != container && can_drop_obj ( ch, obj ) && ( container->item_type != ITEM_KEYRING || obj->item_type == ITEM_KEY ) && ( container->item_type != ITEM_QUIVER || obj->item_type == ITEM_PROJECTILE ) && get_obj_weight ( obj ) + get_obj_weight ( container ) <= container->value[0] ) { if ( number && ( cnt + obj->count ) > number ) split_obj ( obj, number - cnt ); cnt += obj->count; obj_from_char ( obj ); if ( container->item_type == ITEM_KEYRING ) { act ( AT_ACTION, "$n slips $p onto $P.", ch, obj, container, TO_ROOM ); act ( AT_ACTION, "You slip $p onto $P.", ch, obj, container, TO_CHAR ); } else { act ( AT_ACTION, "$n puts $p in $P.", ch, obj, container, TO_ROOM ); act ( AT_ACTION, "You put $p in $P.", ch, obj, container, TO_CHAR ); } obj = obj_to_obj ( obj, container ); found = TRUE; if ( char_died ( ch ) ) return; if ( number && cnt >= number ) break; } } /* * Don't bother to save anything if nothing was dropped -Thoric */ if ( !found ) { if ( fAll ) act ( AT_PLAIN, "You are not carrying anything.", ch, NULL, NULL, TO_CHAR ); else act ( AT_PLAIN, "You are not carrying any $T.", ch, NULL, chk, TO_CHAR ); return; } if ( save_char ) save_char_obj ( ch ); /* * Clan storeroom check */ if ( xIS_SET ( ch->in_room->room_flags, ROOM_CLANSTOREROOM ) && container->carried_by == NULL ) { /* * if (!char_died && !save_char) save_char_obj(ch); */ for ( clan = first_clan; clan; clan = clan->next ) if ( clan->storeroom == ch->in_room->vnum ) save_clan_storeroom ( ch, clan ); } } return; } void do_drop ( CHAR_DATA * ch, char *argument ) { char arg[MAX_INPUT_LENGTH]; OBJ_DATA *obj; OBJ_DATA *obj_next; bool found; CLAN_DATA *clan; int number; argument = one_argument ( argument, arg ); if ( is_number ( arg ) ) { number = atoi ( arg ); if ( number < 1 ) { send_to_char ( "That was easy...\r\n", ch ); return; } argument = one_argument ( argument, arg ); } else number = 0; if ( arg[0] == STRING_NULL ) { send_to_char ( "Drop what?\r\n", ch ); return; } if ( !IS_NPC ( ch ) && xIS_SET ( ch->act, PLR_LITTERBUG ) ) { set_char_color ( AT_YELLOW, ch ); send_to_char ( "A godly force prevents you from dropping anything...\r\n", ch ); return; } if ( xIS_SET ( ch->in_room->room_flags, ROOM_NODROP ) && ch != supermob ) { set_char_color ( AT_MAGIC, ch ); send_to_char ( "A magical force stops you!\r\n", ch ); set_char_color ( AT_TELL, ch ); send_to_char ( "Someone tells you, 'No littering here!'\r\n", ch ); return; } if ( number > 0 ) { /* * 'drop NNNN coins' */ if ( !str_cmp ( arg, "coins" ) || !str_cmp ( arg, "coin" ) ) { if ( ch->gold < number ) { send_to_char ( "You haven't got that many coins.\r\n", ch ); return; } ch->gold -= number; for ( obj = ch->in_room->first_content; obj; obj = obj_next ) { obj_next = obj->next_content; switch ( obj->pIndexData->vnum ) { case OBJ_VNUM_MONEY_ONE: number += 1; extract_obj ( obj ); break; case OBJ_VNUM_MONEY_SOME: number += obj->value[0]; extract_obj ( obj ); break; } } act ( AT_ACTION, "$n drops some gold.", ch, NULL, NULL, TO_ROOM ); obj_to_room ( create_money ( number ), ch->in_room, ch ); save_house_by_vnum ( ch->in_room->vnum ); /* House Object Saving */ send_to_char ( "You let the gold slip from your hand.\r\n", ch ); if ( IS_SET ( sysdata.save_flags, SV_DROP ) ) save_char_obj ( ch ); return; } } if ( number <= 1 && str_cmp ( arg, "all" ) && str_prefix ( "all.", arg ) ) { /* * 'drop obj' */ if ( ( obj = get_obj_carry ( ch, arg ) ) == NULL ) { send_to_char ( "You do not have that item.\r\n", ch ); return; } if ( !can_drop_obj ( ch, obj ) ) { send_to_char ( "You can't let go of it.\r\n", ch ); return; } separate_obj ( obj ); act ( AT_ACTION, "$n drops $p.", ch, obj, NULL, TO_ROOM ); act ( AT_ACTION, "You drop $p.", ch, obj, NULL, TO_CHAR ); obj_from_char ( obj ); obj = obj_to_room ( obj, ch->in_room, ch ); oprog_drop_trigger ( ch, obj ); /* mudprogs */ if ( char_died ( ch ) || obj_extracted ( obj ) ) return; /* * Clan storeroom saving */ if ( xIS_SET ( ch->in_room->room_flags, ROOM_CLANSTOREROOM ) ) { /* * if (!char_died) save_char_obj(ch); */ for ( clan = first_clan; clan; clan = clan->next ) if ( clan->storeroom == ch->in_room->vnum ) save_clan_storeroom ( ch, clan ); } } else { int cnt = 0; char *chk; bool fAll; if ( !str_cmp ( arg, "all" ) ) fAll = TRUE; else fAll = FALSE; if ( number > 1 ) chk = arg; else chk = &arg[4]; /* * 'drop all' or 'drop all.obj' */ if ( xIS_SET ( ch->in_room->room_flags, ROOM_NODROPALL ) || xIS_SET ( ch->in_room->room_flags, ROOM_CLANSTOREROOM ) ) { send_to_char ( "You can't seem to do that here...\r\n", ch ); return; } found = FALSE; for ( obj = ch->first_carrying; obj; obj = obj_next ) { obj_next = obj->next_content; if ( ( fAll || nifty_is_name ( chk, obj->name ) ) && can_see_obj ( ch, obj ) && obj->wear_loc == WEAR_NONE && can_drop_obj ( ch, obj ) ) { found = TRUE; if ( HAS_PROG ( obj->pIndexData, DROP_PROG ) && obj->count > 1 ) { ++cnt; separate_obj ( obj ); obj_from_char ( obj ); if ( !obj_next ) obj_next = ch->first_carrying; } else { if ( number && ( cnt + obj->count ) > number ) split_obj ( obj, number - cnt ); cnt += obj->count; obj_from_char ( obj ); } act ( AT_ACTION, "$n drops $p.", ch, obj, NULL, TO_ROOM ); act ( AT_ACTION, "You drop $p.", ch, obj, NULL, TO_CHAR ); obj = obj_to_room ( obj, ch->in_room, ch ); oprog_drop_trigger ( ch, obj ); /* mudprogs */ if ( char_died ( ch ) ) return; if ( number && cnt >= number ) break; } } if ( !found ) { if ( fAll ) act ( AT_PLAIN, "You are not carrying anything.", ch, NULL, NULL, TO_CHAR ); else act ( AT_PLAIN, "You are not carrying any $T.", ch, NULL, chk, TO_CHAR ); save_house_by_vnum ( ch->in_room->vnum ); /* House Object Saving */ } } if ( IS_SET ( sysdata.save_flags, SV_DROP ) ) save_char_obj ( ch ); /* duping protector */ return; } void do_give ( CHAR_DATA * ch, char *argument ) { char arg1[MAX_INPUT_LENGTH]; char arg2[MAX_INPUT_LENGTH]; char buf[MAX_INPUT_LENGTH]; CHAR_DATA *victim, *questman; OBJ_DATA *obj; argument = one_argument ( argument, arg1 ); argument = one_argument ( argument, arg2 ); if ( !str_cmp ( arg2, "to" ) && argument[0] != STRING_NULL ) argument = one_argument ( argument, arg2 ); if ( arg1[0] == STRING_NULL || arg2[0] == STRING_NULL ) { send_to_char ( "Give what to whom?\r\n", ch ); return; } if ( is_number ( arg1 ) ) { /* * 'give NNNN coins victim' */ int amount; amount = atoi ( arg1 ); if ( amount <= 0 || ( str_cmp ( arg2, "coins" ) && str_cmp ( arg2, "coin" ) ) ) { send_to_char ( "Sorry, you can't do that.\r\n", ch ); return; } argument = one_argument ( argument, arg2 ); if ( !str_cmp ( arg2, "to" ) && argument[0] != STRING_NULL ) argument = one_argument ( argument, arg2 ); if ( arg2[0] == STRING_NULL ) { send_to_char ( "Give what to whom?\r\n", ch ); return; } if ( ( victim = get_char_room ( ch, arg2 ) ) == NULL ) { send_to_char ( "They aren't here.\r\n", ch ); return; } if ( ch->gold < amount ) { send_to_char ( "Very generous of you, but you haven't got that much gold.\r\n", ch ); return; } ch->gold -= amount; victim->gold += amount; strcpy ( buf, "$n gives you " ); strcat ( buf, arg1 ); strcat ( buf, ( amount > 1 ) ? " coins." : " coin." ); act ( AT_ACTION, buf, ch, NULL, victim, TO_VICT ); act ( AT_ACTION, "$n gives $N some gold.", ch, NULL, victim, TO_NOTVICT ); act ( AT_ACTION, "You give $N some gold.", ch, NULL, victim, TO_CHAR ); mprog_bribe_trigger ( victim, ch, amount ); if ( IS_SET ( sysdata.save_flags, SV_GIVE ) && !char_died ( ch ) ) save_char_obj ( ch ); if ( IS_SET ( sysdata.save_flags, SV_RECEIVE ) && !char_died ( victim ) ) save_char_obj ( victim ); return; } if ( ( obj = get_obj_carry ( ch, arg1 ) ) == NULL ) { send_to_char ( "You do not have that item.\r\n", ch ); return; } if ( obj->wear_loc != WEAR_NONE ) { send_to_char ( "You must remove it first.\r\n", ch ); return; } if ( ( victim = get_char_room ( ch, arg2 ) ) == NULL ) { send_to_char ( "They aren't here.\r\n", ch ); return; } if ( !can_drop_obj ( ch, obj ) ) { send_to_char ( "You can't let go of it.\r\n", ch ); return; } if ( obj->item_type == ITEM_QUESTTOKEN ) { if ( !str_prefix ( "all.", arg1 ) ) { send_to_char ( "You cannot give all.token, this is to stop a crash, will fix it soon as possible\r\n", ch ); return; } for ( questman = ch->in_room->first_person; questman != NULL; questman = questman->next_in_room ) if ( IS_NPC ( questman ) && xIS_SET ( questman->act, ACT_QUESTMASTER ) ) break; if ( questman ) { if ( ( victim = get_char_room ( ch, arg2 ) ) == questman ) { separate_obj ( obj ); obj_from_char ( obj ); act ( AT_ACTION, "$n gives $p to $N.", ch, obj, victim, TO_NOTVICT ); act ( AT_ACTION, "$n gives you $p.", ch, obj, victim, TO_VICT ); act ( AT_ACTION, "You give $p to $N.", ch, obj, victim, TO_CHAR ); obj = obj_to_char ( obj, victim ); mprog_give_trigger ( victim, ch, obj ); if ( IS_SET ( sysdata.save_flags, SV_GIVE ) && !char_died ( ch ) ) save_char_obj ( ch ); if ( IS_SET ( sysdata.save_flags, SV_RECEIVE ) && !char_died ( victim ) ) save_char_obj ( victim ); do_token_redeem ( ch, obj ); return; } } } if ( victim->carry_number + ( get_obj_number ( obj ) / obj->count ) > can_carry_n ( victim ) ) { act ( AT_PLAIN, "$N has $S hands full.", ch, NULL, victim, TO_CHAR ); obj->timer = 1; return; } if ( victim->carry_weight + ( get_obj_weight ( obj ) / obj->count ) > can_carry_w ( victim ) ) { act ( AT_PLAIN, "$N can't carry that much weight.", ch, NULL, victim, TO_CHAR ); obj->timer = 1; return; } if ( !can_see_obj ( victim, obj ) ) { act ( AT_PLAIN, "$N can't see it.", ch, NULL, victim, TO_CHAR ); return; } if ( IS_OBJ_STAT ( obj, ITEM_PROTOTYPE ) && !can_take_proto ( victim ) ) { act ( AT_PLAIN, "You cannot give that to $N!", ch, NULL, victim, TO_CHAR ); return; } separate_obj ( obj ); obj_from_char ( obj ); act ( AT_ACTION, "$n gives $p to $N.", ch, obj, victim, TO_NOTVICT ); act ( AT_ACTION, "$n gives you $p.", ch, obj, victim, TO_VICT ); act ( AT_ACTION, "You give $p to $N.", ch, obj, victim, TO_CHAR ); obj = obj_to_char ( obj, victim ); mprog_give_trigger ( victim, ch, obj ); if ( IS_SET ( sysdata.save_flags, SV_GIVE ) && !char_died ( ch ) ) save_char_obj ( ch ); if ( IS_SET ( sysdata.save_flags, SV_RECEIVE ) && !char_died ( victim ) ) save_char_obj ( victim ); return; } /* * Damage an object. -Thoric * Affect player's AC if necessary. * Make object into scraps if necessary. * Send message about damaged object. */ obj_ret damage_obj ( OBJ_DATA * obj ) { CHAR_DATA *ch; obj_ret objcode; int random_number; ch = obj->carried_by; objcode = rNONE; separate_obj ( obj ); if ( !IS_NPC ( ch ) && ( !IS_PKILL ( ch ) || ( IS_PKILL ( ch ) && !IS_SET ( ch->pcdata->flags, PCFLAG_GAG ) ) ) ) act ( AT_OBJECT, "($p gets damaged)", ch, obj, NULL, TO_CHAR ); else if ( obj->in_room && ( ch = obj->in_room->first_person ) != NULL ) { act ( AT_OBJECT, "($p gets damaged)", ch, obj, NULL, TO_ROOM ); act ( AT_OBJECT, "($p gets damaged)", ch, obj, NULL, TO_CHAR ); ch = NULL; } if ( obj->item_type != ITEM_LIGHT ) oprog_damage_trigger ( ch, obj ); else if ( !in_arena ( ch ) ) oprog_damage_trigger ( ch, obj ); if ( obj_extracted ( obj ) ) return global_objcode; switch ( obj->item_type ) { default: make_scraps ( obj ); objcode = rOBJ_SCRAPPED; break; case ITEM_CONTAINER: if ( --obj->value[3] <= 0 ) { if ( !in_arena ( ch ) ) { make_scraps ( obj ); objcode = rOBJ_SCRAPPED; } else obj->value[3] = 1; } case ITEM_SHOVEL: case ITEM_KEYRING: case ITEM_QUIVER: if ( --obj->value[3] <= 0 ) { if ( !in_arena ( ch ) ) { make_scraps ( obj ); objcode = rOBJ_SCRAPPED; } else obj->value[3] = 1; } break; case ITEM_LIGHT: if ( --obj->value[0] <= 0 ) { if ( !in_arena ( ch ) ) { make_scraps ( obj ); objcode = rOBJ_SCRAPPED; } else obj->value[0] = 1; } break; case ITEM_ARMOR: random_number = number_range ( 0, 4 ); if ( random_number == 1 ) { if ( --obj->value[3] <= 0 ) { make_scraps ( obj ); objcode = rOBJ_SCRAPPED; } } break; case ITEM_WEAPON: random_number = number_range ( 0, 4 ); if ( random_number == 1 ) { if ( --obj->value[0] <= 0 ) { make_scraps ( obj ); objcode = rOBJ_SCRAPPED; } break; } } if ( ch != NULL ) save_char_obj ( ch ); /* Stop scrap duping - Samson 1-2-00 */ return objcode; } /* * Remove an object. */ bool remove_obj ( CHAR_DATA * ch, int iWear, bool fReplace ) { OBJ_DATA *obj, *tmpobj; if ( ( obj = get_eq_char ( ch, iWear ) ) == NULL ) return TRUE; if ( !fReplace && ch->carry_number + get_obj_number ( obj ) > can_carry_n ( ch ) ) { act ( AT_PLAIN, "$d: you can't carry that many items.", ch, NULL, obj->name, TO_CHAR ); return FALSE; } if ( !fReplace ) return FALSE; if ( IS_OBJ_STAT ( obj, ITEM_NOREMOVE ) ) { act ( AT_PLAIN, "You can't remove $p.", ch, obj, NULL, TO_CHAR ); return FALSE; } if ( obj == get_eq_char ( ch, WEAR_WIELD ) && ( tmpobj = get_eq_char ( ch, WEAR_DUAL_WIELD ) ) != NULL ) tmpobj->wear_loc = WEAR_WIELD; unequip_char ( ch, obj ); act ( AT_ACTION, "$n stops using $p.", ch, obj, NULL, TO_ROOM ); act ( AT_ACTION, "You stop using $p.", ch, obj, NULL, TO_CHAR ); oprog_remove_trigger ( ch, obj ); return TRUE; } /* * See if char could be capable of dual-wielding -Thoric */ bool could_dual ( CHAR_DATA * ch ) { // if( IS_NPC( ch ) || ch->pcdata->learned[gsn_dual_wield] ) // return TRUE; return FALSE; } /* * Check for the ability to dual-wield under all conditions. -Orion * * Original version by Thoric. */ bool can_dual ( CHAR_DATA * ch ) { /* * We must assume that when they come in, they are NOT wielding something. We * take care of the actual value later. -Orion */ bool wielding[2], alreadyWielding = FALSE; wielding[0] = FALSE; wielding[1] = FALSE; /* * If they don't have the ability to dual-wield, why should we allow them to * do so? -Orion */ if ( !could_dual ( ch ) ) return FALSE; /* * Get that true wielding value I mentioned earlier. If they're wielding and * missile wielding, we can simply return FALSE. If not, set the values. -Orion */ if ( get_eq_char ( ch, WEAR_WIELD ) && get_eq_char ( ch, WEAR_MISSILE_WIELD ) ) { send_to_char ( "You are already wielding two weapons... grow some more arms!\r\n", ch ); return FALSE; } else { /* * Wield position. -Orion */ wielding[0] = get_eq_char ( ch, WEAR_WIELD ) ? TRUE : FALSE; /* * Missile wield position. -Orion */ wielding[1] = get_eq_char ( ch, WEAR_MISSILE_WIELD ) ? TRUE : FALSE; } /* * Save some extra typing farther down. -Orion */ if ( wielding[0] || wielding[1] ) alreadyWielding = TRUE; /* * If wielding and dual wielding, then they can't wear another weapon. Return * FALSE. We can assume that dual wield will not be full if there is no wield * slot already filled. -Orion */ if ( wielding[0] && get_eq_char ( ch, WEAR_DUAL_WIELD ) ) { send_to_char ( "You are already wielding two weapons... grow some more arms!\r\n", ch ); return FALSE; } /* * If wielding or missile wielding and holding a shield, then we can return * FALSE. -Orion */ if ( alreadyWielding && get_eq_char ( ch, WEAR_SHIELD ) ) { send_to_char ( "You cannot dual wield, you're already holding a shield!\r\n", ch ); return FALSE; } /* * If wielding or missile wielding and holding something, then we can return * FALSE. -Orion */ if ( alreadyWielding && get_eq_char ( ch, WEAR_HOLD ) ) { send_to_char ( "You cannot hold another weapon, you're already holding something in that hand!\r\n", ch ); return FALSE; } return TRUE; } /* * Check to see if there is room to wear another object on this location * (Layered clothing support) */ bool can_layer ( CHAR_DATA * ch, OBJ_DATA * obj, short wear_loc ) { OBJ_DATA *otmp; short bitlayers = 0; short objlayers = obj->pIndexData->layers; for ( otmp = ch->first_carrying; otmp; otmp = otmp->next_content ) if ( otmp->wear_loc == wear_loc ) { if ( !otmp->pIndexData->layers ) return FALSE; else bitlayers |= otmp->pIndexData->layers; } if ( ( bitlayers && !objlayers ) || bitlayers > objlayers ) return FALSE; if ( !bitlayers || ( ( bitlayers & ~objlayers ) == bitlayers ) ) return TRUE; return FALSE; } /* * Wear one object. * Optional replacement of existing objects. * Big repetitive code, ick. * * Restructured a bit to allow for specifying body location -Thoric * & Added support for layering on certain body locations */ void wear_obj ( CHAR_DATA * ch, OBJ_DATA * obj, bool fReplace, short wear_bit ) { char buf[MAX_STRING_LENGTH]; OBJ_DATA *tmpobj = NULL; short bit, tmp; separate_obj ( obj ); if ( get_trust ( ch ) < obj->level ) { sprintf ( buf, "You must be level %d to use this object.\r\n", obj->level ); send_to_char ( buf, ch ); act ( AT_ACTION, "$n tries to use $p, but is too inexperienced.", ch, obj, NULL, TO_ROOM ); return; } /* if ( !IS_IMMORTAL ( ch ) && ( ( IS_OBJ_STAT ( obj, ITEM_ANTI_DEATH ) && ( ch->Class == CLASS_WU_JEN || ch->Class == CLASS_KENSEI ) ) || ( IS_OBJ_STAT ( obj, ITEM_ANTI_LIFE ) && ( ch->Class == CLASS_BUSHI || ch->Class == CLASS_SHUGENJA ) ) || ( IS_OBJ_STAT ( obj, ITEM_ANTI_DECAY ) && ( ch->Class == CLASS_HENSHIN || ch->Class == CLASS_IAIJUTSU ) ) || ( IS_OBJ_STAT ( obj, ITEM_ANTI_GROWTH ) && ( ch->Class == CLASS_SOHEI || ch->Class == CLASS_KISHI ) ) ) ) { act ( AT_MAGIC, "It goes against the nature of your class t use that item.", ch, NULL, NULL, TO_CHAR ); act ( AT_ACTION, "$n tries to use $p, but is forbidden to do so.", ch, obj, NULL, TO_ROOM ); return; } if ( !IS_IMMORTAL ( ch ) && ( ( IS_OBJ_STAT ( obj, ITEM_ANTI_EVIL ) && ( ch->race == RACE_UNDEAD || ch->race == RACE_DEMON ) ) || ( IS_OBJ_STAT ( obj, ITEM_ANTI_NEUTRAL ) && ( ch->race == RACE_NEZUMI || ch->race == RACE_SPIRIT ) ) || ( IS_OBJ_STAT ( obj, ITEM_ANTI_GOOD ) && ( ch->Class == RACE_ANGEL || ch->race == RACE_VANARA ) ) ) ) { act ( AT_MAGIC, "It goes against the nature of your race to use that item.", ch, NULL, NULL, TO_CHAR ); act ( AT_ACTION, "$n tries to use $p, but is forbidden to do so.", ch, obj, NULL, TO_ROOM ); return; }*/ if ( wear_bit > -1 ) { bit = wear_bit; if ( !CAN_WEAR ( obj, 1 << bit ) ) { if ( fReplace ) { switch ( 1 << bit ) { case ITEM_HOLD: send_to_char ( "You cannot hold that.\r\n", ch ); break; case ITEM_WIELD: case ITEM_MISSILE_WIELD: send_to_char ( "You cannot wield that.\r\n", ch ); break; default: sprintf ( buf, "You cannot wear that on your %s.\r\n", w_flags[bit] ); send_to_char ( buf, ch ); } } return; } } else { for ( bit = -1, tmp = 1; tmp < 31; tmp++ ) { if ( CAN_WEAR ( obj, 1 << tmp ) ) { bit = tmp; break; } } } /* * currently cannot have a light in non-light position */ if ( obj->item_type == ITEM_LIGHT ) { if ( !remove_obj ( ch, WEAR_LIGHT, fReplace ) ) return; if ( !oprog_use_trigger ( ch, obj, NULL, NULL, NULL ) ) { act ( AT_ACTION, "$n holds $p as a light.", ch, obj, NULL, TO_ROOM ); act ( AT_ACTION, "You hold $p as your light.", ch, obj, NULL, TO_CHAR ); } equip_char ( ch, obj, WEAR_LIGHT ); oprog_wear_trigger ( ch, obj ); return; } if ( bit == -1 ) { if ( fReplace ) send_to_char ( "You can't wear, wield, or hold that.\r\n", ch ); return; } switch ( 1 << bit ) { default: bug ( "wear_obj: uknown/unused item_wear bit %d", bit ); if ( fReplace ) send_to_char ( "You can't wear, wield, or hold that.\r\n", ch ); return; case ITEM_LODGE_RIB: act ( AT_ACTION, "$p strikes you and deeply imbeds itself in your ribs!", ch, obj, NULL, TO_CHAR ); act ( AT_ACTION, "$p strikes $n and deeply imbeds itself in $s ribs!", ch, obj, NULL, TO_ROOM ); equip_char ( ch, obj, WEAR_LODGE_RIB ); break; case ITEM_LODGE_ARM: act ( AT_ACTION, "$p strikes you and deeply imbeds itself in your arm!", ch, obj, NULL, TO_CHAR ); act ( AT_ACTION, "$p strikes $n and deeply imbeds itself in $s arm!", ch, obj, NULL, TO_ROOM ); equip_char ( ch, obj, WEAR_LODGE_ARM ); break; case ITEM_LODGE_LEG: act ( AT_ACTION, "$p strikes you and deeply imbeds itself in your leg!", ch, obj, NULL, TO_CHAR ); act ( AT_ACTION, "$p strikes $n and deeply imbeds itself in $s leg!", ch, obj, NULL, TO_ROOM ); equip_char ( ch, obj, WEAR_LODGE_LEG ); break; case ITEM_WEAR_BODY: if ( !can_layer ( ch, obj, WEAR_BODY ) ) { send_to_char ( "It won't fit overtop of what you're already wearing.\r\n", ch ); return; } if ( !oprog_use_trigger ( ch, obj, NULL, NULL, NULL ) ) { act ( AT_ACTION, "$n fits $p on $s body.", ch, obj, NULL, TO_ROOM ); act ( AT_ACTION, "You fit $p on your body.", ch, obj, NULL, TO_CHAR ); } equip_char ( ch, obj, WEAR_BODY ); oprog_wear_trigger ( ch, obj ); return; case ITEM_WEAR_HEAD: if ( !remove_obj ( ch, WEAR_HEAD, fReplace ) ) return; if ( !oprog_use_trigger ( ch, obj, NULL, NULL, NULL ) ) { act ( AT_ACTION, "$n dons $p upon $s head.", ch, obj, NULL, TO_ROOM ); act ( AT_ACTION, "You don $p upon your head.", ch, obj, NULL, TO_CHAR ); } equip_char ( ch, obj, WEAR_HEAD ); oprog_wear_trigger ( ch, obj ); return; case ITEM_WEAR_LEGS: if ( !can_layer ( ch, obj, WEAR_LEGS ) ) { send_to_char ( "It won't fit overtop of what you're already wearing.\r\n", ch ); return; } if ( !oprog_use_trigger ( ch, obj, NULL, NULL, NULL ) ) { act ( AT_ACTION, "$n slips into $p.", ch, obj, NULL, TO_ROOM ); act ( AT_ACTION, "You slip into $p.", ch, obj, NULL, TO_CHAR ); } equip_char ( ch, obj, WEAR_LEGS ); oprog_wear_trigger ( ch, obj ); return; case ITEM_WEAR_FEET: if ( !can_layer ( ch, obj, WEAR_FEET ) ) { send_to_char ( "It won't fit overtop of what you're already wearing.\r\n", ch ); return; } if ( !oprog_use_trigger ( ch, obj, NULL, NULL, NULL ) ) { act ( AT_ACTION, "$n wears $p on $s feet.", ch, obj, NULL, TO_ROOM ); act ( AT_ACTION, "You wear $p on your feet.", ch, obj, NULL, TO_CHAR ); } equip_char ( ch, obj, WEAR_FEET ); oprog_wear_trigger ( ch, obj ); return; case ITEM_WEAR_HANDS: if ( !can_layer ( ch, obj, WEAR_HANDS ) ) { send_to_char ( "It won't fit overtop of what you're already wearing.\r\n", ch ); return; } if ( !oprog_use_trigger ( ch, obj, NULL, NULL, NULL ) ) { act ( AT_ACTION, "$n wears $p on $s hands.", ch, obj, NULL, TO_ROOM ); act ( AT_ACTION, "You wear $p on your hands.", ch, obj, NULL, TO_CHAR ); } equip_char ( ch, obj, WEAR_HANDS ); oprog_wear_trigger ( ch, obj ); return; case ITEM_WEAR_ARMS: if ( !can_layer ( ch, obj, WEAR_ARMS ) ) { send_to_char ( "It won't fit overtop of what you're already wearing.\r\n", ch ); return; } if ( !oprog_use_trigger ( ch, obj, NULL, NULL, NULL ) ) { act ( AT_ACTION, "$n wears $p on $s arms.", ch, obj, NULL, TO_ROOM ); act ( AT_ACTION, "You wear $p on your arms.", ch, obj, NULL, TO_CHAR ); } equip_char ( ch, obj, WEAR_ARMS ); oprog_wear_trigger ( ch, obj ); return; case ITEM_WEAR_BACK: if ( !remove_obj ( ch, WEAR_BACK, fReplace ) ) return; if ( !oprog_use_trigger ( ch, obj, NULL, NULL, NULL ) ) { act ( AT_ACTION, "$n slings $p on $s back.", ch, obj, NULL, TO_ROOM ); act ( AT_ACTION, "You sling $p on your back.", ch, obj, NULL, TO_CHAR ); } equip_char ( ch, obj, WEAR_BACK ); oprog_wear_trigger ( ch, obj ); return; case ITEM_WEAR_SHIELD: if ( get_eq_char ( ch, WEAR_DUAL_WIELD ) || ( get_eq_char ( ch, WEAR_WIELD ) && get_eq_char ( ch, WEAR_MISSILE_WIELD ) ) ) { send_to_char ( "You can't use a shield AND two weapons!\r\n", ch ); return; } if ( !remove_obj ( ch, WEAR_SHIELD, fReplace ) ) return; if ( !oprog_use_trigger ( ch, obj, NULL, NULL, NULL ) ) { act ( AT_ACTION, "$n uses $p as a shield.", ch, obj, NULL, TO_ROOM ); act ( AT_ACTION, "You use $p as a shield.", ch, obj, NULL, TO_CHAR ); } equip_char ( ch, obj, WEAR_SHIELD ); oprog_wear_trigger ( ch, obj ); return; case ITEM_MISSILE_WIELD: case ITEM_WIELD: if ( !could_dual ( ch ) ) { if ( !remove_obj ( ch, WEAR_MISSILE_WIELD, fReplace ) ) return; if ( !remove_obj ( ch, WEAR_WIELD, fReplace ) ) return; tmpobj = NULL; } else { OBJ_DATA *mw, *dw, *hd, *sd; tmpobj = get_eq_char ( ch, WEAR_WIELD ); mw = get_eq_char ( ch, WEAR_MISSILE_WIELD ); dw = get_eq_char ( ch, WEAR_DUAL_WIELD ); hd = get_eq_char ( ch, WEAR_HOLD ); sd = get_eq_char ( ch, WEAR_SHIELD ); if ( tmpobj ) { if ( !can_dual ( ch ) ) return; if ( get_obj_weight ( obj ) + get_obj_weight ( tmpobj ) > str_app[get_curr_str ( ch ) ].wield ) { send_to_char ( "It is too heavy for you to wield.\r\n", ch ); return; } if ( mw || dw ) { send_to_char ( "You're already wielding two weapons.\r\n", ch ); return; } if ( hd || sd ) { send_to_char ( "You're already wielding a weapon AND holding something.\r\n", ch ); return; } if ( !oprog_use_trigger ( ch, obj, NULL, NULL, NULL ) ) { act ( AT_ACTION, "$n dual-wields $p.", ch, obj, NULL, TO_ROOM ); act ( AT_ACTION, "You dual-wield $p.", ch, obj, NULL, TO_CHAR ); } if ( 1 << bit == ITEM_MISSILE_WIELD ) equip_char ( ch, obj, WEAR_MISSILE_WIELD ); else equip_char ( ch, obj, WEAR_DUAL_WIELD ); oprog_wear_trigger ( ch, obj ); return; } if ( mw ) { if ( !can_dual ( ch ) ) return; if ( 1 << bit == ITEM_MISSILE_WIELD ) { send_to_char ( "You're already wielding a missile weapon.\r\n", ch ); return; } if ( get_obj_weight ( obj ) + get_obj_weight ( mw ) > str_app[get_curr_str ( ch ) ].wield ) { send_to_char ( "It is too heavy for you to wield.\r\n", ch ); return; } if ( tmpobj || dw ) { send_to_char ( "You're already wielding two weapons.\r\n", ch ); return; } if ( hd || sd ) { send_to_char ( "You're already wielding a weapon AND holding something.\r\n", ch ); return; } if ( !oprog_use_trigger ( ch, obj, NULL, NULL, NULL ) ) { act ( AT_ACTION, "$n wields $p.", ch, obj, NULL, TO_ROOM ); act ( AT_ACTION, "You wield $p.", ch, obj, NULL, TO_CHAR ); } equip_char ( ch, obj, WEAR_WIELD ); oprog_wear_trigger ( ch, obj ); return; } } if ( get_obj_weight ( obj ) > str_app[get_curr_str ( ch ) ].wield ) { send_to_char ( "It is too heavy for you to wield.\r\n", ch ); return; } if ( !oprog_use_trigger ( ch, obj, NULL, NULL, NULL ) ) { act ( AT_ACTION, "$n wields $p.", ch, obj, NULL, TO_ROOM ); act ( AT_ACTION, "You wield $p.", ch, obj, NULL, TO_CHAR ); } if ( 1 << bit == ITEM_MISSILE_WIELD ) equip_char ( ch, obj, WEAR_MISSILE_WIELD ); else equip_char ( ch, obj, WEAR_WIELD ); oprog_wear_trigger ( ch, obj ); return; case ITEM_HOLD: if ( get_eq_char ( ch, WEAR_DUAL_WIELD ) || ( get_eq_char ( ch, WEAR_WIELD ) && get_eq_char ( ch, WEAR_MISSILE_WIELD ) ) ) { send_to_char ( "You cannot hold something AND two weapons!\r\n", ch ); return; } if ( !remove_obj ( ch, WEAR_HOLD, fReplace ) ) return; if ( obj->item_type == ITEM_WAND || obj->item_type == ITEM_STAFF || obj->item_type == ITEM_FOOD || obj->item_type == ITEM_COOK || obj->item_type == ITEM_PILL || obj->item_type == ITEM_POTION || obj->item_type == ITEM_SCROLL || obj->item_type == ITEM_DRINK_CON || obj->item_type == ITEM_BLOOD || obj->item_type == ITEM_PIPE || obj->item_type == ITEM_HERB || obj->item_type == ITEM_KEY || !oprog_use_trigger ( ch, obj, NULL, NULL, NULL ) ) { act ( AT_ACTION, "$n holds $p in $s hands.", ch, obj, NULL, TO_ROOM ); act ( AT_ACTION, "You hold $p in your hands.", ch, obj, NULL, TO_CHAR ); } equip_char ( ch, obj, WEAR_HOLD ); oprog_wear_trigger ( ch, obj ); return; } } void do_wear ( CHAR_DATA * ch, char *argument ) { char arg1[MAX_INPUT_LENGTH]; char arg2[MAX_INPUT_LENGTH]; OBJ_DATA *obj; short wear_bit; argument = one_argument ( argument, arg1 ); argument = one_argument ( argument, arg2 ); if ( ( !str_cmp ( arg2, "on" ) || !str_cmp ( arg2, "upon" ) || !str_cmp ( arg2, "around" ) ) && argument[0] != STRING_NULL ) argument = one_argument ( argument, arg2 ); if ( arg1[0] == STRING_NULL ) { send_to_char ( "Wear, wield, or hold what?\r\n", ch ); return; } if ( !str_cmp ( arg1, "all" ) ) { OBJ_DATA *obj_next; for ( obj = ch->first_carrying; obj; obj = obj_next ) { obj_next = obj->next_content; if ( obj->wear_loc == WEAR_NONE && can_see_obj ( ch, obj ) ) { wear_obj ( ch, obj, FALSE, -1 ); if ( char_died ( ch ) ) return; } } return; } else { if ( ( obj = get_obj_carry ( ch, arg1 ) ) == NULL ) { send_to_char ( "You do not have that item.\r\n", ch ); return; } if ( arg2[0] != STRING_NULL ) wear_bit = get_wflag ( arg2 ); else wear_bit = -1; wear_obj ( ch, obj, TRUE, wear_bit ); } return; } void do_remove ( CHAR_DATA * ch, char *argument ) { char arg[MAX_INPUT_LENGTH]; OBJ_DATA *obj, *obj_next; one_argument ( argument, arg ); if ( arg[0] == STRING_NULL ) { send_to_char ( "Remove what?\r\n", ch ); return; } if ( !str_cmp ( arg, "all" ) ) /* SB Remove all */ { for ( obj = ch->first_carrying; obj != NULL; obj = obj_next ) { obj_next = obj->next_content; if ( obj->wear_loc != WEAR_NONE && can_see_obj ( ch, obj ) ) remove_obj ( ch, obj->wear_loc, TRUE ); } return; } if ( ( obj = get_obj_wear ( ch, arg ) ) == NULL ) { send_to_char ( "You are not using that item.\r\n", ch ); return; } if ( ( obj_next = get_eq_char ( ch, obj->wear_loc ) ) != obj ) { act ( AT_PLAIN, "You must remove $p first.", ch, obj_next, NULL, TO_CHAR ); return; } remove_obj ( ch, obj->wear_loc, TRUE ); return; } void do_bury ( CHAR_DATA * ch, char *argument ) { char arg[MAX_INPUT_LENGTH]; OBJ_DATA *obj; bool shovel; short move; one_argument ( argument, arg ); if ( arg[0] == STRING_NULL ) { send_to_char ( "What do you wish to bury?\r\n", ch ); return; } shovel = FALSE; for ( obj = ch->first_carrying; obj; obj = obj->next_content ) if ( obj->item_type == ITEM_SHOVEL ) { shovel = TRUE; break; } obj = get_obj_list_rev ( ch, arg, ch->in_room->last_content ); if ( !obj ) { send_to_char ( "You can't find it.\r\n", ch ); return; } separate_obj ( obj ); if ( !CAN_WEAR ( obj, ITEM_TAKE ) ) { if ( !IS_OBJ_STAT ( obj, ITEM_CLANCORPSE ) || IS_NPC ( ch ) || !IS_SET ( ch->pcdata->flags, PCFLAG_DEADLY ) ) { act ( AT_PLAIN, "You cannot bury $p.", ch, obj, 0, TO_CHAR ); return; } } switch ( ch->in_room->sector_type ) { case SECT_CITY: case SECT_INSIDE: send_to_char ( "The floor is too hard to dig through.\r\n", ch ); return; case SECT_WATER_SWIM: case SECT_WATER_NOSWIM: case SECT_UNDERWATER: send_to_char ( "You cannot bury something here.\r\n", ch ); return; case SECT_AIR: send_to_char ( "What? In the air?!\r\n", ch ); return; } if ( obj->weight > ( UMAX ( 5, ( can_carry_w ( ch ) / 10 ) ) ) && !shovel ) { send_to_char ( "You'd need a shovel to bury something that big.\r\n", ch ); return; } move = ( obj->weight * 50 * ( shovel ? 1 : 5 ) ) / UMAX ( 1, can_carry_w ( ch ) ); move = URANGE ( 2, move, 1000 ); if ( move > ch->move ) { send_to_char ( "You don't have the energy to bury something of that size.\r\n", ch ); return; } ch->move -= move; if ( obj->item_type == ITEM_CORPSE_NPC || obj->item_type == ITEM_CORPSE_PC ) adjust_favor ( ch, 6, 1 ); act ( AT_ACTION, "You solemnly bury $p...", ch, obj, NULL, TO_CHAR ); act ( AT_ACTION, "$n solemnly buries $p...", ch, obj, NULL, TO_ROOM ); xSET_BIT ( obj->extra_flags, ITEM_BURIED ); WAIT_STATE ( ch, URANGE ( 10, move / 2, 100 ) ); return; } void do_sacrifice ( CHAR_DATA * ch, char *argument ) { char arg[MAX_INPUT_LENGTH]; char buf[MAX_STRING_LENGTH]; char name[50]; OBJ_DATA *obj; one_argument ( argument, arg ); if ( arg[0] == STRING_NULL || !str_cmp ( arg, ch->name ) ) { act ( AT_ACTION, "$n offers $mself to $s deity, who graciously declines.", ch, NULL, NULL, TO_ROOM ); send_to_char ( "Your deity appreciates your offer and may accept it later.\r\n", ch ); return; } if ( !str_cmp ( arg, "all" ) ) { if ( !ch->in_room->first_content ) { send_to_char ( "All what? There's nothing here!\r\n", ch ); return; } for ( obj = ch->in_room->first_content; obj; obj = obj->next_content ) { separate_obj ( obj ); if ( !CAN_WEAR ( obj, ITEM_TAKE ) || !can_see_obj ( ch, obj ) ) { continue; } if ( IS_SET ( obj->magic_flags, ITEM_PKDISARMED ) && !IS_NPC ( ch ) ) { if ( CAN_PKILL ( ch ) && !get_timer ( ch, TIMER_PKILLED ) ) { if ( ch->level - obj->value[5] > 5 || obj->value[5] - ch->level > 5 ) { continue; } } } if ( !IS_NPC ( ch ) && ch->pcdata->deity && ch->pcdata->deity->name[0] != STRING_NULL ) { strcpy ( name, ch->pcdata->deity->name ); } else if ( !IS_NPC ( ch ) && ch->pcdata->clan && ch->pcdata->clan->deity[0] != STRING_NULL ) { strcpy ( name, ch->pcdata->clan->deity ); } else { strcpy ( name, "The God's" ); } ch->gold += 1; if ( obj->item_type == ITEM_CORPSE_NPC || obj->item_type == ITEM_CORPSE_PC ) adjust_favor ( ch, 5, 1 ); sprintf ( buf, "%s give you one gold coin for sacrificing %s.\r\n", name, obj->short_descr ); send_to_char ( buf, ch ); sprintf ( buf, "$n sacrifices $p to %s.", name ); act ( AT_ACTION, buf, ch, obj, NULL, TO_ROOM ); oprog_sac_trigger ( ch, obj ); if ( obj_extracted ( obj ) ) return; if ( cur_obj == obj->serial ) global_objcode = rOBJ_SACCED; extract_obj ( obj ); } return; } obj = get_obj_list_rev ( ch, arg, ch->in_room->last_content ); if ( !obj ) { send_to_char ( "You can't find it.\r\n", ch ); return; } separate_obj ( obj ); if ( !CAN_WEAR ( obj, ITEM_TAKE ) ) { act ( AT_PLAIN, "$p is not an acceptable sacrifice.", ch, obj, 0, TO_CHAR ); return; } if ( IS_SET ( obj->magic_flags, ITEM_PKDISARMED ) && !IS_NPC ( ch ) ) { if ( CAN_PKILL ( ch ) && !get_timer ( ch, TIMER_PKILLED ) ) { if ( ch->level - obj->value[5] > 5 || obj->value[5] - ch->level > 5 ) { send_to_char_color ( "\r\n&bA godly force freezes your outstretched hand.\r\n", ch ); return; } } } if ( !IS_NPC ( ch ) && ch->pcdata->deity && ch->pcdata->deity->name[0] != STRING_NULL ) { strcpy ( name, ch->pcdata->deity->name ); } else if ( !IS_NPC ( ch ) && ch->pcdata->clan && ch->pcdata->clan->deity[0] != STRING_NULL ) { strcpy ( name, ch->pcdata->clan->deity ); } else { strcpy ( name, "The God's" ); } ch->gold += 1; if ( obj->item_type == ITEM_CORPSE_NPC || obj->item_type == ITEM_CORPSE_PC ) adjust_favor ( ch, 5, 1 ); sprintf ( buf, "%s give you one gold coin for your sacrifice.\r\n", name ); send_to_char ( buf, ch ); sprintf ( buf, "$n sacrifices $p to %s.", name ); act ( AT_ACTION, buf, ch, obj, NULL, TO_ROOM ); oprog_sac_trigger ( ch, obj ); if ( obj_extracted ( obj ) ) return; if ( cur_obj == obj->serial ) global_objcode = rOBJ_SACCED; separate_obj ( obj ); extract_obj ( obj ); save_house_by_vnum ( ch->in_room->vnum ); /* Prevent House Object Duplication */ return; } void do_brandish ( CHAR_DATA * ch, char *argument ) { CHAR_DATA *vch; CHAR_DATA *vch_next; OBJ_DATA *staff; ch_ret retcode; int sn; if ( ( staff = get_eq_char ( ch, WEAR_HOLD ) ) == NULL ) { send_to_char ( "You hold nothing in your hand.\r\n", ch ); return; } if ( staff->item_type != ITEM_STAFF ) { send_to_char ( "You can brandish only with a staff.\r\n", ch ); return; } if ( ( sn = staff->value[3] ) < 0 || sn >= top_sn || skill_table[sn]->spell_fun == NULL ) { bug ( "Do_brandish: bad sn %d.", sn ); return; } WAIT_STATE ( ch, 2 * PULSE_VIOLENCE ); if ( staff->value[2] > 0 ) { if ( !oprog_use_trigger ( ch, staff, NULL, NULL, NULL ) ) { act ( AT_MAGIC, "$n brandishes $p.", ch, staff, NULL, TO_ROOM ); act ( AT_MAGIC, "You brandish $p.", ch, staff, NULL, TO_CHAR ); } for ( vch = ch->in_room->first_person; vch; vch = vch_next ) { vch_next = vch->next_in_room; if ( !IS_NPC ( vch ) && xIS_SET ( vch->act, PLR_WIZINVIS ) && vch->pcdata->wizinvis >= LEVEL_IMMORTAL ) continue; else switch ( skill_table[sn]->target ) { default: bug ( "Do_brandish: bad target for sn %d.", sn ); return; case TAR_IGNORE: if ( vch != ch ) continue; break; case TAR_CHAR_OFFENSIVE: if ( IS_NPC ( ch ) ? IS_NPC ( vch ) : !IS_NPC ( vch ) ) continue; break; case TAR_CHAR_DEFENSIVE: if ( IS_NPC ( ch ) ? !IS_NPC ( vch ) : IS_NPC ( vch ) ) continue; break; case TAR_CHAR_SELF: if ( vch != ch ) continue; break; } retcode = obj_cast_spell ( staff->value[3], staff->value[0], ch, vch, NULL ); if ( retcode == rCHAR_DIED || retcode == rBOTH_DIED ) { bug ( "do_brandish: char died", 0 ); return; } } } if ( --staff->value[2] <= 0 ) { act ( AT_MAGIC, "$p blazes bright and vanishes from $n's hands!", ch, staff, NULL, TO_ROOM ); act ( AT_MAGIC, "$p blazes bright and is gone!", ch, staff, NULL, TO_CHAR ); if ( staff->serial == cur_obj ) global_objcode = rOBJ_USED; extract_obj ( staff ); } return; } void do_zap ( CHAR_DATA * ch, char *argument ) { char arg[MAX_INPUT_LENGTH]; CHAR_DATA *victim; OBJ_DATA *wand; OBJ_DATA *obj; ch_ret retcode; one_argument ( argument, arg ); if ( arg[0] == STRING_NULL && !ch->fighting ) { send_to_char ( "Zap whom or what?\r\n", ch ); return; } if ( ( wand = get_eq_char ( ch, WEAR_HOLD ) ) == NULL ) { send_to_char ( "You hold nothing in your hand.\r\n", ch ); return; } if ( wand->item_type != ITEM_WAND ) { send_to_char ( "You can zap only with a wand.\r\n", ch ); return; } obj = NULL; if ( arg[0] == STRING_NULL ) { if ( ch->fighting ) { victim = who_fighting ( ch ); } else { send_to_char ( "Zap whom or what?\r\n", ch ); return; } } else { if ( ( victim = get_char_room ( ch, arg ) ) == NULL && ( obj = get_obj_here ( ch, arg ) ) == NULL ) { send_to_char ( "You can't find it.\r\n", ch ); return; } } WAIT_STATE ( ch, 1 * PULSE_VIOLENCE ); if ( wand->value[2] > 0 ) { if ( victim ) { if ( !oprog_use_trigger ( ch, wand, victim, NULL, NULL ) ) { act ( AT_MAGIC, "$n aims $p at $N.", ch, wand, victim, TO_ROOM ); act ( AT_MAGIC, "You aim $p at $N.", ch, wand, victim, TO_CHAR ); } } else { if ( !oprog_use_trigger ( ch, wand, NULL, obj, NULL ) ) { act ( AT_MAGIC, "$n aims $p at $P.", ch, wand, obj, TO_ROOM ); act ( AT_MAGIC, "You aim $p at $P.", ch, wand, obj, TO_CHAR ); } } retcode = obj_cast_spell ( wand->value[3], wand->value[0], ch, victim, obj ); if ( retcode == rCHAR_DIED || retcode == rBOTH_DIED ) { bug ( "do_zap: char died", 0 ); return; } } if ( --wand->value[2] <= 0 ) { act ( AT_MAGIC, "$p explodes into fragments.", ch, wand, NULL, TO_ROOM ); act ( AT_MAGIC, "$p explodes into fragments.", ch, wand, NULL, TO_CHAR ); if ( wand->serial == cur_obj ) global_objcode = rOBJ_USED; extract_obj ( wand ); } return; } /* * Save items in a clan storage room -Scryn & Thoric */ void save_clan_storeroom ( CHAR_DATA * ch, CLAN_DATA * clan ) { FILE *fp; char filename[256]; short templvl; OBJ_DATA *contents; if ( !clan ) { bug ( "save_clan_storeroom: Null clan pointer!", 0 ); return; } if ( !ch ) { bug ( "save_clan_storeroom: Null ch pointer!", 0 ); return; } sprintf ( filename, "%s%s.vault", CLAN_DIR, clan->filename ); if ( ( fp = fopen ( filename, "w" ) ) == NULL ) { bug ( "save_clan_storeroom: fopen", 0 ); perror ( filename ); } else { templvl = ch->level; ch->level = LEVEL_HERO; /* make sure EQ doesn't get lost */ contents = ch->in_room->last_content; if ( contents ) fwrite_obj ( ch, contents, fp, 0, OS_CARRY, FALSE ); fprintf ( fp, "#END\n" ); ch->level = templvl; fclose ( fp ); return; } return; } /* put an item on auction, or see the stats on the current item or bet */ void do_auction ( CHAR_DATA * ch, char *argument ) { OBJ_DATA *obj; char arg1[MAX_INPUT_LENGTH]; char arg2[MAX_INPUT_LENGTH]; char arg3[MAX_INPUT_LENGTH]; char buf[MAX_STRING_LENGTH]; int i; SKILLTYPE *sktmp; argument = one_argument ( argument, arg1 ); argument = one_argument ( argument, arg2 ); argument = one_argument ( argument, arg3 ); set_char_color ( AT_LBLUE, ch ); if ( IS_NPC ( ch ) ) /* NPC can be extracted at any time and thus can't auction! */ return; set_char_color ( AT_AUCTION, ch ); if ( ch->level < 3 ) { send_to_char ( "You must be at least level three to use the auction...\r\n", ch ); return; } if ( ( time_info.hour > 18 || time_info.hour < 9 ) && auction->item == NULL && !IS_IMMORTAL ( ch ) ) { send_to_char ( "\r\nThe auctioneer works between the hours of 9 AM and 6 PM\r\n", ch ); return; } if ( arg1[0] == STRING_NULL ) { if ( auction->item != NULL ) { AFFECT_DATA *paf; obj = auction->item; /* * show item data here */ send_to_char ( "&D--------------------------------------------------------------------------------\r\n", ch ); ch_printf ( ch, "Object: &w'%s&D'\r\n", obj->short_descr ); send_to_char ( "&D--------------------------------------------------------------------------------\r\n", ch ); ch_printf ( ch, "Item Type : &w%s&D\r\n", item_type_name ( obj ) ); if ( obj->item_type != ITEM_LIGHT && obj->wear_flags - 1 > 0 ) ch_printf ( ch, "Wear location:&w %s&D\r\n", flag_string ( obj->wear_flags, w_flags ) ); ch_printf ( ch, "Weight :&w %d&D\r\n", obj->weight ); ch_printf ( ch, "Level :&w %d&D\r\n", obj->level ); ch_printf ( ch, "Cost :&w %d&D\r\n", obj->cost ); ch_printf ( ch, "Flags :&w %s&D\r\n", extra_bit_name ( &obj->extra_flags ) ); switch ( obj->item_type ) { case ITEM_CONTAINER: ch_printf ( ch, "&wCapacity : %d&D items.\r\n", obj->value[0] ); break; case ITEM_PILL: case ITEM_SCROLL: case ITEM_POTION: ch_printf ( ch, "Level %d spells of:", obj->value[0] ); if ( obj->value[1] >= 0 && ( sktmp = get_skilltype ( obj->value[1] ) ) != NULL ) { send_to_char ( " '", ch ); send_to_char ( sktmp->name, ch ); send_to_char ( "'", ch ); } if ( obj->value[2] >= 0 && ( sktmp = get_skilltype ( obj->value[2] ) ) != NULL ) { send_to_char ( " '", ch ); send_to_char ( sktmp->name, ch ); send_to_char ( "'", ch ); } if ( obj->value[3] >= 0 && ( sktmp = get_skilltype ( obj->value[3] ) ) != NULL ) { send_to_char ( " '", ch ); send_to_char ( sktmp->name, ch ); send_to_char ( "'", ch ); } send_to_char ( ".\r\n", ch ); break; case ITEM_SALVE: ch_printf ( ch, "Has %d(%d) applications of level %d", obj->value[1], obj->value[2], obj->value[0] ); if ( obj->value[4] >= 0 && ( sktmp = get_skilltype ( obj->value[4] ) ) != NULL ) { send_to_char ( " '", ch ); send_to_char ( sktmp->name, ch ); send_to_char ( "'", ch ); } if ( obj->value[5] >= 0 && ( sktmp = get_skilltype ( obj->value[5] ) ) != NULL ) { send_to_char ( " '", ch ); send_to_char ( sktmp->name, ch ); send_to_char ( "'", ch ); } send_to_char ( ".\r\n", ch ); break; case ITEM_WAND: case ITEM_STAFF: ch_printf ( ch, "Has %d(%d) charges of level %d", obj->value[1], obj->value[2], obj->value[0] ); if ( obj->value[3] >= 0 && ( sktmp = get_skilltype ( obj->value[3] ) ) != NULL ) { send_to_char ( " '", ch ); send_to_char ( sktmp->name, ch ); send_to_char ( "'", ch ); } send_to_char ( ".\r\n", ch ); break; case ITEM_WEAPON: ch_printf ( ch, "Damage : &w%d &Dto &w%d &D(average &w%d&D)\r\n", obj->value[1], obj->value[2], ( obj->value[1] + obj->value[2] ) / 2 ); ch_printf ( ch, "Skill needed : &w%s&D\r\n", weapon_skills[obj->value[4]] ); ch_printf ( ch, "Damage type : &w%s&D\r\n", attack_table[obj->value[3]] ); break; case ITEM_MISSILE_WEAPON: ch_printf ( ch, "Bonus damage added to projectiles is %d to %d (average %d).\r\n", obj->value[1], obj->value[2], ( obj->value[1] + obj->value[2] ) / 2 ); ch_printf ( ch, "Skill needed: %s\r\n", weapon_skills[obj->value[4]] ); ch_printf ( ch, "Projectiles fired: %s\r\n", projectiles[obj->value[5]] ); break; case ITEM_PROJECTILE: ch_printf ( ch, "Damage is %d to %d (average %d)%s\r\n", obj->value[1], obj->value[2], ( obj->value[1] + obj->value[2] ) / 2, IS_OBJ_STAT ( obj, ITEM_POISONED ) ? ", and is poisonous." : "." ); ch_printf ( ch, "Damage type: %s\r\n", attack_table[obj->value[3]] ); ch_printf ( ch, "Projectile type: %s\r\n", projectiles[obj->value[4]] ); break; case ITEM_ARMOR: ch_printf ( ch, "Armor Class : &w%d&D.\r\n", obj->value[0] ); break; } for ( paf = obj->pIndexData->first_affect; paf; paf = paf->next ) showaffect ( ch, paf ); for ( paf = obj->first_affect; paf; paf = paf->next ) showaffect ( ch, paf ); send_to_char ( "&D--------------------------------------------------------------------------------\r\n", ch ); for ( paf = obj->pIndexData->first_affect; paf; paf = paf->next ) showaffect ( ch, paf ); for ( paf = obj->first_affect; paf; paf = paf->next ) showaffect ( ch, paf ); if ( ( obj->item_type == ITEM_CONTAINER || obj->item_type == ITEM_KEYRING || obj->item_type == ITEM_QUIVER ) && obj->first_content ) { set_char_color ( AT_OBJECT, ch ); send_to_char ( "Contents:\r\n", ch ); show_list_to_char ( obj->first_content, ch, TRUE, FALSE ); } ch_printf ( ch, "Seller: &w%s&D.\r\n", auction->seller->name ); ch_printf ( ch, "Bidder: &w%s&D.\r\n", auction->buyer->name ); ch_printf ( ch, "Round : &w%d&D.\r\n", ( auction->going + 1 ) ); ch_printf ( ch, "Time left in round: &w%d.&D\r\n", auction->pulse ); if ( auction->bet > 0 ) ch_printf ( ch, "\r\nCurrent bid on this item is %s gold.\r\n", num_punct ( auction->bet ) ); else ch_printf ( ch, "\r\nNo bids on this item have been received.\r\n" ); send_to_char ( "--------------------------------------------------------------------------------\r\n", ch ); return; } else { set_char_color ( AT_LBLUE, ch ); send_to_char ( "\r\nThere is nothing being auctioned right now. What would you like to auction?\r\n", ch ); return; } } if ( IS_IMMORTAL ( ch ) && !str_cmp ( arg1, "stop" ) ) { if ( auction->item == NULL ) { send_to_char ( "There is no auction to stop.\r\n", ch ); return; } else /* stop the auction */ { set_char_color ( AT_LBLUE, ch ); sprintf ( buf, "Sale of %s has been stopped by an Immortal.", auction->item->short_descr ); talk_auction ( buf ); obj_to_char ( auction->item, auction->seller ); if ( IS_SET ( sysdata.save_flags, SV_AUCTION ) ) save_char_obj ( auction->seller ); auction->item = NULL; if ( auction->buyer != NULL && auction->buyer != auction->seller ) /* return money to the buyer */ { auction->buyer->gold += auction->bet; send_to_char ( "Your money has been returned.\r\n", auction->buyer ); } return; } } if ( !str_cmp ( arg1, "bid" ) ) { if ( auction->item != NULL ) { int newbet; if ( ch->level < auction->item->level ) { send_to_char ( "This object's level is too high for your use.\r\n", ch ); return; } if ( ch == auction->seller ) { send_to_char ( "You can't bid on your own item!\r\n", ch ); return; } /* * make - perhaps - a bet now */ if ( arg2[0] == STRING_NULL ) { send_to_char ( "Bid how much?\r\n", ch ); return; } newbet = parsebet ( auction->bet, arg2 ); /* * ch_printf( ch, "Bid: %d\r\n",newbet); */ if ( newbet < auction->starting ) { send_to_char ( "You must place a bid that is higher than the starting bet.\r\n", ch ); return; } /* * to avoid slow auction, use a bigger amount than 100 if the bet * is higher up - changed to 10000 for our high economy */ if ( newbet < ( auction->bet ) ) { send_to_char ( "You must at least bid over the current bid.\r\n", ch ); return; } if ( newbet > ch->gold ) { send_to_char ( "You don't have that much money!\r\n", ch ); return; } if ( newbet > 2000000000 ) { send_to_char ( "You can't bid over 2 billion coins.\r\n", ch ); return; } /* * Is it the item they really want to bid on? --Shaddai */ if ( arg3[0] != STRING_NULL && !nifty_is_name ( arg3, auction->item->name ) ) { send_to_char ( "That item is not being auctioned right now.\r\n", ch ); return; } /* * the actual bet is OK! */ /* * return the gold to the last buyer, if one exists */ if ( auction->buyer != NULL && auction->buyer != auction->seller ) auction->buyer->gold += auction->bet; ch->gold -= newbet; /* substract the gold - important :) */ if ( IS_SET ( sysdata.save_flags, SV_AUCTION ) ) save_char_obj ( ch ); auction->buyer = ch; auction->bet = newbet; auction->going = 0; auction->pulse = PULSE_AUCTION; /* start the auction over again */ sprintf ( buf, "A bid of %s gold has been received on %s.\r\n", num_punct ( newbet ), auction->item->short_descr ); talk_auction ( buf ); return; } else { send_to_char ( "There isn't anything being auctioned right now.\r\n", ch ); return; } } obj = get_obj_carry ( ch, arg1 ); /* does char have the item ? */ if ( obj == NULL ) { send_to_char ( "You aren't carrying that.\r\n", ch ); return; } if ( obj->timer > 0 ) { send_to_char ( "You can't auction objects that are decaying.\r\n", ch ); return; } /* * prevent repeat auction items */ for ( i = 0; i < AUCTION_MEM && auction->history[i]; i++ ) { if ( auction->history[i] == obj->pIndexData ) { send_to_char ( "Such an item has been auctioned " "recently, try again later.\r\n", ch ); return; } } if ( arg2[0] == STRING_NULL ) { auction->starting = 0; strcpy ( arg2, "0" ); } if ( !is_number ( arg2 ) ) { send_to_char ( "You must input a number at which to start the auction.\r\n", ch ); return; } if ( atoi ( arg2 ) < 0 ) { send_to_char ( "You can't auction something for less than 0 gold!\r\n", ch ); return; } if ( auction->item == NULL ) switch ( obj->item_type ) { default: act ( AT_TELL, "You cannot auction $Ts.", ch, NULL, item_type_name ( obj ), TO_CHAR ); return; /* * insert any more item types here... items with a timer MAY NOT BE * AUCTIONED! */ case ITEM_LIGHT: case ITEM_TREASURE: case ITEM_POTION: case ITEM_CONTAINER: case ITEM_KEYRING: case ITEM_QUIVER: case ITEM_DRINK_CON: case ITEM_FOOD: case ITEM_COOK: case ITEM_PEN: case ITEM_BOAT: case ITEM_PILL: case ITEM_PIPE: case ITEM_HERB_CON: case ITEM_INCENSE: case ITEM_FIRE: case ITEM_RUNEPOUCH: case ITEM_MAP: case ITEM_BOOK: case ITEM_RUNE: case ITEM_MATCH: case ITEM_HERB: case ITEM_WEAPON: case ITEM_MISSILE_WEAPON: case ITEM_ARMOR: case ITEM_STAFF: case ITEM_WAND: case ITEM_SCROLL: separate_obj ( obj ); obj_from_char ( obj ); if ( IS_SET ( sysdata.save_flags, SV_AUCTION ) ) save_char_obj ( ch ); auction->item = obj; auction->bet = 0; auction->buyer = ch; auction->seller = ch; auction->pulse = PULSE_AUCTION; auction->going = 0; auction->starting = atoi ( arg2 ); /* * add the new item to the history */ if ( AUCTION_MEM > 0 ) { memmove ( ( char * ) auction->history + sizeof ( OBJ_INDEX_DATA * ), auction->history, ( AUCTION_MEM - 1 ) * sizeof ( OBJ_INDEX_DATA * ) ); auction->history[0] = obj->pIndexData; } /* * reset the history timer */ auction->hist_timer = 0; if ( auction->starting > 0 ) auction->bet = auction->starting; sprintf ( buf, "A new item is being auctioned: %s at %d gold.", obj->short_descr, auction->starting ); talk_auction ( buf ); return; } /* switch */ else { act ( AT_TELL, "Try again later - $p is being auctioned right now!", ch, auction->item, NULL, TO_CHAR ); if ( !IS_IMMORTAL ( ch ) ) WAIT_STATE ( ch, PULSE_VIOLENCE ); return; } } /* Make objects in rooms that are nofloor fall - Scryn 1/23/96 */ void obj_fall ( OBJ_DATA * obj, bool through ) { EXIT_DATA *pexit; ROOM_INDEX_DATA *to_room; static int fall_count; char buf[MAX_STRING_LENGTH]; static bool is_falling; /* Stop loops from the call to obj_to_room() -- Altrag */ if ( !obj->in_room || is_falling ) return; if ( fall_count > 30 ) { bug ( "object falling in loop more than 30 times", 0 ); extract_obj ( obj ); fall_count = 0; return; } if ( xIS_SET ( obj->in_room->room_flags, ROOM_NOFLOOR ) && CAN_GO ( obj, DIR_DOWN ) && !IS_OBJ_STAT ( obj, ITEM_MAGIC ) ) { pexit = get_exit ( obj->in_room, DIR_DOWN ); to_room = pexit->to_room; if ( through ) fall_count++; else fall_count = 0; if ( obj->in_room == to_room ) { sprintf ( buf, "Object falling into same room, room %d", to_room->vnum ); bug ( buf, 0 ); extract_obj ( obj ); return; } if ( obj->in_room->first_person ) { act ( AT_PLAIN, "$p falls far below...", obj->in_room->first_person, obj, NULL, TO_ROOM ); act ( AT_PLAIN, "$p falls far below...", obj->in_room->first_person, obj, NULL, TO_CHAR ); } obj_from_room ( obj ); is_falling = TRUE; obj = obj_to_room ( obj, to_room, NULL ); is_falling = FALSE; if ( obj->in_room->first_person ) { act ( AT_PLAIN, "$p falls from above...", obj->in_room->first_person, obj, NULL, TO_ROOM ); act ( AT_PLAIN, "$p falls from above...", obj->in_room->first_person, obj, NULL, TO_CHAR ); } if ( !xIS_SET ( obj->in_room->room_flags, ROOM_NOFLOOR ) && through ) { /* * int dam = (int)9.81*sqrt(fall_count*2/9.81)*obj->weight/2; */ int dam = fall_count * obj->weight / 2; /* * Damage players */ if ( obj->in_room->first_person && number_percent( ) > 15 ) { CHAR_DATA *rch; CHAR_DATA *vch = NULL; int chcnt = 0; for ( rch = obj->in_room->first_person; rch; rch = rch->next_in_room, chcnt++ ) if ( number_range ( 0, chcnt ) == 0 ) vch = rch; act ( AT_WHITE, "$p falls on $n!", vch, obj, NULL, TO_ROOM ); act ( AT_WHITE, "$p falls on you!", vch, obj, NULL, TO_CHAR ); if ( IS_NPC ( vch ) && xIS_SET ( vch->act, ACT_HARDHAT ) ) act ( AT_WHITE, "$p bounces harmlessly off your head!", vch, obj, NULL, TO_CHAR ); else damage ( vch, vch, dam * vch->level, TYPE_UNDEFINED ); } /* * Damage objects */ switch ( obj->item_type ) { case ITEM_WEAPON: case ITEM_ARMOR: if ( ( obj->value[0] - dam ) <= 0 ) { if ( obj->in_room->first_person ) { act ( AT_PLAIN, "$p is destroyed by the fall!", obj->in_room->first_person, obj, NULL, TO_ROOM ); act ( AT_PLAIN, "$p is destroyed by the fall!", obj->in_room->first_person, obj, NULL, TO_CHAR ); } make_scraps ( obj ); } else obj->value[0] -= dam; break; default: if ( ( dam * 15 ) > get_obj_resistance ( obj ) ) { if ( obj->in_room->first_person ) { act ( AT_PLAIN, "$p is destroyed by the fall!", obj->in_room->first_person, obj, NULL, TO_ROOM ); act ( AT_PLAIN, "$p is destroyed by the fall!", obj->in_room->first_person, obj, NULL, TO_CHAR ); } make_scraps ( obj ); } break; } } obj_fall ( obj, TRUE ); } return; } /* Scryn, by request of Darkur, 12/04/98 */ /* Reworked recursive_note_find to fix crash bug when the note was left * blank. 7/6/98 -- Shaddai */ void do_findnote ( CHAR_DATA * ch, char *argument ) { OBJ_DATA *obj; if ( IS_NPC ( ch ) ) { send_to_char ( "Huh?\r\n", ch ); return; } if ( argument[0] == STRING_NULL ) { send_to_char ( "You must specify at least one keyword.\r\n", ch ); return; } obj = recursive_note_find ( ch->first_carrying, argument ); if ( obj ) { if ( obj->in_obj ) { obj_from_obj ( obj ); obj = obj_to_char ( obj, ch ); } wear_obj ( ch, obj, TRUE, -1 ); } else send_to_char ( "Note not found.\r\n", ch ); return; } OBJ_DATA *recursive_note_find ( OBJ_DATA * obj, char *argument ) { OBJ_DATA *returned_obj; bool match = TRUE; char *argcopy; char *subject; char arg[MAX_INPUT_LENGTH]; char subj[MAX_STRING_LENGTH]; if ( !obj ) return NULL; switch ( obj->item_type ) { case ITEM_PAPER: if ( ( subject = get_extra_descr ( "_subject_", obj->first_extradesc ) ) == NULL ) break; sprintf ( subj, "%s", strlower ( subject ) ); subject = strlower ( subj ); argcopy = argument; while ( match ) { argcopy = one_argument ( argcopy, arg ); if ( arg[0] == STRING_NULL ) break; if ( !strstr ( subject, arg ) ) match = FALSE; } if ( match ) return obj; break; case ITEM_CONTAINER: case ITEM_CORPSE_NPC: case ITEM_CORPSE_PC: if ( obj->first_content ) { returned_obj = recursive_note_find ( obj->first_content, argument ); if ( returned_obj ) return returned_obj; } break; default: break; } return recursive_note_find ( obj->next_content, argument ); } void do_rolldie ( CHAR_DATA * ch, char *argument ) { OBJ_DATA *die; char output_string[MAX_STRING_LENGTH]; char roll_string[MAX_STRING_LENGTH]; char total_string[MAX_STRING_LENGTH]; char *verb; /* * char* face_string = NULL; * char** face_table = NULL; */ int rollsum = 0; int roll_count = 0; int numsides; int numrolls; bool *face_seen_table = NULL; if ( IS_NPC ( ch ) ) { send_to_char ( "Huh?\r\n", ch ); return; } if ( ( die = get_eq_char ( ch, WEAR_HOLD ) ) == NULL || die->item_type != ITEM_CHANCE ) { ch_printf ( ch, "You must be holding an item of chance!\r\n" ); return; } numrolls = ( is_number ( argument ) ) ? atoi ( argument ) : 1; verb = get_chance_verb ( die ); if ( numrolls > 100 ) { ch_printf ( ch, "You can't %s more than 100 times!\r\n", verb ); return; } numsides = die->value[0]; if ( numsides <= 1 ) { ch_printf ( ch, "There is no element of chance in this game!\r\n" ); return; } if ( die->value[3] == 1 ) { if ( numrolls > numsides ) { ch_printf ( ch, "Nice try, but you can only %s %d times.\r\n", verb, numsides ); return; } face_seen_table = calloc ( numsides, sizeof ( bool ) ); if ( !face_seen_table ) { bug ( "do_rolldie: cannot allocate memory for face_seen_table array, terminating.\r\n", 0 ); return; } } sprintf ( roll_string, " " ); while ( roll_count++ < numrolls ) { int current_roll; char current_roll_string[MAX_STRING_LENGTH]; do { current_roll = number_range ( 1, numsides ); } while ( die->value[3] == 1 && face_seen_table[current_roll - 1] == TRUE ); if ( die->value[3] == 1 ) face_seen_table[current_roll - 1] = TRUE; rollsum += current_roll; if ( roll_count > 1 ) strcat ( roll_string, ", " ); if ( numrolls > 1 && roll_count == numrolls ) strcat ( roll_string, "and " ); if ( die->value[1] == 1 ) { char *face_name = get_ed_number ( die, current_roll ); if ( face_name ) { char *face_name_copy = strdup ( face_name ); /* Since I want to tokenize without modifying the original string */ sprintf ( current_roll_string, "%s", strtok ( face_name_copy, "\n" ) ); free ( face_name_copy ); } else sprintf ( current_roll_string, "%d", current_roll ); } else sprintf ( current_roll_string, "%d", current_roll ); strcat ( roll_string, current_roll_string ); } if ( numrolls > 1 && die->value[2] == 1 ) { sprintf ( total_string, ", for a total of %d", rollsum ); strcat ( roll_string, total_string ); } strcat ( roll_string, ".\r\n" ); sprintf ( output_string, "You %s%s", verb, roll_string ); act ( AT_GREEN, output_string, ch, NULL, NULL, TO_CHAR ); sprintf ( output_string, "$n %s%s", verb, roll_string ); act ( AT_GREEN, output_string, ch, NULL, NULL, TO_ROOM ); if ( face_seen_table ) free ( face_seen_table ); return; } char *get_ed_number ( OBJ_DATA * obj, int number ) { EXTRA_DESCR_DATA *ed; int count; for ( ed = obj->first_extradesc, count = 1; ed; ed = ed->next, count++ ) { if ( count == number ) return ed->description; } return NULL; } char *get_chance_verb ( OBJ_DATA * obj ) { return ( obj->action_desc[0] != STRING_NULL ) ? obj->action_desc : "roll$q"; } /*dice chance deal throw*/ /* Junk command installed by Samson 1-13-98 * Code courtesy of Stu, from the mailing list. Allows player to destroy an item in their inventory. * Debugged and cleaned up on 4-16-01 by Samson. */ void do_junk ( CHAR_DATA * ch, char *argument ) { OBJ_DATA *obj, *obj_next; bool found = FALSE; if ( !argument || argument[0] == STRING_NULL ) { send_to_char ( "Junk what?\r\n", ch ); return; } for ( obj = ch->first_carrying; obj; obj = obj_next ) { obj_next = obj->next_content; if ( ( nifty_is_name ( argument, obj->name ) ) && can_see_obj ( ch, obj ) && obj->wear_loc == WEAR_NONE ) { found = TRUE; break; } } if ( found ) { if ( !can_drop_obj ( ch, obj ) && ch->level < LEVEL_IMMORTAL ) { send_to_char ( "You cannot junk that, it's cursed!\r\n", ch ); return; } separate_obj ( obj ); obj_from_char ( obj ); extract_obj ( obj ); act ( AT_ACTION, "$n junks $p.", ch, obj, NULL, TO_ROOM ); act ( AT_ACTION, "You junk $p.", ch, obj, NULL, TO_CHAR ); } return; } void do_donate ( CHAR_DATA * ch, char *argument ) { OBJ_DATA *obj; if ( !argument || argument[0] == STRING_NULL ) { send_to_char ( "Donate what?\r\n", ch ); return; } if ( ch->position == POS_FIGHTING ) { send_to_char ( "You cannot donate while fighting!\r\n", ch ); return; } if ( ! ( obj = get_obj_carry ( ch, argument ) ) ) { send_to_char ( "You do not have that!\r\n", ch ); return; } if ( !can_drop_obj ( ch, obj ) && ch->level < LEVEL_IMMORTAL ) { send_to_char ( "You cannot donate that, it's cursed!\r\n", ch ); return; } if ( ( obj->item_type == ITEM_CORPSE_NPC ) || ( obj->item_type == ITEM_CORPSE_PC ) ) { send_to_char ( "You cannot donate corpses!\r\n", ch ); return; } if ( obj->timer > 0 ) { send_to_char ( "You cannot donate that.\r\n", ch ); return; } if ( xIS_SET ( obj->extra_flags, ITEM_DONATION ) ) { send_to_char ( "You cannot donate a previously donated item\r\n", ch ); return; } if ( obj->item_type == ITEM_WEAPON ) { act ( AT_ACTION, "You donate $p, how generous of you!", ch, obj, NULL, TO_CHAR ); obj->cost = 0; separate_obj ( obj ); obj_from_char ( obj ); obj_to_room ( obj, get_room_index ( ROOM_VNUM_WEAPON ), NULL ); xSET_BIT ( obj->extra_flags, ITEM_DONATION ); save_char_obj ( ch ); return; } else if ( obj->item_type == ITEM_ARMOR ) { act ( AT_ACTION, "You donate $p, how generous of you!", ch, obj, NULL, TO_CHAR ); obj->cost = 0; separate_obj ( obj ); obj_from_char ( obj ); obj_to_room ( obj, get_room_index ( ROOM_VNUM_ARMOR ), NULL ); xSET_BIT ( obj->extra_flags, ITEM_DONATION ); save_char_obj ( ch ); return; } else { act ( AT_ACTION, "You donate $p, how generous of you!", ch, obj, NULL, TO_CHAR ); obj->cost = 0; separate_obj ( obj ); obj_from_char ( obj ); obj_to_room ( obj, get_room_index ( ROOM_VNUM_OTHER ), NULL ); xSET_BIT ( obj->extra_flags, ITEM_DONATION ); save_char_obj ( ch ); return; } return; }