Page 1 of 1

EXP settings - Avlis

Posted: Thu May 27, 2004 11:03 pm
by Aloro
Here are Avlis' current EXP settings:

* set Module EXP slider to 0
* change nw_c2_default7 (and all other OnDeath scripts, as needed) to use ExecuteScript("3ed_exp_sys", OBJECT_SELF)
* make sure the following script is in your module

Code: Select all

// Name     : 3ed_exp_sys.nss
// Purpose  : Calculate xp for a killed creature using DMG 3rd edition rules
// Author   : Aloro, based on avlis_exp_sys by Orl and Pap
// Date     : created on January 29, 2004
// Modified : Feb 04, 2004 - Aloro - added towing rules, lowered max exp
// Modified : Feb 05, 2004 - Aloro - added distance calculation, var. party bonus
// Modified : Feb 07, 2004 - Aloro - tweaked towing (count highlevel 3x)
// Modified : Feb 10, 2004 - Aloro - lowered exp slider, min exp for low CR
//                                   changed 2 GetIsObjectValid checks to GetIsPC
// Modified : Feb 11, 2004 - Aloro - lowered bonus to 1d4
// Modified : Feb 19, 2004 - Aloro - lowered exp slider & party bonus
// Modified : Mar 18, 2004 - Aloro - fixed divide by zero error, per Mistcaller
// Modified : May 06, 2004 - Aloro - added check to see if killer is DM

const int   iMaximumXP = 250;  // maximum for a single character
const float fSlider = 0.007;  // % of Standard DMG experience rewarded
const float fDistance = 50.0; // maximum distance from killer to give experience
const float fPtySizeBonus = 0.035; // bonus per person in a group (after first)
const int   iPtySizeBMax = 4; // number of party members to give bonus for

void main()
{
    // make sure a PC, an associate, or a trap killed the creature
    object oKiller = GetLastKiller();
    object oMaster;
    if (!GetIsPC(oKiller))
    {
        if (GetObjectType(oKiller) == OBJECT_TYPE_TRIGGER)
        {
            // killed by a trap
            object oCreator = GetTrapCreator(oKiller);
            // GetIsPC check added by Aloro Feb 10, 2004
            // replaced object valid check
            if (GetIsPC(oCreator))
                oKiller = oCreator;
            else
                return; // not killed by PC placed trap
        }
        else
        {
            // test for familiar / summon
            oMaster = GetMaster(oKiller);
            // GetIsPC check added by Aloro Feb 10, 2004
            // replaced object valid check
            if (GetIsPC(oMaster))
                oKiller = oMaster;
            else
                return; // not killed by PC pet - forget it
        }
    }

    if (GetIsDM(oKiller) || GetIsDMPossessed(oKiller)) return;

    float fEXP;
    float fCR = GetChallengeRating(OBJECT_SELF);
    int iCR = FloatToInt(fCR);
    // exp charts start at CR 1 - lower CRs are handled later on
    if (iCR < 1)
        iCR = 1;

    int iEXP;
    int iHitDice;
    int iPartyLevelSum = 0;
    int iPartyMembers = 0;
    int iHighLevel = 0;
    int iPartyLevelAvg;
    int iDifference;
    int iBonus = d4(1);
    object oKilledArea = GetArea(OBJECT_SELF);

    // Get party average level
    object oMember = GetFirstFactionMember(oKiller, FALSE);
    while (GetIsObjectValid(oMember))
    {
        // only count those party members in the area
        if (GetArea(oMember) == oKilledArea)
        {
            // only count members within specified distance
            if (GetDistanceBetween(oMember, oKiller) <= fDistance)
            {
                // do not count familiars and summons as party members
                oMaster = GetMaster(oMember);
                if (oMaster == OBJECT_INVALID)
                {
                    if (GetHitDice(oMember) > iHighLevel)
                        iHighLevel = GetHitDice(oMember);
                    iPartyMembers++;
                    iHitDice = GetHitDice(oMember);
                    iPartyLevelSum += iHitDice;
                }
            }
        }
        oMember = GetNextFactionMember(oKiller, FALSE);
    }

    // count the highest level person thrice for party average
    // this is to minimize towing
    iPartyLevelSum += iHighLevel;
    iPartyLevelSum += iHighLevel;
    iPartyMembers += 2;

    iPartyLevelAvg = iPartyLevelSum / iPartyMembers;

    // don't count anyone thrice when dividing shares though
    iPartyMembers -= 2;

    // calculate base experience when avg level = monster CR
    fEXP = 300.0 * iPartyLevelAvg;

    // calculate experience
    iDifference = iCR - iPartyLevelAvg;

    switch (iDifference)
    {
        case -7:
            fEXP /= 12;
            break;
        case -6:
            fEXP /= 8;
            break;
        case -5:
            fEXP = fEXP * 3 / 16;
            break;
        case -4:
            fEXP /= 4;
            break;
        case -3:
            fEXP /= 3;
            break;
        case -2:
            fEXP /= 2;
            break;
        case -1:
            fEXP = fEXP * 2 / 3;
            break;
        case 0:
            break;
        case 1:
            fEXP = fEXP * 3 / 2;
            break;
        case 2:
            fEXP *= 2;
            break;
        case 3:
            fEXP *= 3;
            break;
        case 4:
            fEXP *= 4;
            break;
        case 5:
            fEXP *= 6;
            break;
        case 6:
            fEXP *= 8;
            break;
        case 7:
            fEXP *= 12;
            break;
    }

    // if CR is more than 7 levels higher or lower than party avg, exp = 1
    if (abs(iDifference) > 7)
        fEXP = 1.0;

    // Calculations for CR < 1
    if (fCR < 1.0)
        fEXP *= fCR;

    // factor in EXP slider
    fEXP *= fSlider;

    // Divide EXP into equal shares
    if (iPartyMembers > 0)
        fEXP /= iPartyMembers;

    // minimum 1 exp for all kills
    if (fEXP < 1.0)
        fEXP = 1.0;

    // use constants defined above to give party bonus - currently:
    // 5% exp bonus for each party member after the first, max 20%
    if (iPartyMembers > 1)
    {
        iPartyMembers--;
        if (iPartyMembers > iPtySizeBMax)
            iPartyMembers = iPtySizeBMax;
        float fPartyBonus  = iPartyMembers * fPtySizeBonus;
        fPartyBonus += 1.0;
        fEXP *= fPartyBonus;
    }

    iEXP = FloatToInt(fEXP);

    // no bonus exp when high level party kills low level NPC
    if (fCR <= 3.0 && abs(iDifference) > 7)
        iBonus = 0;

    // Give 1d4 bonus EXP
    iEXP += iBonus;

    // Make sure EXP does not exceed maximum
    if (iEXP > iMaximumXP)
        iEXP = iMaximumXP;

    // Reward EXP
    object oPC = GetFirstFactionMember(oKiller, TRUE);
    while (GetIsObjectValid(oPC))
    {
        if (GetArea(oPC) == oKilledArea)
        {
            if (GetDistanceBetween(oPC, oKiller) <= fDistance)
                GiveXPToCreature(oPC, iEXP);
        }
        oPC = GetNextFactionMember(oKiller, TRUE);
    }
}
Using this will ensure 100% compatibility with Avlis' EXP system for combat. This is not necessary under CoPaP guidelines, as there is room for deviance above and below Avlis' settings - I am only posting this as a point of reference.

- Aloro