////////////////////////////////////////////////////////////////////////////////
// lib_hos1_xp - Experience Point System for Harvest of Souls 1
//------------------------------------------------------------------------------
// By Deva B. Winblood.   April 8th, 2009
////////////////////////////////////////////////////////////////////////////////
/*  VARIABLES:

bEasy
bChallenging

Experience Multiplier
4
6 [default]
8
12
20
30
50
75
fXPMultiplier

*/


///////////////////////////////////////
// PROTOTYPES
///////////////////////////////////////


// FILE: lib_hos1_xp        FUNCTION: GetXPValue()
// This function will return the XP value of oTarget if defeated by oKiller.
int GetXPValue(object oKiller,object oTarget);


///////////////////////////////////////
// FUNCTIONS
///////////////////////////////////////


float fnGetCR(object oOb)
{ // PURPOSE: Return level
    float fCR=GetChallengeRating(oOb);
    if (fCR==0.0) fCR=IntToFloat(GetLevelByPosition(1,oOb)+GetLevelByPosition(2,oOb)+GetLevelByPosition(3,oOb));
    if (fCR<0.1) fCR=0.1;
    return fCR;
} // fnXPGetLevel()


float fnXPGetAttackerValues(object oKiller)
{ // PURPOSE: Return the attacker values
    int nN;
    float fCR=fnGetCR(oKiller);
    float fTotals=fCR;
    object oOb;
    if (!GetIsPC(oKiller))
    { // NPC
        object oMaster=GetMaster(oKiller);
        if (GetIsObjectValid(oMaster))
        { // master exists
            if (!GetIsPC(oMaster))
            { // master is not a PC
                fTotals=fTotals+fnGetCR(oMaster);
                string sID=GetLocalString(oMaster,"sTeamID");
                if (GetStringLength(sID)>0)
                { // team member
                    oOb=GetAssociate(ASSOCIATE_TYPE_FAMILIAR,oMaster);
                    if (GetIsObjectValid(oOb)) fTotals=fTotals+(fnGetCR(oOb)/3.0);
                    oOb=GetAssociate(ASSOCIATE_TYPE_ANIMALCOMPANION,oMaster);
                    if (GetIsObjectValid(oOb)) fTotals=fTotals+(fnGetCR(oOb)/3.0);
                    oOb=GetAssociate(ASSOCIATE_TYPE_HENCHMAN,oMaster);
                    if (GetIsObjectValid(oOb)) fTotals=fTotals+(fnGetCR(oOb)/3.0);
                    oOb=GetAssociate(ASSOCIATE_TYPE_DOMINATED,oMaster);
                    if (GetIsObjectValid(oOb)) fTotals=fTotals+(fnGetCR(oOb)/4.0);
                    oOb=GetAssociate(ASSOCIATE_TYPE_SUMMONED,oMaster);
                    if (GetIsObjectValid(oOb)) fTotals=fTotals+(fnGetCR(oOb)/4.0);
                    nN=1;
                    oOb=GetNearestCreature(CREATURE_TYPE_IS_ALIVE,TRUE,oMaster,nN,CREATURE_TYPE_PLAYER_CHAR,PLAYER_CHAR_IS_PC,CREATURE_TYPE_REPUTATION,REPUTATION_TYPE_FRIEND);
                    while(GetIsObjectValid(oOb)&&GetDistanceBetween(oKiller,oOb)<30.0)
                    { // possible assisting PC
                        if (GetLocalString(oOb,"sTeamID")==sID) fTotals=fTotals+(fnGetCR(oOb)/2.0);
                        nN++;
                        oOb=GetNearestCreature(CREATURE_TYPE_IS_ALIVE,TRUE,oMaster,nN,CREATURE_TYPE_PLAYER_CHAR,PLAYER_CHAR_IS_PC,CREATURE_TYPE_REPUTATION,REPUTATION_TYPE_FRIEND);
                    } // possible assisting PC
                } // team member
            } // master is not a PC
            else
            { // master is PC
                oOb=GetAssociate(ASSOCIATE_TYPE_FAMILIAR,oMaster);
                    if (GetIsObjectValid(oOb)) fTotals=fTotals+(fnGetCR(oOb)/3.0);
                    oOb=GetAssociate(ASSOCIATE_TYPE_ANIMALCOMPANION,oMaster);
                    if (GetIsObjectValid(oOb)) fTotals=fTotals+(fnGetCR(oOb)/3.0);
                    oOb=GetAssociate(ASSOCIATE_TYPE_HENCHMAN,oMaster);
                    if (GetIsObjectValid(oOb)) fTotals=fTotals+(fnGetCR(oOb)/3.0);
                    oOb=GetAssociate(ASSOCIATE_TYPE_DOMINATED,oMaster);
                    if (GetIsObjectValid(oOb)) fTotals=fTotals+(fnGetCR(oOb)/4.0);
                    oOb=GetAssociate(ASSOCIATE_TYPE_SUMMONED,oMaster);
                    if (GetIsObjectValid(oOb)) fTotals=fTotals+(fnGetCR(oOb)/4.0);
                    nN=1;
                    oOb=GetNearestCreature(CREATURE_TYPE_IS_ALIVE,TRUE,oMaster,nN,CREATURE_TYPE_PLAYER_CHAR,PLAYER_CHAR_IS_PC,CREATURE_TYPE_REPUTATION,REPUTATION_TYPE_FRIEND);
                    while(GetIsObjectValid(oOb)&&GetDistanceBetween(oKiller,oOb)<30.0)
                    { // possible assisting PC
                        fTotals=fTotals+(fnGetCR(oOb)/2.0);
                        nN++;
                        oOb=GetNearestCreature(CREATURE_TYPE_IS_ALIVE,TRUE,oMaster,nN,CREATURE_TYPE_PLAYER_CHAR,PLAYER_CHAR_IS_PC,CREATURE_TYPE_REPUTATION,REPUTATION_TYPE_FRIEND);
                    } // possible assisting PC
            } // master is PC
        } // master exists
        else
        { // no master - check for nearby PC team members
            string sID=GetLocalString(oKiller,"sTeamID");
            if (GetStringLength(sID)>0)
            { // team unit
                nN=1;
                oOb=GetNearestCreature(CREATURE_TYPE_IS_ALIVE,TRUE,oKiller,nN,CREATURE_TYPE_REPUTATION,REPUTATION_TYPE_FRIEND);
                while(GetIsObjectValid(oOb)&&GetDistanceBetween(oKiller,oOb)<30.0)
                { // possible assisting creature
                    if (GetLocalString(oOb,"sTeamID")==sID)
                    { // team members
                        if (!GetIsPC(oOb)) fTotals=fTotals+(fnGetCR(oOb)/2.0);
                        else { fTotals=fTotals+fnGetCR(oOb); }
                    } // team members
                    nN++;
                    oOb=GetNearestCreature(CREATURE_TYPE_IS_ALIVE,TRUE,oKiller,nN,CREATURE_TYPE_REPUTATION,REPUTATION_TYPE_FRIEND);
                } // possible assisting creature
            } // team unit
        } // no master - check for nearby PC team members
    } // NPC
    else
    { // PC
        oOb=GetAssociate(ASSOCIATE_TYPE_FAMILIAR,oKiller);
        if (GetIsObjectValid(oOb)) fTotals=fTotals+(fnGetCR(oOb)/2.0);
        oOb=GetAssociate(ASSOCIATE_TYPE_ANIMALCOMPANION,oKiller);
        if (GetIsObjectValid(oOb)) fTotals=fTotals+(fnGetCR(oOb)/2.0);
        oOb=GetAssociate(ASSOCIATE_TYPE_HENCHMAN,oKiller);
        if (GetIsObjectValid(oOb)) fTotals=fTotals+(fnGetCR(oOb)/2.0);
        oOb=GetAssociate(ASSOCIATE_TYPE_DOMINATED,oKiller);
        if (GetIsObjectValid(oOb)) fTotals=fTotals+(fnGetCR(oOb)/3.0);
        oOb=GetAssociate(ASSOCIATE_TYPE_SUMMONED,oKiller);
        if (GetIsObjectValid(oOb)) fTotals=fTotals+(fnGetCR(oOb)/3.0);
        nN=1;
        oOb=GetNearestCreature(CREATURE_TYPE_IS_ALIVE,TRUE,oKiller,nN,CREATURE_TYPE_PLAYER_CHAR,PLAYER_CHAR_IS_PC,CREATURE_TYPE_REPUTATION,REPUTATION_TYPE_FRIEND);
        while(GetIsObjectValid(oOb)&&GetDistanceBetween(oKiller,oOb)<30.0)
        { // possible assisting PC
            fTotals=fTotals+(fnGetCR(oOb)/2.0);
            nN++;
            oOb=GetNearestCreature(CREATURE_TYPE_IS_ALIVE,TRUE,oKiller,nN,CREATURE_TYPE_PLAYER_CHAR,PLAYER_CHAR_IS_PC,CREATURE_TYPE_REPUTATION,REPUTATION_TYPE_FRIEND);
        } // possible assisting PC
    } // PC
    return fTotals;
} // fnXPGetAttackerValues()


int GetXPValue(object oKiller,object oTarget)
{ // PURPOSE: Return the experience point value
    int nXP=0;
    string sID=GetLocalString(oKiller,"sTeamID");
    string sTID=GetLocalString(oTarget,"sTeamID");
    if (GetStringLength(sID)>0&&sID==sTID) return 0; // no XP for killing own team members
    float fValue=fnXPGetAttackerValues(oKiller);
    float fTargetCR=fnGetCR(oTarget);
    float fXPMultiplier=GetLocalFloat(GetModule(),"fXPMultiplier");
    if (fTargetCR<0.1) fTargetCR=0.1;
    if (fXPMultiplier<6.0) fXPMultiplier=6.0;
    if (GetLocalInt(GetModule(),"bEasy")) fTargetCR=fTargetCR+1.0;
    else if (GetLocalInt(GetModule(),"bChallenging")) fTargetCR=(fTargetCR/6.0)*5.0;
    if (fValue==0.0) fValue=fnGetCR(oKiller);
    float fBase=fTargetCR/fValue;
    float fTotal=fBase*10.0;
    fTotal=fTotal*fXPMultiplier;
    nXP=FloatToInt(fTotal);
    if (nXP<1&&sID!=sTID) nXP=1;
    return nXP;
} // GetXPValue()




//void main(){}