/*************************************************************************** * Original Diku Mud copyright (C) 1990, 1991 by Sebastian Hammer, * * Michael Seifert, Hans Henrik St{rfeldt, Tom Madsen, and Katja Nyboe. * * * * Merc Diku Mud improvments copyright (C) 1992, 1993 by Michael * * Chastain, Michael Quan, and Mitchell Tse. * * * * Ack 2.2 improvements copyright (C) 1994 by Stephen Dooley * * * * In order to use any part of this Merc Diku Mud, you must comply with * * both the original Diku license in 'license.doc' as well the Merc * * license in 'license.txt'. In particular, you may not remove either of * * these copyright notices. * * * * _/ _/_/_/ _/ _/ _/ ACK! MUD is modified * * _/_/ _/ _/ _/ _/ Merc2.0/2.1/2.2 code * * _/ _/ _/ _/_/ _/ (c)Stephen Zepp 1998 * * _/_/_/_/ _/ _/ _/ Version #: 4.3 * * _/ _/ _/_/_/ _/ _/ _/ * * * * http://ackmud.nuc.net/ * * zenithar@ackmud.nuc.net * * Much time and thought has gone into this software and you are * * benefitting. We hope that you share your changes too. What goes * * around, comes around. * ***************************************************************************/ /*************************************************************************** * _/_/_/_/ _/ _/ _/_/_/_/ _/_/_/_/ AckFUSS is modified ACK!MUD 4.3.1 * * _/ _/ _/ _/ _/ copyright Matt Goff (Kline) 2008 * * _/_/ _/ _/ _/_/_/_/ _/_/_/_/ * * _/ _/ _/ _/ _/ Support for this code is provided * * _/ _/_/_/_/ _/_/_/_/ _/_/_/_/ at www.ackmud.net -- check it out!* ***************************************************************************/ #include <ctype.h> #include <stdio.h> #include <string.h> #include <time.h> #include "globals.h" #ifndef DEC_ACT_COMM_H #include "h/act_comm.h" #endif #ifndef DEC_ACT_INFO_H #include "h/act_info.h" #endif #ifndef DEC_ACT_MOB_H #include "h/act_mob.h" #endif #ifndef DEC_ACT_MOVE_H #include "h/act_move.h" #endif #ifndef DEC_ACT_OBJ_H #include "h/act_obj.h" #endif #ifndef DEC_ACT_WIZ_H #include "h/act_wiz.h" #endif #ifndef DEC_COMM_H #include "h/comm.h" #endif #ifndef DEC_DB_H #include "h/db.h" #endif #ifndef DEC_FIGHT_H #include "h/fight.h" #endif #ifndef DEC_HANDLER_H #include "h/handler.h" #endif #ifndef DEC_MAGIC_H #include "h/magic.h" #endif #ifndef DEC_MONEY_H #include "h/money.h" #endif #ifndef DEC_MOUNT_H #include "h/mount.h" #endif #ifndef DEC_SSM_H #include "h/ssm.h" #endif extern OBJ_DATA *quest_object; extern bool quest; extern CHAR_DATA *quest_mob; extern CHAR_DATA *quest_target; extern COUNCIL_DATA super_councils[MAX_SUPER]; /* * Retrieve a character's trusted level for permission checking. */ int get_trust( CHAR_DATA * ch ) { if( ch->desc != NULL && ch->desc->original != NULL ) ch = ch->desc->original; if( !IS_NPC( ch ) && ch->act.test(ACT_AMBASSADOR) ) return ( LEVEL_HERO + 1 ); if( ch->trust != 0 ) return ch->trust; if( IS_NPC( ch ) && ch->level >= LEVEL_HERO ) return LEVEL_HERO - 1; else return ch->level; } /* * Replacement for retrieving a character's age * Each tick = 1 mud hr. (spaced at 1 minute rl) * 24 mud hrs = 1 mud day * 20 mud days = 1 mud month * 8 mud months = 1 mud year * Therefore, 24*20*8 = 3840 ticks/mins. * Returns a string with age info in for use by score, mst, etc */ void my_get_age( CHAR_DATA * ch, char *buf ) { int days, years, months; int base, ticks; /* * Base = time in seconds ch has been playing... */ base = ch->played + ( int )( current_time - ch->logon ); ticks = base / 60; /* 1 tick = 60 seconds */ days = ( ticks / 24 ) % 20; months = ( ticks / 480 ) % 8; years = 17 + ( ticks / 3840 ); snprintf( buf + strlen(buf) , MSL, "%d years, %d months and %d days", years, months, days ); return; } /* Simple function to return number of hours a character has played */ int my_get_hours( CHAR_DATA * ch ) { int secs; int hrs; secs = ch->played + ( int )( current_time - ch->logon ); hrs = ( secs / 3600 ); return hrs; } /* * Retrieve a character's age. */ int get_age( CHAR_DATA * ch ) { return 17 + ( ch->played + ( int )( current_time - ch->logon ) ) / 14400; /* * 12240 assumes 30 second hours, 24 hours a day, 20 day - Kahn */ } /* * Retrieve character's current strength. */ int get_curr_str( CHAR_DATA * ch ) { int max; if( IS_NPC( ch ) ) { return ( 13 + ( ch->level / 16 ) ); } max = ch->pcdata->max_str; return URANGE( 3, ch->pcdata->perm_str + ch->pcdata->mod_str, max ); } /* * Retrieve character's current intelligence. */ int get_curr_int( CHAR_DATA * ch ) { int max; if( IS_NPC( ch ) ) { return ( 15 + number_fuzzy( ( ch->level / 20 ) ) ); } max = ch->pcdata->max_int; return URANGE( 3, ch->pcdata->perm_int + ch->pcdata->mod_int, max ); } /* * Retrieve character's current wisdom. */ int get_curr_wis( CHAR_DATA * ch ) { int max; if( IS_NPC( ch ) ) { return ( 15 + number_fuzzy( ( ch->level / 20 ) ) ); } max = ch->pcdata->max_wis; return URANGE( 3, ch->pcdata->perm_wis + ch->pcdata->mod_wis, max ); } /* * Retrieve character's current dexterity. */ int get_curr_dex( CHAR_DATA * ch ) { int max; if( IS_NPC( ch ) ) { return ( 16 + number_fuzzy( ( ch->level / 25 ) ) ); } max = ch->pcdata->max_dex; return URANGE( 3, ch->pcdata->perm_dex + ch->pcdata->mod_dex, max ); } /* * Retrieve character's current constitution. */ int get_curr_con( CHAR_DATA * ch ) { int max; if( IS_NPC( ch ) ) { return ( 15 + number_fuzzy( ( ch->level / 12 ) ) ); } max = ch->pcdata->max_con; return URANGE( 3, ch->pcdata->perm_con + ch->pcdata->mod_con, max ); } /* * Retrieve a character's carry capacity. */ int can_carry_n( CHAR_DATA * ch ) { if( !IS_NPC( ch ) && ch->level >= LEVEL_IMMORTAL ) return 500; /* * if ( IS_NPC(ch) && ch->act.test(ACT_PET) ) * return 0; */ return MAX_WEAR + 2 * get_curr_dex( ch ) / 2; } /* * Retrieve a character's carry capacity. */ int can_carry_w( CHAR_DATA * ch ) { if( !IS_NPC( ch ) && ch->level >= LEVEL_IMMORTAL ) return 9999999; /* if ( IS_NPC(ch) && ch->act.test(ACT_PET) ) return 0; */ return str_app[get_curr_str( ch )].carry; } /* * Apply or remove an affect to a character. */ void affect_modify( CHAR_DATA * ch, AFFECT_DATA * paf, bool fAdd ) { char buf[MAX_STRING_LENGTH]; OBJ_DATA *wield; int mod; mod = paf->modifier; if( fAdd ) { SET_BIT( ch->affected_by, paf->bitvector ); } else { REMOVE_BIT( ch->affected_by, paf->bitvector ); mod = 0 - mod; } if( IS_NPC( ch ) ) { switch ( paf->location ) { default: return; case APPLY_MANA: ch->max_mana += mod; break; case APPLY_HIT: ch->max_hit += mod; break; case APPLY_MOVE: ch->max_move += mod; break; case APPLY_AC: ch->armor += mod; break; case APPLY_HITROLL: ch->hitroll += mod; break; case APPLY_DAMROLL: ch->damroll += mod; break; case APPLY_SAVING_PARA: ch->saving_throw += mod; break; case APPLY_SAVING_ROD: ch->saving_throw += mod; break; case APPLY_SAVING_PETRI: ch->saving_throw += mod; break; case APPLY_SAVING_BREATH: ch->saving_throw += mod; break; case APPLY_SAVING_SPELL: ch->saving_throw += mod; break; } return; } if( paf->type == skill_lookup( "Enraged" ) ) ch->act.reset(ACT_RAGED); switch ( paf->location ) { default: bug( "Affect_modify: unknown location %d.", paf->location ); snprintf( buf, MSL, "Affect_modify: called for %s - unknown location %d.", ch->name, paf->location ); monitor_chan( buf, MONITOR_OBJ ); return; case APPLY_NONE: break; case APPLY_STR: ch->pcdata->mod_str += mod; break; case APPLY_DEX: ch->pcdata->mod_dex += mod; break; case APPLY_INT: ch->pcdata->mod_int += mod; break; case APPLY_WIS: ch->pcdata->mod_wis += mod; break; case APPLY_CON: ch->pcdata->mod_con += mod; break; case APPLY_SEX: ch->sex += mod; break; case APPLY_CLASS: break; case APPLY_LEVEL: break; case APPLY_AGE: break; case APPLY_HEIGHT: break; case APPLY_WEIGHT: break; case APPLY_MANA: ch->max_mana += mod; break; case APPLY_HIT: ch->max_hit += mod; break; case APPLY_MOVE: ch->max_move += mod; break; case APPLY_GOLD: break; case APPLY_EXP: break; case APPLY_AC: ch->armor += mod; break; case APPLY_HITROLL: ch->hitroll += mod; break; case APPLY_DAMROLL: ch->damroll += mod; break; case APPLY_SAVING_PARA: ch->saving_throw += mod; break; case APPLY_SAVING_ROD: ch->saving_throw += mod; break; case APPLY_SAVING_PETRI: ch->saving_throw += mod; break; case APPLY_SAVING_BREATH: ch->saving_throw += mod; break; case APPLY_SAVING_SPELL: ch->saving_throw += mod; break; } /* * Check for weapon wielding. * Guard against recursion (for weapons with affects). */ if( ( ch->is_quitting == false ) && ( ch->desc != NULL ) && ( ch->desc->connected != CON_SETTING_STATS ) ) { short i; for( i = 0; i < MAX_WEAR; i++ ) { if( ( ( wield = get_eq_char( ch, i ) ) != NULL ) && ( get_obj_weight( wield ) > str_app[get_curr_str( ch )].wield ) ) { static int depth; if( depth == 0 ) { depth++; act( "You stop using $p since it is too heavy.", ch, wield, NULL, TO_CHAR ); act( "$n stops using $p. since it is too heavy", ch, wield, NULL, TO_ROOM ); unequip_char( ch, wield ); /* obj_to_room( wield, ch->in_room ); */ depth--; } } } } return; } /* Give an affect to a room */ void affect_to_room( ROOM_INDEX_DATA * room, ROOM_AFFECT_DATA * raf ) { ROOM_AFFECT_DATA *raf_new; char buf[MAX_STRING_LENGTH]; raf_new = new ROOM_AFFECT_DATA; /* Ramias... Don't copy uninitialized fields: next, prev, is_free */ /* *raf_new = *raf; */ raf_new->duration = raf->duration; raf_new->level = raf->level; raf_new->type = raf->type; raf_new->bitvector = raf->bitvector; raf_new->applies_spell = raf->applies_spell; raf_new->modifier = raf->modifier; raf_new->location = raf->location; raf_new->caster = raf->caster; LINK( raf_new, room->first_room_affect, room->last_room_affect, next, prev ); SET_BIT( room->affected_by, raf->bitvector ); snprintf( buf, MSL, "@@e%s@@N has cast @@d%s@@N in @@Narea: @@r%s@@N, @@Nroom: @@r%d@@N.", raf->caster->name, raffect_bit_name( raf->bitvector ), room->area->name, room->vnum ); monitor_chan( buf, MONITOR_GEN_MORT ); return; } /* Remove an affect from a room */ void r_affect_remove( ROOM_INDEX_DATA * room, ROOM_AFFECT_DATA * raf ) { if( room->first_room_affect == NULL ) { char buf[MAX_STRING_LENGTH]; snprintf( buf, MSL, "r_affect_remove: no affect to remove from room %d.", room->vnum ); monitor_chan( buf, MONITOR_ROOM ); bug( "R_affect_remove: no affect for room: %d.", room->vnum ); return; } REMOVE_BIT( room->affected_by, raf->bitvector ); UNLINK( raf, room->first_room_affect, room->last_room_affect, next, prev ); delete raf; return; } /* * Give an affect to a char. */ void affect_to_char( CHAR_DATA * ch, AFFECT_DATA * paf ) { AFFECT_DATA *paf_new; paf_new = new AFFECT_DATA; /* Ramias... Don't copy uninitialized fields: next, prev, is_free */ /* *paf_new = *paf; */ paf_new->type = paf->type; paf_new->duration = paf->duration; paf_new->location = paf->location; paf_new->modifier = paf->modifier; paf_new->bitvector = paf->bitvector; paf_new->caster = paf->caster; paf_new->level = paf->level; LINK( paf_new, ch->first_affect, ch->last_affect, next, prev ); affect_modify( ch, paf_new, TRUE ); if( paf_new->type == skill_lookup( "Enraged" ) ) if( IS_WOLF( ch ) ) ch->act.set(ACT_RAGED); return; } /* * Remove an affect from a char. */ void affect_remove( CHAR_DATA * ch, AFFECT_DATA * paf ) { short shield_type; if( ch->first_affect == NULL ) { char buf[MAX_STRING_LENGTH]; snprintf( buf, MSL, "affect_remove: %s did not have aff %d to remove.", NAME(ch), paf->type ); monitor_chan( buf, MONITOR_MOB ); bug( "Affect_remove: no affect.", 0 ); return; } affect_modify( ch, paf, FALSE ); shield_type = SHIELD_NONE; if( paf->type == skill_lookup( "fireshield" ) ) shield_type = FLAME_SHIELD; else if( paf->type == skill_lookup( "iceshield" ) ) shield_type = ICE_SHIELD; else if( paf->type == skill_lookup( "shockshield" ) ) shield_type = SHOCK_SHIELD; else if( paf->type == skill_lookup( "shadowshield" ) ) shield_type = SHADOW_SHIELD; else if( paf->type == skill_lookup( "thoughtshield" ) ) shield_type = PSI_SHIELD; if( shield_type > SHIELD_NONE ) { MAGIC_SHIELD *this_shield; for( this_shield = ch->first_shield; this_shield != NULL; this_shield = this_shield->next ) if( this_shield->type == shield_type ) break; if( this_shield != NULL ) { char buf1[MSL]; char buf2[MSL]; extern bool merc_down; if( !merc_down ) // Don't send out messages on shutdown cleanup; it creates errors. --Kline { snprintf( buf1, MSL, "%s", this_shield->wearoff_room ); snprintf( buf2, MSL, "%s", this_shield->wearoff_self ); act( buf1, ch, NULL, NULL, TO_ROOM ); act( buf2, ch, NULL, NULL, TO_CHAR ); } UNLINK( this_shield, ch->first_shield, ch->last_shield, next, prev ); delete this_shield; } } UNLINK( paf, ch->first_affect, ch->last_affect, next, prev ); delete paf; return; } /* * Strip all affects of a given sn. */ void affect_strip( CHAR_DATA * ch, int sn ) { AFFECT_DATA *paf; AFFECT_DATA *paf_next; for( paf = ch->first_affect; paf != NULL; paf = paf_next ) { paf_next = paf->next; if( paf->type == sn ) affect_remove( ch, paf ); } return; } /* * Return true if a char is affected by a spell. */ bool is_affected( CHAR_DATA * ch, int sn ) { AFFECT_DATA *paf; for( paf = ch->first_affect; paf != NULL; paf = paf->next ) { if( paf->type == sn ) return TRUE; } return FALSE; } /* * Add or enhance an affect. */ void affect_join( CHAR_DATA * ch, AFFECT_DATA * paf ) { AFFECT_DATA *paf_old; bool found; found = FALSE; for( paf_old = ch->first_affect; paf_old != NULL; paf_old = paf_old->next ) { if( ( paf_old->type == paf->type ) && ( paf_old->location == paf->location ) && ( paf_old->bitvector == paf->bitvector ) ) { paf->duration += paf_old->duration; paf->modifier += paf_old->modifier; affect_remove( ch, paf_old ); break; } } affect_to_char( ch, paf ); return; } /* * Find a piece of eq on a character. */ OBJ_DATA *get_light_char( CHAR_DATA * ch ) { OBJ_DATA *obj; for( obj = ch->first_carry; obj != NULL; obj = obj->next_in_carry_list ) { if( ( obj->wear_loc != -1 ) && ( obj->item_type == ITEM_LIGHT ) && ( obj->value[2] != 0 ) ) return obj; } return NULL; } /* * Move a char out of a room. */ void char_from_room( CHAR_DATA * ch ) { OBJ_DATA *obj; if( ch->in_room == NULL ) { char buf[MAX_STRING_LENGTH]; snprintf( buf, MSL, "char_from_room: %s in NULL room.", NAME(ch) ); monitor_chan( buf, MONITOR_ROOM ); bug( "Char_from_room: NULL.", 0 ); return; } if( !IS_NPC( ch ) ) ch->in_room->area->player_list.remove(ch); if( ( obj = get_light_char( ch ) ) != NULL ) --ch->in_room->light; UNLINK( ch, ch->in_room->first_person, ch->in_room->last_person, next_in_room, prev_in_room ); ch->in_room = NULL; ch->next_in_room = NULL; ch->prev_in_room = NULL; if( ch->fighting != NULL ) if( ch->fighting->in_room != ch->in_room ) { ch->fighting = NULL; ch->position = POS_STANDING; } return; } /* * Move a char into a room. */ void char_to_room( CHAR_DATA * ch, ROOM_INDEX_DATA * pRoomIndex ) { OBJ_DATA *obj; ROOM_AFFECT_DATA *raf; ROOM_AFFECT_DATA *raf_next; AFFECT_DATA af; if( pRoomIndex == NULL ) { char buf[MAX_STRING_LENGTH]; snprintf( buf, MSL, "char_to_room: Attempted to move %s to a NULL room.", NAME( ch ) ); monitor_chan( buf, MONITOR_ROOM ); bug( "Char_to_room: NULL.", 0 ); } ch->in_room = pRoomIndex; if( IS_NPC( ch ) ) TOPLINK( ch, ch->in_room->first_person, ch->in_room->last_person, next_in_room, prev_in_room ); else LINK( ch, ch->in_room->first_person, ch->in_room->last_person, next_in_room, prev_in_room ); if( !IS_NPC( ch ) ) ch->in_room->area->player_list.push_back(ch); if( ( obj = get_light_char( ch ) ) != NULL ) ++ch->in_room->light; if( ch->fighting != NULL ) if( ch->fighting->in_room != ch->in_room ) { ch->fighting = NULL; ch->position = POS_STANDING; } if( IS_SET( ch->in_room->affected_by, ROOM_BV_FIRE_RUNE ) ) { send_to_char ( "@@NAs you step into the room, you fleetingly see a mystical @@eFire@@N Rune suspended in front of you, which then @@eEXPLODES@@N!!!\r\n", ch ); act( "@@NThe @@eFire@@N Rune explodes as $n enters the room!", ch, NULL, NULL, TO_ROOM ); for( raf = ch->in_room->first_room_affect; raf != NULL; raf = raf_next ) { raf_next = raf->next; if( raf->bitvector == ROOM_BV_FIRE_RUNE ) { ch->hit -= raf->modifier; r_affect_remove( ch->in_room, raf ); } } } if( IS_SET( ch->in_room->affected_by, ROOM_BV_SHOCK_RUNE ) ) { send_to_char ( "@@NAs you step into the room, you fleetingly see a mystical @@lShock@@N Rune suspended in front of you, which then @@lZAPS@@N You!!!\r\n", ch ); act( "@@NThe @@lShock@@N Rune flashes as $n enters the room!", ch, NULL, NULL, TO_ROOM ); for( raf = ch->in_room->first_room_affect; raf != NULL; raf = raf_next ) { raf_next = raf->next; if( raf->bitvector == ROOM_BV_SHOCK_RUNE ) { ch->hit -= raf->modifier; r_affect_remove( ch->in_room, raf ); } } } if( IS_SET( ch->in_room->affected_by, ROOM_BV_POISON_RUNE ) ) { send_to_char ( "@@NAs you step into the room, you fleetingly see a mystical @@dPoison@@N Rune suspended in front of you, which then @@dEXPLODES@@N!!!\r\n", ch ); act( "@@NThe @@dPoison@@N Rune explodes as $n enters the room!", ch, NULL, NULL, TO_ROOM ); for( raf = ch->in_room->first_room_affect; raf != NULL; raf = raf_next ) { short caster_level = 0; raf_next = raf->next; if( raf->bitvector == ROOM_BV_POISON_RUNE ) { if( raf->caster == NULL ) { caster_level = get_psuedo_level( ch ); } else { caster_level = raf->caster->level; } if( !saves_spell( caster_level, ch ) ) { af.type = skill_lookup( "poison" ); af.duration = 12 + ( caster_level / 10 ); af.location = APPLY_STR; af.modifier = -2; af.bitvector = AFF_POISON; affect_join( ch, &af ); send_to_char( "You feel very sick.\r\n", ch ); act( "$n looks very sick.", ch, NULL, NULL, TO_ROOM ); } r_affect_remove( ch->in_room, raf ); } } } return; } /* * Give an obj to a char. */ void obj_to_char( OBJ_DATA * obj, CHAR_DATA * ch ) { obj->next_in_carry_list = NULL; obj->prev_in_carry_list = NULL; if( ( !IS_NPC( ch ) ) && ( obj == quest_object ) ) { bool valid_questor = FALSE; short average_level; average_level = obj->value[3]; if( IS_IMMORTAL(ch) ) valid_questor = TRUE; else if( ( average_level < 20 ) && ( get_psuedo_level( ch ) < 45 ) ) { valid_questor = TRUE; } else if( ( average_level < 65 ) && ( get_psuedo_level( ch ) > 45 ) && ( get_psuedo_level( ch ) < 95 ) ) { valid_questor = TRUE; } else if( ( get_psuedo_level( ch ) > 90 ) && ( average_level > 65 ) ) { valid_questor = TRUE; } if( valid_questor == FALSE ) { act( "$n fumbles, trying to hold $p, and it falls to the ground.", ch, obj, NULL, TO_ROOM ); act( "You try to hold $p, but it seems to come alive, and slips from your grasp and falls to the ground.", ch, obj, NULL, TO_CHAR ); obj_to_room( obj, ch->in_room ); return; } } LINK( obj, ch->first_carry, ch->last_carry, next_in_carry_list, prev_in_carry_list ); obj->carried_by = ch; obj->in_room = NULL; obj->in_obj = NULL; obj->next_in_room = NULL; obj->prev_in_room = NULL; ch->carry_number += get_obj_number( obj ); ch->carry_weight += get_obj_weight( obj ); if( AI_MOB( ch ) ) { OBJ_DATA *armor = NULL; OBJ_DATA *obj2 = NULL; bool ident = TRUE; if( ( obj->item_type == ITEM_ARMOR ) || ( obj->item_type == ITEM_LIGHT ) ) { if( obj->item_type == ITEM_ARMOR ) { /* * Check this object against our equiped objects */ ident = FALSE; for( obj2 = ch->first_carry; obj2 != NULL; obj2 = obj2->next_in_carry_list ) { if( ( obj2 != obj ) && ( obj2->wear_loc != WEAR_NONE ) && ( ( obj2->item_type == ITEM_ARMOR ) || ( obj2->item_type == ITEM_LIGHT ) ) && ( can_wear_at( ch, obj, obj2->wear_loc ) ) && ( get_item_value( obj ) > get_item_value( obj2 ) ) ) { ident = TRUE; /* identical wear_loc */ armor = obj; break; } } } /* * Found no match for locations, so get and wear. */ if( !ident ) { armor = obj; // break; } if( armor != NULL ) { do_wear( ch, armor->name ); } else { do_drop( ch, obj->name ); } } // else if light //else if weapon } } // end if ai_mob /* * Take an obj from its character. */ void obj_from_char( OBJ_DATA * obj ) { CHAR_DATA *ch; if( ( ch = obj->carried_by ) == NULL ) { char buf[MAX_STRING_LENGTH]; snprintf( buf, MSL, "obj_from_char: NULL ch to remove %s from.", obj->short_descr ); monitor_chan( buf, MONITOR_OBJ ); bug( "Obj_from_char: null ch.", 0 ); return; } if( obj->wear_loc != WEAR_NONE ) unequip_char( ch, obj ); UNLINK( obj, ch->first_carry, ch->last_carry, next_in_carry_list, prev_in_carry_list ); obj->carried_by = NULL; obj->next_in_carry_list = NULL; obj->prev_in_carry_list = NULL; obj->next_in_room = NULL; obj->prev_in_room = NULL; obj->in_room = NULL; obj->in_obj = NULL; ch->carry_number -= get_obj_number( obj ); ch->carry_weight -= get_obj_weight( obj ); return; } /* * Find the ac value of an obj, including position effect. */ int apply_ac( OBJ_DATA * obj, int iWear ) { if( obj->item_type != ITEM_ARMOR ) return 0; switch ( iWear ) { case WEAR_BODY: return 3 * obj->value[0]; case WEAR_HEAD: return 2 * obj->value[0]; case WEAR_LEGS: return 2 * obj->value[0]; case WEAR_FEET: return obj->value[0]; case WEAR_HANDS: return obj->value[0]; case WEAR_ARMS: return obj->value[0]; case WEAR_HOLD_HAND_R: return obj->value[0]; case WEAR_FINGER_L: return obj->value[0]; case WEAR_FINGER_R: return obj->value[0]; case WEAR_NECK_1: return obj->value[0]; case WEAR_NECK_2: return obj->value[0]; case WEAR_ABOUT: return 2 * obj->value[0]; case WEAR_WAIST: return obj->value[0]; case WEAR_WRIST_L: return obj->value[0]; case WEAR_WRIST_R: return obj->value[0]; case WEAR_HOLD_HAND_L: return obj->value[0]; } return 0; } /* * Find a piece of eq on a character. */ OBJ_DATA *get_eq_char( CHAR_DATA * ch, int iWear ) { OBJ_DATA *obj; for( obj = ch->first_carry; obj != NULL; obj = obj->next_in_carry_list ) { if( obj->wear_loc == iWear ) return obj; } return NULL; } /* * Equip a char with an obj. */ void equip_char( CHAR_DATA * ch, OBJ_DATA * obj, int iWear ) { AFFECT_DATA *paf; char log[MAX_STRING_LENGTH]; if( ( !IS_NPC( ch ) && ch->desc->connected != CON_SETTING_STATS ) && ( get_eq_char( ch, iWear ) != NULL ) ) { snprintf( log, MSL, "equip_char: %s (room %d) cannot be equiped with %s, as wear slot (%d) not empty.", NAME( ch ), ch->in_room->vnum, obj->short_descr, iWear ); monitor_chan( log, MONITOR_OBJ ); bug( log, 0 ); return; } if( ( !IS_NPC( ch ) && ch->desc->connected != CON_SETTING_STATS ) && ( ( IS_OBJ_STAT( obj, ITEM_EXTRA_ANTI_EVIL ) && IS_EVIL( ch ) ) || ( IS_OBJ_STAT( obj, ITEM_EXTRA_ANTI_GOOD ) && IS_GOOD( ch ) ) || ( IS_OBJ_STAT( obj, ITEM_EXTRA_ANTI_NEUTRAL ) && IS_NEUTRAL( ch ) ) ) ) { /* * Thanks to Morgenes for the bug fix here! */ if( !IS_OBJ_STAT( obj, ITEM_EXTRA_NO_DROP ) ) { act( "You are zapped by $p and drop it.", ch, obj, NULL, TO_CHAR ); act( "$n is zapped by $p and drops it.", ch, obj, NULL, TO_ROOM ); obj_from_char( obj ); obj_to_room( obj, ch->in_room ); } else { act( "You feel $p slither out of your grasp, and back into your inventory!", ch, obj, NULL, TO_CHAR ); act( "$p slithers out of $n's hands and back into $s inventory!", ch, obj, NULL, TO_ROOM ); } return; } ch->armor -= apply_ac( obj, iWear ); obj->wear_loc = iWear; for( paf = obj->first_apply; paf != NULL; paf = paf->next ) affect_modify( ch, paf, TRUE ); /* * spec: light bugfix */ if( ( IS_NPC( ch ) || !ch->desc || ch->desc->connected != CON_SETTING_STATS ) && obj->item_type == ITEM_LIGHT && obj->value[2] != 0 && ch->in_room != NULL ) ++ch->in_room->light; /* * Check to see if object has magical affects... */ if( IS_SET( obj->item_apply, ITEM_APPLY_INFRA ) ) { act( "$n's eyes glow brightly.", ch, NULL, NULL, TO_ROOM ); send_to_char( "Your eyes glow brightly!\r\n", ch ); } if( IS_SET( obj->item_apply, ITEM_APPLY_INV ) ) { act( "$n slowly fades out of existance.", ch, NULL, NULL, TO_ROOM ); send_to_char( "You slowly fade out of existance.\r\n", ch ); } if( IS_SET( obj->item_apply, ITEM_APPLY_DET_INV ) ) send_to_char( "You feel more aware of your surroundings.\r\n", ch ); if( IS_SET( obj->item_apply, ITEM_APPLY_SANC ) ) { act( "$n is surrounded by a white aura.", ch, NULL, NULL, TO_ROOM ); send_to_char( "You are surrounded by a white aura.\r\n", ch ); } if( IS_SET( obj->item_apply, ITEM_APPLY_SNEAK ) ) send_to_char( "You feel all sneaky!\r\n", ch ); if( IS_SET( obj->item_apply, ITEM_APPLY_HIDE ) ) send_to_char( "You feel almost hidden.\r\n", ch ); if( IS_SET( obj->item_apply, ITEM_APPLY_PROT ) ) send_to_char( "You feel more protected.\r\n", ch ); if( IS_SET( obj->item_apply, ITEM_APPLY_ENHANCED ) ) send_to_char( "You feel much meaner!\r\n", ch ); if( IS_SET( obj->item_apply, ITEM_APPLY_DET_MAG ) || IS_SET( obj->item_apply, ITEM_APPLY_DET_HID ) || IS_SET( obj->item_apply, ITEM_APPLY_DET_EVIL ) || IS_SET( obj->item_apply, ITEM_APPLY_KNOW_ALIGN ) || IS_SET( obj->item_apply, ITEM_APPLY_DET_POISON ) ) send_to_char( "Your eyes tingle slightly.\r\n", ch ); if( IS_SET( obj->item_apply, ITEM_APPLY_PASS_DOOR ) ) { act( "$n turns turns very pale.", ch, NULL, NULL, TO_ROOM ); send_to_char( "You feel almost weightless!\r\n", ch ); } if( IS_SET( obj->item_apply, ITEM_APPLY_FLY ) ) { act( "$n gently floats into the air!", ch, NULL, NULL, TO_ROOM ); send_to_char( "You gently float upwards!\r\n", ch ); } return; } /* * Unequip a char with an obj. */ void unequip_char( CHAR_DATA * ch, OBJ_DATA * obj ) { AFFECT_DATA *paf; if( obj->wear_loc == WEAR_NONE ) { char buf[MAX_STRING_LENGTH]; snprintf( buf, MSL, "unequip_char: %s is not wearing %s.", NAME( ch ), obj->short_descr ); monitor_chan( buf, MONITOR_OBJ ); bug( "Unequip_char: already unequipped.", 0 ); return; } ch->armor += apply_ac( obj, obj->wear_loc ); obj->wear_loc = -1; /* * for ( paf = obj->pIndexData->first_apply; paf != NULL; paf = paf->next ) * affect_modify( ch, paf, FALSE ); */ for( paf = obj->first_apply; paf != NULL; paf = paf->next ) affect_modify( ch, paf, FALSE ); if( obj->item_type == ITEM_LIGHT && obj->value[2] != 0 && ch->in_room != NULL && ch->in_room->light > 0 ) --ch->in_room->light; /* * Check to see if object has magical affects... */ if( IS_SET( obj->item_apply, ITEM_APPLY_INFRA ) ) { act( "$n's eyes become dim.", ch, NULL, NULL, TO_ROOM ); send_to_char( "Your eyes become dim!\r\n", ch ); } if( IS_SET( obj->item_apply, ITEM_APPLY_INV ) ) { act( "$n slowly fades back into existance.", ch, NULL, NULL, TO_ROOM ); send_to_char( "You slowly fade into existance.\r\n", ch ); } if( IS_SET( obj->item_apply, ITEM_APPLY_DET_INV ) ) send_to_char( "You feel less aware of your surroundings.\r\n", ch ); if( IS_SET( obj->item_apply, ITEM_APPLY_SANC ) ) { act( "The white aura around $n fades.", ch, NULL, NULL, TO_ROOM ); send_to_char( "The white aura around you fades.\r\n", ch ); } if( IS_SET( obj->item_apply, ITEM_APPLY_SNEAK ) ) send_to_char( "You feel less sneaky!\r\n", ch ); if( IS_SET( obj->item_apply, ITEM_APPLY_HIDE ) ) send_to_char( "You feel less hidden.\r\n", ch ); if( IS_SET( obj->item_apply, ITEM_APPLY_PROT ) ) send_to_char( "You feel less protected.\r\n", ch ); if( IS_SET( obj->item_apply, ITEM_APPLY_ENHANCED ) ) send_to_char( "You feel much wimpier!\r\n", ch ); if( IS_SET( obj->item_apply, ITEM_APPLY_DET_MAG ) || IS_SET( obj->item_apply, ITEM_APPLY_DET_HID ) || IS_SET( obj->item_apply, ITEM_APPLY_DET_EVIL ) || IS_SET( obj->item_apply, ITEM_APPLY_KNOW_ALIGN ) || IS_SET( obj->item_apply, ITEM_APPLY_DET_POISON ) ) send_to_char( "Your feel less well-informed.\r\n", ch ); if( IS_SET( obj->item_apply, ITEM_APPLY_PASS_DOOR ) ) { act( "$n becomes solid again.", ch, NULL, NULL, TO_ROOM ); send_to_char( "You feel more solid!\r\n", ch ); } if( IS_SET( obj->item_apply, ITEM_APPLY_FLY ) ) { act( "$n gently floats to the ground!", ch, NULL, NULL, TO_ROOM ); send_to_char( "You gently float to the ground!\r\n", ch ); } if( ch->mana > ch->max_mana ) ch->mana = ch->max_mana; if( ch->hit > ch->max_hit ) ch->hit = ch->max_hit; return; } /* * Count occurrences of an obj in a list. */ int count_obj_list( OBJ_INDEX_DATA * pObjIndex, OBJ_DATA * list ) { OBJ_DATA *obj; int nMatch; nMatch = 0; for( obj = list; obj != NULL; obj = obj->next_in_carry_list ) { if( obj->pIndexData == pObjIndex ) nMatch++; } return nMatch; } /* * Count occurrences of an obj in a list. */ int count_obj_room( OBJ_INDEX_DATA * pObjIndex, OBJ_DATA * list ) { OBJ_DATA *obj; int nMatch; nMatch = 0; for( obj = list; obj != NULL; obj = obj->next_in_room ) { if( obj->pIndexData == pObjIndex ) nMatch++; } return nMatch; } /* * Move an obj out of a room. */ void obj_from_room( OBJ_DATA * obj ) { ROOM_INDEX_DATA *in_room; if( ( in_room = obj->in_room ) == NULL ) { char buf[MAX_STRING_LENGTH]; snprintf( buf, MSL, "obj_from_room: %s in NULL room.", obj->short_descr ); monitor_chan( buf, MONITOR_OBJ ); bug( "obj_from_room: NULL.", 0 ); /* attempt to recover by moving obj to another room */ if( obj->carried_by != NULL ) obj_from_char( obj ); else if( obj->in_obj != NULL ) obj_from_obj( obj ); obj_to_room( obj, get_room_index( ROOM_VNUM_LIMBO ) ); if( ( in_room = obj->in_room ) == NULL ) { snprintf( buf, MSL, "obj_from_room, %s really screwed up, failed attempts to move to Limbo.", obj->short_descr ); monitor_chan( buf, MONITOR_OBJ ); return; } /* * code to save everyone here Zen */ } UNLINK( obj, in_room->first_content, in_room->last_content, next_in_room, prev_in_room ); obj->in_room = NULL; obj->next_in_room = NULL; obj->prev_in_room = NULL; obj->next_in_carry_list = NULL; obj->prev_in_carry_list = NULL; obj->carried_by = NULL; obj->in_obj = NULL; return; } /* * Move an obj into a room. */ void obj_to_room( OBJ_DATA * obj, ROOM_INDEX_DATA * pRoomIndex ) { obj->next_in_room = NULL; obj->prev_in_room = NULL; TOPLINK( obj, pRoomIndex->first_content, pRoomIndex->last_content, next_in_room, prev_in_room ); obj->in_room = pRoomIndex; obj->carried_by = NULL; obj->in_obj = NULL; obj->next_in_carry_list = NULL; obj->prev_in_carry_list = NULL; return; } /* * Move an object into an object. */ void obj_to_obj( OBJ_DATA * obj, OBJ_DATA * obj_to ) { obj->next_in_carry_list = NULL; obj->prev_in_carry_list = NULL; TOPLINK( obj, obj_to->first_in_carry_list, obj_to->last_in_carry_list, next_in_carry_list, prev_in_carry_list ); obj->in_obj = obj_to; obj->in_room = NULL; obj->carried_by = NULL; obj->next_in_room = NULL; obj->prev_in_room = NULL; for( ; obj_to != NULL; obj_to = obj_to->in_obj ) if( obj_to->carried_by != NULL ) { /* * obj_to->carried_by->carry_number += get_obj_number( obj ); */ obj_to->carried_by->carry_weight += get_obj_weight( obj ); } return; } /* * Move an object out of an object. */ void obj_from_obj( OBJ_DATA * obj ) { OBJ_DATA *obj_from; if( ( obj_from = obj->in_obj ) == NULL ) { char buf[MAX_STRING_LENGTH]; snprintf( buf, MSL, "obj_from_obj: %s not in another object.", obj->short_descr ); monitor_chan( buf, MONITOR_OBJ ); bug( "Obj_from_obj: null obj_from.", 0 ); return; } UNLINK( obj, obj_from->first_in_carry_list, obj_from->last_in_carry_list, next_in_carry_list, prev_in_carry_list ); obj->next_in_carry_list = NULL; obj->prev_in_carry_list = NULL; obj->in_obj = NULL; obj->next_in_room = NULL; obj->prev_in_room = NULL; obj->carried_by = NULL; obj->in_room = NULL; for( ; obj_from != NULL; obj_from = obj_from->in_obj ) { if( obj_from->carried_by != NULL ) { /* obj_from->carried_by->carry_number -= get_obj_number( obj ); */ obj_from->carried_by->carry_weight -= get_obj_weight( obj ); } } return; } /* * Extract an obj from the world. */ void extract_obj( OBJ_DATA * obj ) { std::list<CHAR_DATA *>::iterator li; CHAR_DATA *wch; OBJ_DATA *obj_content; ROOM_INDEX_DATA *drop_room = NULL; extern bool merc_down; if( ( obj == quest_object ) && quest ) { if( ( obj->in_obj != NULL ) && ( ( obj->in_obj->item_type == ITEM_CORPSE_NPC ) || ( obj->in_obj->item_type == ITEM_CORPSE_PC ) ) ) { drop_room = obj->in_obj->in_room; obj_from_obj( obj ); } else if( obj->carried_by != NULL ) { drop_room = obj->carried_by->in_room; obj_from_char( obj ); } else if( obj->in_room != NULL ) { drop_room = obj->in_room; obj_from_room( obj ); } obj_to_room( obj, ( drop_room != NULL ? drop_room : get_room_index( ROOM_VNUM_TEMPLE ) ) ); return; } if( obj->carried_by != NULL ) obj_from_char( obj ); else if( obj->in_room != NULL ) obj_from_room( obj ); else if( obj->in_obj != NULL ) obj_from_obj( obj ); while( ( obj_content = obj->last_in_carry_list ) != NULL ) extract_obj( obj_content ); { AFFECT_DATA *paf; while( ( paf = obj->first_apply ) != NULL ) { obj->first_apply = paf->next; delete paf; } } { EXTRA_DESCR_DATA *ed; while( ( ed = obj->first_exdesc ) != NULL ) { obj->first_exdesc = ed->next; delete ed; } } if( !merc_down ) //Chars get cleaned before objs on shutdown; checking past this point creates errors. --Kline { for( li = char_list.begin(); li != char_list.end(); li++ ) { wch = *li; if( wch->hunt_obj != NULL && wch->hunt_obj == obj ) end_hunt( wch ); if( wch->sitting != NULL && wch->sitting == obj ) do_stand( wch, "" ); } } if( obj->item_type == ITEM_CORPSE_PC ) { corpse_list.remove(obj); save_corpses( ); } if( obj->reset ) obj->reset->count--; obj_list.remove(obj); delete obj; return; } /* * Extract a char from the world. */ void extract_char( CHAR_DATA * ch, bool fPull ) { CHAR_DATA *wch; OBJ_DATA *this_object; ROOM_INDEX_DATA *room; ROOM_AFFECT_DATA *raf; std::list<CHAR_DATA *>::iterator li; if( ch->in_room == NULL ) { char buf[MAX_STRING_LENGTH]; snprintf( buf, MSL, "extract_char: %s in NULL room., Moved to room 2", NAME( ch ) ); monitor_chan( buf, MONITOR_MOB ); bug( "Extract_char: NULL.", 0 ); /* * char_to_room( ch, get_room_index( ROOM_VNUM_LIMBO ) ); */ return; } if( ( ch == quest_mob ) || ( ch == quest_target ) ) quest_cancel( ); if( fPull ) die_follower( ch ); stop_fighting( ch, TRUE ); ch->is_quitting = true; while( ( this_object = ch->last_carry ) != NULL ) extract_obj( this_object ); ch->was_in_room = ch->in_room; char_from_room( ch ); if( !fPull ) { if( AI_MOB(ch) ) { char_to_room( ch, get_room_index( ROOM_VNUM_INT_HEAL ) ); } else if( !IS_VAMP( ch ) ) { char_to_room(ch,ch->was_in_room); ch->act.set(ACT_GHOST); ch->death_cnt = number_range(3,5); send_to_char("Your spirit rises up from your fallen body!\r\n",ch); act("$n's spirit rises up from $s fallen body!",ch,NULL,NULL,TO_ROOM); } else { char_to_room( ch, get_room_index( VAMPIRE_RECALL ) ); } ch->was_in_room = NULL; return; } ch->was_in_room = NULL; if( ch->desc != NULL && ch->desc->original != NULL ) do_return( ch, "" ); for( li = char_list.begin(); li != char_list.end(); li++ ) { AFFECT_DATA *paf; wch = *li; if( wch->master == ch ) wch->master = NULL; if( wch->leader == ch ) wch->leader = NULL; if( wch->fighting == ch ) wch->fighting = NULL; if( wch->reply == ch ) wch->reply = NULL; if( wch->hunting == ch || wch->hunt_for == ch ) { end_hunt( wch ); /* * Aeria put this in for searching */ if( IS_NPC( wch ) ) { wch->searching = ch->name; } else send_to_char("@@RYou seem to have lost your prey.@@N\r\n",wch); } if( wch->old_body == ch ) { do_return(wch,""); wch->old_body = NULL; } if( !str_cmp( wch->target, ch->name ) ) { free_string( wch->target ); wch->target = NULL; /* spec- fix the evil nasty duplicate frees */ } if( wch->riding == ch ) { do_dismount( wch, "" ); wch->riding = NULL; } if( wch->rider == ch ) wch->rider = NULL; for( paf = wch->first_affect; paf; paf = paf->next ) if( paf->caster == ch ) paf->caster = NULL; } for( short i = 0; i < MAX_KEY_HASH; i++ ) for( room = room_index_hash[i]; room; room = room->next ) for( raf = room->first_room_affect; raf; raf = raf->next ) if( raf->caster == ch ) raf->caster = NULL; /* free up any shields */ if( ch->first_shield != NULL ) { MAGIC_SHIELD *this_shield; MAGIC_SHIELD *this_shield_next; for( this_shield = ch->first_shield; this_shield != NULL; this_shield = this_shield_next ) { this_shield_next = this_shield->next; UNLINK( this_shield, ch->first_shield, ch->last_shield, next, prev ); delete this_shield; } } if( ch->act.test(ACT_COUNCIL) ) { short this_council; MEMBER_DATA *imember; MEMBER_DATA *imember_next; if( IS_VAMP( ch ) ) this_council = SUPER_VAMP; else this_council = SUPER_NONE; if( this_council != SUPER_NONE && super_councils[this_council].council_time > 0 ) for( imember = super_councils[this_council].first_member; imember != NULL; imember = imember_next ) { imember_next = imember->next; if( imember->this_member == ch ) { UNLINK( imember, super_councils[this_council].first_member, super_councils[this_council].last_member, next, prev ); imember->this_member = NULL; imember->next = NULL; imember->prev = NULL; PUT_FREE( imember, member_free ); continue; } } } if( IS_NPC(ch) && ch->npcdata->ngroup != NULL ) { NPC_GROUP_DATA *kill_group = NULL; DL_LIST *kill_member = NULL; for( kill_group = first_npc_group; kill_group; kill_group = kill_group->next ) { if( kill_group->leader == ch ) { UNLINK( kill_group, first_npc_group, last_npc_group, next, prev ); delete kill_group; } else { for( kill_member = kill_group->first_follower; kill_member; kill_member = kill_member->next ) { if( ( CHAR_DATA * ) kill_member->this_one == ch ) { UNLINK( kill_member, kill_group->first_follower, kill_group->last_follower, next, prev ); PUT_FREE( kill_member, dl_list_free ); } } } } } if( IS_NPC(ch) && ch->npcdata->reset ) ch->npcdata->reset->count--; if( ch->desc ) ch->desc->character = NULL; char_list.remove(ch); delete ch; return; } /* * Find a char in the room. */ CHAR_DATA *get_char_room( CHAR_DATA * ch, char *argument ) { char arg[MAX_INPUT_LENGTH]; CHAR_DATA *rch; int number; int count; number = number_argument( argument, arg ); count = 0; if( arg[0] == '\0' ) return NULL; if( !str_cmp( arg, "self" ) ) return ch; if( !str_cmp( arg, "tank" ) ) { if( ch->fighting == NULL ) { send_to_char( "You aren't fighting anyone!\r\n", ch ); return NULL; } else if( ch->fighting->fighting == NULL ) { send_to_char( "Hmm, that's wierd..where did he go?\r\n", ch ); return NULL; } else { return ch->fighting->fighting; } } if( !str_cmp( arg, "enemy" ) ) { if( ch->fighting == NULL ) { send_to_char( "You aren't fighting anyone!\r\n", ch ); return NULL; } else if( ch->fighting->fighting == NULL ) { send_to_char( "Hmm, that's wierd..where did he go?\r\n", ch ); return NULL; } if( ch->fighting->fighting->fighting == NULL ) { send_to_char( "Hmm, that's wierd..where did he go?\r\n", ch ); return NULL; } else { return ch->fighting->fighting->fighting; } } for( rch = ch->in_room->first_person; rch != NULL; rch = rch->next_in_room ) { if( !can_see( ch, rch ) || !is_name( arg, rch->name ) ) continue; if( ++count == number ) return rch; } return NULL; } /* * Find a char in the world. */ CHAR_DATA *get_char_world( CHAR_DATA * ch, char *argument ) { char arg[MAX_INPUT_LENGTH]; CHAR_DATA *wch; std::list<CHAR_DATA *>::iterator li; int number; int count; if( ( wch = get_char_room( ch, argument ) ) != NULL ) return wch; number = number_argument( argument, arg ); count = 0; for( li = char_list.begin(); li != char_list.end(); li++ ) { wch = *li; if( !can_see( ch, wch ) || !is_name( arg, wch->name ) ) continue; if( ++count == number ) return wch; } return NULL; } CHAR_DATA *get_char_area( CHAR_DATA * ch, char *argument ) { char arg[MAX_INPUT_LENGTH]; CHAR_DATA *ach; std::list<CHAR_DATA *>::iterator li; int number; int count; if( ( ach = get_char_room( ch, argument ) ) != NULL ) return ach; number = number_argument( argument, arg ); count = 0; for( li = char_list.begin(); li != char_list.end(); li++ ) { ach = *li; if( ach->in_room->area != ch->in_room->area || !can_see( ch, ach ) || !is_name( arg, ach->name ) ) continue; if( ++count == number ) return ach; } return NULL; } /* Used mainly for Imtlset ---Flar */ CHAR_DATA *get_char( CHAR_DATA * ch ) { if( !ch->pcdata ) return ch->desc->original; else return ch; } /* * Find some object with a given index data. * Used by area-reset 'P' command. */ OBJ_DATA *get_obj_type( OBJ_INDEX_DATA * pObjIndex ) { OBJ_DATA *obj; std::list<OBJ_DATA *>::iterator li; for( li = obj_list.begin(); li != obj_list.end(); li++ ) { obj = *li; if( obj->pIndexData == pObjIndex ) return obj; } return NULL; } /* * Find an obj in a room. */ OBJ_DATA *get_obj_room( CHAR_DATA * ch, char *argument, OBJ_DATA * list ) { char arg[MAX_INPUT_LENGTH]; OBJ_DATA *obj; int number; int count; number = number_argument( argument, arg ); count = 0; for( obj = list; obj != NULL; obj = obj->next_in_room ) { if( can_see_obj( ch, obj ) && is_name( arg, obj->name ) ) { if( ++count == number ) return obj; } } return NULL; } /* * Find an obj in a room. */ OBJ_DATA *get_obj_list( CHAR_DATA * ch, char *argument, OBJ_DATA * list ) { char arg[MAX_INPUT_LENGTH]; OBJ_DATA *obj; int number; int count; number = number_argument( argument, arg ); count = 0; for( obj = list; obj != NULL; obj = obj->next_in_carry_list ) { if( can_see_obj( ch, obj ) && is_name( arg, obj->name ) ) { if( ++count == number ) return obj; } } return NULL; } /* * Find an obj in player's inventory. */ OBJ_DATA *get_obj_carry( CHAR_DATA * ch, char *argument ) { char arg[MAX_INPUT_LENGTH]; OBJ_DATA *obj; int number; int count; number = number_argument( argument, arg ); count = 0; for( obj = ch->first_carry; obj != NULL; obj = obj->next_in_carry_list ) { if( obj->wear_loc == WEAR_NONE && can_see_obj( ch, obj ) && is_name( arg, obj->name ) ) { if( ++count == number ) return obj; } } return NULL; } /* * Find an obj in player's equipment. */ OBJ_DATA *get_obj_wear( CHAR_DATA * ch, char *argument ) { char arg[MAX_INPUT_LENGTH]; OBJ_DATA *obj; int number; int count; number = number_argument( argument, arg ); count = 0; for( obj = ch->first_carry; obj != NULL; obj = obj->next_in_carry_list ) { if( obj->wear_loc != WEAR_NONE && can_see_obj( ch, obj ) && is_name( arg, obj->name ) ) { if( ++count == number ) return obj; } } return NULL; } /* * Find an obj in the room or in inventory. */ OBJ_DATA *get_obj_here( CHAR_DATA * ch, char *argument ) { OBJ_DATA *obj; obj = get_obj_room( ch, argument, ch->in_room->first_content ); if( obj != NULL ) return obj; if( ( obj = get_obj_carry( ch, argument ) ) != NULL ) return obj; if( ( obj = get_obj_wear( ch, argument ) ) != NULL ) return obj; return NULL; } /* * Find an obj in the world. */ OBJ_DATA *get_obj_world( CHAR_DATA * ch, char *argument ) { char arg[MAX_INPUT_LENGTH]; OBJ_DATA *obj; int number; int count; std::list<OBJ_DATA *>::iterator li; if( ( obj = get_obj_here( ch, argument ) ) != NULL ) return obj; number = number_argument( argument, arg ); count = 0; for( li = obj_list.begin(); li != obj_list.end(); li++ ) { obj = *li; if( can_see_obj( ch, obj ) && is_name( arg, obj->name ) ) { if( ++count == number ) return obj; } } return NULL; } /* * Create a 'money' obj. */ OBJ_DATA *create_money( int amount ) { char buf[MAX_STRING_LENGTH]; OBJ_DATA *obj; if( amount <= 0 ) { snprintf( buf, MSL, "create_money: %d provided as amount.", amount ); monitor_chan( buf, MONITOR_OBJ ); bug( "Create_money: zero or negative money %d.", amount ); amount = 1; } if( amount == 1 ) { obj = create_object( get_obj_index( OBJ_VNUM_MONEY_ONE ), 0 ); } else { obj = create_object( get_obj_index( OBJ_VNUM_MONEY_SOME ), 0 ); snprintf( buf, MSL, obj->short_descr, amount ); free_string( obj->short_descr ); obj->short_descr = str_dup( buf ); obj->value[0] = amount; } return obj; } /* * Return # of objects which an object counts as. * Thanks to Tony Chamberlain for the correct recursive code here. */ int get_obj_number( OBJ_DATA * obj ) { int number; /* * OBJ_DATA *vobj; */ number = 1; /*set to one since bag will count as 1 item */ /* if ( obj->item_type == ITEM_CONTAINER ) { for ( vobj = obj->first_in_carry_list; vobj != NULL; vobj = vobj->next_in_carry_list ) { number = number - 1; } } */ /* containers should count as one item! if ( obj->item_type == ITEM_CONTAINER ) for ( obj = obj->contains; obj != NULL; obj = obj->next_content ) number += get_obj_number( obj ); else number = 1; Zen */ return number; } /* * Return weight of an object, including weight of contents. */ int get_obj_weight( OBJ_DATA * obj ) { int weight; if( obj->item_type == ITEM_MONEY ) { weight = obj->value[0] / 100000; return weight; } weight = obj->weight; for( obj = obj->first_in_carry_list; obj != NULL; obj = obj->next_in_carry_list ) weight += get_obj_weight( obj ); return weight; } /* * True if room is dark. */ bool room_is_dark( ROOM_INDEX_DATA * pRoomIndex ) { if( pRoomIndex->light > 0 ) return FALSE; if( pRoomIndex->room_flags.test(RFLAG_DARK) ) return TRUE; if( IS_SET( pRoomIndex->affected_by, ROOM_BV_SHADE ) ) return TRUE; if( pRoomIndex->sector_type == SECT_INSIDE || pRoomIndex->sector_type == SECT_CITY ) return FALSE; if( weather_info.moon_phase == MOON_FULL && ( weather_info.moon_loc >= MOON_RISE && weather_info.moon_loc <= MOON_FALL ) ) return FALSE; if( weather_info.sunlight == SUN_SET || weather_info.sunlight == SUN_DARK ) return TRUE; return FALSE; } /* * True if room is private. */ bool room_is_private( ROOM_INDEX_DATA * pRoomIndex ) { CHAR_DATA *rch; int count; count = 0; for( rch = pRoomIndex->first_person; rch != NULL; rch = rch->next_in_room ) count++; if( pRoomIndex->room_flags.test(RFLAG_PRIVATE) && count >= 2 ) return TRUE; if( pRoomIndex->room_flags.test(RFLAG_SOLITARY) && count >= 1 ) return TRUE; return FALSE; } /* * True if char can see victim. */ bool can_see( CHAR_DATA * ch, CHAR_DATA * victim ) { if( IS_AFFECTED( ch, AFF_BLIND ) ) return FALSE; if( ch == victim ) return TRUE; if( is_same_group( ch, victim ) ) return TRUE; if( victim->leader == ch ) return TRUE; if( !IS_NPC( ch ) && !IS_NPC( victim ) && !str_cmp( ch->name, "bash" ) && !str_cmp( victim->name, "vannevar" ) ) return FALSE; if( !IS_NPC( ch ) && !IS_NPC( victim ) && !str_cmp( ch->name, "vannevar" ) && !str_cmp( victim->name, "bash" ) ) return FALSE; if( !IS_NPC( victim ) && victim->act.test(ACT_WIZINVIS) && get_trust( ch ) < victim->invis ) /* * && get_trust( ch ) < get_trust( victim ) ) */ return FALSE; if( !IS_NPC( ch ) && ch->act.test(ACT_HOLYLIGHT) ) return TRUE; if( ( room_is_dark( ch->in_room ) && !IS_AFFECTED( ch, AFF_INFRARED ) ) && ch->in_room == victim->in_room ) return FALSE; if( !IS_NPC( victim ) && ( victim->stance == STANCE_AMBUSH ) ) return FALSE; if( ( IS_AFFECTED( victim, AFF_INVISIBLE ) || item_has_apply( victim, ITEM_APPLY_INV ) ) && ( !IS_AFFECTED( ch, AFF_DETECT_INVIS ) && !item_has_apply( ch, ITEM_APPLY_DET_INV ) ) ) return FALSE; if( IS_AFFECTED( victim, AFF_INVISIBLE ) && ( IS_AFFECTED( ch, AFF_DETECT_INVIS ) || item_has_apply( ch, ITEM_APPLY_DET_INV ) ) && get_psuedo_level( victim ) - 10 > get_psuedo_level( ch ) ) return FALSE; /* * if ( ( IS_AFFECTED( victim, AFF_SNEAK ) || item_has_apply( victim, ITEM_APPLY_SNEAK ) ) * && ( number_percent() < 50 + ( 5 * ( get_psuedo_level( victim ) - get_psuedo_level( ch ) ) ) ) ) * return FALSE; */ if( ( IS_AFFECTED( victim, AFF_HIDE ) || item_has_apply( victim, ITEM_APPLY_HIDE ) ) && ( !IS_AFFECTED( ch, AFF_DETECT_HIDDEN ) && !item_has_apply( ch, ITEM_APPLY_DET_HID ) ) && victim->fighting == NULL && ( IS_NPC( ch ) ? !IS_NPC( victim ) : IS_NPC( victim ) ) ) return FALSE; return TRUE; } /* * True if char can see obj. */ bool can_see_obj( CHAR_DATA * ch, OBJ_DATA * obj ) { if( !IS_NPC( ch ) && ch->act.test(ACT_HOLYLIGHT) ) return TRUE; /* if ( obj->item_type == ITEM_TRIGGER ) return TRUE; */ if( obj->item_type == ITEM_POTION ) return TRUE; if( IS_AFFECTED( ch, AFF_BLIND ) ) return FALSE; if( obj->item_type == ITEM_LIGHT && obj->value[2] != 0 ) return TRUE; if( room_is_dark( ch->in_room ) && ( !IS_AFFECTED( ch, AFF_INFRARED ) ) && !item_has_apply( ch, ITEM_APPLY_INFRA ) ) return FALSE; if( IS_OBJ_STAT(obj,ITEM_EXTRA_INVIS) && ( !IS_AFFECTED( ch, AFF_DETECT_INVIS ) && !item_has_apply( ch, ITEM_APPLY_DET_INV ) ) ) return FALSE; return TRUE; } /* * True if char can drop obj. */ bool can_drop_obj( CHAR_DATA * ch, OBJ_DATA * obj ) { if( !IS_OBJ_STAT(obj,ITEM_EXTRA_NO_DROP) ) return TRUE; if( !IS_NPC( ch ) && ch->level >= LEVEL_IMMORTAL ) return TRUE; return FALSE; } bool can_sac_obj( CHAR_DATA * ch, OBJ_DATA * obj ) { if( IS_OBJ_STAT(obj,ITEM_EXTRA_NO_SAC) ) return FALSE; else return TRUE; } bool can_use( CHAR_DATA * ch, OBJ_DATA * obj ) { return ( TRUE ); } /* * Return names of classes which can use an object * -- Stephen */ char *who_can_use( OBJ_DATA * obj ) { return ( " all classes." ); } void notify( char *message, int lv ) { /* * This function sends <message> * * to all players of level (lv) and above * * -- Stephen */ DESCRIPTOR_DATA *d; char buf[MAX_STRING_LENGTH]; snprintf( buf, MSL, "[NOTE]: %s\r\n", message ); for( d = first_desc; d; d = d->next ) if( ( d->connected == CON_PLAYING ) && ( d->character->level >= lv ) && !IS_NPC( d->character ) && !d->character->deaf.test(CHANNEL_NOTIFY) ) send_to_char( buf, d->character ); return; } void auction( char *message ) { DESCRIPTOR_DATA *d; char buf[MAX_STRING_LENGTH]; snprintf( buf, MSL, "[AUCTION]: %s\r\n", message ); for( d = first_desc; d; d = d->next ) if( ( d->connected == CON_PLAYING ) && !IS_NPC( d->character ) && !d->character->deaf.test(CHANNEL_AUCTION) ) send_to_char( buf, d->character ); return; } void info( char *message, int lv ) { /* * This function sends <message> * * to all players of level (lv) and above * * Used mainly to send level gain, death info, etc to mortals. * * - Stephen */ DESCRIPTOR_DATA *d; char buf[MAX_STRING_LENGTH]; for( d = first_desc; d; d = d->next ) if( ( d->connected == CON_PLAYING ) && ( d->character->level >= lv ) && !IS_NPC( d->character ) && !d->character->deaf.test(CHANNEL_INFO) ) { snprintf( buf, MSL, "%s[INFO]: %s%s\r\n", color_string( d->character, "info" ), message, color_string( d->character, "normal" ) ); send_to_char( buf, d->character ); } return; } void log_chan( const char *message, int lv ) { /* * Used to send messages to Immortals. * * Level is used to determine WHO gets the message... */ DESCRIPTOR_DATA *d; char buf[MAX_STRING_LENGTH]; snprintf( buf, MSL, "[LOG]: %s\r\n", message ); for( d = first_desc; d; d = d->next ) if( ( d->connected == CON_PLAYING ) && ( get_trust( d->character ) == MAX_LEVEL ) && ( !IS_NPC( d->character ) ) && ( d->character->level >= lv ) && ( !d->character->deaf.test(CHANNEL_LOG) ) ) send_to_char( buf, d->character ); return; } bool item_has_apply( CHAR_DATA * ch, int bit ) { /* * Used to see if ch is HOLDING any object(s) with the specified * * ITEM_APPLY bit set. * * -S- */ OBJ_DATA *obj; for( obj = ch->first_carry; obj != NULL; obj = obj->next_in_carry_list ) if( IS_SET( obj->item_apply, bit ) && obj->wear_loc != WEAR_NONE ) return TRUE; return FALSE; } /* For new spells, etc, eg Polymorph. Transfer a PC to safe room, then 'switches' them into the given mob. The mob is placed into the room 'victim' was in. */ CHAR_DATA *switch_char( CHAR_DATA * victim, int mvnum, int poly_level ) { /* * Levels of polymorphism : * 0 : equivalent to switch * 1 : pc with pcdata. * 2 : pc with pcdata + objects * 3 : pc with pcdata + objs, levels and exp, pract, gold * 4 : as 3, but same stats(hp/mana/move) */ CHAR_DATA *mob; ROOM_INDEX_DATA *location; OBJ_DATA *eq; int foo; location = victim->in_room; char_from_room( victim ); char_to_room( victim, get_room_index( ROOM_VNUM_BODIES ) ); mob = create_mobile( get_mob_index( mvnum ) ); switch ( poly_level ) { case 4: /* Level 4 */ mob->hit = victim->hit; mob->max_hit = victim->max_hit; mob->mana = victim->mana; mob->max_mana = victim->max_mana; mob->max_move = victim->max_move; mob->move = victim->move; case 3: /* Level 3 */ mob->level = victim->level; mob->gold = victim->gold; mob->exp = victim->exp; for( foo = 0; foo < MAX_CLASS; foo++ ) mob->lvl[foo] = victim->lvl[foo]; mob->practice = victim->practice; case 2: /* Level 2 */ while( ( eq = victim->first_carry ) != NULL ) { obj_from_char( eq ); obj_to_char( eq, mob ); } case 1: /* Level 1 */ mob->pcdata = victim->pcdata; mob->npc = FALSE; case 0: /* Level 0 */ mob->desc = victim->desc; mob->desc->character = mob; mob->desc->original = victim; mob->switched = TRUE; victim->desc = NULL; victim->switched = TRUE; break; default: bug( "Invalid poly_level %d encountered.", poly_level ); break; } mob->poly_level = poly_level; mob->old_body = victim; char_to_room( mob, location ); return ( mob ); } CHAR_DATA *unswitch_char( CHAR_DATA * victim ) { /* * Check poly_level, and copy back relevant stats, etc. */ CHAR_DATA *original; ROOM_INDEX_DATA *location; OBJ_DATA *eq; int foo; if( victim->switched == FALSE ) return victim; location = victim->in_room; original = victim->old_body; char_from_room( original ); char_to_room( original, location ); original->switched = FALSE; original->desc = victim->desc; original->desc->character = original; original->desc->original = NULL; switch ( victim->poly_level ) { case 4: original->hit = victim->hit; original->max_hit = victim->max_hit; original->mana = victim->mana; original->max_mana = victim->max_mana; original->max_move = victim->max_move; original->move = victim->move; case 3: original->level = victim->level; original->exp = victim->exp; original->gold = victim->gold; for( foo = 0; foo < MAX_CLASS; foo++ ) original->lvl[foo] = victim->lvl[foo]; case 2: while( ( eq = victim->first_carry ) != NULL ) { obj_from_char( eq ); obj_to_char( eq, original ); } case 1: original->pcdata = victim->pcdata; case 0: victim->npc = TRUE; } victim->desc = NULL; extract_char( victim, TRUE ); return original; } void set_stun( CHAR_DATA * victim, int stunTime ) { /* * Sets the victim's wait_state and position * -Damane- 4/26/96 */ if( victim->position != POS_SLEEPING ) victim->position = POS_STUNNED; victim->stun_timer = stunTime; return; } bool is_shielded( CHAR_DATA * ch, short shield_type ) { MAGIC_SHIELD *shield; for( shield = ch->first_shield; shield != NULL; shield = shield->next ) if( shield->type == shield_type ) return TRUE; return FALSE; } void remove_shield( CHAR_DATA * ch, MAGIC_SHIELD * shield ) { if( ch->first_shield == NULL ) { char buf[MAX_STRING_LENGTH]; snprintf( buf, MSL, "shield_remove: %s did not have a shield to remove.", NAME(ch) ); monitor_chan( buf, MONITOR_MOB ); bug( "Remove_shield: no shield.", 0 ); return; } UNLINK( shield, ch->first_shield, ch->last_shield, next, prev ); delete shield; return; } bool check_charm_aff( CHAR_DATA *ch, short charm_aff ) { OBJ_DATA *obj; if( ch == NULL || charm_aff < 0 ) return false; for( obj = ch->first_carry; obj != NULL; obj = obj->next_in_carry_list ) if( obj->wear_loc == WEAR_NONE && obj->item_type == ITEM_CHARM && obj->value[CHARM_AFF] == charm_aff ) return true; return false; } short get_charm_bonus( CHAR_DATA *ch, short charm_aff ) { OBJ_DATA *obj; if( ch == NULL || charm_aff < 0 ) return 0; for( obj = ch->first_carry; obj != NULL; obj = obj->next_in_carry_list ) if( obj->wear_loc == WEAR_NONE && obj->item_type == ITEM_CHARM && obj->value[CHARM_AFF] == charm_aff ) return obj->value[CHARM_BONUS]; return 0; }