/******************************************************************************
 Copyright (c) 2000-2001 Richard Woolcock

 Permission is hereby granted, free of charge, to any person obtaining a copy 
 of this software and associated documentation files (the "Software"), to deal 
 in the Software without restriction, including without limitation the rights 
 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 
 copies of the Software, and to permit persons to whom the Software is 
 furnished to do so, subject to the following conditions:

 The above copyright notice and this permission notice shall be included in all 
 copies or substantial portions of the Software.

 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 
 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 
 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 
 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 
 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 
 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 
 SOFTWARE.
 ******************************************************************************/

/******************************************************************************
 File Name        : combat.c
 ******************************************************************************
 Description      : The combat system.
 ******************************************************************************/

/******************************************************************************
 Required library files.
 ******************************************************************************/

#include <stdlib.h>
#include <stdio.h>
#include <stdarg.h>
#include <string.h>
#include <unistd.h>
#include <ctype.h>
#include <netinet/in.h>
#include <sys/time.h>
#include <sys/types.h>
#include <sys/socket.h>
#include "sockets.h"
#include "combat.h"
#include "combat_hands.h"
#include "combat_legs.h"
#include "combat_eyes.h"
#include "glad.h"
#include "text_io.h"

/******************************************************************************
 Required local variables.
 ******************************************************************************/

/* Create the combat table */
const cmbt_table_t *kstCmbtTable[] =
{
    kstCmbtTableHands,
    kstCmbtTableLegs,
    kstCmbtTableEyes,
    NULL
};

/******************************************************************************
 Required operations.
 ******************************************************************************/

/* Function: Combat
 *
 * This function reads in a move and determines which combat technique will be 
 * executed by the character.  A pointer to the technique is stored in the 
 * character's body and their timer is set.
 *
 * The function takes four parameters, as follows:
 *
 * pstBody:   The player's body.
 * eLocation: The body location performing the technique.
 * chMove:    The type of move being performed.
 * eTable:    The combat table being used.
 *
 * This function has no return value.
 */
void Combat( body_t *pstBody, ap_t eLocation, char chMove, table_t eTable )
{
   int i; /* loop counter */

   /* Push the move onto the end of the player's list */
   PushMove(pstBody->a_chTechniques[eLocation], chMove);

   /* Find the technique */
   for ( i = 0; kstCmbtTable[eTable][i].szRequirements != NULL; i++ )
   {
      int iLength = strlen(kstCmbtTable[eTable][i].szRequirements);
      if ( !strncmp(&pstBody->a_chTechniques[eLocation][MAX_TECHNIQUES-iLength], 
         kstCmbtTable[eTable][i].szRequirements, iLength) )
      {
         /* A matching technique was found! */
         pstBody->pfnAttack[eLocation] = kstCmbtTable[eTable][i].pfnFunction;
         pstBody->iSpeed[eLocation] = kstCmbtTable[eTable][i].iSpeed;
         pstBody->iCmbtIndex[eLocation] = i;
         return; /* No point carrying on */
      }
   }

   /* If we reach this point, there's a problem! */
   Log( "BUG[%s]: No matching technique was found.\n", __FUNCTION__ );
}



/* Function: CombatCmd
 *
 * This function finds the appropriate command in the combat table depending 
 * on the table used by the specified location of the body.  A pointer to the 
 * function in the combat table is returned.
 *
 * The function takes three parameters, as follows:
 *
 * pstBody:   The player's body.
 * szCmd:     The command to look for in the combat table.
 * eLocation: The body location performing the technique.
 *
 * This function returns a pointer to a function in the combat table which 
 * takes two parameters, as follows:
 *
 * pstBody:   The body performing the command.
 * eLocation: The body location performing the command.
 * 
 * The function pointed to has no return value.
 */
void (*CombatCmd( body_t *pstBody, char *szCmd, ap_t eLocation ))(body_t* pstBody, ap_t eLocation)
{
   int i; /* loop counter */

   /* Set up the dynamic text variables */
   TextInit(eLocation);

   /* Find the command */
   for ( i = 0; kstCmbtTable[pstBody->eTable[eLocation]][i].szRequirements != NULL; i++ )
   {
      if ( !strcmp(szCmd, kstCmbtTable[pstBody->eTable[eLocation]][i].szRequirements) )
      {
         /* A matching technique was found! */
         return ( kstCmbtTable[pstBody->eTable[eLocation]][i].pfnFunction );
      }
   }

   /* The command doesn't exist */
   return ( NULL );
}



/* Function: PushMove
 *
 * This function shifts the moves one position to the left and adds a new 
 * one on the right.
 *
 * The function takes two parameters, as follows:
 *
 * szTxt:  The string containing the previous moves.
 * chMove: The current move.
 *
 * This function has no return value.
 */
void PushMove( char *szTxt, char chMove )
{
   int i; /* loop counter */

   for ( i = 0; i < MAX_TECHNIQUES-1; i++ )
   {
      /* Push each character along one space */
      szTxt[i] = szTxt[i+1];
   }

   /* Add the new character on to the end (but before the NUL) */
   szTxt[MAX_TECHNIQUES-1] = chMove;
}



/* Function: IsBlocked
 *
 * This function determines whether or not the attack was blocked by 
 * the defender.  If it is, a message is displayed.
 *
 * The function takes two parameters, as follows:
 *
 * pstBody:    The attacker's body.
 * szAttack:   The name of the attack.
 * iAttack:    The attack rating.
 *
 * This function returns a bool which is TRUE if the attack was blocked 
 * and FALSE if it was not.
 */
bool IsBlocked( body_t *pstBody, char *szAttack, int iAttack )
{
   body_t *pstOpponent = pstBody->pstOpponent;
   int     iDefence    = GetDefence(pstOpponent);
   bool    bIsBlocked  = FALSE;
   ap_t    eLocation;
   int     iChance = RollDice(100);

   /* Add on the bonus of the best hand */
   if ( kstCmbtTable[pstBody->eTable[AP_LEFT_HAND]][pstBody->iCmbtIndex[AP_LEFT_HAND]].iDefence > 
      kstCmbtTable[pstBody->eTable[AP_RIGHT_HAND]][pstBody->iCmbtIndex[AP_RIGHT_HAND]].iDefence )
   {
      eLocation = AP_LEFT_HAND;
   }
   else /* Right hand has the best defence */
   {
      eLocation = AP_RIGHT_HAND;
   }

   /* Add on the defence bonus for the defenders best hand */
   iDefence += kstCmbtTable[pstOpponent->eTable[eLocation]][pstOpponent->iCmbtIndex[eLocation]].iDefence;

   /* Add on the bonus/penalty for the defenders eyes/feet */
   iDefence += kstCmbtTable[pstOpponent->eTable[AP_EYES]][pstOpponent->iCmbtIndex[AP_EYES]].iDefence;
   iDefence += kstCmbtTable[pstOpponent->eTable[AP_LEGS]][pstOpponent->iCmbtIndex[AP_LEGS]].iDefence;

   /* Add on the bonus for the attackers eyes */
   iAttack += kstCmbtTable[pstBody->eTable[AP_EYES]][pstBody->iCmbtIndex[AP_EYES]].iAttack;

   /* Minimum chance of a block is 10%, maximum chance is 90% */
   if ( iChance > 10 && ( iChance > (iAttack - iDefence + 50) || iChance > 90 ) )
   {
      SendToBody( pstBody, TO_USER, "Your %s %s {opponent}.\n\r", szAttack, 
         kstCmbtTable[pstOpponent->eTable[eLocation]][pstOpponent->iCmbtIndex[eLocation]].szBlockTxt );
      SendToBody( pstOpponent, TO_USER, "{opponent}'s %s %s you.\n\r", szAttack, 
         kstCmbtTable[pstOpponent->eTable[eLocation]][pstOpponent->iCmbtIndex[eLocation]].szBlockTxt );
      bIsBlocked = TRUE;
   }

   return ( bIsBlocked );
}




/* Function: GetEnhancedDamage
 *
 * This function returns the DAMAGE of the specified body after applying 
 * adjustments according to the combat tables.
 *
 * The function takes one parameter, as follows:
 *
 * pstBody: The body from which to determine the enhanced DAMAGE.
 *
 * This function returns an int, which contains the maximum enhanced DAMAGE 
 * capacity of the body.
 */
int GetEnhancedDamage( body_t *pstBody )
{
   int iDamage = GetDamage(pstBody);

   iDamage += kstCmbtTable[pstBody->eTable[AP_EYES]][pstBody->iCmbtIndex[AP_EYES]].iDamage;

   return ( iDamage );
}

/******************************************************************************
 Hand combat techniques.
 ******************************************************************************/

CMBT(Null)
{
   /* Nothing */
}