/***************************************************************************
* 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. *
***************************************************************************/
#include <stdio.h>
#include <string.h>
#include <time.h>
#include <math.h>
#include "globals.h"
#ifndef DEC_ACT_MOB_H
#include "act_mob.h"
#endif
bool able_to_level( CHAR_DATA * ch )
{
bool in_need = FALSE;
if( ch->intell_exp > ( 5 * exp_for_mobile( ch->level, ch ) ) )
in_need = TRUE;
return in_need;
}
void gain_level( CHAR_DATA * ch )
{
int cost;
char buf[MAX_STRING_LENGTH];
cost = 5 * exp_for_mobile( ch->level, ch );
if( ch->intell_exp < cost )
return;
ch->intell_exp -= cost;
ch->level = UMIN( 140, ch->level++ );
xprintf( buf, "%s gains a level!", ch->short_descr );
info( buf, 1 );
return;
}
int find_spell( CHAR_DATA * ch, int type )
{
int sn;
int bar;
int level;
int spell = -1;
int spell_level = -1;
for( sn = 0; sn < MAX_SKILL; sn++ )
{
if( skill_table[sn].name == NULL )
break;
if( skill_table[sn].slot == 0 )
continue;
if( skill_table[sn].target != type )
continue;
level = -1;
for( bar = 0; bar < MAX_CLASS; bar++ )
if( skill_table[sn].skill_level[bar] > level && ch->level >= skill_table[sn].skill_level[bar] )
level = skill_table[sn].skill_level[bar];
if( level == -1 ) /* not high enough to use */
continue;
if( level > spell_level && mana_cost( ch, sn ) < ch->mana )
{
spell = sn;
spell_level = level;
}
}
return spell;
}
void mob_group_follow( CHAR_DATA * ch, CHAR_DATA * target )
{
char buf[MAX_STRING_LENGTH];
CHAR_DATA *vch;
int num;
if( ( ch == NULL ) || ( target == NULL ) )
{
xprintf( buf, "%s", "Null ch and/or target in mob_group_follow, exiting." );
monitor_chan( buf, MONITOR_MOB );
return;
}
xprintf( buf, "Ok guys, let's all follow %s.", target->short_descr );
do_say( ch, buf );
for( vch = ch->in_room->first_person; vch != NULL; vch = vch->next_in_room )
{
if( ( ch != vch ) && ( AI_MOB( vch ) ) && ( is_same_group( ch, vch ) ) )
{
if( vch->position != POS_STANDING )
do_stand( vch, "" );
num = number_percent( );
// WAIT_STATE( vch, 12 );
if( num > 85 )
do_say( vch, "Ok boss. Whatever you say." );
else if( num > 70 )
do_say( vch, "Alright! More people, more power!" );
else if( num > 55 )
do_say( vch, "Whoo Hooo!" );
else if( num > 35 )
do_say( vch, "Sure thing." );
else if( num > 29 )
{
if( num > 32 )
xprintf( buf, "Man I don't want to join %s's group!", target->short_descr );
else
xprintf( buf, "I hate big groups." );
do_say( vch, buf );
do_follow( vch, vch->name );
do_say( vch, "I'm outta here." );
do_recall( vch, "" );
continue;
}
if( !can_see( vch, target ) )
{
vch->master = target;
vch->leader = NULL;
}
else
do_follow( vch, target->name );
do_group( target, "all" );
}
}
return;
}
void get_mob_group( CHAR_DATA * ch, CHAR_DATA * target )
{
CHAR_DATA *vch;
bool ch_is_leader = FALSE;
bool tar_is_leader = FALSE;
bool is_hunting = FALSE;
bool ch_is_higher = FALSE;
char buf[MAX_STRING_LENGTH];
int number_of_tar_group = 1;
int number_of_ch_group = 1;
ch_is_leader = is_group_leader( ch );
tar_is_leader = is_group_leader( target );
if( tar_is_leader == TRUE )
{
for( vch = ch->in_room->first_person; vch != NULL; vch = vch->next_in_room )
{
if( !AI_MOB( vch ) )
{
continue;
}
if( vch != target && is_same_group( vch, target ) )
{
number_of_tar_group = number_of_tar_group + 1;
continue;
}
if( vch != ch && is_same_group( ch, vch ) )
{
number_of_ch_group = number_of_ch_group + 1;
continue;
}
}
}
do_say( ch, "Hello there. What are you up to?" );
// WAIT_STATE( target, 24 );
if( target->hunting != NULL )
{
is_hunting = TRUE;
if( tar_is_leader == TRUE )
{
xprintf( buf, "We're planning on killing %s.", target->hunting->short_descr );
}
else
{
xprintf( buf, "I'm planning on killing %s.", target->hunting->short_descr );
}
do_say( target, buf );
}
else
{
do_say( target, "Nothing. Just hanging around." );
}
WAIT_STATE( ch, 24 );
/*
* check to see which of the two is higher. the higher mob will lead
*/
if( get_psuedo_level( ch ) >= get_psuedo_level( target ) )
ch_is_higher = TRUE;
/*
* if ch is higher in levels and victim is hunting, then say
* * appropriate line.
*/
if( ( ch_is_higher == FALSE ) && ( is_hunting == TRUE ) )
{
do_say( ch, "Oh really? Cool! Need any help?" );
}
else if( ( ch_is_higher == FALSE ) && ( is_hunting == FALSE ) )
{
do_say( ch, "Great! Since you're not doing anything, wanna group?" );
}
else if( ( ch_is_higher == TRUE ) && ( is_hunting == TRUE ) )
{
if( ch_is_leader == TRUE )
{
xprintf( buf, "Want to help us kill %s instead?", ch->hunting->short_descr );
do_say( ch, buf );
}
else if( ch_is_leader == FALSE )
{
xprintf( buf, "Want to help me kill %s instead?", ch->hunting->short_descr );
do_say( ch, buf );
}
}
else if( ( ch_is_higher == TRUE ) && ( ch->hunting == FALSE ) )
{
do_say( ch, "Want to group?" );
}
WAIT_STATE( target, 24 );
if( ch_is_higher == TRUE )
{
do_say( target, "Ok sure! Thanks for asking." );
if( tar_is_leader == TRUE )
{
mob_group_follow( target, ch );
}
do_follow( target, ch->name );
do_group( ch, target->name );
}
else
{
do_say( target, "Ok, why not!? Follow me." );
WAIT_STATE( ch, 24 );
do_say( ch, "Cool!" );
if( ch_is_leader == TRUE )
{
mob_group_follow( ch, target );
}
do_follow( ch, target->name );
do_group( target, ch->name );
}
return;
}
/* returns false if mob needed to cast a room affect spell */
bool ready_heal_room( CHAR_DATA * ch )
{
bool ready = TRUE;
if( ( !IS_SET( ch->in_room->affected_by, ROOM_BV_HEAL_REGEN ) ) && ( ch->hit < ch->max_hit * 75 / 100 ) )
{
if( ch->mana >= mana_cost( ch, skill_lookup( "healing light" ) ) )
{
ready = FALSE;
do_cast( ch, "'healing light'" );
return ready;
}
}
if( ( !IS_SET( ch->in_room->affected_by, ROOM_BV_MANA_REGEN ) ) && ( ch->mana < ch->max_mana * 75 / 100 ) )
{
if( ch->mana >= mana_cost( ch, skill_lookup( "mana flare" ) ) )
{
ready = FALSE;
do_cast( ch, "'mana flare'" );
return ready;
}
}
/*
* don't cast seal room in midgaard
*/
// ZEN FIX this to check for bad room spells allowed in area
// if ( ( ch->in_room->vnum > ROOM_VNUM_MID_TOP
// || ch->in_room->vnum < ROOM_VNUM_MID_BOTTOM )
// && ( !IS_SET( ch->in_room->affected_by, ROOM_BV_ENCAPS ) ) )
// {
// if ( ch->mana >= mana_cost( ch, skill_lookup ( "seal room" ) ) )
// {
// ready = FALSE;
// do_cast ( ch, "'seal room'" );
// return ready;
// }
// }
return ready;
}
/* checks to see if mob needs to stand up for any reason, if so then stand. */
void need_to_stand( CHAR_DATA * ch )
{
int current_state;
CHAR_DATA *vch;
current_state = ch->position;
/*
* if someone in your group is fighting, get up
*/
for( vch = ch->in_room->first_person; vch != NULL; vch = vch->next_in_room )
{
if( ( is_same_group( ch, vch ) ) && ( vch->position == POS_FIGHTING ) )
{
get_up( ch, current_state );
return;
}
}
/*
* if your leader is up and ready to move, get up
*/
if( ( ch->leader != NULL )
&& ( ch->in_room == ch->leader->in_room )
&& ( ch->leader->position == POS_STANDING )
&& ( ch->leader->hit >= ch->leader->max_hit * 85 / 100 ) && ( ch->leader->mana >= ch->leader->max_mana * 85 / 100 ) )
{
get_up( ch, current_state );
return;
}
/*
* Do you need heal? if so, can you heal?
*/
if( ch->hit < ch->max_hit * 85 / 100 )
{
if( ( ch->mana >= mana_cost( ch, skill_lookup( "heal" ) ) )
|| ( ch->mana >= mana_cost( ch, skill_lookup( "cure critical" ) ) )
|| ( ch->mana >= mana_cost( ch, skill_lookup( "cure serious" ) ) ) )
{
get_up( ch, current_state );
return;
}
}
/*
* if there is an int mob in the room stand so that you can group with
* * it
*/
if( ch->leader == NULL )
{
for( vch = ch->in_room->first_person; vch != NULL; vch = vch->next_in_room )
{
if( ( AI_MOB( vch ) )
&& ( vch->leader == NULL )
&& ( !is_same_group( vch, ch ) )
&& ( IS_SET( vch->act, ACT_INTELLIGENT ) )
&& ( vch != ch )
&& ( ( get_psuedo_level( vch ) - get_psuedo_level( ch ) <= 20 )
&& ( get_psuedo_level( vch ) - get_psuedo_level( ch ) >= -20 ) ) )
{
get_up( ch, current_state );
return;
}
}
}
/*
* if you're ready to move, stand
*/
if( ( ch->hit >= ch->max_hit * 85 / 100 ) && ( ch->mana >= ch->max_mana * 85 / 100 ) )
get_up( ch, current_state );
return;
}
void get_up( CHAR_DATA * ch, int current_state )
{
if( current_state == POS_SLEEPING )
do_wake( ch, "" );
else if( current_state == POS_RESTING )
do_stand( ch, "" );
return;
}
void mob_regen_check( CHAR_DATA * ch, CHAR_DATA * target, bool need_flee )
{
char buf[MAX_STRING_LENGTH];
if( target == NULL )
target = ch;
if( ch->mana >= mana_cost( ch, skill_lookup( "heal" ) ) )
xprintf( buf, "'heal' %s", target->name );
else if( ch->mana >= mana_cost( ch, skill_lookup( "cure critical" ) ) )
xprintf( buf, "'cure critical' %s", target->name );
else if( ch->mana >= mana_cost( ch, skill_lookup( "cure serious" ) ) )
xprintf( buf, "'cure serious' %s", target->name );
else if( need_flee == TRUE )
{
do_flee( ch, "" );
return;
}
else if( need_flee == FALSE )
return;
do_cast( ch, buf );
return;
}
void mob_is_fighting( CHAR_DATA * ch )
{
CHAR_DATA *vch;
CHAR_DATA *target = NULL;
bool is_being_attacked = FALSE;
bool need_flee = FALSE;
/*
* check to see if you are the one being attacked
*/
for( vch = ch->in_room->first_person; vch != NULL; vch = vch->next_in_room )
{
if( vch->fighting == ch )
{
is_being_attacked = TRUE;
break;
}
}
/*
* if you have a leader and he/she is present, they should rescue you if
* * you are being attacked, else you should check on them in case they
* * need heals
*/
if( ( ch->leader != NULL ) && ( ch->leader->in_room == ch->in_room ) )
{
target = ch->leader;
if( is_being_attacked == TRUE && target != ch )
do_rescue( target, ch->name );
else if( target->hit < target->max_hit * 50 / 100 )
mob_regen_check( ch, target, need_flee );
else
{
for( vch = ch->in_room->first_person; vch != NULL; vch = vch->next_in_room )
{
if( ( is_same_group( ch, vch ) ) && ( vch->hit < vch->max_hit * 20 / 100 ) )
{
mob_regen_check( ch, vch, need_flee );
return;
}
}
}
return;
}
/*
* if flow reaches here, you are the tank
*/
/*
* either heal yourself or flee
*/
if( ch->hit < ch->max_hit * 50 / 100 )
{
if( ch->hit < ch->max_hit * 20 / 100 )
need_flee = TRUE;
mob_regen_check( ch, target, need_flee );
}
return;
}
void power_up_mob( CHAR_DATA * ch )
{
int num_percent;
/*
* you can only have one cloak spell
*/
if( !IS_AFFECTED( ch, AFF_CLOAK_ABSORPTION )
&& !IS_AFFECTED( ch, AFF_CLOAK_REFLECTION ) && !IS_AFFECTED( ch, AFF_CLOAK_FLAMING ) )
{
num_percent = number_percent( );
if( num_percent > 75 )
{
if( ch->mana >= mana_cost( ch, skill_lookup( "cloak:flaming" ) ) )
do_cast( ch, "'cloak:flaming'" );
return;
}
if( num_percent > 50 )
{
if( ch->mana >= mana_cost( ch, skill_lookup( "cloak:reflection" ) ) )
do_cast( ch, "cloak:reflection" );
return;
}
if( num_percent > 25 )
{
if( ch->mana >= mana_cost( ch, skill_lookup( "cloak:absorption" ) ) )
do_cast( ch, "cloak:absorption" );
return;
}
}
/*
* usually i only have mobs do one thing per round but what they hell
* * let the kids have their fun :)
*/
if( !IS_AFFECTED( ch, AFF_SANCTUARY ) )
if( ch->mana >= mana_cost( ch, skill_lookup( "sanctuary" ) ) )
do_cast( ch, "sanctuary" );
if( !IS_AFFECTED( ch, AFF_PROTECT ) )
if( ch->mana >= mana_cost( ch, skill_lookup( "protection" ) ) )
do_cast( ch, "protection" );
if( !IS_AFFECTED( ch, skill_lookup( "bless" ) ) )
if( ch->mana >= mana_cost( ch, skill_lookup( "bless" ) ) )
do_cast( ch, "bless" );
if( !IS_AFFECTED( ch, skill_lookup( "stone skin" ) ) )
if( ch->mana >= mana_cost( ch, skill_lookup( "stone skin" ) ) )
do_cast( ch, "stone" );
return;
}
void mob_is_standing( CHAR_DATA * ch )
{
sh_int dir;
CHAR_DATA *vch;
CHAR_DATA *tch;
bool ready = TRUE;
bool prey_still_exist = FALSE;
int number_got_up = 0;
int number_of_group = 1;
int number_of_other_group = 1;
/*
* get a light source
*/
if( ch->in_room->light <= 0 )
{
if( ch->mana >= mana_cost( ch, skill_lookup( "continual light" ) ) )
{
do_cast( ch, "'continual light'" );
do_get( ch, "all" );
do_wear( ch, "all" );
return;
}
}
if( ( IS_AFFECTED( ch, AFF_POISON ) ) || ( IS_AFFECTED( ch, AFF_BLIND ) ) )
{
if( IS_AFFECTED( ch, AFF_POISON ) )
if( ch->mana >= mana_cost( ch, skill_lookup( "cure poison" ) ) )
do_cast( ch, "'cure poison'" );
if( IS_AFFECTED( ch, AFF_BLIND ) )
if( ch->mana >= mana_cost( ch, skill_lookup( "cure blindness" ) ) )
do_cast( ch, "'cure blindness'" );
return;
}
/*
* is anyone in group being attacked? if so, assist!
*/
/*
* -leaders will be forced to rescue in the 'mob_is_fighting' function
* * already so no need to check for it here
*/
for( vch = ch->in_room->first_person; vch != NULL; vch = vch->next_in_room )
{
if( ( is_same_group( ch, vch ) ) && ( vch->fighting != NULL ) && ( vch != ch ) )
{
do_assist( ch, "" );
return;
}
}
if( ch->leader == NULL )
{
for( vch = ch->in_room->first_person; vch != NULL; vch = vch->next_in_room )
{
if( is_same_group( ch, vch ) && ( ch != vch ) )
{
number_of_group = number_of_group + 1;
}
}
if( number_of_group < 4 )
{
for( vch = ch->in_room->first_person; vch != NULL; vch = vch->next_in_room )
{
if( vch->leader != NULL )
continue;
if( ( vch != ch ) && ( IS_NPC( vch ) )
&& ( IS_SET( vch->act, ACT_INTELLIGENT ) )
&& ( !is_same_group( ch, vch ) )
&& ( vch->position == POS_STANDING )
&& ( ( get_psuedo_level( vch ) - get_psuedo_level( ch ) <= 20
&& get_psuedo_level( vch ) - get_psuedo_level( ch ) >= -20 )
|| ( get_psuedo_level( ch ) - get_psuedo_level( vch ) <= 20
&& get_psuedo_level( ch ) - get_psuedo_level( vch ) >= -20 ) )
&& ( can_see( vch, ch ) ) && ( can_see( ch, vch ) ) )
{
if( vch->leader == NULL )
{
for( tch = vch->in_room->first_person; tch != NULL; tch = tch->next_in_room )
{
if( is_same_group( tch, vch ) && ( tch != vch ) )
{
number_of_other_group = number_of_other_group + 1;
}
}
}
if( number_of_group + number_of_other_group <= 4 )
{
get_mob_group( ch, vch );
return;
}
}
}
}
}
/*
* do you need to heal?
*/
if( ch->hit < ch->max_hit * 85 / 100 )
{
if( ( ch->mana >= mana_cost( ch, skill_lookup( "heal" ) ) )
|| ( ch->mana >= mana_cost( ch, skill_lookup( "cure critical" ) ) )
|| ( ch->mana >= mana_cost( ch, skill_lookup( "cure serious" ) ) ) )
mob_regen_check( ch, NULL, FALSE );
/*
* if leader is ready to move, just keep standing
*/
if( ( ch->leader != NULL )
&& ( ch->leader->in_room == ch->in_room )
&& ( ch->leader->position == POS_STANDING )
&& ( ch->leader->mana >= ch->leader->max_mana * 85 / 100 )
&& ( ch->leader->hit >= ch->leader->max_hit * 85 / 100 ) )
return;
else
{
if( ch->mana >= ch->max_mana * 75 / 100 )
ready = ready_heal_room( ch );
if( ready == TRUE )
do_sleep( ch, "" );
return;
}
}
if( ch->mana < ch->max_mana * 85 / 100 )
{
do_sleep( ch, "" );
return;
}
/*
* do you need to level? if you have a group leader, have the leader
* * find a the trainer. if you are the leader just go and find the
* * trainer
*/
// ZEN FIX Have them recall then hunt the room
if( able_to_level( ch ) )
{
char_from_room( ch );
char_to_room( ch, get_room_index( 3758 ) );
gain_level( ch );
return;
/*
dir = h_find_dir ( get_room_index(ch->in_room->vnum),
get_room_index(ROOM_VNUM_INT_HEAL),
ch->hunt_flags );
if ( dir == -1 )
gain_level ( ch );
else
{
if ( ( ch->leader != NULL )
&& ( ch->leader->in_room == ch->in_room ) )
{
hunt_move ( ch->leader, dir );
end_hunt ( ch->leader );
return;
}
else
{
hunt_move ( ch, dir );
return;
}
} */
}
/*
* if you're leader and you don't need to gain level, does anyone else
* * in the group?
*/
/*
* actually, the above function will force the leader to find a trainer
* * already. but since i don't want the leader to select a new target
* * until the group gains the needed level, i'll put this check here
*/
for( vch = ch->in_room->first_person; vch != NULL; vch = vch->next_in_room )
{
if( ( is_same_group( vch, ch ) )
&& ( vch->in_room == ch->in_room ) && ( vch->leader == ch ) && ( able_to_level( vch ) ) )
{
dir = h_find_dir( get_room_index( ch->in_room->vnum ), get_room_index( ROOM_VNUM_INT_HEAL ), ch->hunt_flags );
hunt_move( ch, dir );
return;
}
}
/*
* if noone needs to heal or gain level, then let's hunt!
*/
/*
* by the way, only leaders will hunt. followers will just follow and
* * assist when needed
*/
if( ( ch->leader != NULL ) && ( ch->leader->in_room == ch->in_room ) && ( ch->hunting != NULL ) )
{
end_hunt( ch );
}
else if( ( ch->leader != NULL ) && ( ch->leader->in_room == ch->in_room ) && ( ch->hunting == NULL ) )
{
return;
}
else if( is_group_leader( ch ) )
{
for( vch = ch->in_room->first_person; vch != NULL; vch = vch->next_in_room )
{
if( ( vch != ch ) && ( is_same_group( vch, ch ) ) && ( vch->position != POS_STANDING ) )
{
get_up( vch, vch->position );
number_got_up = number_got_up + 1;
}
}
if( number_got_up != 0 )
return;
}
else
{
if( ch->hunting != NULL )
{
for( vch = first_char; vch != NULL; vch = vch->next )
{
if( vch == ch->hunting )
{
prey_still_exist = TRUE;
return;
}
}
if( prey_still_exist == FALSE )
{
ch->hunting = NULL;
}
}
if( ch->hunting == NULL && ch->leader == NULL )
{
select_target( ch );
return;
}
}
/*
* power_up_mob ( ch );
*/
/*
* if ( ch->leader != NULL
* && ch->in_room != ch->leader->in_room )
* {
* do_follow( ch, ch->name );
* }
*/
return;
}
bool valid_target( CHAR_DATA * ch, CHAR_DATA * victim, int l )
{
/*
* Return TRUE if victim is a valid target for ch to kill.
*/
/*
* don't hunt people you can't even see
*/
if( !can_see( ch, victim ) )
return FALSE;
/*
* Don't attack group members or self!
*/
if( is_same_group( ch, victim ) )
return FALSE;
/*
* Don't attack other int mobs!
*/
if( IS_NPC( victim ) && IS_SET( victim->act, ACT_INTELLIGENT ) )
return FALSE;
/*
* Don't attack players.... except for have spec_vamp_hunter
*/
if( ( !IS_NPC( victim ) ) && ( ch->spec_fun != spec_lookup( "spec_vamp_hunter" ) ) )
return FALSE;
/*
* don't attack fairy godmother
*/
if( IS_NPC( victim ) )
if( victim->pIndexData->vnum == 1026 )
return FALSE;
/*
* if IS vamp_hunter, make sure target is a player vamp
*/
if( ( IS_VAMP( victim ) ) && ( !IS_NPC( victim ) ) && ( ch->spec_fun != spec_lookup( "spec_vamp_hunter" ) ) )
return FALSE;
/*
* don't attack NPC VAMPS (they can't die )
*/
if( ( IS_VAMP( victim ) ) && ( IS_NPC( victim ) ) )
return FALSE;
/*
* Only kill victims of similar level
*/
if( ( ( get_psuedo_level( victim ) - get_psuedo_level( ch ) ) > -7 )
|| ( ( get_psuedo_level( ch ) - get_psuedo_level( victim ) ) > 12 ) )
return FALSE;
// if ( ( IS_GOOD( ch ) && IS_GOOD( victim ) )
// || ( IS_EVIL( ch ) && IS_EVIL( victim ) )
// || ( IS_NEUTRAL( ch ) && IS_NEUTRAL( victim ) ) )
// return FALSE;
if( ( ch->spec_fun == spec_lookup( "spec_vamp_hunter" ) ) && ( IS_NPC( victim ) ) && ( number_percent( ) < 20 ) )
return FALSE;
if( ( IS_SET( victim->in_room->room_flags, ROOM_SAFE ) ) || ( IS_SET( victim->act, ACT_SOLO ) )
/*
* || ( IS_SET( victim->in_room->room_flags, ROOM_JAIL_CELL ) )
*/ )
return FALSE;
return TRUE;
}
void select_target( CHAR_DATA * ch )
{
/*
* Find a new target for the group to go after
*/
int average_level;
// int tmp = 0;
CHAR_DATA *vch;
CHAR_DATA *victim = NULL;
char buf[MAX_STRING_LENGTH];
int force_index = 0;
bool alone = TRUE;
bool mob_is_leader = FALSE;
sh_int attempts;
/*
* mobs were doing ethereal travel too much... i've now lowered it to
* * 15% of the time and only if they are not hunting
*/
mob_is_leader = is_group_leader( ch );
if( ( number_percent( ) < 15 ) && ( ch->hunting == NULL ) && ( ch->in_room->vnum != ROOM_VNUM_ETHEREAL_PLANE ) )
/* was victim == NULL, that's always true at this point.. Zen */
{
if( mob_is_leader == TRUE )
{
for( vch = ch->in_room->first_person; vch != NULL; vch = vch->next_in_room )
{
if( ( is_same_group( ch, vch ) ) == TRUE )
{
if( vch->mana < mana_cost( vch, skill_lookup( "ethereal travel" ) ) )
{
return;
}
}
}
}
if( ch->mana < mana_cost( ch, skill_lookup( "ethereal travel" ) ) )
return;
do_say( ch, "This place is boring! I am gonna go somewhere else!" );
for( vch = ch->in_room->first_person; vch != NULL; vch = vch->next_in_room )
{
if( ( is_same_group( vch, ch ) ) && ( ch != vch ) )
{
do_say( vch, "Yeah, it is--we're outta here!" );
do_cast( vch, "ethereal" );
}
}
do_cast( ch, "ethereal" );
}
else
{
/*
* keeps checking until you've found a valid target
*/
attempts = 0;
while( ( victim == NULL ) && ( attempts < 15 ) )
{
// ZEN FIX set average level based on level of ngroup
attempts++;
average_level = get_psuedo_level( ch );
force_index = number_range( 1, 1200 );
/* we currently have about 1300 mobs..this should get a random enough sample */
for( vch = first_char; vch != NULL; vch = vch->next )
{
if( victim != NULL )
break;
force_index--;
if( force_index > 0 )
continue;
if( valid_target( ch, vch, average_level ) )
{
/*
* Trick used in something else...
*/
if( number_range( 0, 1 ) == 0 )
{
victim = vch;
}
if( victim == NULL ) /* screwed up somehow */
{
continue;
}
if( !IS_NPC( victim ) )
{
for( vch = ch->in_room->first_person; vch != NULL; vch = vch->next_in_room )
{
if( is_same_group( ch, vch ) )
{
alone = FALSE;
break;
}
}
if( alone == FALSE )
{
xprintf( buf, "%s We're coming for you!", victim->name );
do_tell( ch, buf );
}
else
{
xprintf( buf, "%s I'm coming for you!", victim->name );
do_tell( ch, buf );
}
}
}
}
}
if( set_hunt( ch, NULL, victim, NULL, HUNT_WORLD | HUNT_PICKDOOR | HUNT_CR, HUNT_MERC ) )
{
xprintf( buf, "Right! %s is our new target!!", victim->short_descr );
do_say( ch, buf );
}
return;
}
return;
}
static const char *group_state_table[] = {
"@@eFleeing@@N",
"@@rFighting@@N",
"@@eCritical Healing@@N",
"@@aReforming@@N",
"@@eCritical Mana@@N",
"@@lHunting@@N",
"@@cNormal Healing@@N",
"@@cNormal Mana@@N",
"@@WLevelling@@N",
"@@yGetting EQ@@N",
"@@pIdling@@N",
"@@eLost@@N"
};
/* i have condensed this function to just three states: MOB_FIGHTING,
* MOB_RESTING/ MOB_SLEEPING, and MOB_STANDING. each of these three states
* will call it's appropriate function. */
void int_group_handler( NPC_GROUP_DATA * ngroup )
{
CHAR_DATA *follower = NULL;
CHAR_DATA *leader = ngroup->leader;
DL_LIST *follower_ptr;
// sh_int followers_want = GRP_STATE_NO_CHANGE;
sh_int leader_wants = GRP_STATE_NO_CHANGE;
sh_int group_count = 1; // start with leader
char monbuf[MSL];
if( leader == NULL )
{
monitor_chan( "No Leader in NPC_GROUP", MONITOR_MOB );
return;
}
// check for followers needs
for( follower_ptr = ngroup->first_follower; follower_ptr; follower_ptr = follower_ptr->next )
{
// check for needing healing, levelling
follower = follower_ptr->this_one;
group_count++;
continue;
}
// check for leader's needs
if( leader->hit < leader->max_hit * 25 / 100 )
{
leader_wants = GRP_STATE_CRIT_HEAL;
}
else if( leader->mana < leader->max_mana * 25 / 100 )
{
leader_wants = GRP_STATE_CRIT_MANA;
}
else if( leader->hit < leader->max_hit * 60 / 100 )
{
leader_wants = GRP_STATE_NORM_HEAL;
}
else if( leader->mana < leader->max_mana * 50 / 100 )
{
leader_wants = GRP_STATE_NORM_MANA;
}
else if( able_to_level( leader ) )
{
leader_wants = GRP_STATE_LEVELING;
}
xprintf( monbuf, "NPC Group Handler, Leader is %s, state is %s", ngroup->leader->name, group_state_table[ngroup->state] );
monitor_chan( monbuf, MONITOR_MOB );
switch ( ngroup->state )
{
case GRP_STATE_CRIT_HEAL:
case GRP_STATE_CRIT_MANA:
case GRP_STATE_NORM_HEAL:
case GRP_STATE_NORM_MANA:
{
bool everyone_ready = TRUE;
bool room_ready = FALSE;
// ready_heal_room( leader );
if( ( leader->mana < leader->max_mana * 85 / 100 ) || ( leader->hit < leader->max_hit * 85 / 100 ) )
{
everyone_ready = FALSE;
if( ( ( room_ready = ready_heal_room( leader ) ) == TRUE ) || ( leader->mana < leader->max_mana * 20 / 100 ) )
{
do_sleep( leader, "" );
}
}
else
{
do_stand( leader, "" );
}
for( follower_ptr = ngroup->first_follower; follower_ptr; follower_ptr = follower_ptr->next )
{
follower = follower_ptr->this_one;
if( ( follower->mana < follower->max_mana * 75 / 100 ) || ( follower->hit < follower->max_hit * 75 / 100 ) )
{
everyone_ready = FALSE;
do_sleep( follower, "" );
}
else
{
do_stand( follower, "" );
}
}
if( everyone_ready == TRUE )
{
ngroup->state = GRP_STATE_IDLE;
}
break;
}
case GRP_STATE_FIGHT:
{ // violence_update will handle
if( ( leader_wants < GRP_STATE_HUNTING ) || ( leader->fighting == NULL ) )
{
bool someone_still_fighting = FALSE;
ngroup->state = GRP_STATE_FLEE;
for( follower_ptr = ngroup->first_follower; follower_ptr; follower_ptr = follower_ptr->next )
{
follower = follower_ptr->this_one;
if( follower->fighting != NULL )
{
do_flee( follower, "" );
someone_still_fighting = TRUE;
}
}
if( someone_still_fighting == FALSE )
{
ngroup->state = GRP_STATE_REFORM;
}
if( leader->fighting != NULL )
{
do_flee( leader, "" );
}
}
break;
}
case GRP_STATE_FLEE:
{
bool someone_still_fighting = FALSE;
for( follower_ptr = ngroup->first_follower; follower_ptr; follower_ptr = follower_ptr->next )
{
follower = follower_ptr->this_one;
if( follower->fighting != NULL )
{
do_flee( follower, "" );
someone_still_fighting = TRUE;
}
}
if( leader->fighting != NULL )
{
do_flee( leader, "" );
someone_still_fighting = TRUE;
}
if( someone_still_fighting == FALSE )
{
ngroup->state = GRP_STATE_REFORM;
}
break;
}
case GRP_STATE_IDLE:
{
// check_re_equip( leader );
// check_rewield( leader );
if( leader_wants < GRP_STATE_NO_CHANGE )
{
ngroup->state = leader_wants;
break;
}
else if( number_percent( ) < 40 )
{
select_target( ngroup->leader );
ngroup->state = GRP_STATE_HUNTING;
break;
}
}
case GRP_STATE_HUNTING:
{ // poll followers later
sh_int move_dir;
if( leader->fighting != NULL )
{
ngroup->state = GRP_STATE_FIGHT;
break;
}
if( leader->hunting == NULL )
{
// xprintf( monbuf, "Leader %s not hunting anything in GRP_STATE_HUNTING",
// leader->name );
// monitor_chan( monbuf, MONITOR_MOB );
select_target( ngroup->leader );
break;
}
if( leader->in_room == leader->hunting->in_room )
{
ngroup->state = GRP_STATE_FIGHT;
multi_hit( leader, leader->hunting, TYPE_UNDEFINED );
break;
}
move_dir = h_find_dir( leader->in_room, leader->hunting->in_room,
HUNT_WORLD | HUNT_OPENDOOR | HUNT_UNLOCKDOOR | HUNT_PICKDOOR );
if( move_dir < 0 ) // can't get there from here
{
ngroup->state = GRP_STATE_LOST;
break;
}
hunt_move( leader, move_dir );
break;
}
case GRP_STATE_LEVELING:
{
char_from_room( leader );
char_to_room( leader, get_room_index( 3758 ) );
if( able_to_level( leader ) )
{
gain_level( leader );
}
for( follower_ptr = ngroup->first_follower; follower_ptr; follower_ptr = follower_ptr->next )
{
follower = follower_ptr->this_one;
if( able_to_level( follower ) )
{
gain_level( follower );
}
}
ngroup->state = GRP_STATE_IDLE;
break;
}
case GRP_STATE_REFORM:
{
bool all_are_here = TRUE;
for( follower_ptr = ngroup->first_follower; follower_ptr; follower_ptr = follower_ptr->next )
{
follower = follower_ptr->this_one;
if( follower->in_room != leader->in_room )
{
sh_int move_dir;
all_are_here = FALSE;
move_dir = h_find_dir( follower->in_room, leader->in_room,
HUNT_WORLD | HUNT_OPENDOOR | HUNT_UNLOCKDOOR | HUNT_PICKDOOR );
if( move_dir < 0 ) // can't get there from here
{
ngroup->state = GRP_STATE_LOST;
break;
}
hunt_move( follower, move_dir );
}
}
if( all_are_here == TRUE )
{
ngroup->state = GRP_STATE_IDLE;
}
break;
}
}
}
void int_handler( CHAR_DATA * ch )
{
int current_state;
current_state = ch->position;
/*
* if you're fighting check on your condition
*/
if( current_state == POS_FIGHTING )
{
mob_is_fighting( ch );
return;
}
/*
* if you are resting or sleeping, check to see if you need to stand up
*/
if( current_state != POS_STANDING )
{
need_to_stand( ch );
return;
}
/*
* cheat so that players cannot get easy xp from almost dead int mobs
*/
/*
* not sure where to place this yet -- will look at this later
*/
if( ch->hit < 100 )
{
ch->hit = ch->max_hit * 50 / 100;
ch->mana = ch->max_mana * 50 / 100;
}
/*
* by now you should be standing
*/
mob_is_standing( ch );
return;
}
/* i've never learned cases before so i'm pretty much leaving this one
* alone, except for taking out the one_arguement() function */
void int_combat_handler( CHAR_DATA * ch, CHAR_DATA * victim )
{
/*
* Called from fight.c during combat to enable mobs to use spells and
* skills. ACT_INTELLIGENT mobs can call cast() now.
* --Stephen
*/
char arg[MAX_STRING_LENGTH];
char buf[MAX_STRING_LENGTH];
CHAR_DATA *vch;
int sn;
int counter = 1;
if( number_percent( ) < 65 )
return;
for( vch = ch->in_room->first_person; vch != NULL; vch = vch->next_in_room )
{
if( vch == victim )
{
xprintf( buf, "%d.%s", counter, vch->name );
break;
}
counter = counter + 1;
}
switch ( number_range( 0, 5 ) ) /* Pick a skill or a spell */
{
case 0:
case 1:
case 2:
case 3:
/*
* Use a skill
*/
switch ( number_range( 0, 5 ) )
{
case 0:
xprintf( arg, "frenzy" );
break;
case 1:
xprintf( arg, "punch %s", buf );
break;
case 2:
xprintf( arg, "knee %s", buf );
break;
case 3:
xprintf( arg, "headbutt %s", buf );
break;
case 4:
xprintf( arg, "punch %s", buf );
break;
case 5:
xprintf( arg, "dirt %s", buf );
break;
}
interpret( ch, arg );
do_say( ch, buf );
break;
default:
sn = find_spell( ch, TAR_CHAR_OFFENSIVE );
if( ( sn != -1 ) && ( ch->mana > mana_cost( ch, sn ) ) )
{
xprintf( arg, "cast '%s' %s", skill_table[sn].name, buf );
interpret( ch, arg );
}
}
return;
}