/*************************************************************************** * God Wars Mud copyright (C) 1994, 1995, 1996 by Richard Woolcock * * * * Legend of Chrystancia copyright (C) 1999, 2000, 2001 by Matthew Little * * This mud is NOT to be copied in whole or in part, or to be run without * * the permission of Matthew Little. Nobody else has permission to * * authorise the use of this code. * ***************************************************************************/ #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); 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; } DO_COM (do_hunt) { char buf[MAX_STRING_LENGTH]; char arg[MAX_STRING_LENGTH]; CHAR_DATA *victim; int direction; bool fArea; one_argument (argument, arg); if (!IS_CLASS (ch, CLASS_WEREWOLF) && !IS_CLASS (ch, CLASS_NINJA) && !IS_CLASS (ch, CLASS_DEMON) && !IS_IMPLEMENTOR (ch)) { do_rand_typo (ch); return; } if (IS_CLASS (ch, CLASS_DEMON) && !IS_SET (ch->warp, WARP_HUNT)) { stc ("You need the hunting warp to hunt!\n\r", ch); return; } 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 = (!IS_IMPLEMENTOR (ch)); 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 (IS_IMMORTAL (victim) && !IS_IMPLEMENTOR (ch)) { send_to_char ("You failed to get any scent.\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); act ("You carefully sniff the air.", ch, NULL, NULL, TO_CHAR); /* WAIT_STATE( ch, skill_table[gsn_hunt].beats ); */ WAIT_STATE (ch, 8); 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; } /* 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; }