/**************************************************************************
* Original Diku Mud copyright (C) 1990, 1991 by Sebastian Hammer, *
* Michael Seifert, Hans Henrik St{rfeldt, Tom Madsen, and Katja Nyboe. *
* *
* Merc Diku Mud improvements copyright (C) 1992, 1993 by Michael *
* Chastain, Michael Quan, and Mitchell Tse. *
* *
* 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. *
* *
* Much time and thought has gone into this software and you are *
* benefiting. We hope that you share your changes too. What goes *
* around, comes around. *
***************************************************************************
* ROM 2.4 is copyright 1993-1998 Russ Taylor *
* ROM has been brought to you by the ROM consortium *
* Russ Taylor (rtaylor@hypercube.org) *
* Gabrielle Taylor (gtaylor@hypercube.org) *
* Brian Moore (zump@rom.org) *
* By using this code, you have agreed to follow the terms of the *
* ROM license, in the file Rom24/doc/rom.license *
***************************************************************************
* 1stMUD ROM Derivative (c) 2001-2002 by Ryan Jennings *
* http://1stmud.dlmud.com/ <r-jenn@shaw.ca> *
***************************************************************************/
#include <sys/types.h>
#include <time.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include "merc.h"
#include "interp.h"
struct hash_link
{
int key;
struct hash_link *next;
void *data;
};
struct hash_header
{
int rec_size;
int table_size;
int *keylist, klistsize, klistlen;
struct hash_link **buckets;
};
#define HASH_KEY(ht,key)((((unsigned int)(key))*17)%(ht)->table_size)
struct hunting_data
{
char *name;
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
args((struct hash_header * ht, int rec_size, int table_size));
void init_world args((ROOM_INDEX_DATA * room_db[]));
CHAR_DATA *get_char_area_restrict args((CHAR_DATA * ch, char *argument));
void destroy_hash_table args((struct hash_header * ht));
void _hash_enter args((struct hash_header * ht, int key, void *data));
ROOM_INDEX_DATA *room_find args((ROOM_INDEX_DATA * room_db[], int key));
void *hash_find args((struct hash_header * ht, int key));
int room_enter args((ROOM_INDEX_DATA * rb[], int key, ROOM_INDEX_DATA * rm));
int hash_enter args((struct hash_header * ht, int key, void *data));
ROOM_INDEX_DATA *room_find_or_create args((ROOM_INDEX_DATA * rb[], int key));
void *hash_find_or_create args((struct hash_header * ht, int key));
int room_remove args((ROOM_INDEX_DATA * rb[], int key));
void *hash_remove args((struct hash_header * ht, int key));
int exit_ok args((EXIT_DATA * pexit));
int find_path
args((int in_room_vnum, int out_room_vnum, CHAR_DATA * ch, int depth,
int in_zone));
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 =
(struct hash_link **) calloc(sizeof(*ht->buckets), table_size);
ht->keylist = (int *) calloc(sizeof(*ht->keylist), (ht->klistsize = 128));
ht->klistlen = 0;
}
void init_world(ROOM_INDEX_DATA * room_db[])
{
memset(room_db, 0, sizeof(ROOM_INDEX_DATA *) * top_room);
}
CHAR_DATA *get_char_area(CHAR_DATA * ch, char *argument)
{
char arg[MIL];
CHAR_DATA *ach;
int number;
int count;
if (IS_NULLSTR(argument))
return NULL;
if ((ach = get_char_room(ch, NULL, argument)) != NULL)
return ach;
number = number_argument(argument, arg);
count = 0;
for (ach = char_first; ach != NULL; ach = ach->next)
{
if (ach->in_room == NULL
|| ach->in_room->area != ch->in_room->area
|| !can_see(ch, ach) || !is_name(arg, ach->name))
continue;
if (++count == number)
return ach;
}
return NULL;
}
void destroy_hash_table(struct hash_header *ht)
{
int i;
struct hash_link *scan, *temp;
for (i = 0; i < ht->table_size; i++)
for (scan = ht->buckets[i]; scan;)
{
temp = scan->next;
free(scan);
scan = temp;
}
free(ht->buckets);
free(ht->keylist);
}
void _hash_enter(struct hash_header *ht, int key, void *data)
{
struct hash_link *temp;
int i;
temp = (struct hash_link *) calloc(sizeof(*temp), 1);
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 =
(int *) 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 < top_room && 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 *) calloc(sizeof(*rv), 1);
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 = (struct hash_link *) (*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)
{
memcpy((char *) ht->keylist + i + 1,
(char *) ht->keylist + i,
(ht->klistlen - i) * sizeof(*ht->keylist));
ht->klistlen--;
}
return temp;
}
return NULL;
}
int exit_ok(EXIT_DATA * pexit)
{
ROOM_INDEX_DATA *to_room;
if ((pexit == NULL) || (to_room = pexit->u1.to_room) == NULL)
return 0;
return 1;
}
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);
q_head = (struct room_q *) calloc(sizeof(*q_head), 1);
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);
if (herep->area == startp->area || !in_zone)
{
for (i = 0; i < MAX_DIR; i++)
{
exitp = herep->exit[i];
if (exit_ok(exitp) && (thru_doors ? GO_OK_SMARTER : GO_OK))
{
tmp_room = herep->exit[i]->u1.to_room->vnum;
if (tmp_room != out_room_vnum)
{
if (!hash_find(&x_room, tmp_room) && (count < depth))
{
count++;
tmp_q = (struct room_q *) calloc(sizeof(*tmp_q), 1);
tmp_q->room_nr = tmp_room;
tmp_q->next_q = 0;
q_tail->next_q = tmp_q;
q_tail = tmp_q;
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
{
tmp_room = q_head->room_nr;
for (; q_head; q_head = tmp_q)
{
tmp_q = q_head->next_q;
free(q_head);
}
if ((int) hash_find(&x_room, tmp_room) == -1)
{
if (x_room.buckets)
{
destroy_hash_table(&x_room);
}
return (i);
}
else
{
i = (int) hash_find(&x_room, tmp_room);
if (x_room.buckets)
{
destroy_hash_table(&x_room);
}
return (-1 + i);
}
}
}
}
}
tmp_q = q_head->next_q;
free(q_head);
q_head = tmp_q;
}
if (x_room.buckets)
{
destroy_hash_table(&x_room);
}
return -1;
}
CH_CMD(do_hunt)
{
char buf[MSL];
char arg[MSL];
CHAR_DATA *victim;
int direction;
bool fArea;
one_argument(argument, arg);
if (get_skill(ch, gsn_hunt) == 0 || !can_use_skpell(ch, gsn_hunt))
{
chprintln(ch, "You don't know how to hunt.");
return;
}
if (arg[0] == '\0')
{
chprintln(ch, "Whom are you trying to hunt?");
return;
}
fArea = (get_trust(ch) < MAX_LEVEL);
if (IS_NPC(ch))
victim = get_char_world(ch, arg);
else if (fArea)
victim = get_char_area(ch, arg);
else
victim = get_char_world(ch, arg);
if (victim == NULL)
{
chprintln(ch, "No-one around by that name.");
return;
}
if (ch->in_room == victim->in_room)
{
act("$N is here!", ch, NULL, victim, TO_CHAR);
return;
}
if (ch->move > 2)
ch->move -= 3;
else
{
chprintln(ch, "You're too exhausted to hunt anyone!");
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)
{
chprintln(ch, "Hmm... Something seems to be wrong.");
return;
}
if ((IS_NPC(ch) && number_percent() > 50) ||
(!IS_NPC(ch) && number_percent() > get_skill(ch, gsn_hunt)))
{
do
{
direction = number_door();
}
while ((ch->in_room->exit[direction] == NULL) ||
(ch->in_room->exit[direction]->u1.to_room == NULL));
}
sprintf(buf, "$N is %s from here.", dir_name[direction]);
act(buf, ch, NULL, victim, TO_CHAR);
check_improve(ch, gsn_hunt, TRUE, 1);
return;
}
void hunt_victim(CHAR_DATA * ch)
{
int dir;
bool found;
CHAR_DATA *tmp;
if (ch == NULL || ch->hunting == NULL || !IS_NPC(ch))
return;
for (found = 0, tmp = char_first; tmp && !found; tmp = tmp->next)
if (ch->hunting == tmp)
found = 1;
if (!found || !can_see(ch, ch->hunting))
{
do_function(ch, &do_say, "Damn! My prey is gone!!");
ch->hunting = NULL;
return;
}
if (ch->in_room == ch->hunting->in_room)
{
if (number_percent() < 60)
{
act("" CTAG(_SAY1) "$n" CTAG(_SAY1) " glares at $N"
CTAG(_SAY1) " and says, '" CTAG(_SAY2)
"Ye shall DIE!" CTAG(_SAY1) "'{x", ch, NULL,
ch->hunting, TO_NOTVICT);
act("" CTAG(_SAY1) "$n" CTAG(_SAY1)
" glares at you and says, '" CTAG(_SAY2)
"Ye shall DIE!" CTAG(_SAY1) "'{x", ch, NULL,
ch->hunting, TO_VICT);
act("" CTAG(_SAY1) "You glare at $N" CTAG(_SAY1)
" and say, '" CTAG(_SAY2) "Ye shall DIE!"
CTAG(_SAY1) "'{x", ch, NULL, ch->hunting, TO_CHAR);
}
else
{
act("" CTAG(_SAY1) "$n" CTAG(_SAY1) " glares at $N"
CTAG(_SAY1) " and says, '" CTAG(_SAY2)
"Hey, I remember you!" CTAG(_SAY1) "'{x", ch, NULL,
ch->hunting, TO_NOTVICT);
act("" CTAG(_SAY1) "$n" CTAG(_SAY1)
" glares at you and says, '" CTAG(_SAY2)
"Hey, I remember you!" CTAG(_SAY1) "'{x", ch, NULL,
ch->hunting, TO_VICT);
act("" CTAG(_SAY1) "You glare at $N" CTAG(_SAY1)
" and say, '" CTAG(_SAY2) "Hey, I remember you!"
CTAG(_SAY1) "'{x", 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("" CTAG(_SAY1) "$n" CTAG(_SAY1) " says '" CTAG(_SAY2)
"Damn! Lost $M" CTAG(_SAY1) "!'{x", ch, NULL, ch->hunting,
TO_ROOM);
ch->hunting = NULL;
return;
}
if (number_percent() > 50)
{
do
{
dir = number_door();
}
while ((ch->in_room->exit[dir] == NULL) ||
(ch->in_room->exit[dir]->u1.to_room == NULL));
}
if (IS_SET(ch->in_room->exit[dir]->exit_info, EX_CLOSED))
{
do_function(ch, &do_open, (char *) dir_name[dir]);
return;
}
move_char(ch, dir, FALSE);
return;
}