/*************************************************************************** * STAR WARS REALITY 1.0 * *--------------------------------------------------------------------------* * Star Wars Reality Code Additions and changes from the Smaug Code * * copyright (c) 1997 by Sean Cooper * * -------------------------------------------------------------------------* * Starwars and Starwars Names copyright(c) Lucas Film Ltd. * *--------------------------------------------------------------------------* * SMAUG 1.0 (C) 1994, 1995, 1996 by Derek Snider * * SMAUG code team: Thoric, Altrag, Blodkai, Narn, Haus, * * Scryn, Rennard, Swordbearer, Gorog, Grishnakh and Tricops * * ------------------------------------------------------------------------ * * Merc 2.1 Diku Mud improvments copyright (C) 1992, 1993 by Michael * * Chastain, Michael Quan, and Mitchell Tse. * * Original Diku Mud copyright (C) 1990, 1991 by Sebastian Hammer, * * Michael Seifert, Hans Henrik St{rfeldt, Tom Madsen, and Katja Nyboe. * * ------------------------------------------------------------------------ * * Main structure manipulation module * ****************************************************************************/ #include <sys/types.h> #include <ctype.h> #include <stdio.h> #include <string.h> #include <time.h> #include "mud.h" #define BFS_MARK BV01 extern int top_exit; extern int top_ed; extern int top_affect; extern int cur_qobjs; extern int cur_qchars; extern CHAR_DATA * gch_prev; extern OBJ_DATA * gobj_prev; extern REL_DATA * first_relation; extern REL_DATA * last_relation; CHAR_DATA *cur_char; ROOM_INDEX_DATA *cur_room; bool cur_char_died; ch_ret global_retcode; int cur_obj; int cur_obj_serial; bool cur_obj_extracted; obj_ret global_objcode; bool is_wizvis( CHAR_DATA *ch , CHAR_DATA *victim ); OBJ_DATA *group_object( OBJ_DATA *obj1, OBJ_DATA *obj2 ); void room_explode( OBJ_DATA *obj , CHAR_DATA *xch, ROOM_INDEX_DATA *room ); void room_explode_1( OBJ_DATA *obj , CHAR_DATA *xch, ROOM_INDEX_DATA *room , int blast ); void room_explode_2( ROOM_INDEX_DATA *room , int blast ); void explode( OBJ_DATA *obj ) { if ( obj->armed_by ) { ROOM_INDEX_DATA *room; CHAR_DATA *xch; bool held = FALSE; for ( xch = first_char; xch; xch = xch->next ) if ( !IS_NPC( xch ) && nifty_is_name( obj->armed_by, xch->name ) ) { if ( obj->carried_by ) { act( AT_WHITE, "$p EXPLODES in $n's hands!", obj->carried_by, obj, NULL, TO_ROOM ); act( AT_WHITE, "$p EXPLODES in your hands!", obj->carried_by, obj, NULL, TO_CHAR ); room = xch->in_room; held = TRUE; } else if ( obj->in_room ) room = obj->in_room; else room = NULL; if ( room ) { if ( !held && room->first_person ) act( AT_WHITE, "$p EXPLODES!", room->first_person , obj, NULL, TO_ROOM ); room_explode( obj , xch, room ); } } } if (!obj_extracted(obj)) make_scraps(obj); } void room_explode( OBJ_DATA *obj, CHAR_DATA *xch, ROOM_INDEX_DATA *room ) { int blast; blast = (int) (obj->value[1] / 500) ; room_explode_1( obj , xch, room , blast ); room_explode_2( room , blast ); } void room_explode_1( OBJ_DATA *obj , CHAR_DATA *xch, ROOM_INDEX_DATA *room , int blast ) { CHAR_DATA *rch; CHAR_DATA *rnext; OBJ_DATA *robj; OBJ_DATA *robj_next; int dam; char buf[MAX_STRING_LENGTH]; if ( xIS_SET( room->room_flags, BFS_MARK ) ) return; xSET_BIT( room->room_flags , BFS_MARK ); for ( rch = room->first_person ; rch ; rch = rnext ) { rnext = rch->next_in_room; act( AT_WHITE, "The shockwave from a massive explosion rips through your body!", room->first_person , obj, NULL, TO_ROOM ); dam = number_range ( obj->value[0] , obj->value[1] ); damage( rch, rch , dam, TYPE_UNDEFINED ); if ( !char_died(rch) ) { if ( IS_NPC( rch ) ) { if ( IS_SET( rch->act , ACT_SENTINEL ) ) { rch->was_sentinel = rch->in_room; REMOVE_BIT( rch->act, ACT_SENTINEL ); } start_hating( rch , xch ); start_hunting( rch , xch ); } } } for ( robj = room->first_content; robj; robj = robj_next ) { robj_next = robj->next_content; if ( robj != obj && robj->item_type != ITEM_SCRAPS && robj->item_type != ITEM_CORPSE_NPC && robj->item_type != ITEM_CORPSE_PC && robj->item_type != ITEM_DROID_CORPSE) make_scraps( robj ); } if ( xIS_SET(room->room_flags, ROOM_SPACECRAFT) ) { SHIP_DATA *ship; for ( ship = first_ship; ship; ship = ship->next ) { if ( room->vnum >= ship->firstroom && room->vnum <= ship->lastroom ) { sprintf( buf, "The explosion from %s's grenade rocks the ship.",xch->name ); echo_to_ship( AT_RED , ship , buf ); sprintf( buf, "GRENADE: %s's grenade hits ship called %s", xch->name, ship->name ); log_string(buf); damage_ship(ship,0,dam/10); } } } { EXIT_DATA *pexit; for ( pexit = room->first_exit; pexit; pexit = pexit->next ) { if ( pexit->to_room && pexit->to_room != room ) { if ( blast > 0 ) { int roomblast; roomblast = blast - 1; room_explode_1( obj , xch, pexit->to_room , roomblast ); } else echo_to_room( AT_WHITE, pexit->to_room , "You hear a loud EXPLOSION not to far from here." ); } } } } void room_explode_2( ROOM_INDEX_DATA *room , int blast ) { if ( !xIS_SET( room->room_flags, BFS_MARK ) ) return; xREMOVE_BIT( room->room_flags , BFS_MARK ); if ( blast > 0 ) { int roomblast; EXIT_DATA *pexit; for ( pexit = room->first_exit; pexit; pexit = pexit->next ) { if ( pexit->to_room && pexit->to_room != room ) { roomblast = blast - 1; room_explode_2( pexit->to_room , roomblast ); } } } } bool is_wizvis( CHAR_DATA *ch , CHAR_DATA *victim ) { if ( !IS_NPC(victim) && IS_SET(victim->act, PLR_WIZINVIS) && get_trust( ch ) < victim->pcdata->wizinvis ) return FALSE; return TRUE; } /* * Return how much exp a char has */ int get_exp( CHAR_DATA *ch , int ability ) { if ( ability >= MAX_ABILITY || ability < 0 ) return 0; return ch->experience[ability]; } /* * Calculate roughly how much experience a character is worth */ int get_exp_worth( CHAR_DATA *ch ) { int exp; exp = ch->skill_level[COMBAT_ABILITY] * ch->top_level * 50; exp += ch->max_hit * 2; exp -= (ch->armor-50) * 2; exp += ( ch->barenumdie * ch->baresizedie + GET_DAMROLL(ch) ) * 50; exp += GET_HITROLL(ch) * ch->top_level * 10; if ( IS_AFFECTED(ch, AFF_SANCTUARY) ) exp += exp * 1.5; if ( IS_AFFECTED(ch, AFF_FIRESHIELD) ) exp += exp * 1.2; if ( IS_AFFECTED(ch, AFF_SHOCKSHIELD) ) exp += exp * 1.2; exp = URANGE( MIN_EXP_WORTH, exp, MAX_EXP_WORTH ); return exp; } /* -Thoric * Return how much experience is required for ch to get to a certain level */ int exp_level( sh_int level) { int lvl; lvl = UMAX(0, level - 1); return ( lvl * lvl * 500 ); } /* * Get what level ch is based on exp */ sh_int level_exp( CHAR_DATA *ch, int exp ) { int x, lastx, y, tmp; x = LEVEL_SUPREME; lastx = x; y = 0; while ( !y ) { tmp = exp_level( x); lastx = x; if ( tmp > exp ) x /= 2; else if (lastx != x ) x += ( x / 2 ); else y = x; } if ( y < 1 ) y = 1; if ( y > LEVEL_SUPREME ) y = LEVEL_SUPREME; return y; } /* * Retrieve a character's trusted level for permission checking. */ sh_int get_trust( CHAR_DATA *ch ) { if ( !ch ) return 0; if ( ch->desc ) { if ( ch->desc->original ) ch = ch->desc->original; } if ( ch->trust != 0 ) return ch->trust; if ( IS_NPC(ch) && ch->top_level >= LEVEL_AVATAR ) return LEVEL_AVATAR; if ( ch->top_level >= LEVEL_NEOPHYTE && IS_RETIRED( ch ) ) return LEVEL_NEOPHYTE; return ch->top_level; } /* * Retrieve a character's age. * Updated for new code by Gavin * With help from Darrik Vequir of SW:RiP */ sh_int get_age( CHAR_DATA *ch ) { int years; int months; if ( IS_NPC(ch) ) return 17 + ( ch->played + (current_time - ch->logon) ) / 14400; if ( ch->pcdata->birthday.year <= -1 && ch->pcdata->birthday.day <= -1 && ch->pcdata->birthday.month <= -1 ) { bug("%s doesn't have a Birthday",ch->name); return -1 ; } /*years = ( (time_info.year - ch->pcdata->birthday.year) + ch->pcdata->age );*/ years = ( (time_info.year - ch->pcdata->birthday.year) + ch->pcdata->age ); months = 12 + ( time_info.month - ch->pcdata->birthday.month ); months %= 12; if ( time_info.day < ch->pcdata->birthday.day ) months--; if ( months < 0 ) months += 12; if ( time_info.month < ch->pcdata->birthday.month ) years--; return years; } /* * Retrieve character's current strength. */ sh_int get_curr_str( CHAR_DATA *ch ) { sh_int max; if ( !IS_NPC(ch) ) { max = 20 + race_table[ch->race]->str_plus; max = UMIN(max,25); if ( IS_SET(ch->pcdata->cyber, CYBER_STRENGTH) ) { /*ch->mod_str += 1;*/ max += 1; } } else max = 20; return URANGE( 3, ch->perm_str + ch->mod_str, max ); } /* * Retrieve character's current intelligence. */ sh_int get_curr_int( CHAR_DATA *ch ) { sh_int max; if ( !IS_NPC(ch) ) { max = 20 + race_table[ch->race]->int_plus; max = UMIN(max,25); if ( IS_SET(ch->pcdata->cyber, CYBER_MIND) ) /* ch->mod_int += 1;*/ max += 1; } else max = 20; return URANGE( 3, ch->perm_int + ch->mod_int, max ); } /* * Retrieve character's current wisdom. */ sh_int get_curr_wis( CHAR_DATA *ch ) { sh_int max; if ( !IS_NPC(ch) ) { max = 20 + race_table[ch->race]->wis_plus; max = UMIN(max,25); } else max = 20; return URANGE( 3, ch->perm_wis + ch->mod_wis, max ); } /* * Retrieve character's current dexterity. */ sh_int get_curr_dex( CHAR_DATA *ch ) { sh_int max; if ( !IS_NPC(ch) ) { max = 20 + race_table[ch->race]->dex_plus; max = UMIN(max,25); if ( IS_SET(ch->pcdata->cyber, CYBER_REFLEXES) ) /*ch->mod_dex += 1;*/ max += 1; } else max = 20; return URANGE( 3, ch->perm_dex + ch->mod_dex, max ); } /* * Retrieve character's current constitution. */ sh_int get_curr_con( CHAR_DATA *ch ) { sh_int max; if ( !IS_NPC(ch) ) { max = 20 + race_table[ch->race]->con_plus; max = UMIN(max,25); } else max = 20; return URANGE( 3, ch->perm_con + ch->mod_con, max ); } /* * Retrieve character's current charisma. */ sh_int get_curr_cha( CHAR_DATA *ch ) { sh_int max; if ( !IS_NPC( ch) ) { max = 20 + race_table[ch->race]->cha_plus; max = UMIN(max,25); } else max = 20; return URANGE( 3, ch->perm_cha + ch->mod_cha, max ); } /* * Retrieve character's current luck. */ sh_int get_curr_lck( CHAR_DATA *ch ) { sh_int max; if ( !IS_NPC(ch) ) { max = 20 + race_table[ch->race]->lck_plus; max = UMIN(max,25); } else max = 20; return URANGE( 3, ch->perm_lck + ch->mod_lck, max ); } /* * Retrieve a character's carry capacity. * Vastly reduced (finally) due to containers -Thoric */ int can_carry_n( CHAR_DATA *ch ) { int penalty = 0; if ( !IS_NPC(ch) && get_trust(ch) >= LEVEL_IMMORTAL ) return get_trust(ch)*200; if ( IS_NPC(ch) && IS_SET(ch->act, ACT_PET) ) return 0; if ( IS_NPC(ch) && IS_SET(ch->act, ACT_VENDOR) ) return 600; if ( get_eq_char(ch, WEAR_WIELD) ) ++penalty; if ( get_eq_char(ch, WEAR_DUAL_WIELD) ) ++penalty; if ( get_eq_char(ch, WEAR_MISSILE_WIELD) ) ++penalty; if ( get_eq_char(ch, WEAR_HOLD) ) ++penalty; if ( get_eq_char(ch, WEAR_SHIELD) ) ++penalty; return URANGE(5, (ch->top_level+15)/5 + get_curr_dex(ch)-13 - penalty, 20); } /* * Retrieve a character's carry capacity. */ int can_carry_w( CHAR_DATA *ch ) { if ( !IS_NPC(ch) && get_trust(ch) >= LEVEL_IMMORTAL ) return 1000000; if ( IS_NPC(ch) && IS_SET(ch->act, ACT_VENDOR) ) return 1000000; if ( IS_NPC(ch) && IS_SET(ch->act, ACT_PET) ) return 0; return str_app[get_curr_str(ch)].carry; } /* * See if a player/mob can take a piece of prototype eq -Thoric */ bool can_take_proto( CHAR_DATA *ch ) { if ( IS_IMMORTAL(ch) ) return TRUE; else if ( IS_NPC(ch) && IS_SET(ch->act, ACT_PROTOTYPE) ) return TRUE; else return FALSE; } /* * See if a string is one of the names of an object. */ bool is_name( const char *str, char *namelist ) { char name[MAX_INPUT_LENGTH]; for ( ; ; ) { namelist = one_argument( namelist, name ); if ( name[0] == '\0' ) return FALSE; if ( !str_cmp( str, name ) ) return TRUE; } } bool is_name_prefix( const char *str, char *namelist ) { char name[MAX_INPUT_LENGTH]; for ( ; ; ) { namelist = one_argument( namelist, name ); if ( name[0] == '\0' ) return FALSE; if ( !str_prefix( str, name ) ) return TRUE; } } /* * See if a string is one of the names of an object. -Thoric * Treats a dash as a word delimiter as well as a space */ bool is_name2( const char *str, char *namelist ) { char name[MAX_INPUT_LENGTH]; for ( ; ; ) { namelist = one_argument2( namelist, name ); if ( name[0] == '\0' ) return FALSE; if ( !str_cmp( str, name ) ) return TRUE; } } bool is_name2_prefix( const char *str, char *namelist ) { char name[MAX_INPUT_LENGTH]; for ( ; ; ) { namelist = one_argument2( namelist, name ); if ( name[0] == '\0' ) return FALSE; if ( !str_prefix( str, name ) ) return TRUE; } } /* -Thoric * Checks if str is a name in namelist supporting multiple keywords */ bool nifty_is_name( char *str, char *namelist ) { char name[MAX_INPUT_LENGTH]; if ( !str || str[0] == '\0' ) return FALSE; for ( ; ; ) { str = one_argument2( str, name ); if ( name[0] == '\0' ) return TRUE; if ( !is_name2( name, namelist ) ) return FALSE; } } bool nifty_is_name_prefix( char *str, char *namelist ) { char name[MAX_INPUT_LENGTH]; if ( !str || str[0] == '\0' ) return FALSE; for ( ; ; ) { str = one_argument2( str, name ); if ( name[0] == '\0' ) return TRUE; if ( !is_name2_prefix( name, namelist ) ) return FALSE; } } /* * Apply or remove an affect to a character. */ void affect_modify( CHAR_DATA *ch, AFFECT_DATA *paf, bool fAdd ) { OBJ_DATA *wield; int mod; struct skill_type *skill; ch_ret retcode; mod = paf->modifier; if ( fAdd ) { SET_BIT( ch->affected_by, paf->bitvector ); } else { REMOVE_BIT( ch->affected_by, paf->bitvector ); /* * might be an idea to have a duration removespell which returns * the spell after the duration... but would have to store * the removed spell's information somewhere... -Thoric */ if ( (paf->location % REVERSE_APPLY) == APPLY_REMOVESPELL ) return; switch( paf->location % REVERSE_APPLY ) { case APPLY_AFFECT: REMOVE_BIT( ch->affected_by, mod ); return; case APPLY_RESISTANT: REMOVE_BIT( ch->resistant, mod ); return; case APPLY_IMMUNE: REMOVE_BIT( ch->immune, mod ); return; case APPLY_SUSCEPTIBLE: REMOVE_BIT( ch->susceptible, mod ); return; case APPLY_WEARSPELL: /* affect only on wear */ return; case APPLY_REMOVE: SET_BIT( ch->affected_by, mod ); return; } mod = 0 - mod; } switch ( paf->location % REVERSE_APPLY ) { default: bug( "Affect_modify: unknown location %d.", paf->location ); return; case APPLY_NONE: break; case APPLY_STR: ch->mod_str += mod; break; case APPLY_DEX: ch->mod_dex += mod; break; case APPLY_INT: ch->mod_int += mod; break; case APPLY_WIS: ch->mod_wis += mod; break; case APPLY_CON: ch->mod_con += mod; break; case APPLY_CHA: ch->mod_cha += mod; break; case APPLY_LCK: ch->mod_lck += mod; break; case APPLY_SEX: ch->sex = (ch->sex+mod) % 3; if ( ch->sex < 0 ) ch->sex += 2; ch->sex = URANGE( 0, ch->sex, 2 ); break; case APPLY_LEVEL: break; case APPLY_AGE: break; case APPLY_HEIGHT: ch->height += mod; break; case APPLY_WEIGHT: ch->weight += 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_AFFECT: SET_BIT( ch->affected_by, mod ); break; case APPLY_RESISTANT: SET_BIT( ch->resistant, mod ); break; case APPLY_IMMUNE: SET_BIT( ch->immune, mod ); break; case APPLY_SUSCEPTIBLE: SET_BIT( ch->susceptible, mod ); break; case APPLY_WEAPONSPELL: /* see fight.c */ break; case APPLY_REMOVE: REMOVE_BIT(ch->affected_by, mod); break; case APPLY_DRUNK: if ( !IS_NPC(ch) ) ch->pcdata->condition[COND_DRUNK] = URANGE( 0, ch->pcdata->condition[COND_DRUNK] + mod, 48 ); break; case APPLY_MENTALSTATE: ch->mental_state = URANGE(-100, ch->mental_state + mod, 100); break; case APPLY_EMOTION: ch->emotional_state = URANGE(-100, ch->emotional_state + mod, 100); break; case APPLY_STRIPSN: if ( IS_VALID_SN(mod) ) affect_strip( ch, mod ); else bug( "affect_modify: APPLY_STRIPSN invalid sn %d", mod ); break; /* spell cast upon wear/removal of an object -Thoric */ case APPLY_WEARSPELL: case APPLY_REMOVESPELL: if ( xIS_SET(ch->in_room->room_flags, ROOM_NO_MAGIC) || IS_SET(ch->immune, RIS_MAGIC) || saving_char == ch /* so save/quit doesn't trigger */ || loading_char == ch ) /* so loading doesn't trigger */ return; mod = abs(mod); if ( IS_VALID_SN(mod) && (skill=skill_table[mod]) != NULL && skill->type == SKILL_SPELL ) if ( (retcode=(*skill->spell_fun) ( mod, 1/*ch->skill_level[FORCE_ABILITY]*/, ch, ch )) == rCHAR_DIED || char_died(ch) ) return; break; } /* * Check for weapon wielding. * Guard against recursion (for weapons with affects). */ if ( !IS_NPC( ch ) && saving_char != ch && ( wield = get_eq_char( ch, WEAR_WIELD ) ) != NULL && get_obj_weight(wield) > str_app[get_curr_str(ch)].wield ) { static int depth; if ( depth == 0 ) { depth++; act( AT_ACTION, "You are too weak to wield $p any longer.", ch, wield, NULL, TO_CHAR ); act( AT_ACTION, "$n stops wielding $p.", ch, wield, NULL, TO_ROOM ); unequip_char( ch, wield ); depth--; } } return; } /* * Give an affect to a char. */ void affect_to_char( CHAR_DATA *ch, AFFECT_DATA *paf ) { AFFECT_DATA *paf_new; if ( !ch ) { bug( "Affect_to_char: NULL ch!", 0 ); return; } if ( !paf ) { bug( "Affect_to_char: NULL paf!", 0 ); return; } CREATE( paf_new, AFFECT_DATA, 1 ); LINK( paf_new, ch->first_affect, ch->last_affect, next, prev ); 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; affect_modify( ch, paf_new, TRUE ); return; } /* * Remove an affect from a char. */ void affect_remove( CHAR_DATA *ch, AFFECT_DATA *paf ) { if ( !ch->first_affect ) { bug( "Affect_remove: no affect.", 0 ); return; } affect_modify( ch, paf, FALSE ); UNLINK( paf, ch->first_affect, ch->last_affect, next, prev ); DISPOSE( 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; 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; paf = paf->next ) if ( paf->type == sn ) return TRUE; return FALSE; } /* * Add or enhance an affect. * Limitations put in place by Thoric, they may be high... but at least * they're there :) */ void affect_join( CHAR_DATA *ch, AFFECT_DATA *paf ) { AFFECT_DATA *paf_old; for ( paf_old = ch->first_affect; paf_old; paf_old = paf_old->next ) if ( paf_old->type == paf->type ) { paf->duration = UMIN( 1000000, paf->duration + paf_old->duration ); if ( paf->modifier ) paf->modifier = UMIN( 5000, paf->modifier + paf_old->modifier ); else paf->modifier = paf_old->modifier; affect_remove( ch, paf_old ); break; } affect_to_char( ch, paf ); return; } /* * Move a char out of a room. */ void char_from_room( CHAR_DATA *ch ) { OBJ_DATA *obj; if ( !ch ) { bug( "Char_from_room: NULL char.", 0 ); return; } if ( !ch->in_room ) { bug( "Char_from_room: NULL room: %s", ch->name ); return; } if ( !IS_NPC(ch) ) --ch->in_room->area->nplayer; if ( ( obj = get_eq_char( ch, WEAR_LIGHT ) ) != NULL && obj->item_type == ITEM_LIGHT && obj->value[2] != 0 && ch->in_room->light > 0 ) --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 ( !IS_NPC(ch) && get_timer( ch, TIMER_SHOVEDRAG ) > 0 ) remove_timer( ch, TIMER_SHOVEDRAG ); return; } /* * Move a char into a room. */ void char_to_room( CHAR_DATA *ch, ROOM_INDEX_DATA *pRoomIndex ) { OBJ_DATA *obj; if ( !ch ) { bug( "Char_to_room: NULL ch!", 0 ); return; } if ( !pRoomIndex ) { char buf[MAX_STRING_LENGTH]; sprintf( buf, "Char_to_room: %s -> NULL room! Putting char in limbo (%d)", ch->name, ROOM_VNUM_LIMBO ); bug( buf, 0 ); /* This used to just return, but there was a problem with crashing and I saw no reason not to just put the char in limbo. -Narn */ pRoomIndex = get_room_index( ROOM_VNUM_LIMBO ); } ch->in_room = pRoomIndex; LINK( ch, pRoomIndex->first_person, pRoomIndex->last_person, next_in_room, prev_in_room ); if ( !IS_NPC(ch) ) if ( ++ch->in_room->area->nplayer > ch->in_room->area->max_players ) ch->in_room->area->max_players = ch->in_room->area->nplayer; if ( ( obj = get_eq_char( ch, WEAR_LIGHT ) ) != NULL && obj->item_type == ITEM_LIGHT && obj->value[2] != 0 ) ++ch->in_room->light; if ( !IS_NPC(ch) && xIS_SET(ch->in_room->room_flags, ROOM_SAFE) && get_timer(ch, TIMER_SHOVEDRAG) <= 0 ) add_timer( ch, TIMER_SHOVEDRAG, 10, NULL, 0 ); /*-30 Seconds-*/ return; } /* * Give an obj to a char. */ OBJ_DATA *obj_to_char( OBJ_DATA *obj, CHAR_DATA *ch ) { OBJ_DATA *otmp; OBJ_DATA *oret = obj; bool skipgroup, grouped; int oweight = get_obj_weight( obj ); int onum = get_obj_number( obj ); int wear_loc = obj->wear_loc; int extra_flags = obj->extra_flags; skipgroup = FALSE; grouped = FALSE; if (IS_OBJ_STAT( obj, ITEM_PROTOTYPE ) ) { if (!IS_IMMORTAL( ch ) && (IS_NPC(ch) && !IS_SET(ch->act, ACT_PROTOTYPE)) ) return obj_to_room( obj, ch->in_room ); } if ( loading_char == ch ) { int x,y; for ( x = 0; x < MAX_WEAR; x++ ) for ( y = 0; y < MAX_LAYERS; y++ ) if ( save_equipment[x][y] == obj ) { skipgroup = TRUE; break; } } if ( !skipgroup ) for ( otmp = ch->first_carrying; otmp; otmp = otmp->next_content ) if ( (oret=group_object( otmp, obj )) == otmp ) { grouped = TRUE; break; } if ( !grouped ) { LINK( obj, ch->first_carrying, ch->last_carrying, next_content, prev_content ); obj->carried_by = ch; obj->in_room = NULL; obj->in_obj = NULL; } if (wear_loc == WEAR_NONE) { ch->carry_number += onum; ch->carry_weight += oweight; } else if ( !IS_SET(extra_flags, ITEM_MAGIC) ) ch->carry_weight += oweight; return (oret ? oret : obj); } /* * Take an obj from its character. */ void obj_from_char( OBJ_DATA *obj ) { CHAR_DATA *ch; if ( ( ch = obj->carried_by ) == NULL ) { bug( "Obj_from_char: null ch.", 0 ); return; } if ( obj->wear_loc != WEAR_NONE ) unequip_char( ch, obj ); /* obj may drop during unequip... */ if ( !obj->carried_by ) return; UNLINK( obj, ch->first_carrying, ch->last_carrying, next_content, prev_content ); if ( IS_OBJ_STAT( obj, ITEM_COVERING ) && obj->first_content ) empty_obj( obj, NULL, NULL ); obj->in_room = NULL; obj->carried_by = 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_SHIELD: 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: return obj->value[0]; case WEAR_EYES: return obj->value[0]; } return 0; } /* * Find a piece of eq on a character. * Will pick the top layer if clothing is layered. -Thoric */ OBJ_DATA *get_eq_char( CHAR_DATA *ch, int iWear ) { OBJ_DATA *obj, *maxobj = NULL; for ( obj = ch->first_carrying; obj; obj = obj->next_content ) if ( obj->wear_loc == iWear ) { if ( !obj->pIndexData->layers ) return obj; else if ( !maxobj || obj->pIndexData->layers > maxobj->pIndexData->layers ) maxobj = obj; } return maxobj; } /* * Equip a char with an obj. */ void equip_char( CHAR_DATA *ch, OBJ_DATA *obj, int iWear ) { AFFECT_DATA *paf; OBJ_DATA *otmp; if ( (otmp=get_eq_char( ch, iWear )) != NULL && (!otmp->pIndexData->layers || !obj->pIndexData->layers) ) { bug( "Equip_char: already equipped (%d).", iWear ); return; } if ( (xIS_SET(ch->bodyparts,BODY_L_HAND) || xIS_SET(ch->bodyparts,BODY_R_HAND)) && ( iWear == WEAR_HANDS || iWear == WEAR_DUAL_WIELD || iWear == WEAR_HOLD || iWear == WEAR_WIELD ) ) { send_to_char( "It hurts too much!\n\r", ch); return; } separate_obj(obj); /* just in case */ if ( ( IS_OBJ_STAT(obj, ITEM_ANTI_EVIL) && IS_EVIL(ch) ) || ( IS_OBJ_STAT(obj, ITEM_ANTI_GOOD) && IS_GOOD(ch) ) || ( IS_OBJ_STAT(obj, ITEM_ANTI_NEUTRAL) && IS_NEUTRAL(ch) ) ) { /* * Thanks to Morgenes for the bug fix here! */ if ( loading_char != ch ) { act( AT_MAGIC, "You are zapped by $p and drop it.", ch, obj, NULL, TO_CHAR ); act( AT_MAGIC, "$n is zapped by $p and drops it.", ch, obj, NULL, TO_ROOM ); } if ( obj->carried_by ) obj_from_char( obj ); obj_to_room( obj, ch->in_room ); oprog_zap_trigger( ch, obj); if ( IS_SET(sysdata.save_flags, SV_ZAPDROP) && !char_died(ch) ) save_char_obj( ch ); return; } ch->armor -= apply_ac( obj, iWear ); obj->wear_loc = iWear; ch->carry_number -= get_obj_number( obj ); if ( IS_SET( obj->extra_flags, ITEM_MAGIC ) ) ch->carry_weight -= get_obj_weight( obj ); for ( paf = obj->pIndexData->first_affect; paf; paf = paf->next ) affect_modify( ch, paf, TRUE ); for ( paf = obj->first_affect; paf; paf = paf->next ) affect_modify( ch, paf, TRUE ); if ( obj->item_type == ITEM_LIGHT && obj->value[2] != 0 && ch->in_room ) ++ch->in_room->light; 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 ) { bug( "Unequip_char: already unequipped.", 0 ); return; } ch->carry_number += get_obj_number( obj ); if ( IS_SET( obj->extra_flags, ITEM_MAGIC ) ) ch->carry_weight += get_obj_weight( obj ); ch->armor += apply_ac( obj, obj->wear_loc ); obj->wear_loc = -1; for ( paf = obj->pIndexData->first_affect; paf; paf = paf->next ) affect_modify( ch, paf, FALSE ); if ( obj->carried_by ) for ( paf = obj->first_affect; paf; paf = paf->next ) affect_modify( ch, paf, FALSE ); if ( !obj->carried_by ) return; if ( obj->item_type == ITEM_LIGHT && obj->value[2] != 0 && ch->in_room && ch->in_room->light > 0 ) --ch->in_room->light; 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; obj = obj->next_content ) if ( obj->pIndexData == pObjIndex ) nMatch++; return nMatch; } /* * Move an obj out of a room. */ void write_corpses args( ( CHAR_DATA *ch, char *name ) ); int falling; void obj_from_room( OBJ_DATA *obj ) { ROOM_INDEX_DATA *in_room; if ( ( in_room = obj->in_room ) == NULL ) { bug( "obj_from_room: NULL.", 0 ); return; } UNLINK( obj, in_room->first_content, in_room->last_content, next_content, prev_content ); if ( IS_OBJ_STAT( obj, ITEM_COVERING ) && obj->first_content ) empty_obj( obj, NULL, obj->in_room ); if (obj->item_type == ITEM_FIRE) obj->in_room->light -= obj->count; obj->carried_by = NULL; obj->in_obj = NULL; obj->in_room = NULL; if ( obj->pIndexData->vnum == OBJ_VNUM_CORPSE_PC && falling == 0 ) write_corpses( NULL, obj->short_descr+14 ); return; } /* * Move an obj into a room. */ OBJ_DATA *obj_to_room( OBJ_DATA *obj, ROOM_INDEX_DATA *pRoomIndex ) { OBJ_DATA *otmp, *oret; sh_int count = obj->count; sh_int item_type = obj->item_type; if ( pRoomIndex->first_content ) for ( otmp = pRoomIndex->first_content; otmp; otmp = otmp->next_content ) if ( (oret=group_object( otmp, obj )) == otmp ) { if (item_type == ITEM_FIRE) pRoomIndex->light += count; return oret; } LINK( obj, pRoomIndex->first_content, pRoomIndex->last_content, next_content, prev_content ); obj->in_room = pRoomIndex; obj->carried_by = NULL; obj->in_obj = NULL; if (item_type == ITEM_FIRE) pRoomIndex->light += count; falling++; obj_fall( obj, FALSE ); falling--; if ( obj->pIndexData->vnum == OBJ_VNUM_CORPSE_PC && falling == 0 ) write_corpses( NULL, obj->short_descr+14 ); return obj; } /* * Move an object into an object. */ OBJ_DATA *obj_to_obj( OBJ_DATA *obj, OBJ_DATA *obj_to ) { OBJ_DATA *otmp, *oret; if ( obj == obj_to ) { bug( "Obj_to_obj: trying to put object inside itself: vnum %d", obj->pIndexData->vnum ); return obj; } /* Big carry_weight bug fix here by Thoric */ if ( obj->carried_by != obj_to->carried_by ) { if ( obj->carried_by ) obj->carried_by->carry_weight -= get_obj_weight( obj ); if ( obj_to->carried_by ) obj_to->carried_by->carry_weight += get_obj_weight( obj ); } for ( otmp = obj_to->first_content; otmp; otmp = otmp->next_content ) if ( (oret=group_object( otmp, obj )) == otmp ) return oret; LINK( obj, obj_to->first_content, obj_to->last_content, next_content, prev_content ); obj->in_obj = obj_to; obj->in_room = NULL; obj->carried_by = NULL; return obj; } /* * 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 ) { bug( "Obj_from_obj: null obj_from.", 0 ); return; } UNLINK( obj, obj_from->first_content, obj_from->last_content, next_content, prev_content ); if ( IS_OBJ_STAT( obj, ITEM_COVERING ) && obj->first_content ) empty_obj( obj, obj->in_obj, NULL ); obj->in_obj = NULL; obj->in_room = NULL; obj->carried_by = NULL; for ( ; obj_from; obj_from = obj_from->in_obj ) if ( obj_from->carried_by ) obj_from->carried_by->carry_weight -= get_obj_weight( obj ); return; } /* * Extract an obj from the world. */ void extract_obj( OBJ_DATA *obj ) { OBJ_DATA *obj_content; REL_DATA *RQueue, *rq_next; if ( !obj ) { bug( "extract_obj: !obj" ); return; } if ( obj_extracted(obj) ) { bug( "extract_obj: obj %d already extracted!", obj->pIndexData->vnum ); return; } if ( obj->carried_by ) obj_from_char( obj ); else if ( obj->in_room ) obj_from_room( obj ); else if ( obj->in_obj ) obj_from_obj( obj ); while ( ( obj_content = obj->last_content ) != NULL ) extract_obj( obj_content ); { AFFECT_DATA *paf; AFFECT_DATA *paf_next; for ( paf = obj->first_affect; paf; paf = paf_next ) { paf_next = paf->next; DISPOSE( paf ); } obj->first_affect = obj->last_affect = NULL; } { EXTRA_DESCR_DATA *ed; EXTRA_DESCR_DATA *ed_next; for ( ed = obj->first_extradesc; ed; ed = ed_next ) { ed_next = ed->next; STRFREE( ed->description ); STRFREE( ed->keyword ); DISPOSE( ed ); } obj->first_extradesc = obj->last_extradesc = NULL; } if ( obj == gobj_prev ) gobj_prev = obj->prev; for ( RQueue = first_relation; RQueue; RQueue = rq_next ) { rq_next = RQueue->next; if ( RQueue->Type == relOSET_ON ) { if ( obj == RQueue->Subject ) ( ( CHAR_DATA * ) RQueue->Actor )->dest_buf = NULL; else continue; UNLINK( RQueue, first_relation, last_relation, next, prev ); DISPOSE( RQueue ); } } UNLINK( obj, first_object, last_object, next, prev ); /* shove onto extraction queue */ queue_extracted_obj( obj ); obj->pIndexData->count -= obj->count; numobjsloaded -= obj->count; --physicalobjects; if ( obj->serial == cur_obj ) { cur_obj_extracted = TRUE; if ( global_objcode == rNONE ) global_objcode = rOBJ_EXTRACTED; } return; } /* * Extract a char from the world. */ void extract_char( CHAR_DATA *ch, bool fPull ) { CHAR_DATA *wch; OBJ_DATA *obj; char buf[MAX_STRING_LENGTH]; ROOM_INDEX_DATA *location; REL_DATA *RQueue, *rq_next; if ( !ch ) { bug( "Extract_char: NULL ch.", 0 ); return; } if ( !ch->in_room ) { bug( "Extract_char: %s in NULL room.", ch->name ? ch->name : "???" ); return; } if ( ch == supermob ) { bug( "Extract_char: ch == supermob!", 0 ); return; } if ( char_died(ch) ) { bug( "extract_char: %s already died!", ch->name ); return; } if ( ch == cur_char ) cur_char_died = TRUE; /* shove onto extraction queue */ queue_extracted_char( ch, fPull ); for ( RQueue = first_relation; RQueue; RQueue = rq_next ) { rq_next = RQueue->next; if ( fPull && RQueue->Type == relMSET_ON ) { if ( ch == RQueue->Subject ) ( ( CHAR_DATA * ) RQueue->Actor )->dest_buf = NULL; else if ( ch != RQueue->Actor ) continue; UNLINK( RQueue, first_relation, last_relation, next, prev ); DISPOSE( RQueue ); } } if ( gch_prev == ch ) gch_prev = ch->prev; if ( fPull) die_follower( ch ); stop_fighting( ch, TRUE ); if ( ch->mount ) { REMOVE_BIT( ch->mount->act, ACT_MOUNTED ); ch->mount = NULL; ch->position = POS_STANDING; } /* * check if this NPC was a mount or a pet */ if ( IS_NPC(ch) ) { for ( wch = first_char; wch; wch = wch->next ) { if ( wch->mount == ch ) { wch->mount = NULL; wch->position = POS_STANDING; if ( wch->in_room == ch->in_room ) { act( AT_SOCIAL, "Your faithful mount, $N collapses beneath you...", wch, NULL, ch, TO_CHAR ); act( AT_SOCIAL, "Sadly you dismount $M for the last time.", wch, NULL, ch, TO_CHAR ); act( AT_PLAIN, "$n sadly dismounts $N for the last time.", wch, NULL, ch, TO_ROOM ); } } if ( wch->pcdata && wch->pcdata->pet == ch ) { wch->pcdata->pet = NULL; if ( wch->in_room == ch->in_room ) act( AT_SOCIAL, "You mourn for the loss of $N.", wch, NULL, ch, TO_CHAR ); if ( IS_SET( ch->act, ACT_PET ) ) REMOVE_BIT( wch->act, PLR_BOUGHT_PET ); } } } REMOVE_BIT( ch->act, ACT_MOUNTED ); while ( (obj = ch->last_carrying) != NULL ) extract_obj(obj); char_from_room(ch); if ( !fPull ) { location = NULL; if ( !location ) location = get_room_index( ROOM_VNUM_ALTAR ); if ( !location ) location = get_room_index( 1 ); char_to_room( ch, location ); /* * Make things a little fancier -Thoric */ if ( ( wch = get_char_room( ch, "healer" ) ) != NULL ) { act( AT_MAGIC, "$n mutters a few incantations, waves $s hands and points $s finger.", wch, NULL, NULL, TO_ROOM ); act( AT_MAGIC, "$n appears from some strange swirling mists!", ch, NULL, NULL, TO_ROOM ); sprintf(buf, "Welcome back to the land of the living, %s", capitalize( ch->name ) ); do_say( wch, buf ); } else act( AT_MAGIC, "$n appears from some strange swirling mists!", ch, NULL, NULL, TO_ROOM ); ch->position = POS_RESTING; return; } if ( IS_NPC(ch) ) { --ch->pIndexData->count; --nummobsloaded; } if ( ch->desc && ch->desc->original ) do_return( ch, "" ); for ( wch = first_char; wch; wch = wch->next ) { if ( wch->reply == ch ) wch->reply = NULL; if( wch->retell == ch ) wch->retell = NULL; } UNLINK( ch, first_char, last_char, next, prev ); if ( ch->desc ) { if ( ch->desc->character != ch ) bug( "Extract_char: char's descriptor points to another char", 0 ); else { ch->desc->character = NULL; close_socket( ch->desc, FALSE ); ch->desc = NULL; } } 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, count, vnum; number = number_argument( argument, arg ); if ( !str_cmp( arg, "self" ) ) return ch; if ( get_trust(ch) >= LEVEL_SAVIOR && is_number( arg ) ) vnum = atoi( arg ); else vnum = -1; count = 0; for ( rch = ch->in_room->first_person; rch; rch = rch->next_in_room ) if ( can_see( ch, rch ) && (nifty_is_name( arg, rch->name ) || (IS_NPC(rch) && vnum == rch->pIndexData->vnum)) ) { if ( number == 0 && !IS_NPC(rch) ) return rch; else if ( ++count == number ) return rch; } if ( vnum != -1 ) return NULL; /* If we didn't find an exact match, run through the list of characters again looking for prefix matching, ie gu == guard. Added by Narn, Sept/96 */ count = 0; for ( rch = ch->in_room->first_person; rch; rch = rch->next_in_room ) { if ( !can_see( ch, rch ) || !nifty_is_name_prefix( arg, rch->name ) ) continue; if ( number == 0 && !IS_NPC(rch) ) return rch; else 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; int number, count, vnum; number = number_argument( argument, arg ); count = 0; if ( !str_cmp( arg, "self" ) ) return ch; /* * Allow reference by vnum for saints+ -Thoric */ if ( get_trust(ch) >= LEVEL_SAVIOR && is_number( arg ) ) vnum = atoi( arg ); else vnum = -1; /* check the room for an exact match */ for ( wch = ch->in_room->first_person; wch; wch = wch->next_in_room ) if ( (nifty_is_name( arg, wch->name ) || (IS_NPC(wch) && vnum == wch->pIndexData->vnum)) && is_wizvis(ch,wch)) { if ( number == 0 && !IS_NPC(wch) ) return wch; else if ( ++count == number ) return wch; } count = 0; /* check the world for an exact match */ for ( wch = first_char; wch; wch = wch->next ) if ( (nifty_is_name( arg, wch->name ) || (IS_NPC(wch) && vnum == wch->pIndexData->vnum)) && is_wizvis(ch,wch) ) { if ( number == 0 && !IS_NPC(wch) ) return wch; else if ( ++count == number ) return wch; } /* bail out if looking for a vnum match */ if ( vnum != -1 ) return NULL; /* * If we didn't find an exact match, check the room for * for a prefix match, ie gu == guard. * Added by Narn, Sept/96 */ count = 0; for ( wch = ch->in_room->first_person; wch; wch = wch->next_in_room ) { if ( !nifty_is_name_prefix( arg, wch->name ) ) continue; if ( number == 0 && !IS_NPC(wch) && is_wizvis(ch,wch)) return wch; else if ( ++count == number && is_wizvis(ch, wch) ) return wch; } /* * If we didn't find a prefix match in the room, run through the full list * of characters looking for prefix matching, ie gu == guard. * Added by Narn, Sept/96 */ count = 0; for ( wch = first_char; wch; wch = wch->next ) { if ( !nifty_is_name_prefix( arg, wch->name ) ) continue; if ( number == 0 && !IS_NPC(wch) && is_wizvis(ch, wch) ) return wch; else if ( ++count == number && is_wizvis(ch, wch) ) return wch; } return NULL; } /* * Find some object with a given index data. * Used by area-reset 'P', 'T' and 'H' commands. */ OBJ_DATA *get_obj_type( OBJ_INDEX_DATA *pObjIndex ) { OBJ_DATA *obj; for ( obj = last_object; obj; obj = obj->prev ) if ( obj->pIndexData == pObjIndex ) return obj; return NULL; } /* * Find an obj in a list. */ 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; obj = obj->next_content ) if ( can_see_obj( ch, obj ) && nifty_is_name( arg, obj->name ) ) if ( (count += obj->count) >= number ) return obj; /* If we didn't find an exact match, run through the list of objects again looking for prefix matching, ie swo == sword. Added by Narn, Sept/96 */ count = 0; for ( obj = list; obj; obj = obj->next_content ) if ( can_see_obj( ch, obj ) && nifty_is_name_prefix( arg, obj->name ) ) if ( (count += obj->count) >= number ) return obj; return NULL; } /* * Find an obj in a list...going the other way -Thoric */ OBJ_DATA *get_obj_list_rev( 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; obj = obj->prev_content ) if ( can_see_obj( ch, obj ) && nifty_is_name( arg, obj->name ) ) if ( (count += obj->count) >= number ) return obj; /* If we didn't find an exact match, run through the list of objects again looking for prefix matching, ie swo == sword. Added by Narn, Sept/96 */ count = 0; for ( obj = list; obj; obj = obj->prev_content ) if ( can_see_obj( ch, obj ) && nifty_is_name_prefix( arg, obj->name ) ) if ( (count += obj->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, count, vnum; number = number_argument( argument, arg ); if ( get_trust(ch) >= LEVEL_SAVIOR && is_number( arg ) ) vnum = atoi( arg ); else vnum = -1; count = 0; for ( obj = ch->last_carrying; obj; obj = obj->prev_content ) if ( obj->wear_loc == WEAR_NONE && can_see_obj( ch, obj ) && (nifty_is_name( arg, obj->name ) || obj->pIndexData->vnum == vnum) ) if ( (count += obj->count) >= number ) return obj; if ( vnum != -1 ) return NULL; /* If we didn't find an exact match, run through the list of objects again looking for prefix matching, ie swo == sword. Added by Narn, Sept/96 */ count = 0; for ( obj = ch->last_carrying; obj; obj = obj->prev_content ) if ( obj->wear_loc == WEAR_NONE && can_see_obj( ch, obj ) && nifty_is_name_prefix( arg, obj->name ) ) if ( (count += obj->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, count, vnum; if ( !ch ) { bug( "get_obj_wear: null ch" ); } number = number_argument( argument, arg ); if ( get_trust(ch) >= LEVEL_SAVIOR && is_number( arg ) ) vnum = atoi( arg ); else vnum = -1; count = 0; for ( obj = ch->last_carrying; obj; obj = obj->prev_content ) if ( obj->wear_loc != WEAR_NONE && can_see_obj( ch, obj ) && (nifty_is_name( arg, obj->name ) || obj->pIndexData->vnum == vnum) ) if ( ++count == number ) return obj; if ( vnum != -1 ) return NULL; /* If we didn't find an exact match, run through the list of objects again looking for prefix matching, ie swo == sword. Added by Narn, Sept/96 */ count = 0; for ( obj = ch->last_carrying; obj; obj = obj->prev_content ) if ( obj->wear_loc != WEAR_NONE && can_see_obj( ch, obj ) && nifty_is_name_prefix( 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; if ( !ch || !ch->in_room ) return NULL; obj = get_obj_list_rev( ch, argument, ch->in_room->last_content ); if ( obj ) 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, count, vnum; if (!ch) return NULL; if ( ( obj = get_obj_here( ch, argument ) ) != NULL ) return obj; number = number_argument( argument, arg ); /* * Allow reference by vnum for saints+ -Thoric */ if ( get_trust(ch) >= LEVEL_SAVIOR && is_number( arg ) ) vnum = atoi( arg ); else vnum = -1; count = 0; for ( obj = first_object; obj; obj = obj->next ) if ( can_see_obj( ch, obj ) && (nifty_is_name( arg, obj->name ) || vnum == obj->pIndexData->vnum) ) if ( (count += obj->count) >= number ) return obj; /* bail out if looking for a vnum */ if ( vnum != -1 ) return NULL; /* If we didn't find an exact match, run through the list of objects again looking for prefix matching, ie swo == sword. Added by Narn, Sept/96 */ count = 0; for ( obj = first_object; obj; obj = obj->next ) if ( can_see_obj( ch, obj ) && nifty_is_name_prefix( arg, obj->name ) ) if ( (count += obj->count) >= number ) return obj; return NULL; } /* * How mental state could affect finding an object -Thoric * Used by get/drop/put/quaff/recite/etc * Increasingly freaky based on mental state and drunkeness */ bool ms_find_obj( CHAR_DATA *ch ) { int ms = ch->mental_state; int drunk = IS_NPC(ch) ? 0 : ch->pcdata->condition[COND_DRUNK]; char *t; /* * we're going to be nice and let nothing weird happen unless * you're a tad messed up */ drunk = UMAX( 1, drunk ); if ( abs(ms) + (drunk/3) < 30 ) return FALSE; if ( (number_percent() + (ms < 0 ? 15 : 5))> abs(ms)/2 + drunk/4 ) return FALSE; if ( ms > 15 ) /* range 1 to 20 */ switch( number_range( UMAX(1, (ms/5-15)), (ms+4) / 5 ) ) { default: case 1: t="As you reach for it, you forgot what it was...\n\r"; break; case 2: t="As you reach for it, something inside stops you...\n\r"; break; case 3: t="As you reach for it, it seems to move out of the way...\n\r"; break; case 4: t="You grab frantically for it, but can't seem to get a hold of it...\n\r"; break; case 5: t="It disappears as soon as you touch it!\n\r"; break; case 6: t="You would if it would stay still!\n\r"; break; case 7: t="Whoa! It's covered in blood! Ack! Ick!\n\r"; break; case 8: t="Wow... trails!\n\r"; break; case 9: t="You reach for it, then notice the back of your hand is growing something!\n\r"; break; case 10: t="As you grasp it, it shatters into tiny shards which bite into your flesh!\n\r"; break; case 11: t="What about that huge dragon flying over your head?!?!?\n\r"; break; case 12: t="You stratch yourself instead...\n\r"; break; case 13: t="You hold the universe in the palm of your hand!\n\r"; break; case 14: t="You're too scared.\n\r"; break; case 15: t="Your mother smacks your hand... 'NO!'\n\r"; break; case 16: t="Your hand grasps the worse pile of revoltingness than you could ever imagine!\n\r"; break; case 17: t="You stop reaching for it as it screams out at you in pain!\n\r"; break; case 18: t="What about the millions of burrow-maggots feasting on your arm?!?!\n\r"; break; case 19: t="That doesn't matter anymore... you've found the true answer to everything!\n\r"; break; case 20: t="A supreme entity has no need for that.\n\r"; break; } else { int sub = URANGE(1, abs(ms)/2 + drunk, 60); switch( number_range( 1, sub/10 ) ) { default: case 1: t="In just a second...\n\r"; break; case 2: t="You can't find that...\n\r"; break; case 3: t="It's just beyond your grasp...\n\r"; break; case 4: t="...but it's under a pile of other stuff...\n\r"; break; case 5: t="You go to reach for it, but pick your nose instead.\n\r"; break; case 6: t="Which one?!? I see two... no three...\n\r"; break; } } send_to_char( t, ch ); return TRUE; } /* * Generic get obj function that supports optional containers. -Thoric * currently only used for "eat" and "quaff". */ OBJ_DATA *find_obj( CHAR_DATA *ch, char *argument, bool carryonly ) { char arg1[MAX_INPUT_LENGTH]; char arg2[MAX_INPUT_LENGTH]; OBJ_DATA *obj; argument = one_argument( argument, arg1 ); argument = one_argument( argument, arg2 ); if ( !str_cmp( arg2, "from" ) && argument[0] != '\0' ) argument = one_argument( argument, arg2 ); if ( arg2[0] == '\0' ) { if ( carryonly && ( obj = get_obj_carry( ch, arg1 ) ) == NULL ) { send_to_char( "You do not have that item.\n\r", ch ); return NULL; } else if ( !carryonly && ( obj = get_obj_here( ch, arg1 ) ) == NULL ) { act( AT_PLAIN, "I see no $T here.", ch, NULL, arg1, TO_CHAR ); return NULL; } return obj; } else { OBJ_DATA *container; if ( carryonly && ( container = get_obj_carry( ch, arg2 ) ) == NULL && ( container = get_obj_wear( ch, arg2 ) ) == NULL ) { send_to_char( "You do not have that item.\n\r", ch ); return NULL; } if ( !carryonly && ( container = get_obj_here( ch, arg2 ) ) == NULL ) { act( AT_PLAIN, "I see no $T here.", ch, NULL, arg2, TO_CHAR ); return NULL; } 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 NULL; } 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 $p." : "I see nothing like that in $p.", ch, container, NULL, TO_CHAR ); return obj; } return NULL; } int get_obj_number( OBJ_DATA *obj ) { return obj->count; } /* * Return weight of an object, including weight of contents. */ int get_obj_weight( OBJ_DATA *obj ) { int weight; weight = obj->count * obj->weight; for ( obj = obj->first_content; obj; obj = obj->next_content ) weight += get_obj_weight( obj ); return weight; } /* * True if room is dark. */ bool room_is_dark( ROOM_INDEX_DATA *pRoomIndex ) { if ( !pRoomIndex ) { bug( "room_is_dark: NULL pRoomIndex", 0 ); return TRUE; } if ( pRoomIndex->light > 0 ) return FALSE; if ( xIS_SET(pRoomIndex->room_flags, ROOM_DARK) ) return TRUE; if ( pRoomIndex->sector_type == SECT_INSIDE || pRoomIndex->sector_type == SECT_CITY ) return FALSE; if ( time_info.sunlight == SUN_SET || time_info.sunlight == SUN_DARK ) return TRUE; return FALSE; } /* * If room is "do not disturb" return the pointer to the imm with dnd flag * NULL if room is not "do not disturb". */ CHAR_DATA *room_is_dnd( CHAR_DATA *ch, ROOM_INDEX_DATA *pRoomIndex ) { CHAR_DATA *rch; if ( !pRoomIndex ) { bug( "room_is_dnd: NULL pRoomIndex", 0 ); return NULL; } if ( !xIS_SET(pRoomIndex->room_flags, ROOM_DND) ) return NULL; for ( rch = pRoomIndex->first_person; rch; rch = rch->next_in_room ) { if ( !IS_NPC(rch) && rch->pcdata && IS_IMMORTAL(rch) && IS_SET(rch->pcdata->flags, PCFLAG_DND) && get_trust(ch) < get_trust(rch) && can_see(ch, rch) ) return rch; } return NULL; } /* * True if room is private. */ bool room_is_private( CHAR_DATA *ch , ROOM_INDEX_DATA *pRoomIndex ) { CHAR_DATA *rch; int count; if ( !ch ) { bug( "room_is_private: NULL ch", 0 ); return FALSE; } if ( !pRoomIndex ) { bug( "room_is_private: NULL pRoomIndex", 0 ); return FALSE; } if ( (xIS_SET(pRoomIndex->room_flags, ROOM_PLR_HOME) && ch->pcdata->plr_home != pRoomIndex) ) return TRUE; if ( xIS_SET(pRoomIndex->room_flags, ROOM_HOUSE) ) { HOME_DATA * home; home = home_from_entrance(pRoomIndex->vnum); if ( home && !check_member(ch,home) && home->class <= APARTMENT_HOME ) return TRUE; } count = 0; for ( rch = pRoomIndex->first_person; rch; rch = rch->next_in_room ) count++; if ( xIS_SET(pRoomIndex->room_flags, ROOM_PRIVATE) && count >= 2 ) return TRUE; /* if ( xIS_SET(pRoomIndex->room_flags, ROOM_SOLITARY) && count >= 1 ) return TRUE;*/ return FALSE; } /* * True if char can see victim. */ bool can_see( CHAR_DATA *ch, CHAR_DATA *victim ) { if (!victim) return FALSE; if ( victim->position == POS_FIGHTING || victim->position < POS_SLEEPING ) return TRUE; if ( !ch ) { if ( IS_AFFECTED(victim, AFF_INVISIBLE) || IS_AFFECTED(victim, AFF_HIDE) || IS_SET(victim->act, PLR_WIZINVIS) ) return FALSE; else return TRUE; } if ( ch == victim ) return TRUE; if ( !IS_NPC(victim) && IS_SET(victim->act, PLR_WIZINVIS) && get_trust( ch ) < victim->pcdata->wizinvis ) return FALSE; if ( victim->position == POS_FIGHTING || victim->position < POS_SLEEPING ) return TRUE; if ( victim->position == POS_FIGHTING || victim->position < POS_SLEEPING ) return TRUE; /* SB */ if ( IS_NPC(victim) && IS_SET(victim->act, ACT_MOBINVIS) && get_trust( ch ) < victim->mobinvis ) return FALSE; if ( !IS_IMMORTAL(ch) && !IS_NPC(victim) && !victim->desc && get_timer(victim, TIMER_RECENTFIGHT) > 0 && (!victim->switched || !IS_AFFECTED(victim->switched, AFF_POSSESS)) ) return FALSE; if ( !IS_NPC(ch) && IS_SET(ch->act, PLR_HOLYLIGHT) ) return TRUE; /* The miracle cure for blindness? -- Altrag */ if ( !IS_AFFECTED(ch, AFF_TRUESIGHT) ) { if ( IS_AFFECTED(ch, AFF_BLIND) ) return FALSE; if ( room_is_dark( ch->in_room ) && !IS_AFFECTED(ch, AFF_INFRARED) ) return FALSE; if ( IS_AFFECTED(victim, AFF_HIDE) && !IS_AFFECTED(ch, AFF_DETECT_HIDDEN) && !victim->fighting ) return FALSE; if ( ch->race == RACE_DEFEL && victim->race == RACE_DEFEL ) return TRUE; if ( IS_AFFECTED(victim, AFF_INVISIBLE) && !IS_AFFECTED(ch, AFF_DETECT_INVIS) ) return FALSE; } return TRUE; } /* * True if char can see obj. */ bool can_see_obj( CHAR_DATA *ch, OBJ_DATA *obj ) { if ( !IS_NPC(ch) && IS_SET(ch->act, PLR_HOLYLIGHT) ) return TRUE; if ( IS_OBJ_STAT( obj, ITEM_BURRIED ) ) return FALSE; if ( IS_AFFECTED( ch, AFF_TRUESIGHT ) ) return TRUE; if ( IS_AFFECTED( ch, AFF_BLIND ) ) return FALSE; if ( IS_OBJ_STAT(obj, ITEM_HIDDEN) ) 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) ) return FALSE; if ( IS_OBJ_STAT(obj, ITEM_INVIS) && !IS_AFFECTED(ch, AFF_DETECT_INVIS) ) 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_NODROP) ) return TRUE; if ( !IS_NPC(ch) && get_trust(ch) >= LEVEL_IMMORTAL ) return TRUE; if ( IS_NPC(ch) && ch->pIndexData->vnum == 3 ) return TRUE; return FALSE; } /* * Return ascii name of an item type. */ char *item_type_name( OBJ_DATA *obj ) { if ( obj->item_type < 1 || obj->item_type > MAX_ITEM_TYPE ) { bug( "Item_type_name: unknown type %d.", obj->item_type ); return "(unknown)"; } return o_types[obj->item_type]; } /* * Return ascii name of an affect location. */ char *affect_loc_name( int location ) { switch ( location ) { case APPLY_NONE: return "none"; case APPLY_STR: return "strength"; case APPLY_DEX: return "dexterity"; case APPLY_INT: return "intelligence"; case APPLY_WIS: return "wisdom"; case APPLY_CON: return "constitution"; case APPLY_CHA: return "charisma"; case APPLY_LCK: return "luck"; case APPLY_SEX: return "sex"; case APPLY_LEVEL: return "level"; case APPLY_AGE: return "age"; case APPLY_HIT: return "hp"; case APPLY_MOVE: return "moves"; case APPLY_GOLD: return "gold"; case APPLY_EXP: return "experience"; case APPLY_AC: return "armor class"; case APPLY_HITROLL: return "hit roll"; case APPLY_DAMROLL: return "damage roll"; case APPLY_HEIGHT: return "height"; case APPLY_WEIGHT: return "weight"; case APPLY_AFFECT: return "affected_by"; case APPLY_RESISTANT: return "resistant"; case APPLY_IMMUNE: return "immune"; case APPLY_SUSCEPTIBLE: return "susceptible"; case APPLY_WEAPONSPELL: return "weapon spell"; case APPLY_WEARSPELL: return "wear spell"; case APPLY_REMOVESPELL: return "remove spell"; case APPLY_MENTALSTATE: return "mental state"; case APPLY_EMOTION: return "emotional state"; case APPLY_STRIPSN: return "dispel"; case APPLY_REMOVE: return "remove"; case APPLY_DRUNK: return "drunk"; case APPLY_CONTRACEPTIVE: return "contraceptive"; default: return "Error, contact coder"; } bug( "Affect_location_name: unknown location %d.", location ); return "(unknown)"; } /* * Return ascii name of an affect bit vector. */ char *affect_bit_name( int vector ) { static char buf[512]; buf[0] = '\0'; if ( vector & AFF_BLIND ) strcat( buf, " blind" ); if ( vector & AFF_INVISIBLE ) strcat( buf, " invisible" ); if ( vector & AFF_DETECT_EVIL ) strcat( buf, " detect_evil" ); if ( vector & AFF_DETECT_INVIS ) strcat( buf, " detect_invis" ); if ( vector & AFF_DETECT_MAGIC ) strcat( buf, " detect_magic" ); if ( vector & AFF_DETECT_HIDDEN ) strcat( buf, " detect_hidden" ); if ( vector & AFF_WEAKEN ) strcat( buf, " weaken" ); if ( vector & AFF_SANCTUARY ) strcat( buf, " sanctuary" ); if ( vector & AFF_FAERIE_FIRE ) strcat( buf, " faerie_fire" ); if ( vector & AFF_INFRARED ) strcat( buf, " infrared" ); if ( vector & AFF_CURSE ) strcat( buf, " curse" ); if ( vector & AFF_FLAMING ) strcat( buf, " flaming" ); if ( vector & AFF_POISON ) strcat( buf, " poison" ); if ( vector & AFF_PROTECT ) strcat( buf, " protect" ); if ( vector & AFF_PARALYSIS ) strcat( buf, " paralysis" ); if ( vector & AFF_SLEEP ) strcat( buf, " sleep" ); if ( vector & AFF_SNEAK ) strcat( buf, " sneak" ); if ( vector & AFF_HIDE ) strcat( buf, " hide" ); if ( vector & AFF_CHARM ) strcat( buf, " charm" ); if ( vector & AFF_POSSESS ) strcat( buf, " possess" ); if ( vector & AFF_FLYING ) strcat( buf, " flying" ); if ( vector & AFF_PASS_DOOR ) strcat( buf, " pass_door" ); if ( vector & AFF_FLOATING ) strcat( buf, " floating" ); if ( vector & AFF_TRUESIGHT ) strcat( buf, " true_sight" ); if ( vector & AFF_DETECTTRAPS ) strcat( buf, " detect_traps" ); if ( vector & AFF_SCRYING ) strcat( buf, " scrying" ); if ( vector & AFF_FIRESHIELD ) strcat( buf, " fireshield" ); if ( vector & AFF_SHOCKSHIELD ) strcat( buf, " shockshield" ); if ( vector & AFF_CONTRACEPTION ) strcat( buf, " contraception" ); if ( vector & AFF_ICESHIELD ) strcat( buf, " iceshield" ); if ( vector & AFF_POSSESS ) strcat( buf, " possess" ); if ( vector & AFF_BERSERK ) strcat( buf, " berserk" ); if ( vector & AFF_AQUA_BREATH ) strcat( buf, " aqua_breath" ); return ( buf[0] != '\0' ) ? buf+1 : "none"; } /* * Return ascii name of extra flags vector. */ char *extra_bit_name( int extra_flags ) { static char buf[512]; buf[0] = '\0'; if ( extra_flags & ITEM_GLOW ) strcat( buf, " glow" ); if ( extra_flags & ITEM_HUM ) strcat( buf, " hum" ); if ( extra_flags & ITEM_DARK ) strcat( buf, " dark" ); if ( extra_flags & ITEM_HUTT_SIZE ) strcat( buf, " hutt_size" ); if ( extra_flags & ITEM_CONTRABAND ) strcat( buf, " contraband" ); if ( extra_flags & ITEM_INVIS ) strcat( buf, " invis" ); if ( extra_flags & ITEM_MAGIC ) strcat( buf, " magic" ); if ( extra_flags & ITEM_NODROP ) strcat( buf, " nodrop" ); if ( extra_flags & ITEM_BLESS ) strcat( buf, " bless" ); if ( extra_flags & ITEM_ANTI_GOOD ) strcat( buf, " anti-good" ); if ( extra_flags & ITEM_ANTI_EVIL ) strcat( buf, " anti-evil" ); if ( extra_flags & ITEM_ANTI_NEUTRAL ) strcat( buf, " anti-neutral" ); if ( extra_flags & ITEM_NOREMOVE ) strcat( buf, " noremove" ); if ( extra_flags & ITEM_INVENTORY ) strcat( buf, " inventory" ); if ( extra_flags & ITEM_DEATHROT ) strcat( buf, " deathrot" ); if ( extra_flags & ITEM_ANTI_SOLDIER ) strcat( buf, " anti-soldier" ); if ( extra_flags & ITEM_ANTI_THIEF ) strcat( buf, " anti-thief" ); if ( extra_flags & ITEM_ANTI_HUNTER ) strcat( buf, " anti-hunter" ); if ( extra_flags & ITEM_ANTI_JEDI ) strcat( buf, " anti-jedi" ); if ( extra_flags & ITEM_ANTI_SITH ) strcat( buf, " anti-sith" ); if ( extra_flags & ITEM_ANTI_PILOT ) strcat( buf, " anti-pilot" ); if ( extra_flags & ITEM_SMALL_SIZE ) strcat( buf, " small_size" ); if ( extra_flags & ITEM_LARGE_SIZE ) strcat( buf, " large_size" ); if ( extra_flags & ITEM_DONATION ) strcat( buf, " donation" ); if ( extra_flags & ITEM_CLANOBJECT ) strcat( buf, " clan" ); if ( extra_flags & ITEM_ANTI_CITIZEN ) strcat( buf, " anti-citizen" ); if ( extra_flags & ITEM_PROTOTYPE ) strcat( buf, " prototype" ); if ( extra_flags & ITEM_HUMAN_SIZE ) strcat( buf, " human_size" ); return ( buf[0] != '\0' ) ? buf+1 : "none"; } /* * Return ascii name of magic flags vector. - Scryn */ char *magic_bit_name( int magic_flags ) { static char buf[512]; buf[0] = '\0'; if ( magic_flags & ITEM_RETURNING ) strcat( buf, " returning" ); return ( buf[0] != '\0' ) ? buf+1 : "none"; } char *cyber_bit_name(int cyber_flags) { static char buf[512]; buf[0] = '\0'; if (cyber_flags & CYBER_COMM ) strcat(buf, " internal comm unit\n\r"); if (cyber_flags & CYBER_EYES ) strcat(buf, " infrared eyes\n\r"); if (cyber_flags & CYBER_LEGS ) strcat(buf, " leg enhancements\n\r"); if (cyber_flags & CYBER_CHEST ) strcat(buf, " chest plating\n\r"); if (cyber_flags & CYBER_REFLEXES ) strcat(buf, " augmented reflexes\n\r"); if (cyber_flags & CYBER_MIND ) strcat(buf, " internal computer\n\r"); if (cyber_flags & CYBER_STRENGTH ) strcat(buf, " augmented muscles\n\r"); if (cyber_flags & CYBER_REACTOR ) strcat(buf, " Internal Reactor\n\r"); if (cyber_flags & CYBER_STERILE ) strcat(buf, " Cyber Sterialation\n\r"); return ( buf[0] != '\0' ) ? buf+1 : "none"; } /* * Return a pointer to the first object of a certain type found that * a player is carrying/wearing */ OBJ_DATA *get_objtype( CHAR_DATA *ch, sh_int type ) { OBJ_DATA *obj; for ( obj = ch->first_carrying; obj; obj = obj->next_content ) if ( obj->item_type == type ) return obj; return NULL; } /* * Remove an exit from a room -Thoric */ void extract_exit( ROOM_INDEX_DATA *room, EXIT_DATA *pexit ) { UNLINK( pexit, room->first_exit, room->last_exit, next, prev ); if ( pexit->rexit ) pexit->rexit->rexit = NULL; STRFREE( pexit->keyword ); STRFREE( pexit->description ); DISPOSE( pexit ); } /* * Remove a room */ void extract_room( ROOM_INDEX_DATA *room ) { bug( "extract_room: not implemented", 0 ); /* (remove room from hash table) clean_room( room ) DISPOSE( room ); */ return; } /* * clean out a room (leave list pointers intact ) -Thoric */ void clean_room( ROOM_INDEX_DATA *room ) { EXTRA_DESCR_DATA *ed, *ed_next; EXIT_DATA *pexit, *pexit_next; STRFREE( room->description ); STRFREE( room->name ); for ( ed = room->first_extradesc; ed; ed = ed_next ) { ed_next = ed->next; STRFREE( ed->description ); STRFREE( ed->keyword ); DISPOSE( ed ); top_ed--; } room->first_extradesc = NULL; room->last_extradesc = NULL; for ( pexit = room->first_exit; pexit; pexit = pexit_next ) { pexit_next = pexit->next; STRFREE( pexit->keyword ); STRFREE( pexit->description ); DISPOSE( pexit ); top_exit--; } room->first_exit = NULL; room->last_exit = NULL; xCLEAR_BITS(room->room_flags); room->sector_type = 0; room->light = 0; } /* * clean out an object (index) (leave list pointers intact ) -Thoric */ void clean_obj( OBJ_INDEX_DATA *obj ) { AFFECT_DATA *paf; AFFECT_DATA *paf_next; EXTRA_DESCR_DATA *ed; EXTRA_DESCR_DATA *ed_next; STRFREE( obj->name ); STRFREE( obj->short_descr ); STRFREE( obj->description ); STRFREE( obj->action_desc ); obj->item_type = 0; obj->extra_flags = 0; obj->wear_flags = 0; obj->count = 0; obj->weight = 0; obj->cost = 0; obj->value[0] = 0; obj->value[1] = 0; obj->value[2] = 0; obj->value[3] = 0; for ( paf = obj->first_affect; paf; paf = paf_next ) { paf_next = paf->next; DISPOSE( paf ); top_affect--; } obj->first_affect = NULL; obj->last_affect = NULL; for ( ed = obj->first_extradesc; ed; ed = ed_next ) { ed_next = ed->next; STRFREE( ed->description ); STRFREE( ed->keyword ); DISPOSE( ed ); top_ed--; } obj->first_extradesc = NULL; obj->last_extradesc = NULL; } /* * clean out a mobile (index) (leave list pointers intact ) -Thoric */ void clean_mob( MOB_INDEX_DATA *mob ) { MPROG_DATA *mprog, *mprog_next; STRFREE( mob->player_name ); STRFREE( mob->short_descr ); STRFREE( mob->long_descr ); STRFREE( mob->description ); mob->spec_fun = NULL; mob->spec_2 = NULL; mob->pShop = NULL; mob->rShop = NULL; mob->progtypes = 0; for ( mprog = mob->mudprogs; mprog; mprog = mprog_next ) { mprog_next = mprog->next; STRFREE( mprog->arglist ); STRFREE( mprog->comlist ); DISPOSE( mprog ); } mob->count = 0; mob->killed = 0; mob->sex = 0; mob->level = 0; mob->act = 0; mob->affected_by = 0; mob->alignment = 0; mob->mobthac0 = 0; mob->ac = 0; mob->hitnodice = 0; mob->hitsizedice = 0; mob->hitplus = 0; mob->damnodice = 0; mob->damsizedice = 0; mob->damplus = 0; mob->gold = 0; mob->position = 0; mob->defposition = 0; mob->height = 0; mob->weight = 0; } extern int top_reset; /* * Remove all resets from an area -Thoric */ void clean_resets( AREA_DATA *tarea ) { RESET_DATA *pReset, *pReset_next; for ( pReset = tarea->first_reset; pReset; pReset = pReset_next ) { pReset_next = pReset->next; DISPOSE( pReset ); --top_reset; } tarea->first_reset = NULL; tarea->last_reset = NULL; } /* no more silliness */ void name_stamp_stats( CHAR_DATA *ch ) { } /* * "Fix" a character's stats -Thoric */ void fix_char( CHAR_DATA *ch ) { AFFECT_DATA *aff; OBJ_DATA *carry[MAX_LEVEL*200]; OBJ_DATA *obj; int x, ncarry; de_equip_char( ch ); ncarry = 0; while ( (obj=ch->first_carrying) != NULL ) { carry[ncarry++] = obj; obj_from_char( obj ); } for ( aff = ch->first_affect; aff; aff = aff->next ) affect_modify( ch, aff, FALSE ); ch->affected_by = race_table[ch->race]->affected; ch->mental_state = 0; ch->hit = UMAX( 1, ch->hit ); ch->mana = UMAX( 1, ch->mana ); ch->move = UMAX( 1, ch->move ); ch->armor = 100; ch->mod_str = 0; ch->mod_dex = 0; ch->mod_wis = 0; ch->mod_int = 0; ch->mod_con = 0; ch->mod_cha = 0; ch->mod_lck = 0; ch->damroll = 0; ch->hitroll = 0; ch->alignment = URANGE( -1000, ch->alignment, 1000 ); ch->saving_breath = 0; ch->saving_wand = 0; ch->saving_para_petri = 0; ch->saving_spell_staff = 0; ch->saving_poison_death = 0; ch->carry_weight = 0; ch->carry_number = 0; ch->speaks = 0; for ( aff = ch->first_affect; aff; aff = aff->next ) affect_modify( ch, aff, TRUE ); for ( x = 0; x < ncarry; x++ ) obj_to_char( carry[x], ch ); re_equip_char( ch ); } /* * Show an affect verbosely to a character -Thoric */ void showaffect( CHAR_DATA *ch, AFFECT_DATA *paf ) { char buf[MAX_STRING_LENGTH]; int x; if ( !paf ) { bug( "showaffect: NULL paf", 0 ); return; } if ( paf->location != APPLY_NONE && paf->modifier != 0 ) { switch( paf->location ) { default: sprintf( buf, "Affects %s by %d.\n\r", affect_loc_name( paf->location ), paf->modifier ); break; case APPLY_AFFECT: sprintf( buf, "Affects %s by", affect_loc_name( paf->location ) ); for ( x = 0; x < 32 ; x++ ) if ( IS_SET( paf->modifier, 1 << x ) ) { strcat( buf, " " ); strcat( buf, a_flags[x] ); } strcat( buf, "\n\r" ); break; case APPLY_WEAPONSPELL: case APPLY_WEARSPELL: case APPLY_REMOVESPELL: sprintf( buf, "Casts spell '%s'\n\r", IS_VALID_SN(paf->modifier) ? skill_table[paf->modifier]->name : "unknown" ); break; case APPLY_RESISTANT: case APPLY_IMMUNE: case APPLY_SUSCEPTIBLE: sprintf( buf, "Affects %s by", affect_loc_name( paf->location ) ); for ( x = 0; x < 32 ; x++ ) if ( IS_SET( paf->modifier, 1 << x ) ) { strcat( buf, " " ); strcat( buf, ris_flags[x] ); } strcat( buf, "\n\r" ); break; } send_to_char( buf, ch ); } } /* * Set the current global object to obj -Thoric */ void set_cur_obj( OBJ_DATA *obj ) { cur_obj = obj->serial; cur_obj_extracted = FALSE; global_objcode = rNONE; } /* * Check the recently extracted object queue for obj -Thoric */ bool obj_extracted( OBJ_DATA *obj ) { OBJ_DATA *cod; if ( !obj ) return TRUE; if ( obj->serial == cur_obj && cur_obj_extracted ) return TRUE; for (cod = extracted_obj_queue; cod; cod = cod->next ) if ( obj == cod ) return TRUE; return FALSE; } /* * Stick obj onto extraction queue */ void queue_extracted_obj( OBJ_DATA *obj ) { ++cur_qobjs; obj->next = extracted_obj_queue; extracted_obj_queue = obj; } /* * Clean out the extracted object queue */ void clean_obj_queue() { OBJ_DATA *obj; while ( extracted_obj_queue ) { obj = extracted_obj_queue; extracted_obj_queue = extracted_obj_queue->next; STRFREE( obj->name ); STRFREE( obj->description ); STRFREE( obj->short_descr ); STRFREE( obj->action_desc ); DISPOSE( obj ); --cur_qobjs; } } /* * Set the current global character to ch -Thoric */ void set_cur_char( CHAR_DATA *ch ) { cur_char = ch; cur_char_died = FALSE; cur_room = ch->in_room; global_retcode = rNONE; } /* * Check to see if ch died recently -Thoric */ bool char_died( CHAR_DATA *ch ) { EXTRACT_CHAR_DATA *ccd; if ( ch == cur_char && cur_char_died ) return TRUE; for (ccd = extracted_char_queue; ccd; ccd = ccd->next ) if ( ccd->ch == ch ) return TRUE; return FALSE; } /* * Add ch to the queue of recently extracted characters -Thoric */ void queue_extracted_char( CHAR_DATA *ch, bool extract ) { EXTRACT_CHAR_DATA *ccd; if ( !ch ) { bug( "queue_extracted char: ch = NULL", 0 ); return; } CREATE( ccd, EXTRACT_CHAR_DATA, 1 ); ccd->ch = ch; ccd->room = ch->in_room; ccd->extract = extract; if ( ch == cur_char ) ccd->retcode = global_retcode; else ccd->retcode = rCHAR_DIED; ccd->next = extracted_char_queue; extracted_char_queue = ccd; cur_qchars++; } /* * clean out the extracted character queue */ void clean_char_queue() { EXTRACT_CHAR_DATA *ccd; for ( ccd = extracted_char_queue; ccd; ccd = extracted_char_queue ) { extracted_char_queue = ccd->next; if ( ccd->extract ) free_char( ccd->ch ); DISPOSE( ccd ); --cur_qchars; } } /* * Add a timer to ch -Thoric * Support for "call back" time delayed commands */ void add_timer( CHAR_DATA *ch, sh_int type, sh_int count, DO_FUN *fun, int value ) { TIMER *timer; for ( timer = ch->first_timer; timer; timer = timer->next ) if ( timer->type == type ) { timer->count = count; timer->do_fun = fun; timer->value = value; break; } if ( !timer ) { CREATE( timer, TIMER, 1 ); timer->count = count; timer->type = type; timer->do_fun = fun; timer->value = value; LINK( timer, ch->first_timer, ch->last_timer, next, prev ); } } TIMER *get_timerptr( CHAR_DATA *ch, sh_int type ) { TIMER *timer; for ( timer = ch->first_timer; timer; timer = timer->next ) if ( timer->type == type ) return timer; return NULL; } sh_int get_timer( CHAR_DATA *ch, sh_int type ) { TIMER *timer; if ( (timer = get_timerptr( ch, type )) != NULL ) return timer->count; else return 0; } void extract_timer( CHAR_DATA *ch, TIMER *timer ) { if ( !timer ) { bug( "extract_timer: NULL timer", 0 ); return; } UNLINK( timer, ch->first_timer, ch->last_timer, next, prev ); DISPOSE( timer ); return; } void remove_timer( CHAR_DATA *ch, sh_int type ) { TIMER *timer; for ( timer = ch->first_timer; timer; timer = timer->next ) if ( timer->type == type ) break; if ( timer ) extract_timer( ch, timer ); } bool in_soft_range( CHAR_DATA *ch, AREA_DATA *tarea ) { return TRUE; if ( IS_IMMORTAL(ch) ) return TRUE; else if ( IS_NPC(ch) ) return TRUE; else if ( ch->top_level >= tarea->low_soft_range || ch->top_level <= tarea->hi_soft_range ) return TRUE; else return FALSE; } bool in_hard_range( CHAR_DATA *ch, AREA_DATA *tarea ) { return TRUE; if ( IS_IMMORTAL(ch) ) return TRUE; else if ( IS_NPC(ch) ) return TRUE; else if ( ch->top_level >= tarea->low_hard_range && ch->top_level <= tarea->hi_hard_range ) return TRUE; else return FALSE; } /* * Scryn, standard luck check 2/2/96 */ bool chance( CHAR_DATA *ch, sh_int percent ) { sh_int ms; if (!ch) { bug("Chance: null ch!", 0); return FALSE; } /* Mental state bonus/penalty: Your mental state is a ranged value with * zero (0) being at a perfect mental state (bonus of 10). * negative values would reflect how sedated one is, and * positive values would reflect how stimulated one is. * In most circumstances you'd do best at a perfectly balanced state. */ ms = 10 - abs(ch->mental_state); if ( (number_percent() - get_curr_lck(ch) + 13 - ms) <= percent ) return TRUE; else return FALSE; } /* * Make a simple clone of an object (no extras...yet) -Thoric */ OBJ_DATA *clone_object( OBJ_DATA *obj ) { OBJ_DATA *clone; CREATE( clone, OBJ_DATA, 1 ); clone->pIndexData = obj->pIndexData; clone->name = QUICKLINK( obj->name ); clone->short_descr = QUICKLINK( obj->short_descr ); clone->description = QUICKLINK( obj->description ); clone->action_desc = QUICKLINK( obj->action_desc ); clone->item_type = obj->item_type; clone->extra_flags = obj->extra_flags; clone->magic_flags = obj->magic_flags; clone->wear_flags = obj->wear_flags; clone->wear_loc = obj->wear_loc; clone->weight = obj->weight; clone->cost = obj->cost; clone->level = obj->level; clone->timer = obj->timer; clone->value[0] = obj->value[0]; clone->value[1] = obj->value[1]; clone->value[2] = obj->value[2]; clone->value[3] = obj->value[3]; clone->value[4] = obj->value[4]; clone->value[5] = obj->value[5]; clone->count = 1; ++obj->pIndexData->count; ++numobjsloaded; ++physicalobjects; cur_obj_serial = UMAX((cur_obj_serial + 1 ) & (BV30-1), 1); clone->serial = clone->pIndexData->serial = cur_obj_serial; LINK( clone, first_object, last_object, next, prev ); return clone; } /* * If possible group obj2 into obj1 -Thoric * This code, along with clone_object, obj->count, and special support * for it implemented throughout handler.c and save.c should show improved * performance on MUDs with players that hoard tons of potions and scrolls * as this will allow them to be grouped together both in memory, and in * the player files. */ OBJ_DATA *group_object( OBJ_DATA *obj1, OBJ_DATA *obj2 ) { if ( !obj1 || !obj2 ) return NULL; if ( obj1 == obj2 ) return obj1; if ( obj1->pIndexData == NULL || obj2->pIndexData == NULL) return NULL; if ( obj1->pIndexData == obj2->pIndexData /* && !obj1->pIndexData->mudprogs && !obj2->pIndexData->mudprogs */ && QUICKMATCH( obj1->name, obj2->name ) && QUICKMATCH( obj1->short_descr, obj2->short_descr ) && QUICKMATCH( obj1->description, obj2->description ) && QUICKMATCH( obj1->action_desc, obj2->action_desc ) && obj1->item_type == obj2->item_type && obj1->extra_flags == obj2->extra_flags && obj1->magic_flags == obj2->magic_flags && obj1->wear_flags == obj2->wear_flags && obj1->wear_loc == obj2->wear_loc && obj1->weight == obj2->weight && obj1->cost == obj2->cost && obj1->level == obj2->level && obj1->timer == obj2->timer && obj1->value[0] == obj2->value[0] && obj1->value[1] == obj2->value[1] && obj1->value[2] == obj2->value[2] && obj1->value[3] == obj2->value[3] && obj1->value[4] == obj2->value[4] && obj1->value[5] == obj2->value[5] && !obj1->first_extradesc && !obj2->first_extradesc && !obj1->first_affect && !obj2->first_affect && !obj1->first_content && !obj2->first_content ) { obj1->count += obj2->count; obj1->pIndexData->count += obj2->count; /* to be decremented in */ numobjsloaded += obj2->count; /* extract_obj */ extract_obj( obj2 ); return obj1; } return obj2; } /* * Split off a grouped object -Thoric * decreased obj's count to num, and creates a new object containing the rest */ void split_obj( OBJ_DATA *obj, int num ) { int count; OBJ_DATA *rest; if (!obj) return; count =obj->count; if ( count <= num || num == 0 ) return; rest = clone_object(obj); --obj->pIndexData->count; /* since clone_object() ups this value */ --numobjsloaded; rest->count = obj->count - num; obj->count = num; if ( obj->carried_by ) { LINK( rest, obj->carried_by->first_carrying, obj->carried_by->last_carrying, next_content, prev_content ); rest->carried_by = obj->carried_by; rest->in_room = NULL; rest->in_obj = NULL; } else if ( obj->in_room ) { LINK( rest, obj->in_room->first_content, obj->in_room->last_content, next_content, prev_content ); rest->carried_by = NULL; rest->in_room = obj->in_room; rest->in_obj = NULL; } else if ( obj->in_obj ) { LINK( rest, obj->in_obj->first_content, obj->in_obj->last_content, next_content, prev_content ); rest->in_obj = obj->in_obj; rest->in_room = NULL; rest->carried_by = NULL; } } void separate_obj( OBJ_DATA *obj ) { split_obj( obj, 1 ); } /* * Empty an obj's contents... optionally into another obj, or a room */ bool empty_obj( OBJ_DATA *obj, OBJ_DATA *destobj, ROOM_INDEX_DATA *destroom ) { OBJ_DATA *otmp, *otmp_next; CHAR_DATA *ch = obj->carried_by; bool movedsome = FALSE; if ( !obj ) { bug( "empty_obj: NULL obj", 0 ); return FALSE; } if ( destobj || (!destroom && !ch && (destobj = obj->in_obj) != NULL) ) { for ( otmp = obj->first_content; otmp; otmp = otmp_next ) { otmp_next = otmp->next_content; if ( ( destobj->item_type == ITEM_CONTAINER ) && get_obj_weight( otmp ) + get_obj_weight( destobj ) > destobj->value[0] ) continue; obj_from_obj( otmp ); obj_to_obj( otmp, destobj ); movedsome = TRUE; } return movedsome; } if ( destroom || (!ch && (destroom = obj->in_room) != NULL) ) { for ( otmp = obj->first_content; otmp; otmp = otmp_next ) { otmp_next = otmp->next_content; if ( ch && (otmp->pIndexData->progtypes & DROP_PROG) && otmp->count > 1 ) { separate_obj( otmp ); obj_from_obj( otmp ); if ( !otmp_next ) otmp_next = obj->first_content; } else obj_from_obj( otmp ); otmp = obj_to_room( otmp, destroom ); if ( ch ) { oprog_drop_trigger( ch, otmp ); /* mudprogs */ if ( char_died(ch) ) ch = NULL; } movedsome = TRUE; } return movedsome; } if ( ch ) { for ( otmp = obj->first_content; otmp; otmp = otmp_next ) { otmp_next = otmp->next_content; obj_from_obj( otmp ); obj_to_char( otmp, ch ); movedsome = TRUE; } return movedsome; } bug( "empty_obj: could not determine a destination for vnum %d", obj->pIndexData->vnum ); return FALSE; } /* * Improve mental state -Thoric */ void better_mental_state( CHAR_DATA *ch, int mod ) { int c = URANGE( 0, abs(mod), 20 ); int con = get_curr_con(ch); c += number_percent() < con ? 1 : 0; if ( ch->mental_state < 0 ) ch->mental_state = URANGE( -100, ch->mental_state + c, 0 ); else if ( ch->mental_state > 0 ) ch->mental_state = URANGE( 0, ch->mental_state - c, 100 ); } /* * Deteriorate mental state -Thoric */ void worsen_mental_state( CHAR_DATA *ch, int mod ) { int c = URANGE( 0, abs(mod), 20 ); int con = get_curr_con(ch); c -= number_percent() < con ? 1 : 0; if ( c < 1 ) return; /* Nuisance flag makes state worsen quicker. --Shaddai */ if ( !IS_NPC(ch) && ch->pcdata->nuisance &&ch->pcdata->nuisance->flags > 2 ) c += .4*((ch->pcdata->nuisance->flags-2)*ch->pcdata->nuisance->power); if ( ch->mental_state < 0 ) ch->mental_state = URANGE( -100, ch->mental_state - c, 100 ); else if ( ch->mental_state > 0 ) ch->mental_state = URANGE( -100, ch->mental_state + c, 100 ); else ch->mental_state -= c; } /* * Add gold to an area's economy -Thoric */ void boost_economy( AREA_DATA *tarea, int gold ) { while ( gold >= 1000000000 ) { ++tarea->high_economy; gold -= 1000000000; } tarea->low_economy += gold; while ( tarea->low_economy >= 1000000000 ) { ++tarea->high_economy; tarea->low_economy -= 1000000000; } } /* * Take gold from an area's economy -Thoric */ void lower_economy( AREA_DATA *tarea, int gold ) { while ( gold >= 1000000000 ) { tarea->high_economy -= 1; gold -= 1000000000; } tarea->low_economy -= gold; while ( tarea->low_economy < 0 ) { tarea->high_economy -=1; tarea->low_economy += 1000000000; } } /* * Check to see if economy has at least this much gold -Thoric */ bool economy_has( AREA_DATA *tarea, int gold ) { int hasgold = ((tarea->high_economy > 0) ? 1 : 0) * 1000000000 + tarea->low_economy; if ( hasgold >= gold ) return TRUE; return FALSE; } /* * Used in db.c when resetting a mob into an area -Thoric * Makes sure mob doesn't get more than 10% of that area's gold, * and reduces area economy by the amount of gold given to the mob */ void economize_mobgold( CHAR_DATA *mob ) { int gold; AREA_DATA *tarea; /* make sure it isn't way too much */ mob->gold = UMIN( mob->gold, mob->top_level * mob->top_level * 400 ); if ( !mob->in_room ) return; tarea = mob->in_room->area; gold = ((tarea->high_economy > 0) ? 1 : 0) * 1000000000 + tarea->low_economy; mob->gold = URANGE( 0, mob->gold, gold / 10 ); if ( mob->gold ) lower_economy( tarea, mob->gold ); } /* * Add another notch on that there belt... ;) * Keep track of the last so many kills by vnum -Thoric */ void add_kill( CHAR_DATA *ch, CHAR_DATA *mob ) { int x; int vnum; sh_int track; if ( IS_NPC(ch) ) return; if ( !IS_NPC(mob) ) return; vnum = mob->pIndexData->vnum; track = URANGE( 2, ((ch->skill_level[COMBAT_ABILITY]+3) * MAX_KILLTRACK)/LEVEL_AVATAR, MAX_KILLTRACK ); for ( x = 0; x < track; x++ ) if ( ch->pcdata->killed[x].vnum == vnum ) { if ( ch->pcdata->killed[x].count < 50 ) ++ch->pcdata->killed[x].count; return; } else if ( ch->pcdata->killed[x].vnum == 0 ) break; memmove( (char *) ch->pcdata->killed+sizeof(KILLED_DATA), ch->pcdata->killed, (track-1) * sizeof(KILLED_DATA) ); ch->pcdata->killed[0].vnum = vnum; ch->pcdata->killed[0].count = 1; if ( track < MAX_KILLTRACK ) ch->pcdata->killed[track].vnum = 0; } /* * Return how many times this player has killed this mob -Thoric * Only keeps track of so many (MAX_KILLTRACK), and keeps track by vnum */ int times_killed( CHAR_DATA *ch, CHAR_DATA *mob ) { int x; int vnum; sh_int track; if ( IS_NPC(ch) ) return 0; if ( !IS_NPC(mob) ) return 0; vnum = mob->pIndexData->vnum; track = URANGE( 2, ((ch->skill_level[COMBAT_ABILITY]+3) * MAX_KILLTRACK)/LEVEL_AVATAR, MAX_KILLTRACK ); for ( x = 0; x < track; x++ ) if ( ch->pcdata->killed[x].vnum == vnum ) return ch->pcdata->killed[x].count; else if ( ch->pcdata->killed[x].vnum == 0 ) break; return 0; } /* * returns area with name matching input string * Last Modified : July 21, 1997 * Fireblade */ AREA_DATA *get_area(char *name) { AREA_DATA *pArea; if(!name) { bug("get_area: NULL input string."); return NULL; } for(pArea = first_area; pArea; pArea = pArea->next) { /*if(nifty_is_name(name, pArea->name))*/ if(!str_cmp(name, pArea->name)) break; } if(!pArea) { for(pArea = first_build; pArea; pArea = pArea->next) { /*if(nifty_is_name(name, pArea->name))*/ if(!str_cmp(name, pArea->name)) break; } } return pArea; } /* * returns area with name matching input string * Last Modified : April 14, 2001 * Fireblade */ AREA_DATA *get_area_by_filename(char *name) { AREA_DATA *pArea; if(!name) { bug("get_area: NULL input string."); return NULL; } for(pArea = first_area; pArea; pArea = pArea->next) { if( !str_cmp(name, pArea->filename) ) break; } if(!pArea) { for(pArea = first_build; pArea; pArea = pArea->next) { if(!str_cmp(name, pArea->filename)) break; } } return pArea; } AREA_DATA * get_area_obj ( OBJ_INDEX_DATA *pObjIndex ) { AREA_DATA *pArea; if ( !pObjIndex ) { bug("get_area_obj: pObjIndex is NULL."); return NULL; } for ( pArea = first_area; pArea; pArea = pArea->next ) { if ( pObjIndex->vnum >= pArea->low_o_vnum && pObjIndex->vnum <= pArea->hi_o_vnum ) break; } return pArea; }