/*___________________________________________________________________________* )()( DalekenMUD 1.12 (C) 2000 )()( `][' by Martin Thomson, Lee Brooks, `][' || Ken Herbert and David Jacques || || ----------------------------------------------------------------- || || Envy Diku Mud improvements copyright (C) 1994 by Michael Quan, || || David Love, Guilherme 'Willie' Arnold, and Mitchell Tse. || || Merc 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. || || ----------------------------------------------------------------- || || Any use of this software must follow the licenses of the || || creators. 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. || || ----------------------------------------------------------------- || || update.c || || Contains all regular update handling functions. || *_/<>\_________________________________________________________________/<>\_*/ #include <math.h> #include "mud.h" #include "event.h" /* * Externals */ extern bool merc_down; /* * Globals */ bool delete_obj; bool delete_char; /* * Semi-globals. */ int pulse_point; /* * Local functions. */ void hit_gain args( ( CHAR_DATA *ch ) ); void mana_gain args( ( CHAR_DATA *ch ) ); void move_gain args( ( CHAR_DATA *ch ) ); void mobile_update args( ( void ) ); void weather_update args( ( void ) ); void char_update args( ( void ) ); void aggr_update args( ( void ) ); void update_auction args( ( void ) ); void smash_update args( ( void ) ); void explode args( ( OBJ_DATA *obj ) ); void quest_update args( ( void ) ); void spam_update args( ( void ) ); /* * Advancement stuff. */ int level_hpgain( int con, int Class, int extra ) { int x, y; x = power( class_table[Class].hp_min, 5, con - 16 ); y = power( class_table[Class].hp_max, 5, con - 15 ); x = ( number_range( x, y ) + number_range( x, y ) ) / 2; return x * ( 100 + extra / 2 ) / 100; } int level_managain( int intell, int wisd, int magic, int Class, int extra ) { int gain; gain = power( 112, 2, ( intell * 3 + wisd - 60 ) / 2 ); gain = number_range( gain * 2 / 3, gain ) + number_range( gain, gain * 3 / 2 ); gain = gain * ( number_fuzzy( class_table[Class].fMana + 10 ) - 10 ); gain = gain * ( 100 + extra / 2 ) / 25000; gain += number_range( 0, number_range( 0, magic ) ) / 5; return gain; } void advance_level( CHAR_DATA *ch, bool multiple ) { char buf[MAX_STRING_LENGTH]; int add_hp; int i; int add_mana[MAGIC_MAX]; int add_move; int add_prac; int Class; if( ( Class = get_aspire_class( ch ) ) != CLASS_NONE || get_first_class( ch ) == CLASS_NONE ) { if( Class < 0 ) Class = ch->class; add_hp = level_hpgain( get_curr_con( ch ), Class, race_table[ch->race].hp_gain ); for( i = 0; i < MAGIC_MAX; ++i ) add_mana[i] = level_managain( get_curr_int( ch ), get_curr_wis( ch ), get_magic( ch, i ), Class, race_table[ch->race].mana_gain[i] ); } else { add_hp = level_hpgain( get_curr_con( ch ), ch->class, race_table[ch->race].hp_gain ) + 2 * level_hpgain( get_curr_con( ch ), get_first_class( ch ), race_table[ch->race].hp_gain ); add_hp /= 3; for( i = 0; i < MAGIC_MAX; ++i ) { add_mana[i] = level_managain( get_curr_int( ch ), get_curr_wis( ch ), get_magic( ch, i ), ch->class, race_table[ch->race].mana_gain[i] ) + 2 * level_managain( get_curr_int( ch ), get_curr_wis( ch ), get_magic( ch, i ), get_first_class( ch ), race_table[ch->race].mana_gain[i] ); add_mana[i] /= 3; } } add_move = ( 90 + 2 * get_curr_dex( ch ) + get_curr_con( ch ) ) / 18; add_move = number_range( add_move, add_move * 2 ); add_prac = power( 100, 8, get_curr_wis( ch ) - 15 ); add_prac = number_range( add_prac * 11 / 12, add_prac * 13 / 12 ); add_prac = add_prac * ( 100 + race_table[ch->race].move_gain / 2 ) / 100; add_hp = UMAX( 1, add_hp ); for( i = 0; i < MAGIC_MAX; ++i ) add_mana[i] = UMAX( 0, add_mana[i] ); add_move = UMAX( 8, add_move ); if( ch->sublevel ) { add_hp /= 2; for( i = 0; i < MAGIC_MAX; ++i ) add_mana[i] /= 2; add_move /= 2; add_prac /= 2; } ch->max_hit += add_hp; ch->hit = ch->max_hit; for( i = 0; i < MAGIC_MAX; ++i ) { ch->max_mana[i] += add_mana[i]; ch->mana[i] = ch->max_mana[i]; } ch->max_move += add_move; ch->move = ch->max_move; ch->practice += add_prac; if( !IS_NPC( ch ) ) xREMOVE_BIT( ch->act, PLR_BOUGHT_PET ); if( !multiple ) { SysInfo->levels++; charprintf( ch, "&GYou raise a level!!! &mYour gain is: " "%d/%d hp, %d/%d mv %d/%d prac.\n\r&gMana: ", add_hp, get_max_hit( ch ), add_move, get_max_move( ch ), add_prac, ch->practice ); for( i = 0; i < MAGIC_MAX; ++i ) charprintf( ch, "%s%d/%d %s%s", magic_colour[i], add_mana[i], get_max_mana( ch, i ), magic_name[i], ( i < MAGIC_MAX - 1 ) ? ", " : "&g.&n\n\r" ); if( ch->sublevel ) { sprintf( buf, "%s has gained in power to sublevel %d!", ch->name, ch->sublevel ); } else { sprintf( buf, "%s is now level %d!", ch->name, ch->level ); } wiznet( ch, WIZ_LEVELS, get_trust( ch ), buf ); talk_channel( NULL, buf, CHANNEL_INFO, "INFO" ); update_highest_list( ch ); } return; } /* * Demote stuff. */ void demote_level( CHAR_DATA *ch ) { int add_hp; int i; int add_mana[MAGIC_MAX]; int add_move; int add_prac; int Class; if( ch->level == 1 ) return; if( ( Class = get_aspire_class( ch ) ) != CLASS_NONE || get_first_class( ch ) == CLASS_NONE ) { if( Class < 0 ) Class = ch->class; add_hp = level_hpgain( get_curr_con( ch ), Class, race_table[ch->race].hp_gain ); for( i = 0; i < MAGIC_MAX; ++i ) add_mana[i] = level_managain( get_curr_int( ch ), get_curr_wis( ch ), get_magic( ch, i ), Class, race_table[ch->race].mana_gain[i] ); } else { add_hp = level_hpgain( get_curr_con( ch ), ch->class, race_table[ch->race].hp_gain ) + 2 * level_hpgain( get_curr_con( ch ), get_first_class( ch ), race_table[ch->race].hp_gain ); add_hp /= 3; for( i = 0; i < MAGIC_MAX; ++i ) { add_mana[i] = level_managain( get_curr_int( ch ), get_curr_wis( ch ), get_magic( ch, i ), ch->class, race_table[ch->race].mana_gain[i] ) + 2 * level_managain( get_curr_int( ch ), get_curr_wis( ch ), get_magic( ch, i ), get_first_class( ch ), race_table[ch->race].mana_gain[i] ); } } add_move = ( 90 + 2 * get_curr_dex( ch ) + get_curr_con( ch ) ) / 18; add_move = number_range( add_move, add_move * 2 ); add_prac = power( 100, 8, get_curr_wis( ch ) - 15 ); add_prac = number_range( add_prac * 11 / 12, add_prac * 13 / 12 ); add_prac = add_prac * ( 100 + race_table[ch->race].move_gain / 2 ) / 100; add_hp = UMAX( 1, add_hp ); for( i = 0; i < MAGIC_MAX; ++i ) add_mana[i] = UMAX( 0, add_mana[i] ); add_move = UMAX( 8, add_move ); if( ch->sublevel ) { add_hp /= 2; for( i = 0; i < MAGIC_MAX; ++i ) add_mana[i] /= 2; add_move /= 2; add_prac /= 2; } ch->max_hit -= add_hp; ch->hit = ch->max_hit; for( i = 0; i < MAGIC_MAX; ++i ) { ch->max_mana[i] -= add_mana[i]; ch->mana[i] = ch->max_mana[i]; } ch->max_move -= add_move; ch->move = ch->max_move; ch->practice -= add_prac; if( !IS_NPC( ch ) ) xREMOVE_BIT( ch->act, PLR_BOUGHT_PET ); ch->level -= 1; charprintf( ch, "Your loss is: %d/%d hp, %d/%d mv %d/%d prac.\n\r", add_hp, get_max_hit( ch ), add_move, get_max_move( ch ), add_prac, ch->practice ); for( i = 0; i < MAGIC_MAX; ++i ) charprintf( ch, "%d/%d %s mana%s", add_mana[i], get_max_mana( ch, i ), magic_name[i], ( i < MAGIC_MAX - 1 ) ? ", " : ".\n\r" ); wiznetf( ch, WIZ_LEVELS, get_trust( ch ), "%s has lost a level.", ch->name ); return; } /* * Find which class to assign to the successful multi-classer * A little complex but it works. * --Symposium */ void set_new_class( CHAR_DATA *ch, int second ) { int newclass, i; if( second > NUM_MULTI_CLASS || second < 0 || ch->class < 0 || ch->class > AVAIL_CLASS ) return; ch->pcdata->multi_class[second] = CLASS_SECOND; ch->pcdata->multi_class[ch->class] = CLASS_FIRST; newclass = AVAIL_CLASS + UMIN( ch->class, second ) * AVAIL_CLASS; newclass += UMAX( ch->class, second ); for( i = 1; i <= UMIN( ch->class, second ); ++i ) newclass -= i; ch->class = newclass; return; } void gain_exp( CHAR_DATA *ch, int gain ) { char Info[MAX_INPUT_LENGTH]; int i; if( IS_NPC( ch ) || ch->level >= LEVEL_HERO ) return; ch->exp -= UMIN( get_tnl( ch ) * 2, gain ); while( ch->level < LEVEL_HERO && ch->exp <= 0 ) { ch->exp += get_tnl( ch ); if( ch->sublevel ) { ch->sublevel++; if( ch->sublevel > ch->level ) { ch->sublevel = 0; ch->level++; if( ( i = get_aspire_class( ch ) ) >= 0 ) { if( get_first_class( ch ) == CLASS_NONE ) { ch->pcdata->multi_class[i] = CLASS_SECOND; set_new_class( ch, i ); act( "You are now fully a $t, congratulations!", ch, class_table[ch->class].name, NULL, TO_CHAR ); sprintf( Info, "Please congratulate %s on obtaining status as a %s!", ch->name, class_table[ch->class].name ); } else { ch->pcdata->multi_class[i] = CLASS_ADEPT; act( "You are now adept at the disciplines of the $t class.", ch, class_table[i].name, NULL, TO_CHAR ); sprintf( Info, "%s has just earned status as a level %d %s!", ch->name, ch->level, class_table[i].name ); } if( Info[0] != '\0' ) talk_channel( NULL, Info, CHANNEL_INFO, "INFO" ); break; } } } else /* they dont have a sublevel */ { ch->level++; if( ch->level == 50 ) do_help( ch, "new hero" ); } advance_level( ch, FALSE ); } while( ch->level == LEVEL_HERO && ch->exp <= 0 ) { ch->exp += get_tnl( ch ); if( ch->sublevel < 1000 ) ch->sublevel++; for( i = 0; i < 4 && ch->sublevel == LEVEL_HERO; ++i ) { ch->pcdata->multi_class[i] = CLASS_ASPIRING; } if( ch->exp > 0 ) advance_level( ch, FALSE ); else advance_level( ch, TRUE ); } return; } /* * Regeneration stuff. */ void hit_gain( CHAR_DATA *ch ) { int gain; if( IS_AFFECTED( ch, AFF_BLEEDING ) ) return; if( IS_NPC( ch ) ) { gain = ch->level * 3 / 2; } else { gain = power( 30, 8, get_curr_con( ch ) - 20 ); switch( ch->position ) { default: gain /= 8; break; case POS_SLEEPING: gain += ch->max_hit / 80; break; case POS_SMASHED: case POS_SITTING: gain /= 4; break; case POS_RESTING: gain /= 2; break; case POS_MEDITATING: gain += ch->max_hit / 30; break; } if( ch->pcdata->condition[COND_FULL] == 0 ) gain /= 2; if( ch->pcdata->condition[COND_THIRST] == 0 ) gain /= 2; if( get_curr_temp( ch ) - get_room_temp( ch->in_room ) > 40 ) { gain *= 100; gain /= ( 60 + get_curr_temp( ch ) - get_room_temp( ch->in_room ) ); } else if( get_room_temp( ch->in_room ) - get_curr_temp( ch ) > 40 ) { gain *= 100; gain /= ( 60 + get_room_temp( ch->in_room ) - get_curr_temp( ch ) ); } if( ch->pcdata->religion && ch->in_room->area->order && ch->pcdata->religion == ch->in_room->area->order->religion ) gain += gain >> 4; } if( ch->on && ch->on->item_type == ITEM_FURNITURE ) gain = gain * ( 100 + ch->on->value[2] ) / 100; gain = gain * ( 100 + race_table[ch->race].hp_gain ) / 100; if( IS_AFFECTED( ch, AFF_POISON ) || IS_AFFECTED( ch, AFF_PLAGUE ) ) gain /= 4; gain = UMAX( 1, gain ); if( ch->hit > ch->max_hit ) ch->hit = UMAX( ch->max_hit, ch->hit - 2000 / gain ); else ch->hit = UMIN( ch->max_hit, ch->hit + gain ); } void mana_gain( CHAR_DATA *ch ) { int gain, i, magic; int mod = 100; if( !IS_NPC( ch ) ) { if( get_curr_temp( ch ) - get_room_temp( ch->in_room ) > 40 ) mod = mod * 100 / ( 60 + get_curr_temp( ch ) - get_room_temp( ch->in_room ) ); else if( get_room_temp( ch->in_room ) - get_curr_temp( ch ) > 40 ) mod = mod * 100 / ( 60 + get_room_temp( ch->in_room ) - get_curr_temp( ch ) ); } if( IS_AFFECTED( ch, AFF_POISON ) || IS_AFFECTED( ch, AFF_PLAGUE ) ) mod /= 4; if( IS_AFFECTED( ch, AFF_BLEEDING ) ) mod /= 2; if( ch->on && ch->on->item_type == ITEM_FURNITURE ) mod = mod * ( 100 + ch->on->value[3] ) / 100; for( i = 0; i < MAGIC_MAX; ++i ) { if( ch->mana[i] == ch->max_mana[i] ) continue; magic = get_magic( ch, i ); if( IS_NPC( ch ) ) { gain = ch->level; } else { gain = get_curr_int( ch ); gain = gain * ( gain + magic ) / 10; gain = gain * 3 / 4 + gain * class_table[ch->class].fMana / 15; gain += magic; switch( ch->position ) { default: gain /= 8; break; case POS_SLEEPING: gain += ch->max_mana[i] / 40; break; case POS_SMASHED: case POS_SITTING: gain /= 4; break; case POS_RESTING: gain /= 2; break; case POS_MEDITATING: gain += ch->max_mana[i] / 25; gain += gain / 2; break; } if( ch->pcdata->religion && ch->in_room->area->order && ch->pcdata->religion == ch->in_room->area->order->religion ) gain += gain >> 4; } gain = gain * mod * ( 100 + race_table[ch->race].mana_gain[i] ) / 10000; gain = UMAX( 1, gain ); if( ch->mana[i] > ch->max_mana[i] ) ch->mana[i] = UMAX( ch->max_mana[i], ch->mana[i] - 2000 / gain ); else ch->mana[i] = UMIN( ch->max_mana[i], ch->mana[i] + gain ); } } void move_gain( CHAR_DATA *ch ) { int gain; if( IS_NPC( ch ) ) { gain = ch->level; } else { gain = UMAX( 15 + ( ch->level / 10 ), 2 * ch->level ); gain += ch->max_move / 50; switch( ch->position ) { case POS_SLEEPING: gain += get_curr_dex( ch ) * 2; break; case POS_RESTING: case POS_SITTING: gain += get_curr_dex( ch ); break; default: break; } if( ch->pcdata->condition[COND_FULL] == 0 ) gain /= 2; if( ch->pcdata->condition[COND_THIRST] == 0 ) gain /= 2; if( get_curr_temp( ch ) - get_room_temp( ch->in_room ) > 40 ) { gain *= 100; gain /= ( 60 + get_curr_temp( ch ) - get_room_temp( ch->in_room ) ); } else if( get_room_temp( ch->in_room ) - get_curr_temp( ch ) > 40 ) { gain *= 100; gain /= ( 60 + get_room_temp( ch->in_room ) - get_curr_temp( ch ) ); } if( ch->pcdata->religion && ch->in_room->area->order && ch->pcdata->religion == ch->in_room->area->order->religion ) gain += gain >> 4; if( ch->on && ch->on->item_type == ITEM_FURNITURE ) gain = gain * ( 100 + ch->on->value[2] ) / 100; gain = gain * ( 100 + race_table[ch->race].move_gain ) / 100; } if( IS_AFFECTED( ch, AFF_POISON ) || IS_AFFECTED( ch, AFF_PLAGUE ) ) gain /= 4; if( IS_AFFECTED( ch, AFF_BLEEDING ) ) gain /= 2; gain = UMAX( 1, gain ); if( ch->move > ch->max_move ) ch->move = UMAX( ch->max_move, ch->move - 2000 / gain ); else ch->move = UMIN( ch->max_move, ch->move + gain ); } void gain_condition( CHAR_DATA *ch, int iCond, int value ) { int condition; if( value == 0 || IS_NPC( ch ) || ( ch->level >= LEVEL_HERO && iCond != COND_DRUNK ) ) return; condition = ch->pcdata->condition[iCond]; switch( iCond ) { case COND_FULL: ch->pcdata->condition[iCond] = URANGE( 0, condition + value, race_table[ch->race].hunger_mod * 10 ); break; case COND_THIRST: ch->pcdata->condition[iCond] = URANGE( 0, condition + value, race_table[ch->race].thirst_mod * 10 ); break; case COND_DRUNK: ch->pcdata->condition[iCond] = URANGE( 0, condition + value, 1000 ); break; } if( ch->pcdata->condition[iCond] == 0 ) { switch( iCond ) { case COND_FULL: send_to_char( "You are hungry.\n\r", ch ); break; case COND_THIRST: send_to_char( "You are thirsty.\n\r", ch ); break; case COND_DRUNK: if( condition != 0 ) send_to_char( "You are sober.\n\r", ch ); break; } } return; } /* * Update the weather. */ void weather_update( void ) { DESCRIPTOR_DATA *d; char buf[MAX_STRING_LENGTH]; int diff; PLANE_DATA *pPlane; for( pPlane = plane_list; pPlane; pPlane = pPlane->next ) { buf[0] = '\0'; switch( ++pPlane->time.hour ) { case 6: pPlane->weather.sunlight = SUN_RISE; strcat( buf, "&bThe &Ysun&b peeks over the eastern horizon.&n\n\r" ); break; case 7: pPlane->weather.sunlight = SUN_LIGHT; strcat( buf, "&bThe sky brightens into &yday&b.&n\n\r" ); break; case 19: pPlane->weather.sunlight = SUN_SET; strcat( buf, "&bThe &Ysun&b sinks below the western horizon.&n\n\r" ); break; case 20: pPlane->weather.sunlight = SUN_DARK; strcat( buf, "&KNight&b covers the land in a blanket of &Kdarkness&b.&n\n\r" ); break; case 24: pPlane->time.hour = 0; pPlane->time.day++; break; } if( pPlane->time.day >= 35 ) { pPlane->time.day = 0; pPlane->time.month++; } if( pPlane->time.month >= 17 ) { pPlane->time.month = 0; pPlane->time.year++; } /* * Weather change. */ pPlane->weather.winddir += number_range( 0, 2 ) - 1; if( pPlane->time.month >= 9 && pPlane->time.month <= 16 ) diff = pPlane->weather.mmhg > 985 ? -2 : 2; else diff = pPlane->weather.mmhg > 1015 ? -2 : 2; pPlane->weather.change += diff * dice( 1, 4 ) + dice( 2, 6 ) - dice( 2, 6 ); pPlane->weather.change = UMAX( pPlane->weather.change, -12 ); pPlane->weather.change = UMIN( pPlane->weather.change, 12 ); pPlane->weather.mmhg += pPlane->weather.change; pPlane->weather.mmhg = UMAX( pPlane->weather.mmhg, 960 ); pPlane->weather.mmhg = UMIN( pPlane->weather.mmhg, 1040 ); switch( pPlane->weather.sky ) { default: bug( "Weather_update: bad sky %d.", pPlane->weather.sky ); pPlane->weather.sky = SKY_CLOUDLESS; break; case SKY_CLOUDLESS: if( pPlane->weather.mmhg < 990 || ( pPlane->weather.mmhg < 1010 && number_bits( 2 ) == 0 ) ) { if( pPlane->time.month <= 4 || pPlane->time.month >= 15 ) { strcat( buf, "&bA few &wsnow flakes&b drift down from the grey sky.&n\n\r" ); pPlane->weather.temperature -= number_fuzzy( 5 ); } else strcat( buf, "&wClouds&b begin to build in the sky.&n\n\r" ); pPlane->weather.sky = SKY_CLOUDY; pPlane->weather.windspeed += number_fuzzy( 10 ); } break; case SKY_CLOUDY: if( pPlane->weather.mmhg < 970 || ( pPlane->weather.mmhg < 990 && number_bits( 2 ) == 0 ) ) { if( pPlane->time.month <= 4 || pPlane->time.month >= 15 ) { strcat( buf, "&wIcy cold &Wsnow&b begins to fall.&n\n\r" ); pPlane->weather.temperature -= number_fuzzy( 5 ); } else strcat( buf, "&bThe sky opens up and it starts &craining&b.&n\n\r" ); pPlane->weather.sky = SKY_RAINING; pPlane->weather.windspeed += number_fuzzy( 10 ); } if( pPlane->weather.mmhg > 1030 && number_bits( 2 ) == 0 ) { if( pPlane->time.month <= 4 || pPlane->time.month >= 15 ) { strcat( buf, "&bThe &wsnow&b gradually lets up.&n\n\r" ); pPlane->weather.temperature += number_fuzzy( 5 ); } else strcat( buf, "&bThe &wclouds&b clear and &cblue sky&b shows through.&n\n\r" ); pPlane->weather.sky = SKY_CLOUDLESS; pPlane->weather.windspeed -= number_fuzzy( 10 ); } break; case SKY_RAINING: if( pPlane->weather.mmhg < 970 && number_bits( 2 ) == 0 ) { if( pPlane->time.month <= 4 || pPlane->time.month >= 15 ) { strcat( buf, "&bA churning &f&Wblizzard&n&b surrounds you.&n\n\r" ); pPlane->weather.temperature -= number_fuzzy( 16 ); } else strcat( buf, "&bHuge bolts of &Wlightning&b &fflash&n&b in the sky.&n\n\r" ); pPlane->weather.sky = SKY_LIGHTNING; pPlane->weather.windspeed += number_fuzzy( 10 ); } if( pPlane->weather.mmhg > 1030 || ( pPlane->weather.mmhg > 1010 && number_bits( 2 ) == 0 ) ) { if( pPlane->time.month <= 4 || pPlane->time.month >= 15 ) { strcat( buf, "&bThe rain swiftly subsides, leaving leaden skies.&n\n\r" ); pPlane->weather.temperature += number_fuzzy( 16 ); } else strcat( buf, "&bThe &crain&b stops.&n\n\r" ); pPlane->weather.sky = SKY_CLOUDY; pPlane->weather.windspeed -= number_fuzzy( 10 ); } break; case SKY_LIGHTNING: if( pPlane->weather.mmhg > 1010 || ( pPlane->weather.mmhg > 990 && number_bits( 2 ) == 0 ) ) { if( pPlane->time.month <= 4 || pPlane->time.month >= 15 ) { strcat( buf, "&bThe sheets of churning &wice&b slowly turns to a light mist.&n\n\r" ); pPlane->weather.temperature += number_fuzzy( 5 ); } else strcat( buf, "&bThe storm quietens and the &Wlightning&b stops.&n\n\r" ); pPlane->weather.sky = SKY_RAINING; pPlane->weather.windspeed -= number_fuzzy( 10 ); break; } break; } if( buf[0] != '\0' ) { for( d = descriptor_list; d; d = d->next ) { if( !IS_SET( d->interpreter->flags, INTERPRETER_NOMESSAGE ) && IS_OUTSIDE( d->character ) && IS_AWAKE( d->character ) && !xIS_SET( CH(d)->act, PLR_BUSY ) && CH(d)->in_room->area->plane == pPlane ) send_to_char( buf, d->character ); } } pPlane->weather.temperature = ( pPlane->time.hour < 3 ) ? 0 - pPlane->time.hour : ( ( pPlane->time.hour < 16 ) ? pPlane->time.hour / 2 - 3 : ( 23 - pPlane->time.hour ) / 2 ); switch( pPlane->weather.sky ) { case SKY_CLOUDLESS: pPlane->weather.temperature += number_fuzzy( 3 ); break; case SKY_RAINING: pPlane->weather.temperature -= number_fuzzy( 5 ); break; default: break; } if( pPlane->weather.mmhg < 980 ) { pPlane->weather.temperature -= number_range( 2, 6 ); } else if( pPlane->weather.mmhg > 1020 ) { pPlane->weather.temperature += number_range( 2, 6 ); } else { pPlane->weather.temperature = number_fuzzy( pPlane->weather.temperature ); } } return; } /* * Update all chars, including mobs. * This function is performance sensitive. */ void char_update( void ) { CHAR_DATA *ch; CHAR_DATA *ch_save; CHAR_DATA *ch_quit; time_t save_time; int dmg; ch_save = NULL; ch_quit = NULL; save_time = current_time; for( ch = char_list; ch; ch = ch->next ) { AFFECT_DATA *paf; if( ch->deleted ) continue; /* * Find dude with oldest save time. */ if( !IS_NPC( ch ) && ( !ch->desc || !IS_SET( ch->desc->interpreter->flags, INTERPRETER_SAFE ) ) && ch->level >= 2 && ch->save_time < save_time ) { ch_save = ch; save_time = ch->save_time; } if( ch->fighting && IS_AFFECTED( ch, AFF_FAST_TALK ) && UMIN( 18, ( ch->fighting->level - ch->level + 12 ) ) < number_range( 0, 25 ) ) { act( "$n is convinced by $N not to attack $M.", ch->fighting, NULL, ch, TO_NOTVICT ); act( "$n is convinced of your harmlessness.", ch->fighting, NULL, ch, TO_VICT ); stop_fighting( ch, TRUE ); } if( !IS_NPC( ch ) && ch->pcdata->familiar > 0 ) { ch->pcdata->familiar -= power( 60 + ch->level, 5, 20 - get_curr_int( ch ) ); if( ch->pcdata->familiar <= 0 ) { ch->pcdata->familiar = 0; send_to_char( "Your familiar sighs and disappears in a puff of smoke.\n\r", ch ); } } if( IS_AFFECTED( ch, AFF_BLEEDING ) ) { OBJ_DATA *blood = NULL; if( ch->in_room && !( blood = get_obj_list( ch, "blood", ch->in_room->contents ) ) ) { blood = create_object( get_obj_index( OBJ_VNUM_BLOOD_STAIN ), 0 ); obj_to_room( blood, ch->in_room ); } if( blood ) set_timer_tick( blood, number_range( 3, 5 ) ); act( "$n is bleeding profusely.", ch, NULL, NULL, TO_ROOM ); send_to_char( "You are bleeding quite badly.\n\r", ch ); if( IS_NPC( ch ) && !ch->fighting && ch->position >= POS_STANDING && number_bits( 5 ) < 9 ) do_tend( ch, "" ); } if( IS_AFFECTED( ch, AFF_PLAGUE ) && ch->in_room->area->nplayer > 0 ) spell_mass_plague( gsn_mass_plague, ch->level, ch, NULL ); if( IS_AFFECTED( ch, AFF_POISON ) && IS_AFFECTED( ch, AFF_POISONRESIST ) && number_bits( 1 ) ) { act( "$n fights off the effects of the poison.", ch, NULL, NULL, TO_ALL ); affect_strip( ch, gsn_poison ); xREMOVE_BIT( ch->affected_by, AFF_POISON ); } if( ch->position >= POS_STUNNED ) { hit_gain( ch ); mana_gain( ch ); move_gain( ch ); } if( ch->position == POS_STUNNED ) update_pos( ch ); if( !IS_NPC( ch ) && ( ch->level < LEVEL_IMMORTAL || ( !ch->desc && !IS_SWITCHED( ch ) ) ) ) { OBJ_DATA *obj; for( obj = ch->carrying; obj; obj = obj->next ) { if( obj->deleted || obj->item_type != ITEM_LIGHT ) continue; if( obj->value[2] <= 0 || obj->wear_loc == WEAR_NONE ) { switch( obj->value[0] ) { case 1: act( "$p carried by $n flickers and sputters.", ch, obj, NULL, TO_ROOM ); act( "$p flickers and sputters.", ch, obj, NULL, TO_CHAR ); break; case 2: act( "$p carried by $n flickers.", ch, obj, NULL, TO_ROOM ); act( "$p flickers.", ch, obj, NULL, TO_CHAR ); break; case 3: act( "$p carried by $n flickers slightly.", ch, obj, NULL, TO_ROOM ); act( "$p flickers slightly.", ch, obj, NULL, TO_CHAR ); break; } continue; } if( --obj->value[2] == 0 && ch->in_room ) { if( IS_SET( obj->extra_flags, ITEM_DARK ) ) ch->in_room->light += 30; else if( IS_SET( obj->extra_flags, ITEM_GLOW ) ) ch->in_room->light -= 20; else ch->in_room->light -= 10; act( "$p goes out.", ch, obj, NULL, TO_ROOM ); act( "$p goes out.", ch, obj, NULL, TO_CHAR ); extract_obj( obj ); } } if( ++ch->pcdata->timer >= 10 && !IS_IMMORTAL( ch ) ) { if( !ch->was_in_room && ch->in_room ) { ch->was_in_room = ch->in_room; if( ch->fighting ) stop_fighting( ch, TRUE ); act( "$n disappear$% into the void.", ch, NULL, NULL, TO_ALL ); save_char_obj( ch ); char_from_room( ch ); char_to_room( ch, get_room_index( ROOM_VNUM_LIMBO ) ); } } if( ch->pcdata->timer > 20 && !IS_IMMORTAL( ch ) ) ch_quit = ch; gain_condition( ch, COND_DRUNK, -100 - get_curr_con( ch ) * 2 ); if( !IS_AFFECTED( ch, AFF_GHOUL ) ) { float i; i = race_table[ch->race].hunger_mod; i = -35 * log( i / 100 ) - 50; gain_condition( ch, COND_FULL, ( int )i ); i = race_table[ch->race].thirst_mod; i = -35 * log( i / 100 ) - 50; gain_condition( ch, COND_THIRST, ( int )i ); } } for( paf = ch->affected; paf; paf = paf->next ) { if( paf->deleted ) continue; /* * Incubus' continuous spell effect. * there is the possibility that this function could create * problems if it kills the character (deleted checks are * required from here on in when a ch is referred to). * If you know of a better way, tell me. */ if( paf->type == gsn_continuous_effect ) { /* hit the character with the spell... */ ( *skill_table[paf->location].spell_fun ) ( paf->location, URANGE( 1, paf->modifier, LEVEL_HERO * 2 ), ch, ch ); if( ch->deleted || ch->position == POS_DEAD ) break; } if( paf->duration > 0 ) paf->duration--; else if( paf->duration < 0 ) /* permanent */ ; else { if( !paf->next || paf->next->type != paf->type || paf->next->duration > 0 ) { if( paf->type > 0 && skill_table[paf->type].msg_off ) { send_to_char( skill_table[paf->type].msg_off, ch ); send_to_char( "\n\r", ch ); } } if( paf->type == gsn_vampiric_bite ) { AFFECT_DATA *pnaf; pnaf = new_affect( ); pnaf->type = gsn_vampiric_bite; pnaf->location = APPLY_RACE; pnaf->modifier = race_lookup( "Vampire" ) - ch->race; pnaf->duration = 1000; vset( pnaf->bitvector, AFF_POLYMORPH ); xSET_BIT( pnaf->bitvector, AFF_VAMP_BITE ); pnaf->next = ch->affected; ch->affected = pnaf; } affect_remove( ch, paf ); if( ch->deleted || ch->position == POS_DEAD ) break; } } if( !ch->deleted && !IS_NPC( ch ) ) juggle_shuffle( ch ); if( ch->deleted || ch->position == POS_DEAD ) continue; /* * Careful with the damages here, * MUST NOT refer to ch after damage taken, * as it may be lethal damage (on NPC). */ if( ( ch->in_room->area->plane->time.hour > 5 && ch->in_room->area->plane->time.hour < 21 ) && IS_SET( race_table[ch->race].race_abilities, RACE_NO_SUN ) && ch->in_room->sector_type != SECT_INSIDE && !IS_SET( ch->in_room->room_flags, ROOM_UNDERGROUND ) && !IS_SET( ch->in_room->room_flags, ROOM_INDOORS ) && !room_is_dark( ch->in_room ) ) { if( IS_NPC( ch ) ) dmg = 2; else if( ch->in_room->sector_type == SECT_INSIDE ) dmg = 5; else if( ch->in_room->sector_type == SECT_FOREST ) dmg = 8; else dmg = 15; if( ch->in_room->area->plane->weather.sky == SKY_CLOUDY ) dmg /= 2; if( ch->in_room->area->plane->weather.sky == SKY_RAINING ) { dmg *= 3; dmg /= 4; } damage( ch, ch, ch->hit * dmg / 100, gsn_plague, WEAR_NONE ); } else if( IS_AFFECTED( ch, AFF_POISON ) ) { dmg = number_range( ch->hit / 30, ch->hit / 20 ); act( "$n shiver$% and suffer$%.", ch, NULL, NULL, TO_ALL ); damage( ch, ch, dmg, gsn_poison, WEAR_NONE ); } else if( IS_AFFECTED( ch, AFF_PLAGUE ) ) { dmg = number_range( ch->hit / 30, ch->hit / 20 ); if( IS_NPC( ch ) ) dmg /= 20; act( "You feel your blood turning to molten lead.", ch, NULL, NULL, TO_CHAR ); act( "$n shiver$% and suffer$%.", ch, NULL, NULL, TO_ROOM ); damage( ch, ch, dmg, gsn_plague, WEAR_NONE ); } else if( ch->position == POS_INCAP ) damage( ch, ch, 1, TYPE_UNDEFINED, WEAR_NONE ); else if( ch->position <= POS_MORTAL ) damage( ch, ch, 2, TYPE_UNDEFINED, WEAR_NONE ); } /* * Autosave and autoquit. * Check that these chars still exist. */ if( ch_save || ch_quit ) { for( ch = char_list; ch; ch = ch->next ) { if( ch->deleted ) continue; if( ch == ch_save ) save_char_obj( ch ); if( ch == ch_quit ) do_quit( ch, "" ); } } return; } /* * Aggress. * * for each mortal PC * for each mob in room * aggress on some random PC * * This function takes .2% of total CPU time. * * -Kahn */ void aggr_update( void ) { CHAR_DATA *ch; CHAR_DATA *mch, *mchnext; CHAR_DATA *vch; CHAR_DATA *victim; DESCRIPTOR_DATA *d; /* * Let's not worry about link dead characters. -Kahn */ for( d = descriptor_list; d; d = d->next ) { ch = d->character; if( IS_SET( d->interpreter->flags, INTERPRETER_SAFE ) || ch->level >= LEVEL_IMMORTAL || !ch->in_room || number_bits( 1 ) ) continue; /* mch wont get hurt */ for( mch = ch->in_room->people; mch; mch = mchnext ) { int count; bool hate = FALSE; mchnext = mch->next_in_room; if( !IS_NPC( mch ) || mch->deleted || mch->fighting || !IS_AWAKE( mch ) || IS_AFFECTED( mch, AFF_CHARM ) || IS_AFFECTED( mch, AFF_CALM ) || ( xIS_SET( mch->act, ACT_WIMPY ) && IS_AWAKE( ch ) && !IS_AFFECTED( ch, AFF_TAUNT ) ) || !can_see( mch, ch ) ) continue; if( ( xIS_SET( mch->act, ACT_RACIST ) || IS_AFFECTED( ch, AFF_TAUNT ) ) && !str_infix( race_table[ch->race].name, race_table[mch->race].hate ) ) hate = TRUE; if( !xIS_SET( mch->act, ACT_AGGRESSIVE ) && !hate && ( !xIS_SET( mch->act, ACT_ASSIST ) || !IS_AFFECTED( ch, AFF_TAUNT ) || number_bits( 3 ) != 0 ) ) continue; /* * Ok we have a 'ch' player character and a 'mch' npc aggressor. * Now make the aggressor fight a RANDOM pc victim in the room, * giving each 'vch' an equal chance of selection. */ count = 0; victim = NULL; for( vch = mch->in_room->people; vch; vch = vch->next_in_room ) { if( IS_NPC( vch ) || vch->deleted || vch->level >= LEVEL_IMMORTAL || ( IS_AFFECTED( vch, AFF_SNEAK ) && number_bits( 4 ) != 0 ) || !can_see( mch, vch ) ) continue; if( ( !hate && ( !xIS_SET( mch->act, ACT_WIMPY ) || !IS_AWAKE( vch ) ) ) || ( hate && !str_infix( race_table[vch->race].name, race_table[mch->race].hate ) ) ) { if( IS_AFFECTED( vch, AFF_TAUNT ) ) { if( number_range( 0, count / 2 ) == 0 ) { victim = vch; break; } } else if( number_range( 0, count ) == 0 ) victim = vch; count++; } } if( !victim || IS_AFFECTED( victim, AFF_GHOUL ) ) continue; if( !IS_AFFECTED( victim, AFF_FAST_TALK ) || UMIN( ( mch->level - victim->level + 8 ), 30 ) >= ( number_percent( ) / 2 ) ) { if( hate ) act( "$N screams wildly and attacks $n!", victim, NULL, mch, TO_ALL ); multi_hit( mch, victim, TYPE_UNDEFINED ); } } /* mch loop */ } /* descriptor loop */ return; } /* Update the check on time for autoshutdown */ void time_update( void ) { FILE *fp; char buf[MAX_STRING_LENGTH]; if( SysInfo->down_time <= 0 ) return; if( current_time == SysInfo->down_time - 225 ) { sprintf( buf, "First Warning!\n\r%s in %d minutes or %d seconds.\n\r", IS_SET( SysInfo->flags, SYSINFO_REBOOT ) ? "Reboot" : "Shutdown", (int)( SysInfo->down_time - current_time ) / 60, (int)( SysInfo->down_time - current_time ) ); send_to_all_char( buf ); } if( current_time == SysInfo->down_time - 150 ) { sprintf( buf, "Second Warning!\n\r%s in %d minutes or %d seconds.\n\r", IS_SET( SysInfo->flags, SYSINFO_REBOOT ) ? "Reboot" : "Shutdown", (int)( SysInfo->down_time - current_time ) / 60, (int)( SysInfo->down_time - current_time ) ); send_to_all_char( buf ); } if( current_time == SysInfo->down_time - 10 ) { sprintf( buf, "Final Warning!\n\r%s in 10 seconds.\n\r", IS_SET( SysInfo->flags, SYSINFO_REBOOT ) ? "Reboot" : "Shutdown" ); send_to_all_char( buf ); } if( current_time > SysInfo->down_time ) { sprintf( buf, "%s by system.\n\r", IS_SET( SysInfo->flags, SYSINFO_REBOOT ) ? "Reboot" : "Shutdown" ); send_to_all_char( buf ); log_string( buf ); end_of_game( ); if( !IS_SET( SysInfo->flags, SYSINFO_REBOOT ) ) { if( !( fp = open_file( SHUTDOWN_FILE, "a", FALSE ) ) ) { perror( SHUTDOWN_FILE ); bug( "Could not open the Shutdown file!" ); } else { fprintf( fp, "Shutdown by System\n" ); close_file( fp ); } } merc_down = TRUE; } return; } /* * Remove deleted EXTRA_DESCR_DATA from objects. * Remove deleted AFFECT_DATA from chars and objects. * Remove deleted CHAR_DATA and OBJ_DATA from char_list and object_list. */ void list_update( void ) { CHAR_DATA *ch; CHAR_DATA *ch_next; CHAR_DATA *ch_prev = NULL; OBJ_DATA *obj; OBJ_DATA *obj_next; OBJ_DATA *obj_prev = NULL; AFFECT_DATA *paf; AFFECT_DATA *paf_next; AFFECT_DATA *paf_prev; if( delete_char ) for( ch = char_list; ch; ch = ch_next ) { paf_prev = NULL; for( paf = ch->affected; paf; paf = paf_next ) { paf_next = paf->next; if( paf->deleted || ch->deleted ) { if( !paf_prev ) ch->affected = paf->next; else paf_prev->next = paf->next; paf->next = affect_free; affect_free = paf; } else paf_prev = paf; } ch_next = ch->next; if( ch->deleted ) { if( !ch_prev ) char_list = ch->next; else ch_prev->next = ch->next; free_char( ch ); } else ch_prev = ch; } if( delete_obj ) for( obj = object_list; obj; obj = obj_next ) { EXTRA_DESCR_DATA *ed; EXTRA_DESCR_DATA *ed_next; if( obj->deleted ) for( ed = obj->extra_descr; ed; ed = ed_next ) { ed_next = ed->next; free_string( ed->description ); free_string( ed->keyword ); ed->next = extra_descr_free; extra_descr_free = ed; } paf_prev = NULL; for( paf = obj->affected; paf; paf = paf_next ) { paf_next = paf->next; if( paf->deleted || obj->deleted ) { if( !paf_prev ) obj->affected = paf->next; else paf_prev->next = paf->next; paf->next = affect_free; affect_free = paf; } else paf_prev = paf; } obj_next = obj->next; if( obj->deleted ) { if( !obj_prev ) object_list = obj->next; else obj_prev->next = obj->next; free_string( obj->name ); free_string( obj->description ); free_string( obj->short_descr ); --obj->pIndexData->count; obj->next = obj_free; obj_free = obj; } else obj_prev = obj; } delete_obj = FALSE; delete_char = FALSE; return; } /* * Handle all kinds of updates. * Called once per pulse from game loop. * Random times to defeat tick-timing clients and players. */ void update_handler( void ) { static int pulse_auction; static int pulse_db_dump; /* OLC 1.1b */ static int pulse_quest; event_update(); if( --pulse_point <= 0 ) { wiznet( NULL, WIZ_TICKS, L_SEN, "Update tick." ); pulse_point = number_range( PULSE_TICK / 2, 3 * PULSE_TICK / 2 ); weather_update( ); list_update( ); } else if( pulse_point == 2 ) char_update( ); if( --pulse_auction <= 0 ) { pulse_auction = PULSE_VIOLENCE * 3; update_auction( ); } /* OLC 1.1b */ if( --pulse_db_dump <= 0 ) { wiznet( NULL, WIZ_TICKS, L_BLD, "Dump Area pulse (OLC)" ); pulse_db_dump = PULSE_DB_DUMP; db_dump(); } else if( pulse_db_dump == 5 ) wiznet( NULL, WIZ_TICKS, L_JUN, "Area dump incoming..." ); else if( pulse_db_dump == 10 ) do_dupefind( NULL, "" ); if( --pulse_quest <= 0 ) { pulse_quest = 60 * PULSE_PER_SECOND; quest_update(); } update_act_progs(); aggr_update( ); time_update( ); spam_update( ); return; } void pop( OBJ_DATA *vobj, OBJ_DATA *obj ) { CHAR_DATA *carried, *victim, *vnext; if( vobj->in_obj ) { extract_obj( vobj ); return; } if( ( carried = vobj->carried_by ) ) { ( *skill_table[gsn_explosive].spell_fun ) ( gsn_explosive, vobj->value[0] * 2, carried, (void *)carried ); victim = carried->in_room->people; } else { victim = vobj->in_room->people; } for( ; victim; victim = vnext ) { vnext = victim->next_in_room; if( vobj != obj ) act( "$p is set off by $P!", victim, vobj, obj, TO_CHAR ); if( victim->deleted || victim == carried ) continue; ( *skill_table[gsn_explosive].spell_fun ) ( gsn_explosive, vobj->value[0], victim, (void *)victim ); } extract_obj( vobj ); } void explode( OBJ_DATA *obj ) { CHAR_DATA *victim, *vnext; ROOM_INDEX_DATA *room = NULL; int i; OBJ_DATA *vobj = NULL, *obj_next; if( obj->in_room ) room = obj->in_room; else if( obj->carried_by && obj->carried_by->in_room ) room = obj->carried_by->in_room; for( i = 0; room && i < 6; ++i ) { if( room->exit[i] ) send_to_room( "You hear a loud explosion nearby.", room->exit[i]->to_room ); } if( obj->carried_by ) vobj = obj->carried_by->carrying; else if( obj->in_room ) vobj = obj->in_room->contents; else if( obj->in_obj ) { OBJ_DATA *in_obj; vobj = obj->in_obj->contains; for( in_obj = vobj; in_obj->in_obj; in_obj = in_obj->in_obj ) ; if( in_obj->carried_by ) act( "You hear a muffled explosion from inside $p", in_obj->carried_by, in_obj, NULL, TO_ALL ); else if( in_obj->in_room->people ) act( "You hear a muffled explosion from inside $p", in_obj->in_room->people, in_obj, NULL, TO_ALL ); } for( ; vobj; vobj = obj_next ) { obj_next = vobj->next_content; if( !vobj->deleted && vobj->item_type == ITEM_EXPLOSIVE && obj != vobj ) pop( vobj, obj ); } /* it was muffled, just extract the obj and leave. */ if( obj->in_obj ) { extract_obj( obj ); return; } /* go through the inventories of everyone in the room. * all explosives carried go off too. */ if( obj->in_room ) victim = obj->in_room->people; else victim = obj->carried_by->in_room->people; for( ; victim; victim = vnext ) { vnext = victim->next_in_room; if( victim->deleted || victim == obj->carried_by ) continue; for( vobj = victim->carrying; vobj; vobj = obj_next ) { obj_next = vobj->next_content; if( !vobj->deleted && vobj->item_type == ITEM_EXPLOSIVE && obj != vobj ) pop( vobj, obj ); } } pop( obj, obj ); return; } /* * Slot a character into the highest list where they should go * This assumes that they will be higher than they last were, * or at the very least the same position in the list * any modifications downward will need editing of the HIGHEST_FILE */ #define NEW_HIGHESTLIST( hightype ) \ for( high = highest_first; high; high = high->next ) \ { \ if( !str_cmp( high->type, (hightype) ) ) \ break; \ } \ if( !high ) \ { \ high = alloc_perm( sizeof( *high ) ); \ high->type = str_dup( (hightype) ); \ high->entries[0] = new_highent( ); \ high->entries[0]->name = str_dup( ch->name ); \ high->entries[0]->level = ch->level; \ high->entries[0]->sublevel = ch->sublevel; \ high->entries[0]->class = ch->class; \ high->entries[0]->race = ch->race; \ for( j = 1; j < 10; ++j ) \ high->entries[j] = NULL; \ if( !highest_first ) \ highest_first = high; \ if( highest_last ) \ highest_last->next = high; \ highest_last = high; \ } void update_highest_list( CHAR_DATA *ch ) { HIGHEST_DATA *high; int i, j; char buf[MAX_INPUT_LENGTH]; bool congrats = FALSE; if( IS_NPC( ch ) || get_trust( ch ) >= L_APP || ch->level < 5 ) return; for( high = highest_first; high; high = high->next ) { if( ( strcmp( high->type, "TopTen" ) || IS_IMMORTAL( ch ) ) && str_cmp( high->type, class_table[ch->class].name ) && str_cmp( high->type, race_table[ch->race].name ) ) continue; for( i = 0; high->entries[i] && i < 10; ++i ) { if( ch->level >= high->entries[i]->level || ( ch->level == high->entries[i]->level && ch->sublevel >= high->entries[i]->sublevel ) ) break; } if( i >= 10 ) continue; for( j = i; j < 10; ++j ) { if( high->entries[j] && !str_cmp( high->entries[j]->name, ch->name ) ) break; } if( j == i ) continue; if( j > i ) /* if they are moving up */ { char temp[MAX_INPUT_LENGTH]; if( !congrats ) { sprintf( buf, "Congratulations %s!\n\r", ch->name ); send_to_char( buf, ch ); } else congrats = TRUE; if( i ) sprintf( temp, "You are now the %d%s highest", i + 1, ( i + 1 == 2 ) ? "nd" : ( i + 1 == 3 ) ? "rd" : "th" ); else strcpy( temp, "You are now the highest" ); strcpy( buf, temp ); if( !strcmp( high->type, "TopTen" ) ) strcat( buf, " character overall.\n\r" ); else sprintf( buf, "%s %s overall.\n\r", temp, high->type ); send_to_char( buf, ch ); } j = UMIN( j, 9 ); if( high->entries[j] ) free_highent( high->entries[j] ); for( ; j > i; --j ) high->entries[j] = high->entries[j - 1]; high->entries[i] = new_highent( ); high->entries[i]->name = str_dup( ch->name ); high->entries[i]->level = ch->level; high->entries[i]->sublevel = ch->sublevel; high->entries[i]->class = ch->class; high->entries[i]->race = ch->race; } NEW_HIGHESTLIST( "TopTen" ); NEW_HIGHESTLIST( class_table[ch->class].name ); NEW_HIGHESTLIST( race_table[ch->race].name ); return; } void quest_update( void ) { QUEST_DATA * qq; DESCRIPTOR_DATA *d; for( d = descriptor_list; d; d = d->next ) { if( IS_SET( d->interpreter->flags, INTERPRETER_SAFE ) ) continue; qq = CH( d )->pcdata->quest; if( qq->time <= 0 ) continue; if( --qq->time == 0 ) { if( qq->type != QUEST_NONE ) { send_to_char( "You have run out of time for your quest.\n\r", d->character ); switch( qq->type ) { case QUEST_RACE_CORPSE: case QUEST_BODY_PART: free_mem( qq->target, sizeof( struct quest_race_corpse ) ); break; case QUEST_OBJ_MATERIAL: free_mem( qq->target, sizeof( struct quest_obj_material ) ); break; } qq->target = NULL; qq->type = QUEST_NONE; qq->time = 30; } else send_to_char( "You may now quest again.\n\r", d->character ); } else { qq->reward = qq->reward * number_fuzzy( 9 ) / 10; if( qq->time <= 3 && qq->type != QUEST_NONE ) send_to_char( "Better hurry, you are almost" " out of time for your quest.\n\r", d->character ); } } return; } void spam_update( void ) { DESCRIPTOR_DATA *d; for( d = descriptor_list; d; d = d->next ) { if( !IS_SET( d->interpreter->flags, INTERPRETER_NOMESSAGE ) ) purge_spam( d->character->in_room ); } } void purge_spam( ROOM_INDEX_DATA *room ) { CHAR_DATA *ch, *vch, *victim; static const char *const him_her[] = { "it", "him", "her" }; char buf[ MAX_INPUT_LENGTH ]; char buf1[256]; char buf2[256]; char buf3[256]; char buf4[256]; char buf5[256]; char tmp[25]; char punct, *point; int i; for( ch = room->people; ch; ch = ch->next_in_room ) { if( !ch->fighting || ch->num_hits < 0 ) continue; victim = ch->fighting; for( i = 0; dam_table[i].max_dam >= 0; i++ ) { if( dam_table[i].max_dam >= ch->tot_dam ) break; } punct = ( ch->tot_dam <= 100 ) ? '.' : '!'; if( ch->tot_dam > 0 ) { sprintf( buf1, "Your %d attack%s %s %%s&n%c%%s\n\r", ch->num_hits, ch->num_hits > 1 ? "s" : "", dam_table[i].mesg, punct ); sprintf( buf2, "%%s&n's %d attack%s %s you%c%%s\n\r", ch->num_hits, ch->num_hits > 1 ? "s" : "", dam_table[i].mesg, punct ); sprintf( buf3, "%%s&n's %d attack%s %s %%s&n%c%%s\n\r", ch->num_hits, ch->num_hits > 1 ? "s" : "", dam_table[i].mesg, punct ); sprintf( buf4, "Your %d attack%s %s you%c%%s\n\r", ch->num_hits, ch->num_hits > 1 ? "s" : "", dam_table[i].mesg, punct ); sprintf( buf5, "%%s&n's %d attack%s %s %%s%c%%s\n\r", ch->num_hits, ch->num_hits > 1 ? "s" : "", dam_table[i].mesg, punct ); } else { strcpy( buf1, "Your attacks haven't hurt %s&n!%s\n\r" ); strcpy( buf2, "%s&n's attacks haven't hurt you!%s\n\r" ); strcpy( buf3, "%s&n's attacks haven't hurt %s&n!%s\n\r" ); strcpy( buf4, "Your attacks haven't hurt you!%s\n\r" ); strcpy( buf5, "%s&n's attacks haven't hurt %s!%s\n\r" ); } for( vch = room->people; vch; vch = vch->next_in_room ) { if( !vch->desc || !IS_AWAKE( vch ) || ( ( vch == ch || vch == victim ) && !xIS_SET( CH(vch->desc)->act, PLR_BATTLESELF ) ) || ( ( vch != ch && vch != victim ) && !xIS_SET( CH(vch->desc)->act, PLR_BATTLEOTHER ) ) ) continue; if( vch == ch ) { if( ch == victim ) sprintf( buf, buf4, dam_amount( tmp, vch, ch->tot_dam ) ); else sprintf( buf, buf1, PERS( victim, vch ), dam_amount( tmp, vch, ch->tot_dam ) ); } else if( vch == victim ) sprintf( buf, buf2, PERS( ch, vch ), dam_amount( tmp, vch, ch->tot_dam ) ); else if( ch == victim ) sprintf( buf, buf5, PERS( ch, vch ), him_her[URANGE( 0, ch->sex, 2 )], dam_amount( tmp, vch, ch->tot_dam ) ); else sprintf( buf, buf3, PERS( ch, vch ), PERS( victim, vch ), dam_amount( tmp, vch, ch->tot_dam ) ); point = &buf[0]; while( *point == '&' ) point += 2; *point = UPPER( *point ); send_to_char( buf, vch ); } ch->num_hits = -1; ch->tot_dam = 0; } for( ch = room->people; ch; ch = ch->next_in_room ) { if( ch->desc && ch->tot_xp > 0 && !IS_SET( ch->desc->interpreter->flags, INTERPRETER_SAFE ) && xIS_SET( CH( ch->desc )->act, PLR_BATTLESELF|PLR_BATTLEOTHER ) ) { if( ch->tot_xp >= 2500 ) charprintf( ch, "&gYou gained %d experience that round.&n\n\r", ch->tot_xp / 100 ); else charprintf( ch, "&gYou gained %d.%2.2d experience that round.&n\n\r", ch->tot_xp / 100, ch->tot_xp % 100 ); } ch->tot_xp = 0; } }