From arrasjid@netcom.com Wed Nov 9 03:45:00 1994
Received: from mail2.netcom.com by farside.atinc.com with SMTP (5.65/1.2-eef)
id AA18862; Wed, 9 Nov 94 03:45:00 -0500
Return-Path: <arrasjid@netcom.com>
Received: from cs.tut.fi by mail2.netcom.com (8.6.9/Netcom)
id AAA27752; Wed, 9 Nov 1994 00:27:13 -0800
Received: from kaarne.cs.tut.fi (turtle@kaarne.cs.tut.fi [130.230.3.2]) by cs.tut.fi (8.6.9/8.6.4) with ESMTP id KAA12048 for <merc-l@netcom.com>; Wed, 9 Nov 1994 10:29:01 +0200
From: Kilpikoski Mikko <turtle@cs.tut.fi>
Received: (turtle@localhost) by kaarne.cs.tut.fi (8.6.8/8.6.4) id KAA11444 for merc-l@netcom.com; Wed, 9 Nov 1994 10:26:22 +0200
Message-Id: <199411090826.KAA11444@kaarne.cs.tut.fi>
Subject: hunt.c (faster than graph.c)
To: merc-l@netcom.com
Date: Wed, 9 Nov 1994 10:26:21 +0200 (EET)
X-Mailer: ELM [version 2.4 PL23]
Mime-Version: 1.0
Content-Type: text/plain; charset=ISO-8859-1
Content-Transfer-Encoding: 8bit
Content-Length: 16082
Status: RO
HUNTING
-------
Some time ago someone posted graph.c on the list, and it was pretty nice.
The code was clean and well commented, but I found it too slow. A longer
while ago there was another hunt code posted here, and it was a lot faster.
(Though it contained a whole bunch of files and the code didn't look as nice.)
Well, here I post it again, in one file and re-indended to look a bit
cleaner.
The code was obtained from ftp.atinc.com:/pub/mud/outgoing/track.merc21.tar.gz.
It seems to originate from SillyMUD.
Installation (Merc22)
---------------------
The code should work as well with envies and older mercs, though some changes
may be needed. The following files will be modified:
Makefile, act_wiz.c, const.c, db.c, fight.c, interp.c, and merc.h
Makefile
--------
- add hunt.o to O_FILES list
act_wiz.c
---------
- add to do_mstat right after showing the mob spec:
if ( IS_NPC(victim) && victim->hunting != NULL )
{
sprintf(buf, "Hunting victim: %s (%s)\n\r",
IS_NPC(victim->hunting) ? victim->hunting->short_descr
: victim->hunting->name,
IS_NPC(victim->hunting) ? "MOB" : "PLAYER" );
strcat(buf1, buf);
}
- change the line
send_to_char( " thirst drunk full", ch );
in do_mset to:
send_to_char( " thirst drunk full hunt", ch );
- add to do_mset:
/* Change their hunting status. */
else if (!str_cmp(arg2, "hunt"))
{
CHAR_DATA *hunted = 0;
if ( !IS_NPC(victim) )
{
send_to_char( "Not on PC's.\n\r", ch );
return;
}
if ( str_cmp( arg3, "." ) )
if ( (hunted = get_char_area(victim, arg3)) == NULL )
{
send_to_char("Mob couldn't locate the victim to hunt.\n\r", ch);
return;
}
victim->hunting = hunted;
return;
}
const.c
-------
- add skill for hunting in skill table:
{
"hunt", { 37, 37, 30, 20 },
spell_null, TAR_IGNORE, POS_RESTING,
&gsn_hunt, SLOT( 0), 0, 12,
"", "!Hunt!"
},
db.c
----
- add gsn declaration:
sh_int gsn_hunt;
fight.c
-------
- add the violence_update before lines
if ( ( victim = ch->fighting ) == NULL || ch->in_room == NULL )
continue;
right after lines
for ( ch = char_list; ch != NULL; ch = ch->next )
{
ch_next = ch->next;
the following:
/*
* Hunting mobs.
*/
if ( IS_NPC(ch)
&& ch->fighting == NULL
&& IS_AWAKE(ch)
&& ch->hunting != NULL )
{
hunt_victim(ch);
continue;
}
interp.c
--------
- add command for hunting:
{ "hunt", do_hunt, POS_STANDING, 0, LOG_NORMAL },
merc.h
------
- add hunting data to char_data structure:
CHAR_DATA * hunting; /* Used by hunting routine */
- add declaration for do_hunt:
DECLARE_DO_FUN( do_hunt );
- add hunt_victim definition:
/* hunt.c */
void hunt_victim args( ( CHAR_DATA *ch ) );
I hope I didn't leave anything vital out, but if anything fails to work,
feel free to consult me. I myself have the code installed in my mud, and
it works fine. The times needed to hunt down someone are really a _lot_
quicker that with graph.c.
hunt.c
------
And here is the hunt.c file itself:
/*
SillyMUD Distribution V1.1b (c) 1993 SillyMUD Developement
See license.doc for distribution terms. SillyMUD is based on DIKUMUD
Modifications by Rip in attempt to port to merc 2.1
*/
/*
Modified by Turtle for Merc22 (07-Nov-94)
I got this one from ftp.atinc.com:/pub/mud/outgoing/track.merc21.tar.gz.
It cointained 5 files: README, hash.c, hash.h, skills.c, and skills.h.
I combined the *.c and *.h files in this hunt.c, which should compile
without any warnings or errors.
*/
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include "merc.h"
void bcopy(char *s1,char* s2,int len);
void bzero(char *sp,int len);
extern const char * dir_name[];
struct hash_link
{
int key;
struct hash_link *next;
void *data;
};
struct hash_header
{
int rec_size;
int table_size;
int *keylist, klistsize, klistlen; /* this is really lame,
AMAZINGLY lame */
struct hash_link **buckets;
};
#define WORLD_SIZE 30000
#define HASH_KEY(ht,key)((((unsigned int)(key))*17)%(ht)->table_size)
struct hunting_data
{
char *name;
struct char_data **victim;
};
struct room_q
{
int room_nr;
struct room_q *next_q;
};
struct nodes
{
int visited;
int ancestor;
};
#define IS_DIR (get_room_index(q_head->room_nr)->exit[i])
#define GO_OK (!IS_SET( IS_DIR->exit_info, EX_CLOSED ))
#define GO_OK_SMARTER 1
void init_hash_table(struct hash_header *ht,int rec_size,int table_size)
{
ht->rec_size = rec_size;
ht->table_size= table_size;
ht->buckets = (void*)calloc(sizeof(struct hash_link**),table_size);
ht->keylist = (void*)malloc(sizeof(ht->keylist)*(ht->klistsize=128));
ht->klistlen = 0;
}
void init_world(ROOM_INDEX_DATA *room_db[])
{
/* zero out the world */
bzero((char *)room_db,sizeof(ROOM_INDEX_DATA *)*WORLD_SIZE);
}
void destroy_hash_table(struct hash_header *ht,void (*gman)())
{
int i;
struct hash_link *scan,*temp;
for(i=0;i<ht->table_size;i++)
for(scan=ht->buckets[i];scan;)
{
temp = scan->next;
(*gman)(scan->data);
free(scan);
scan = temp;
}
free(ht->buckets);
free(ht->keylist);
}
void _hash_enter(struct hash_header *ht,int key,void *data)
{
/* precondition: there is no entry for <key> yet */
struct hash_link *temp;
int i;
temp = (struct hash_link *)malloc(sizeof(struct hash_link));
temp->key = key;
temp->next = ht->buckets[HASH_KEY(ht,key)];
temp->data = data;
ht->buckets[HASH_KEY(ht,key)] = temp;
if(ht->klistlen>=ht->klistsize)
{
ht->keylist = (void*)realloc(ht->keylist,sizeof(*ht->keylist)*
(ht->klistsize*=2));
}
for(i=ht->klistlen;i>=0;i--)
{
if(ht->keylist[i-1]<key)
{
ht->keylist[i] = key;
break;
}
ht->keylist[i] = ht->keylist[i-1];
}
ht->klistlen++;
}
ROOM_INDEX_DATA *room_find(ROOM_INDEX_DATA *room_db[],int key)
{
return((key<WORLD_SIZE&&key>-1)?room_db[key]:0);
}
void *hash_find(struct hash_header *ht,int key)
{
struct hash_link *scan;
scan = ht->buckets[HASH_KEY(ht,key)];
while(scan && scan->key!=key)
scan = scan->next;
return scan ? scan->data : NULL;
}
int room_enter(ROOM_INDEX_DATA *rb[],int key,ROOM_INDEX_DATA *rm)
{
ROOM_INDEX_DATA *temp;
temp = room_find(rb,key);
if(temp) return(0);
rb[key] = rm;
return(1);
}
int hash_enter(struct hash_header *ht,int key,void *data)
{
void *temp;
temp = hash_find(ht,key);
if(temp) return 0;
_hash_enter(ht,key,data);
return 1;
}
ROOM_INDEX_DATA *room_find_or_create(ROOM_INDEX_DATA *rb[],int key)
{
ROOM_INDEX_DATA *rv;
rv = room_find(rb,key);
if(rv) return rv;
rv = (ROOM_INDEX_DATA *)malloc(sizeof(ROOM_INDEX_DATA));
rb[key] = rv;
return rv;
}
void *hash_find_or_create(struct hash_header *ht,int key)
{
void *rval;
rval = hash_find(ht, key);
if(rval) return rval;
rval = (void*)malloc(ht->rec_size);
_hash_enter(ht,key,rval);
return rval;
}
int room_remove(ROOM_INDEX_DATA *rb[],int key)
{
ROOM_INDEX_DATA *tmp;
tmp = room_find(rb,key);
if(tmp)
{
rb[key] = 0;
free(tmp);
}
return(0);
}
void *hash_remove(struct hash_header *ht,int key)
{
struct hash_link **scan;
scan = ht->buckets+HASH_KEY(ht,key);
while(*scan && (*scan)->key!=key)
scan = &(*scan)->next;
if(*scan)
{
int i;
struct hash_link *temp, *aux;
temp = (*scan)->data;
aux = *scan;
*scan = aux->next;
free(aux);
for(i=0;i<ht->klistlen;i++)
if(ht->keylist[i]==key)
break;
if(i<ht->klistlen)
{
bcopy((char *)ht->keylist+i+1,(char *)ht->keylist+i,(ht->klistlen-i)
*sizeof(*ht->keylist));
ht->klistlen--;
}
return temp;
}
return NULL;
}
void room_iterate(ROOM_INDEX_DATA *rb[],void (*func)(),void *cdata)
{
register int i;
for(i=0;i<WORLD_SIZE;i++)
{
ROOM_INDEX_DATA *temp;
temp = room_find(rb,i);
if(temp) (*func)(i,temp,cdata);
}
}
void hash_iterate(struct hash_header *ht,void (*func)(),void *cdata)
{
int i;
for(i=0;i<ht->klistlen;i++)
{
void *temp;
register int key;
key = ht->keylist[i];
temp = hash_find(ht,key);
(*func)(key,temp,cdata);
if(ht->keylist[i]!=key) /* They must have deleted this room */
i--; /* Hit this slot again. */
}
}
int exit_ok( EXIT_DATA *pexit )
{
ROOM_INDEX_DATA *to_room;
if ( ( pexit == NULL )
|| ( to_room = pexit->to_room ) == NULL )
return 0;
return 1;
}
void donothing()
{
return;
}
int find_path( int in_room_vnum, int out_room_vnum, CHAR_DATA *ch,
int depth, int in_zone )
{
struct room_q *tmp_q, *q_head, *q_tail;
struct hash_header x_room;
int i, tmp_room, count=0, thru_doors;
ROOM_INDEX_DATA *herep;
ROOM_INDEX_DATA *startp;
EXIT_DATA *exitp;
if ( depth <0 )
{
thru_doors = TRUE;
depth = -depth;
}
else
{
thru_doors = FALSE;
}
startp = get_room_index( in_room_vnum );
init_hash_table( &x_room, sizeof(int), 2048 );
hash_enter( &x_room, in_room_vnum, (void *) - 1 );
/* initialize queue */
q_head = (struct room_q *) malloc(sizeof(struct room_q));
q_tail = q_head;
q_tail->room_nr = in_room_vnum;
q_tail->next_q = 0;
while(q_head)
{
herep = get_room_index( q_head->room_nr );
/* for each room test all directions */
if( herep->area == startp->area || !in_zone )
{
/* only look in this zone...
saves cpu time and makes world safer for players */
for( i = 0; i <= 5; i++ )
{
exitp = herep->exit[i];
if( exit_ok(exitp) && ( thru_doors ? GO_OK_SMARTER : GO_OK ) )
{
/* next room */
tmp_room = herep->exit[i]->to_room->vnum;
if( tmp_room != out_room_vnum )
{
/* shall we add room to queue ?
count determines total breadth and depth */
if( !hash_find( &x_room, tmp_room )
&& ( count < depth ) )
/* && !IS_SET( RM_FLAGS(tmp_room), DEATH ) ) */
{
count++;
/* mark room as visted and put on queue */
tmp_q = (struct room_q *)
malloc(sizeof(struct room_q));
tmp_q->room_nr = tmp_room;
tmp_q->next_q = 0;
q_tail->next_q = tmp_q;
q_tail = tmp_q;
/* ancestor for first layer is the direction */
hash_enter( &x_room, tmp_room,
((int)hash_find(&x_room,q_head->room_nr)
== -1) ? (void*)(i+1)
: hash_find(&x_room,q_head->room_nr));
}
}
else
{
/* have reached our goal so free queue */
tmp_room = q_head->room_nr;
for(;q_head;q_head = tmp_q)
{
tmp_q = q_head->next_q;
free(q_head);
}
/* return direction if first layer */
if ((int)hash_find(&x_room,tmp_room)==-1)
{
if (x_room.buckets)
{
/* junk left over from a previous track */
destroy_hash_table(&x_room, donothing);
}
return(i);
}
else
{
/* else return the ancestor */
int i;
i = (int)hash_find(&x_room,tmp_room);
if (x_room.buckets)
{
/* junk left over from a previous track */
destroy_hash_table(&x_room, donothing);
}
return( -1+i);
}
}
}
}
}
/* free queue head and point to next entry */
tmp_q = q_head->next_q;
free(q_head);
q_head = tmp_q;
}
/* couldn't find path */
if( x_room.buckets )
{
/* junk left over from a previous track */
destroy_hash_table( &x_room, donothing );
}
return -1;
}
void do_hunt( CHAR_DATA *ch, char *argument )
{
char buf[MAX_STRING_LENGTH];
char arg[MAX_STRING_LENGTH];
CHAR_DATA *victim;
int direction;
bool fArea;
one_argument( argument, arg );
if( arg[0] == '\0' )
{
send_to_char( "Whom are you trying to hunt?\n\r", ch );
return;
}
/* only imps can hunt to different areas */
fArea = ( get_trust(ch) < MAX_LEVEL );
if( fArea )
victim = get_char_area( ch, arg );
else
victim = get_char_world( ch, arg );
if( victim == NULL )
{
send_to_char("No-one around by that name.\n\r", ch );
return;
}
if( ch->in_room == victim->in_room )
{
act( "$N is here!", ch, NULL, victim, TO_CHAR );
return;
}
/*
* Deduct some movement.
*/
if( ch->move > 2 )
ch->move -= 3;
else
{
send_to_char( "You're too exhausted to hunt anyone!\n\r", ch );
return;
}
act( "$n carefully sniffs the air.", ch, NULL, NULL, TO_ROOM );
WAIT_STATE( ch, skill_table[gsn_hunt].beats );
direction = find_path( ch->in_room->vnum, victim->in_room->vnum,
ch, -40000, fArea );
if( direction == -1 )
{
act( "You couldn't find a path to $N from here.",
ch, NULL, victim, TO_CHAR );
return;
}
if( direction < 0 || direction > 5 )
{
send_to_char( "Hmm... Something seems to be wrong.\n\r", ch );
return;
}
/*
* Give a random direction if the player misses the die roll.
*/
if( ( IS_NPC (ch) && number_percent () > 75) /* NPC @ 25% */
|| (!IS_NPC (ch) && number_percent () > /* PC @ norm */
ch->pcdata->learned[gsn_hunt] ) )
{
do
{
direction = number_door();
}
while( ( ch->in_room->exit[direction] == NULL )
|| ( ch->in_room->exit[direction]->to_room == NULL) );
}
/*
* Display the results of the search.
*/
sprintf( buf, "$N is %s from here.", dir_name[direction] );
act( buf, ch, NULL, victim, TO_CHAR );
return;
}
void hunt_victim( CHAR_DATA *ch )
{
int dir;
bool found;
CHAR_DATA *tmp;
if( ch == NULL || ch->hunting == NULL || !IS_NPC(ch) )
return;
/*
* Make sure the victim still exists.
*/
for( found = 0, tmp = char_list; tmp && !found; tmp = tmp->next )
if( ch->hunting == tmp )
found = 1;
if( !found || !can_see( ch, ch->hunting ) )
{
do_say( ch, "Damn! My prey is gone!!" );
ch->hunting = NULL;
return;
}
if( ch->in_room == ch->hunting->in_room )
{
act( "$n glares at $N and says, 'Ye shall DIE!'",
ch, NULL, ch->hunting, TO_NOTVICT );
act( "$n glares at you and says, 'Ye shall DIE!'",
ch, NULL, ch->hunting, TO_VICT );
act( "You glare at $N and say, 'Ye shall DIE!",
ch, NULL, ch->hunting, TO_CHAR);
multi_hit( ch, ch->hunting, TYPE_UNDEFINED );
ch->hunting = NULL;
return;
}
WAIT_STATE( ch, skill_table[gsn_hunt].beats );
dir = find_path( ch->in_room->vnum, ch->hunting->in_room->vnum,
ch, -40000, TRUE );
if( dir < 0 || dir > 5 )
{
act( "$n says 'Damn! Lost $M!'", ch, NULL, ch->hunting, TO_ROOM );
ch->hunting = NULL;
return;
}
/*
* Give a random direction if the mob misses the die roll.
*/
if( number_percent () > 75 ) /* @ 25% */
{
do
{
dir = number_door();
}
while( ( ch->in_room->exit[dir] == NULL )
|| ( ch->in_room->exit[dir]->to_room == NULL ) );
}
if( IS_SET( ch->in_room->exit[dir]->exit_info, EX_CLOSED ) )
{
do_open( ch, (char *) dir_name[dir] );
return;
}
move_char( ch, dir );
return;
}
That's all there is to hunt... Read you later :)
--
Mikko Kilpikoski __ Sig? Naaah...
E-Mail: turtle@modeemi.cs.tut.fi /__\@ I feel too relaxed
WWW: http://modeemi.cs.tut.fi/~turtle L L for that...
MUD: vichy.modeemi.cs.tut.fi (130.230.11.124) 2011
=============================================================================
/ ______ _______ ____ _____ ___ __ _ ______ ____ ____ _____ /
\ | ____|__ __| _ \ / ____\ / _ \| \ / | ____| / __ \| _ \ / ____\ \
/ | |__ | | | |_| | | | |_| | |\/| | |___ | | | | |_| | | /
/ | ___| | | | ___/| | __| _ | | | | ____| | | | | __/| | ___ \
\ | | | | | | | |___| | | | | | | | |____ | |__| | |\ \| |___| | /
/ |_| |_| |_| o \_____/|_| |_|_| |_|______|o \____/|_| \_|\_____/ \
\ /
============================================================================
------------------------------------------------------------------------------
ftp://ftp.game.org/pub/mud FTP.GAME.ORG http://www.game.org/ftpsite/
------------------------------------------------------------------------------
This file came from FTP.GAME.ORG, the ultimate source for MUD resources.
------------------------------------------------------------------------------