/******************************************************************
  
  Module:  rule_global.cpp
  
  Author: Sean Craig
  
  Copyright 2005 Sony Online Entertainment.  All rights reserved.
  
*******************************************************************/

//-------------------------------------------------------- Includes
#include "rule_global.h"
#include "rule.h"
#include "titan.h"
#include "stats.h"
#include "registry.h"
#include "graphic.h"
#include "animcontroller.h"

//---------------------------------------------- Class Declarations
class cGlobalCombatRule : public cRule
{
public:
  virtual const char * GetName(){return "Global";};

  virtual void    CalcHealthMax(cCalcPacket *packet);
  virtual void    CalcHealthRegen(cCalcPacket *packet);
  virtual void    CalcPowerMax(cCalcPacket *packet);
  virtual void    CalcPowerRegen(cCalcPacket *packet);
  virtual void    CalcBlockMax(cCalcPacket *packet);
  virtual void    CalcBlockRegen(cCalcPacket *packet);

  virtual void    CalcStrikethrough(cDamagePacket *packet);
  virtual void    CalcDamageInitial(cDamagePacket *packet);
  virtual void    CalcDamageRaw(cDamagePacket *packet);
  virtual void    CalcDamageReduced(cDamagePacket *packet);

  virtual void    CalcCriticalChance(cDamagePacket *packet);
  virtual void    CalcDefense(cDamagePacket *packet);

  virtual void    CalcCarryingCapacity(cCalcPacket *packet); 
  virtual void    CalcExperienceGain(cCalcPacket *packet); 

protected:

};
//----------------------------------------- static variable definition
//----------------------------------------- Functions Declarations

void 
AddGlobalRules(cRuleContainer *container)
{
  container->Add(new cGlobalCombatRule);
}
//------------------------------------ Member Functions Definitions


void    
cGlobalCombatRule::CalcHealthMax(cCalcPacket *packet)
{
  cGameObject *obj = mpTitan->GetRegistry()->Fetch(packet->mObjectID);
  SyAssertf(obj!=NULL,"Bad packet");
  cStatsCharacter *stats = (cStatsCharacter *)obj->GetStats();

  const cCharacterLevel *pLevel = stats->GetLevel();
  packet->SetTotal((int)pLevel->mStats.mMaxHP,"Level",GetName());

  const cCharacterClass *pClass = stats->GetClass();
  packet->MultiplyTotal(pClass->mStats.mMaxHP,"Class",GetName());
};
 
void    
cGlobalCombatRule::CalcHealthRegen(cCalcPacket *packet)
{
  packet->SetTotal(0,"Base",GetName());
};

void    
cGlobalCombatRule::CalcBlockMax(cCalcPacket *packet)
{
  cGameObject *obj = mpTitan->GetRegistry()->Fetch(packet->mObjectID);
  SyAssertf(obj!=NULL,"Bad packet");
  cStatsCharacter *stats = (cStatsCharacter *)obj->GetStats();

  const cCharacterLevel *pLevel = stats->GetLevel();
  packet->SetTotal((int)pLevel->mStats.mBlockMeter,"Level",GetName());

  const cCharacterClass *pClass = stats->GetClass();
  packet->MultiplyTotal(pClass->mStats.mBlockMeter,"Class",GetName());
};

void    
cGlobalCombatRule::CalcBlockRegen(cCalcPacket *packet)
{
  cGameObject *obj = mpTitan->GetRegistry()->Fetch(packet->mObjectID);
  SyAssertf(obj!=NULL,"Bad packet");
  cStatsCharacter *stats = (cStatsCharacter *)obj->GetStats();

  const cCharacterLevel *pLevel = stats->GetLevel();
  int total = ((int)pLevel->mStats.mBlockMeter) * 100;  
  packet->SetTotal(total,"Level",GetName());

  const cCharacterClass *pClass = stats->GetClass();
  packet->MultiplyTotal(pClass->mStats.mBlockMeter,"Class",GetName());
};


void    
cGlobalCombatRule::CalcPowerMax(cCalcPacket *packet)
{
  cGameObject *obj = mpTitan->GetRegistry()->Fetch(packet->mObjectID);
  SyAssertf(obj!=NULL,"Bad packet");
  cStatsCharacter *stats = (cStatsCharacter *)obj->GetStats();

  const cCharacterLevel *pLevel = stats->GetLevel();
  packet->SetTotal((int)pLevel->mStats.mMaxMana,"Level",GetName());

  const cCharacterClass *pClass = stats->GetClass();
  packet->MultiplyTotal(pClass->mStats.mMaxMana,"Class",GetName());
};

void    
cGlobalCombatRule::CalcPowerRegen(cCalcPacket *packet)
{
  packet->SetTotal(0,"Base",GetName());
};

void    
cGlobalCombatRule::CalcDamageInitial(cDamagePacket *packet)
{
  cGameObject *obj = mpTitan->GetRegistry()->Fetch(packet->mObjectID);
  SyAssertf(obj!=NULL,"Bad packet");
  cStatsCharacter *stats = (cStatsCharacter *)obj->GetStats();

  const cCharacterLevel *pLevel = stats->GetLevel();
  const cCharacterClass *pClass = stats->GetClass();

  if (packet->mbRanged)
  {
    packet->SetTotal((int)pLevel->mStats.mRangedPower,"Level",GetName());
    packet->MultiplyTotal(pClass->mStats.mRangedPower,"Class",GetName());
  }
  else
  {
    packet->SetTotal((int)pLevel->mStats.mMeleePower,"Level",GetName());
    packet->MultiplyTotal(pClass->mStats.mMeleePower,"Class",GetName());
  }
};

void    
cGlobalCombatRule::CalcDamageRaw(cDamagePacket *packet)
{
  cGameObject *obj = mpTitan->GetRegistry()->Fetch(packet->mObjectID);
  SyAssertf(obj!=NULL,"Bad packet");

  if (!packet->mbRanged)
  {
    cAnimCharControllerInterface *interface = ((cGraphicCharacter *) obj->GetGraphic())->GetAnimController();
    packet->MultiplyTotal(interface->GetDamageMultiplier(packet->mCombo),"Combo Multiplier",GetName());
  }
};

void    
cGlobalCombatRule::CalcDamageReduced(cDamagePacket *packet)
{
  cGameObject *attacker = mpTitan->GetRegistry()->Fetch(packet->mAttackerID);
  SyAssertf(attacker!=NULL,"Bad packet");
  cStatsCharacter *attacker_stats = (cStatsCharacter *)attacker->GetStats();

  cGameObject *defender = mpTitan->GetRegistry()->Fetch(packet->mDefenderID);
  SyAssertf(defender!=NULL,"Bad packet");
  cStatsCharacter *defender_stats = (cStatsCharacter *)defender->GetStats();

  // calculate defense
  cDamagePacket defense_packet = *packet;
  defense_packet.mPacketType = cRulePacket::CALC_DEFENSE;
  defense_packet.Reset();
  defender_stats->ProcessRulePacket(&defense_packet);

  int defense = defense_packet.GetTotal();
  int level_difference = defender_stats->GetMaster()->mLevel -attacker_stats->GetMaster()->mLevel;
  float multiplier;
  static const float DAMAGE_CHANGE_PER_LEVEL_DIFFERENCE = 0.01f;
  static const float DAMAGE_CHANGE_PER_DEFENSE = 0.001f;

  Log("Level Difference %d * Change Per Level Difference %.4f = %.4f\n",
       level_difference,
       DAMAGE_CHANGE_PER_LEVEL_DIFFERENCE,
       (float)level_difference * DAMAGE_CHANGE_PER_LEVEL_DIFFERENCE);

  Log("Defense %d * Change Per Defense %.4f = %.4f\n",
    defense,
    DAMAGE_CHANGE_PER_LEVEL_DIFFERENCE,
    (float)defense * DAMAGE_CHANGE_PER_LEVEL_DIFFERENCE);


  float percent_change =(float)level_difference * DAMAGE_CHANGE_PER_LEVEL_DIFFERENCE + (float) defense * DAMAGE_CHANGE_PER_DEFENSE; 

  if (percent_change > 0)
  {
    Log("1.0 - %.4f = %.4f\n",percent_change, 1.0f-percent_change);
    multiplier = 1.0f - percent_change;
  }
  else
  {
    Log("1.0 / (1.0 - %.4f) = %f\n",percent_change, 1.0f/(1.0f-percent_change));
    multiplier = 1.0f / (1.0f - percent_change);
  }

  if (multiplier < 0.0f)
  {
    multiplier = 0.0f;
  }

  if (!packet->mbRanged)
  {
    packet->MultiplyTotal(multiplier,"Defense Multiplier",GetName());
  }
};

void    
cGlobalCombatRule::CalcDefense(cDamagePacket *packet)
{
  cGameObject *obj = mpTitan->GetRegistry()->Fetch(packet->mObjectID);
  SyAssertf(obj!=NULL,"Bad packet");
  cStatsCharacter *stats = (cStatsCharacter *)obj->GetStats();

  const cCharacterLevel *pLevel = stats->GetLevel();
  packet->SetTotal((int)pLevel->mStats.mDefense,"Level",GetName());

  const cCharacterClass *pClass = stats->GetClass();
  packet->MultiplyTotal(pClass->mStats.mDefense,"Class",GetName());
};

void    
cGlobalCombatRule::CalcStrikethrough(cDamagePacket *packet)
{
  cGameObject *obj = mpTitan->GetRegistry()->Fetch(packet->mObjectID);
  SyAssertf(obj!=NULL,"Bad packet");
  cStatsCharacter *stats = (cStatsCharacter *)obj->GetStats();

  const cCharacterLevel *pLevel = stats->GetLevel();
  packet->SetTotal((int)pLevel->mStats.mStrikethrough,"Level",GetName());

  const cCharacterClass *pClass = stats->GetClass();
  packet->MultiplyTotal(pClass->mStats.mStrikethrough,"Class",GetName());
};


void    
cGlobalCombatRule::CalcCriticalChance(cDamagePacket *packet)
{
};

void  
cGlobalCombatRule::CalcCarryingCapacity(cCalcPacket *packet)
{
}; 

void    
cGlobalCombatRule::CalcExperienceGain(cCalcPacket *packet)
{
}; 

// EOF
