/**************************************************************************** * [S]imulated [M]edieval [A]dventure multi[U]ser [G]ame | * * -----------------------------------------------------------| \\._.// * * SmaugWiz (C) 1998 by Russ Pillsbury (Windows NT version) | (0...0) * * -----------------------------------------------------------| ).:.( * * SMAUG (C) 1994, 1995, 1996 by Derek Snider | {o o} * * -----------------------------------------------------------| / ' ' \ * * SMAUG code team: Thoric, Altrag, Blodkai, Narn, Haus, |~'~.VxvxV.~'~* * Scryn, Swordbearer, Rennard, Tricops, and Gorog. | * * ------------------------------------------------------------------------ * * Merc 2.1 Diku Mud improvments copyright (C) 1992, 1993 by Michael * * Chastain, Michael Quan, and Mitchell Tse. * * Original Diku Mud copyright (C) 1990, 1991 by Sebastian Hammer, * * Michael Seifert, Hans Henrik Staerfeldt, Tom Madsen, and Katja Nyboe. * * ------------------------------------------------------------------------ * * Tracking/hunting module * ****************************************************************************/ #include "stdafx.h" #include "smaug.h" #include "skill.h" #include "mobiles.h" #include "objects.h" #include "rooms.h" #include "Exits.h" #include "descriptor.h" #include "character.h" #include "sysdata.h" #define BFS_ERROR -1 #define BFS_ALREADY_THERE -2 #define BFS_NO_PATH -3 #define TRACK_THROUGH_DOORS extern short top_room; /* You can define or not define TRACK_THOUGH_DOORS, above, depending on whether or not you want track to find paths which lead through closed or hidden doors. */ struct bfs_queue_struct { CRoomIndexData *room; char dir; struct bfs_queue_struct *next; }; static struct bfs_queue_struct *queue_head = NULL, *queue_tail = NULL, *room_queue = NULL; CRoomIndexData *toroom (CRoomIndexData *room, short door) { return (get_exit (room, door)->GetToRoom ()); } BOOL valid_edge (CRoomIndexData *room, short door) { CExitData *pexit; CRoomIndexData *to_room; pexit = get_exit (room, door); if (pexit && (to_room = pexit->GetToRoom ()) != NULL #ifndef TRACK_THROUGH_DOORS && !IS_SET (pexit->exit_info, EX_CLOSED) #endif && ! to_room->IsMarked ()) return TRUE; else return FALSE; } void bfs_enqueue (CRoomIndexData *room, char dir) { struct bfs_queue_struct *curr; curr = new bfs_queue_struct; curr->room = room; curr->dir = dir; curr->next = NULL; if (queue_tail) { queue_tail->next = curr; queue_tail = curr; } else queue_head = queue_tail = curr; } void bfs_dequeue (void) { struct bfs_queue_struct *curr; curr = queue_head; if (! (queue_head = queue_head->next)) queue_tail = NULL; delete curr; } void bfs_clear_queue (void) { while (queue_head) bfs_dequeue (); } void room_enqueue (CRoomIndexData *room) { struct bfs_queue_struct *curr; curr = new bfs_queue_struct; curr->room = room; curr->next = room_queue; room_queue = curr; } void clean_room_queue (void) { bfs_queue_struct *curr, *curr_next; for (curr = room_queue; curr; curr = curr_next) { curr->room->UnMarkRoom (); curr_next = curr->next; delete curr; } room_queue = NULL; } int find_first_step (CRoomIndexData *src, CRoomIndexData *target, int maxdist) { int curr_dir, count; if (!src || !target) { bug ("Illegal value passed to find_first_step (track.c)", 0); return BFS_ERROR; } if (src == target) return BFS_ALREADY_THERE; if (src->GetArea () != target->GetArea ()) return BFS_NO_PATH; room_enqueue (src); src->MarkRoom (); /* first, enqueue the first steps, saving which direction we're going. */ for (curr_dir = 0; curr_dir < 10; curr_dir++) if (valid_edge (src, curr_dir)) { toroom (src, curr_dir)->MarkRoom (); room_enqueue (toroom (src, curr_dir)); bfs_enqueue (toroom (src, curr_dir), curr_dir); } count = 0; while (queue_head) { if (++count > maxdist) { bfs_clear_queue (); clean_room_queue (); return BFS_NO_PATH; } if (queue_head->room == target) { curr_dir = queue_head->dir; bfs_clear_queue (); clean_room_queue (); return curr_dir; } else { for (curr_dir = 0; curr_dir < 10; curr_dir++) if (valid_edge (queue_head->room, curr_dir)) { toroom (queue_head->room, curr_dir)->MarkRoom (); room_enqueue (toroom (queue_head->room, curr_dir)); bfs_enqueue (toroom (queue_head->room, curr_dir),queue_head->dir); } bfs_dequeue (); } } clean_room_queue (); return BFS_NO_PATH; } void do_track (CCharacter *ch, char *argument) { CCharacter *vict; char arg[MAX_INPUT_LENGTH]; char buf[MAX_STRING_LENGTH]; int dir, maxdist; if (!ch->IsNpc () && !ch->GetPcData ()->learned [gsn_track]) { ch->SendText ("You do not know of this skill yet.\n\r"); return; } one_argument (argument, arg); if (arg[0]=='\0') { ch->SendText ("Whom are you trying to track?\n\r"); return; } WAIT_STATE (ch, SkillTable.GetBeats (gsn_track)); if (! (vict = get_char_world (ch, arg))) { ch->SendText ("You can't find a trail of anyone like that.\n\r"); return; } maxdist = 100 + ch->GetLevel () * 30; if (!ch->IsNpc ()) maxdist = (maxdist * ch->GetPcData ()->learned[gsn_track]) / 100; dir = find_first_step (ch->GetInRoom (), vict->GetInRoom (), maxdist); switch (dir) { case BFS_ERROR: ch->SendText ("Hmm... something seems to be wrong.\n\r"); break; case BFS_ALREADY_THERE: ch->SendText ("You're already in the same room!\n\r"); break; case BFS_NO_PATH: sprintf (buf, "You can't sense a trail from here.\n\r"); ch->SendText (buf); learn_from_failure (ch, gsn_track); break; default: ch->SendTextf ("You sense a trail %s from here...\n\r", dir_name[dir]); learn_from_success (ch, gsn_track); break; } } void found_prey (CCharacter *ch, CCharacter *victim) { char buf[MAX_STRING_LENGTH]; char victname[MAX_STRING_LENGTH]; if (victim == NULL) { bug ("Found_prey: null victim", 0); return; } if (victim->GetInRoom () == NULL) { bug ("Found_prey: null victim->GetInRoom ()", 0); return; } sprintf (victname, victim->IsNpc () ? victim->GetShortDescr () : victim->GetName ()); if (!can_see (ch, victim)) { if (number_percent () < 90) return; switch (number_bits (2)) { case 0: sprintf (buf, "Don't make me find you, %s!", victname); do_say (ch, buf); break; case 1: act (AT_ACTION, "$n sniffs around the room for $N.", ch, NULL, victim, TO_NOTVICT); act (AT_ACTION, "You sniff around the room for $N.", ch, NULL, victim, TO_CHAR); act (AT_ACTION, "$n sniffs around the room for you.", ch, NULL, victim, TO_VICT); sprintf (buf, "I can smell your blood!"); do_say (ch, buf); break; case 2: sprintf (buf, "I'm going to tear %s apart!", victname); do_yell (ch, buf); break; case 3: do_say (ch, "Just wait until I find you..."); break; } return; } if (ch->GetInRoom ()->IsSafe ()) { if (number_percent () < 90) return; switch (number_bits (2)) { case 0: do_say (ch, "C'mon out, you coward!"); sprintf (buf, "%s is a bloody coward!", victname); do_yell (ch, buf); break; case 1: sprintf (buf, "Let's take this outside, %s", victname); do_say (ch, buf); break; case 2: sprintf (buf, "%s is a yellow-bellied wimp!", victname); do_yell (ch, buf); break; case 3: act (AT_ACTION, "$n takes a few swipes at $N.", ch, NULL, victim, TO_NOTVICT); act (AT_ACTION, "You try to take a few swipes $N.", ch, NULL, victim, TO_CHAR); act (AT_ACTION, "$n takes a few swipes at you.", ch, NULL, victim, TO_VICT); break; } return; } switch (number_bits (2)) { case 0: sprintf (buf, "Your blood is mine, %s!", victname); do_yell (ch, buf); break; case 1: sprintf (buf, "Alas, we meet again, %s!", victname); do_say (ch, buf); break; case 2: sprintf (buf, "What do you want on your tombstone, %s?", victname); do_say (ch, buf); break; case 3: act (AT_ACTION, "$n lunges at $N from out of nowhere!", ch, NULL, victim, TO_NOTVICT); act (AT_ACTION, "You lunge at $N catching $M off guard!", ch, NULL, victim, TO_CHAR); act (AT_ACTION, "$n lunges at you from out of nowhere!", ch, NULL, victim, TO_VICT); } stop_hunting (ch); set_fighting (ch, victim); multi_hit (ch, victim, TYPE_UNDEFINED); return; } void hunt_victim (CCharacter *ch) { BOOL found; CCharacter *tmp; short ret; if (!ch || !ch->hunting) return; /* make sure the char still exists */ for (found = FALSE, tmp = first_char; tmp && !found; tmp = tmp->GetNext ()) if (ch->hunting->who == tmp) found = TRUE; if (!found) { do_say (ch, "Damn! My prey is gone!!"); stop_hunting (ch); return; } if (ch->GetInRoom () == ch->hunting->who->GetInRoom ()) { if (ch->GetFightData ()) return; found_prey (ch, ch->hunting->who); return; } ret = find_first_step (ch->GetInRoom (), ch->hunting->who->GetInRoom (), 500 + ch->GetLevel () * 25); if (ret<0) { do_say (ch, "Damn! Lost my prey!"); stop_hunting (ch); return; } else { move_char (ch, get_exit (ch->GetInRoom (), ret), FALSE); if (!ch->hunting) { if (!ch->GetInRoom ()) { char buf[MAX_STRING_LENGTH]; sprintf (buf, "Hunt_victim: no ch->GetInRoom ()! Mob #%d, name: %s. Placing mob in limbo.", ch->GetMobIndex ()->vnum, ch->GetName ()); bug (buf, 0); ch->SendToRoom (RoomTable.GetRoom (SysData.m_RoomLimbo)); return; } do_say (ch, "Damn! Lost my prey!"); return; } if (ch->GetInRoom () == ch->hunting->who->GetInRoom ()) found_prey (ch, ch->hunting->who); return; } }