/*************************************************************************** * GreedMud 0.99.7 improvements copyright (C) 1997-2001 * * by Vasco Costa. * * * * Much time and thought has gone into this software and you are * * benefitting. We hope that you share your changes too. What goes * * around, comes around. * ***************************************************************************/ #include <sys/types.h> #include <ctype.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <time.h> #include "merc.h" /* * Structure types. */ typedef struct bfs_queue BFS_DATA; /* * Hunting parameters. */ #define BFS_ERROR -1 #define BFS_ALREADY_THERE -2 #define BFS_NO_PATH -3 #define MARK_ROOM( room ) ( SET_BIT ((room)->room_flags, ROOM_MARKED) ) #define UNMARK_ROOM( room ) ( REMOVE_BIT((room)->room_flags, ROOM_MARKED) ) #define IS_MARKED_ROOM( room ) ( IS_SET ((room)->room_flags, ROOM_MARKED) ) struct bfs_queue { ROOM_INDEX_DATA * room; int dir; }; static BFS_DATA * queue; static int nqueue; void bfs_enqueue(ROOM_INDEX_DATA *room, int dir) { MARK_ROOM(room); queue = realloc(queue, (nqueue+1)*sizeof(BFS_DATA)); queue[nqueue].room = room; queue[nqueue].dir = dir; nqueue++; } void bfs_cleanup(void) { int i; for (i=0; i<nqueue; i++) UNMARK_ROOM(queue[i].room); free(queue); } int find_path( ROOM_INDEX_DATA *src, ROOM_INDEX_DATA *dst, int maxdist ) { int count; int k; int door; if ( !src || !dst ) { bug( "Illegal value passed to find_first_step (track.c)", 0 ); return BFS_ERROR; } if ( src == dst ) return BFS_ALREADY_THERE; queue = NULL; nqueue = 0; MARK_ROOM(src); /* first, enqueue the first steps, saving which direction we're going. */ for ( door = 0; door < MAX_DIR; door++ ) { ROOM_INDEX_DATA * to_room; EXIT_DATA * pexit; pexit = src->exit[door]; if ( pexit && (to_room=pexit->to_room) && !IS_MARKED_ROOM(to_room) ) bfs_enqueue(to_room, door); } count = 0; k = 0; while ( nqueue > k ) { ROOM_INDEX_DATA * room; int dir; if ( ++count > maxdist ) { bfs_cleanup(); UNMARK_ROOM(src); return BFS_NO_PATH; } room = queue[k].room; dir = queue[k].dir; if ( room == dst ) { bfs_cleanup(); UNMARK_ROOM(src); return dir; } else { k++; for ( door = 0; door < MAX_DIR; door++ ) { ROOM_INDEX_DATA * to_room; EXIT_DATA * pexit; pexit = room->exit[door]; if ( pexit && (to_room=pexit->to_room) && !IS_MARKED_ROOM(to_room) ) bfs_enqueue(to_room, dir); } } } bfs_cleanup(); UNMARK_ROOM(src); return BFS_NO_PATH; } void found_prey( CHAR_DATA *ch, CHAR_DATA *victim ) { char buf [ MAX_STRING_LENGTH ]; char victname [ MAX_STRING_LENGTH ]; if ( !victim || victim->deleted ) { bug( "Found_prey: null victim", 0 ); return; } if ( !victim->in_room ) { bug( "Found_prey: null victim->in_room", 0 ); return; } sprintf( victname, IS_NPC( victim ) ? victim->short_descr : victim->name ); 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( "$n sniffs around the room for $N.", ch, NULL, victim, TO_NOTVICT ); act( "You sniff around the room for $N.", ch, NULL, victim, TO_CHAR ); act( "$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 ( IS_SET( ch->in_room->room_flags, ROOM_SAFE ) ) { 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( "$n takes a few swipes at $N.", ch, NULL, victim, TO_NOTVICT ); act( "You try to take a few swipes $N.", ch, NULL, victim, TO_CHAR ); act( "$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( "$n lunges at $N from out of nowhere!", ch, NULL, victim, TO_NOTVICT ); act( "You lunge at $N catching $M off guard!", ch, NULL, victim, TO_CHAR ); act( "$n lunges at you from out of nowhere!", ch, NULL, victim, TO_VICT ); } stop_hunting( ch ); multi_hit( ch, victim, TYPE_UNDEFINED ); return; } void do_track( CHAR_DATA *ch, char *argument ) { char buf [ MAX_STRING_LENGTH ]; char arg [ MAX_STRING_LENGTH ]; CHAR_DATA *victim; int dir; bool fArea; if ( !can_use( ch, gsn_track ) ) { send_to_char( "You do not know of this skill yet.\n\r", ch ); return; } one_argument( argument, arg ); if ( arg[0] == '\0' ) { send_to_char( "Whom are you trying to track?\n\r", ch ); return; } if ( ch->riding ) { send_to_char( "You can't sniff a trail mounted.\n\r", ch ); return; } /* only imps can hunt to different areas */ fArea = ( get_trust( ch ) < L_DIR ); if ( fArea ) victim = get_char_area( ch, arg ); else victim = get_char_world( ch, arg ); if ( !victim ) { send_to_char( "You can't find a trail of anyone like that.\n\r", ch ); return; } if ( ch->in_room == victim->in_room ) { act( "You're already in $N's room!", 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_track].beats ); /* * 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_track] ) ) { do { dir = number_door( ); } while ( !( ch->in_room->exit[dir] ) || !( ch->in_room->exit[dir]->to_room ) ); learn( ch, gsn_track, FALSE ); } else { dir = find_path( ch->in_room, victim->in_room, 100 + ch->level * 30 ); if ( dir < 0 ) { act( "You can't sense $N's trail from here.", ch, NULL, victim, TO_CHAR ); return; } learn( ch, gsn_track, TRUE ); } /* * Display the results of the search. */ sprintf( buf, "You sense $N's trail %s from here...", dir_name[dir] ); act( buf, ch, NULL, victim, TO_CHAR ); return; } void hunt_victim( CHAR_DATA *ch ) { CHAR_DATA *tmp; int dir; bool found; if ( !ch || ch->deleted || !ch->hunting ) return; /* * Make sure the victim still exists. */ found = FALSE; for ( tmp = char_list; tmp; tmp = tmp->next ) if ( ch->hunting->who == tmp ) { found = TRUE; break; } if ( !found ) { do_say( ch, "Damn! My prey is gone!!" ); stop_hunting( ch ); return; } if ( ch->in_room == ch->hunting->who->in_room ) { if ( ch->fighting ) return; found_prey( ch, ch->hunting->who ); 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] ) || !( ch->in_room->exit[dir]->to_room ) ); } else { dir = find_path( ch->in_room, ch->hunting->who->in_room, 500 + ch->level * 25 ); if ( dir < 0 ) { act( "$n says 'Damn! Lost $M!'", ch, NULL, ch->hunting->who, TO_ROOM ); stop_hunting( ch ); return; } } { EXIT_DATA *pexit; pexit = ch->in_room->exit[dir]; if ( IS_SET( pexit->to_room->room_flags, ROOM_NO_MOB ) || ( xIS_SET( ch->act, ACT_STAY_AREA ) && pexit->to_room->area != ch->in_room->area ) ) { stop_hunting( ch ); return; } if ( IS_SET( pexit->exit_info, EX_CLOSED ) ) { do_open( ch, dir_name[dir] ); return; } } move_char( ch, dir ); if ( ch->deleted ) { return; } if ( !ch->hunting ) { if ( !ch->in_room ) { char buf [ MAX_STRING_LENGTH ]; sprintf( buf, "Hunt_victim: no ch->in_room! Mob #%d, name: %s. Placing mob in limbo.", ch->pIndexData->vnum, ch->name ); bug( buf, 0 ); char_to_room( ch, get_room_index( ROOM_VNUM_LIMBO ) ); return; } do_say( ch, "Damn! Lost my prey!" ); return; } if ( ch->in_room == ch->hunting->who->in_room ) found_prey( ch, ch->hunting->who ); return; }