/***************************************************************************
* 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. *
***************************************************************************/
#if defined(macintosh)
#include <types.h>
#else
#include <sys/types.h>
#endif
#include <stdio.h>
#include <string.h>
#include <time.h>
#include "ack.h"
#include <math.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 ++ );
sprintf ( 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 ) )
{
sprintf( buf, "%s", "Null ch and/or target in mob_group_follow, exiting." );
monitor_chan( buf, MONITOR_MOB );
return;
}
sprintf ( 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 )
sprintf( buf, "Man I don't want to join %s's group!",
target->short_descr );
else
sprintf( 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 )
{
sprintf ( buf, "We're planning on killing %s.",
target->hunting->short_descr );
}
else
{
sprintf ( 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 )
{
sprintf ( buf, "Want to help us kill %s instead?",
ch->hunting->short_descr );
do_say ( ch, buf );
}
else if ( ch_is_leader == FALSE )
{
sprintf ( 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") ) )
sprintf ( buf, "'heal' %s", target->name );
else if ( ch->mana >= mana_cost ( ch, skill_lookup("cure critical") ) )
sprintf ( buf, "'cure critical' %s", target->name );
else if ( ch->mana >= mana_cost ( ch, skill_lookup("cure serious") ) )
sprintf ( 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 )
{
sprintf ( buf, "%s We're coming for you!", victim->name );
do_tell ( ch, buf );
}
else
{
sprintf ( 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 ) )
{
sprintf( 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;
}
sprintf( 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 )
{
// sprintf( 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 )
{
sprintf( 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:
sprintf( arg, "frenzy" );
break;
case 1:
sprintf( arg, "punch %s", buf );
break;
case 2:
sprintf( arg, "knee %s", buf );
break;
case 3:
sprintf( arg, "headbutt %s", buf );
break;
case 4:
sprintf( arg, "punch %s", buf );
break;
case 5:
sprintf( 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 ) ) )
{
sprintf( arg, "cast '%s' %s", skill_table[sn].name, buf );
interpret( ch, arg );
}
}
return;
}