/*************************************************************************** * 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. * ***************************************************************************/ #if defined(macintosh) #include <types.h> #else #include <sys/types.h> #endif #include <ctype.h> #include <stdio.h> #include <string.h> #include <time.h> #include "ack.h" #ifndef DEC_MONEY_H #include "money.h" #endif #ifndef DEC_ACT_MOB_H #include "act_mob.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]; /* * Local functions. */ void affect_modify args( ( CHAR_DATA *ch, AFFECT_DATA *paf, bool fAdd ) ); /* * Updated pointer referencing, curtesy of Spectrum, from Beyond the Veil * */ struct obj_ref_type *obj_ref_list; void obj_reference(struct obj_ref_type *ref) { if (ref->inuse) { bugf("Reused obj_reference!"); abort(); } ref->inuse=TRUE; ref->next=obj_ref_list; obj_ref_list=ref; } void obj_unreference(OBJ_DATA **var) { struct obj_ref_type *p, *last; for (p=obj_ref_list, last=NULL; p && p->var!=var; last=p,p=p->next) ; if (!p) { bugf("obj_unreference: var not found"); return; } p->inuse=FALSE; if (!last) obj_ref_list=obj_ref_list->next; else last->next=p->next; } struct char_ref_type *char_ref_list; void char_reference(struct char_ref_type *ref) { if (ref->inuse) { bugf("Reused char_reference!"); abort(); } ref->inuse=TRUE; ref->next=char_ref_list; char_ref_list=ref; } void char_unreference(CHAR_DATA **var) { struct char_ref_type *p, *last; for (p=char_ref_list, last=NULL; p && p->var!=var; last = p, p=p->next) ; if (!p) { bugf("char_unreference: var not found"); return; } p->inuse=FALSE; if (!last) char_ref_list=char_ref_list->next; else last->next=p->next; } /* * 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) && IS_SET( ch->pcdata->pflags, PFLAG_AMBAS ) ) 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 ); sprintf( buf+strlen(buf), "%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) && IS_SET(ch->act, 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) && IS_SET(ch->act, 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" ) ) REMOVE_BIT( ch->pcdata->pflags, PFLAG_RAGED ); switch ( paf->location ) { default: bug( "Affect_modify: unknown location %d.", paf->location ); sprintf( buf, "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 ) ) { sh_int 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; } void mark_to_room( int this_room_vnum, MARK_DATA * mark ) { /* this assumes that the mark_data is good, and has * been constructed properly. It will link it to the room * and the main list. Caller must get the struct memory. * */ MARK_LIST_MEMBER *mlist; MARK_LIST_MEMBER *rlist; ROOM_INDEX_DATA *this_room; if ( ( this_room = get_room_index( this_room_vnum ) ) == NULL ) { PUT_FREE( mark, mark_free ); return; } GET_FREE( mlist, mark_list_free); GET_FREE( rlist, mark_list_free); mlist->mark = mark; rlist->mark = mark; LINK( mlist, first_mark_list, last_mark_list, next, prev ); LINK( rlist, this_room->first_mark_list, this_room->last_mark_list, next, prev ); if ( !booting_up ) save_marks( ); return; } void mark_from_room( int this_room_vnum, MARK_DATA * mark ) { MARK_LIST_MEMBER *mlist; MARK_LIST_MEMBER *rlist; ROOM_INDEX_DATA *this_room; this_room = get_room_index( this_room_vnum ); for ( rlist = this_room->first_mark_list; rlist != NULL; rlist = rlist->next ) { if ( rlist->mark == mark ) { UNLINK( rlist, this_room->first_mark_list, this_room->last_mark_list, next, prev ); break; } } for ( mlist = first_mark_list; mlist != NULL; mlist = mlist->next ) { if ( mlist->mark == mark ) { UNLINK( mlist, first_mark_list, last_mark_list, next, prev ); break; } } PUT_FREE( mark, mark_free ); PUT_FREE( rlist, mark_list_free ); PUT_FREE( mlist, mark_list_free ); if ( !booting_up ) save_marks( ); 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]; GET_FREE(raf_new, raffect_free); /* 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 ); sprintf( buf, "@@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]; sprintf( buf, "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); PUT_FREE(raf, raffect_free); return; } /* * Give an affect to a char. */ void affect_to_char( CHAR_DATA *ch, AFFECT_DATA *paf ) { AFFECT_DATA *paf_new; GET_FREE(paf_new, affect_free); /* 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_NPC( ch ) && IS_WOLF( ch ) ) SET_BIT( ch->pcdata->pflags, PFLAG_RAGED ); return; } /* * Remove an affect from a char. */ void affect_remove( CHAR_DATA *ch, AFFECT_DATA *paf ) { sh_int shield_type; if ( ch->first_affect == NULL ) { char buf[MAX_STRING_LENGTH]; sprintf( buf, "affect_remove: %s did not have aff %d to remove.", IS_NPC(ch) ? ch->short_descr : ch->name, 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]; sprintf( buf1, this_shield->wearoff_room ); sprintf( buf2, 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 ); PUT_FREE( this_shield, shield_free ); } } UNLINK( paf, ch->first_affect, ch->last_affect, next, prev ); PUT_FREE(paf, affect_free); 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]; sprintf( buf, "char_from_room: %s in NULL room.", IS_NPC(ch) ? ch->short_descr : ch->name ); monitor_chan( buf, MONITOR_ROOM ); bug( "Char_from_room: NULL.", 0 ); return; } if ( !IS_NPC(ch) ) --ch->in_room->area->nplayer; 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]; sprintf( buf, "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, pRoomIndex->first_person, pRoomIndex->last_person, next_in_room, prev_in_room); else LINK(ch, pRoomIndex->first_person, pRoomIndex->last_person, next_in_room, prev_in_room); if ( !IS_NPC(ch) ) ++ch->in_room->area->nplayer; 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!!!\n\r", 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 ) && ( ch->is_free == FALSE ) ) { 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!!!\n\r", 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 ) && ( ch->is_free == FALSE ) ) { 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!!!\n\r", 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 ) { sh_int 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.\n\r", 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 ) { extern OBJ_DATA * quest_object; obj->next_in_carry_list = NULL; obj->prev_in_carry_list = NULL; if ( ( !IS_NPC( ch ) ) && ( obj == quest_object ) ) { bool valid_questor = FALSE; sh_int average_level; average_level = obj->value[3]; 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]; sprintf( buf, "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 ) ) { sprintf( log, "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_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 ( !IS_OBJ_STAT( obj, ITEM_NODROP ) ) { 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!\n\r", 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.\n\r", ch ); } if ( IS_SET( obj->item_apply, ITEM_APPLY_DET_INV ) ) send_to_char( "You feel more aware of your surroundings.\n\r", 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.\n\r", ch ); } if ( IS_SET( obj->item_apply, ITEM_APPLY_SNEAK ) ) send_to_char( "You feel all sneaky!\n\r", ch ); if ( IS_SET( obj->item_apply, ITEM_APPLY_HIDE ) ) send_to_char( "You feel almost hidden.\n\r", ch ); if ( IS_SET( obj->item_apply, ITEM_APPLY_PROT ) ) send_to_char( "You feel more protected.\n\r", ch ); if ( IS_SET( obj->item_apply, ITEM_APPLY_ENHANCED ) ) send_to_char( "You feel much meaner!\n\r", 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.\n\r", 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!\n\r", 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!\n\r", 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]; sprintf( buf, "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!\n\r", 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.\n\r", ch ); } if ( IS_SET( obj->item_apply, ITEM_APPLY_DET_INV ) ) send_to_char( "You feel less aware of your surroundings.\n\r", 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.\n\r", ch ); } if ( IS_SET( obj->item_apply, ITEM_APPLY_SNEAK ) ) send_to_char( "You feel less sneaky!\n\r", ch ); if ( IS_SET( obj->item_apply, ITEM_APPLY_HIDE ) ) send_to_char( "You feel less hidden.\n\r", ch ); if ( IS_SET( obj->item_apply, ITEM_APPLY_PROT ) ) send_to_char( "You feel less protected.\n\r", ch ); if ( IS_SET( obj->item_apply, ITEM_APPLY_ENHANCED ) ) send_to_char( "You feel much wimpier!\n\r", 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.\n\r", 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!\n\r", 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!\n\r", 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]; sprintf( buf, "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 ) { sprintf( buf, "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]; sprintf( buf, "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 ) { CHAR_DATA *wch; OBJ_DATA * obj_content; struct obj_ref_type *ref; ROOM_INDEX_DATA * drop_room = NULL; for (ref=obj_ref_list; ref; ref=ref->next) if (*ref->var==obj) switch (ref->type) { case OBJ_NEXT: *ref->var=obj->next; break; case OBJ_NEXTCONTENT: *ref->var=obj->next_in_carry_list; break; case OBJ_NULL: *ref->var=NULL; break; default: bugf("Bad obj_ref_list type %d", ref->type); break; } 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 ); UNLINK(obj, first_obj, last_obj, next, prev); { AFFECT_DATA *paf; while ( (paf = obj->first_apply) != NULL ) { obj->first_apply = paf->next; PUT_FREE(paf, affect_free); } } { EXTRA_DESCR_DATA *ed; while ( (ed = obj->first_exdesc) != NULL ) { obj->first_exdesc = ed->next; PUT_FREE(ed, exdesc_free); } } for ( wch = first_char; wch; wch = wch->next ) { MPROG_ACT_LIST *mpact; if ( wch->hunt_obj == obj ) end_hunt(wch); /* wch->hunt_obj = NULL;*/ if ( wch->sitting == obj ) do_stand( wch, "" ); for ( mpact = wch->first_mpact; mpact; mpact = mpact->next ) { if ( mpact->obj == obj ) mpact->obj = NULL; if ( mpact->vo == obj ) mpact->vo = NULL; } } if ( obj->item_type == ITEM_CORPSE_PC ) { CORPSE_DATA * this_corpse; for ( this_corpse = first_corpse; this_corpse != NULL; this_corpse = this_corpse->next) if ( this_corpse->this_corpse == obj ) break; if ( this_corpse != NULL ) { UNLINK( this_corpse, first_corpse, last_corpse, next, prev ); PUT_FREE( this_corpse, corpse_free ); } save_corpses( ); } --obj->pIndexData->count; if ( obj->money != NULL ) { PUT_FREE( obj->money, money_type_free ); } PUT_FREE(obj, obj_free); return; } /* * Extract a char from the world. */ void extract_char( CHAR_DATA *ch, bool fPull ) { CHAR_DATA *wch; OBJ_DATA * this_object; extern CHAR_DATA *quest_mob; extern CHAR_DATA * quest_target; struct char_ref_type *ref; /* * Updated pointer referencing, curtesy of Spectrum, from Beyond the Veil * */ if ( ch->in_room == NULL ) { char buf[MAX_STRING_LENGTH]; sprintf( buf, "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; } for (ref=char_ref_list; ref; ref=ref->next) if (*ref->var==ch) switch (ref->type) { case CHAR_NEXT: *ref->var=ch->next; break; case CHAR_NEXTROOM: *ref->var=ch->next_in_room; break; case CHAR_NULL: *ref->var=NULL; break; default: bugf("Bad char_ref_list type %d", ref->type); break; } 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 ); char_from_room( ch ); if ( !fPull ) { if ( IS_NPC( ch ) && IS_SET( ch->act, ACT_INTELLIGENT ) ) { char_to_room( ch, get_room_index( ROOM_VNUM_INT_HEAL ) ); } else if ( !IS_VAMP(ch) ) { char_to_room( ch, get_room_index( ROOM_VNUM_MORIBUND ) ); } else { char_to_room( ch, get_room_index( VAMPIRE_RECALL ) ); } return; } if ( IS_NPC(ch) ) --ch->pIndexData->count; if ( ch->desc != NULL && ch->desc->original != NULL ) do_return( ch, "" ); for ( wch = first_char; wch != NULL; wch = wch->next ) { AFFECT_DATA *paf; 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; } } 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; } /* 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 ); PUT_FREE( this_shield, shield_free ); } } PUT_FREE( ch->money, money_type_free ); PUT_FREE( ch->bank_money, money_type_free ); if ( !IS_NPC( ch ) && IS_SET( ch->pcdata->pflags, PFLAG_SUPER_COUNCIL ) ) { sh_int 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 ( ch->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 ); PUT_FREE( kill_group, npc_group_free ); } 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 ); } } } } } UNLINK(ch, first_char, last_char, next, prev); if ( ch->desc ) ch->desc->character = NULL; free_char( 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!\n\r", ch ); return NULL; } else if ( ch->fighting->fighting == NULL ) { send_to_char( "Hmm, that's wierd..where did he go?\n\r", 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!\n\r", ch ); return NULL; } else if ( ch->fighting->fighting == NULL ) { send_to_char( "Hmm, that's wierd..where did he go?\n\r", ch ); return NULL; } if ( ch->fighting->fighting->fighting == NULL ) { send_to_char( "Hmm, that's wierd..where did he go?\n\r", 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; int number; int count; if ( ( wch = get_char_room( ch, argument ) ) != NULL ) return wch; number = number_argument( argument, arg ); count = 0; for ( wch = first_char; wch != NULL ; wch = wch->next ) { 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; int number; int count; if ( ( ach = get_char_room( ch, argument ) ) != NULL ) return ach; number = number_argument( argument, arg ); count = 0; for ( ach = first_char; ach != NULL ; ach = ach->next ) { 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; for ( obj = first_obj; obj != NULL; obj = obj->next ) { 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; if ( ( obj = get_obj_here( ch, argument ) ) != NULL ) return obj; number = number_argument( argument, arg ); count = 0; for ( obj = first_obj; obj != NULL; obj = obj->next ) { 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 ) { char buf[MAX_STRING_LENGTH]; sprintf( buf, "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 ); sprintf( buf, 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 ( IS_SET(pRoomIndex->room_flags, ROOM_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 ( IS_SET(pRoomIndex->room_flags, ROOM_PRIVATE) && count >= 2 ) return TRUE; if ( IS_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 ( 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) && IS_SET(victim->act, PLR_WIZINVIS) && get_trust( ch ) < victim->invis ) /* && get_trust( ch ) < get_trust( victim ) ) */ return FALSE; if ( !IS_NPC(ch) && IS_SET(ch->act, PLR_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) && IS_SET(ch->act, PLR_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_SET(obj->extra_flags, ITEM_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_SET(obj->extra_flags, ITEM_NODROP) ) 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_SET( obj->extra_flags, ITEM_NOSAC ) ) 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]; sprintf( buf, "[NOTE]: %s\n\r", message ); for ( d = first_desc; d; d = d->next ) if ( ( d->connected == CON_PLAYING ) && (d->character->level >=lv) && !IS_NPC(d->character) && !IS_SET( d->character->deaf, CHANNEL_NOTIFY ) ) send_to_char( buf, d->character ); return; } void auction( char * message ) { DESCRIPTOR_DATA *d; char buf[MAX_STRING_LENGTH]; sprintf( buf, "[AUCTION]: %s\n\r", message ); for ( d = first_desc; d; d = d->next ) if ( ( d->connected == CON_PLAYING ) && !IS_NPC(d->character) && !IS_SET( d->character->deaf, 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) && !IS_SET( d->character->deaf, CHANNEL_INFO ) ) { sprintf( buf, "%s[INFO]: %s%s\n\r", 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]; sprintf( buf, "[LOG]: %s\n\r", 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 ) && ( !IS_SET( d->character->deaf, 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; } /* This is for immrotal authorized skills. Enables imms to set which skillks lower imms may use. handy for abuse control --Flar */ bool authorized( CHAR_DATA *ch, char *skllnm ) { char buf [ MAX_STRING_LENGTH ]; if ( ( !IS_NPC( ch ) && str_infix( skllnm, ch->pcdata->immskll ) ) || IS_NPC( ch ) ) { sprintf( buf, "Sorry, you are not authorized to use %s.\n\r", skllnm ); send_to_char( buf, ch ); return FALSE; } return TRUE; } /* 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; REMOVE_BIT( mob->act, ACT_IS_NPC); 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: SET_BIT( victim->act, ACT_IS_NPC ); } 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->stunTimer = stunTime; return; } bool is_shielded( CHAR_DATA * ch, sh_int 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]; sprintf( buf, "shield_remove: %s did not have a shield to remove.", IS_NPC(ch) ? ch->short_descr : ch->name ); monitor_chan( buf, MONITOR_MOB ); bug( "Remove_shield: no shield.", 0 ); return; } UNLINK(shield, ch->first_shield, ch->last_shield, next, prev); PUT_FREE(shield, shield_free); return; }