/***************************************************************************
* 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!*
***************************************************************************/
/* Mob/player hunting.. */
/* Copied this from one of my old MUDs.. Much cleaner than the sillymud
hunt routines -- Alty */
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <ctype.h>
#include "globals.h"
#ifndef DEC_ACT_COMM_H
#include "h/act_comm.h"
#endif
#ifndef DEC_ACT_MOVE_H
#include "h/act_move.h"
#endif
#ifndef DEC_ACT_WIZ_H
#include "h/act_wiz.h"
#endif
#ifndef DEC_COMM_H
#include "h/comm.h"
#endif
#define NEVER_FREE_HUNT
H_QUEUE *h_head = NULL;
H_QUEUE *h_tail = NULL;
#ifdef NEVER_FREE_HUNT
H_QUEUE *h_free = NULL;
void setup_hunt( void );
#endif
#ifdef DEBUG_HUNT_CODE
static FILE *h_fp;
#endif
void h_enqueue( ROOM_INDEX_DATA * room, short dir )
{
H_QUEUE *hunt;
#ifdef NEVER_FREE_HUNT
if( h_free )
{
hunt = h_free;
h_free = h_free->next;
}
else
#endif
hunt = (H_QUEUE *)getmem( sizeof( *hunt ) );
hunt->next = NULL;
hunt->room = room;
hunt->dir = dir;
room->room_flags.set(RFLAG_HUNT_MARK);
if( !h_head )
h_head = hunt;
else
h_tail->next = hunt;
h_tail = hunt;
#ifdef DEBUG_HUNT_CODE
fprintf( h_fp, "Enqueue: %5d - %d\n", room->vnum, is_set( room->room_flags, RFLAG_HUNT_MARK ) );
fflush( h_fp );
#endif
return;
}
void h_dequeue( void )
{
H_QUEUE *hunt;
if( !( hunt = h_head ) )
return;
h_head = hunt->next;
if( h_tail == hunt )
h_tail = NULL;
hunt->room->room_flags.reset(RFLAG_HUNT_MARK);
#ifdef DEBUG_HUNT_CODE
fprintf( h_fp, "Dequeue: %5d\n", hunt->room->vnum );
fflush( h_fp );
#endif
#ifdef NEVER_FREE_HUNT
hunt->next = h_free;
h_free = hunt;
#else
dispose( hunt, sizeof( *hunt ) );
#endif
return;
}
void h_clear( void )
{
#ifdef DEBUG_HUNT_CODE
fprintf( h_fp, "h_clear\n" );
fflush( h_fp );
#endif
while( h_head != NULL )
h_dequeue( );
#ifdef DEBUG_HUNT_CODE
fprintf( h_fp, "Cleared\n" );
fflush( h_fp );
#endif
}
bool h_is_valid_exit( ROOM_INDEX_DATA * room, short dir, int h_flags )
{
EXIT_DATA *exit = room->exit[dir];
if( !exit )
return FALSE;
if( !exit->to_room )
return FALSE;
#ifdef DEBUG_HUNT_CODE
fprintf( h_fp, "IsValid: %5d - %s\n", exit->to_room->vnum,
( is_set( exit->to_room->room_flags, RFLAG_HUNT_MARK ) ? "set" : "unset" ) );
fflush( h_fp );
#endif
if( exit->to_room->room_flags.test(RFLAG_HUNT_MARK) )
return FALSE;
if( !IS_SET( h_flags, HUNT_WORLD ) && room->area != exit->to_room->area )
return FALSE;
if( exit->exit_info.test(EX_CLOSED) )
{
if( !IS_SET( h_flags, HUNT_OPENDOOR ) )
return FALSE;
if( exit->exit_info.test(EX_LOCKED) )
{
if( !IS_SET( h_flags, HUNT_UNLOCKDOOR | HUNT_PICKDOOR ) )
return FALSE;
if( !IS_SET( h_flags, HUNT_UNLOCKDOOR ) && exit->exit_info.test(EX_PICKPROOF) )
return FALSE;
}
}
return TRUE;
}
void h_enqueue_room( ROOM_INDEX_DATA * room, short dir, int h_flags )
{
short edir;
#ifdef DEBUG_HUNT_CODE
fprintf( h_fp, "h_enqueue_room\n" );
fflush( h_fp );
#endif
for( edir = 0; edir < 6; edir++ )
if( h_is_valid_exit( room, edir, h_flags ) )
h_enqueue( room->exit[edir]->to_room, ( dir == -1 ? edir : dir ) );
return;
}
short h_find_dir( ROOM_INDEX_DATA * room, ROOM_INDEX_DATA * target, int h_flags )
{
H_QUEUE *hunt;
if( room == target )
return -1;
#ifdef DEBUG_HUNT_CODE
if( !h_fp )
h_fp = file_open( "hunt.out", "w" );
fprintf( h_fp, "h_find_dir\n" );
fflush( h_fp );
#endif
#ifdef NEVER_FREE_HUNT
if( !h_free && !h_head && !h_tail )
setup_hunt( );
#endif
room->room_flags.set(RFLAG_HUNT_MARK);
h_enqueue_room( room, -1, h_flags );
for( hunt = h_head; hunt; hunt = hunt->next )
{
if( hunt->room == target )
{
short dir = hunt->dir;
#ifdef DEBUG_HUNT_CODE
fprintf( h_fp, "Found dir %d\n", dir );
fflush( h_fp );
#endif
h_clear( );
room->room_flags.reset(RFLAG_HUNT_MARK);
return dir;
}
h_enqueue_room( hunt->room, hunt->dir, h_flags );
}
#ifdef DEBUG_HUNT_CODE
fprintf( h_fp, "Invalid dir\n" );
fflush( h_fp );
#endif
h_clear( );
room->room_flags.reset(RFLAG_HUNT_MARK);
return -1;
}
bool set_hunt( CHAR_DATA * ch, CHAR_DATA * fch, CHAR_DATA * vch, OBJ_DATA * vobj, int set_flags, int rem_flags )
{
int nflags;
ROOM_INDEX_DATA *troom;
char buf[MAX_STRING_LENGTH];
troom = ( vch ? vch->in_room : vobj ? vobj->in_room : NULL );
nflags = ( ( ch ? ch->hunt_flags : 0 ) | set_flags ) & ~rem_flags;
if( !ch || !troom || h_find_dir( ch->in_room, troom, nflags ) < 0 )
return FALSE;
ch->hunting = vch;
ch->hunt_obj = vobj;
ch->hunt_for = fch;
if( IS_NPC( ch ) )
ch->hunt_home = ( ch->hunt_home ? ch->hunt_home : ch->in_room );
else
ch->hunt_home = NULL;
if( ch->searching )
{
free_string( ch->searching );
ch->searching = NULL;
}
ch->hunt_flags = nflags;
snprintf( buf, MSL, "%s has started hunting (%s) %s",
NAME( ch ),
( vch ? IS_NPC( vch ) ? "mobile" : "player" : "object" ), ( vch ? NAME( vch ) : vobj->short_descr ) );
if( fch )
snprintf( buf + strlen( buf ), (2 * MIL), " for %s", NAME( fch ) );
monitor_chan( buf, MONITOR_HUNTING );
/* bug(buf, 0); */
return TRUE;
}
void end_hunt( CHAR_DATA * ch )
{
ch->hunting = NULL;
ch->hunt_obj = NULL;
ch->hunt_for = NULL;
if( !IS_NPC( ch ) )
{
ch->hunt_home = NULL;
ch->hunt_flags = 0;
}
else
ch->hunt_flags = ch->pIndexData->hunt_flags;
if( ch->searching )
{
free_string( ch->searching );
ch->searching = NULL;
}
}
bool has_key args( ( CHAR_DATA * ch, int key ) );
void hunt_move( CHAR_DATA * mob, short dir )
{
EXIT_DATA *exit = mob->in_room->exit[dir];
if( exit->exit_info.test(EX_CLOSED) )
{
if( exit->exit_info.test(EX_LOCKED) )
{
if( IS_SET( mob->hunt_flags, HUNT_UNLOCKDOOR ) && has_key( mob, exit->key ) )
do_unlock( mob, dir_name[dir] );
else if( IS_SET( mob->hunt_flags, HUNT_PICKDOOR ) && !exit->exit_info.test(EX_PICKPROOF) )
do_pick( mob, dir_name[dir] );
}
else if( IS_SET( mob->hunt_flags, HUNT_OPENDOOR ) )
do_open( mob, dir_name[dir] );
}
else
move_char( mob, dir, FALSE );
return;
}
/*#define NAME(ch) (IS_NPC(ch) ? ch->short_descr : ch->name)*/
bool mob_hunt( CHAR_DATA * mob )
{
short dir;
char buf[128];
if( !mob || !IS_NPC( mob ) )
return FALSE;
if( !mob->hunting )
{
if( mob->hunt_obj != NULL )
{
if( mob->hunt_obj->in_room == NULL )
{
if( IS_SET( mob->hunt_flags, HUNT_CR ) && mob->hunt_for && mob->hunt_obj->item_type == ITEM_CORPSE_PC )
act( "$N tells you 'Someone else seems to have gotten to your "
"corpse before me.'", mob->hunt_for, NULL, mob, TO_CHAR );
end_hunt( mob );
return TRUE;
}
if( can_see_obj( mob, mob->hunt_obj ) && mob->in_room == mob->hunt_obj->in_room )
{
if( IS_SET( mob->hunt_flags, HUNT_CR ) && mob->hunt_for && mob->hunt_obj->item_type == ITEM_CORPSE_PC )
act( "$N tell you 'I have found your corpse. I shall return it "
"to you now.", mob->hunt_for, NULL, mob, TO_CHAR );
obj_from_room( mob->hunt_obj );
obj_to_char( mob->hunt_obj, mob );
act( "$n gets $o.", mob, mob->hunt_obj, NULL, TO_ROOM );
set_hunt( mob, NULL, mob->hunt_for, mob->hunt_obj, 0, 0 );
return TRUE;
}
if( !can_see_obj( mob, mob->hunt_obj ) ||
( dir = h_find_dir( mob->in_room, mob->hunt_obj->in_room, mob->hunt_flags ) ) < 0 )
{
if( IS_SET( mob->hunt_flags, HUNT_CR ) && mob->hunt_for && mob->hunt_obj->item_type == ITEM_CORPSE_PC )
act( "$N tells you 'I seem to have lost the way to your corpse.'", mob->hunt_for, NULL, mob, TO_CHAR );
end_hunt( mob );
return TRUE;
}
hunt_move( mob, dir );
if( mob->in_room == mob->hunt_obj->in_room )
mob_hunt( mob );
}
/*
* deleted because the hunt is started in mobile_update
* else if ( mob->searching &&
* (mob->hunting = get_char_world(mob, mob->searching)) != NULL )
* {
* free_string(mob->searching);
* mob->searching = NULL;
* }
* --Aeria
*/
else if( mob->hunt_home )
{
dir = -1;
if( mob->in_room == mob->hunt_home || ( dir = h_find_dir( mob->in_room, mob->hunt_home, mob->hunt_flags ) ) < 0 )
{
mob->hunt_home = NULL;
mob->hunt_flags = mob->pIndexData->hunt_flags;
}
else if( dir >= 0 )
hunt_move( mob, dir );
}
else
{
return FALSE;
}
return TRUE;
}
if( !can_see( mob, mob->hunting ) )
{
if( IS_SET( mob->hunt_flags, HUNT_MERC ) && mob->hunt_for )
{
/*
* 6.25% chance of giving up, 18.75% chance of telling employer.
*/
switch ( number_bits( 4 ) )
{
case 0:
snprintf( buf, MSL, "$N tells you '%s seems to have disappeared!'", NAME( mob->hunting ) );
act( buf, mob->hunt_for, NULL, mob, TO_CHAR );
end_hunt( mob );
return TRUE;
case 1:
case 2:
case 3:
snprintf( buf, MSL, "$N tells you '%s seems to have disappeared! I shall "
"find %s though!'", NAME( mob->hunting ),
( mob->hunting->sex == SEX_MALE ? "him" : mob->hunting->sex == SEX_FEMALE ? "her" : "it" ) );
act( buf, mob->hunt_for, NULL, mob, TO_CHAR );
return TRUE;
}
}
if( IS_SET( mob->hunt_flags, HUNT_INFORM ) )
{
switch ( number_bits( 5 ) )
{
case 0:
snprintf( buf, MSL, "Where are you, %s?", NAME( mob->hunting ) );
break;
case 1:
snprintf( buf, MSL, "Why can't I find you, %s?", NAME( mob->hunting ) );
break;
case 2:
snprintf( buf, MSL, "I know you're out there, %s!", NAME( mob->hunting ) );
break;
case 3:
snprintf( buf, MSL, "I'll find you, %s, just wait!", NAME( mob->hunting ) );
break;
default:
return FALSE;
}
do_yell( mob, buf );
return TRUE;
}
return FALSE;
}
if( mob->in_room == mob->hunting->in_room )
{
if( IS_SET( mob->hunt_flags, HUNT_CR ) && mob->hunt_obj && mob->hunt_obj->item_type == ITEM_CORPSE_PC )
{
act( "$N tells you 'I have returned with your corpse!'", mob->hunting, NULL, mob, TO_CHAR );
/*
* Ok maybe im a little paranoid here.. :).. -- Alty
*/
if( mob->hunt_obj->carried_by == mob )
{
if( mob->hunt_obj->wear_loc != WEAR_NONE )
unequip_char( mob, mob->hunt_obj );
act( "$n drops $o.", mob, mob->hunt_obj, NULL, TO_ROOM );
obj_from_char( mob->hunt_obj );
obj_to_room( mob->hunt_obj, mob->in_room );
}
end_hunt( mob );
return TRUE;
}
if( IS_SET( mob->hunt_flags, HUNT_MERC ) && mob->hunt_for )
{
snprintf( buf, MSL, "$N tells you 'I have found %s! Now %s shall die!'",
NAME( mob->hunting ),
( mob->hunting->sex == SEX_FEMALE ? "she" : mob->hunting->sex == SEX_MALE ? "he" : "it" ) );
act( buf, mob->hunt_for, NULL, mob, TO_CHAR );
}
switch ( number_bits( 2 ) )
{
case 0:
snprintf( buf, MSL, "Now I have you, %s!", NAME( mob->hunting ) );
break;
case 1:
snprintf( buf, MSL, "I knew you'd be here, %s!", NAME( mob->hunting ) );
break;
case 2:
snprintf( buf, MSL, "Did you really think you were safe, %s?", NAME( mob->hunting ) );
break;
case 3:
snprintf( buf, MSL, "So here you are, %s!", NAME( mob->hunting ) );
break;
}
if( IS_SET( mob->hunt_flags, HUNT_INFORM ) )
do_yell( mob, buf );
else
do_say( mob, buf );
one_hit( mob, mob->hunting, TYPE_UNDEFINED );
end_hunt( mob );
return TRUE;
}
if( ( dir = h_find_dir( mob->in_room, mob->hunting->in_room, mob->hunt_flags ) ) == -1 )
{
if( IS_SET( mob->hunt_flags, HUNT_MERC ) && mob->hunt_for )
{
/*
* 6.25% chance of giving up, 18.75% chance of informing employer
*/
switch ( number_bits( 4 ) )
{
case 0:
snprintf( buf, MSL, "$N tells you 'I seem to have lost %s's trail.'", NAME( mob->hunting ) );
act( buf, mob->hunt_for, NULL, mob, TO_CHAR );
end_hunt( mob );
return TRUE;
case 1:
case 2:
case 3:
snprintf( buf, MSL, "$N tells you 'I seem to have lost %s's trail. I shall "
"find it again, though!'", NAME( mob->hunting ) );
act( buf, mob->hunt_for, NULL, mob, TO_CHAR );
return TRUE;
}
}
if( IS_SET( mob->hunt_flags, HUNT_INFORM ) )
{
switch ( number_bits( 6 ) )
{
case 0:
snprintf( buf, MSL, "Where are you hiding, %s?", NAME( mob->hunting ) );
break;
case 1:
snprintf( buf, MSL, "You can't run forever, %s!", NAME( mob->hunting ) );
break;
case 2:
snprintf( buf, MSL, "Come out, come out, wherever you are, %s!", NAME( mob->hunting ) );
break;
case 3:
snprintf( buf, MSL, "I promise I won't hurt you, %s.", NAME( mob->hunting ) );
break;
default:
return FALSE;
}
do_yell( mob, buf );
return TRUE;
}
return FALSE;
}
hunt_move( mob, dir );
if( mob->in_room == mob->hunting->in_room )
mob_hunt( mob );
return TRUE;
}
/*#undef NAME*/
void char_hunt( CHAR_DATA * ch )
{
short dir;
char buf[MAX_STRING_LENGTH];
if( IS_NPC( ch ) )
return;
if( !ch->hunting )
{
if( ch->hunt_obj )
{
if( !can_see_obj( ch, ch->hunt_obj ) || !ch->hunt_obj->in_room )
{
snprintf( buf, MSL, "@@RYou seem to have lost the trail to %s.@@N\n\r", ch->hunt_obj->short_descr );
send_to_char( buf, ch );
end_hunt( ch );
}
else if( ch->hunt_obj->in_room == ch->in_room )
{
snprintf( buf, MSL, "@@RAhhh. You have found %s!@@N\n\r", ch->hunt_obj->short_descr );
send_to_char( buf, ch );
end_hunt( ch );
}
else if( ( dir = h_find_dir( ch->in_room, ch->hunt_obj->in_room, ch->hunt_flags ) ) < 0 )
{
snprintf( buf, MSL, "@@RYou seem to have lost the trail to %s.@@N\n\r", ch->hunt_obj->short_descr );
send_to_char( buf, ch );
end_hunt( ch );
}
else
{
snprintf( buf, MSL, "@@RYou sense that %s is %s of here.@@N\n\r", ch->hunt_obj->short_descr, dir_name[dir] );
send_to_char( buf, ch );
}
}
return;
}
if( !can_see( ch, ch->hunting ) )
{
send_to_char( "@@RYou seem to have lost your prey.@@N\n\r", ch );
end_hunt( ch );
}
else if( ch->in_room == ch->hunting->in_room )
{
send_to_char( "@@RAhhh. You have found your prey!@@N\n\r", ch );
end_hunt( ch );
}
else if( ( dir = h_find_dir( ch->in_room, ch->hunting->in_room, ch->hunt_flags ) ) < 0 )
{
send_to_char( "@@RYou seem to have lost your prey.@@N\n\r", ch );
end_hunt( ch );
}
else
{
snprintf( buf, MSL, "@@RYou sense your prey is %s of here.@@N\n\r", dir_name[dir] );
send_to_char( buf, ch );
}
return;
}
void do_hunt( CHAR_DATA * ch, char *argument )
{
CHAR_DATA *victim;
char arg[MAX_INPUT_LENGTH];
short chance;
if( IS_NPC( ch ) && ( ch->hunting || ch->hunt_obj ) )
return;
argument = one_argument( argument, arg );
if( !*arg )
{
send_to_char( "Hunt for whom?\n\r", ch );
return;
}
if( !IS_NPC( ch ) && IS_WOLF( ch ) && ( IS_SHIFTED( ch ) || IS_RAGED( ch ) ) )
victim = get_char_world( ch, arg );
else
victim = ( get_trust( ch ) >= MAX_LEVEL ? get_char_world( ch, arg ) : get_char_area( ch, arg ) );
if( victim == ch )
{
if( ch->hunting )
{
snprintf( arg, MIL, "You stop hunting %s.\n\r", NAME( ch->hunting ) );
send_to_char( arg, ch );
}
else if( ch->hunt_obj )
{
snprintf( arg, MIL, "You stop looking for %s.\n\r", ch->hunt_obj->short_descr );
send_to_char( arg, ch );
}
else
{
send_to_char( "You find yourself right where you're standing!\n\r", ch );
}
end_hunt( ch );
return;
}
else if( !IS_IMMORTAL( ch ) && ( victim != NULL ) && !IS_NPC( victim ) && IS_IMMORTAL( victim ) )
{
snprintf( arg, MIL, "You can't hunt Immortal %s!\n\r", NAME( victim ) );
send_to_char( arg, ch );
return;
}
/*
* 100% chance of finding them if you're looking right at them.. :)
*/
if( victim != NULL && victim->in_room == ch->in_room )
{
send_to_char( "You're already there!\n\r", ch );
return;
}
/*
* Chance of picking up wrong trail.. (25% for NPC, PC @ normal)
*/
chance = ( IS_NPC( ch ) ? 75 : ch->pcdata->learned[gsn_hunt] );
if( !IS_NPC( ch ) && IS_WOLF( ch ) && ( IS_SHIFTED( ch ) || IS_RAGED( ch ) ) )
chance = ( ( MAX_WOLF_LEVEL - ch->pcdata->super->generation ) * 4 ) + ch->pcdata->super->level;
if( chance < number_percent( ) )
{
CHAR_DATA *vch;
short vcnt = 0;
victim = NULL;
for( vch = first_char; vch; vch = vch->next )
{
if( IS_NPC( vch ) && vch->in_room &&
vch->in_room->area == ch->in_room->area && vch->in_room != ch->in_room && number_range( 0, vcnt ) == 0 )
victim = vch;
vcnt++;
}
}
/*
* Max_level people can hunt through the world, and anyone who has
* practiced over 70% can hunt through doors.. -- Alty
*/
if( !IS_NPC( ch ) && IS_WOLF( ch ) && ( IS_SHIFTED( ch ) || IS_RAGED( ch ) ) )
ch->hunt_flags = HUNT_WORLD | HUNT_OPENDOOR | HUNT_UNLOCKDOOR | HUNT_PICKDOOR;
else if( !IS_NPC( ch ) )
ch->hunt_flags = ( get_trust( ch ) >= MAX_LEVEL ? HUNT_WORLD : 0 )
| ( ch->pcdata->learned[gsn_hunt] >= 70 ? HUNT_OPENDOOR | HUNT_UNLOCKDOOR | HUNT_PICKDOOR : 0 );
if( !victim || !set_hunt( ch, NULL, victim, NULL, 0, HUNT_CR | HUNT_MERC ) )
{
send_to_char( "You couldn't find a trail.\n\r", ch );
return;
}
return;
}
#ifdef NEVER_FREE_HUNT
#define MAX_BUCKET_SIZE 4096
#define TOP_BUCKET_LIST 4095
void setup_hunt( void )
{
H_QUEUE *bucket;
int bcnt;
bucket = (H_QUEUE *)getmem( MAX_BUCKET_SIZE * sizeof( *bucket ) );
for( bcnt = 0; bcnt < MAX_BUCKET_SIZE; bcnt++ )
bucket[bcnt].next = ( bcnt < TOP_BUCKET_LIST ? &bucket[bcnt + 1] : h_free );
h_free = &bucket[0];
return;
}
#undef TOP_BUCKET_SIZE
#undef MAX_BUCKET_SIZE
#endif