/* New goto system provides more flexibility, lettings imms perform
 * gotos to chars, mobs, objects, vnums, etc. There may be another
 * release of this depending on if we find we need more functionality
 * on AWW, or someone suggests something.
 *
 * I havn't released any snips in a while, but hopefully someone can
 * make use of this. It's made a lot of difference on our MUD, though
 * it does require an extra argument over normal goto'ing.
 *
 * Dont forget to...
 * #define stc send_to_char
 * #define ptc printf_to_char
 * Change interp.c so goto points at do_new_goto
 *
 * Hopefully the rest is self-explanatory, but if you need help, you can
 * reach me via MudMagic.com as Dalsor.
 *
 * Eric Lowe, aka Dalsor Anskaven
 * http://www.aww-mud.org
 */


/* Add these to handler.c */

CHAR_DATA *get_mob_world( CHAR_DATA *ch, char *argument )
{
    char arg[MAX_INPUT_LENGTH];
    CHAR_DATA *wch;
    int number;
    int count;

    if ( ch && ( wch = get_char_room( ch, NULL, argument ) ) != NULL )
		return wch;

    number = number_argument( argument, arg );
    count  = 0;

    for ( wch = char_list; wch != NULL ; wch = wch->next )
    {
		if ( wch->in_room == NULL || ( ch && !can_see( ch, wch ) )
		||   !is_name( arg, wch->name ) )
		    continue;
		if ( !IS_NPC( wch ) )
			continue;
		if ( ++count == number )
		    return wch;
    }
    return NULL;
}
CHAR_DATA *get_mob_by_vnum( CHAR_DATA *ch, char *argument )
{
    CHAR_DATA *wch;
    int vnum;

	if ( !is_number( argument ) )
	{
		bugf( "get_mob_by_vnum:: non-number lookup", 0 );
		return NULL;
	}
	vnum = atol( argument );
    for ( wch = char_list; wch != NULL ; wch = wch->next )
    {
		if ( wch->in_room == NULL || ( ch && !can_see( ch, wch ) ) )
		    continue;
		if ( !IS_NPC( wch ) )
			continue;
		if ( !wch->pIndexData )
			continue;
		if ( wch->pIndexData->vnum != vnum )
			continue;
		if ( wch->pIndexData->vnum == vnum )
		    return wch;
    }
    return NULL;
}
CHAR_DATA *get_pc_world( CHAR_DATA *ch, char*argument )
{
	DESCRIPTOR_DATA *d;
	if(!str_cmp(argument,"self"))
		return ch;
	for ( d = descriptor_list; d != NULL; d = d->next )
	{
		if ( !d || !d->character || d->connected != CON_PLAYING )
		{
			continue;
		}
		if ( is_name(argument,  d->character->name ) )
			return (d->character);
	}
	return NULL;
}

/* Add these to act_wiz.c and change interp.c so goto points at do_new_goto */

void perform_goto( CHAR_DATA *ch, ROOM_INDEX_DATA *location )
{
    CHAR_DATA *rch;
    int count = 0;
    count = 0;

	if ( location->vnum <= 0 )
	{
		stc("That location is not valid. Perhaps the reset doesn't exist?\n\r", ch);
		return;
	}

    for ( rch = location->people; rch != NULL; rch = rch->next_in_room )
        count++;

    if ( is_fighting(ch) )
		stop_all_fighting( ch);

    for (rch = ch->in_room->people; rch != NULL; rch = rch->next_in_room)
    {
		if (get_trust(rch) >= ch->invis_level)
		{
		    if (ch->pcdata != NULL && ch->pcdata->bamfout[0] != '\0')
				act("{c$t",ch,ch->pcdata->bamfout,rch,TO_VICT);
		    else
				act("{c$n leaves in a swirling mist.",ch,NULL,rch,TO_VICT);
		}
    }

    char_from_room( ch );
    char_to_room( ch, location );

    if (ch->pet != NULL)
    {
    	char_from_room (ch->pet);
		char_to_room (ch->pet, location);
    }

    if( MOUNTED(ch) )
    {
        char_from_room( MOUNTED(ch) );
        char_to_room( MOUNTED(ch), location );
        send_to_char("Your rider is a god, and did a goto. You went along for the ride.\n\r", MOUNTED(ch));
    }

    for (rch = ch->in_room->people; rch != NULL; rch = rch->next_in_room)
    {
        if (get_trust(rch) >= ch->invis_level)
        {
            if (ch->pcdata != NULL && ch->pcdata->bamfin[0] != '\0')
                act("{c$t",ch,ch->pcdata->bamfin,rch,TO_VICT);
            else
                act("{c$n appears in a swirling mist.",ch,NULL,rch,TO_VICT);
        }
    }

    do_function(ch, &do_look, "auto" );
    return;
}
void do_new_goto( CHAR_DATA *ch, char *argument )
{
    ROOM_INDEX_DATA *location = NULL;
	char arg1[MIL], arg2[MIL];

	argument = one_argument( argument, arg1 );
	argument = one_argument( argument, arg2 );

    if ( arg1[0] == '\0' || arg2[0] == '\0' || !str_cmp( arg1, "?" ) || !str_cmp( arg1, "help" ) )
    {
		stc("Goto where?\n\r", ch );
		stc("Goto Char  <PC Name>\n\r", ch );
		stc("Goto Mob   <Mobile Name>\n\r", ch );
		stc("Goto Mobv  <Mobile Vnum>\n\r", ch );
		stc("Goto Room  <Room Vnum>\n\r", ch );
		stc("Goto Obj   <Obj Name>\n\r", ch );
		stc("Goto Objv  <Obj Vnum>\n\r", ch );
		return;
    }

	/* working 05.01.2004 - Dalsor */
	if ( !str_cmp( arg1, "char" ) )
	{
		CHAR_DATA *victim;
		if ( ( victim = get_pc_world( ch, arg2 ) ) != NULL)
		{
			location = victim->in_room;
			if ( location != NULL )
				perform_goto( ch, location );
			else
			{
				stc("The location appears to be null.\n\r", ch);
				return;
			}
		}
		else
		{
			stc("No such PC in the world.\n\r", ch);
			return;
		}
	}
	/* working 05.01.2004 - Dalsor */
	if ( !str_cmp( arg1, "mob" ) )
	{
		CHAR_DATA *victim;
		if ( ( victim = get_mob_world( ch, arg2 ) ) != NULL )
		{
			if ( !IS_NPC( victim ) )
			{
				stc("For some reason, get_mob_world returned a PC\n\r", ch);
				return;
			}
			if ( ( location = victim->in_room ) != NULL )
				perform_goto( ch, location );
			else
			{
				stc("The location appears to be null.\n\r", ch);
				return;
			}
		}
		else
		{
			stc("Could not find that mobile.\n\r", ch);
			return;
		}
	}
	/* working 05.01.2004 - Dalsor */
	if ( !str_cmp( arg1, "mobv" ) )
	{
		CHAR_DATA *victim;
		MOB_INDEX_DATA *pMob;
		long vnum;
		if ( !is_number( arg2 ) )
		{
			stc("Location must be a valid mobile vnum.\n\r", ch);
			return;
		}
		vnum = atol( arg2 );
		if ( !( pMob = get_mob_index( vnum ) ) )
		{
			stc("No such mobile index.\n\r", ch);
			return;
		}
		if ( ( victim = get_mob_by_vnum( ch, arg2 ) ) != NULL )
		{
			if ( ( location = victim->in_room ) != NULL )
			{
				if ( location->vnum <= 0 )
				{
					stc("The object does not appear to be reset in the world.\n\r", ch);
					return;
				}
				else
					perform_goto( ch, location );
			}
			else
			{
				stc("The location appears to be null.\n\r", ch);
				return;
			}
		}
		else
		{
			stc("Could not find that mobile.\n\r", ch);
			return;
		}
	}
	/* working 05.01.2004 - Dalsor */
	if ( !str_cmp( arg1, "room" ) )
	{
		long vnum;
		if ( !is_number( arg2 ) )
		{
			stc("Location must be a valid room vnum.\n\r", ch);
			return;
		}
		vnum = atol( arg2 );
		if ( ( location = get_room_index( vnum ) ) != NULL )
			perform_goto( ch, location );
		else
		{
			stc("The location appears to be null.\n\r", ch);
			return;
		}
	}
	/* working 05.01.2004 - Dalsor */
	if ( !str_cmp( arg1, "obj" ) )
	{
		OBJ_DATA *obj;
		if ( ( obj = get_obj_world( ch, arg2 ) ) != NULL )
		{
			/*
			if ( obj->carried_by != NULL )
			{
				ptc( ch, "%s is carried by %s in room %ld.",
					obj->short_descr, obj->carried_by->name, obj->carried_by->in_room->vnum );
				location = obj->carried_by->in_room;
			}
			else
				location = obj->in_room;
			*/
			while(obj->carried_by ==NULL && obj->in_room == NULL)
			{
				ptc( ch, "%s is in %s.\n\r",
					obj->short_descr, obj->in_obj->short_descr);
				if(!obj->in_obj)
				{
					ptc(ch,"%s is not in_room, carried_by or in_obj.\n\r",obj->short_descr);
					return;
				}
				obj = obj->in_obj;
			}
			if ( obj->carried_by != NULL )
			{
				ptc( ch, "%s is carried by %s in room %ld.\n\r",
					obj->short_descr, obj->carried_by->name, obj->carried_by->in_room->vnum );
				location = obj->carried_by->in_room;
			}
			else
			{
				ptc( ch, "%s is in room %ld.\n\r",
						obj->short_descr, obj->in_room->vnum);
				location = obj->in_room;
			}
		}
		if ( location != NULL )
			perform_goto( ch, location );
		else
		{
			stc("The location appears to be null.\n\r", ch);
			return;
		}
	}
	/* working 05.01.2004 - Dalsor */
	if ( !str_cmp( arg1, "objv" ) )
	{
		OBJ_DATA *obj;
		OBJ_INDEX_DATA *pObj;
		long vnum;
		if ( !is_number( arg2 ) )
		{
			stc("Location must be a valid object vnum.\n\r", ch);
			return;
		}
		vnum = atol( arg2 );
		if ( !( pObj = get_obj_index( vnum ) ) )
		{
			stc("No such object index.\n\r", ch);
			return;
		}
		if ( ( obj = get_obj_by_vnum( ch, arg2 ) ) != NULL )
		{
			/*
			if ( obj->carried_by != NULL )
			{
				ptc( ch, "%s is carried by %s in room %ld.",
					obj->short_descr, obj->carried_by->name, obj->carried_by->in_room->vnum );
				location = obj->carried_by->in_room;
			}
			else
				location = obj->in_room;
			*/
			while(obj->carried_by ==NULL && obj->in_room == NULL)
			{
				ptc( ch, "%s is in %s.\n\r",
					obj->short_descr, obj->in_obj->short_descr);
				if(!obj->in_obj)
				{
					ptc(ch,"%s is not in_room, carried_by or in_obj.\n\r",obj->short_descr);
					return;
				}
				obj = obj->in_obj;
			}
			if ( obj->carried_by != NULL )
			{
				ptc( ch, "%s is carried by %s in room %ld.\n\r",
					obj->short_descr, obj->carried_by->name, obj->carried_by->in_room->vnum );
				location = obj->carried_by->in_room;
			}
			else
			{
				ptc( ch, "%s is in room %ld.\n\r",
						obj->short_descr, obj->in_room->vnum);
				location = obj->in_room;
			}
		}
		/* redundant and crash prone *
		if ( location->vnum <= 0 )
		{
			stc("The object does not appear to be reset in the world.\n\r", ch);
			return;
		} */
		if ( location != NULL )
		{
			if ( location->vnum <= 0 )
			{
				stc("The object does not appear to be reset in the world.\n\r", ch);
				return;
			}
			else
				perform_goto( ch, location );
		}
		else
		{
			stc("The location appears to be null.\n\r", ch);
			return;
		}
	}
    return;
}