/***************************************************************************
* 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. *
* *
* Envy Diku Mud improvements copyright (C) 1994 by Michael Quan, David *
* Love, Guilherme 'Willie' Arnold, and Mitchell Tse. *
* *
* In order to use any part of this Envy Diku Mud, you must comply with *
* the original Diku license in 'license.doc', the Merc license in *
* 'license.txt', as well as the Envy license in 'license.nvy'. *
* In particular, you may not remove either of these copyright notices. *
* *
* 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. *
***************************************************************************/
/*$Id: update.c,v 1.32 2005/03/31 14:33:31 ahsile Exp $*/
#if defined( macintosh )
#include <types.h>
#else
#include <sys/types.h>
#endif
#include <stdio.h>
#include <string.h>
#include <time.h>
#include "merc.h"
/*
* Externals
*/
extern bool merc_down;
extern int auc_count;
extern void auc_channel( char *auction );
extern int port;
extern void userl_save( void );
int pulse_db_dump;
extern void do_timequake( CHAR_DATA *ch, char *argument );
/*
* Globals
*/
bool delete_obj;
bool delete_char;
/*
* Local functions.
*/
int hit_gain args( ( CHAR_DATA *ch ) );
int mana_gain args( ( CHAR_DATA *ch ) );
int move_gain args( ( CHAR_DATA *ch ) );
void mobile_update args( ( void ) );
void weather_update args( ( void ) );
void char_update args( ( void ) );
void obj_update args( ( void ) );
void aggr_update args( ( void ) );
void comb_update args( ( void ) ); /* XOR */
void auc_update args( ( void ) ); /* Altrag */
void rdam_update args( ( void ) ); /* Altrag */
void strew_corpse args( ( OBJ_DATA *obj, AREA_DATA *inarea ) );
void orprog_update args( ( void ) );
void trap_update args( ( void ) );
void rtime_update args( ( void ) ); /* Timed room progs */
void quest_update args( ( void ) );
void rquest_update args( ( void ) );
void craft_update args( ( void ) );
void timed_room_update args(( void) ); /* temporary room flags */
#ifdef TIMEQUAKE
void rand_update args( ( void ) );
#endif
/*
* Advancement stuff.
*/
void advance_level( CHAR_DATA *ch )
{
char buf [ MAX_STRING_LENGTH ];
int add_hp;
int add_mana;
int add_move;
int add_prac;
if ( !IS_SET( ch->act, PLR_KEEPTITLE ) )
{
sprintf( buf, "the %s",
title_table [ch->class] [ch->level] [ch->sex == SEX_FEMALE ? 1 : 0] );
set_title( ch, buf );
}
add_hp = con_app[get_curr_con( ch )].hitp + number_range(
class_table[ch->class].hp_min,
class_table[ch->class].hp_max );
add_mana = class_table[ch->class].fMana
? number_range(2, ( 12 * get_curr_int( ch ) + get_curr_wis( ch ) ) / 6 )
: 0;
add_move =
number_range( 5, ( get_curr_con( ch ) + get_curr_dex( ch ) ) / 4 );
add_prac = wis_app[get_curr_wis( ch )].practice;
if( ch->race == 0 )
{
add_prac += 1;
}
if( ch->class == ch->multied )
{
add_prac += 1;
}
add_hp = UMAX( 1, add_hp );
add_mana = UMAX( 0, add_mana );
add_move = UMAX( 10, add_move );
if(ch->level == LEVEL_DEMIGOD)
{
add_hp = 4000;
add_mana = 1000;
}
ch->max_hit += add_hp;
if (( ch->class != CLASS_VAMPIRE )&&(ch->class != CLASS_ANTI_PALADIN))
ch->max_mana += add_mana;
else
{
add_mana -= add_mana / 2;
ch->max_bp += add_mana;
}
ch->max_move += add_move;
ch->practice += add_prac;
if ( !IS_NPC( ch ) )
REMOVE_BIT( ch->act, PLR_BOUGHT_PET );
if (( ch->class != CLASS_VAMPIRE )&&(ch->class != CLASS_ANTI_PALADIN))
sprintf( buf,
"Your gain is: %d/%d hp, %d/%d m, %d/%d mv %d/%d prac.\n\r",
add_hp, ch->max_hit,
add_mana, ch->max_mana,
add_move, ch->max_move,
add_prac, ch->practice );
else
sprintf( buf,
"Your gain is: %d/%d hp, %d/%d bp, %d/%d mv %d/%d prac.\n\r",
add_hp, ch->max_hit,
add_mana, ch->max_bp,
add_move, ch->max_move,
add_prac, ch->practice );
send_to_char(AT_WHITE, buf, ch );
save_char_obj( ch, FALSE );
if( ch->hit < ch->max_hit )
{
ch->hit = ch->max_hit;
}
if (( ch->class != CLASS_VAMPIRE) && ( ch->class != CLASS_ANTI_PALADIN ))
{
if( ch->mana < ch->max_mana )
{
ch->mana = ch->max_mana;
}
}
else
{
if( ch->bp < ch->max_bp )
{
ch->bp = ch->max_bp;
}
}
if( ch->move < ch->max_move )
{
ch->move = ch->max_move;
}
return;
}
void gain_exp( CHAR_DATA *ch, int gain )
{
if ( IS_NPC( ch ) || ch->exp >= MAX_EXPERIENCE )
return;
ch->exp = UMAX( 1000, ch->exp + gain );
if ( ch->level < 100 && ch->exp >= 1000 * ( ch->level + 1 ) )
{
send_to_char(AT_BLUE, "You raise a level!! ", ch );
ch->level += 1;
advance_level( ch );
if(ch->level >= 50 )
{
SET_BIT ( ch->act, PLR_GHOST );
}
sprintf( log_buf, "%s has risen to level %d.", ch->name, ch->level );
if( !IS_AFFECTED3( ch, AFF_STEALTH ) )
{
broadcast_channel( ch, log_buf, CHANNEL_INFO, "!!SOUND(clap1.wav V=100 L=1 P=50 T=Info)");
}
sprintf( log_buf, "%s has risen to level %d.", ch->name, ch->level );
log_string( log_buf, CHANNEL_LOG, -1 );
}
if ( ch->level == LEVEL_HERO && ch->exp >= 1500 + 1000 * (ch->level + 1) )
{
send_to_char(AT_BLUE, "You raise a champion level!! ", ch );
ch->level += 1;
advance_level( ch );
sprintf( log_buf, "%s has risen to level %d.", ch->name, ch->level );
if( !IS_AFFECTED3( ch, AFF_STEALTH ) )
{
broadcast_channel( ch, log_buf, CHANNEL_INFO, "!!SOUND(welcome2.wav V=100 L=1 P=75 T=Info)");
}
}
if ( ch->level == LEVEL_HERO1 && ch->exp >= 5500 + 1000 * (ch->level + 1) )
{
send_to_char(AT_BLUE, "You raise a champion level!! ", ch );
ch->level += 1;
advance_level( ch );
sprintf( log_buf, "%s has risen to level %d.", ch->name, ch->level );
if( !IS_AFFECTED3( ch, AFF_STEALTH ) )
{
broadcast_channel( ch, log_buf, CHANNEL_INFO, "!!SOUND(welcome2.wav V=100 L=1 P=75 T=Info)");
}
sprintf( log_buf, "%s has risen to level %d.", ch->name, ch->level );
log_string( log_buf, CHANNEL_LOG, -1 );
}
if ( ch->level == LEVEL_HERO2 && ch->exp >= 12000 + 1000 * (ch->level + 1) )
{
send_to_char(AT_BLUE, "You raise a champion level!! ", ch );
ch->level += 1;
advance_level( ch );
sprintf( log_buf, "%s has risen to level %d.", ch->name, ch->level );
if( !IS_AFFECTED3( ch, AFF_STEALTH ) )
{
broadcast_channel( ch, log_buf, CHANNEL_INFO, "!!SOUND(welcome2.wav V=100 L=1 P=75 T=Info)");
}
sprintf( log_buf, "%s has risen to level %d.", ch->name, ch->level );
log_string( log_buf, CHANNEL_LOG, -1 );
}
if ( ch->level == LEVEL_HERO3 && ch->exp >= 31000 + 1000 * (ch->level + 1) )
{
send_to_char(AT_BLUE, "You raise a champion level!! ", ch );
ch->level += 1;
advance_level( ch );
sprintf( log_buf, "%s has risen to level %d.", ch->name, ch->level );
if( !IS_AFFECTED3( ch, AFF_STEALTH ) )
{
broadcast_channel( ch, log_buf, CHANNEL_INFO, "!!SOUND(welcome2.wav V=100 L=1 P=75 T=Info)");
}
sprintf( log_buf, "%s has risen to level %d.", ch->name, ch->level );
log_string( log_buf, CHANNEL_LOG, -1 );
}
if ( ch->level == LEVEL_CHAMP && ch->exp >= 95000 + 1000 * (ch->level + 1 ) )
{
send_to_char(AT_BLUE, "You are now a Demi-God!! ", ch );
ch->level += 1;
advance_level( ch );
sprintf( log_buf, "%s has risen to level %d, and is now a Demi-God.", ch->name, ch->level );
if( !IS_AFFECTED3( ch, AFF_STEALTH ) )
{
broadcast_channel( ch, log_buf, CHANNEL_INFO, "!!SOUND(welcome2.wav V=100 L=1 P=100 T=Info)");
log_string( log_buf, CHANNEL_INFO, -1 );
}
sprintf( log_buf, "%s has risen to level %d.", ch->name, ch->level );
log_string( log_buf, CHANNEL_LOG, -1 );
}
if ( ch->level == LEVEL_DEMIGOD && ch->exp >= MAX_EXPERIENCE )
{
send_to_char(AT_BLUE, "\n\r\n\rYOU ARE NOW A LEGEND!!!\n\r\n\r", ch );
sprintf( log_buf, "%s has attained the status of LEGEND.", ch->name );
broadcast_channel( ch, log_buf, CHANNEL_INFO, "!!SOUND(welcome2.wav V=100 L=1 P=100 T=Info)");
log_string( log_buf, CHANNEL_LOG, -1 );
ch->max_hit += 5000;
if (( ch->class != 9 )&&(ch->class != 11))
{
ch->max_mana += 2500;
send_to_char(AT_BLUE, "You have gained: 4000hp, 2500ma, 1000mv, and a special gift!\n\r", ch );
}
else
{
ch->max_bp += 2500;
send_to_char(AT_BLUE, "You have gained: 4000hp, 2500bp, 1000mv, and a special gift!\n\r", ch );
}
ch->max_move += 1000;
if( !IS_SET(ch->act, PLR_HOLYLIGHT) )
{
SET_BIT(ch->act, PLR_HOLYLIGHT);
}
}
return;
}
/*
* Regeneration stuff.
*/
int hit_gain( CHAR_DATA *ch )
{
CHAR_DATA *gch;
int gain = 0;
int racehpgainextra = 0;
if ( IS_AFFECTED3( ch, AFF_CLOUD_OF_HEALING ) )
{
for ( gch = ch->in_room->people; gch; gch = gch->next_in_room )
{
send_to_char(AT_YELLOW, "A cloud of healing engulfs the room!\n\r",gch);
if ((gch->hit + gch->level*5) > gch->max_hit)
gch->hit = gch->max_hit;
else
gch->hit = gch->hit + gch->level*5;
}
}
if ( IS_AFFECTED4( ch, AFF_BURROW ) )
{
gain += ch->level * 10;
if (!str_cmp(ch->name, "Vemon"))
{
gain *= 2;
}
}
if ( ( ch->race == 10 )
|| ( ch->race == 11 ) )
{
racehpgainextra = 2;
}
if ( ( ch->race == 9 )
|| ( ch->race == 13 ) )
{
racehpgainextra = 3;
}
if ( ch->race == 14 )
{
racehpgainextra = 10;
}
if ( ch->race == 17 )
{
racehpgainextra = 15;
}
if ( IS_NPC( ch ) )
{
gain = ch->level * 3 / 2;
}
else
{
gain += UMIN( 5, ch->level );
switch ( ch->position )
{
case POS_SLEEPING: gain += ch->level * 4; break;
case POS_RESTING: gain += get_curr_con( ch ) * 4 / 2; break;
}
if ( ch->pcdata->condition[COND_FULL ] == 0 )
gain /= 2;
if ( ch->pcdata->condition[COND_THIRST] == 0 )
gain /= 2;
}
if ( IS_AFFECTED( ch, AFF_POISON ) )
gain /= 10;
if ( IS_AFFECTED3( ch, AFF_PESTILENCE ) )
gain = 0;
if ( IS_AFFECTED3( ch, AFF_TORTURE ) )
gain = 0;
if (!IS_NPC( ch ) && ( ch->pcdata->learned[skill_lookup("rapid healing")] / 10 ) > 0 )
{
gain *= ch->pcdata->learned[skill_lookup("rapid healing")] / 200;
update_skpell( ch, skill_lookup("rapid healing"), 0 );
}
return UMIN( gain, ch->max_hit - ch->hit );
}
int mana_gain( CHAR_DATA *ch )
{
int gain;
if ( IS_NPC( ch ) )
{
gain = ch->level;
}
else
{
gain = UMIN( 20, ch->level / 2 );
switch ( ch->position )
{
case POS_SLEEPING: gain += get_curr_int( ch ) * 12; break;
case POS_RESTING: gain += get_curr_int( ch ) * 12 / 2; break;
}
if ( ch->pcdata->condition[COND_FULL ] == 0 )
gain /= 2;
if ( ch->pcdata->condition[COND_THIRST] == 0 )
gain /= 2;
}
if ( ( ch->race == 2 )
|| ( ch->race == 40 ) )
gain += ch->level / 2;
if ( IS_AFFECTED( ch, AFF_POISON ) )
gain /= 10;
if ( IS_AFFECTED3( ch, AFF_PESTILENCE ) )
gain = 0;
if ( IS_AFFECTED3( ch, AFF_TORTURE ) )
gain = 0;
return UMIN( gain, ch->max_mana - ch->mana );
}
int move_gain( CHAR_DATA *ch )
{
int gain;
if ( IS_NPC( ch ) )
{
gain = ch->level;
}
else
{
gain = UMAX( 15, 2 * ch->level );
switch ( ch->position )
{
case POS_SLEEPING: gain += get_curr_dex( ch ) * 4; break;
case POS_RESTING: gain += get_curr_dex( ch ) * 2; break;
}
if ( ch->pcdata->condition[COND_FULL ] == 0 )
gain /= 2;
if ( ch->pcdata->condition[COND_THIRST] == 0 )
gain /= 2;
}
if ( ( ch->race == 21 )
|| ( ch->race == 25 )
|| ( ch->race == 34 ) )
gain += ch->level / 2;
if ( IS_AFFECTED( ch, AFF_POISON ) )
gain /= 10;
if ( IS_AFFECTED3( ch, AFF_PESTILENCE ) )
gain = 0;
if ( IS_AFFECTED3( ch, AFF_TORTURE ) )
gain = 0;
return UMIN( gain, ch->max_move - ch->move );
}
void gain_condition( CHAR_DATA *ch, int iCond, int value )
{
int condition;
if ( value == 0 || IS_NPC( ch ) || ch->level >= L_APP )
return;
if ( ch->level >= LEVEL_HERO && iCond != COND_DRUNK )
return;
if ( ch->position == POS_GHOST )
return;
condition = ch->pcdata->condition[ iCond ];
ch->pcdata->condition[iCond] = URANGE( 0, condition + value, 48 );
if ( ch->pcdata->condition[iCond] == 0 )
{
switch ( iCond )
{
case COND_FULL:
send_to_char(AT_ORANGE, "You are hungry.\n\r", ch );
/* if( ( ch->hit ) > (ch->level * 11 ) )
{
damage(ch, ch, ch->level * 10, gsn_poison);
} */
break;
case COND_THIRST:
send_to_char(AT_BLUE, "You are thirsty.\n\r", ch );
break;
case COND_DRUNK:
if ( condition != 0 )
send_to_char(AT_BLUE, "You are sober.\n\r", ch );
break;
}
}
return;
}
/*
* Mob autonomous action.
* This function takes 25% of ALL Merc cpu time.
* -- Furey
*/
void mobile_update( void )
{
CHAR_DATA *ch;
EXIT_DATA *pexit;
int door;
/* Examine all mobs. */
for ( ch = char_list; ch; ch = ch->next )
{
if ( ch->deleted )
continue;
if ( IS_NPC(ch) && (ch->wait -= PULSE_MOBILE) < 0 )
ch->wait = 0;
if ( !IS_NPC( ch )
|| !ch->in_room
|| IS_AFFECTED( ch, AFF_STUN )
|| IS_AFFECTED( ch, AFF_CHARM )
|| ch->wait > 0 )
continue;
/* Examine call for special procedure */
if ( ch->spec_fun != 0 )
{
if ( ( *ch->spec_fun ) ( ch ) )
continue;
}
/* That's all for sleeping / busy monster */
if ( ch->position < POS_STANDING )
continue;
if ( ch->in_room->area->nplayer > 0 )
{
mprog_random_trigger( ch );
if ( ch->position < POS_STANDING )
continue;
}
/* Scavenge */
if ( IS_SET( ch->act, ACT_SCAVENGER )
&& ch->in_room->contents
&& number_bits( 2 ) == 0 )
{
OBJ_DATA *obj;
OBJ_DATA *obj_best;
int max;
max = 1;
obj_best = 0;
for ( obj = ch->in_room->contents; obj; obj = obj->next_content )
{
if ( CAN_WEAR( obj, ITEM_TAKE )
&& obj->cost > max
&& can_see_obj( ch, obj ) )
{
obj_best = obj;
max = obj->cost;
}
}
if ( obj_best )
{
obj_from_room( obj_best );
obj_to_char( obj_best, ch );
act(AT_GREY, "$n gets $p.", ch, obj_best, NULL, TO_ROOM );
}
}
/* Wander */
if ( !IS_SET( ch->act, ACT_SENTINEL )
&& ( door = number_bits( 5 ) ) <= 5
&& ( pexit = ch->in_room->exit[door] )
&& pexit->to_room
&& !IS_SET( pexit->exit_info, EX_CLOSED )
&& !IS_SET( pexit->to_room->room_flags, ROOM_NO_MOB )
&& !ch->hunting
&& ( !IS_SET( ch->act, ACT_STAY_AREA )
|| pexit->to_room->area == ch->in_room->area ) )
{
move_char( ch, door );
if ( ch->position < POS_STANDING )
continue;
}
/* Flee */
if ( ch->hit < ( ch->max_hit / 2 )
&& ( door = number_bits( 3 ) ) <= 5
&& ( pexit = ch->in_room->exit[door] )
&& pexit->to_room
&& !IS_SET( pexit->exit_info, EX_CLOSED )
&& !IS_SET( pexit->to_room->room_flags, ROOM_NO_MOB ) )
{
CHAR_DATA *rch;
bool found;
found = FALSE;
for ( rch = pexit->to_room->people;
rch;
rch = rch->next_in_room )
{
if ( rch->deleted )
continue;
if ( !IS_NPC( rch ) )
{
found = TRUE;
break;
}
}
if ( !found )
move_char( ch, door );
}
hunt_victim( ch );
}
MOBtrigger = TRUE;
return;
}
/*
* Update the weather.
*/
void weather_update( void )
{
DESCRIPTOR_DATA *d;
char buf [ MAX_STRING_LENGTH ];
char buf2 [ MAX_STRING_LENGTH ];
int diff;
char buf3 [ MAX_STRING_LENGTH ];
buf[0] = '\0';
buf2[0] = '\0';
buf3[0] = '\0';
userl_save();
switch ( ++time_info.hour )
{
case 1:
time_info.total++;
/* Adds 1 to the TOTAL NUMBER OF DAYS the mud has been up */
break;
case 5:
weather_info.sunlight = SUN_LIGHT;
strcat( buf, "&cThe day has begun." );
break;
case 6:
weather_info.sunlight = SUN_RISE;
strcat( buf, "The &Ysun&B rises in the east." );
break;
case 19:
weather_info.sunlight = SUN_SET;
strcat( buf, "The &Ysun&B slowly disappears in the west." );
break;
case 20:
weather_info.sunlight = SUN_DARK;
strcat( buf, "&zThe night has begun.&w" );
sprintf(buf3, "!!SOUND(cricket2.wav V=100 L=1 P=50 T=Background)");
break;
case 24:
time_info.hour = 0;
time_info.day++;
break;
}
if ( time_info.day >= NUMBER_OF_DAYS_TO_RESET )
{
time_info.day = 0;
time_info.month++;
}
if ( time_info.month >= 12 )
{
time_info.month = 0;
time_info.year++;
}
if ( !(time_info.total % NUMBER_OF_DAYS_TO_RESET) && time_info.total && !time_info.hour)
{
do_resetxp(NULL, "all");
}
if ( time_info.total >= NUMBER_OF_DAYS_TO_REBOOT - 3 && time_info.hour == 23 )
{
sprintf( buf2, "A system reboot will occur very soon." );
log_string( buf2, CHANNEL_INFO, -1 );
}
if ( time_info.total >= NUMBER_OF_DAYS_TO_REBOOT )
{
send_to_all_char("You feel compelled to rest, for a little while,\n\r as the sun sets upon the end of this year.\n\r");
end_of_game();
merc_down = TRUE;
return;
}
/*
* Weather change.
*/
if ( time_info.month >= 9 && time_info.month <= 16 )
diff = weather_info.mmhg > 985 ? -2 : 2;
else
diff = weather_info.mmhg > 1015 ? -2 : 2;
weather_info.change += diff * dice( 1, 4 ) + dice( 2, 6 ) - dice( 2, 6 );
weather_info.change = UMAX( weather_info.change, -12 );
weather_info.change = UMIN( weather_info.change, 12 );
weather_info.mmhg += weather_info.change;
weather_info.mmhg = UMAX( weather_info.mmhg, 960 );
weather_info.mmhg = UMIN( weather_info.mmhg, 1040 );
switch ( weather_info.sky )
{
default:
bug( "Weather_update: bad sky %d.", weather_info.sky );
weather_info.sky = SKY_CLOUDLESS;
break;
case SKY_CLOUDLESS:
if ( weather_info.mmhg < 990
|| ( weather_info.mmhg < 1010 && number_bits( 2 ) == 0 ) )
{
strcat( buf, "The sky is getting &zcloudy." );
weather_info.sky = SKY_CLOUDY;
sprintf( buf3, "!!SOUND(wind3.wav V=100 L=1 P=50 T=Background)");
}
break;
case SKY_CLOUDY:
if ( weather_info.mmhg < 970
|| ( weather_info.mmhg < 990 && number_bits( 2 ) == 0 ) )
{
strcat( buf, "It starts to rain." );
weather_info.sky = SKY_RAINING;
sprintf(buf3, "!!SOUND(rain1.wav V=100 L=1 P=50 T=Background)");
}
if ( weather_info.mmhg > 1030 && number_bits( 2 ) == 0 )
{
strcat( buf, "The &zclouds&B disappear." );
weather_info.sky = SKY_CLOUDLESS;
sprintf(buf3, "!!SOUND(birds4.wav V=100 L=1 P=50 T=Background)");
}
break;
case SKY_RAINING:
if ( weather_info.mmhg < 970 && number_bits( 2 ) == 0 )
{
strcat( buf, "&WLightning&B flashes in the sky." );
weather_info.sky = SKY_LIGHTNING;
sprintf(buf3, "!!SOUND(thunder5.wav V=100 L=1 P=50 T=Background)");
}
if ( weather_info.mmhg > 1030
|| ( weather_info.mmhg > 1010 && number_bits( 2 ) == 0 ) )
{
strcat( buf, "The rain stopped." );
weather_info.sky = SKY_CLOUDY;
sprintf(buf3, "!!SOUND(birds4.wav V=100 L=1 P=50 T=Background)");
}
break;
case SKY_LIGHTNING:
if ( weather_info.mmhg > 1010
|| ( weather_info.mmhg > 990 && number_bits( 2 ) == 0 ) )
{
strcat( buf, "The &Wlightning&B has stopped." );
weather_info.sky = SKY_RAINING;
sprintf(buf3, "!!SOUND(rain1.wav V=100 L=1 P=50 T=Background)");
break;
}
break;
}
if ( buf[0] != '\0' )
{
for ( d = descriptor_list; d; d = d->next )
{
if ( d->connected == CON_PLAYING
&& IS_OUTSIDE( d->character )
&& IS_AWAKE ( d->character )
&& !IS_SET( d->character->in_room->room_flags, ROOM_INDOORS ) )
{
send_to_char(AT_BLUE, buf, d->character );
if( IS_SET( d->character->act, PLR_SOUND ) )
{
send_to_char(AT_BLUE, buf3, d->character );
}
send_to_char(AT_BLUE, "\n\r", d->character );
}
}
}
return;
}
/*
* Update the bank system
* (C) 1996 The Maniac from Mythran Mud
*
* This updates the shares value (I hope)
*/
void bank_update(void)
{
int value = 0;
FILE *fp;
if ((time_info.hour < 9) || (time_info.hour > 17))
return; /* Bank is closed, no market... */
value = number_range ( 0, 200);
value -= 100;
value /= 10;
share_value += value;
if( share_value < 5 || share_value > 195 )
{
share_value = 100;
}
if ( !( fp = fopen ( BANK_FILE, "w" ) ) )
{
bug( "bank_update: fopen of BANK_FILE failed", 0 );
return;
}
fprintf (fp, "SHARE_VALUE %d\n\r", share_value);
fclose(fp);
}
/*
* 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;
CHAR_DATA *ch_next; /* XOR */
time_t save_time;
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 || ch->desc->connected == CON_PLAYING )
&& ch->level >= 2
&& ch->save_time < save_time )
{
ch_save = ch;
save_time = ch->save_time;
}
if ( ch->position >= POS_STUNNED )
{
if ( ch->hit < ch->max_hit )
{
ch->hit += hit_gain( ch );
}
if (IS_AFFECTED4(ch, AFF_BURROW) && ch->hit >= ch->max_hit)
{
affect_strip(ch, skill_lookup("tomba di vemon"));
send_to_char(AT_ORANGE, "The earth has healed you!\n\r",ch);
act(AT_ORANGE, "$n rises from the earth!\n\r",ch,NULL,NULL,TO_ROOM);
}
if ( ch->mana < ch->max_mana )
ch->mana += mana_gain( ch );
if ( ch->move < ch->max_move )
ch->move += move_gain( ch );
if ( ch->position == POS_STUNNED )
{
ch->position = POS_STANDING;
update_pos( ch );
}
}
if (is_affected(ch, skill_lookup("berserk"))
&& !ch->fighting )
{
affect_strip( ch, skill_lookup("berserk") );
send_to_char(AT_WHITE, "The rage leaves you.\n\r", ch );
}
if (IS_AFFECTED2(ch, AFF_BERSERK)
&& !ch->fighting )
{
REMOVE_BIT( ch->affected_by2, AFF_BERSERK );
}
if (is_affected(ch, skill_lookup("bloodthirsty"))
&& !ch->fighting )
{
affect_strip( ch, skill_lookup("bloodthirsty") );
send_to_char(AT_WHITE, "Your lust for blood fades.\n\r", ch );
}
if (IS_AFFECTED3(ch, AFF_BLOODTHIRSTY)
&& !ch->fighting )
{
REMOVE_BIT( ch->affected_by3, AFF_BLOODTHIRSTY );
}
if (is_affected(ch, skill_lookup("force of nature"))
&& !ch->fighting )
{
affect_strip(ch, skill_lookup("force of nature") );
ch->shields -= 1;
send_to_char(AT_GREEN, "The force of nature leaves your soul.\n\r", ch );
}
if (IS_AFFECTED4(ch, AFF_FORCE_OF_NATURE)
&& !ch->fighting )
{
REMOVE_BIT( ch->affected_by4, AFF_FORCE_OF_NATURE );
}
if ( ch->position == POS_STUNNED )
update_pos( ch );
if ( !IS_NPC( ch ) && (( time(NULL) - ch->pkill_timer) > 600 ) ){
ch->pkill_timer = 0;
}
if ( ch->mountcharmed > 0 )
{
ch->mountcharmed--;
}
if ( !IS_NPC( ch ) && ( ch->level < LEVEL_IMMORTAL
|| ( !ch->desc && !IS_SWITCHED( ch ) ) ) )
{
OBJ_DATA *obj;
if ( ( obj = get_eq_char( ch, WEAR_LIGHT ) )
&& obj->item_type == ITEM_LIGHT
&& obj->value[2] > 0 )
{
if ( --obj->value[2] == 0 && ch->in_room )
{
--ch->in_room->light;
act(C_DEFAULT, "$p goes out.", ch, obj, NULL, TO_ROOM );
act(C_DEFAULT, "$p goes out.", ch, obj, NULL, TO_CHAR );
extract_obj( obj );
}
}
if ( ++ch->timer >= 10 )
{
if ( !ch->was_in_room && ch->in_room )
{
ch->was_in_room = ch->in_room;
if ( ch->fighting )
stop_fighting( ch, TRUE );
send_to_char(AT_GREEN, "You disappear into the void.\n\r", ch );
act(AT_GREEN, "$n disappears into the void.",
ch, NULL, NULL, TO_ROOM );
save_char_obj( ch, FALSE );
char_from_room( ch );
char_to_room( ch, get_room_index( ROOM_VNUM_LIMBO ) );
}
}
if ( ch->timer > 20 && !IS_SWITCHED( ch ) )
ch_quit = ch;
gain_condition( ch, COND_DRUNK, -8 );
gain_condition( ch, COND_FULL, -1 );
gain_condition( ch, COND_THIRST, -1 );
}
for ( paf = ch->affected; paf; paf = paf->next )
{
if ( paf->deleted )
continue;
if ( paf->duration > 0 )
paf->duration--;
else if ( paf->duration < 0 )
;
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(C_DEFAULT, skill_table[paf->type].msg_off, ch );
send_to_char(C_DEFAULT, "\n\r", ch );
}
}
affect_remove( ch, paf );
if ( paf->type > 0 && skill_table[paf->type].shield_bit == SHIELD_YES )
{
ch->shields -= 1;
}
if ( paf->type == AFF_FLYING )
check_nofloor( ch );
}
}
for ( paf = ch->affected2; paf; paf = paf->next )
{
if ( paf->deleted )
continue;
if ( paf->duration > 0 )
paf->duration--;
else if ( paf->duration < 0 )
;
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(C_DEFAULT, skill_table[paf->type].msg_off, ch );
send_to_char(C_DEFAULT, "\n\r", ch );
}
}
affect_remove2( ch, paf );
if ( paf->type > 0 && skill_table[paf->type].shield_bit == SHIELD_YES )
{
ch->shields -= 1;
}
}
}
for ( paf = ch->affected3; paf; paf = paf->next )
{
if ( paf->deleted )
continue;
if ( paf->duration > 0 )
paf->duration--;
else if ( paf->duration < 0 )
;
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(C_DEFAULT, skill_table[paf->type].msg_off, ch );
send_to_char(C_DEFAULT, "\n\r", ch );
}
}
affect_remove3( ch, paf );
if ( paf->type > 0 && skill_table[paf->type].shield_bit == SHIELD_YES )
{
ch->shields -= 1;
}
}
}
for ( paf = ch->affected4; paf; paf = paf->next )
{
if ( paf->deleted )
continue;
if ( paf->duration > 0 )
paf->duration--;
else if ( paf->duration < 0 )
;
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(C_DEFAULT, skill_table[paf->type].msg_off, ch );
send_to_char(C_DEFAULT, "\n\r", ch );
}
}
affect_remove4( ch, paf );
if ( paf->type > 0 && skill_table[paf->type].shield_bit == SHIELD_YES )
{
ch->shields -= 1;
}
}
}
for ( paf = ch->affected_powers; paf; paf = paf->next )
{
if ( paf->deleted )
continue;
if ( paf->duration > 0 )
paf->duration--;
else if ( paf->duration < 0 )
;
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(C_DEFAULT, skill_table[paf->type].msg_off, ch );
send_to_char(C_DEFAULT, "\n\r", ch );
}
}
affect_remove_powers( ch, paf );
if ( paf->type > 0 && skill_table[paf->type].shield_bit == SHIELD_YES )
{
ch->shields -= 1;
}
}
}
for ( paf = ch->affected_weaknesses; paf; paf = paf->next )
{
if ( paf->deleted )
continue;
if ( paf->duration > 0 )
paf->duration--;
else if ( paf->duration < 0 )
;
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(C_DEFAULT, skill_table[paf->type].msg_off, ch );
send_to_char(C_DEFAULT, "\n\r", ch );
}
}
affect_remove_weaknesses( ch, paf );
if ( paf->type > 0 && skill_table[paf->type].shield_bit == SHIELD_YES )
{
ch->shields -= 1;
}
}
}
if ( ch->gspell && --ch->gspell->timer <= 0 )
{
send_to_char(AT_BLUE, "You slowly lose your concentration.\n\r",ch);
end_gspell( ch );
}
if ( ch->ctimer > 0 )
ch->ctimer--;
if ( ch->rtimer > 0 )
ch->rtimer--;
/*
* Careful with the damages here,
* MUST NOT refer to ch after damage taken,
* as it may be lethal damage (on NPC).
*/
if ( IS_AFFECTED3( ch, AFF_POWER_LEAK ) )
{
int temp = number_range(ch->level * 3, ch->level * 10 );
send_to_char(AT_CYAN, "You lose some energy.\n\r", ch );
act(AT_CYAN, "$n face looks drained.", ch, NULL, NULL,TO_ROOM);
if ((ch->mana - temp) < 0)
ch->mana = 0;
else
ch->mana = ch->mana - temp;
}
if ( IS_AFFECTED( ch, AFF_POISON ) )
{
send_to_char(AT_GREEN, "You shiver and suffer.\n\r", ch );
act(AT_GREEN, "$n shivers and suffers.", ch, NULL, NULL, TO_ROOM );
/*
damage( ch, ch, 10, gsn_poison );
*/
damage( ch, ch, ( ( ch->level/10 ) +1 ) * ( ch->poison_level ), skill_lookup("poison") );
if ( ch->poison_level > 0 )
{
ch->poison_level--;
}
if ( ch->poison_level == 0 )
{
affect_strip( ch, AFF_POISON );
}
}
else if
(
(
!IS_NPC(ch) && ch->in_room->sector_type == SECT_UNDERWATER
&& (!IS_IMMORTAL( ch ) && !IS_AFFECTED3( ch, AFF_GILLS )
&& !IS_SET( race_table[ch->race].race_abilities,
RACE_WATERBREATH ) && ch->position != POS_GHOST )
)
||
(
( !IS_NPC( ch )
&& ch->in_room->sector_type != SECT_UNDERWATER
&& ch->in_room->sector_type != SECT_WATER_NOSWIM
&& ch->in_room->sector_type != SECT_WATER_SWIM )
&& IS_SET( race_table[ ch->race ].race_abilities,
RACE_WATERBREATH )
&& ( strcmp( race_table[ ch->race ].race_name, "Object" )
&& strcmp( race_table[ ch->race ].race_name, "God" ) )
)
)
{
send_to_char( AT_BLUE, "You can't breathe!\n\r", ch );
act( AT_BLUE, "$n sputters and chokes!", ch, NULL, NULL, TO_ROOM );
damage( ch, ch, number_fuzzy(ch->level) + number_percent( ), /* TYPE_UNDEFINED */ skill_lookup("breathe water") );
}
if ( IS_AFFECTED3( ch, AFF_PESTILENCE ) )
{
send_to_char(AT_GREEN, "You suffer the wrath of Pestilence.\n\r", ch );
act(AT_GREEN, "$n's body breaks out in spores as they suffer the Pestilence.", ch, NULL, NULL, TO_ROOM );
damage( ch, ch, 400, skill_lookup("pestilence") );
}
if ( IS_AFFECTED3( ch, AFF_NAGAROMS_CURSE ) )
{
send_to_char(AT_GREEN, "You feel Nagarom watching you.\n\r", ch );
}
if ( IS_AFFECTED3( ch, AFF_TORTURE )
&& (IS_SET(ch->in_room->room_flags, ROOM_SAFE) ) )
{
send_to_char(AT_BLOOD, "Your soul feels great pain!\n\r", ch );
act(AT_BLOOD, "$n's soul is tortured!", ch, NULL, NULL, TO_ROOM );
damage( ch, ch, 500, skill_lookup("tortured soul") );
}
if ( IS_AFFECTED3( ch, AFF_DEADLY_POISON ) )
{
send_to_char(AT_GREEN, "Your body is ravaged by a deadly poison!\n\r", ch );
act(AT_GREEN, "$n's body is ravaged by a deadly poison!", ch, NULL, NULL, TO_ROOM );
damage( ch, ch, ch->hit/4, skill_lookup("deadly poison") );
}
if ( IS_AFFECTED( ch, AFF_FLAMING ) )
{
send_to_char(AT_RED, "Your skin blisters and burns.\n\r", ch );
act(AT_RED, "$n's body blisters and burns as it is licked in flames.", ch, NULL, NULL, TO_ROOM );
damage( ch, ch, ch->level/4, skill_lookup("incinerate") );
}
else if ( ch->position == POS_INCAP )
{
damage( ch, ch, 1, TYPE_UNDEFINED );
}
else if ( ch->position == POS_MORTAL )
{
damage( ch, ch, 2, TYPE_UNDEFINED );
}
}
/*
* 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, FALSE );
if ( ch == ch_quit )
do_quit( ch, "" );
}
}
/* XOR */
for(ch = char_list;ch != NULL;ch = ch_next)
{
ch_next = ch->next;
if(ch->summon_timer <= 0)
;
else
ch->summon_timer--;
if(IS_NPC(ch) && ch->summon_timer == 0)
{
extract_char(ch, TRUE);
}
}
/* END */
return;
}
/*
* Update all objs.
* This function is performance sensitive.
*/
void obj_update( void )
{
OBJ_DATA *obj;
OBJ_DATA *obj_next;
for ( obj = object_list; obj; obj = obj_next )
{
CHAR_DATA *rch;
char *message;
obj_next = obj->next;
if ( obj->deleted )
continue;
if ( obj->timer < -1 )
obj->timer = -1;
if ( obj->timer < 0 )
continue;
/*
* Bug fix: used to shift to obj_free if an object whose
* timer ran out contained obj->next. Bug was reported
* only when the object(s) inside also had timer run out
* during the same tick. --Thelonius (Monk)
*/
if ( --obj->timer == 0 )
{
AREA_DATA *inarea = NULL;
bool pccorpse = FALSE;
switch ( obj->item_type )
{
default: message = "$p vanishes."; break;
case ITEM_FOUNTAIN: message = "$p dries up."; break;
case ITEM_CORPSE_NPC: message = "$p decays into dust."; break;
case ITEM_CORPSE_PC: message = "$p decays into dust.";
pccorpse = TRUE; break;
case ITEM_FOOD: message = "$p decomposes."; break;
case ITEM_BLOOD: message = "$p soaks into the ground."; break;
case ITEM_PORTAL: message = "$p shimmers and is gone."; break;
case ITEM_VODOO: message = "$p slowly fades out of existance."; break;
case ITEM_BERRY: message = "$p rots away."; break;
}
if ( obj->carried_by )
{
act(C_DEFAULT, message, obj->carried_by, obj, NULL, TO_CHAR );
}
else
if ( obj->in_room
&& ( rch = obj->in_room->people ) )
{
act(C_DEFAULT, message, rch, obj, NULL, TO_ROOM );
act(C_DEFAULT, message, rch, obj, NULL, TO_CHAR );
}
if ( obj->in_room )
inarea = obj->in_room->area;
if ( obj == object_list )
{
if ( !pccorpse || !inarea )
{
extract_obj( obj );
obj_next = object_list;
}
else
strew_corpse( obj, inarea );
}
else /* (obj != object_list) */
{
OBJ_DATA *previous;
for ( previous = object_list; previous;
previous = previous->next )
{
if ( previous->next == obj )
break;
}
if ( !previous ) /* Can't see how, but... */
bug( "Obj_update: obj %d no longer in object_list",
obj->pIndexData->vnum );
if ( !pccorpse || !inarea )
{
extract_obj( obj );
obj_next = previous->next;
}
else
strew_corpse( obj, inarea );
}
}
}
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;
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 ( d->connected != CON_PLAYING
|| !ch
|| !ch->in_room )
continue;
/* mch wont get hurt */
for ( mch = ch->in_room->people; mch; mch = mch->next_in_room )
{
int count;
bool hate = FALSE;
/*
if ( IS_NPC( mch ) && mch->mpactnum > 0 )
{
MPROG_ACT_LIST * tmp_act, *tmp2_act;
for ( tmp_act = mch->mpact; tmp_act != NULL; tmp_act = tmp_act->next )
{
mprog_wordlist_check( tmp_act->buf,mch, tmp_act->ch, tmp_act->obj, tmp_act->vo, ACT_PROG );
}
for ( tmp_act = mch->mpact; tmp_act != NULL; tmp_act = tmp2_act )
{
mch->mpactnum--;
tmp2_act = tmp_act->next;
free_mprog_act( tmp_act );
}
if(mch->mpactnum > 0)
bug("Not all mprogs released for %d!", mch->pIndexData->vnum);
mch->mpactnum = 0;
mch->mpact = NULL;
}
*/
if ( !IS_NPC( mch )
|| mch->deleted
|| IS_AFFECTED( mch, AFF_STUN )
|| mch->fighting
|| IS_AFFECTED( mch, AFF_CHARM )
|| !IS_AWAKE( mch )
|| !can_see( mch, ch )
|| ( !IS_SET( mch->act, ACT_AGGRESSIVE )
&& ( str_infix( race_table[ch->race].race_full,
race_table[mch->race].hate )
|| ( !str_infix( race_table[ch->race].race_full,
race_table[mch->race].hate )
&& abs( mch->level - ch->level ) > 4 ) ) )
|| mch->wait > 0
|| ch->wait > 0 )
continue;
if ( !str_infix( race_table[ch->race].race_full,
race_table[mch->race].hate ) )
hate = TRUE;
if ( !IS_SET( mch->act, ACT_AGGRESSIVE )
|| (IS_SET( mch->act, ACT_WIMPY ) && IS_AWAKE( ch ) )
|| IS_AFFECTED( ch, AFF_PEACE ) || ch->position == POS_GHOST
|| IS_IMMORTAL( ch ) )
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 )
continue;
if ( ( !IS_SET( mch->act, ACT_WIMPY ) || !IS_AWAKE( vch ) )
&& can_see( mch, vch ) )
{
if ( !hate
|| ( hate
&& !str_infix( race_table[vch->race].race_full,
race_table[mch->race].hate ) ) )
{
if ( number_range( 0, count ) == 0 )
victim = vch;
count++;
}
}
}
if ( !victim )
continue;
if (!is_safe(mch, victim))
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 *curr_time;
char buf [ MAX_STRING_LENGTH ];
if ( down_time == "*" )
return;
curr_time = ctime( ¤t_time );
if ( !str_infix( warning1, curr_time ) )
{
sprintf( buf, "First Warning!\n\r%s at %s system time\n\r"
"Current time is %s\n\r",
(stype == 0 ? "Reboot" : "Shutdown"),
down_time,
curr_time );
send_to_all_char( buf );
free_string( warning1 );
warning1 = str_dup( "*" );
}
if ( !str_infix( warning2, curr_time ) )
{
sprintf( buf, "Second Warning!\n\r%s at %s system time\n\r"
"Current time is %s\n\r",
(stype == 0 ? "Reboot" : "Shutdown"),
down_time,
curr_time );
send_to_all_char( buf );
free_string( warning2 );
warning2 = str_dup( "*" );
}
if ( !str_infix( down_time, curr_time ) )
{
/* OLC 1.1b */
do_asave( NULL, "" );
if ( stype == 1 )
{
send_to_all_char( "Shutdown by system.\n\r" );
log_string( "Shutdown by system.", CHANNEL_GOD, -1 );
end_of_game( );
}
else
{
send_to_all_char( "Reboot by system.\n\r" );
log_string( "Reboot by system.", CHANNEL_GOD, -1 );
end_of_game( );
merc_down = TRUE;
return;
}
fclose( fpReserve );
if ( !( fp = fopen( SHUTDOWN_FILE, "a" ) ) )
{
perror( SHUTDOWN_FILE );
bug( "Could not open the Shutdown file!", 0 );
}
else
{
fprintf( fp, "Shutdown by System\n" );
fclose ( fp );
}
fpReserve = fopen ( NULL_FILE, "r" );
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;
OBJ_DATA *obj;
OBJ_DATA *obj_next;
extern bool delete_obj;
extern bool delete_char;
if ( delete_char )
for ( ch = char_list; ch; ch = ch_next )
{
AFFECT_DATA *paf;
AFFECT_DATA *paf_next;
for ( paf = ch->affected; paf; paf = paf_next )
{
paf_next = paf->next;
if ( paf->deleted || ch->deleted )
{
if ( ch->affected == paf )
{
ch->affected = paf->next;
}
else
{
AFFECT_DATA *prev;
for ( prev = ch->affected; prev; prev = prev->next )
{
if ( prev->next == paf )
{
prev->next = paf->next;
break;
}
}
if ( !prev )
{
bug( "List_update: cannot find paf on ch.", 0 );
sprintf( log_buf, "Char: %s", ch->name );
bug( log_buf, 0 );
continue;
}
}
free_affect( paf);
}
}
for ( paf = ch->affected2; paf; paf = paf_next )
{
paf_next = paf->next;
if ( paf->deleted || ch->deleted )
{
if ( ch->affected2 == paf )
{
ch->affected2 = paf->next;
}
else
{
AFFECT_DATA *prev;
for ( prev = ch->affected2; prev; prev = prev->next )
{
if ( prev->next == paf )
{
prev->next = paf->next;
break;
}
}
if ( !prev )
{
bug( "List_update2: cannot find paf on ch.", 0 );
sprintf( log_buf, "Char: %s", ch->name ? ch->name
: "(Unknown)" );
bug( log_buf, 0 );
continue;
}
}
free_affect( paf);
}
}
ch_next = ch->next;
if ( ch->deleted )
{
if ( ch == char_list )
{
char_list = ch->next;
} else
{
CHAR_DATA *prev;
for ( prev = char_list; prev; prev = prev->next )
{
if ( prev->next == ch )
{
prev->next = ch->next;
break;
}
}
if ( !prev )
{
char buf [ MAX_STRING_LENGTH ];
sprintf( buf, "List_update: char %s not found.", ch->name );
bug( buf, 0 );
continue;
}
}
if (ch->in_room)
{
char buf [MAX_STRING_LENGTH];
sprintf(buf, "List_update: char %s being deleted, but still in room \"%s\" (%d)", ch->name, ch->in_room->name, ch->in_room->vnum);
bug(buf,0);
extract_char(ch, TRUE);
}
free_ch( ch );
}
}
if ( delete_obj )
for ( obj = object_list; obj; obj = obj_next )
{
AFFECT_DATA *paf;
AFFECT_DATA *paf_next;
EXTRA_DESCR_DATA *ed;
EXTRA_DESCR_DATA *ed_next;
for ( ed = obj->extra_descr; ed; ed = ed_next )
{
ed_next = ed->next;
if ( obj->deleted )
{
free_extra_descr( ed );
}
}
for ( paf = obj->affected; paf; paf = paf_next )
{
paf_next = paf->next;
if ( obj->deleted )
{
if ( obj->affected == paf )
{
obj->affected = paf->next;
}
else
{
AFFECT_DATA *prev;
for ( prev = obj->affected; prev; prev = prev->next )
{
if ( prev->next == paf )
{
prev->next = paf->next;
break;
}
}
if ( !prev )
{
bug( "List_update: cannot find paf on obj.", 0 );
continue;
}
}
free_affect( paf);
}
}
obj_next = obj->next;
if ( obj->deleted )
{
if ( obj == object_list )
{
object_list = obj->next;
}
else
{
OBJ_DATA *prev;
for ( prev = object_list; prev; prev = prev->next )
{
if ( prev->next == obj )
{
prev->next = obj->next;
break;
}
}
if ( !prev )
{
bug( "List_update: obj %d not found.",
obj->pIndexData->vnum );
continue;
}
}
--obj->pIndexData->count;
free_obj( obj );
}
}
delete_obj = FALSE;
delete_char = FALSE;
return;
}
#ifdef TIMEQUAKE
void rand_update( void )
{
bug("Random Timequake Triggered", 0);
if (number_range(0,1000) > 990)
{
do_timequake(NULL, NULL);
}
}
#endif
/*
* Handle all kinds of updates.
* Called once per pulse from game loop.
*/
void update_handler( void )
{
static int pulse_quest; /* Non-Variable pulse for Timers - Ahsile */
static int pulse_area;
static int pulse_mobile;
static int pulse_violence;
static int pulse_point;
static int pulse_combat; /* XOR pkill */
#ifdef SQL_SYSTEM
static int pulse_dirty; /* Save dirty chars */
if ( --pulse_dirty <= 0 )
{
sql_save_dirty_list(TRUE);
pulse_dirty = PULSE_DIRTY;
}
#endif
#ifndef DISABLE_EDITS_SAVES
/* OLC 1.1b */
if ( --pulse_db_dump <= 0 )
{
pulse_db_dump = PULSE_DB_DUMP;
do_asave( NULL, "" );
}
#endif
if ( --pulse_quest <= 0 )
{
pulse_quest = PULSE_QUEST;
quest_update ( );
rquest_update ( );
}
if ( --pulse_area <= 0 )
{
pulse_area = number_range( PULSE_AREA / 2, 3 * PULSE_AREA / 2 );
area_update ( );
#ifdef TIMEQUAKE
rand_update ( );
#endif
}
if ( --pulse_violence <= 0 )
{
pulse_violence = PULSE_VIOLENCE;
violence_update ( );
craft_update( );
timed_room_update( );
}
if ( --pulse_mobile <= 0 )
{
pulse_mobile = PULSE_MOBILE;
mobile_update ( );
rdam_update ( );
orprog_update( );
}
#if defined (AUTO_WORLD_SAVE)
/* OLC 1.1b */
if ( --pulse_db_dump <= 0 )
{
wiznet(NULL, WIZ_TICKS, L_DIR, "Dump Area pulse (OLC)" );
pulse_db_dump = PULSE_DB_DUMP;
do_asave( NULL, "" );
}
#endif
if ( --pulse_point <= 0 )
{
pulse_point = number_range( PULSE_TICK / 2, 3 * PULSE_TICK / 2 );
weather_update ( );
rtime_update ( );
char_update ( );
obj_update ( );
list_update ( );
bank_update ( );
}
/* XOR causing alot of lag */
/* yeah yeah, see if its fixed now =) */
if(--pulse_combat <= 0)
{
pulse_combat = PULSE_PER_SECOND;
comb_update();
}
/* END */
/* Auction timer update -- Altrag */
if ( auc_count >= 0 && ++auc_count % (8 * PULSE_PER_SECOND) == 0 )
auc_update ( );
time_update( );
aggr_update( );
tail_chain( );
return;
}
/* X combat timer update */
void comb_update()
{
CHAR_DATA *ch;
for ( ch = char_list; ch != NULL; ch = ch->next )
{
if ( ch->deleted )
continue;
if(--ch->combat_timer < 0)
ch->combat_timer = 0;
}
}
/* Auctioneer timer update -- Altrag */
void auc_update()
{
extern OBJ_DATA *auc_obj;
extern CHAR_DATA *auc_held;
extern CHAR_DATA *auc_bid;
extern int auc_cost;
char buf[MAX_STRING_LENGTH];
if ( !auc_obj )
return;
if ( !auc_held )
{
bug( "Auc_update: auc_obj found without auc_held.",0);
return;
}
switch ( auc_count / (8 * PULSE_PER_SECOND) )
{
case 1:
sprintf( buf, "%s for %d gold coins (going ONCE).", auc_obj->short_descr, auc_cost );
auc_channel( buf );
sprintf( buf, "%s auctioning %s.", auc_held->name, auc_obj->name );
log_string( buf, CHANNEL_GOD, -1 );
return;
case 2:
sprintf( buf, "%s for %d gold coins (going TWICE).", auc_obj->short_descr, auc_cost );
auc_channel( buf );
sprintf( buf, "%s auctioning %s.", auc_held->name, auc_obj->name );
log_string( buf, CHANNEL_GOD, -1 );
return;
case 3:
sprintf( buf, "%s for %d gold coins (going THRICE).", auc_obj->short_descr, auc_cost );
auc_channel( buf );
sprintf( buf, "%s auctioning %s.", auc_held->name, auc_obj->name );
log_string( buf, CHANNEL_GOD, -1 );
return;
}
if ( auc_bid && auc_bid->gold >= auc_cost )
{
sprintf( buf, "%s for %d gold coins SOLD! to %s.", auc_obj->short_descr, auc_cost,
auc_bid->name );
auc_bid->gold -= auc_cost;
auc_held->gold += auc_cost;
obj_to_char( auc_obj, auc_bid );
act( AT_DGREEN, "$p appears in your hands.", auc_bid, auc_obj, NULL, TO_CHAR );
act( AT_DGREEN, "$p appears in the hands of $n.", auc_bid, auc_obj, NULL,
TO_ROOM );
}
else if ( auc_bid )
{
sprintf( buf, "%d gold coins not carried for %s, ending auction.", auc_cost, auc_obj->short_descr );
obj_to_char( auc_obj, auc_held );
act( AT_DGREEN, "$p appears in your hands.", auc_held, auc_obj, NULL, TO_CHAR );
act( AT_DGREEN, "$p appears in the hands of $n.", auc_held, auc_obj, NULL, TO_ROOM );
}
else
{
sprintf( buf, "%s not sold, ending auction.", auc_obj->short_descr );
obj_to_char( auc_obj, auc_held );
act( AT_DGREEN, "$p appears in your hands.", auc_held, auc_obj, NULL, TO_CHAR );
act( AT_DGREEN, "$p appears in the hands of $n.", auc_held, auc_obj, NULL,
TO_ROOM );
}
auc_channel( buf );
auc_count = -1;
auc_cost = 0;
auc_obj = NULL;
auc_held = NULL;
auc_bid = NULL;
return;
}
void rdam_update( )
{
DESCRIPTOR_DATA *d;
CHAR_DATA *ch;
for ( d = descriptor_list; d; d = d->next )
{
if ( d->connected != CON_PLAYING )
continue;
ch = d->original ? d->original : d->character;
if ( !( ch->in_room ) )
continue;
if ( ch->level < L_APP && ch->position != POS_GHOST )
if ( IS_SET( ch->in_room->room_flags, ROOM_DAMAGE ) )
{
if ( ch->hit <= ch->in_room->rd )
{
send_to_char( AT_RED, "Pain shoots through your body.\n\r", ch );
}
damage( ch, ch, ch->in_room->rd, TYPE_UNDEFINED );
}
}
return;
}
/* Wind timer routines.. needs updates for weather stuff.. -- Altrag */
const char *dir_wind [] = {"north", "northeast", "east", "southeast",
"south", "southwest", "west", "northwest"};
/* END */
void strew_corpse( OBJ_DATA *obj, AREA_DATA *inarea )
{
OBJ_DATA *currobj;
ROOM_INDEX_DATA *newroom;
OBJ_DATA *cobj_next;
for ( currobj = obj->contains; currobj; currobj = cobj_next )
{
cobj_next = currobj->next_content;
switch( currobj->item_type )
{
case ITEM_FOOD:
case ITEM_DRINK_CON:
currobj->value[3] = 1;
break;
case ITEM_POTION:
if ( number_percent( ) < 20 )
{
extract_obj( currobj );
continue;
}
break;
default: break;
}
if ( number_percent( ) < 2 )
{
extract_obj( currobj );
continue;
}
if ( number_percent( ) < 30 )
{
obj_from_obj( currobj );
obj_to_room( currobj, obj->in_room );
}
else
{
obj_from_obj( currobj );
newroom = get_room_index( number_range( inarea->lvnum, inarea->uvnum ) );
for ( ; !newroom; )
newroom = get_room_index( number_range( inarea->lvnum, inarea->uvnum ) );
obj_to_room( currobj, newroom );
}
}
extract_obj( obj );
return;
}
void orprog_update( void )
{
OBJ_DATA *obj;
OBJ_DATA *obj_next;
AREA_DATA *pArea;
for ( obj = object_list; obj; obj = obj_next )
{
obj_next = obj->next;
if ( obj->deleted )
continue;
/* ie: carried or in room */
if ( !obj->in_obj && !obj->stored_by &&
((obj->in_room && obj->in_room->area->nplayer) ||
(obj->carried_by && obj->carried_by->in_room &&
obj->carried_by->in_room->area->nplayer)) )
oprog_random_trigger( obj );
}
for ( pArea = area_first; pArea; pArea = pArea->next )
if ( pArea->nplayer > 0 )
{
int room;
ROOM_INDEX_DATA *pRoom;
for ( room = pArea->lvnum; room <= pArea->uvnum; room++ )
if ( (pRoom = get_room_index( room )) )
rprog_random_trigger( pRoom );
}
return;
}
void trap_update( void )
{
TRAP_DATA *pTrap;
for ( pTrap = trap_list; pTrap; pTrap = pTrap->next )
if ( --pTrap->disarm_dur <= 0 )
{
pTrap->disarm_dur = 0;
pTrap->disarmed = FALSE;
}
return;
}
void rtime_update( void )
{
AREA_DATA *pArea;
for ( pArea = area_first; pArea; pArea = pArea->next )
if ( pArea->nplayer )
{
int room;
ROOM_INDEX_DATA *pRoom;
for ( room = pArea->lvnum; room <= pArea->uvnum; room++ )
if ( (pRoom = get_room_index( room )) )
rprog_time_trigger( pRoom, time_info.hour );
}
return;
}
void craft_update( void )
{
CHAR_DATA* ch;
for (ch = char_list; ch; ch = ch->next)
{
if (IS_NPC(ch)) { continue; }
if (!ch->pcdata->craft_timer) { continue; }
ch->pcdata->craft_timer -= PULSE_VIOLENCE;
if (ch->pcdata->craft_timer <= 0)
{
ch->pcdata->craft_timer = 0;
finish_craft( ch );
}
}
}
void timed_room_update( void )
{
ROOM_INDEX_DATA* room;
ROOM_INDEX_DATA* last = NULL;
for (room = timed_room_list; room; room = room->next_timed_room)
{
room->flag_timer -= PULSE_VIOLENCE;
if (room->flag_timer <= 0)
{
room->flag_timer = 0;
strip_timed_room_flags(room);
if (room == timed_room_list)
timed_room_list = room->next_timed_room;
else
last->next_timed_room = room->next_timed_room;
room->next_timed_room = NULL;
}
last = room;
}
}