574 lines
15 KiB
Plaintext
574 lines
15 KiB
Plaintext
#include "sha_subr_methds"
|
|
|
|
// ::DEFINERS
|
|
float SHA_GetXP(float CR, float AvgPartyLevel);
|
|
|
|
object DeadMonster = OBJECT_SELF;
|
|
|
|
int SHA_GetECL(object oPC)
|
|
{
|
|
int iLevel = GetPlayerLevel(oPC);
|
|
if(iLevel > MAXIMUM_PLAYER_LEVEL)
|
|
{
|
|
iLevel = MAXIMUM_PLAYER_LEVEL;
|
|
}
|
|
string Subrace = GetStringLowerCase( GetSubRace(oPC) );
|
|
if(Subrace == "")
|
|
{
|
|
return iLevel;
|
|
}
|
|
// Removed below and moved to the GetECL method
|
|
//else if( (Subrace == "vampire" || Subrace == "lich" ) && GetHitDice(oPC) < 5 )
|
|
//{
|
|
// iLevel += 1;
|
|
else {
|
|
iLevel += GetECL(oPC);
|
|
}
|
|
|
|
if(iLevel < 0)
|
|
{
|
|
iLevel = 0;
|
|
}
|
|
return iLevel;
|
|
}
|
|
|
|
|
|
float SHA_CalculateXPModifier(int PartySize, int NumberOfNPCs)
|
|
{
|
|
float fModifier;
|
|
if(USE_BIOWARE_STANDARD_XP_SYSTEM)
|
|
{
|
|
fModifier = 1.0/IntToFloat(PartySize);
|
|
}
|
|
else if(PartySize == 1)
|
|
{
|
|
fModifier = 0.35;
|
|
}
|
|
else if(PartySize > 1)
|
|
{
|
|
fModifier = XP_MODIFIER_FOR_PARTY_OF_TWO + (IntToFloat(PartySize - 2)*XP_MODIFIER_BONUS_PER_PARTY_MEMBER);
|
|
if(fModifier > XP_MAXIMUM_MODIFER_VALUE)
|
|
{
|
|
fModifier = XP_MAXIMUM_MODIFER_VALUE;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// ::PC's summon or familar killed the monster, and the PC was not near by.
|
|
fModifier = 0.0;
|
|
}
|
|
|
|
// ::For NPCs.
|
|
if(NumberOfNPCs >= 1)
|
|
{
|
|
fModifier = fModifier - (XP_MODIFIER_FOR_NPC*IntToFloat(NumberOfNPCs));
|
|
}
|
|
return fModifier;
|
|
}
|
|
|
|
float SHA_GetXP(float CR, float AvgPartyLevel)
|
|
{
|
|
// ::Party Level is less than 8 (Special and rather weird distribution)
|
|
if(AvgPartyLevel < 8.0)
|
|
{
|
|
float XP;
|
|
// ::Made up some values for Player level < 1. (Incase of a negative ECL)
|
|
if(AvgPartyLevel < 1.0)
|
|
{
|
|
if(CR < 1.0)
|
|
{
|
|
XP = 3.0;
|
|
}
|
|
else if(CR >= 1.0 && CR < 2.0)
|
|
{
|
|
XP = 6.0;
|
|
}
|
|
else if(CR >= 2.0 && CR < 3.0)
|
|
{
|
|
XP = 10.6;
|
|
}
|
|
else if(CR >= 3.0 && CR < 4.0)
|
|
{
|
|
XP = 16.4;
|
|
}
|
|
else if(CR >= 4.0 && CR < 5.0)
|
|
{
|
|
XP = 28.2;
|
|
}
|
|
else if(CR >= 5.0)
|
|
{
|
|
XP = 32.0;
|
|
}
|
|
}
|
|
else if(AvgPartyLevel >= 1.0 && AvgPartyLevel < 2.0)
|
|
{
|
|
if(CR < 1.0)
|
|
{
|
|
XP = 2.0;
|
|
}
|
|
else if(CR >= 1.0 && CR < 2.0)
|
|
{
|
|
XP = 5.0;
|
|
}
|
|
else if(CR >= 2.0 && CR < 3.0)
|
|
{
|
|
XP = 9.6;
|
|
}
|
|
else if(CR >= 3.0 && CR < 4.0)
|
|
{
|
|
XP = 14.4;
|
|
}
|
|
else if(CR >= 4.0 && CR < 5.0)
|
|
{
|
|
XP = 25.2;
|
|
}
|
|
else if(CR >= 5.0)
|
|
{
|
|
XP = 30.0;
|
|
}
|
|
}
|
|
else if(AvgPartyLevel >= 2.0 && AvgPartyLevel < 3.0)
|
|
{
|
|
if(CR < 1.0)
|
|
{
|
|
XP = 1.8;
|
|
}
|
|
else if(CR >= 1.0 && CR < 2.0)
|
|
{
|
|
XP = 4.8;
|
|
}
|
|
else if(CR >= 2.0 && CR < 3.0)
|
|
{
|
|
XP = 9.0;
|
|
}
|
|
else if(CR >= 3.0 && CR < 4.0)
|
|
{
|
|
XP = 13.7;
|
|
}
|
|
else if(CR >= 4.0 && CR < 5.0)
|
|
{
|
|
XP = 19.2;
|
|
}
|
|
else if(CR >= 5.0 && CR < 6.0)
|
|
{
|
|
XP = 31.5;
|
|
}
|
|
else if(CR >= 6.0)
|
|
{
|
|
XP = 40.0;
|
|
}
|
|
}
|
|
else if(AvgPartyLevel >= 3.0 && AvgPartyLevel < 4.0)
|
|
{
|
|
if(CR < 1.0)
|
|
{
|
|
XP = 1.7;
|
|
}
|
|
else if(CR >= 1.0 && CR < 2.0)
|
|
{
|
|
XP = 4.2;
|
|
}
|
|
else if(CR >= 2.0 && CR < 3.0)
|
|
{
|
|
XP = 7.5;
|
|
}
|
|
else if(CR >= 3.0 && CR < 4.0)
|
|
{
|
|
XP = 12.0;
|
|
}
|
|
else if(CR >= 4.0 && CR < 5.0)
|
|
{
|
|
XP = 17.7;
|
|
}
|
|
else if(CR >= 5.0 && CR < 6.0)
|
|
{
|
|
XP = 24.0;
|
|
}
|
|
else if(CR >= 6.0 && CR < 7.0)
|
|
{
|
|
XP = 37.8;
|
|
}
|
|
else if(CR >= 7.0)
|
|
{
|
|
XP = 50.0;
|
|
}
|
|
}
|
|
else if(AvgPartyLevel >= 4.0 && AvgPartyLevel < 5.0)
|
|
{
|
|
if(CR < 1.0)
|
|
{
|
|
XP = 0.68;
|
|
}
|
|
else if(CR >= 1.0 && CR < 2.0)
|
|
{
|
|
XP = 2.6;
|
|
}
|
|
else if(CR >= 2.0 && CR < 3.0)
|
|
{
|
|
XP = 4.2;
|
|
}
|
|
else if(CR >= 3.0 && CR < 4.0)
|
|
{
|
|
XP = 6.28;
|
|
}
|
|
else if(CR >= 4.0 && CR < 5.0)
|
|
{
|
|
XP = 10.48;
|
|
}
|
|
else if(CR >= 5.0 && CR < 6.0)
|
|
{
|
|
XP = 15.2;
|
|
}
|
|
else if(CR >= 6.0 && CR < 7.0)
|
|
{
|
|
XP = 20.2;
|
|
}
|
|
else if(CR >= 7.0 && CR < 8.0)
|
|
{
|
|
XP = 30.88;
|
|
}
|
|
else if(CR >= 8.0)
|
|
{
|
|
XP = 38.48;
|
|
}
|
|
}
|
|
else if(AvgPartyLevel >= 5.0 && AvgPartyLevel < 6.0)
|
|
{
|
|
if(CR < 1.0)
|
|
{
|
|
XP = 0.68;
|
|
}
|
|
else if(CR >= 1.0 && CR < 2.0)
|
|
{
|
|
XP = 2.28;
|
|
}
|
|
else if(CR >= 2.0 && CR < 3.0)
|
|
{
|
|
XP = 3.28;
|
|
}
|
|
else if(CR >= 3.0 && CR < 4.0)
|
|
{
|
|
XP = 5.28;
|
|
}
|
|
else if(CR >= 4.0 && CR < 5.0)
|
|
{
|
|
XP = 7.68;
|
|
}
|
|
else if(CR >= 5.0 && CR < 6.0)
|
|
{
|
|
XP = 12.6;
|
|
}
|
|
else if(CR >= 6.0 && CR < 7.0)
|
|
{
|
|
XP = 18.08;
|
|
}
|
|
else if(CR >= 7.0 && CR < 8.0)
|
|
{
|
|
XP = 23.48;
|
|
}
|
|
else if(CR >= 8.0 && CR < 9.0)
|
|
{
|
|
XP = 35.28;
|
|
}
|
|
else if(CR >= 9.0)
|
|
{
|
|
XP = 42.0;
|
|
}
|
|
}
|
|
else if(AvgPartyLevel >= 6.0 && AvgPartyLevel < 7.0)
|
|
{
|
|
if(CR < 1.0)
|
|
{
|
|
XP = 0.68;
|
|
}
|
|
else if(CR >= 1.0 && CR < 2.0)
|
|
{
|
|
XP = 1.88;
|
|
}
|
|
else if(CR >= 2.0 && CR < 3.0)
|
|
{
|
|
XP = 2.8;
|
|
}
|
|
else if(CR >= 3.0 && CR < 4.0)
|
|
{
|
|
XP = 4.0;
|
|
}
|
|
else if(CR >= 4.0 && CR < 5.0)
|
|
{
|
|
XP = 6.28;
|
|
}
|
|
else if(CR >= 5.0 && CR < 6.0)
|
|
{
|
|
XP = 9.08;
|
|
}
|
|
else if(CR >= 6.0 && CR < 7.0)
|
|
{
|
|
XP = 14.68;
|
|
}
|
|
else if(CR >= 7.0 && CR < 8.0)
|
|
{
|
|
XP = 20.0;
|
|
}
|
|
else if(CR >= 8.0 && CR < 9.0)
|
|
{
|
|
XP = 26.88;
|
|
}
|
|
else if(CR >= 9.0 && CR < 10.0)
|
|
{
|
|
XP = 39.68;
|
|
}
|
|
else if(CR >= 10.0)
|
|
{
|
|
XP = 49.0;
|
|
}
|
|
}
|
|
else if(AvgPartyLevel >= 7.0)
|
|
{
|
|
if(CR < 1.0)
|
|
{
|
|
XP = 0.68;
|
|
}
|
|
else if(CR >= 1.0 && CR < 2.0)
|
|
{
|
|
XP = 1.68;
|
|
}
|
|
else if(CR >= 2.0 && CR < 3.0)
|
|
{
|
|
XP = 2.28;
|
|
}
|
|
else if(CR >= 3.0 && CR < 4.0)
|
|
{
|
|
XP = 3.28;
|
|
}
|
|
else if(CR >= 4.0 && CR < 5.0)
|
|
{
|
|
XP = 4.68;
|
|
}
|
|
else if(CR >= 5.0 && CR < 6.0)
|
|
{
|
|
XP = 7.4;
|
|
}
|
|
else if(CR >= 6.0 && CR < 7.0)
|
|
{
|
|
XP = 10.48;
|
|
}
|
|
else if(CR >= 7.0 && CR < 8.0)
|
|
{
|
|
XP = 16.80;
|
|
}
|
|
else if(CR >= 8.0 && CR < 9.0)
|
|
{
|
|
XP = 23.68;
|
|
}
|
|
else if(CR >= 9.0 && CR < 10.0)
|
|
{
|
|
XP = 28.0;
|
|
}
|
|
else if(CR >= 10.0 && CR < 11.0)
|
|
{
|
|
XP = 44.08;
|
|
}
|
|
else
|
|
{
|
|
XP = 56.0;
|
|
}
|
|
}
|
|
return XP;
|
|
}
|
|
else
|
|
{
|
|
float AdjustedCR = CR - AvgPartyLevel;
|
|
float RewardXP = BASE_XP;
|
|
if(AdjustedCR >= 0.0)
|
|
{
|
|
if(AdjustedCR >= 8.0)
|
|
{
|
|
RewardXP += XP_LEVEL8;
|
|
}
|
|
else if(AdjustedCR < 8.0 && AdjustedCR >= 7.0)
|
|
{
|
|
RewardXP += XP_LEVEL7;
|
|
}
|
|
else if(AdjustedCR < 7.0 && AdjustedCR >= 6.0)
|
|
{
|
|
RewardXP += XP_LEVEL6;
|
|
}
|
|
else if(AdjustedCR < 6.0 && AdjustedCR >= 5.0)
|
|
{
|
|
RewardXP += XP_LEVEL5;
|
|
}
|
|
else if(AdjustedCR < 5.0 && AdjustedCR >= 4.0)
|
|
{
|
|
RewardXP += XP_LEVEL4;
|
|
}
|
|
else if(AdjustedCR < 4.0 && AdjustedCR >= 3.0)
|
|
{
|
|
RewardXP += XP_LEVEL3;
|
|
}
|
|
else if(AdjustedCR < 3.0 && AdjustedCR >= 2.0)
|
|
{
|
|
RewardXP += XP_LEVEL2;
|
|
}
|
|
else if(AdjustedCR < 2.0 && AdjustedCR >= 0.5)
|
|
{
|
|
RewardXP += XP_LEVEL1;
|
|
}
|
|
else if(AdjustedCR < 0.5 && AdjustedCR >= 0.0)
|
|
{
|
|
// ::Nothing, just base XP. The Monster is of a challenging level.
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if(AdjustedCR <= -9.0)
|
|
{
|
|
RewardXP = 0.4;
|
|
}
|
|
else if(AdjustedCR > -9.0 && AdjustedCR <= -8.0)
|
|
{
|
|
RewardXP += XP_LEVEL_8;
|
|
}
|
|
else if(AdjustedCR > -8.0 && AdjustedCR <= -7.0)
|
|
{
|
|
RewardXP += XP_LEVEL_7;
|
|
}
|
|
else if(AdjustedCR > -7.0 && AdjustedCR <= -6.0)
|
|
{
|
|
RewardXP += XP_LEVEL_6;
|
|
}
|
|
else if(AdjustedCR > -6.0 && AdjustedCR <= -5.0)
|
|
{
|
|
RewardXP += XP_LEVEL_5;
|
|
}
|
|
else if(AdjustedCR > -5.0 && AdjustedCR <= -4.0)
|
|
{
|
|
RewardXP += XP_LEVEL_4;
|
|
}
|
|
else if(AdjustedCR > -4.0 && AdjustedCR <= -3.0)
|
|
{
|
|
RewardXP += XP_LEVEL_4;
|
|
}
|
|
else if(AdjustedCR > -3.0 && AdjustedCR <= -2.0)
|
|
{
|
|
RewardXP += XP_LEVEL_3;
|
|
}
|
|
else if(AdjustedCR > -2.0 && AdjustedCR <= -1.0)
|
|
{
|
|
RewardXP += XP_LEVEL_2;
|
|
}
|
|
else if(AdjustedCR > -1.0 && AdjustedCR <= -0.5)
|
|
{
|
|
RewardXP += XP_LEVEL_1;
|
|
}
|
|
else if(AdjustedCR > -0.5 && AdjustedCR < 0.0)
|
|
{
|
|
// ::base XP. The Monster is of a challenging level.
|
|
}
|
|
}
|
|
return RewardXP;
|
|
}
|
|
}
|
|
|
|
|
|
void main()
|
|
{
|
|
object oKiller = GetLastKiller();
|
|
if(GetIsDM(oKiller))
|
|
{ return; }
|
|
int PCPartySize = 0;
|
|
int TotalLevel = 0;
|
|
int NumberOfNPCs = 0;
|
|
int HighestLevel = 0;
|
|
int LowestLevel = 0;
|
|
// ::Count PCs and NPCs in party as well as the PCs' levels.
|
|
object Member = GetFirstFactionMember(oKiller, FALSE);
|
|
while(GetIsObjectValid(Member))
|
|
{
|
|
if((GetDistanceBetween(DeadMonster, Member) <= MAX_DISTANCE_BETWEEN_PC_AND_MONSTER)
|
|
&& (GetArea(Member) == GetArea(DeadMonster)) && !GetIsDead(Member))
|
|
{
|
|
if(GetIsPC(Member))
|
|
{
|
|
PCPartySize++;
|
|
int level = SHA_GetECL(Member);
|
|
TotalLevel += level;
|
|
// Added below code to check high and low on HD instead of ECL
|
|
level = GetHitDice(Member);
|
|
if(level > HighestLevel)
|
|
{
|
|
HighestLevel = level;
|
|
}
|
|
if( level < LowestLevel || LowestLevel == 0 )
|
|
{
|
|
LowestLevel = level;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
NumberOfNPCs++;
|
|
}
|
|
}
|
|
Member = GetNextFactionMember(oKiller, FALSE);
|
|
}
|
|
// ::Killed by familar. PC not in range.
|
|
if(PCPartySize == 0)
|
|
{ return; }
|
|
float AvgPartyLevel = IntToFloat(TotalLevel)/IntToFloat(PCPartySize);
|
|
float LevelOfHighestMember = IntToFloat(HighestLevel);
|
|
float LevelOfLowestMember = IntToFloat(LowestLevel);
|
|
int GapExceeded = FALSE;
|
|
// Old if statemnt
|
|
// if( (AvgPartyLevel + MAXIMUM_LEVEL_GAP < LevelOfHighestMember) || (AvgPartyLevel - MAXIMUM_LEVEL_GAP > LevelOfLowestMember) )
|
|
// New if statement checks difference between low and high (on HD, not ECL) and determines gap
|
|
if( LevelOfHighestMember - LevelOfLowestMember > MAXIMUM_LEVEL_GAP )
|
|
{
|
|
AvgPartyLevel = LevelOfHighestMember;
|
|
GapExceeded = TRUE;
|
|
}
|
|
float fCR = GetChallengeRating(DeadMonster);
|
|
float XP = SHA_GetXP(fCR, AvgPartyLevel);
|
|
float XPModifier = SHA_CalculateXPModifier(PCPartySize, NumberOfNPCs);
|
|
|
|
float RewardXP = XP_SLIDER_VALUE*XP*XPModifier;
|
|
if(RewardXP <= 0.0)
|
|
{
|
|
// ::incase the user had set rediculous values...
|
|
RewardXP = 0.0;
|
|
}
|
|
Member = GetFirstFactionMember(oKiller, TRUE);
|
|
while(GetIsObjectValid(Member))
|
|
{
|
|
if((GetDistanceBetween(DeadMonster, Member) <= MAX_DISTANCE_BETWEEN_PC_AND_MONSTER)
|
|
&& (GetArea(Member) == GetArea(DeadMonster)) && !GetIsDead(Member))
|
|
{
|
|
if(GetIsPC(Member))
|
|
{
|
|
if(GapExceeded)
|
|
{
|
|
SendMessageToPC(Member, "No XP awarded: Some members of the party are outside the allowed 5 level difference.");
|
|
|
|
Member = GetNextFactionMember(oKiller, TRUE);
|
|
continue;
|
|
}
|
|
// ::check for any adjustment in Subrace's favored classes.
|
|
// changed to take the higher of the 2 decreases (ECL or Multi-Class range).
|
|
float iSubMod = GetSubraceXPModifier(Member);
|
|
float iECLMod = 1.0 - (0.1 * GetECL( Member ));
|
|
if( iECLMod < iSubMod )
|
|
{
|
|
iSubMod = iECLMod;
|
|
}
|
|
int iRewardXP = FloatToInt(RewardXP*iSubMod);
|
|
if(XP_DEBUG)
|
|
{
|
|
SendMessageToPC(Member, "Creature CR: " + FloatToString(fCR) + ". /n Party size: " + IntToString(PCPartySize) + "./n NPCs or Familiars: " + IntToString(NumberOfNPCs) + "./n Average Party Level: " + FloatToString(AvgPartyLevel) + (GapExceeded?"./n Has party Exceeded Max Level Gap":""));
|
|
}// Moved debug message up so we always get it.
|
|
GiveXPToCreature(Member, iRewardXP);
|
|
}
|
|
}
|
|
Member = GetNextFactionMember(oKiller, TRUE);
|
|
}
|
|
}
|
|
|
|
|