/*___________________________________________________________________________*
)()( 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;
}
}