414 lines
15 KiB
Plaintext
414 lines
15 KiB
Plaintext
#include "nw_i0_generic"
|
|
|
|
|
|
|
|
int iDebug = FALSE; // Set to TRUE enables several debug lines.
|
|
// Debug info includes party shares, etc.
|
|
|
|
int iDouble_EXP = FALSE; // Set to TRUE enables seeing first the PW
|
|
// experience followed by Bioware experience.
|
|
// This is useful to compare values.
|
|
|
|
float Experience_Slider = 0.06;// This is the percentage that can be adjusted.
|
|
// This value matches the Bioware slider.
|
|
|
|
float Exp_Level_Cap = 10.0; // This is the basic CR cap.
|
|
|
|
int iBoss_Cap_Method = 2; // These are mode sets for how bosses are handled
|
|
// Mode 1: The CR of the boss is modified.
|
|
// The exp cap is left at +8 CR.
|
|
// Mode 2: The CR of the boss is left alone.
|
|
// The exp cap is raised by the mod.
|
|
// Mode 3: The CR of the boss is modified.
|
|
// The exp cap is raised by the mod.
|
|
|
|
float Lower_Exponent = 1.15; // This is the exponent that defines how exp
|
|
// drops off when the CR is lower than player.
|
|
|
|
float Higher_Exponent = 1.15; // This is the exponent that defines how exp
|
|
// increases whent he CR is higher than player.
|
|
|
|
float Party_Proximity = 15.0; // The distance a party member must be to get a
|
|
// share of the experience.
|
|
|
|
float Leveling_Exponent = 1.08;// This exponent defines how fast the exponent is
|
|
// when determining party shares.
|
|
// The following is the level difference and
|
|
// how it relates to shares:
|
|
// 1.10 at 10 levels difference = 1.63 shares
|
|
// 1.20 at 10 levels difference = 6.19 shares
|
|
// 1.30 at 10 levels difference = 13.79 shares
|
|
|
|
float Familiar_Split = 0.10; // The ratio of shares that a familiar or animal
|
|
// companion receives.
|
|
|
|
float Henchman_Split = 0.25; // The ratio of shares that a henchman or
|
|
// summoned creature receives.
|
|
|
|
|
|
/*
|
|
|
|
|
|
|
|
The party experience split is calculated based upon an exponential equation
|
|
that is referenced to the level of the party members. In general, two players
|
|
of equal level each receive equal shares. If there is a 5 level difference,
|
|
then the higher level character gets 3.71 shares, while the lower gets 1.00
|
|
shares. The intent here is to give more experience to the high level characters
|
|
and less to the lower. After about 10 levels of difference, there is basically
|
|
no point in grouping, because there is very little experience gained for the
|
|
low level member.
|
|
|
|
All NPCs that are grouped with the party get a fraction of the shares that a
|
|
normal player would. This means that NPC party members subtract from the
|
|
experience pool like a normal player would, but to a lesser extent. A familiar
|
|
and summoned animal friend both recieve 1/3 of the experience pool. A summoned
|
|
creature, or henchman receives 2/3 of the experience pool. This means that
|
|
using a familiar should be viable for a spell caster. A chart is given at the
|
|
end of this script for the exact values of the shares based upon the level
|
|
differences in the party.
|
|
|
|
A major bug in the Bioware code is using the average level of the party to
|
|
determine how much experience should be given to the party. This is typically
|
|
abused on PWs by creating a 1st level summoned creature to reduce the party
|
|
average level, and thereby inflate the experience gained dramatically. This
|
|
problem is simply resolved by making the experience given to the party always
|
|
based off the highest level member.
|
|
|
|
The split of the experience pool is finally modified by the size of the party.
|
|
The intent here is to increase the experience for groups, and to promote their
|
|
use for leveling. The basic concept is two players of equal level would each
|
|
recieve 75% of the experience for the kill. This inflates the total experience
|
|
for the kill by 50%, but results in a more realistic gain for the party. A
|
|
chart is given at the end of this script for how the party experience is
|
|
enhanced.
|
|
|
|
All of these changes should promote grouping with like levels and allow some
|
|
of the lesser used game features, such as henchmen and familiars, to be more
|
|
common. The base experience gain is roughly equivelent to that of setting the
|
|
module experience slider to 4%. The majority of the equations used in this
|
|
system are second order polynomials. To change the 4% scale, simply adjust the
|
|
value float value at the start of this file. All attempts have been made to
|
|
directly match the Bioware scales for basic experience calculations.
|
|
|
|
When using custom death scripts, the last parameter in give_custom_exp is the
|
|
CR modifier that can be used to boost experience for creatures. The method of
|
|
the boost is defined by the Boss_Cap_Method variable.
|
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Absolutely, Positively do not call this function inside another loop
|
|
// that uses GetNextPC. This can be used inside GetNextFactionMember().
|
|
void SendMessageToParty( object oMember, string sText )
|
|
{
|
|
|
|
object oPartyMember = GetFirstPC();
|
|
while( GetIsObjectValid(oPartyMember) )
|
|
{
|
|
if( GetFactionEqual( oPartyMember, oMember ) )
|
|
SendMessageToPC( oPartyMember, sText );
|
|
oPartyMember = GetNextPC();
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
// This routine comes from and idea from Tone Eternal.
|
|
// It limits a player from gaining more experience after reaching enough to
|
|
// continue to the next level. This is not really a bug, but a short-coming
|
|
// of the Bioware code.
|
|
// This function is not used in version 1.4 or higher, but can be installed.
|
|
|
|
|
|
int IsPlayerLevelingUp( object oPlayer )
|
|
{
|
|
int nNeeded;
|
|
switch( GetHitDice(oPlayer) )
|
|
{
|
|
case 1: nNeeded = 1000; break;
|
|
case 2: nNeeded = 3000; break;
|
|
case 3: nNeeded = 6000; break;
|
|
case 4: nNeeded = 10000; break;
|
|
case 5: nNeeded = 15000; break;
|
|
case 6: nNeeded = 21000; break;
|
|
case 7: nNeeded = 28000; break;
|
|
case 8: nNeeded = 36000; break;
|
|
case 9: nNeeded = 45000; break;
|
|
case 10: nNeeded = 55000; break;
|
|
case 11: nNeeded = 66000; break;
|
|
case 12: nNeeded = 78000; break;
|
|
case 13: nNeeded = 91000; break;
|
|
case 14: nNeeded = 105000; break;
|
|
case 15: nNeeded = 120000; break;
|
|
case 16: nNeeded = 136000; break;
|
|
case 17: nNeeded = 153000; break;
|
|
case 18: nNeeded = 171000; break;
|
|
case 19: nNeeded = 200000; break;
|
|
default: nNeeded = 1000000; break;
|
|
}
|
|
|
|
if( nNeeded < GetXP( oPlayer ) )
|
|
return( TRUE );
|
|
|
|
return( FALSE );
|
|
}
|
|
|
|
|
|
|
|
|
|
// The main routine for giving experience to the player.
|
|
// Created by David Bills.
|
|
void give_custom_exp( object oKiller, object oDead, int nCRMod )
|
|
{
|
|
|
|
// Custom DMG EXP Script (varies slightly on bonuses and penalties)
|
|
// Concept and Original Code By Helznicht
|
|
// Syntax Clean-Up and Area Check Award by Mmealman
|
|
// Major bug rennovation by David Bills. 1-9-03
|
|
// Basic experience for creatures is around Bioware 3%.
|
|
// To adjust this, modify the polynomial equation below.
|
|
|
|
if( GetLocalInt( oDead, "AlreadyDyingEXP" ) == 1 )
|
|
return;
|
|
|
|
|
|
|
|
// First get all the members of the party
|
|
float LowestLevelMember = 1000.0;
|
|
float HighestLevelMember = -10.0;
|
|
|
|
float PartyShares = 0.0;
|
|
float fLevel = 0.0;
|
|
float fCRMod = IntToFloat( nCRMod );
|
|
|
|
object oMaster, oHighest, oLowest;
|
|
|
|
int bOld;
|
|
int nTotalMembers = 0;
|
|
|
|
object oPartyMember = GetFirstFactionMember(oKiller, FALSE );
|
|
|
|
while( GetIsObjectValid(oPartyMember) )
|
|
{
|
|
if( GetArea(oKiller) == GetArea(oPartyMember) &&
|
|
GetCurrentHitPoints( oPartyMember ) > 1 &&
|
|
GetDistanceBetween( oKiller, oPartyMember ) < Party_Proximity )
|
|
{
|
|
|
|
// Debug line
|
|
//if(iDebug== TRUE)
|
|
//{
|
|
SendMessageToAllDMs("Member: "+ GetName(oKiller));
|
|
//}
|
|
//
|
|
|
|
nTotalMembers ++;
|
|
|
|
if( GetIsPC( oPartyMember ) )
|
|
fLevel = IntToFloat( GetHitDice( oPartyMember ) );
|
|
else
|
|
fLevel = GetChallengeRating( oPartyMember );
|
|
|
|
if( LowestLevelMember > fLevel )
|
|
{
|
|
LowestLevelMember = fLevel;
|
|
oLowest = oPartyMember;
|
|
}
|
|
if( HighestLevelMember < fLevel )
|
|
{
|
|
HighestLevelMember = fLevel;
|
|
oHighest = oPartyMember;
|
|
}
|
|
}
|
|
|
|
oPartyMember = GetNextFactionMember(oKiller, FALSE);
|
|
}
|
|
|
|
// Now we need to test for the Really low level creatures.
|
|
// They need to be scaled as negative level to function properly.
|
|
float fChallenge =GetChallengeRating( oDead );
|
|
if( fChallenge < 1.0 )
|
|
fChallenge = 1.0 - (( 1.0 - fChallenge ) * 5.0);
|
|
|
|
|
|
|
|
// This is a debug routine.
|
|
if(iDebug== TRUE)
|
|
{
|
|
SendMessageToParty( oKiller, "Enemy CR: "+FloatToString( fChallenge ) );
|
|
SendMessageToParty( oKiller, "Highest Member: "+GetName( oHighest ) );
|
|
}
|
|
|
|
|
|
// This is the level difference of the dead to the highest
|
|
fLevel = fChallenge - HighestLevelMember;
|
|
|
|
if( iBoss_Cap_Method == 1 )
|
|
{
|
|
fLevel += fCRMod;
|
|
if( fLevel >= Exp_Level_Cap )
|
|
fLevel = Exp_Level_Cap;
|
|
}
|
|
else
|
|
if( iBoss_Cap_Method == 2 )
|
|
{
|
|
if( fLevel >= Exp_Level_Cap+fCRMod )
|
|
fLevel = Exp_Level_Cap+fCRMod;
|
|
}
|
|
else
|
|
{
|
|
if( fLevel >= Exp_Level_Cap )
|
|
fLevel = Exp_Level_Cap;
|
|
fLevel += fCRMod;
|
|
}
|
|
|
|
|
|
//Calculate basic value of kill
|
|
float FinalMonValue = 84.0 * HighestLevelMember + 750;
|
|
float fSharePercent;
|
|
|
|
// This is the exponential function to match the 3e rules.
|
|
// There is some adjustment here to allow for smooth transitions.
|
|
if( fLevel < 0.0 )
|
|
FinalMonValue = FinalMonValue * pow( Lower_Exponent, fLevel ) ;
|
|
else
|
|
FinalMonValue = FinalMonValue * pow( Higher_Exponent, fLevel ) ;
|
|
|
|
FinalMonValue = FinalMonValue * Experience_Slider;
|
|
|
|
if( FinalMonValue < 0.0 )
|
|
FinalMonValue = 0.0 ;
|
|
|
|
//if(iDebug == TRUE)//////////////////////////////////////////
|
|
//{
|
|
SendMessageToAllDMs("Base Xp: "+FloatToString( FinalMonValue ) );
|
|
//}
|
|
|
|
|
|
/* Now determine shares based upon the lowest party member. */
|
|
|
|
oPartyMember = GetFirstFactionMember(oKiller, FALSE);
|
|
while( GetIsObjectValid(oPartyMember) )
|
|
{
|
|
if( GetArea(oKiller) == GetArea(oPartyMember) &&
|
|
GetCurrentHitPoints( oPartyMember ) > 0 &&
|
|
GetDistanceBetween( oKiller, oPartyMember ) < Party_Proximity )
|
|
{
|
|
if( GetIsPC( oPartyMember ) )
|
|
fLevel = IntToFloat( GetHitDice( oPartyMember ) );
|
|
else
|
|
fLevel = GetChallengeRating( oPartyMember );
|
|
|
|
fLevel = fLevel - LowestLevelMember;
|
|
|
|
fSharePercent = pow( Leveling_Exponent , fLevel );
|
|
|
|
// This check is for summoned monsters, and familiars.
|
|
oMaster = GetMaster( oPartyMember );
|
|
if( GetIsObjectValid(oMaster) )
|
|
{
|
|
if( oPartyMember == GetAssociate( ASSOCIATE_TYPE_FAMILIAR, oMaster ) ||
|
|
oPartyMember == GetAssociate( ASSOCIATE_TYPE_ANIMALCOMPANION, oMaster ) )
|
|
fSharePercent = fSharePercent * Familiar_Split ;
|
|
else
|
|
fSharePercent = fSharePercent * Henchman_Split ;
|
|
}
|
|
|
|
// This is a debug line
|
|
if(iDebug == TRUE)
|
|
{
|
|
SendMessageToParty( oKiller, GetName(oPartyMember)+" Share="+FloatToString(fSharePercent) );
|
|
}
|
|
|
|
|
|
/* Adjusting the differential for level variance here */
|
|
PartyShares += fSharePercent;
|
|
}
|
|
|
|
oPartyMember = GetNextFactionMember(oKiller, FALSE);
|
|
}
|
|
|
|
// This is a debug line
|
|
if(iDebug== TRUE)
|
|
SendMessageToParty( oKiller, "Total Shares="+FloatToString(PartyShares) );
|
|
|
|
|
|
int nPenalty;
|
|
|
|
if( PartyShares > 0.0 )
|
|
{
|
|
//Determine the value of the Split EXP
|
|
// This is based on shares compared to the lowest member to the heighest.
|
|
int SFEint;
|
|
|
|
//Distribute EXP to all PCs in the Party based upon shares.
|
|
|
|
oPartyMember = GetFirstFactionMember(oKiller, TRUE);
|
|
while ( GetIsObjectValid(oPartyMember) )
|
|
{
|
|
if( GetArea(oKiller) == GetArea(oPartyMember) &&
|
|
GetCurrentHitPoints( oPartyMember ) > 0 &&
|
|
GetDistanceBetween( oKiller, oPartyMember ) < Party_Proximity )
|
|
{
|
|
fLevel = IntToFloat( GetHitDice( oPartyMember ) );
|
|
fLevel = fLevel - LowestLevelMember;
|
|
|
|
// The share system here is used because a 20th level character
|
|
// is MANY times more powerful than a 10th level character. And
|
|
// the experience shares should not simply be based upon straight
|
|
// level values.
|
|
// Use the formula: your share = (your level - lowest level) ^ 1.10
|
|
fSharePercent = pow( Leveling_Exponent , fLevel ) / PartyShares;
|
|
|
|
// The following modification improves experience for groups.
|
|
// It is not needed for a flat experience system, but then most
|
|
// people would not group. What it normally does is similar to
|
|
// two people of equal levels in a group each get 0.75 of the total
|
|
// experience, instead of an equal split of 0.50.
|
|
|
|
// Use the formula: Your fraction = 2 * share - share ^ 2
|
|
fSharePercent = 2*fSharePercent - (fSharePercent * fSharePercent );
|
|
|
|
if(iDebug== TRUE)
|
|
SendMessageToParty( oKiller, "Party Percent " +
|
|
GetName( oPartyMember ) +": "+
|
|
FloatToString(fSharePercent*100.0)+"%" );
|
|
|
|
SFEint = FloatToInt( fSharePercent * FinalMonValue );
|
|
|
|
// This code will give experience regardless of level.
|
|
//GiveXPToCreature(oPartyMember, SFEint);
|
|
|
|
// Use this code instead of the above line if you want to stop your
|
|
// players from gaining experience when they reach the next level.
|
|
if(IsPlayerLevelingUp(oPartyMember) == FALSE)
|
|
GiveXPToCreature(oPartyMember, SFEint);
|
|
else
|
|
SendMessageToPC( oKiller,
|
|
"You cannot gain experience until you level your character." );
|
|
//
|
|
|
|
}
|
|
|
|
oPartyMember = GetNextFactionMember(oKiller, TRUE);
|
|
}
|
|
}
|
|
|
|
// This line is needed to stop looping on death.
|
|
SetLocalInt( oDead, "AlreadyDyingEXP", 1 );
|
|
|
|
|
|
}
|
|
|
|
|
|
//void main() {}
|
|
|