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

//-------------------------------------------------------- Includes
#include "class.h"
#include "tinyxml.h"
#include "SyAssert.h"
#include "stats.h"
#include "ai/behaviortypes.h"
#include "database.h"
//---------------------------------------------- Class Declarations

cStatistics::cStatistics() :
  mAttackPower(1.0f),
  mSpellPower(1.0f),
  mPhysicalDefense(1.0f),
  mMagicalDefense(1.0f),
  mStrikethrough(1.0f),
  mBlockMeter(1.0f),
  mMovementSpeed(1.0f),
  mCloseDistance(1.0f),
  mMeleeRange(1.0f),
  mAccuracy(1.0f),
  mThrowStrength(10.0f),
  mDropChance(0.0f),
  mDropHealthAmount(0.0f),
  mDropHealthWeight(0.0f),
  mDropManaAmount(0.0f),
  mDropManaWeight(0.0f),
  mDropEssenceAmount(0.0f),
  mDropEssenceWeight(0.0f)
{
}

void 
cStatistics::Parse(TiXmlNode* node)
{
  TiXmlNode* data_node;

  data_node = node->FirstChild("AttackPower");
  if (data_node && data_node->FirstChild() && data_node->FirstChild()->Value())
  {
    mAttackPower = (float)atof(data_node->FirstChild()->Value());
  }

  data_node = node->FirstChild("SpellPower");
  if (data_node && data_node->FirstChild() && data_node->FirstChild()->Value())
  {
    mSpellPower = (float)atof(data_node->FirstChild()->Value());
  }

  data_node = node->FirstChild("PhysicalDefense");
  if (data_node && data_node->FirstChild() && data_node->FirstChild()->Value())
  {
    mPhysicalDefense = (float)atof(data_node->FirstChild()->Value());
  }

  data_node = node->FirstChild("MagicalDefense");
  if (data_node && data_node->FirstChild() && data_node->FirstChild()->Value())
  {
    mMagicalDefense = (float)atof(data_node->FirstChild()->Value());
  }

  data_node = node->FirstChild("Strikethrough");
  if (data_node && data_node->FirstChild() && data_node->FirstChild()->Value())
  {
    mStrikethrough = (float)atof(data_node->FirstChild()->Value());
  }

  data_node = node->FirstChild("BlockMeter");
  if (data_node && data_node->FirstChild() && data_node->FirstChild()->Value())
  {
    mBlockMeter = (float)atof(data_node->FirstChild()->Value());
  }

  data_node = node->FirstChild("MovementSpeed");
  if (data_node && data_node->FirstChild() && data_node->FirstChild()->Value())
  {
    mMovementSpeed = (float)atof(data_node->FirstChild()->Value());
  }

  data_node = node->FirstChild("CloseDistance");
  if (data_node && data_node->FirstChild() && data_node->FirstChild()->Value())
  {
    mCloseDistance = (float)atof(data_node->FirstChild()->Value());
  }

  data_node = node->FirstChild("MeleeRange");
  if (data_node && data_node->FirstChild() && data_node->FirstChild()->Value())
  {
    mMeleeRange = (float)atof(data_node->FirstChild()->Value());
  }

  data_node = node->FirstChild("ThrowStrength");
  if (data_node && data_node->FirstChild() && data_node->FirstChild()->Value())
  {
    mThrowStrength = (float)atof(data_node->FirstChild()->Value());
  }

  data_node = node->FirstChild("DropChance");
  if (data_node && data_node->FirstChild() && data_node->FirstChild()->Value())
  {
    mDropChance = (float)atof(data_node->FirstChild()->Value());
  }

  data_node = node->FirstChild("DropHealthAmount");
  if (data_node && data_node->FirstChild() && data_node->FirstChild()->Value())
  {
    mDropHealthAmount = (float)atof(data_node->FirstChild()->Value());
  }

  data_node = node->FirstChild("DropHealthWeight");
  if (data_node && data_node->FirstChild() && data_node->FirstChild()->Value())
  {
    mDropHealthWeight = (float)atof(data_node->FirstChild()->Value());
  }

  data_node = node->FirstChild("DropManaAmount");
  if (data_node && data_node->FirstChild() && data_node->FirstChild()->Value())
  {
    mDropManaAmount = (float)atof(data_node->FirstChild()->Value());
  }

  data_node = node->FirstChild("DropManaWeight");
  if (data_node && data_node->FirstChild() && data_node->FirstChild()->Value())
  {
    mDropManaWeight = (float)atof(data_node->FirstChild()->Value());
  }

  data_node = node->FirstChild("DropEssenceAmount");
  if (data_node && data_node->FirstChild() && data_node->FirstChild()->Value())
  {
    mDropEssenceAmount = (float)atof(data_node->FirstChild()->Value());
  }

  data_node = node->FirstChild("DropEssenceWeight");
  if (data_node && data_node->FirstChild() && data_node->FirstChild()->Value())
  {
    mDropEssenceWeight = (float)atof(data_node->FirstChild()->Value());
  }
}

//----------------------------------------- Functions Declarations

cCharacterClass::cCharacterClass()
:  mMaxHP(1.0f),
   mMaxMana(1.0f),
   mDamage(1.0f),
   mNPCBehaviorType(NPCBEH_BASIC),
   mNPCFaction(0),
   mXPMultiplier(1.0f)
{
  for (int i=0; i< NUM_ELEMENTAL_TYPES; ++i)
  {
    mElementalMultipliers[i] = 1.0f;
  }
}

cCharacterClass *
ParseClass(TiXmlNode* node)
{
  TiXmlNode* data_node;
  cCharacterClass *newmaster = new cCharacterClass; 
  data_node = node->FirstChild("Class");
  SyAssert(data_node);
  const char *name = data_node->FirstChild()->Value();
  newmaster->mName.SetName(name);

  newmaster->mStats.Parse(node);

  data_node = node->FirstChild("HP");
  if (data_node && data_node->FirstChild() && data_node->FirstChild()->Value())
  {
    newmaster->mMaxHP = (float)atof(data_node->FirstChild()->Value());
  }

  data_node = node->FirstChild("Mana");
  if (data_node && data_node->FirstChild() && data_node->FirstChild()->Value())
  {
    newmaster->mMaxMana = (float)atof(data_node->FirstChild()->Value());
  }

  data_node = node->FirstChild("Damage");
  if (data_node && data_node->FirstChild() && data_node->FirstChild()->Value())
  {
    newmaster->mDamage = (float)atof(data_node->FirstChild()->Value());
  }

  data_node = node->FirstChild("XPMultiplier");
  if (data_node && data_node->FirstChild() && data_node->FirstChild()->Value())
  {
    newmaster->mXPMultiplier = (float)atof(data_node->FirstChild()->Value());
  }

  data_node = node->FirstChild("BehaviorType");
  if (data_node && data_node->FirstChild() && data_node->FirstChild()->Value())
  {
    int enumVal = 0;
    const char *type = data_node->FirstChild()->Value();
    bool bResult = ChooseEnum(type,NPC_BEHAVIOR_TYPE_NAMES,NPCBEH_MAXTYPES, enumVal);
    SyAssertf(bResult,"Unknown NPC BehaviorType type in class.xml");
    if (bResult)
    {
      newmaster->mNPCBehaviorType = (char)enumVal;
    }
  }
  else
  {
    newmaster->mNPCBehaviorType = NPCBEH_BASIC;
  }

  static const int NUM_NPCFACTION_NAMES = (sizeof(NPC_FACTION_NAMES) / sizeof (NPC_FACTION_NAMES[0]));

  data_node = node->FirstChild("Faction");
  if (data_node && data_node->FirstChild() && data_node->FirstChild()->Value())
  {
    int enumVal = 0;
    const char *type = data_node->FirstChild()->Value();
    SyAssertf(NUM_NPCFACTION_NAMES == NPCFACTION_MAXTYPES,"Forgot to add NPC Faction type name.");
    bool result = ChooseEnum(type,NPC_FACTION_NAMES,NUM_NPCFACTION_NAMES, enumVal);
    SyAssertf(result,"Unknown Faction type in class.xml");
    newmaster->mNPCFaction = (char) enumVal;
  }
  else
  {
    newmaster->mNPCFaction = NPCFACTION_MONSTER;
  }

  data_node = node->FirstChild("FireMultiplier");
  if (data_node && data_node->FirstChild() && data_node->FirstChild()->Value())
  {
    newmaster->mElementalMultipliers[ET_FIRE] = (float)atof(data_node->FirstChild()->Value());
  }

  data_node = node->FirstChild("IceMultiplier");
  if (data_node && data_node->FirstChild() && data_node->FirstChild()->Value())
  {
    newmaster->mElementalMultipliers[ET_ICE] = (float)atof(data_node->FirstChild()->Value());
  }

  data_node = node->FirstChild("LightningMultiplier");
  if (data_node && data_node->FirstChild() && data_node->FirstChild()->Value())
  {
    newmaster->mElementalMultipliers[ET_LIGHTNING] = (float)atof(data_node->FirstChild()->Value());
  }

  data_node = node->FirstChild("PoisonMultiplier");
  if (data_node && data_node->FirstChild() && data_node->FirstChild()->Value())
  {
    newmaster->mElementalMultipliers[ET_POISON] = (float)atof(data_node->FirstChild()->Value());
  }

  data_node = node->FirstChild("ShadowMultiplier");
  if (data_node && data_node->FirstChild() && data_node->FirstChild()->Value())
  {
    newmaster->mElementalMultipliers[ET_SHADOW] = (float)atof(data_node->FirstChild()->Value());
  }

  data_node = node->FirstChild("EarthMultiplier");
  if (data_node && data_node->FirstChild() && data_node->FirstChild()->Value())
  {
    newmaster->mElementalMultipliers[ET_EARTH] = (float)atof(data_node->FirstChild()->Value());
  }

  return newmaster;
}

cCharacterLevel::cCharacterLevel()
: mLevel(0),
  mXPRequired(2000),
  mMaxPlayerHP(1.0f),
  mMaxPlayerMana(1.0f),
  mMaxNPCHP(1.0f),
  mMaxNPCMana(1.0f),
  mPlayerDamage(10.0f),
  mNPCDamage(10.0f)
{
}

cCharacterLevel *
ParseLevel(TiXmlNode* node)
{

  TiXmlNode* data_node;
  cCharacterLevel *newmaster = new cCharacterLevel; 
  data_node = node->FirstChild("Lvl");
  SyAssertf(data_node!=NULL, "Level in level_stats.xml has no Lvl attribute");

  newmaster->mLevel = atoi(data_node->FirstChild()->Value());
  newmaster->mStats.Parse(node);

  data_node = node->FirstChild("ExperienceRequired");
  SyAssertf(data_node!=NULL, "Level in level_stats.xml has no ExperienceRequired attribute");

  newmaster->mXPRequired = atoi(data_node->FirstChild()->Value());

  data_node = node->FirstChild("DamageNPC");
  if (data_node && data_node->FirstChild() && data_node->FirstChild()->Value())
  {
    newmaster->mNPCDamage = (float)atof(data_node->FirstChild()->Value());
  }

  data_node = node->FirstChild("DamagePC");
  if (data_node && data_node->FirstChild() && data_node->FirstChild()->Value())
  {
    newmaster->mPlayerDamage = (float)atof(data_node->FirstChild()->Value());
  }

  data_node = node->FirstChild("HPPC");
  if (data_node && data_node->FirstChild() && data_node->FirstChild()->Value())
  {
    newmaster->mMaxPlayerHP = (float)atof(data_node->FirstChild()->Value());
  }

  data_node = node->FirstChild("ManaPC");
  if (data_node && data_node->FirstChild() && data_node->FirstChild()->Value())
  {
    newmaster->mMaxPlayerMana = (float)atof(data_node->FirstChild()->Value());
  }

  data_node = node->FirstChild("HPNPC");
  if (data_node && data_node->FirstChild() && data_node->FirstChild()->Value())
  {
    newmaster->mMaxNPCHP = (float)atof(data_node->FirstChild()->Value());
  }

  data_node = node->FirstChild("ManaNPC");
  if (data_node && data_node->FirstChild() && data_node->FirstChild()->Value())
  {
    newmaster->mMaxNPCMana = (float)atof(data_node->FirstChild()->Value());
  }

  return newmaster;
}

cExperienceTable::cExperienceTable()
{
  for (int i=0; i<MAX_LEVEL_DELTAS; ++i)
  {
    mDeltaExpReward[i] = -1;
  }
}

int cExperienceTable::GetExperience(int deltaXP) const
{
  SyAssertf(deltaXP >= -(MAX_LEVEL_DELTAS/2) && deltaXP <= (MAX_LEVEL_DELTAS/2), "Invalid level difference when calculating XP %d", deltaXP);

  if (deltaXP < -(MAX_LEVEL_DELTAS/2))
  {
    return mDeltaExpReward[0];
  }
 
  if (deltaXP > (MAX_LEVEL_DELTAS/2))
  {
    return mDeltaExpReward[MAX_LEVEL_DELTAS-1];
  }

  return mDeltaExpReward[deltaXP + (MAX_LEVEL_DELTAS/2)];
}


cDifficultySettingsTable::cDifficultySettingsTable()
{
  for (int i=0; i<MAX_DIFFICULTY_LEVELS; ++i)
  {
    mDamageMultipliers[i] = 1.0f;
    mHealthMultipliers[i] = 1.0f;
    mBlockMultipliers[i] = 1.0f;
  }
}


//------------------------------------ Member Functions Definitions


// EOF
