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