/***************************************************************************
* Original Diku Mud copyright (C) 1990, 1991 by Sebastian Hammer, *
* Michael Seifert, Hans Henrik St{rfeldt, Tom Madsen, and Katja Nyboe. *
* *
* Merc Diku Mud improvments copyright (C) 1992, 1993 by Michael *
* Chastain, Michael Quan, and Mitchell Tse. *
* *
* Ack 2.2 improvements copyright (C) 1994 by Stephen Dooley *
* *
* In order to use any part of this Merc Diku Mud, you must comply with *
* both the original Diku license in 'license.doc' as well the Merc *
* license in 'license.txt'. In particular, you may not remove either of *
* these copyright notices. *
* *
* _/ _/_/_/ _/ _/ _/ ACK! MUD is modified *
* _/_/ _/ _/ _/ _/ Merc2.0/2.1/2.2 code *
* _/ _/ _/ _/_/ _/ (c)Stephen Zepp 1998 *
* _/_/_/_/ _/ _/ _/ Version #: 4.3 *
* _/ _/ _/_/_/ _/ _/ _/ *
* *
* http://ackmud.nuc.net/ *
* zenithar@ackmud.nuc.net *
* Much time and thought has gone into this software and you are *
* benefitting. We hope that you share your changes too. What goes *
* around, comes around. *
***************************************************************************/
/***************************************************************************
* _/_/_/_/ _/ _/ _/_/_/_/ _/_/_/_/ AckFUSS is modified ACK!MUD 4.3.1 *
* _/ _/ _/ _/ _/ copyright Matt Goff (Kline) 2008 *
* _/_/ _/ _/ _/_/_/_/ _/_/_/_/ *
* _/ _/ _/ _/ _/ Support for this code is provided *
* _/ _/_/_/_/ _/_/_/_/ _/_/_/_/ at www.ackmud.net -- check it out!*
***************************************************************************/
#include <sys/time.h>
#include <sys/resource.h>
#include <stdio.h>
#include <string.h>
#include <time.h>
#include "globals.h"
#include <signal.h>
#ifndef DEC_ACT_COMM_H
#include "h/act_comm.h"
#endif
#ifndef DEC_ACT_INFO_H
#include "h/act_info.h"
#endif
#ifndef DEC_ACT_MOVE_H
#include "h/act_move.h"
#endif
#ifndef DEC_ACT_OBJ_H
#include "h/act_obj.h"
#endif
#ifndef DEC_ACT_WIZ_H
#include "h/act_wiz.h"
#endif
#ifndef DEC_AREASAVE_H
#include "h/areasave.h"
#endif
#ifndef DEC_COMM_H
#include "h/comm.h"
#endif
#ifndef DEC_DB_H
#include "h/db.h"
#endif
#ifndef DEC_FIGHT_H
#include "h/fight.h"
#endif
#ifndef DEC_HANDLER_H
#include "h/handler.h"
#endif
#ifndef DEC_MAGIC_H
#include "h/magic.h"
#endif
#ifndef DEC_MONEY_H
#include "h/money.h"
#endif
#ifndef DEC_SSM_H
#include "h/ssm.h"
#endif
extern POL_DATA politics_data;
extern OBJ_DATA *quest_object;
extern CHAR_DATA *quest_mob;
extern COUNCIL_DATA super_councils[MAX_SUPER];
extern int ssm_dup_count;
extern int ssm_loops;
extern int ssm_recent_loops;
extern OBJ_DATA *auction_item;
extern CHAR_DATA *auction_owner;
extern CHAR_DATA *auction_bidder;
extern int auction_bid;
extern int auction_reserve;
extern int auction_stage;
extern int saving_area;
extern bool auction_flop;
extern bool auto_quest;
extern bool quest;
extern int quest_timer;
extern int quest_wait;
/*
* Local functions.
*/
int hit_gain args( ( CHAR_DATA * ch ) );
int mana_gain args( ( CHAR_DATA * ch ) );
void mobile_update args( ( void ) );
void weather_update args( ( void ) );
void char_update args( ( void ) );
void gain_update args( ( void ) );
void obj_update args( ( void ) );
void aggr_update args( ( void ) );
void objfun_update args( ( void ) );
void rooms_update args( ( void ) );
void remember_attack args( ( CHAR_DATA * ch, CHAR_DATA * victim ) );
void quest_update args( ( void ) );
/*
* IMC2 keeps quietly losing sync to the server. Going to let
* it run the keepalive routine so I can stay connected. --Kline
*/
#ifdef IMC
void imc_delete_reminfo args(( REMOTEINFO * p ));
void imc_request_keepalive args(( void ));
#endif
int abort_threshold = BOOT_DB_ABORT_THRESHOLD;
bool disable_timer_abort = FALSE;
int last_checkpoint;
int get_user_seconds( )
{
struct rusage rus;
getrusage( RUSAGE_SELF, &rus );
return rus.ru_utime.tv_sec;
}
/* Update the checkpoint */
void alarm_update( )
{
char *strtime;
char buf[MSL];
ssm_dup_count = 0;
ssm_loops = 0;
last_checkpoint = get_user_seconds( );
if( abort_threshold == BOOT_DB_ABORT_THRESHOLD )
{
abort_threshold = RUNNING_ABORT_THRESHOLD;
strtime = ctime( ¤t_time );
strtime[strlen( strtime ) - 1] = '\0';
snprintf( buf, MSL, "Used %d user CPU seconds.", last_checkpoint );
fprintf( stderr, "%s :: %s\n", strtime, buf );
}
}
#ifndef WIN32
/* Set the virtual (CPU time) timer to the standard setting, ALARM_FREQUENCY */
void reset_itimer( )
{
struct itimerval itimer;
itimer.it_interval.tv_usec = 0; /* miliseconds */
itimer.it_interval.tv_sec = ALARM_FREQUENCY;
itimer.it_value.tv_usec = 0;
itimer.it_value.tv_sec = ALARM_FREQUENCY;
/*
* start the timer - in that many CPU seconds, alarm_handler will be called
*/
if( setitimer( ITIMER_VIRTUAL, &itimer, NULL ) < 0 )
{
perror( "reset_itimer:setitimer" );
exit( 1 );
}
}
#endif
const char *szFrozenMessage = "Alarm_handler: Not checkpointed recently, aborting!\n";
/* Signal handler for alarm - suggested for use in MUDs by Fusion */
void alarm_handler( int signo )
{
int usage_now = get_user_seconds( );
/*
* Has there gone abort_threshold CPU seconds without alarm_update?
*/
if( !disable_timer_abort && ( usage_now - last_checkpoint > abort_threshold ) )
{
/*
* For the log file
*/
char buf[MAX_STRING_LENGTH];
/*
* spec: log usage values
*/
log_f( "current usage: %d, last checkpoint: %d", usage_now, last_checkpoint );
log_f( "SSM dups: %d, loops: %d, recent: %d", ssm_dup_count, ssm_loops, ssm_recent_loops );
snprintf( buf, MSL, "%s\r\n", szFrozenMessage );
bug( buf, 0 );
raise( SIGABRT ); /* kill ourselves on return */
}
/*
* The timer resets to the values specified in it_interval
* * automatically.
* *
* * Spec: additionally, SIGABRT is blocked in this handler, and will
* * only be delivered on return. This should ensure a good core.
*/
}
#ifndef WIN32
/* Install signal alarm handler */
void init_alarm_handler( )
{
struct sigaction sa;
sa.sa_handler = alarm_handler;
sa.sa_flags = SA_RESTART; /* Restart interrupted system calls */
sigemptyset( &sa.sa_mask );
sigaddset( &sa.sa_mask, SIGABRT ); /* block abort() in the handler
* so we can get a good coredump */
if( sigaction( SIGVTALRM, &sa, NULL ) < 0 ) /* setup handler for virtual timer */
{
perror( "init_alarm_handler:sigaction" );
exit( 1 );
}
last_checkpoint = get_user_seconds( );
reset_itimer( ); /* start timer */
}
#endif
/*
* Advancement stuff.
*/
void advance_level( CHAR_DATA * ch, int p_class, bool show, bool remort )
{
/*
* class used instead of ch->p_class. -S-
*/
/*
* show added to allow no display of gain ( when using setclass )
*/
/*
* remort indicates remortal class or normal mortal class
*/
char buf[MAX_STRING_LENGTH];
int add_hp;
int add_mana;
int add_move;
int add_prac;
int add_bloodlust, add_max_skills;
/*
* title no longer changed.....
*/
if( p_class == ADVANCE_WOLF )
{
add_bloodlust = ( number_range( 1, ( ( MAX_WOLF_LEVEL / 2 ) - ch->pcdata->super->generation ) ) ) +
( ( ( MAX_WOLF_LEVEL / 2 ) - ch->pcdata->super->generation ) / 2 );
add_prac = number_range( 1, UMAX( 2, ( ( MAX_WOLF_LEVEL / 2 ) - ch->pcdata->super->generation ) ) );
add_max_skills = add_prac;
ch->pcdata->super->energy_max += add_bloodlust;
ch->pcdata->super->pracs += add_prac;
ch->pcdata->super->skills_max += add_max_skills;
snprintf( buf, MSL, "@@NYou gain: %d @@rRage Ability@@N, and %d @@bWerewolf Practices. .@@N\r\n", add_bloodlust, add_prac );
send_to_char( buf, ch );
return;
}
if( ( p_class == 16 ) )
{
add_bloodlust = UMAX( ( ( MAX_VAMP_LEVEL / 2 ) - ( ch->pcdata->super->generation / 2 ) ), 1 );
add_prac = number_range( 1, UMAX( 2, ( ( MAX_VAMP_LEVEL / 2 ) - ( ch->pcdata->super->generation ) ) ) );
add_max_skills = number_range( 1, UMAX( 2, ( ( MAX_VAMP_LEVEL / 2 ) - ( ch->pcdata->super->generation ) ) ) );
ch->pcdata->super->energy_max += add_bloodlust;
ch->pcdata->super->pracs += add_prac;
ch->pcdata->super->skills_max += add_max_skills;
snprintf( buf, MSL, "You gain: %d @@eBloodlust@@N, and %d Vampyre Practices. .\r\n", add_bloodlust, add_prac );
send_to_char( buf, ch );
return;
}
if( ( p_class == 32 ) )
{
add_hp = con_app[get_curr_con( ch )].hitp + number_range( 10, 50 );
add_mana = number_range( 10, ( 3 * get_curr_int( ch ) + get_curr_wis( ch ) ) / 4 );
}
else if( remort )
{
add_hp = con_app[get_curr_con( ch )].hitp + number_range( remort_table[p_class].hp_min, remort_table[p_class].hp_max );
add_mana = remort_table[p_class].fMana ? number_range( 2, ( 2 * get_curr_int( ch ) + get_curr_wis( ch ) ) / 16 ) : 0;
}
else
{
add_hp = con_app[get_curr_con( ch )].hitp + number_range( class_table[p_class].hp_min, class_table[p_class].hp_max );
add_mana = class_table[p_class].fMana ? number_range( 2, ( 2 * get_curr_int( ch ) + get_curr_wis( ch ) ) / 16 ) : 0;
}
add_move = number_range( 2, ( get_curr_con( ch ) + get_curr_dex( ch ) ) / 5 );
add_prac = ( wis_app[get_curr_wis( ch )].practice / 2 ) + number_range( 1, 3 );
add_hp = UMAX( 1, add_hp );
add_mana = UMAX( 0, add_mana );
add_move = UMAX( 7, add_move );
ch->pcdata->mana_from_gain += add_mana;
ch->pcdata->hp_from_gain += add_hp;
ch->pcdata->move_from_gain += add_move;
ch->max_hit += add_hp;
ch->max_mana += add_mana;
ch->max_move += add_move;
ch->practice += add_prac;
if( !IS_NPC( ch ) )
ch->act.reset(ACT_BOUGHT_PET);
snprintf( buf, MSL, "You gain: %d Hit Points, %d Mana, %d Movement and %d pracs.\r\n", add_hp, add_mana, add_move, add_prac );
if( show )
send_to_char( buf, ch );
return;
}
void gain_exp( CHAR_DATA * ch, int gain )
{
/*
* Not much happens here, as no-longer auto-level... -S-
*/
/*
* -S- Mod: mobs CAN gain exp as well as players
*/
if( IS_NPC( ch ) && !ch->act.test(ACT_INTELLIGENT) )
return;
if( IS_IMMORTAL( ch ) )
return;
/*
* Changed exp system AGAIN old 'cap' was screwy!! -S-
*/
ch->exp += gain;
return;
}
/*
* Regeneration stuff.
*/
int hit_gain( CHAR_DATA * ch )
{
float gain;
if( ch == NULL )
return 0;
if( IS_NPC( ch ) && !ch->act.test(ACT_INTELLIGENT) )
gain = ( 5 + ch->level / 30 );
gain = ( 5 + ch->level / 20 );
if( ch->in_room->room_flags.test(RFLAG_REGEN) )
gain *= 2;
switch ( ch->position )
{
case POS_SLEEPING:
gain += get_curr_con( ch ) / 2;
break;
case POS_RESTING:
gain += get_curr_con( ch ) / 4;
break;
}
if( !IS_NPC( ch ) )
{
if( ch->pcdata->condition[COND_FULL] == 0 )
gain /= 2;
if( ch->pcdata->condition[COND_THIRST] == 0 )
gain /= 2;
if( IS_VAMP( ch ) && ch->pcdata->super->energy < 3 )
gain = 0;
else if( IS_VAMP( ch ) && ch->pcdata->super->energy < 8 )
gain /= 2;
if( IS_VAMP( ch ) && ch->pcdata->super->energy == -10 )
gain = ( 5 + ch->level / 25 );
}
if( IS_AFFECTED( ch, AFF_POISON ) )
gain /= 4;
if( ch->in_room->room_flags.test(RFLAG_COLD) || ch->in_room->room_flags.test(RFLAG_HOT) )
gain *= -2;
if( IS_SET( ch->in_room->affected_by, ROOM_BV_HEAL_REGEN ) )
{
if( gain < 0 )
gain *= -2;
else
gain *= 2;
}
if( IS_AFFECTED( ch, AFF_CLOAK_REGEN ) )
{
if( gain < 0 )
gain *= -2;
else
gain *= 2;
}
if( check_charm_aff(ch,CHARM_AFF_REGEN) )
gain *= ((100 + get_charm_bonus(ch,CHARM_AFF_REGEN)) / 100);
if( IS_SET( ch->in_room->affected_by, ROOM_BV_HEAL_STEAL ) )
if( gain > 0 )
gain *= -1;
if( !IS_NPC( ch ) && ( gain > 0 ) )
{
if( IS_SET( race_table[ch->race].race_flags, RACE_MOD_FAST_HEAL ) )
gain = gain * 1.5;
else if( IS_SET( race_table[ch->race].race_flags, RACE_MOD_SLOW_HEAL ) )
gain = gain * .75;
}
if( !IS_NPC( ch ) && ( gain > 0 ) )
{
if( ( IS_SET( race_table[ch->race].race_flags, RACE_MOD_WOODLAND ) ) && ( ch->in_room != NULL ) )
{
if( ( ch->in_room->sector_type == SECT_FIELD ) || ( ch->in_room->sector_type == SECT_FOREST ) )
gain = gain * 1.3;
else if( ( ch->in_room->sector_type == SECT_CITY ) || ( ch->in_room->sector_type == SECT_INSIDE ) )
gain = gain * .8;
}
else if( ( IS_SET( race_table[ch->race].race_flags, RACE_MOD_DARKNESS ) ) && ( ch->in_room != NULL ) )
{
if( ( ch->in_room->sector_type == SECT_FIELD )
|| ( ch->in_room->sector_type == SECT_HILLS )
|| ( ch->in_room->sector_type == SECT_AIR ) || ( ch->in_room->sector_type == SECT_DESERT ) )
gain = gain * .8;
else if( ( ch->in_room->sector_type == SECT_CITY ) || ( ch->in_room->sector_type == SECT_INSIDE ) )
gain = gain * 1.3;
}
}
return UMIN( static_cast<int>(gain), ch->max_hit - ch->hit );
}
int mana_gain( CHAR_DATA * ch )
{
float gain;
if( ch == NULL )
return 0;
if( IS_NPC( ch ) && !ch->act.test(ACT_INTELLIGENT) )
{
gain = ( 1 + ch->level / 30 );
}
else
{
gain = ( 5 + ch->level / 20 );
if( ch->in_room->room_flags.test(RFLAG_REGEN) )
gain *= 2;
switch ( ch->position )
{
case POS_SLEEPING:
gain += get_curr_int( ch );
break;
case POS_RESTING:
gain += get_curr_int( ch ) / 2;
break;
}
if( !IS_NPC( ch ) )
{
if( ch->pcdata->condition[COND_FULL] == 0 )
gain /= 2;
if( ch->pcdata->condition[COND_THIRST] == 0 )
gain /= 2;
if( IS_VAMP( ch ) && ch->pcdata->super->energy < 3 )
gain = 0;
else if( IS_VAMP( ch ) && ch->pcdata->super->energy < 8 )
gain /= 2;
if( IS_VAMP( ch ) && ch->pcdata->super->energy == -10 )
gain = ( 5 + ch->level / 25 );
if( IS_WOLF( ch ) && IS_RAGED( ch ) )
gain = 0;
}
if( IS_SET( ch->in_room->affected_by, ROOM_BV_MANA_REGEN ) )
{
if( gain < 0 )
gain *= -2;
else
gain *= 2;
}
if( IS_SET( ch->in_room->affected_by, ROOM_BV_MANA_STEAL ) )
if( gain > 0 )
gain *= -1;
}
if( IS_AFFECTED( ch, AFF_POISON ) )
gain /= 4;
if( check_charm_aff(ch,CHARM_AFF_REGEN) )
gain *= ((100 + get_charm_bonus(ch,CHARM_AFF_REGEN)) / 100);
if( !IS_NPC( ch ) && ( gain > 0 ) )
{
if( IS_SET( race_table[ch->race].race_flags, RACE_MOD_NO_MAGIC ) )
gain = gain * .5;
else if( IS_SET( race_table[ch->race].race_flags, RACE_MOD_WEAK_MAGIC ) )
gain = gain * .75;
else if( IS_SET( race_table[ch->race].race_flags, RACE_MOD_STRONG_MAGIC ) )
gain = gain * 1.40;
}
if( !IS_NPC( ch ) && ( gain > 0 ) )
{
if( ( IS_SET( race_table[ch->race].race_flags, RACE_MOD_WOODLAND ) ) && ( ch->in_room != NULL ) )
{
if( ( ch->in_room->sector_type == SECT_FIELD ) || ( ch->in_room->sector_type == SECT_FOREST ) )
gain = gain * 1.3;
else if( ( ch->in_room->sector_type == SECT_CITY ) || ( ch->in_room->sector_type == SECT_INSIDE ) )
gain = gain * .8;
}
else if( ( IS_SET( race_table[ch->race].race_flags, RACE_MOD_DARKNESS ) ) && ( ch->in_room != NULL ) )
{
if( ( ch->in_room->sector_type == SECT_FIELD )
|| ( ch->in_room->sector_type == SECT_HILLS )
|| ( ch->in_room->sector_type == SECT_AIR ) || ( ch->in_room->sector_type == SECT_DESERT ) )
gain = gain * .8;
else if( ( ch->in_room->sector_type == SECT_CITY ) || ( ch->in_room->sector_type == SECT_INSIDE ) )
gain = gain * 1.3;
}
}
if( gain > 0 )
{
gain = gain * int_app[get_curr_int( ch )].mana_regen / 10;
if( MAGIC_STANCE( ch ) )
gain = gain * int_app[get_curr_int( ch )].mana_regen / 10;
}
return UMIN( static_cast<int>(gain), ch->max_mana - ch->mana );
}
int move_gain( CHAR_DATA * ch )
{
float gain;
if( IS_NPC( ch ) )
{
gain = ch->level;
}
else
{
gain = ( 10 + ch->level / 4 );
if( ch->in_room->room_flags.test(RFLAG_REGEN) )
gain *= 2;
switch ( ch->position )
{
case POS_SLEEPING:
gain += get_curr_dex( ch ) / 2;
break;
case POS_RESTING:
gain += get_curr_dex( ch ) / 4;
break;
}
if( ch->pcdata->condition[COND_FULL] == 0 )
gain /= 2;
if( ch->pcdata->condition[COND_THIRST] == 0 )
gain /= 2;
if( IS_VAMP( ch ) && ch->pcdata->super->energy < 3 )
gain = 0;
else if( IS_VAMP( ch ) && ch->pcdata->super->energy < 8 )
gain /= 2;
if( IS_VAMP( ch ) && ch->pcdata->super->energy == -10 )
gain = ( 5 + ch->level / 25 );
}
if( IS_AFFECTED( ch, AFF_POISON ) )
gain /= 4;
if( check_charm_aff(ch,CHARM_AFF_REGEN) )
gain *= ((100 + get_charm_bonus(ch,CHARM_AFF_REGEN)) / 100);
return UMIN( static_cast<int>(gain), ch->max_move - ch->move );
}
void gain_rage( CHAR_DATA * ch )
{
short rage_gain = 0;
short current_rage = 0;
if( IS_NPC( ch ) || !IS_WOLF( ch ) )
return;
if( IS_RAGED( ch ) )
current_rage = ch->pcdata->super->energy_max;
else if( IS_SHIFTED( ch ) )
current_rage = UMAX( 1, ( ch->pcdata->super->energy_max / 5 ) );
else
current_rage = UMAX( 1, ( ch->pcdata->super->energy_max / 10 ) );
rage_gain = number_range( 1, ( MAX_WOLF_LEVEL / 2 - ch->pcdata->super->generation ) );
if( ch->pcdata->super->energy >= current_rage )
ch->pcdata->super->energy = UMIN( ( ch->pcdata->super->energy + rage_gain ), current_rage );
else
ch->pcdata->super->energy = UMIN( current_rage, ( ch->pcdata->super->energy + rage_gain ) );
}
void gain_bloodlust( CHAR_DATA * ch, int value )
{
/*
* Kinda like gain_condition, but handles vampires -S-
*/
int condition;
if( value == 0 )
return;
condition = ch->pcdata->super->energy;
/*
* in case vamp bites off more than he can chew ;)
* -Damane- 4/26/96
*/
if( ( ch->pcdata->super->energy + value ) > ch->pcdata->super->energy_max )
ch->pcdata->super->energy = ch->pcdata->super->energy_max;
else
ch->pcdata->super->energy += value;
if( ch->pcdata->super->energy > ch->pcdata->super->energy_max )
ch->pcdata->super->energy = ch->pcdata->super->energy_max;
if( ch->position == POS_BUILDING || ch->position == POS_WRITING )
return;
if( ( ch->pcdata->super->energy < 0 ) && ( ch->pcdata->super->energy != -10 ) )
ch->pcdata->super->energy = 0;
if( ch->pcdata->super->energy < 2 )
send_to_char( "Your body burns with the need for blood!\r\n", ch );
else if( ch->pcdata->super->energy < 7 )
send_to_char( "You start to feel weaker... more blood needed!\r\n", ch );
else if( ch->pcdata->super->energy < 10 )
send_to_char( "You find yourself missing the taste of blood.\r\n", ch );
return;
}
void gain_condition( CHAR_DATA * ch, int iCond, int value )
{
int condition;
if( value == 0 || IS_NPC( ch ) || ch->level >= LEVEL_HERO )
return;
condition = ch->pcdata->condition[iCond];
ch->pcdata->condition[iCond] = URANGE( 0, condition + value, 48 );
if( ch->position == POS_BUILDING || ch->position == POS_WRITING )
return;
if( ch->pcdata->condition[iCond] == 0 )
{
switch ( iCond )
{
case COND_FULL:
send_to_char( "You are hungry.\r\n", ch );
break;
case COND_THIRST:
send_to_char( "You are thirsty.\r\n", ch );
break;
case COND_DRUNK:
if( condition != 0 )
send_to_char( "You are sober.\r\n", ch );
break;
}
}
return;
}
/*
* Mob autonomous action.
* This function takes 25% to 35% of ALL Merc cpu time.
* -- Furey
*/
void mobile_update( void )
{
CHAR_DATA *ch;
CHAR_DATA *target;
EXIT_DATA *pexit;
int door;
CHAR_DATA *quitter;
std::list<CHAR_DATA *>::iterator li;
/*
* Examine all mobs.
*/
for( li = char_list.begin(); li != char_list.end(); li++ )
{
ch = *li;
if( ch == NULL || !IS_NPC( ch ) || ch->in_room == NULL || IS_AFFECTED( ch, AFF_CHARM ) )
continue;
/*
* Examine call for special procedure
*/
if( IS_NPC(ch) && ch->npcdata->spec_fun != 0 )
{
if( ( *ch->npcdata->spec_fun ) ( ch ) )
continue;
}
/*
* Added by Aeria for mob hunting continuously
*/
if( ch->searching != NULL )
{
if( ( quitter = get_char_world( ch, ch->searching ) ) != NULL )
set_hunt( ch, NULL, quitter, NULL, HUNT_WORLD | HUNT_OPENDOOR | HUNT_PICKDOOR | HUNT_UNLOCKDOOR | HUNT_INFORM,
HUNT_CR | HUNT_MERC );
}
/*
* DISABLED
*/
/*
* Intelligent mob?
*/
/* if ( ch->act.test(ACT_INTELLIGENT) )
int_handler( ch ); Disabled for now, for bugs. */
/*
* That's all for sleeping / busy monster
*/
if( ch->position < POS_STANDING )
continue;
/*
* Check for rewield, and re-equip (specials not used anymore)
*/
if( ch->act.test(ACT_RE_WIELD) )
if( check_rewield( ch ) )
continue;
if( ch->act.test(ACT_RE_EQUIP) )
if( check_re_equip( ch ) )
continue;
/*
* Check for remember victims
*/
if( ch->target != NULL && ( target = get_char_room( ch, ch->target ) ) != NULL )
{
remember_attack( ch, target );
continue;
}
/*
* Check to see if mob is moving somewhere
*/
/* if ( mob_hunt(ch) )
continue;
if ( IS_SET( ch->act_hunt, ACT_HUNT_MOVE )
&& ch->move_to != NO_VNUM )
{
hunt_move( ch );
continue;
}
*/
/*
* Scavenge
*/
if( ch->act.test(ACT_SCAVENGER) && ch->in_room->first_content != NULL && number_bits( 2 ) == 0 )
{
OBJ_DATA *obj;
OBJ_DATA *obj_best;
int max;
max = 1;
obj_best = 0;
for( obj = ch->in_room->first_content; obj; obj = obj->next_in_room )
{
if( CAN_WEAR( obj, ITEM_TAKE ) && obj->cost > max )
{
obj_best = obj;
max = obj->cost;
}
}
if( obj_best )
{
obj_from_room( obj_best );
obj_to_char( obj_best, ch );
act( "$n gets $p.", ch, obj_best, NULL, TO_ROOM );
}
}
/*
* Wander
*/
if( !ch->act.test(ACT_SENTINEL)
&& ch->leader == NULL
&& ( door = number_bits( 5 ) ) <= 5
&& ( pexit = ch->in_room->exit[door] ) != NULL
&& pexit->to_room != NULL
&& !pexit->exit_info.test(EX_CLOSED)
&& !pexit->to_room->room_flags.test(RFLAG_NO_MOB)
&& ( !ch->act.test(ACT_STAY_AREA) || pexit->to_room->area == ch->in_room->area ) )
{
move_char( ch, door, FALSE );
/*
* If ch changes position due
* to it's or someother mob's
* movement via MOBProgs,
* continue - Kahn
*/
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] ) != NULL
&& pexit->to_room != NULL
&& !pexit->exit_info.test(EX_CLOSED) && !pexit->to_room->room_flags.test(RFLAG_NO_MOB) )
{
CHAR_DATA *rch;
bool found;
found = FALSE;
for( rch = pexit->to_room->first_person; rch != NULL; rch = rch->next_in_room )
{
if( !IS_NPC( rch ) )
{
found = TRUE;
break;
}
}
if( !found )
move_char( ch, door, FALSE );
}
}
return;
}
/*
* Update the weather.
*/
void clean_donate_rooms( void )
{
ROOM_INDEX_DATA *room = NULL;
short room_count, looper, chance;
int room_vnum;
OBJ_DATA *object, *obj_next;
/*
* normal donate rooms
*/
if( ( room = get_room_index( ROOM_VNUM_MISC_DONATE ) ) != NULL )
{
for( room_count = 0, object = room->first_content; object; room_count++, object = object->next_in_room );
if( room_count > 150 )
{
for( object = room->first_content; object; object = obj_next )
{
obj_next = object->next_in_room;
if( count_obj_room( object->pIndexData, room->first_content ) > 5 )
chance = 50;
else
chance = 10;
if( IS_OBJ_STAT(object,ITEM_EXTRA_RARE) || object == quest_object )
chance = 0;
if( number_range( 0, 99 ) < chance )
extract_obj( object );
}
}
}
if( ( room = get_room_index( ROOM_VNUM_WEAPON_DONATE ) ) != NULL )
{
for( room_count = 0, object = room->first_content; object; room_count++, object = object->next_in_room );
if( room_count > 150 )
{
for( object = room->first_content; object; object = obj_next )
{
obj_next = object->next_in_room;
if( count_obj_room( object->pIndexData, room->first_content ) > 5 )
chance = 50;
else
chance = 10;
if( IS_OBJ_STAT(object,ITEM_EXTRA_RARE) || object == quest_object )
chance = 0;
if( number_range( 0, 99 ) < chance )
extract_obj( object );
}
}
}
if( ( room = get_room_index( ROOM_VNUM_ARMOR_DONATE ) ) != NULL )
{
for( room_count = 0, object = room->first_content; object; room_count++, object = object->next_in_room );
if( room_count > 150 )
{
for( object = room->first_content; object; object = obj_next )
{
obj_next = object->next_in_room;
if( count_obj_room( object->pIndexData, room->first_content ) > 5 )
chance = 50;
else
chance = 10;
if( IS_OBJ_STAT(object,ITEM_EXTRA_RARE) || object == quest_object )
chance = 0;
if( number_range( 0, 99 ) < chance )
extract_obj( object );
}
}
}
/*
* clan donate rooms
*/
for( looper = 1; looper < MAX_CLAN; looper++ )
{
if( ( room_vnum = clan_table[looper].donat_room ) == 0 )
continue;
if( ( room = get_room_index( room_vnum ) ) != NULL )
{
for( room_count = 0, object = room->first_content; object; room_count++, object = object->next_in_room );
if( room_count > 150 )
{
for( object = room->first_content; object; object = obj_next )
{
obj_next = object->next_in_room;
if( count_obj_room( object->pIndexData, room->first_content ) > 5 )
chance = 50;
else
chance = 10;
if( IS_OBJ_STAT(object,ITEM_EXTRA_RARE) || object == quest_object )
chance = 0;
if( number_range( 0, 99 ) < chance )
extract_obj( object );
}
}
}
}
}
void weather_update( void )
{
char buf[MAX_STRING_LENGTH];
char buf2[MSL];
DESCRIPTOR_DATA *d;
int diff;
short x, y;
#ifdef IMC
REMOTEINFO *r, *rnext;
#endif
buf[0] = '\0';
buf2[0] = '\0';
switch ( ++time_info.hour )
{
case 5:
weather_info.sunlight = SUN_LIGHT;
strncat( buf, "The sky shows signs of daybreak.\r\n", MSL );
break;
case 6:
weather_info.sunlight = SUN_RISE;
strncat( buf, "The sun rises in the east.\r\n", MSL );
for( x = 1; x < MAX_CLAN; x++ )
for( y = 1; y < MAX_CLAN; y++ )
politics_data.daily_negotiate_table[x][y] = FALSE;
break;
case 12:
for( x = 1; x < MAX_CLAN; x++ )
for( y = 1; y < MAX_CLAN; y++ )
politics_data.daily_negotiate_table[x][y] = FALSE;
break;
case 19:
weather_info.sunlight = SUN_SET;
strncat( buf, "The sun slowly disappears in the west.\r\n", MSL );
for( x = 1; x < MAX_CLAN; x++ )
for( y = 1; y < MAX_CLAN; y++ )
politics_data.daily_negotiate_table[x][y] = FALSE;
break;
case 20:
weather_info.sunlight = SUN_DARK;
strncat( buf, "The night has begun.\r\n", MSL );
break;
case 24:
time_info.hour = 0;
time_info.day++;
for( x = 1; x < MAX_CLAN; x++ )
for( y = 1; y < MAX_CLAN; y++ )
politics_data.daily_negotiate_table[x][y] = FALSE;
clean_donate_rooms( );
#ifdef IMC
if( this_imcmud->autoconnect ) /* Don't attempt a re-connect if we don't want to. --Kline */
{
monitor_chan("Mud list is being refreshed.",MONITOR_IMC);
for( r = first_rinfo; r; r = rnext )
{
rnext = r->next;
imc_delete_reminfo( r );
}
imc_request_keepalive( );
}
#endif
break;
}
switch ( time_info.moon++ )
{
case 5:
weather_info.moon_loc = MOON_RISE;
snprintf( buf2, MSL, "@@NA %s @@yMoon @@Nhas risen.\r\n", get_moon_phase_name( ) );
strncat( buf, buf2, MSL );
break;
case 10:
weather_info.moon_loc = MOON_LOW;
snprintf( buf2, MSL, "@@NThe %s @@yMoon @@Nrides low on the horizon.\r\n", get_moon_phase_name( ) );
strncat( buf, buf2, MSL );
break;
case 15:
weather_info.moon_loc = MOON_PEAK;
snprintf( buf2, MSL, "@@NThe %s @@yMoon @@Nreaches it's zenith.\r\n", get_moon_phase_name( ) );
strncat( buf, buf2, MSL );
break;
case 20:
weather_info.moon_loc = MOON_FALL;
snprintf( buf2, MSL, "@@NThe %s @@yMoon @@Nfalls.\r\n", get_moon_phase_name( ) );
strncat( buf, buf2, MSL );
break;
case 25:
weather_info.moon_loc = MOON_SET;
snprintf( buf2, MSL, "@@NThe %s @@yMoon @@Nis setting.\r\n", get_moon_phase_name( ) );
strncat( buf, buf2, MSL );
break;
case 30:
weather_info.moon_loc = MOON_DOWN;
snprintf( buf2, MSL, "@@NThe %s @@yMoon @@Nhas left the sky.\r\n", get_moon_phase_name( ) );
strncat( buf, buf2, MSL );
break;
default:
break;
}
if( time_info.moon >= 50 )
{
time_info.moon = 0;
weather_info.moon_loc = MOON_DOWN;
}
if( time_info.day >= 20 ) /* now 20 days = 1 month */
{
time_info.day = 0;
time_info.month++;
}
if( time_info.month >= 8 ) /* 8 months a year */
{
time_info.month = 0;
time_info.year++;
}
if( ( ( time_info.day ) % 4 ) == 0 )
{
if( !weather_info.phase_changed )
weather_info.moon_phase++;
if( weather_info.moon_phase > MOON_WAN_CRE )
weather_info.moon_phase = MOON_NEW;
weather_info.phase_changed = TRUE;
}
else
weather_info.phase_changed = FALSE;
/*
* 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 ) )
{
strncat( buf, "The sky is getting cloudy.\r\n", MSL );
weather_info.sky = SKY_CLOUDY;
}
break;
case SKY_CLOUDY:
if( weather_info.mmhg < 970 || ( weather_info.mmhg < 990 && number_bits( 2 ) == 0 ) )
{
strncat( buf, "It starts to rain.\r\n", MSL );
weather_info.sky = SKY_RAINING;
}
if( weather_info.mmhg > 1030 && number_bits( 2 ) == 0 )
{
strncat( buf, "The clouds disappear.\r\n", MSL );
weather_info.sky = SKY_CLOUDLESS;
}
break;
case SKY_RAINING:
if( weather_info.mmhg < 970 && number_bits( 2 ) == 0 )
{
strncat( buf, "Lightning flashes in the sky.\r\n", MSL );
weather_info.sky = SKY_LIGHTNING;
}
if( weather_info.mmhg > 1030 || ( weather_info.mmhg > 1010 && number_bits( 2 ) == 0 ) )
{
strncat( buf, "The rain stopped.\r\n", MSL );
weather_info.sky = SKY_CLOUDY;
}
break;
case SKY_LIGHTNING:
if( weather_info.mmhg > 1010 || ( weather_info.mmhg > 990 && number_bits( 2 ) == 0 ) )
{
strncat( buf, "The lightning has stopped.\r\n", MSL );
weather_info.sky = SKY_RAINING;
break;
}
break;
}
if( buf[0] != '\0' )
{
for( d = first_desc; d != NULL; d = d->next )
{
if( d->connected == CON_PLAYING
&& IS_OUTSIDE( d->character ) && ( d->character->position != POS_WRITING ) && IS_AWAKE( d->character ) )
send_to_char( buf, d->character );
}
}
return;
}
/* New update loop to handle gains for players => smaller 'ticks' for
hp/mana/move gain, normal 'ticks' for objects, affects, weather, etc */
void gain_update( void )
{
CHAR_DATA *ch;
std::list<CHAR_DATA *>::iterator li;
/* Update super_councils info */
{
MEMBER_DATA *imember;
short count = 0;
short council_index;
for( council_index = 1; council_index < MAX_SUPER; council_index++ )
{
if( super_councils[council_index].council_time > 0 )
{
super_councils[council_index].council_time--;
if( super_councils[council_index].council_time == 1 )
{
MEMBER_DATA *imember_next;
for( imember = super_councils[council_index].first_member; imember != NULL; imember = imember_next )
{
imember_next = imember->next;
send_to_char( "The current council is disbanded.\r\n", imember->this_member );
UNLINK( imember, super_councils[council_index].first_member, super_councils[council_index].last_member,
next, prev );
imember->this_member = NULL;
imember->next = NULL;
imember->prev = NULL;
PUT_FREE( imember, member_free );
}
super_councils[council_index].council_time = 0;
super_councils[council_index].quorum = FALSE;
}
}
if( !super_councils[council_index].quorum )
{
super_councils[council_index].quorum = FALSE;
for( imember = super_councils[council_index].first_member; imember != NULL; imember = imember->next )
{
count++;
}
if( count >= QUORUM_NUMBER )
{
super_councils[council_index].quorum = TRUE;
super_councils[council_index].council_time = 10;
for( imember = super_councils[council_index].first_member; imember != NULL; imember = imember->next )
send_to_char( "The Council is in Session!\r\n", imember->this_member );
}
}
}
}
for( li = char_list.begin(); li != char_list.end(); li++ )
{
ch = *li;
if( ch == NULL )
continue;
if( ch->position >= POS_STUNNED && !IS_SET( ch->affected_by, AFF_VAMP_HEALING ) && !IS_GHOST(ch) )
{
if( ( ch->hit < ch->max_hit ) && ( !IS_SET( ch->in_room->affected_by, ROOM_BV_NONE ) ) )
ch->hit += ch->position == POS_FIGHTING ? (hit_gain( ch ) / 2) : hit_gain( ch );
ch->hit = UMAX( 25, ch->hit );
if( ( ch->mana < ch->max_mana ) && ( !IS_SET( ch->in_room->affected_by, ROOM_BV_NONE ) ) )
ch->mana += ch->position == POS_FIGHTING ? (mana_gain( ch ) / 2) : mana_gain( ch );
if( ( ch->move < ch->max_move ) && ( ch->carry_weight < can_carry_w( ch ) ) )
ch->move += ch->position == POS_FIGHTING ? (move_gain( ch ) / 2) : move_gain( ch );
else if( ch->carry_weight >= can_carry_w( ch ) )
{
send_to_char( "You are carrying so much weight that you are @@eEXHAUSTED@@N!!\r\n", ch );
ch->move = 0;
}
}
if( ch->position == POS_STUNNED || IS_SET( ch->affected_by, AFF_VAMP_HEALING ) )
update_pos( ch );
}
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;
std::list<CHAR_DATA *>::iterator li;
time_t save_time;
save_time = current_time;
ch_save = NULL;
ch_quit = NULL;
for( li = char_list.begin(); li != char_list.end(); li++ )
{
AFFECT_DATA *paf;
AFFECT_DATA *paf_next;
ch = *li;
if( ch == NULL )
continue;
if( IS_GHOST(ch) )
{
if( ch->death_cnt > 0 )
ch->death_cnt--;
if( ch->death_cnt == 0 )
{
char_from_room(ch);
char_to_room(ch,get_room_index(ROOM_VNUM_ALTAR));
send_to_char("The gods have taken pity upon your ghostly plight...\r\n",ch);
resurrect(ch);
do_mpcr(ch,ch->name);
do_look(ch,"auto");
}
}
if( !IS_NPC( ch ) && IS_WOLF( ch ) )
gain_rage( ch );
/*
* Find dude with oldest save time.
*/
if( !IS_NPC( ch )
&& ( ch->desc == NULL || ch->desc->connected == CON_PLAYING ) && ch->level >= 2 && ch->save_time < save_time )
{
ch_save = ch;
save_time = ch->save_time;
}
if( ( IS_NPC( ch ) ) && ( ch->hit < -15 ) )
raw_kill( ch, "" );
if( ch->sitting != NULL && ch->sitting->in_room != ch->in_room )
{
ch->sitting->value[1]--;
ch->sitting = NULL;
}
/* Update mquest status */
update_mquest_wait_time(ch);
if( ch->position >= POS_STUNNED )
{
/*
* -S- mod.
*/
if( ch->position != POS_WRITING && ch->position != POS_BUILDING )
{
if( ch->in_room->room_flags.test(RFLAG_HOT) )
send_to_char( "You feel your skin burning.\r\n", ch );
else if( ch->in_room->room_flags.test(RFLAG_COLD) )
send_to_char( "You feel your skin freezing.\r\n", ch );
}
}
if( ( !IS_NPC( ch ) && ch->level < LEVEL_IMMORTAL ) )
{
OBJ_DATA *obj;
if( ( obj = get_eq_char( ch, WEAR_LIGHT ) ) != NULL && obj->item_type == ITEM_LIGHT && obj->value[2] > 0 )
{
if( --obj->value[2] == 0 && ch->in_room != NULL )
{
--ch->in_room->light;
act( "$p goes out.", ch, obj, NULL, TO_ROOM );
act( "$p goes out.", ch, obj, NULL, TO_CHAR );
if( obj->value[7] > 0 )
{
OBJ_INDEX_DATA *new_index;
OBJ_DATA *replacer;
if( ( new_index = get_obj_index( obj->value[6] ) ) == NULL )
{
snprintf( bug_buf, (2 * MIL),
"ERROR in expiring item %s(%s %d): item has a replace vnum set (%d), but that is not a valid item.",
obj->name, obj->pIndexData->area->keyword, obj->pIndexData->vnum, obj->value[6] );
monitor_chan( bug_buf, MONITOR_OBJ );
log_f( "%s", bug_buf );
}
else
{
replacer = create_object( new_index, obj->level );
if( obj->carried_by != NULL )
obj_to_char( replacer, obj->carried_by );
else if( obj->in_room != NULL )
obj_to_room( replacer, obj->in_room );
else if( obj->in_obj != NULL )
obj_to_obj( replacer, obj->in_obj );
}
}
extract_obj( obj );
}
}
if( ++ch->timer >= 12 )
{
if( ch->was_in_room == NULL && ch->in_room != NULL )
{
ch->was_in_room = ch->in_room;
if( ch->fighting != NULL )
stop_fighting( ch, TRUE );
act( "$n disappears into the void.", ch, NULL, NULL, TO_ROOM );
send_to_char( "You disappear into the void.\r\n", ch );
save_char_obj( ch );
char_from_room( ch );
char_to_room( ch, get_room_index( ROOM_VNUM_LIMBO ) );
}
}
if( ch->timer > 30 )
ch_quit = ch;
/*
* Move this inside the if loop below to stop imms getting bloodlust
*/
if( ( IS_VAMP( ch ) ) && ( !IS_NPC( ch ) ) )
{
gain_bloodlust( ch, 0 - number_range( 1, 2 ) );
check_vamp( ch );
}
if( !check_charm_aff(ch,CHARM_AFF_HUNGERLESS) )
gain_condition( ch, COND_THIRST, 0 - number_range( 1, 2 ) );
if( ch->pcdata->condition[COND_THIRST] <= 10 )
ch->pcdata->condition[COND_THIRST] = 10;
gain_condition( ch, COND_DRUNK, 0 - number_range( 1, 2 ) );
if( !IS_VAMP( ch ) )
{
if( !check_charm_aff(ch,CHARM_AFF_HUNGERLESS) )
gain_condition( ch, COND_FULL, 0 - number_range( 1, 2 ) );
}
}
for( paf = ch->first_affect; paf != NULL; paf = paf_next )
{
paf_next = paf->next;
if( paf->duration > 0 )
{
paf->duration--;
/*
* We need a check here for spells that keep working...
*/
if( paf->type == skill_lookup( "blood leach" ) )
{
if( paf->caster != NULL && !IS_NPC( paf->caster ) )
{
send_to_char( "You feel the blood leach sapping your strength.\r\n", ch );
act( "You feel a surge of blood, coming from your blood leach on $N.", paf->caster, NULL, ch, TO_CHAR );
paf->caster->pcdata->super->energy += ( 10 - paf->caster->pcdata->super->generation );
if( paf->caster->pcdata->super->energy > paf->caster->pcdata->super->energy_max )
paf->caster->pcdata->super->energy = paf->caster->pcdata->super->energy_max;
damage( ch, ch, paf->caster->pcdata->super->level * 20, TYPE_UNDEFINED );
}
}
if( paf->type == skill_lookup( "black hand" ) )
{
if( paf->caster != NULL && !IS_NPC( paf->caster ) )
{
send_to_char( "You feel the Black Hand choking you.\r\n", ch );
ch->hit -= paf->modifier;
}
}
if( ( paf->type == skill_lookup( "adrenaline bonus" ) ) && ( ch->fighting == NULL ) && ( ch->hit > 10 ) )
{
ch->hit = UMAX( 10, ( ch->hit - ( paf->duration * 30 ) ) );
ch->move = UMAX( 10, ( ch->move - ( paf->duration * 80 ) ) );
send_to_char( "@@NYou feel the affects of your @@eadrenaline rush@@N wear off, leaving you exhausted.\r\n",
ch );
affect_remove( ch, paf );
}
}
else if( paf->duration < 0 )
;
else
{
if( paf_next == NULL || 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( "\r\n", ch );
}
if( paf->type > 0 && skill_table[paf->type].room_off )
act( skill_table[paf->type].room_off, ch, NULL, NULL, TO_ROOM );
}
affect_remove( ch, paf );
}
}
/*
* Careful with the damages here,
* MUST NOT refer to ch after damage taken,
* as it may be lethal damage (on NPC).
*/
if( IS_NPC( ch ) )
{
if( ch->target != NULL && number_bits( 4 ) == 0 )
{
free_string( ch->target );
ch->target = NULL;
}
if( ch->extract_timer > 0 )
{
ch->extract_timer--;
}
else if( ch->extract_timer == 0 )
{
/* if ( IS_SET( ch->affected_by, AFF_CHARM ) )
{ */
if( ( ch->master == NULL ) || ( ch->master->in_room == NULL ) || ( ch->in_room != ch->master->in_room ) )
{
if( ch->in_room != NULL )
{
do_say( ch, "Whaa?? Where am I? How did I get here?" );
do_say( ch, "AHHH!!! Help me!!!! I'm MELTING......" );
}
extract_char( ch, TRUE );
continue;
}
else
{
if( number_range( 0, 99 ) < get_psuedo_level( ch->master ) - 25 )
{
CHAR_DATA *this_master;
this_master = ch->master;
do_say( ch, "Whaa?? Where am I? How did I get here?" );
do_scan( ch, "" );
check_social( ch, "growl", ch->master->name );
do_say( ch, "How dare you order me around!!!" );
stop_follower( ch );
one_hit( ch, this_master, TYPE_UNDEFINED );
continue;
}
}
/*
* }
*/
}
}
if( IS_AFFECTED( ch, AFF_POISON ) )
{
act( "$n shivers and suffers.", ch, NULL, NULL, TO_ROOM );
send_to_char( "You shiver and suffer.\r\n", ch );
damage( ch, ch, number_range( 2, 8 ), gsn_poison );
}
else if( ch->position == POS_INCAP && !IS_VAMP( ch ) )
{
damage( ch, ch, number_range( 1, 4 ), TYPE_UNDEFINED );
}
else if( ch->position == POS_MORTAL && !IS_VAMP( ch ) )
{
damage( ch, ch, number_range( 2, 3 ), TYPE_UNDEFINED );
}
else if( ch->position == POS_DEAD && !IS_VAMP( ch ) )
{
damage( ch, ch, number_range( 5, 10 ), TYPE_UNDEFINED );
}
else if( ch->hit < -10 && !IS_VAMP( ch ) )
{
damage( ch, ch, number_range( 5, 10 ), TYPE_UNDEFINED );
}
}
/*
* Autosave and autoquit.
* Check that these chars still exist.
*/
if( ch_save != NULL )
save_char_obj(ch_save);
if( ch_quit != NULL )
{
send_to_char("Idle for too long. Bye bye!\r\n",ch_quit);
do_quit(ch_quit,"");
}
return;
}
void check_vamp( CHAR_DATA * ch )
{
/*
* If vampire is outside, then (s)he suffers damage
*/
if( is_affected( ch, skill_lookup( "cloak:darkness" ) ) )
return;
if( IS_OUTSIDE( ch ) && !IS_SET( ch->in_room->affected_by, ROOM_BV_SHADE ) && time_info.hour > 5 && time_info.hour < 19 )
{
/*
* Oh dear
*/
int dam;
switch ( weather_info.sky )
{
case SKY_CLOUDLESS:
dam = 4;
break;
case SKY_CLOUDY:
dam = 3;
break;
case SKY_RAINING:
dam = 3;
break;
default:
dam = 1;
break;
}
/*
* Take bloodlust into account when calculating dam!
*/
dam *= 40 - ch->pcdata->super->level;
/*
* So dam ranges from 2 (lightning;no bloodlust)
* * to 200 (sunny;complete bloodlust)
* * And that's each tick!
*/
act( "$n's skin burns with it's contact with daylight!", ch, NULL, NULL, TO_ROOM );
send_to_char( "Your skin burns with it's contact with daylight!", ch );
if( ch->pcdata->super->energy <= -5 )
return;
damage( ch, ch, dam, -1 );
}
return;
}
/* Check for objfuns.... this is probably performance sensitive too. */
void objfun_update( void )
{
OBJ_DATA *obj;
std::list<OBJ_DATA *>::iterator li;
for( li = obj_list.begin(); li != obj_list.end(); li++ )
{
obj = *li;
if( obj->obj_fun != NULL )
{
if( obj->carried_by != NULL )
{
if( !IS_NPC( obj->carried_by ) && IS_WOLF( obj->carried_by )
&& ( IS_SHIFTED( obj->carried_by ) || IS_RAGED( obj->carried_by ) ) )
{
continue;
}
}
( *obj->obj_fun ) ( obj, obj->carried_by );
}
}
return;
}
/*
* Update all objs.
* This function is performance sensitive.
*/
void obj_update( void )
{
OBJ_DATA *obj;
std::list<OBJ_DATA *>::iterator li;
/*
* Repeatedly remove object from front of list, add to tail, and process
* until the marker is at the head of the list. That will indicate all
* objects have been processed.
*/
disable_timer_abort = FALSE;
for( li = obj_list.begin(); li != obj_list.end(); li++ )
{
CHAR_DATA *rch;
char *message;
obj = *li;
monitor_chan(obj->name,MONITOR_OBJ);
if( obj == auction_item )
continue;
if( IS_SET( obj->item_apply, ITEM_APPLY_HEATED ) && number_range( 0, 100 ) < 25 )
{
REMOVE_BIT( obj->item_apply, ITEM_APPLY_HEATED );
if( obj->carried_by != NULL )
{
act( "Your $p @@acools off@@N!!", obj->carried_by, obj, NULL, TO_CHAR );
}
else if( obj->in_room != NULL && ( rch = obj->in_room->first_person ) != NULL )
{
act( "$p @@acools off@@N!!", rch, obj, NULL, TO_ROOM );
act( "$p @@acools off@@N!!", rch, obj, NULL, TO_CHAR );
}
}
if( obj->timer <= 0 || --obj->timer > 0 )
continue;
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 vapourises, and goes to heaven.";
break;
case ITEM_PORTAL:
message = "$p implodes suddenly.";
break;
case ITEM_FOOD:
message = "$p decomposes.";
break;
}
if( obj->carried_by != NULL )
{
act( message, obj->carried_by, obj, NULL, TO_CHAR );
}
else if( obj->in_room != NULL && ( rch = obj->in_room->first_person ) != NULL )
{
act( message, rch, obj, NULL, TO_ROOM );
act( message, rch, obj, NULL, TO_CHAR );
}
/*
if ( obj->in_room == NULL )
continue;
if ( obj->item_type == ITEM_CORPSE_NPC )
continue;
*/
if( obj->value[7] > 0 )
{
OBJ_INDEX_DATA *new_index;
OBJ_DATA *replacer;
if( ( new_index = get_obj_index( obj->value[6] ) ) == NULL )
{
snprintf( bug_buf, (2 * MIL),
"ERROR in expiring item %s(%s %d): item has a replace vnum set (%d), but that is not a valid item.",
obj->name, obj->pIndexData->area->keyword, obj->pIndexData->vnum, obj->value[6] );
monitor_chan( bug_buf, MONITOR_OBJ );
log_f( "%s", bug_buf );
}
else
{
replacer = create_object( new_index, obj->level );
if( obj->carried_by != NULL )
obj_to_char( replacer, obj->carried_by );
else if( obj->in_room != NULL )
obj_to_room( replacer, obj->in_room );
else if( obj->in_obj != NULL )
obj_to_obj( replacer, obj->in_obj );
}
}
extract_obj( obj );
}
disable_timer_abort = FALSE;
return;
}
/*
* Aggress.
*
* for each mortal PC
* for each mob in room
* aggress on some random PC
*
* This function takes 25% to 35% of ALL Merc cpu time.
* Unfortunately, checking on each PC move is too tricky,
* because we don't the mob to just attack the first PC
* who leads the party into the room.
*
* -- Furey
*/
void aggr_update( void )
{
/*
* Check to see if ch has encountered a mob with ACT_REMEMBER set,
* * and with victim->target == ch->name... tbc ;)
* * -- Stephen
*/
CHAR_DATA *wch;
CHAR_DATA *ch;
CHAR_DATA *ch_next;
CHAR_DATA *vch;
CHAR_DATA *vch_next;
CHAR_DATA *victim;
OBJ_DATA *wield;
std::list<CHAR_DATA *>::iterator li;
for( li = char_list.begin(); li != char_list.end(); li++ )
{
wch = *li;
if( wch == NULL )
continue;
if( ( IS_NPC( wch ) ) || wch->level >= LEVEL_IMMORTAL || wch->in_room == NULL )
continue;
for( ch = wch->in_room->first_person; ch != NULL; ch = ch_next )
{
int count;
ch_next = ch->next_in_room;
if( !IS_NPC( ch )
|| !ch->act.test(ACT_AGGRESSIVE)
|| ch->fighting != NULL
|| ch->hunting != NULL
|| IS_AFFECTED( ch, AFF_CHARM )
|| !IS_AWAKE( ch ) || ( ch->act.test(ACT_WIMPY) && IS_AWAKE( wch ) ) || !can_see( ch, wch ) || ch->in_room->area->player_list.empty() )
continue;
if( ( IS_AFFECTED( wch, AFF_SNEAK ) || item_has_apply( wch, ITEM_APPLY_SNEAK ) )
&& ( number_percent( ) < 50 + ( 2 * ( get_psuedo_level( wch ) - get_psuedo_level( ch ) ) ) ) )
continue;
/*
* Ok we have a 'wch' player character and a 'ch' npc aggressor.
* MAG - wch can be an intelligent NPC.
* 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 = wch->in_room->first_person; vch != NULL; vch = vch_next )
{
vch_next = vch->next_in_room;
if( ( !IS_NPC( vch ) || vch->act.test(ACT_INTELLIGENT) )
&& vch->level < LEVEL_IMMORTAL
&& ( !ch->act.test(ACT_WIMPY) || !IS_AWAKE( vch ) )
&& can_see( ch, vch ) && ( !( IS_UNDEAD( ch ) && IS_VAMP( vch ) ) ) )
{
if( number_range( 0, count ) == 0 )
victim = vch;
count++;
}
}
if( victim == NULL )
{
/*
* bug( "Aggr_update: null victim.", count );
*/
continue;
}
if( victim->in_room->room_flags.test(RFLAG_SAFE) )
continue;
if( ch == quest_mob ) /* Stop the quest mob from fighting folks trying to help it! --Kline */
continue;
act( "$n growls at $N!", victim, NULL, ch, TO_NOTVICT );
act( "$N growls at you! Uh-oh!!", victim, NULL, ch, TO_CHAR );
act( "You growl at $N. Get $M!!", ch, NULL, victim, TO_CHAR );
wield = get_eq_char( ch, WEAR_HOLD_HAND_L );
if( wield != NULL && wield->item_type == ITEM_WEAPON && wield->value[3] == 11 && victim->fighting == NULL )
do_backstab( ch, victim->name );
else
one_hit( ch, victim, TYPE_UNDEFINED );
}
}
return;
}
/*
* Check ALL rooms for affects... the ratio of affects to rooms should
* be relatively low, so this shouldn't hit performance too much.
* -S-
*/
void rooms_update( void )
{
ROOM_INDEX_DATA *room;
AREA_DATA *area;
BUILD_DATA_LIST *thing;
ROOM_AFFECT_DATA *raf;
ROOM_AFFECT_DATA *raf_next;
std::list<AREA_DATA *>::iterator li;
std::list<MARK_DATA *>::iterator mi;
for( li = area_list.begin(); li != area_list.end(); li++ )
{
area = *li;
for( thing = area->first_area_room; thing != NULL; thing = thing->next )
{
room = (ROOM_INDEX_DATA *)thing->data;
/*
* if ( room->first_room_affect == NULL )
* continue;
*/
if( !room->mark_list.empty() )
{
for( mi = room->mark_list.begin(); mi != room->mark_list.end(); mi++ )
{
static_cast<MARK_DATA *>(*mi)->duration--;
if( static_cast<MARK_DATA *>(*mi)->duration <= 0 )
mi = room->mark_list.erase(mi);
}
save_marks();
}
for( raf = room->first_room_affect; raf != NULL; raf = raf_next )
{
raf_next = raf->next;
if( raf->duration > 0 )
raf->duration--;
else if( raf->duration < 0 )
;
else
{
if( raf_next == NULL || raf_next->type != raf->type || raf_next->duration > 0 )
{
if( raf->type > 0 && skill_table[raf->type].msg_off )
{
send_to_room( skill_table[raf->type].msg_off, room );
send_to_room( "\r\n", room );
}
r_affect_remove( room, raf );
}
}
}
}
}
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_message;
static int objfun_check;
static int pulse_area;
static int pulse_rooms;
static int pulse_mobile;
static int pulse_gain;
static int pulse_violence;
static int pulse_combat;
static int pulse_point;
static int pulse_auction;
if( saving_area )
build_save( ); /* For incremental area saving */
if( --pulse_area <= 0 )
{
pulse_area = number_range( PULSE_AREA / 2, 3 * PULSE_AREA / 2 );
area_update( );
build_save_flush( );
}
if( --pulse_rooms <= 0 )
{
pulse_rooms = PULSE_ROOMS;
rooms_update( );
}
if( --pulse_message <= 0 )
{
pulse_message = PULSE_MESSAGE;
message_update( );
}
if( auction_flop )
{
pulse_auction = PULSE_AUCTION;
auction_flop = FALSE;
}
if( --pulse_auction <= 0 )
{
pulse_auction = PULSE_AUCTION;
auction_update( );
}
if( --objfun_check <= 0 )
{
objfun_check = PULSE_OBJFUN;
objfun_update( );
}
if( --pulse_violence <= 0 )
{
alarm_update( );
pulse_violence = PULSE_VIOLENCE;
violence_update( );
}
if( --pulse_combat <= 0 )
{
pulse_combat = PULSE_COMBAT;
combat_update( );
}
if( --pulse_mobile <= 0 )
{
pulse_mobile = PULSE_MOBILE;
mobile_update( );
}
if( --pulse_gain <= 0 )
{
gain_update( );
pulse_gain = PULSE_PER_SECOND * number_range( 5, 8 );
}
if( --pulse_point <= 0 )
{
pulse_point = PULSE_TICK;
weather_update( );
char_update( );
obj_update( );
quest_update( );
/*
* This will log the number of perms being used...
* * fgrep the log file to get results...
*/
/*
* perm_update( );
*/
}
aggr_update( );
tail_chain( );
return;
}
bool check_rewield( CHAR_DATA * ch )
{
OBJ_DATA *obj;
OBJ_DATA *weapon = NULL;
int dam;
int chance;
bool pickup;
char buf[MAX_STRING_LENGTH];
pickup = TRUE;
dam = 0;
chance = ( ch->fighting == NULL ? 35 : 60 );
if( number_percent( ) < chance )
{
for( obj = ch->first_carry; obj != NULL; obj = obj->next_in_carry_list )
if( obj->item_type == ITEM_WEAPON && dam < obj->value[2] )
{
dam = obj->value[2];
pickup = FALSE;
weapon = obj;
}
/*
* Then check inventory and room for any weapons
*/
for( obj = ch->in_room->first_content; obj != NULL; obj = obj->next_in_room )
{
if( obj->item_type == ITEM_WEAPON )
{
if( obj->value[2] > dam )
{
dam = obj->value[2];
weapon = obj;
pickup = TRUE;
}
}
}
if( weapon == NULL )
return FALSE;
if( weapon->wear_loc == WEAR_HOLD_HAND_L )
return FALSE;
if( pickup )
{
snprintf( buf, MSL, "Great! %s! Just what i've always wanted!", weapon->short_descr );
do_say( ch, buf );
}
if( weapon != NULL )
{
/*
* Now make the mob get the weapon
*/
if( pickup )
get_obj( ch, weapon, NULL );
do_wear( ch, weapon->name );
/*
* Check is mob wielded weapon ok...
*/
if( weapon->wear_loc == WEAR_NONE && weapon != quest_object )
{
act( "$n sniffs sadly. 'Baah! It's no good to me!'", ch, NULL, NULL, TO_ROOM );
extract_obj( weapon );
act( "$n sacrifices $p.", ch, weapon, NULL, TO_ROOM );
}
return TRUE;
}
}
return FALSE;
}
bool check_re_equip( CHAR_DATA * ch )
{
OBJ_DATA *obj;
OBJ_DATA *obj2;
OBJ_DATA *armor = NULL;
OBJ_DATA *light = NULL;
int ac;
int chance;
bool pickup;
bool ident;
int best;
char buf[MAX_STRING_LENGTH];
int objnum;
best = -1;
pickup = TRUE;
ac = 0;
chance = ( ch->fighting == NULL ? 35 : 60 );
if( number_percent( ) < chance )
{
/*
* Check each armor in room against ch's equipment
*/
ident = FALSE;
for( obj = ch->in_room->first_content; obj != NULL; obj = obj->next_in_room )
{
if( !can_see_obj( ch, obj ) )
continue;
if( !CAN_WEAR(obj,ITEM_TAKE) )
continue; /* Check to see if item cannot be worn */
if( obj->item_type == ITEM_PIECE )
continue;
if( obj->item_type == ITEM_ARMOR )
{
/*
* Check this object against our equiped objects
*/
ident = FALSE;
for( obj2 = ch->first_carry; obj2 != NULL; obj2 = obj2->next_in_carry_list )
{
/*
* Only scan against worn objects.
* * If obj2 is being worn in a position that obj can be worn in,
* * and obj2->value[0] is better, then choose it.
*/
if( obj2->wear_loc != WEAR_NONE
&& obj2->item_type == ITEM_ARMOR
&& can_wear_at( ch, obj, obj2->wear_loc ) && obj->value[0] > obj2->value[0] )
{
ident = TRUE; /* identical wear_loc */
armor = obj;
break;
}
}
/*
* Found no match for locations, so get and wear.
*/
if( !ident )
{
armor = obj;
break;
}
}
if( obj->item_type == ITEM_LIGHT && ( get_eq_char( ch, WEAR_LIGHT ) == NULL ) )
{
light = obj;
break;
}
}
/*
* MAG Modification. Only check one item each time, against currently
* worn object.
*/
/*
* Check one inv item against worn eq, incase we've picked up some nicer
* stuff
*/
objnum = number_percent( ) * ch->carry_number / 100;
for( obj = ch->first_carry; obj != NULL && objnum > 0; obj = obj->next_in_carry_list )
objnum--;
if( obj != NULL && obj->wear_loc == WEAR_NONE && obj->item_type == ITEM_ARMOR )
{
ident = FALSE;
for( obj2 = ch->first_carry; obj2 != NULL; obj2 = obj2->next_in_carry_list )
{
if( obj2->wear_loc != WEAR_NONE && can_wear_at( ch, obj, obj2->wear_loc ) && obj->value[0] > obj2->value[0] )
{
ident = TRUE;
armor = obj;
break;
}
}
if( !ident )
{
armor = obj;
}
}
if( obj != NULL && obj->item_type == ITEM_LIGHT && ( get_eq_char( ch, WEAR_LIGHT ) == NULL ) )
{
light = obj;
}
}
if( armor != NULL )
{
if( armor->carried_by != ch )
{
/*
* Pick up off ground
*/
if( pickup )
{
snprintf( buf, MSL, "Great! %s! Just what i've always wanted!", armor->short_descr );
do_say( ch, buf );
}
/*
* Now make the mob get the armor
*/
if( pickup )
get_obj( ch, armor, NULL );
}
do_wear( ch, armor->name );
/*
* Check is mob wielded weapon ok...
*/
if( armor->wear_loc == WEAR_NONE && armor != quest_object )
{
act( "$n sniffs sadly. 'Baah! It's no good to me!'", ch, NULL, NULL, TO_ROOM );
extract_obj( armor );
act( "$n sacrifices $p.", ch, armor, NULL, TO_ROOM );
}
return TRUE;
}
if( light != NULL )
{
if( light->carried_by != ch )
{
/*
* Pick up off ground
*/
if( pickup )
{
snprintf( buf, MSL, "Great! %s! Just what i've always wanted!", light->short_descr );
do_say( ch, buf );
}
/*
* Now make the mob get the light
*/
if( pickup )
get_obj( ch, light, NULL );
}
do_wear( ch, light->name );
/*
* Check is mob wielded weapon ok...
*/
if( light->wear_loc == WEAR_NONE && light != quest_object )
{
act( "$n sniffs sadly. 'Baah! It's no good to me!'", ch, NULL, NULL, TO_ROOM );
extract_obj( light );
act( "$n sacrifices $p.", ch, light, NULL, TO_ROOM );
}
return TRUE;
}
return FALSE;
}
void auction_update( void )
{
char buf[MAX_STRING_LENGTH];
std::list<CHAR_DATA *>::iterator li;
CHAR_DATA *ach;
bool good_seller = false, good_buyer = false;
/*
* Stages: 0) No/New bid.
* 1) Waiting. (If no bid here, then give up next time)
* 2) Going once.
* 3) Going Twice.
* 4) GONE!
*/
if( auction_item == NULL )
return;
switch ( auction_stage )
{
case 0:
if( auction_bidder == NULL )
{
snprintf( buf, MSL,
"@@N%s (level:%d, valued at %s) has been offered for auction. A @@e10%% fee@@N will be charged, the higher of the reserve price or highest bid.",
auction_item->short_descr, auction_item->level, cost_to_money( auction_item->cost ) );
}
else
{
snprintf( buf, MSL, "%s has bid %s for %s.", auction_bidder->name,
cost_to_money( auction_bid ), auction_item->short_descr );
}
break;
case 1:
if( auction_bidder == NULL )
snprintf( buf, MSL, "Last chance to bid for %s.", auction_item->short_descr );
else
snprintf( buf, MSL, "Last bid for %s was %s. Any more offers?",
auction_item->short_descr, cost_to_money( auction_bid ) );
break;
case 2:
if( auction_bidder == NULL )
{
auction( "No bidders. Auction Ended." );
for( li = char_list.begin(); li != char_list.end(); li++ )
{
ach = *li;
if( auction_owner == ach )
good_seller = TRUE;
if( auction_bidder == ach )
good_buyer = TRUE;
}
if( good_seller )
{
int bid;
char changebuf[MSL];
char *change;
bid = UMIN( money_value( auction_owner->money ), static_cast<int>(auction_reserve * .1) );
change = take_best_coins( auction_owner->money, bid );
change = one_argument( change, changebuf );
money_to_value( auction_owner, change );
join_money( round_money( atoi( change ), TRUE ), auction_owner->money );
obj_to_char( auction_item, auction_owner );
}
else
{
auction( "Oh, well..guess they didn't want it anymore, since they LEFT!! Well, it's mine now! " );
extract_obj( auction_item );
}
auction_item = NULL;
return;
}
snprintf( buf, MSL, "%s - Going Once!", auction_item->short_descr );
break;
case 3:
snprintf( buf, MSL, "%s - Going TWICE!", auction_item->short_descr );
break;
case 4:
if( auction_bid < auction_reserve )
{
for( li = char_list.begin(); li != char_list.end(); li++ )
{
ach = *li;
if( auction_owner == ach )
good_seller = TRUE;
if( auction_bidder == ach )
good_buyer = TRUE;
}
snprintf( buf, MSL, "%s - CANCELLED. Reserve price not matched.", auction_item->short_descr );
if( good_seller )
{
int bid;
char changebuf[MSL];
char *change;
bid = UMIN( money_value( auction_owner->money ), static_cast<int>(auction_reserve * .1) );
change = take_best_coins( auction_owner->money, bid );
change = one_argument( change, changebuf );
money_to_value( auction_owner, change );
join_money( round_money( atoi( change ), TRUE ), auction_owner->money );
obj_to_char( auction_item, auction_owner );
}
else
extract_obj( auction_item );
if( good_buyer )
join_money( round_money( auction_bid, TRUE ), auction_bidder->money );
}
else
{
for( li = char_list.begin(); li != char_list.end(); li++ )
{
ach = *li;
if( auction_owner == ach )
good_seller = TRUE;
if( auction_bidder == ach )
good_buyer = TRUE;
}
if( good_buyer )
{
snprintf( buf, MSL, "%s - SOLD! to %s.", auction_item->short_descr, auction_bidder->name );
obj_to_char( auction_item, auction_bidder );
}
else
{
snprintf( buf, MSL, "%s - SOLD!, but the buyer has left us. Oh Well!!!", auction_item->short_descr );
extract_obj( auction_item );
}
if( good_seller )
join_money( round_money( static_cast<int>(auction_bid - ( auction_bid * .1 )), TRUE ), auction_owner->money );
}
auction_stage = 0;
auction_bidder = NULL;
auction_owner = NULL;
auction_item = NULL;
auction_reserve = 0;
auction_bid = 0;
break;
}
auction( buf );
auction_stage++;
return;
}
void remember_attack( CHAR_DATA * ch, CHAR_DATA * victim )
{
/*
* Called when an NPC ch encounters a PC victim, that tried to
* * kill it previously.
* * --Stephen
*/
char buf[MAX_STRING_LENGTH];
/*
* Pick a random response for ch to give, before attacking
*/
switch ( number_range( 0, 7 ) )
{
case 0:
snprintf( buf, MSL, "%s returns! I shall have my revenge at last!", victim->name );
do_yell( ch, buf );
break;
case 1:
snprintf( buf, MSL, "%s You should never have returned. Ye shall DIE!", victim->name );
do_whisper( ch, buf );
break;
case 2:
act( "$n looks at $N, remembering $S attack", ch, NULL, victim, TO_ROOM );
act( "$n looks at you, remembering your attack", ch, NULL, victim, TO_VICT );
act( "You look at $N, remembering $S attack.", ch, NULL, victim, TO_CHAR );
do_say( ch, "I SHALL HAVE MY REVENGE!!!" );
break;
case 3:
snprintf( buf, MSL, "%s has wronged me, and now I will seek my revenge!", victim->name );
do_gossip( ch, buf );
snprintf( buf, MSL, "Prepare to die, %s.", victim->name );
do_say( ch, buf );
break;
case 4:
snprintf( buf, MSL, "So, %s. You have returned. Let us finish our fight this time!", victim->name );
do_say( ch, buf );
break;
case 5:
snprintf( buf, MSL, "Only cowards flee from me, %s!", victim->name );
do_say( ch, buf );
break;
case 6:
act( "$n looks at $N, and recognizes $M!!", ch, NULL, victim, TO_ROOM );
act( "$n looks at you, and recognizes you!!", ch, NULL, victim, TO_VICT );
act( "You look at $N, and recognize $M!", ch, NULL, victim, TO_CHAR );
snprintf( buf, MSL, "There can only be one winner, %s.", victim->name );
do_say( ch, buf );
break;
}
/*
* Check if has intelligence, and call correct attack?
*/
one_hit( ch, victim, TYPE_UNDEFINED );
/*
* spec- plug leak here
*/
if( ch->target )
{
free_string( ch->target );
ch->target = NULL;
}
return;
}
void quest_update( )
{
if( !quest && !auto_quest )
return;
if( quest )
{
/*
* Make sure the mobile and obj still exist!
*/
if( quest_mob == NULL || quest_object == NULL )
{
quest_cancel( );
return;
}
quest_inform( );
if( quest_timer > 15 )
quest_cancel( );
return;
}
if( !quest )
{
if( quest_wait > 0 )
{
quest_wait--;
return;
}
if( auto_quest )
generate_auto_quest( );
}
}