////////////////////////////////////////////////////////////////////////////////
//
//  Olander's PW XP System
//  xp_opw_system
//  by Don Anderson
//
//  Original Script by Brian Kittrell
//
/*
  - Minimum XP Per Kill
  - Maximum XP Per Kill
  - Kill Bonus to Killer
  - Party Bonus
  - Players above Maximum Level Difference to Lowest Level are Thrown out
  - Maximum Level Cap to Give XP (The Level Set still gets XP)
*/
//
//  This pretty much puts an end to power levelling but
//  still allows low and high levels to travel together
//  and work together as a team.
//
//  This also penalizes for killing Commoners too
//
////////////////////////////////////////////////////////////////////////////////

//SET THE EXPERIENCE VALUES HERE

    // This is the minimum amount of experience that is given
    // to each player. Set this to be as aggressive or slow
    // as needed to achieve a good result.
    // NOTE:    This has the effect of levelling quickly in the
    //          lower levels and naturally slowing down in the
    //          higher levels.
    int nNXP = 0;

    //  This is the Bonus Received for the Kill
    int nKXP = 10;

    //  This is the RATE that determines party bonus. Adjust this
    //  as necessary to get the disired result.
    //  This is calculated to the CR of the creature Killed
    int nBXP = 20;

    //This is the Maximum XP for ANY Creature in a Module
    int nMXP = 200;

    //Maximum Level Difference from Highest to Lowest Level
    //Set to 40 To Basically Disable
    int nMLD = 40;

    //Maximum Level to Give XP
    int nMLXP = 40;

void main()
{
    int nCommoner = GetLevelByClass(CLASS_TYPE_COMMONER);
    int nAlign = GetAlignmentGoodEvil(OBJECT_SELF);
    object oKiller = GetLastKiller();
    object oMember;
    int nMember = 0;
    int nLLevel = 40;
    int nNParty = 0;
    int nLParty = 0;
    int nBFValue = 0;
    int nFMValue;

    // Check if the PC killed a Commoner
    // If YES shift 5 points towards Evil
    if (GetIsPC(oKiller) || GetIsPC(GetMaster(oKiller)))
    {
      int nCommoner = GetLevelByClass(CLASS_TYPE_COMMONER);
      int nAlign = GetAlignmentGoodEvil(OBJECT_SELF);
      if(nCommoner > 0 && (nAlign == ALIGNMENT_GOOD || nAlign == ALIGNMENT_NEUTRAL || nAlign == ALIGNMENT_EVIL ))
      {
        RemoveFromParty(oKiller);
        AdjustAlignment(oKiller, ALIGNMENT_EVIL, 5);
      }

      //Now we calculate the total CR Bonus XP
      float fCRBonusXP = GetChallengeRating(OBJECT_SELF);
      int nCRBonusXP = FloatToInt(fCRBonusXP);

      //First We need the Lowest Level Player
      oMember = GetFirstFactionMember(oKiller, TRUE);
      while(GetIsObjectValid(oMember))
      {
        if (GetArea(OBJECT_SELF) == GetArea(oMember))
        {
        nMember = GetHitDice(oMember);
        if(nMember < nLLevel) nLLevel = nMember;
        }
        oMember = GetNextFactionMember(oKiller, TRUE);
      }

      //All party members in the area of the kill will get XP Unless Outside of Range
      oMember = GetFirstFactionMember(oKiller, TRUE);
      while(GetIsObjectValid(oMember))
      {
        if (GetArea(OBJECT_SELF) == GetArea(oMember))
        {
        nMember = GetHitDice(oMember);
        nNParty++;
        if(nMember <= (nMLD + nLLevel))
        {
          nLParty += nMember;
          SetLocalInt(oMember,"XP_ELIGIBLE",1);
        }
        }
        oMember = GetNextFactionMember(oKiller, TRUE);
      }

      //Now we set the Average Party Level
      if(nNParty <= 0) nNParty = 1;
      int nAVGParty = nLParty / nNParty;
      if(nAVGParty <= 0) nAVGParty = 1;

      //Now we split the Bonus between all party members
      int nBonusXP;// = nCRBonusXP / nAVGParty;

      int nDifferenceCR = nCRBonusXP - nAVGParty;

      if (nDifferenceCR < -10) nDifferenceCR = -10;
      if (nDifferenceCR > 5) nDifferenceCR = 5;

      nDifferenceCR = nDifferenceCR + 11;
      if (nDifferenceCR < 11)
      {
      nBonusXP = nDifferenceCR * 5;
      }
      else
      {
      nDifferenceCR = nDifferenceCR - 11;
      nBonusXP = 100 + nDifferenceCR * 20;
      }
      //Now we set the Bonus to 0 of more
      if (nBonusXP > 0)
      {
        nBFValue = nBonusXP;
      }

      //This is the Final Total Experience Given to each Player
      int nFinalXP = nNXP + nBFValue;
      //if(nFinalXP > nMXP) nFinalXP = nMXP;
      nNParty = nNParty - 1;
      if (nNParty > 5) nNParty = 5;
      int nPartyBonus = nNParty * 10;
      nFinalXP = nFinalXP + nPartyBonus;
      nFinalXP = nFinalXP + GetLocalInt(OBJECT_SELF, "nBonusXP");

      //Now we give XP to all in the Party
      oMember = GetFirstFactionMember(oKiller, TRUE);
      int nXPE;
      while (GetIsObjectValid(oMember))
      {
        if (GetArea(OBJECT_SELF) == GetArea(oMember))
        {
        nXPE = GetLocalInt(oMember,"XP_ELIGIBLE");
        nMember = GetHitDice(oMember);
        if(nXPE == 1 && nMember <= nMLXP)
        {
          //The Killer gets the Kill Bonus
          if(oMember == oKiller) nFinalXP = nFinalXP + nKXP;
          GiveXPToCreature(oMember, nFinalXP);
        }
        }
        oMember = GetNextFactionMember(oKiller, TRUE);
      }

      int nMaxHP = GetMaxHitPoints(OBJECT_SELF);
      ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectResurrection(), OBJECT_SELF);
      ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectDamage(nMaxHP), OBJECT_SELF);
      return;
    }
}