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:
extern sh_int gsn_hunt;
- 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.
*/
/*
Modified by Tyche for Merc22 - 9/5/2011
Removed extraneous code.
Added application specific hash and queue implementations.
Cleaned up and tweaked code for performance.
*/
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#ifdef TIME_HUNT
#include <sys/time.h>
#endif
#include "merc.h"
extern const char *dir_name[];
#define ROOMS_TABLE_SIZE 1063
#define MAKE_ROOM_HASH(key) (((unsigned int)(key))%ROOMS_TABLE_SIZE)
struct rooms_node {
ROOM_INDEX_DATA *key;
int value;
struct rooms_node *next;
};
struct rooms_table {
struct rooms_node *buckets[ROOMS_TABLE_SIZE];
};
struct search_node {
ROOM_INDEX_DATA *room;
struct search_node *next;
};
struct search_queue {
struct search_node *head;
struct search_node *tail;
};
void init_rooms_table (struct rooms_table *rt)
{
int i;
for (i = 0; i < ROOMS_TABLE_SIZE; i++)
rt->buckets[i] = NULL;
}
void destroy_rooms_table (struct rooms_table *rt)
{
int i;
struct rooms_node *entry, *temp;
for (i = 0; i < ROOMS_TABLE_SIZE; i++)
for (entry = rt->buckets[i]; entry;) {
temp = entry->next;
free (entry);
entry = temp;
}
}
void rooms_table_add (struct rooms_table *rt, ROOM_INDEX_DATA * key,
int value)
{
/* precondition: there is no entry for <key> yet */
struct rooms_node *temp;
unsigned int idx;
idx = MAKE_ROOM_HASH (key);
temp = (struct rooms_node *) malloc (sizeof (struct rooms_node));
temp->key = key;
temp->next = rt->buckets[idx];
temp->value = value;
rt->buckets[idx] = temp;
}
int rooms_table_find (struct rooms_table *rt, ROOM_INDEX_DATA * key)
{
struct rooms_node *entry;
unsigned int idx;
idx = MAKE_ROOM_HASH (key);
entry = rt->buckets[idx];
while (entry && entry->key != key)
entry = entry->next;
return entry ? entry->value : 0;
}
void init_search_queue (struct search_queue *sq)
{
sq->head = NULL;
sq->tail = NULL;
}
void destroy_search_queue (struct search_queue *sq)
{
struct search_node *entry, *temp;
for (entry = sq->head; entry;) {
temp = entry->next;
free (entry);
entry = temp;
}
}
ROOM_INDEX_DATA *search_queue_pop (struct search_queue *sq)
{
ROOM_INDEX_DATA *room;
struct search_node *entry;
if (sq->head == NULL)
return NULL;
room = sq->head->room;
entry = sq->head->next;
free (sq->head);
sq->head = entry;
return room;
}
void search_queue_push (struct search_queue *sq, ROOM_INDEX_DATA * room)
{
struct search_node *entry;
entry = (struct search_node *) malloc (sizeof (struct search_node));
entry->room = room;
if (sq->head == NULL) {
entry->next = NULL;
sq->head = entry;
sq->tail = entry;
} else {
entry->next = sq->tail->next;
sq->tail->next = entry;
sq->tail = sq->tail->next;
}
}
struct hunting_data {
char *name;
struct char_data **victim;
};
bool exit_ok (EXIT_DATA * pexit, bool go_thru_doors)
{
if (pexit == NULL || pexit->to_room == NULL)
return FALSE;
if (go_thru_doors)
return TRUE;
if (IS_SET (pexit->exit_info, EX_CLOSED))
return FALSE;
return TRUE;
}
int find_path (ROOM_INDEX_DATA * startp, ROOM_INDEX_DATA * endp,
CHAR_DATA * ch, int depth, bool in_zone)
{
struct search_queue s_queue;
struct rooms_table x_room;
int i, count = 0, direction = -1;
bool thru_doors, first_pass = TRUE;
ROOM_INDEX_DATA *herep, *tmp_room;
#ifdef TIME_HUNT
char buf[MAX_STRING_LENGTH];
struct timeval start = { 0, 0 };
struct timeval stop = { 0, 0 };
struct timeval result = { 0, 0 };
double timing;
gettimeofday (&start, 0);
#endif
if (depth < 0) {
thru_doors = TRUE;
depth = -depth;
} else {
thru_doors = FALSE;
}
init_rooms_table (&x_room);
rooms_table_add (&x_room, startp, -1);
/* initialize queue */
init_search_queue (&s_queue);
search_queue_push (&s_queue, startp);
while ((herep = search_queue_pop (&s_queue)) != NULL) {
/* only look in the same zone...unless option picked */
if (herep->area == startp->area || !in_zone) {
/* for each room look in all directions */
for (i = 0; i <= 5; i++) {
/* make sure exit is valid */
if (exit_ok (herep->exit[i], thru_doors)) {
tmp_room = herep->exit[i]->to_room;
if (tmp_room != endp) {
/* shall we add room to queue?
count determines total breadth and depth */
if (!rooms_table_find (&x_room, tmp_room)
&& (count < depth)) {
count++;
/* put room on queue for further checking of it's exits */
search_queue_push (&s_queue, tmp_room);
/* add room to list of already searched, using it's ancestor for
the direction, unless this is the first pass */
rooms_table_add (&x_room, tmp_room,
first_pass ? (i + 1) : rooms_table_find (&x_room, herep));
}
} else {
/* we have found our target room */
direction = rooms_table_find (&x_room, herep);
/* return direction if first layer */
if (direction == -1)
direction = i;
else
--direction;
goto finished;
}
}
}
}
first_pass = FALSE;
}
finished:
/* couldn't find path */
destroy_search_queue (&s_queue);
destroy_rooms_table (&x_room);
#ifdef TIME_HUNT
gettimeofday (&stop, 0);
timersub (&stop, &start, &result);
timing = ((double) result.tv_sec * 1000000) + ((double) result.tv_usec);
if (IS_IMMORTAL (ch)) {
sprintf (buf, "Total time was %f microseconds in search of %d rooms.\n",
timing, count);
send_to_char (buf, ch);
}
#endif
return direction;
}
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, victim->in_room, 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, ch->hunting->in_room, 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