// // NWExperience // // XP functionality to replace NWN standard XP handling // // (c) Shir'le E. Illios, 2002 (shirle@drowwanderer.com) // //////////////////////////////////////////////////////// #include "dnd_inc_exp" // ************************************************************** // ** Constants // ********************** // General experience scale slider (also includes monster xp scale). float ADVANCE_XP_SCALE = 1.0; // Monster experience scale slider. float MONSTER_XP_SCALE = 1.0; // ************************************************************** // ** Forward declarations // ********************** // Private function for the subraces script. Do not use. int SEI_GetEffectiveCharacterLevel( object a_oCharacter ); // Private function for the subraces script. Do not use. int SEI_ModifyXPForSubrace( object a_oCharacter, int a_nXP ); // ************************************************************** // ** Forward declarations for the Script Editor Help. // ********************** // Reward experience to the character. // ARGUMENTS: // a_oCharacter = The character to give the experience to. // a_nXP = The experience to give to the character. // void XP_RewardXP( object a_oCharacter, int a_nXP ); // Give XP to a party dividing it between them based on level. // ARGUMENTS: // a_oCharacter = One of the party members to give the experience to. // a_oArea = Only party members in this area will get XP. // a_nXP = The amount of experience to divide between the party. // void XP_RewardXPToPartyInArea( object a_oCharacter, object a_oArea, int a_nXP ); // Reward characters experience for a kill. // Use in a creature's OnDeath script. // void XP_RewardXPForKill(); // Make certain the character doesn't get more than one level from their xp gain. // int XP_CapXPToMaxGain( object a_oCharacter, int a_nXP ) { int nResult = a_nXP; // Get the character's level (ECL). int nLevel = SEI_GetEffectiveCharacterLevel( a_oCharacter ); // Get how much experience the character has. int nXP = GetXP( a_oCharacter ); // Get the maximum number of levels the character can gain. int nMaxLevelGain = ( ( nLevel >= 20 ) ? 0 : 1 ); // Get the maximum experience the character is allowed to have. int nMaxXP = ( 500 * ( ( nLevel + nMaxLevelGain + 1 ) * ( nLevel + nMaxLevelGain ) ) ) - 1; // Get the maximum amount of experience the character can gain. int nMaxXPGain = nMaxXP - nXP; // Cap the character's experience gain to a maximum gain. if( nResult > nMaxXPGain ) { nResult = nMaxXPGain; } return nResult; } // End XP_CapXPToMaxGain // Reward experience to the character. // void XP_RewardXP( object a_oCharacter, int a_nXP ) { int nXP = a_nXP; nXP = SEI_ModifyXPForSubrace( a_oCharacter, nXP ); nXP = FloatToInt( ADVANCE_XP_SCALE * nXP ); nXP = XP_CapXPToMaxGain( a_oCharacter, nXP ); // Make certain that the character doesn't get zero XP. if( nXP < 1 ) { nXP = 1; } if(!GetLocalInt(GetModule(),"PWEXP")) GiveXPToCreature( a_oCharacter, nXP ); else DND_add_exp(a_oCharacter, nXP); } // End XP_RewardXP // Give XP to a party dividing it between them based on level. // void XP_RewardXPToPartyInArea( object a_oCharacter, object a_oArea, int a_nXP ) { // SEI_NOTE: There now is an exploit where higher level character can boost // the XP from encounters by including low-level PC (and thus // lowering the avarage level). int nPartyMembers = 0; int nPartyLevelTotal = 0; object oPC = GetFirstFactionMember( a_oCharacter ); // First get the number of party members and total level. while( GetIsObjectValid( oPC ) ) { if( !GetIsDM( oPC ) && ( a_oArea == GetArea( oPC ) ) ) { ++nPartyMembers; nPartyLevelTotal += SEI_GetEffectiveCharacterLevel( oPC ); } oPC = GetNextFactionMember( a_oCharacter, TRUE ); } // End while oPC = GetFirstFactionMember( a_oCharacter ); // Apply experience to each PC based on their level. while( GetIsObjectValid( oPC ) ) { if( !GetIsDM( oPC ) && ( a_oArea == GetArea( oPC ) ) ) { int nCharXP = FloatToInt( IntToFloat( a_nXP ) * ( IntToFloat( SEI_GetEffectiveCharacterLevel( oPC ) ) / IntToFloat( nPartyLevelTotal ) ) ); XP_RewardXP( oPC, nCharXP ); } oPC = GetNextFactionMember( a_oCharacter, TRUE ); } // End while } // End XP_RewardXPToPartyInArea // Get how much experience the CR is worth to a character of the average level. // int XP_GetXPFromCR( float a_fCR, float a_fAvgLvl ) { // Base experience to build the experience from. float fXP = 300.0; if( ( a_fAvgLvl >= 7.0 ) || ( a_fCR >= 1.5 ) ) { fXP *= a_fAvgLvl; int nDiff = FloatToInt( ( ( a_fCR < 1.0 ) ? 1.0 : a_fCR ) - a_fAvgLvl ); switch( nDiff ) { // SEI_NOTE: Broken with styleguide for readability. case -7: fXP /= 12.0; break; case -6: fXP /= 8.0; break; case -5: fXP *= 3.0 / 16.0; break; case -4: fXP /= 4.0; break; case -3: fXP /= 3.0; break; case -2: fXP /= 2.0; break; case -1: fXP *= 2.0 / 3.0; break; case 0: break; case 1: fXP *= 3.0 / 2.0; break; case 2: fXP *= 2.0; break; case 3: fXP *= 3.0; break; case 4: fXP *= 4.0; break; case 5: fXP *= 6.0; break; case 6: fXP *= 8.0; break; case 7: fXP *= 12.0; break; // nDiff > 7 || nDiff < -7 default: fXP = 0.0; break; } // End switch-case } // End if // Calculations for CR < 1 if( ( a_fCR < 0.76 ) && ( fXP > 0.0 ) ) { // SEI_NOTE: Broken with styleguide for readability. if( a_fCR <= 0.11 ) { fXP /= 10.0; } else if( a_fCR <= 0.13 ) { fXP /= 8.0; } else if( a_fCR <= 0.18 ) { fXP /= 6.0; } else if( a_fCR <= 0.28 ) { fXP /= 4.0; } else if( a_fCR <= 0.40 ) { fXP /= 3.0; } else if( a_fCR <= 0.76 ) { fXP /= 2.0; } // Only the CR vs Avg Level table could set nMonsterXP to 0... // to fix any round downs that result in 0: if( fXP <= 0.0 ) { fXP = 1.0; } } // End if return FloatToInt( fXP ); } // End XP_GetXPFromCR // Reward characters experience for a kill. // Use in a creature's OnDeath script. // void XP_RewardXPForKill() { object oKiller = GetLastKiller(); object oKilledArea = GetArea( OBJECT_SELF ); int nPartyMembers = 0; int nPartyLevelTotal = 0; object oPC = GetFirstFactionMember( oKiller ); while( GetIsObjectValid( oPC ) ) { if( !GetIsDM( oPC ) && ( oKilledArea == GetArea( oPC ) ) ) { ++nPartyMembers; nPartyLevelTotal += SEI_GetEffectiveCharacterLevel( oPC ); } oPC = GetNextFactionMember( oKiller, TRUE ); } // End while if( nPartyMembers != 0 ) { float fAvgPartyLevel = IntToFloat( nPartyLevelTotal ) / IntToFloat( nPartyMembers ); // Bring partylevel up to 3 if less than 3 if( fAvgPartyLevel < 3.0 ) { fAvgPartyLevel = 3.0; } float fCR = GetChallengeRating( OBJECT_SELF ); int nTotalXP = XP_GetXPFromCR( fCR, fAvgPartyLevel ); XP_RewardXPToPartyInArea( oKiller, oKilledArea, FloatToInt( MONSTER_XP_SCALE * nTotalXP ) ); } // End if } // End XP_RewardXPForKill