/* Custom arena module, coded by Horus. */
/* Started on 17-Jan-2005 */

#include <sys/types.h>
#include <ctype.h>
#include <math.h>
#include <stdio.h>
#include <string.h>
#include <time.h>
#include "mud.h"


#define ROOM_CHALLENGED	5300
#define ROOM_CHALLENGER	5301

#define PHASE_PREP	0
#define PHASE_START	1
#define PHASE_END	2

#define MODE_DUEL	0
#define MODE_FFA	1
#define MODE_GROUP	2


void arena_update( void );
void arena_resolve( CHAR_DATA *winner, CHAR_DATA *loser );
void arena_link( CHAR_DATA *ch, sh_int team );
void arena_unlink( CHAR_DATA *ch, sh_int team );
void arena_odds( CHAR_DATA *challenger, CHAR_DATA *challenged );
void arena_chan( char *argument );
bool arena_trans( CHAR_DATA *ch, CHAR_DATA *challenger );

/* TODO: Add 'arena' helpfile.			*
 *	 x-Finish 'arena_chan' function/channel	*
 *	 Add 'PLR_NOCHAL' flag/config option	*
 *	 x-Add 'challenged' to pcdata		*
 *	 x-Add 'challenger' to pcdata		*
 *	 Add 'apl' to pcdata			*
 *	 ?-Create 'arenadata' global structure	*
 *	 Finish 'arena_update' function		*
 *	 Add betting and ffa arena shit		*
 *	 Finish 'arena_resolve' function	*
 *	 Finish 'arena_odds' function		*
 *	 Create PL freezing mechanism		*
 *	 Add 'PLR_INARENA' act flag		*
 *	 Finish 'arena_trans' function		*
 *	 x-Finish 'arena_link' function		*
 *	 Finish 'arena_unlink' function		*/

/* Master arena command */
void do_arena( CHAR_DATA *ch, char *argument )
{
    char arg[MAX_INPUT_LENGTH];
    char arg2[MAX_INPUT_LENGTH];
    char buf[MAX_STRING_LENGTH];

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

    if ( IS_NPC(ch) )
    {
	send_to_char( "NPCs cannot use the arena.\n\r", ch );
	return;
    }

    if ( arg[0] == '\0' )
    {
	do_help( ch, "arena" );
	return;
    }

    if ( !str_cmp( arg, "challenge" ) )
    {
	CHAR_DATA *victim;

	if ( arg2[0] == '\0' )
	{
	    send_to_char( "Whom do you wish to challenge?\n\r", ch );
	    return;
	}

	if ( ( victim = get_char_world( ch, arg2 ) ) == NULL )
	{
	    send_to_char( "They aren't here.\n\r", ch );
	    return;
	}

	if ( IS_NPC(victim) )
	{
	    send_to_char( "You cannot challenge NPCs.\n\r", ch );
	    return;
	}

	if ( IS_IMMORTAL(victim) && !IS_IMMORTAL(ch) )
	{
	    send_to_char( "You cannot challenge immortals.\n\r", ch );
	    return;
	}

/*	if ( xIS_SET( victim->act, PLR_NOCHAL ) )
	{
	    send_to_char( "That person does not wish to be challenged.\n\r", ch );
	    return;
	} */

	if ( arenadata.in_use )
	{
	    send_to_char( "The arena is currently in use. Wait a while.\n\r", ch );
	    return;
	}

	ch->pcdata->challenged = victim;
	victim->pcdata->challenger = ch;
	sprintf( buf, "%s has challenged %s to a duel in the arena!", ch->name, victim->name );
	arena_chan( buf );
	ch_printf( victim, "%s has challenged you to a duel, type 'ARENA ACCEPT' or 'ARENA DECLINE'.\n\r", ch->name );
	arenadata.in_use = TRUE;
	arenadata.chal_timer = 5;
	return;
    }

    if ( !str_cmp( arg, "accept" ) )
    {
	CHAR_DATA *challenger = ch->pcdata->challenger;

	if ( !challenger )
	{
	    send_to_char( "You haven't been challenged.\n\r", ch );
	    return;
	}

	if ( IS_NPC(challenger) )
	{
	    send_to_char( "ch->pcdata->challenger points to NPC. Report to Horus.\n\r", ch );
	    return;
	}

	if ( !challenger->pcdata->challenged )
	{
	    send_to_char( "Challenger's pcdata->challenged is null. Report to Horus.\n\r", ch );
	    return;
	}

	if ( !arena_trans( ch, challenger, PHASE_PREP ) )
	{
	    send_to_char( "Your challenger is involved in a PK fight. Wait for it to resolve.\n\r", ch );
	    return;
	}

	if ( !arenadata.in_use )
	    arenadata.in_use = TRUE;

	sprintf( buf, "%s has accepted %s's challenge!", ch->name, challenger->name );
	arena_chan( buf );
	ch_printf( challenger, "%s has accepted your challenge!", ch->name );
	do_look( ch, "auto" );
	do_look( challenger, "auto" );
	arenadata.prep_timer = 2;
	return;
    }

    if ( !str_cmp( arg, "decline" ) )
    {
	CHAR_DATA *challenger = ch->pcdata->challenger;

	if ( !challenger )
	{
	    send_to_char( "You haven't been challenged.\n\r", ch );
	    return;
	}

	if ( IS_NPC(challenger) )
	{
	    send_to_char( "ch->pcdata->challenger points to NPC. Report to Horus.\n\r", ch );
	    return;
	}

	sprintf( buf, "%s has declined %s's challenge! What a wimp.", ch->name, challenger->name );
	arena_chan( buf );
	ch->pcdata->challenger = NULL;
	challenger->pcdata->challenged = NULL;
	arenadata.in_use = FALSE;
	arenadata.chal_timer = -1;
	return;
    }

    if ( !str_cmp( arg, "cancel" ) )
    {
	CHAR_DATA *challenged = ch->pcdata->challenged;

	if ( !challenged )
	{
	    send_to_char( "You haven't challenged anyone.\n\r", ch );
	    return;
	}

	if ( IS_NPC(challenged) )
	{
	    send_to_char( "ch->pcdata->challenged points to NPC. Report to Horus.\n\r", ch );
	    return;
	}

	sprintf( buf, "%s has cancelled his challenge to %s!", ch->name, challenged->name );
	arena_chan( buf );
	ch->pcdata->challenged = NULL;
	challenged->pcdata->challenger = NULL;
	arenadata.in_use = FALSE;
	arenadata.chal_timer = -1;
	return;
    }

    do_help( ch, "arena" );
    return;
}

/* Arena update function, updates timers and announces said updates. */
void arena_update( void )
{
    return;
}

/* When the fight ends, this is called to handle bets and such. */
void arena_resolve( CHAR_DATA *winner, CHAR_DATA *loser )
{
    return;
}

/* Links the player into the appropriate APL_DATA lists. */
void arena_link( CHAR_DATA *ch, sh_int team )
{
    APL_DATA *apl;
    APL_DATA *wapl;
    APL_DATA *plr_team;

    if ( !ch )
    {
	bug( "arena_link called with null ch", 0 );
	return;
    }

    CREATE( apl, APL_DATA, 1 );
    apl->player = ch;
    ch->pcdata->apl = apl;

    if ( team == 1 )
	plr_team = arenadata.first_team1;

    if ( team == 2 )
	plr_team = arenadata.first_team2;

    if ( !plr_team )
    {
	apl->prev_team = NULL;
	apl->next_team = NULL;
	plr_team = apl;
    }

    for ( wapl = plr_team; wapl; wapl = wapl->next_team )
    {
	if ( wapl == apl )
	    break;

	if ( !wapl->next_team )
	{
	    apl->prev_team = wapl;
	    apl->next_team = NULL;
	    wapl->next_team = apl;
	    break;
	}
    }

    if ( !arenadata.first_plr )
    {
	apl->prev = NULL;
	apl->next = NULL;
	arenadata.first_plr = apl;
    }

    for ( wapl = arenadata.first_plr; wapl; wapl = wapl->next )
    {
	if ( wapl == apl )
	    break;

	if ( !wapl->next )
	{
	    apl->prev = wapl;
	    apl->next = NULL;
	    wapl->next = apl;
	}
    }

    return;
}

/* Removes player from arena and team linked lists. */
void arena_unlink( CHAR_DATA *ch, sh_int team )
{
    APL_DATA *apl;

    if ( !ch )
    {
	bug( "arena_unlink called with null ch", 0 );
	return;
    }

    apl = ch->pcdata->apl;

    if ( apl->next && apl->prev )
    {
	apl->prev->next = apl->next;
	apl->next->prev = apl->prev;
	apl->next = NULL;
	apl->prev = NULL;
    }
    else if ( apl->next && !apl->prev )
    {
	arenadata.first_plr = apl->next;
	apl->next->prev = NULL;
	apl->next = NULL;
    }
    else if ( !apl->next && apl->prev )
    {
	apl->prev->next = NULL;
	apl->prev = NULL;
    }
    else if ( !apl->next && !apl->prev )
	arenadata.first_plr = NULL;

    if ( apl->next_team && apl->prev_team )
    {
	apl->prev_team->next_team = apl->next_team;
	apl->next_team->prev_team = apl->prev_team;
	apl->next_team = NULL;
	apl->prev_team = NULL;
    }
    else if ( apl->next_team && !apl->prev_team )
    {
	if ( apl == arenadata.first_team1 )
	    arenadata.first_team1 = apl->next_team;

	if ( apl == arenadata.first_team2 )
	    arenadata.first_team2 = apl->next_team;

	apl->next_team = NULL;
    }
    else if ( !apl->next_team && apl->prev_team )
    {
	apl->prev_team->next_team = NULL;
	apl->prev_team = NULL;
    }
    else if ( !apl->next_team && !apl->prev_team )
    {
	if ( apl == arenadata.first_team1 )
	    arenadata.first_team1 = NULL;

	if ( apl == arenadata.first_team2 )
	    arenadata.first_team2 = NULL;
    }

    apl->player = NULL;
    DISPOSE( apl );
    return;
}

/* Gets odds for betting purposes. */
void arena_odds( CHAR_DATA *challenger, CHAR_DATA *challenged )
{
    return;
}

/* Arena announcement channel. */
void arena_chan( char *argument )
{
    char buf[MAX_STRING_LENGTH];
    DESCRIPTOR_DATA *d;
    CHAR_DATA *och;

    sprintf( buf, "&z[&RARENA&z] &W::&z%s&W::&D\n\r", argument );

    for ( d = first_descriptor; d; d = d->next )
    {
	if ( d->connected != CON_PLAYING )
	    continue;

	och = d->character;

	if ( xIS_SET( och->deaf, CHANNEL_ARENA ) )
	    continue;

	och->desc->psuppress_channel++;
	sysdata.outBytesFlag = LOGBOUTINFO;
	send_to_char( buf, och );
	sysdata.outBytesFlag = LOGBOUTNORM;
    }

    return;
}

/* Moves players to arena, restores, sets flags. Checks if they're PKing before doing anything. */
bool arena_trans( CHAR_DATA *ch, CHAR_DATA *challenger, sh_int phase )
{
    CHAR_DATA *fighting;

    if ( !ch )
    {
	bug( "arena_trans called with null ch", 0 );
	return FALSE;
    }

    if ( phase == PHASE_PREP )
    {
	if ( challenger )
	{
	    if ( ( fighting = who_fighting( challenger ) ) != NULL )
	    {
		if ( !IS_NPC(fighting) )
		    return FALSE;

		stop_fighting( challenger, fighting );
	    }
	    char_from_room( challenger );
	    char_to_room( challenger, get_room_index( ROOM_CHALLENGER ) );
	    challenger->hit = challenger->max_hit;
	    challenger->mana = challenger->max_mana;
	    xSET_BIT( challenger->act, PLR_INARENA );
	}

	char_from_room( ch );
	char_to_room( ch, get_room_index( ROOM_CHALLENGED ) );
	ch->hit = ch->max_hit;
	ch->mana = ch->max_mana;
	xSET_BIT( ch->act, PLR_INARENA );
	return TRUE;
    }

    if ( phase == PHASE_START )
    {
	// START DA MATCH
    }

    if ( phase == PHASE_END )
    {
	// END DA MATCH
    }

    return FALSE;
}
