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