EN6_PRC8/_module/nss/no_lib_analysis.nss
Jaysyn904 a6f6db7303 Initial commit
Initial commit.  Updated release archive.
2024-06-13 15:08:33 -04:00

2901 lines
83 KiB
Plaintext

#include "no_inc_ptypes"
//functions
int GetAOEThreat( object oArea, object oEnt=OBJECT_SELF )
{
string sArea;
if ( GetIsObjectValid( oArea ) )
{
sArea = GetTag( oArea );
}
else
{
return 0;
}
if ( sArea == "VFX_PER_CREEPING_DOOM" )
{
return 1;
}
if ( sArea == "VFX_PER_DARKNESS" )
{
if ( GetHasSpellEffect( SPELL_TRUE_SEEING, oEnt ) || GetHasSpellEffect( SPELL_DARKVISION, oEnt ) )
{
return 0;
}
return 1;
}
if ( sArea == "VFX_PER_DELAYED_BLAST_FIREBALL" )
{
return 1;
}
if ( sArea == "VFX_PER_ENTANGLE" )
{
if ( GetIsEnemy( GetAreaOfEffectCreator( oArea ), oEnt ) )
{
return 1;
}
return 0;
}
if ( sArea == "VFX_PER_EVARDS_BLACK_TENTACLES" )
{
if ( GetIsEnemy( GetAreaOfEffectCreator( oArea ), oEnt ) )
{
return 1;
}
return 0;
}
if ( sArea == "VFX_PER_FOGACID" )
{
return 1;
}
if ( sArea == "VFX_PER_FOGFIRE" )
{
return 1;
}
if ( sArea == "VFX_PER_FOGKILL" )
{
return 1;
}
if ( sArea == "VFX_PER_FOGMIND" )
{
return 1;
}
if ( sArea == "VFX_PER_FOGSTINK" )
{
return 1;
}
if ( sArea == "VFX_PER_GREASE" )
{
return 1;
}
if ( sArea == "VFX_PER_STORM" )
{
return 1;
}
if ( sArea == "VFX_PER_WALLBLADE" )
{
return 1;
}
if ( sArea == "VFX_PER_WALLFIRE" )
{
return 1;
}
if ( sArea == "VFX_PER_WEB" )
{
return 1;
}
if ( sArea == "VFX_PER_FOGBEWILDERMENT" )
{
return 1;
}
if ( sArea == "VFX_PER_STONEHOLD" )
{
return 1;
}
return 0;
}
int GetAOECount( float fRad=10.0f, object oEnt=OBJECT_SELF )
{
int iLoop = 1;
int iCnt = 0;
object oArea;
oArea = GetNearestObject( OBJECT_TYPE_AREA_OF_EFFECT, oEnt, iLoop++ );
while ( GetIsObjectValid( oArea ) && GetDistanceBetween( oEnt, oArea ) <= fRad )
{
if ( GetAOEThreat( oArea ) )
{
iCnt++;
}
oArea = GetNearestObject( OBJECT_TYPE_AREA_OF_EFFECT, oEnt, iLoop++ );
}
return iCnt;
}
vector GetAOEVector( float fRad=10.0f, object oEnt=OBJECT_SELF )
{
int iLoop = 1;
vector vU = GetPosition( oEnt );
vector vT = Vector( 0.0, 0.0, 0.0 );
object oArea;
oArea = GetNearestObject( OBJECT_TYPE_AREA_OF_EFFECT, oEnt, iLoop++ );
while ( GetIsObjectValid( oArea ) && GetDistanceBetween( oEnt, oArea ) <= fRad )
{
if ( GetAOEThreat( oArea ) )
{
vT = vT + GetPosition( oArea ) - vU;
}
oArea = GetNearestObject( OBJECT_TYPE_AREA_OF_EFFECT, oEnt, iLoop++ );
}
return vT;
}
int GetHostileAOECount( float fRad=10.0f, object oEnt=OBJECT_SELF )
{
int iLoop = 1;
int iCnt = 0;
object oArea;
oArea = GetNearestObject( OBJECT_TYPE_AREA_OF_EFFECT, oEnt, iLoop++ );
while ( GetIsObjectValid( oArea ) && GetDistanceBetween( oEnt, oArea ) <= fRad )
{
if ( GetIsEnemy( GetAreaOfEffectCreator( oArea ) ) )
{
iCnt++;
}
oArea = GetNearestObject( OBJECT_TYPE_AREA_OF_EFFECT, oEnt, iLoop++ );
}
return iCnt;
}
vector GetHostileAOEVector( float fRad=10.0f, object oEnt=OBJECT_SELF )
{
int iLoop = 1;
vector vU = GetPosition( oEnt );
vector vT = Vector( 0.0, 0.0, 0.0 );
object oArea;
oArea = GetNearestObject( OBJECT_TYPE_AREA_OF_EFFECT, oEnt, iLoop++ );
while ( GetIsObjectValid( oArea ) && GetDistanceBetween( oEnt, oArea ) <= fRad )
{
if ( GetIsEnemy( GetAreaOfEffectCreator( oArea ) ) )
{
vT = vT + GetPosition( oArea ) - vU;
}
oArea = GetNearestObject( OBJECT_TYPE_AREA_OF_EFFECT, oEnt, iLoop++ );
}
return vT;
}
vector GetAOEEvacVector( vector vS, object oEnt=OBJECT_SELF )
{
vector vU = GetPosition( oEnt );
vector vT = Vector( 0.0, 0.0, 0.0 );
if ( vS != Vector( 0.0, 0.0, 0.0 ) )
{
if ( GetLocalLocation( oEnt, "LASTLOC" ) == GetLocation( oEnt ) )
{
//we've had location flag set, if matches we haven't moved
//probably stuck between wall and AOEs or paralyzed in AOEs
vT = vU + 15.0 * VectorNormalize( vS );
}
else
{
//proceed away from AOEs
vT = vU - 15.0 * VectorNormalize( vS );
}
}
else
{
//we know there was at least 1 area, must be on self
vT = vU + 15.0 * VectorNormalize( AngleToVector( IntToFloat( Random( 360 ) ) ) );
}
return vT;
}
object GetMostDamagedAlly( float fRad=15.0f, object oEnt=OBJECT_SELF, int iSee=FALSE )
{
//gives higher weighting to non-summoned allies
object oSubject = oEnt;
object oHurt = OBJECT_INVALID;
int iCnt = 1;
int iDamage = 0;
while ( GetIsObjectValid( oSubject ) && GetDistanceBetween( oEnt, oSubject ) < fRad )
{
if ( GetObjectSeen( oSubject, oEnt ) >= iSee )
{
iDamage = GetMaxHitPoints( oSubject ) - GetCurrentHitPoints( oSubject );
if ( iDamage )
{
if ( oHurt == OBJECT_INVALID )
{
oHurt = oSubject;
}
else if ( ( GetMaxHitPoints( oHurt ) - GetCurrentHitPoints( oHurt ) ) < iDamage )
{
if ( GetLocalInt( oHurt, "SUMMONED" ) || !GetLocalInt( oSubject, "SUMMONED" ) )
{
oHurt = oSubject;
}
}
}
}
oSubject = GetNearestCreature( CREATURE_TYPE_REPUTATION, REPUTATION_TYPE_FRIEND, oEnt, iCnt++ );
}
return oHurt;
}
object GetLowestHPAlly( float fRad=15.0, int iLim=0, object oEnt=OBJECT_SELF, int iSee=FALSE )
{
object oSub = oEnt;
object oHurt = OBJECT_INVALID;
int iCnt = 0;
int iHP = 0;
int iSubHP;
int iDam;
while ( GetIsObjectValid( oSub ) && GetDistanceBetween( oEnt, oSub ) < fRad )
{
iDam = GetMaxHitPoints( oSub ) - GetCurrentHitPoints( oSub );
if ( GetObjectSeen( oSub, oEnt ) >= iSee && iDam >= iLim )
{
iSubHP = GetCurrentHitPoints( oSub );
if ( !iHP || iSubHP < iHP )
{
//either we haven't got an oHurt yet, or we do and oSub is on less HP
iHP = iSubHP;
oHurt = oSub;
}
}
oSub = GetNearestCreature( CREATURE_TYPE_REPUTATION, REPUTATION_TYPE_FRIEND, oEnt, ++iCnt );
}
return oHurt;
}
object GetLowestHPAllyNoHealer( float fRad=15.0, int iLim=0, object oEnt=OBJECT_SELF, int iSee=FALSE, int iLive=TRUE )
{
object oSub = oEnt;
object oHurt = OBJECT_INVALID;
int iCnt = 0;
int iHP = 0;
int iSubHP;
int iDam;
int iU;
while ( GetIsObjectValid( oSub ) && GetDistanceBetween( oEnt, oSub ) < fRad )
{
iU = GetRacialType( oSub ) == RACIAL_TYPE_UNDEAD;
if ( ( iLive || iU ) && ( !iLive || !iU ) )
{
iDam = GetMaxHitPoints( oSub ) - GetCurrentHitPoints( oSub );
if ( !GetIsObjectValid( GetLocalObject( oSub, "#HEALER" ) ) && GetObjectSeen( oSub, oEnt ) >= iSee && iDam >= iLim )
{
iSubHP = GetCurrentHitPoints( oSub );
if ( !iHP || iSubHP < iHP )
{
//either we haven't got an oHurt yet, or we do and oSub is on less HP
iHP = iSubHP;
oHurt = oSub;
}
}
}
oSub = GetNearestCreature( CREATURE_TYPE_REPUTATION, REPUTATION_TYPE_FRIEND, oEnt, ++iCnt );
}
return oHurt;
}
object GetNearestDeadAlly( float fRad=15.0f, object oEnt=OBJECT_SELF, int iSee=FALSE )
{
int iCnt = 1;
object oDead = OBJECT_INVALID;
//object oSubject = GetNearestObject( OBJECT_TYPE_CREATURE, oEnt, iCnt++ );
object oSubject = GetNearestCreature( CREATURE_TYPE_REPUTATION, REPUTATION_TYPE_FRIEND, oEnt, iCnt++, CREATURE_TYPE_IS_ALIVE, FALSE );
while ( !GetIsObjectValid( oDead ) && GetIsObjectValid( oSubject ) && GetDistanceBetween( oEnt, oSubject ) <= fRad )
{
if ( GetObjectSeen( oSubject, oEnt ) >= iSee )
{
oDead = oSubject;
}
oSubject = GetNearestCreature( CREATURE_TYPE_REPUTATION, REPUTATION_TYPE_FRIEND, oEnt, iCnt++, CREATURE_TYPE_IS_ALIVE, FALSE );
}
return oDead;
}
object GetNearestDeadAllyNoRaiser( float fRad=15.0f, object oEnt=OBJECT_SELF, int iSee=FALSE )
{
int iCnt = 1;
object oDead = OBJECT_INVALID;
//object oSubject = GetNearestObject( OBJECT_TYPE_CREATURE, oEnt, iCnt++ );
object oSubject = GetNearestCreature( CREATURE_TYPE_REPUTATION, REPUTATION_TYPE_FRIEND, oEnt, iCnt++, CREATURE_TYPE_IS_ALIVE, FALSE );
while ( !GetIsObjectValid( oDead ) && GetIsObjectValid( oSubject ) && GetDistanceBetween( oEnt, oSubject ) <= fRad )
{
if ( GetObjectSeen( oSubject, oEnt ) >= iSee && !GetIsObjectValid( GetLocalObject( oSubject, "#RAISER" ) ) )
{
oDead = oSubject;
}
oSubject = GetNearestCreature( CREATURE_TYPE_REPUTATION, REPUTATION_TYPE_FRIEND, oEnt, iCnt++, CREATURE_TYPE_IS_ALIVE, FALSE );
}
return oDead;
}
object GetNearestPetrifiedAllyNoHelper( float fRad=15.0f, object oEnt=OBJECT_SELF, int iSee=FALSE )
{
int iCnt = 1;
int iEff;
object oPet = OBJECT_INVALID;
//object oSubject = GetNearestObject( OBJECT_TYPE_CREATURE, oEnt, iCnt++ );
object oSubject = GetNearestCreature( CREATURE_TYPE_REPUTATION, REPUTATION_TYPE_FRIEND, oEnt, iCnt++, CREATURE_TYPE_IS_ALIVE, TRUE );
while ( !GetIsObjectValid( oPet ) && GetIsObjectValid( oSubject ) && GetDistanceBetween( oEnt, oSubject ) <= fRad )
{
if ( GetObjectSeen( oSubject, oEnt ) >= iSee && !GetIsObjectValid( GetLocalObject( oSubject, "#FLESHER" ) ) )
{
if ( GetEffectsOnObject( oPet ) & 8192 ) //check for petrify effect
{
oPet = oSubject;
}
}
oSubject = GetNearestCreature( CREATURE_TYPE_REPUTATION, REPUTATION_TYPE_FRIEND, oEnt, iCnt++, CREATURE_TYPE_IS_ALIVE, TRUE );
}
return oPet;
}
int GetEffectsOnObject( object oEnt=OBJECT_SELF )
{
int iTally = 0;
int iType;
effect eSubj;
eSubj = GetFirstEffect( oEnt );
while ( GetIsEffectValid( eSubj ) )
{
if ( GetIsFriend( GetEffectCreator( eSubj ) ) )
{
//probably a side-effect or intentionally there, ignore it
}
else
{
iType = GetEffectType( eSubj );
if ( iType == EFFECT_TYPE_ABILITY_DECREASE ||
iType == EFFECT_TYPE_AC_DECREASE ||
iType == EFFECT_TYPE_ATTACK_DECREASE ||
iType == EFFECT_TYPE_DAMAGE_DECREASE ||
iType == EFFECT_TYPE_SPELL_RESISTANCE_DECREASE ||
iType == EFFECT_TYPE_SAVING_THROW_DECREASE )
{
iTally += NO_EFFECT_GENERIC;
}
else if ( iType == EFFECT_TYPE_DISEASE )
{
iTally += NO_EFFECT_DISEASE;
}
else if ( iType == EFFECT_TYPE_CURSE )
{
iTally += NO_EFFECT_CURSE;
}
else if ( iType == EFFECT_TYPE_POISON )
{
iTally += NO_EFFECT_POISON;
}
else if ( iType == EFFECT_TYPE_DEAF )
{
iTally += NO_EFFECT_DEAF;
}
else if ( iType == EFFECT_TYPE_BLINDNESS )
{
iTally += NO_EFFECT_BLINDNESS;
}
else if ( iType == EFFECT_TYPE_SILENCE )
{
iTally += NO_EFFECT_SILENCE;
}
else if ( iType == EFFECT_TYPE_NEGATIVELEVEL )
{
iTally += NO_EFFECT_NEGATIVELEVEL;
}
else if ( iType == EFFECT_TYPE_DAZED )
{
iTally += NO_EFFECT_DAZED;
}
else if ( iType == EFFECT_TYPE_FRIGHTENED )
{
iTally += NO_EFFECT_FRIGHTENED;
}
else if ( iType == EFFECT_TYPE_CONFUSED )
{
iTally += NO_EFFECT_CONFUSED;
}
else if ( iType == EFFECT_TYPE_CHARMED )
{
iTally += NO_EFFECT_CHARMED;
}
else if ( iType == EFFECT_TYPE_SLEEP )
{
iTally += NO_EFFECT_SLEEP;
}
else if ( iType == EFFECT_TYPE_STUNNED )
{
iTally += NO_EFFECT_STUNNED;
}
else if ( iType == EFFECT_TYPE_DOMINATED )
{
iTally += NO_EFFECT_DOMINATED;
}
else if ( iType == EFFECT_TYPE_PETRIFY )
{
iTally += NO_EFFECT_PETRIFY;
}
else if ( iType == EFFECT_TYPE_PARALYZE )
{
iTally += NO_EFFECT_PARALYZE;
}
}
eSubj = GetNextEffect( oEnt );
}
return iTally;
}
object GetMostHamperedAlly( float fRad=15.0f, object oEnt=OBJECT_SELF, int iSee=FALSE )
{
object oSubject = oEnt;
object oHurt = OBJECT_INVALID;
int iCnt = 1;
int iEff = 0;
while ( GetIsObjectValid( oSubject ) && GetDistanceBetween( oEnt, oSubject ) <= fRad )
{
//if ( GetObjectSeen( oSubject, oEnt ) >= iSee && !GetIsObjectValid( GetLocalObject( oHurt, "HELPER" ) ) )
if ( GetObjectSeen( oSubject, oEnt ) >= iSee && !GetIsObjectValid( GetLocalObject( oSubject, "HELPER" ) ) )
{
iEff = GetEffectsOnObject( oSubject );
if ( iEff )
{
if ( GetIsObjectValid( oHurt ) )
{
if ( GetEffectsOnObject( oHurt ) < iEff )
{
oHurt = oSubject;
}
}
else
{
oHurt = oSubject;
}
}
}
oSubject = GetNearestCreature( CREATURE_TYPE_REPUTATION, REPUTATION_TYPE_FRIEND, oEnt, iCnt++ );
}
return oHurt;
}
vector GetAreaTarget( int iS, float fRad, float fMinRad=7.5, float fMaxRad=30.0, int iEffChk=TRUE, object oCaster=OBJECT_SELF )
{
vector vU = GetPosition( oCaster );
vector vS = Vector( 0.0, 0.0, 0.0 );
vector vT = Vector( 0.0, 0.0, 0.0 );
object oSub1 = OBJECT_INVALID;
object oSub2 = OBJECT_INVALID;
int iCnt1 = 0;
int iCnt2 = 0;
int iCnt3 = 0;
int iBestCnt = 0;
float fMinSearchRad = fMinRad;
float fMaxSearchRad = fMaxRad;
oSub1 = GetNearestCreature( CREATURE_TYPE_REPUTATION, REPUTATION_TYPE_ENEMY, oCaster, ++iCnt1, CREATURE_TYPE_PERCEPTION, PERCEPTION_SEEN, CREATURE_TYPE_IS_ALIVE, TRUE );
//first pad out to fMinSearchRad
while ( GetIsObjectValid( oSub1 ) && GetDistanceBetween( oCaster, oSub1 ) <= fMinSearchRad )
{
oSub1 = GetNearestCreature( CREATURE_TYPE_REPUTATION, REPUTATION_TYPE_ENEMY, oCaster, ++iCnt1, CREATURE_TYPE_PERCEPTION, PERCEPTION_SEEN, CREATURE_TYPE_IS_ALIVE, TRUE );
}
//now scan from 7.5 out to 40.0
while ( GetIsObjectValid( oSub1 ) && GetDistanceBetween( oCaster, oSub1 ) <= fMaxSearchRad )
{
iCnt2 = 0;
iCnt3 = 0;
//don't count them as target if they're on the move
if ( GetCurrentAction( oSub1 ) != ACTION_MOVETOPOINT && ( !iEffChk || !GetHasSpellEffect( iS, oSub1 ) ) )
{
iCnt3 = 1; //starts at 1 to count oSub1
vT = GetPosition ( oSub1 ) - vU;
//oSub2 = GetNearestCreature( CREATURE_TYPE_REPUTATION, REPUTATION_TYPE_ENEMY, oSub1, ++iCnt2, CREATURE_TYPE_IS_ALIVE, TRUE );
oSub2 = GetNearestCreature( CREATURE_TYPE_REPUTATION, REPUTATION_TYPE_FRIEND, oSub1, ++iCnt2, CREATURE_TYPE_IS_ALIVE, TRUE );
//this should not pick up dead creatures
while ( GetIsObjectValid( oSub2 ) && GetDistanceBetween( oSub1, oSub2 ) <= fRad )
{
//SpeakString( "TH: " + GetName( oSub1 ) + " -> " + GetName( oSub2 ) );
//don't count them as target if they're on the move
if ( GetObjectSeen( oSub2, oCaster ) && GetCurrentAction( oSub2 ) != ACTION_MOVETOPOINT && ( !iEffChk || !GetHasSpellEffect( iS, oSub2 ) ) )
{
iCnt3++;
vT = vT + GetPosition( oSub2 ) - vU;
}
//oSub2 = GetNearestCreature( CREATURE_TYPE_REPUTATION, REPUTATION_TYPE_ENEMY, oSub1, ++iCnt2, CREATURE_TYPE_IS_ALIVE, TRUE );
oSub2 = GetNearestCreature( CREATURE_TYPE_REPUTATION, REPUTATION_TYPE_FRIEND, oSub1, ++iCnt2, CREATURE_TYPE_IS_ALIVE, TRUE );
}
}
if ( iCnt3 > iBestCnt )
{
vS = VectorNormalize( vT ) * ( VectorMagnitude( vT ) / IntToFloat( iCnt3 ) );
iBestCnt = iCnt3;
}
oSub1 = GetNearestCreature( CREATURE_TYPE_REPUTATION, REPUTATION_TYPE_ENEMY, oCaster, ++iCnt1, CREATURE_TYPE_PERCEPTION, PERCEPTION_SEEN, CREATURE_TYPE_IS_ALIVE, TRUE );
}
//vS should now be averaged central vector to densest concentration of enemies
//iBestCnt is count of enemies within radius of spell at this point
if ( iBestCnt > 1 )
//if ( iBestCnt )
{
return vS;
}
return Vector( 0.0, 0.0, 0.0 );
}
vector GetFriendlyAreaTarget( float fRad, int iSpell=0, int iType=0, object oCaster=OBJECT_SELF )
{
vector vU = GetPosition( oCaster );
vector vS = Vector( 0.0, 0.0, 0.0 );
vector vT = Vector( 0.0, 0.0, 0.0 );
object oSub1 = OBJECT_INVALID;
object oSub2 = OBJECT_INVALID;
int iCnt1 = 0;
int iCnt2 = 0;
int iCnt3 = 0;
int iBestCnt = 0;
float fMaxSearchRad = 30.0;
oSub1 = oCaster;
while ( GetIsObjectValid( oSub1 ) && GetDistanceBetween( oCaster, oSub1 ) <= fMaxSearchRad )
{
if ( ( !iType && !GetHasSpellEffect( iSpell, oSub1 ) ) || ( iType && !GetHasFeatEffect( iSpell, oSub1 ) ) )
{
iCnt2 = 0;
iCnt3 = 0;
//don't count them as target if they're on the move
//if ( GetCurrentAction( oSub1 ) != ACTION_MOVETOPOINT )
//temp for goblin test
if ( TRUE )
{
iCnt3 = 1; //starts at 1 to count oSub1
vT = GetPosition ( oSub1 ) - vU;
}
oSub2 = GetNearestCreature( CREATURE_TYPE_REPUTATION, REPUTATION_TYPE_FRIEND, oSub1, ++iCnt2, CREATURE_TYPE_IS_ALIVE, TRUE );
//this should not pick up dead creatures
while ( GetIsObjectValid( oSub2 ) && GetDistanceBetween( oSub1, oSub2 ) <= fRad )
{
//don't count them as target if they're on the move
//if ( GetObjectSeen( oSub2, oCaster ) && GetCurrentAction( oSub2 ) != ACTION_MOVETOPOINT )
if ( GetObjectSeen( oSub2, oCaster ) &&
( ( !iType && !GetHasSpellEffect( iSpell, oSub2 ) ) || ( iType && !GetHasFeatEffect( iSpell, oSub2 ) ) ) )
{
iCnt3++;
vT = vT + GetPosition( oSub2 ) - vU;
}
oSub2 = GetNearestCreature( CREATURE_TYPE_REPUTATION, REPUTATION_TYPE_FRIEND, oSub1, ++iCnt2, CREATURE_TYPE_IS_ALIVE, TRUE );
}
if ( iCnt3 > iBestCnt )
{
vS = vT / IntToFloat( iCnt3 );
iBestCnt = iCnt3;
}
}
oSub1 = GetNearestCreature( CREATURE_TYPE_REPUTATION, REPUTATION_TYPE_FRIEND, oCaster, ++iCnt1, CREATURE_TYPE_PERCEPTION, PERCEPTION_SEEN, CREATURE_TYPE_IS_ALIVE, TRUE );
}
//vS should now be averaged central vector to densest concentration of enemies
//iBestCnt is count of enemies within radius
//if ( iBestCnt > 1 )
if ( iBestCnt )
{
return vS;
}
return Vector( 0.0, 0.0, 0.0 );
}
int CanAct( object oSelf=OBJECT_SELF )
{
int iType;
effect eEff = GetFirstEffect( oSelf );
if ( GetIsDead( oSelf ) || GetLocalInt( OBJECT_SELF, "DRAGONFLIGHTDEL" ) )
{
return FALSE;
}
while ( GetIsEffectValid( eEff ) )
{
iType = GetEffectType( eEff );
if ( iType == EFFECT_TYPE_CONFUSED ||
iType == EFFECT_TYPE_DAZED ||
iType == EFFECT_TYPE_FRIGHTENED ||
iType == EFFECT_TYPE_PARALYZE ||
iType == EFFECT_TYPE_PETRIFY ||
iType == EFFECT_TYPE_SLEEP ||
iType == EFFECT_TYPE_STUNNED ||
iType == EFFECT_TYPE_TURNED ||
GetLocalInt( oSelf, "DRAGONFLIGHTDEL" ) == TRUE
)
{
return FALSE;
}
eEff = GetNextEffect( oSelf );
}
return TRUE;
}
int GetIsWeapon( object oWeapon )
{
int iType;
if ( GetIsObjectValid( oWeapon ) && ( iType = GetBaseItemType( oWeapon ) ) != BASE_ITEM_INVALID )
{
if (
iType == BASE_ITEM_BASTARDSWORD ||
iType == BASE_ITEM_BATTLEAXE ||
iType == BASE_ITEM_CLUB ||
iType == BASE_ITEM_DAGGER ||
iType == BASE_ITEM_DART ||
iType == BASE_ITEM_DIREMACE ||
iType == BASE_ITEM_DOUBLEAXE ||
iType == BASE_ITEM_GREATAXE ||
iType == BASE_ITEM_GREATSWORD ||
iType == BASE_ITEM_HALBERD ||
iType == BASE_ITEM_HANDAXE ||
iType == BASE_ITEM_HEAVYCROSSBOW ||
iType == BASE_ITEM_HEAVYFLAIL ||
iType == BASE_ITEM_KAMA ||
iType == BASE_ITEM_KATANA ||
iType == BASE_ITEM_KUKRI ||
iType == BASE_ITEM_LIGHTFLAIL ||
iType == BASE_ITEM_LIGHTHAMMER ||
iType == BASE_ITEM_LIGHTMACE ||
iType == BASE_ITEM_LONGBOW ||
iType == BASE_ITEM_LONGSWORD ||
iType == BASE_ITEM_MAGICSTAFF ||
iType == BASE_ITEM_MORNINGSTAR ||
iType == BASE_ITEM_QUARTERSTAFF ||
iType == BASE_ITEM_RAPIER ||
iType == BASE_ITEM_SCIMITAR ||
iType == BASE_ITEM_SCYTHE ||
iType == BASE_ITEM_SHORTBOW ||
iType == BASE_ITEM_SHORTSPEAR ||
iType == BASE_ITEM_SHORTSWORD ||
iType == BASE_ITEM_SHURIKEN ||
iType == BASE_ITEM_SICKLE ||
iType == BASE_ITEM_SLING ||
iType == BASE_ITEM_THROWINGAXE ||
iType == BASE_ITEM_TORCH ||
iType == BASE_ITEM_TWOBLADEDSWORD ||
iType == BASE_ITEM_WARHAMMER
)
{
return TRUE;
}
}
return FALSE;
}
int GetIsLightWeapon( object oWeapon, int iCanBeInvalid=FALSE )
{
int iType;
if ( GetIsObjectValid( oWeapon ) && ( iType = GetBaseItemType( oWeapon ) ) != BASE_ITEM_INVALID )
{
if (
//iType == BASE_ITEM_BASTARDSWORD ||
//iType == BASE_ITEM_BATTLEAXE ||
iType == BASE_ITEM_CLUB ||
iType == BASE_ITEM_DAGGER ||
//iType == BASE_ITEM_DART ||
//iType == BASE_ITEM_DIREMACE ||
//iType == BASE_ITEM_DOUBLEAXE ||
//iType == BASE_ITEM_GREATAXE ||
//iType == BASE_ITEM_GREATSWORD ||
//iType == BASE_ITEM_HALBERD ||
iType == BASE_ITEM_HANDAXE ||
//iType == BASE_ITEM_HEAVYCROSSBOW ||
//iType == BASE_ITEM_HEAVYFLAIL ||
iType == BASE_ITEM_KAMA ||
//iType == BASE_ITEM_KATANA ||
iType == BASE_ITEM_KUKRI ||
iType == BASE_ITEM_LIGHTFLAIL ||
iType == BASE_ITEM_LIGHTHAMMER ||
iType == BASE_ITEM_LIGHTMACE ||
//iType == BASE_ITEM_LONGBOW ||
//iType == BASE_ITEM_LONGSWORD ||
//iType == BASE_ITEM_MAGICSTAFF ||
//iType == BASE_ITEM_MORNINGSTAR ||
//iType == BASE_ITEM_QUARTERSTAFF ||
iType == BASE_ITEM_RAPIER ||
//iType == BASE_ITEM_SCIMITAR ||
//iType == BASE_ITEM_SCYTHE ||
//iType == BASE_ITEM_SHORTBOW ||
//iType == BASE_ITEM_SHORTSPEAR ||
iType == BASE_ITEM_SHORTSWORD ||
//iType == BASE_ITEM_SHURIKEN ||
iType == BASE_ITEM_SICKLE //||
//iType == BASE_ITEM_SLING ||
//iType == BASE_ITEM_THROWINGAXE ||
//iType == BASE_ITEM_TORCH ||
//iType == BASE_ITEM_TWOBLADEDSWORD ||
//iType == BASE_ITEM_WARHAMMER
)
{
return TRUE;
}
}
else if ( !GetIsObjectValid( oWeapon ) && iCanBeInvalid )
{
//special case for unarmed
return TRUE;
}
return FALSE;
}
int GetIsDoubleWeapon( object oWeapon )
{
int iType;
if ( GetIsObjectValid( oWeapon ) && ( iType = GetBaseItemType( oWeapon ) ) != BASE_ITEM_INVALID )
{
if (
//iType == BASE_ITEM_BASTARDSWORD ||
//iType == BASE_ITEM_BATTLEAXE ||
//iType == BASE_ITEM_CLUB ||
//iType == BASE_ITEM_DAGGER ||
//iType == BASE_ITEM_DART ||
iType == BASE_ITEM_DIREMACE ||
iType == BASE_ITEM_DOUBLEAXE ||
//iType == BASE_ITEM_GREATAXE ||
//iType == BASE_ITEM_GREATSWORD ||
//iType == BASE_ITEM_HALBERD ||
//iType == BASE_ITEM_HANDAXE ||
//iType == BASE_ITEM_HEAVYCROSSBOW ||
//iType == BASE_ITEM_HEAVYFLAIL ||
//iType == BASE_ITEM_KAMA ||
//iType == BASE_ITEM_KATANA ||
//iType == BASE_ITEM_KUKRI ||
//iType == BASE_ITEM_LIGHTFLAIL ||
//iType == BASE_ITEM_LIGHTHAMMER ||
//iType == BASE_ITEM_LIGHTMACE ||
//iType == BASE_ITEM_LONGBOW ||
//iType == BASE_ITEM_LONGSWORD ||
//iType == BASE_ITEM_MAGICSTAFF ||
//iType == BASE_ITEM_MORNINGSTAR ||
//iType == BASE_ITEM_QUARTERSTAFF ||
//iType == BASE_ITEM_RAPIER ||
//iType == BASE_ITEM_SCIMITAR ||
//iType == BASE_ITEM_SCYTHE ||
//iType == BASE_ITEM_SHORTBOW ||
//iType == BASE_ITEM_SHORTSPEAR ||
//iType == BASE_ITEM_SHORTSWORD ||
//iType == BASE_ITEM_SHURIKEN ||
//iType == BASE_ITEM_SICKLE ||
//iType == BASE_ITEM_SLING ||
//iType == BASE_ITEM_THROWINGAXE ||
//iType == BASE_ITEM_TORCH ||
iType == BASE_ITEM_TWOBLADEDSWORD //||
//iType == BASE_ITEM_WARHAMMER
)
{
return TRUE;
}
}
return FALSE;
}
int GetCasterCount( float fRad=5.0, object oEnt=OBJECT_SELF )
{
int iCnt = 1;
int iCast = 0;
object oSub = GetNearestCreature( CREATURE_TYPE_REPUTATION, REPUTATION_TYPE_ENEMY, oEnt, iCnt++, CREATURE_TYPE_PERCEPTION, PERCEPTION_SEEN );
while ( GetIsObjectValid( oSub ) )
{
if ( !GetIsDead( oSub ) && GetIsCaster( oSub ) )
{
iCast++;
}
oSub = GetNearestCreature( CREATURE_TYPE_REPUTATION, REPUTATION_TYPE_ENEMY, oEnt, iCnt++, CREATURE_TYPE_PERCEPTION, PERCEPTION_SEEN );
}
return iCast;
}
int GetAttackerCount( float fRad=5.0, object oEnt=OBJECT_SELF, object oS=OBJECT_SELF )
{
int iCnt = 1;
int iAtk = 0;
object oSub = GetNearestCreature( CREATURE_TYPE_REPUTATION, REPUTATION_TYPE_ENEMY, oEnt, iCnt++, CREATURE_TYPE_IS_ALIVE, TRUE );
while ( GetIsObjectValid( oSub ) && GetDistanceBetween( oEnt, oSub ) <= fRad )
{
if ( GetAttackTarget( oSub ) == oEnt )
{
if ( GetObjectSeen( oSub, oS ) || GetObjectHeard( oSub, oS ) )
{
iAtk++;
}
}
oSub = GetNearestCreature( CREATURE_TYPE_REPUTATION, REPUTATION_TYPE_ENEMY, oEnt, iCnt++, CREATURE_TYPE_IS_ALIVE, TRUE );
}
return iAtk;
}
int GetHostileCount( float fRad=5.0, object oEnt=OBJECT_SELF, object oS=OBJECT_SELF )
{
int iCnt = 1;
int iEnemy = 0;
object oSub = GetNearestCreature( CREATURE_TYPE_REPUTATION, REPUTATION_TYPE_ENEMY, oEnt, iCnt++, CREATURE_TYPE_IS_ALIVE, TRUE );
while ( GetIsObjectValid( oSub ) && GetDistanceBetween( oEnt, oSub ) <= fRad )
{
if ( GetObjectSeen( oSub, oS ) || GetObjectHeard( oSub, oS ) )
{
iEnemy++;
}
oSub = GetNearestCreature( CREATURE_TYPE_REPUTATION, REPUTATION_TYPE_ENEMY, oEnt, iCnt++, CREATURE_TYPE_IS_ALIVE, TRUE );
}
return iEnemy;
}
int GetOmniscientHostileCount( float fRad=5.0, object oEnt=OBJECT_SELF, object oS=OBJECT_SELF )
{
int iCnt = 1;
int iEnemy = 0;
object oSub = GetNearestCreature( CREATURE_TYPE_REPUTATION, REPUTATION_TYPE_ENEMY, oEnt, iCnt++, CREATURE_TYPE_IS_ALIVE, TRUE );
while ( GetIsObjectValid( oSub ) && GetDistanceBetween( oEnt, oSub ) <= fRad )
{
iEnemy++;
oSub = GetNearestCreature( CREATURE_TYPE_REPUTATION, REPUTATION_TYPE_ENEMY, oEnt, iCnt++, CREATURE_TYPE_IS_ALIVE, TRUE );
}
return iEnemy;
}
int GetAllyCount( float fRad=5.0, object oEnt=OBJECT_SELF, object oS=OBJECT_SELF )
{
int iCnt = 1;
int iAlly = 0;
object oSub = GetNearestCreature( CREATURE_TYPE_REPUTATION, REPUTATION_TYPE_FRIEND, oEnt, iCnt++, CREATURE_TYPE_IS_ALIVE, TRUE );
while ( GetIsObjectValid( oSub ) && GetDistanceBetween( oEnt, oSub ) <= fRad )
{
if ( GetObjectSeen( oSub, oS ) || GetObjectHeard( oSub, oS ) )
{
iAlly++;
}
oSub = GetNearestCreature( CREATURE_TYPE_REPUTATION, REPUTATION_TYPE_ENEMY, oEnt, iCnt++, CREATURE_TYPE_IS_ALIVE, TRUE );
}
return iAlly;
}
int GetAttackerHD( float fRad=5.0, object oEnt=OBJECT_SELF, object oS=OBJECT_SELF )
{
int iCnt = 1;
int iAtk = 0;
object oSub = GetNearestCreature( CREATURE_TYPE_REPUTATION, REPUTATION_TYPE_ENEMY, oEnt, iCnt++, CREATURE_TYPE_IS_ALIVE, TRUE );
while ( GetIsObjectValid( oSub ) && GetDistanceBetween( oEnt, oSub ) <= fRad )
{
if ( GetAttackTarget( oSub ) == oEnt )
{
if ( GetObjectSeen( oSub, oS ) || GetObjectHeard( oSub, oS ) )
{
iAtk += GetHitDice( oSub );
}
}
oSub = GetNearestCreature( CREATURE_TYPE_REPUTATION, REPUTATION_TYPE_ENEMY, oEnt, iCnt++, CREATURE_TYPE_IS_ALIVE, TRUE );
}
return iAtk;
}
int GetHostileHD( float fRad=5.0, object oEnt=OBJECT_SELF, object oS=OBJECT_SELF )
{
int iCnt = 1;
int iEnemy = 0;
object oSub = GetNearestCreature( CREATURE_TYPE_REPUTATION, REPUTATION_TYPE_ENEMY, oEnt, iCnt++, CREATURE_TYPE_IS_ALIVE, TRUE );
while ( GetIsObjectValid( oSub ) && GetDistanceBetween( oEnt, oSub ) <= fRad )
{
if ( GetObjectSeen( oSub, oS ) || GetObjectHeard( oSub, oS ) )
{
iEnemy += GetHitDice( oSub );
}
oSub = GetNearestCreature( CREATURE_TYPE_REPUTATION, REPUTATION_TYPE_ENEMY, oEnt, iCnt++, CREATURE_TYPE_IS_ALIVE, TRUE );
}
return iEnemy;
}
int GetAllyHD( float fRad=5.0, object oEnt=OBJECT_SELF, object oS=OBJECT_SELF )
{
int iCnt = 1;
int iAlly = 0;
object oSub = GetNearestCreature( CREATURE_TYPE_REPUTATION, REPUTATION_TYPE_FRIEND, oEnt, iCnt++, CREATURE_TYPE_IS_ALIVE, TRUE );
while ( GetIsObjectValid( oSub ) && GetDistanceBetween( oEnt, oSub ) <= fRad )
{
if ( GetObjectSeen( oSub, oS ) || GetObjectHeard( oSub, oS ) )
{
iAlly += GetHitDice( oSub );
}
oSub = GetNearestCreature( CREATURE_TYPE_REPUTATION, REPUTATION_TYPE_ENEMY, oEnt, iCnt++, CREATURE_TYPE_IS_ALIVE, TRUE );
}
return iAlly;
}
vector GetHostileVector( float fRad=10.0f, object oEnt=OBJECT_SELF )
{
int iCnt = 1;
int iNum = 0;
vector vU = GetPosition( oEnt );
vector vT = Vector( 0.0, 0.0, 0.0 );
object oSub;
oSub = GetNearestCreature( CREATURE_TYPE_REPUTATION, REPUTATION_TYPE_ENEMY, oEnt, iCnt++, CREATURE_TYPE_PERCEPTION, PERCEPTION_SEEN, CREATURE_TYPE_IS_ALIVE, TRUE );
while ( GetIsObjectValid( oSub ) && GetDistanceBetween( oEnt, oSub ) <= fRad )
{
iNum++;
vT = vT + GetPosition( oSub ) - vU;
oSub = GetNearestCreature( CREATURE_TYPE_REPUTATION, REPUTATION_TYPE_ENEMY, oEnt, iCnt++, CREATURE_TYPE_PERCEPTION, PERCEPTION_SEEN, CREATURE_TYPE_IS_ALIVE, TRUE );
}
if ( iNum )
{
vT = vT / IntToFloat( iNum );
}
return vT;
}
vector GetHostileEvacVector( vector vS, object oEnt=OBJECT_SELF )
{
vector vU = GetPosition( oEnt );
vector vT = Vector( 0.0, 0.0, 0.0 );
int iR = GetLocalInt( oEnt, "#LASTHSRETRIES" );
if ( VectorMagnitude( vS ) > 0.0 )
{
if ( GetLocalLocation( oEnt, "#LASTHOTSPOT" ) == GetLocation( oEnt ) )
{
if ( !iR )
{
iR++;
vT = 10.0 * VectorNormalize( AngleToVector( GetLocalFloat( oEnt, "#LASTAMANGLE" ) - 90.0 + 180.0 * IntToFloat( Random( 2 ) ) ) );
}
else
{
iR--;
}
}
else
{
vT = 10.0 * VectorNormalize( vS );
}
}
else
{
vT = 10.0 * VectorNormalize( AngleToVector( IntToFloat( Random( 360 ) ) ) );
}
if ( iR )
{
SetLocalInt( oEnt, "#LASTHSRETRIES", iR );
}
else
{
DeleteLocalInt( oEnt, "#LASTHSRETRIES" );
}
return vT;
}
int GetIsCaster( object oEnt=OBJECT_SELF )
{
int iCnt = 0;
if ( GetLevelByClass( CLASS_TYPE_BARD, oEnt ) ||
GetLevelByClass( CLASS_TYPE_CLERIC, oEnt ) ||
GetLevelByClass( CLASS_TYPE_DRUID, oEnt ) ||
GetLevelByClass( CLASS_TYPE_PALADIN, oEnt ) > 4 ||
GetLevelByClass( CLASS_TYPE_RANGER, oEnt ) > 4 ||
GetLevelByClass( CLASS_TYPE_SORCERER, oEnt ) ||
GetLevelByClass( CLASS_TYPE_WIZARD, oEnt ) ||
GetLocalInt( oEnt, "#CASTER" ) )
{
return TRUE;
}
return FALSE;
}
int DoAbilityCheck( int iAbil, int iDC, object oEnt=OBJECT_SELF )
{
if ( d20() + GetAbilityModifier( iAbil, oEnt ) >= iDC )
{
return TRUE;
}
return FALSE;
}
int DoCombatKnowledgeCheck( int iBAB=FALSE, int iDC=10, object oE=OBJECT_SELF )
{
int iM = iBAB == TRUE ? GetBaseAttackBonus( oE ) : GetAbilityModifier( ABILITY_INTELLIGENCE, oE );
if ( d20() + iM >= iDC )
{
return TRUE;
}
return FALSE;
}
float GetFriendFoeRatio( location lLoc, float fRad, object oEnt=OBJECT_SELF )
{
object oSub;
int iEnemies = 0;
int iFriends = 0;
oSub = GetFirstObjectInShape( SHAPE_SPHERE, fRad, lLoc );
while ( GetIsObjectValid( oSub ) )
{
if ( !GetIsDead( oSub ) )
{
if ( GetIsEnemy( oSub ) )
{
iEnemies++;
}
else if ( !GetIsReactionTypeFriendly( oSub, oEnt ) && !GetIsObjectValid( GetMaster( oSub ) ) )
{
iFriends++;
}
}
oSub = GetNextObjectInShape( SHAPE_SPHERE, fRad, lLoc );
}
if ( !iFriends )
{
//no friends in area, ensure that this will be considered a good choice
return 100.0;
}
return IntToFloat( iEnemies ) / iFriends;
}
float GetFriendFoeTolerance( object oEnt=OBJECT_SELF )
{
float fTol = 2.0;
int iGE = GetAlignmentGoodEvil( oEnt );
int iLC = GetAlignmentLawChaos( oEnt );
if ( iGE == ALIGNMENT_GOOD )
{
fTol *= 2.0;
}
else if ( iGE == ALIGNMENT_EVIL )
{
fTol *= 0.5;
}
if ( iLC == ALIGNMENT_LAWFUL )
{
fTol *= 2.0;
}
else if ( iLC == ALIGNMENT_CHAOTIC )
{
fTol *= 0.5;
}
return fTol;
}
object GetNearestEnemyCaster( int iMaxLvl=20, int iMinLvl=1, object oEnt=OBJECT_SELF )
{
int iCnt = 1;
object oC = GetNearestCreature( CREATURE_TYPE_REPUTATION, REPUTATION_TYPE_ENEMY, oEnt, iCnt++, CREATURE_TYPE_IS_ALIVE, TRUE );
while ( GetIsObjectValid( oC ) )
{
if ( GetIsCaster( oC ) )
{
break;
}
oC = GetNearestCreature( CREATURE_TYPE_REPUTATION, REPUTATION_TYPE_ENEMY, oEnt, iCnt++, CREATURE_TYPE_IS_ALIVE, TRUE );
}
return oC;
}
int GetAverageEnemyLevel( float fRad=60.0, object oEnt=OBJECT_SELF )
{
int iNum = 0;
int iHD = 0;
int iCnt = 1;
object oT = GetNearestCreature( CREATURE_TYPE_REPUTATION, REPUTATION_TYPE_ENEMY, oEnt, iCnt++, CREATURE_TYPE_PERCEPTION, PERCEPTION_SEEN, CREATURE_TYPE_IS_ALIVE, TRUE );
while ( GetIsObjectValid( oT ) && GetDistanceBetween( oEnt, oT ) <= fRad )
{
iHD += GetHitDice( oT );
iNum++;
oT = GetNearestCreature( CREATURE_TYPE_REPUTATION, REPUTATION_TYPE_ENEMY, oEnt, iCnt++, CREATURE_TYPE_PERCEPTION, PERCEPTION_SEEN, CREATURE_TYPE_IS_ALIVE, TRUE );
}
if ( iNum )
{
return iHD / iNum;
}
return 0;
}
int GetSafeAverageEnemyLevel( float fRad=40.0, object oEnt=OBJECT_SELF )
{
int iNum = 0;
int iHD = 0;
int iHDTotal = 0;
int iMin = 100;
int iMax = 0;
int iCnt = 0;
int iLvl = 0;
float fHD;
float fLower, fUpper;
float fAvg = 0.0;
float fStd = 0.0;
object oT = GetNearestCreature( CREATURE_TYPE_REPUTATION, REPUTATION_TYPE_ENEMY, oEnt, ++iCnt, CREATURE_TYPE_PERCEPTION, PERCEPTION_SEEN, CREATURE_TYPE_IS_ALIVE, TRUE );
//build list of enemy hit dice
while ( GetIsObjectValid( oT ) && GetDistanceBetween( oEnt, oT ) <= fRad )
{
iHD = GetHitDice( oT );
iHDTotal += iHD;
iNum++;
if ( iHD < iMin )
{
iMin = iHD;
}
if ( iHD > iMax )
{
iMax = iHD;
}
//record the value
SetLocalInt( OBJECT_SELF, "#SAELDATA_" + IntToString( iNum ), iHD );
oT = GetNearestCreature( CREATURE_TYPE_REPUTATION, REPUTATION_TYPE_ENEMY, oEnt, iCnt++, CREATURE_TYPE_PERCEPTION, PERCEPTION_SEEN, CREATURE_TYPE_IS_ALIVE, TRUE );
}
if ( iNum < 1 )
{
//if we didn't count any enemies bail out here
iLvl = 0;
}
else
{
fAvg = IntToFloat( iHDTotal ) / iNum;
iLvl = FloatToInt( fAvg );
//check to see if pruning is necessary
if ( iMax - iMin > 5 )
{
//wide range, may need some pruning
//get std dev
iCnt = 0;
iHD = GetLocalInt( OBJECT_SELF, "#SAELDATA_" + IntToString( ++iCnt ) );
while ( iHD )
{
fStd += pow( IntToFloat( iHD ) - fAvg, 2.0 );
iHD = GetLocalInt( OBJECT_SELF, "#SAELDATA_" + IntToString( ++iCnt ) );
}
fStd = sqrt( fStd / iNum );
fLower = fAvg - fStd;
fUpper = fAvg + fStd;
iHDTotal = 0;
iCnt = 0;
iNum = 0;
iHD = GetLocalInt( OBJECT_SELF, "#SAELDATA_" + IntToString( ++iCnt ) );
while ( iHD )
{
fHD = IntToFloat( iHD );
if ( fHD > fLower && fHD <= fUpper )
{
iNum++;
iHDTotal += iHD;
}
iHD = GetLocalInt( OBJECT_SELF, "#SAELDATA_" + IntToString( ++iCnt ) );
}
if ( !iNum )
{
iLvl = iMax;
}
else
{
fAvg = IntToFloat( iHDTotal ) / iNum;
iLvl = FloatToInt( fAvg );
}
}
}
//clean up local vars
iCnt = 0;
while ( GetLocalInt( OBJECT_SELF, "#SAELDATA_" + IntToString( ++iCnt ) ) )
{
DeleteLocalInt( OBJECT_SELF, "#SAELDATA_" + IntToString( iCnt ) );
}
if ( iLvl == 0 )
{
return iMax;
}
return iLvl;
}
object GetLeastMagicDefendedEnemy( float fRad=5.0, object oEnt=OBJECT_SELF )
{
struct sSpellDefStatus strMDef;
object oS;
object oC;
int iCnt = 0;
int iDef = 100000;
oC = OBJECT_INVALID;
oS = GetNearestCreature( CREATURE_TYPE_REPUTATION, REPUTATION_TYPE_ENEMY, oEnt, ++iCnt, CREATURE_TYPE_PERCEPTION, PERCEPTION_SEEN, CREATURE_TYPE_IS_ALIVE, TRUE );
while ( GetIsObjectValid( oS ) )
{
strMDef = EvaluateSpellDefenses( oS );
if ( strMDef.iTotal < iDef )
{
oC = oS;
iDef = strMDef.iTotal;
}
oS = GetNearestCreature( CREATURE_TYPE_REPUTATION, REPUTATION_TYPE_ENEMY, oEnt, ++iCnt, CREATURE_TYPE_PERCEPTION, PERCEPTION_SEEN, CREATURE_TYPE_IS_ALIVE, TRUE );
}
return oC;
}
vector GetTurningVector( object oEnt=OBJECT_SELF )
{
int iCnt1, iCnt2, iCnt3, iBestCnt;
float fRad = 20.0;
vector vT = Vector( 0.0, 0.0, 0.0 );
vector vS = Vector( 0.0, 0.0, 0.0 );
vector vU = GetPosition( oEnt );
object oT1, oT2;
int iTurnLvl = GetTurningLevel( oEnt );
iCnt1 = 0;
iBestCnt = 0;
oT1 = GetNearestCreature( CREATURE_TYPE_REPUTATION, REPUTATION_TYPE_ENEMY, oEnt, ++iCnt1, CREATURE_TYPE_PERCEPTION, PERCEPTION_SEEN, CREATURE_TYPE_IS_ALIVE, TRUE );
//PrintString( "TU: " + GetName( oT1 ) );
while ( GetIsObjectValid( oT1 ) && GetDistanceBetween( oEnt, oT1 ) <= 40.0f )
{
iCnt2 = 0;
iCnt3 = 0;
if ( GetIsValidTurnTarget( oT1, iTurnLvl ) )
{
//PrintString( "TUV: " + GetName( oT1 ) );
if ( GetHasFeatEffect( FEAT_TURN_UNDEAD, oT1 ) == FALSE && GetCurrentAction( oT1 ) != ACTION_MOVETOPOINT )
{
iCnt3 = 1; //starts at 1 to count oSub1
vT = GetPosition ( oT1 ) - vU;
}
//oT2 = GetNearestCreature( CREATURE_TYPE_REPUTATION, REPUTATION_TYPE_ENEMY, oT1, ++iCnt2, CREATURE_TYPE_PERCEPTION, PERCEPTION_SEEN, CREATURE_TYPE_IS_ALIVE, TRUE );
oT2 = GetNearestCreature( CREATURE_TYPE_REPUTATION, REPUTATION_TYPE_FRIEND, oT1, ++iCnt2, CREATURE_TYPE_PERCEPTION, PERCEPTION_SEEN, CREATURE_TYPE_IS_ALIVE, TRUE );
//this should not pick up dead creatures
while ( GetIsObjectValid( oT2 ) && GetDistanceBetween( oT1, oT2 ) <= fRad )
{
//don't count them as target if they're on the move
if ( GetHasFeatEffect( FEAT_TURN_UNDEAD, oT2 ) == FALSE && GetCurrentAction( oT2 ) != ACTION_MOVETOPOINT )
{
if ( GetIsValidTurnTarget( oT2, iTurnLvl ) )
{
iCnt3++;
vT = vT + GetPosition( oT2 ) - vU;
}
}
//oT2 = GetNearestCreature( CREATURE_TYPE_REPUTATION, REPUTATION_TYPE_ENEMY, oT1, ++iCnt2, CREATURE_TYPE_PERCEPTION, PERCEPTION_SEEN, CREATURE_TYPE_IS_ALIVE, TRUE );
oT2 = GetNearestCreature( CREATURE_TYPE_REPUTATION, REPUTATION_TYPE_FRIEND, oT1, ++iCnt2, CREATURE_TYPE_PERCEPTION, PERCEPTION_SEEN, CREATURE_TYPE_IS_ALIVE, TRUE );
}
if ( iCnt3 > iBestCnt )
{
vS = vT / IntToFloat( iCnt3 );
iBestCnt = iCnt3;
}
}
oT1 = GetNearestCreature( CREATURE_TYPE_REPUTATION, REPUTATION_TYPE_ENEMY, oEnt, ++iCnt1, CREATURE_TYPE_PERCEPTION, PERCEPTION_SEEN, CREATURE_TYPE_IS_ALIVE, TRUE );
}
if ( iBestCnt )
{
return vS;
}
return Vector( 0.0, 0.0, 0.0 );
}
int GetIsValidTurnTarget( object oT, int iL=0, object oEnt=OBJECT_SELF )
{
int iElemental;
int iVermin;
int iConstructs;
int iOutsider;
int iRace;
int iTurn = 0;
//compare hit dice of this target to my turning level, if hd > turning level +4 we can't turn it, abort
if ( GetHitDice( oT ) > iL + 4 )
{
return 0;
}
iElemental = GetHasFeat( FEAT_AIR_DOMAIN_POWER ) + GetHasFeat( FEAT_EARTH_DOMAIN_POWER ) + GetHasFeat( FEAT_FIRE_DOMAIN_POWER ) + GetHasFeat( FEAT_WATER_DOMAIN_POWER );
iVermin = GetHasFeat( FEAT_PLANT_DOMAIN_POWER ) + GetHasFeat( FEAT_ANIMAL_COMPANION );
iConstructs = GetHasFeat( FEAT_DESTRUCTION_DOMAIN_POWER );
iOutsider = GetHasFeat( FEAT_GOOD_DOMAIN_POWER ) + GetHasFeat( FEAT_EVIL_DOMAIN_POWER );
iRace = GetRacialType( oT );
if ( iRace == RACIAL_TYPE_UNDEAD )
{
iTurn = 1;
}
else if ( iRace == RACIAL_TYPE_ELEMENTAL && iElemental )
{
iTurn = 1;
}
else if ( iRace == RACIAL_TYPE_VERMIN && iVermin )
{
iTurn = 1;
}
else if ( iRace == RACIAL_TYPE_CONSTRUCT && iConstructs)
{
iTurn = 1;
}
else if ( iRace == RACIAL_TYPE_OUTSIDER && iOutsider )
{
iTurn = 1;
}
return iTurn;
}
int GetPotionHealAmount( object oP )
{
int iHeal = 0;
string sP = GetResRef( oP );
if ( sP == "nw_it_mpotion002" )
{
//cure light wounds
iHeal = 10;
}
else if ( sP == "nw_it_mpotion021" )
{
//cure moderate wounds
iHeal = 20;
}
else if ( sP == "nw_it_mpotion003" )
{
//cure serious wounds
iHeal = 30;
}
else if ( sP == "nw_it_mpotion004" )
{
//cure critical wounds
iHeal = 40;
}
else if ( sP == "nw_it_mpotion013" )
{
//heal
iHeal = 60;
}
return iHeal;
}
int GetTalentPotionHealAmount( talent tP )
{
int iHeal = 0;
int iP = GetIdFromTalent( tP );
if ( iP == 32 )
{
//cure light wounds
iHeal = 10;
}
else if ( iP == 34 )
{
//cure moderate wounds
iHeal = 20;
}
else if ( iP == 35 )
{
//cure serious wounds
iHeal = 30;
}
else if ( iP == 31 )
{
//cure critical wounds
iHeal = 40;
}
else if ( iP == 79 )
{
//heal
iHeal = 60;
}
return iHeal;
}
/*
====================
GetAreaHealTarget:
Looks for a suitable group of allies to cast a particular group healing spell on.
====================
*/
vector GetAreaHealTarget( float fRad=0.0, int iH=0, object oEnt=OBJECT_SELF )
{
int iCnt1, iCnt2, iCnt3, iBestCnt, iDam;
vector vT = Vector( 0.0, 0.0, 0.0 );
vector vS = Vector( 0.0, 0.0, 0.0 );
vector vU = GetPosition( oEnt );
object oT1, oT2;
float fMaxSearchRad = 30.0;
iCnt1 = 0;
iBestCnt = 0;
oT1 = GetNearestCreature( CREATURE_TYPE_REPUTATION, REPUTATION_TYPE_FRIEND, oEnt, ++iCnt1, CREATURE_TYPE_PERCEPTION, PERCEPTION_SEEN, CREATURE_TYPE_IS_ALIVE, TRUE );
while ( GetIsObjectValid( oT1 ) && GetDistanceBetween( oEnt, oT1 ) <= fMaxSearchRad )
{
iCnt2 = 0;
iCnt3 = 0;
iDam = GetMaxHitPoints( oT1 ) - GetCurrentHitPoints( oT1 );
if ( iDam >= iH )
{
if ( GetCurrentAction( oT1 ) != ACTION_MOVETOPOINT )
{
iCnt3 = 1; //starts at 1 to count oSub1
vT = GetPosition ( oT1 ) - vU;
}
oT2 = GetNearestCreature( CREATURE_TYPE_REPUTATION, REPUTATION_TYPE_FRIEND, oT1, ++iCnt2, CREATURE_TYPE_PERCEPTION, PERCEPTION_SEEN, CREATURE_TYPE_IS_ALIVE, TRUE );
//this should not pick up dead creatures
while ( GetIsObjectValid( oT2 ) && GetDistanceBetween( oT1, oT2 ) <= fRad )
{
//don't count them as target if they're on the move
if ( GetCurrentAction( oT2 ) != ACTION_MOVETOPOINT )
{
iDam = GetMaxHitPoints( oT2 ) - GetCurrentHitPoints( oT2 );
if ( iDam <= iH )
{
iCnt3++;
vT = vT + GetPosition( oT2 ) - vU;
}
}
oT2 = GetNearestCreature( CREATURE_TYPE_REPUTATION, REPUTATION_TYPE_FRIEND, oT1, ++iCnt2, CREATURE_TYPE_PERCEPTION, PERCEPTION_SEEN, CREATURE_TYPE_IS_ALIVE, TRUE );
}
if ( iCnt3 > iBestCnt )
{
vS = vT / IntToFloat( iCnt3 );
iBestCnt = iCnt3;
}
}
oT1 = GetNearestCreature( CREATURE_TYPE_REPUTATION, REPUTATION_TYPE_FRIEND, oEnt, ++iCnt1, CREATURE_TYPE_PERCEPTION, PERCEPTION_SEEN, CREATURE_TYPE_IS_ALIVE, TRUE );
}
if ( iBestCnt )
{
return vS;
}
return Vector( 0.0, 0.0, 0.0 );
}
float GetAllyDamageStats( location lT, float fRad=0.0, object oEnt=OBJECT_SELF )
{
int iCnt = 0;
int iDam = 0;
float fDam = 0.0;
object oS = GetNearestObjectToLocation( OBJECT_TYPE_CREATURE, lT, ++iCnt );
while ( GetIsObjectValid( oS ) && GetDistanceBetween( oEnt, oS ) < fRad )
{
iDam += GetMaxHitPoints( oS ) - GetCurrentHitPoints( oS );
oS = GetNearestObjectToLocation( OBJECT_TYPE_CREATURE, lT, ++iCnt );
}
iCnt--;
if ( iCnt )
{
fDam = IntToFloat( iDam ) / IntToFloat( iCnt );
}
return fDam;
}
object GetMostBuffedEnemy( float fRad=10.0, object oEnt=OBJECT_SELF )
{
int iBuffs;
int iMax = 0;
int iCnt = 0;
object oT;
object oM = OBJECT_INVALID;
effect eT;
oT = GetNearestCreature( CREATURE_TYPE_REPUTATION, REPUTATION_TYPE_ENEMY, oEnt, ++iCnt, CREATURE_TYPE_PERCEPTION, PERCEPTION_SEEN, CREATURE_TYPE_IS_ALIVE, TRUE );
while ( GetIsObjectValid( oT ) && GetDistanceBetween( OBJECT_SELF, oT ) < fRad )
{
iBuffs = 0;
eT = GetFirstEffect( oT );
while ( GetIsEffectValid( eT ) )
{
//try this to narrow down to actual "buffs"
if ( GetEffectSubType( eT ) == SUBTYPE_MAGICAL && GetEffectDurationType( eT ) == DURATION_TYPE_TEMPORARY )
{
iBuffs += GetIsBuffEffect( eT );
}
eT = GetNextEffect( oT );
}
iBuffs += GetIsObjectValid( GetAssociate( ASSOCIATE_TYPE_SUMMONED, oT ) );
iBuffs += GetIsObjectValid( GetAssociate( ASSOCIATE_TYPE_DOMINATED, oT ) );
iBuffs += GetIsObjectValid( GetAssociate( ASSOCIATE_TYPE_FAMILIAR, oT ) );
iBuffs += GetIsObjectValid( GetAssociate( ASSOCIATE_TYPE_ANIMALCOMPANION, oT ) );
if ( iBuffs > iMax )
{
iMax = iBuffs;
oM = oT;
}
oT = GetNearestCreature( CREATURE_TYPE_REPUTATION, REPUTATION_TYPE_ENEMY, oEnt, ++iCnt, CREATURE_TYPE_PERCEPTION, PERCEPTION_SEEN, CREATURE_TYPE_IS_ALIVE, TRUE );
}
return oM;
}
object GetLeastBuffedAlly( float fRad=10.0, int iMelee=FALSE, object oEnt=OBJECT_SELF )
{
int iBuffs;
int iMin = 100;
int iCnt = 0;
object oT;
object oM = OBJECT_INVALID;
effect eT;
oT = oEnt; //start with self
while ( GetIsObjectValid( oT ) && GetDistanceBetween( OBJECT_SELF, oT ) < fRad )
{
if ( !GetIsObjectValid( GetMaster( oT ) ) )
{
//don't consider associates
if ( iMelee && ( GetDistanceBetween( oEnt, oT ) < 7.5 || !GetHostileCount( 5.0, oT ) ) )
{
//don't buff those in the thick of melee
iBuffs = 0;
eT = GetFirstEffect( oT );
while ( GetIsEffectValid( eT ) )
{
//try this to narrow down to actual "buffs"
if ( GetEffectSubType( eT ) == SUBTYPE_MAGICAL && GetEffectDurationType( eT ) == DURATION_TYPE_TEMPORARY )
{
iBuffs += GetIsBuffEffect( eT );
}
eT = GetNextEffect( oT );
}
iBuffs += GetIsObjectValid( GetAssociate( ASSOCIATE_TYPE_SUMMONED, oT ) );
iBuffs += GetIsObjectValid( GetAssociate( ASSOCIATE_TYPE_DOMINATED, oT ) );
iBuffs += GetIsObjectValid( GetAssociate( ASSOCIATE_TYPE_FAMILIAR, oT ) );
iBuffs += GetIsObjectValid( GetAssociate( ASSOCIATE_TYPE_ANIMALCOMPANION, oT ) );
if ( iBuffs < iMin )
{
iMin = iBuffs;
oM = oT;
}
}
}
oT = GetNearestCreature( CREATURE_TYPE_REPUTATION, REPUTATION_TYPE_FRIEND, oEnt, ++iCnt, CREATURE_TYPE_PERCEPTION, PERCEPTION_SEEN, CREATURE_TYPE_IS_ALIVE, TRUE );
}
return oM;
}
int GetIsBuffEffect( effect eT )
{
if ( GetEffectSpellId( eT ) == -1 )
{
return FALSE;
}
if ( GetEffectSpellId( eT ) == SPELL_GREATER_SPELL_MANTLE )
{
return TRUE;
}
if ( GetEffectSpellId( eT ) == SPELL_PREMONITION )
{
return TRUE;
}
if ( GetEffectSpellId( eT ) == SPELL_MIND_BLANK )
{
return TRUE;
}
if ( GetEffectSpellId( eT ) == SPELL_SPELL_MANTLE )
{
return TRUE;
}
if ( GetEffectSpellId( eT ) == SPELL_SHADOW_SHIELD )
{
return TRUE;
}
if ( GetEffectSpellId( eT ) == SPELL_PROTECTION_FROM_SPELLS )
{
return TRUE;
}
if ( GetEffectSpellId( eT ) == SPELL_TRUE_SEEING )
{
return TRUE;
}
if ( GetEffectSpellId( eT ) == SPELL_TENSERS_TRANSFORMATION )
{
return TRUE;
}
if ( GetEffectSpellId( eT ) == SPELL_MASS_HASTE )
{
return TRUE;
}
if ( GetEffectSpellId( eT ) == SPELL_GREATER_STONESKIN )
{
return TRUE;
}
if ( GetEffectSpellId( eT ) == SPELL_GLOBE_OF_INVULNERABILITY )
{
return TRUE;
}
if ( GetEffectSpellId( eT ) == SPELL_ETHEREAL_VISAGE )
{
return TRUE;
}
if ( GetEffectSpellId( eT ) == SPELL_LESSER_SPELL_MANTLE )
{
return TRUE;
}
if ( GetEffectSpellId( eT ) == SPELL_LESSER_MIND_BLANK )
{
return TRUE;
}
if ( GetEffectSpellId( eT ) == SPELL_ENERGY_BUFFER )
{
return TRUE;
}
if ( GetEffectSpellId( eT ) == SPELL_ELEMENTAL_SHIELD )
{
return TRUE;
}
if ( GetEffectSpellId( eT ) == SPELL_STONESKIN )
{
return TRUE;
}
if ( GetEffectSpellId( eT ) == SPELL_POLYMORPH_SELF )
{
return TRUE;
}
if ( GetEffectSpellId( eT ) == SPELL_MINOR_GLOBE_OF_INVULNERABILITY )
{
return TRUE;
}
if ( GetEffectSpellId( eT ) == SPELL_IMPROVED_INVISIBILITY )
{
return TRUE;
}
if ( GetEffectSpellId( eT ) == SPELL_PROTECTION_FROM_ELEMENTS )
{
return TRUE;
}
if ( GetEffectSpellId( eT ) == SPELL_MAGIC_CIRCLE_AGAINST_GOOD )
{
return TRUE;
}
if ( GetEffectSpellId( eT ) == SPELL_MAGIC_CIRCLE_AGAINST_EVIL )
{
return TRUE;
}
if ( GetEffectSpellId( eT ) == SPELL_MAGIC_CIRCLE_AGAINST_CHAOS )
{
return TRUE;
}
if ( GetEffectSpellId( eT ) == SPELL_MAGIC_CIRCLE_AGAINST_LAW )
{
return TRUE;
}
if ( GetEffectSpellId( eT ) == SPELL_INVISIBILITY_SPHERE )
{
return TRUE;
}
if ( GetEffectSpellId( eT ) == SPELL_HASTE )
{
return TRUE;
}
if ( GetEffectSpellId( eT ) == SPELL_CLARITY )
{
return TRUE;
}
if ( GetEffectSpellId( eT ) == SPELL_CLAIRAUDIENCE_AND_CLAIRVOYANCE )
{
return TRUE;
}
if ( GetEffectSpellId( eT ) == SPELL_SEE_INVISIBILITY )
{
return TRUE;
}
if ( GetEffectSpellId( eT ) == SPELL_RESIST_ELEMENTS )
{
return TRUE;
}
if ( GetEffectSpellId( eT ) == SPELL_OWLS_WISDOM )
{
return TRUE;
}
if ( GetEffectSpellId( eT ) == SPELL_INVISIBILITY )
{
return TRUE;
}
if ( GetEffectSpellId( eT ) == SPELL_GHOSTLY_VISAGE )
{
return TRUE;
}
if ( GetEffectSpellId( eT ) == SPELL_FOXS_CUNNING )
{
return TRUE;
}
if ( GetEffectSpellId( eT ) == SPELL_ENDURANCE )
{
return TRUE;
}
if ( GetEffectSpellId( eT ) == SPELL_EAGLE_SPLEDOR )
{
return TRUE;
}
if ( GetEffectSpellId( eT ) == SPELL_DARKVISION )
{
return TRUE;
}
if ( GetEffectSpellId( eT ) == SPELL_CATS_GRACE )
{
return TRUE;
}
if ( GetEffectSpellId( eT ) == SPELL_BULLS_STRENGTH )
{
return TRUE;
}
if ( GetEffectSpellId( eT ) == SPELL_PROTECTION_FROM_GOOD )
{
return TRUE;
}
if ( GetEffectSpellId( eT ) == SPELL_PROTECTION_FROM_EVIL )
{
return TRUE;
}
if ( GetEffectSpellId( eT ) == SPELL_PROTECTION__FROM_CHAOS )
{
return TRUE;
}
if ( GetEffectSpellId( eT ) == SPELL_PROTECTION_FROM_LAW )
{
return TRUE;
}
if ( GetEffectSpellId( eT ) == SPELL_MAGE_ARMOR )
{
return TRUE;
}
if ( GetEffectSpellId( eT ) == SPELL_FREEDOM_OF_MOVEMENT )
{
return TRUE;
}
if ( GetEffectSpellId( eT ) == SPELL_DEATH_WARD )
{
return TRUE;
}
if ( GetEffectSpellId( eT ) == SPELL_PRAYER )
{
return TRUE;
}
if ( GetEffectSpellId( eT ) == SPELL_AID )
{
return TRUE;
}
if ( GetEffectSpellId( eT ) == SPELL_VIRTUE )
{
return TRUE;
}
if ( GetEffectSpellId( eT ) == SPELL_BLESS )
{
return TRUE;
}
if ( GetEffectSpellId( eT ) == SPELL_SHAPECHANGE )
{
return TRUE;
}
if ( GetEffectSpellId( eT ) == SPELL_NATURES_BALANCE )
{
return TRUE;
}
if ( GetEffectSpellId( eT ) == SPELL_AURA_OF_VITALITY )
{
return TRUE;
}
if ( GetEffectSpellId( eT ) == SPELL_REGENERATE )
{
return TRUE;
}
if ( GetEffectSpellId( eT ) == SPELL_SPELL_RESISTANCE )
{
return TRUE;
}
if ( GetEffectSpellId( eT ) == SPELL_AWAKEN )
{
return TRUE;
}
if ( GetEffectSpellId( eT ) == SPELL_BARKSKIN )
{
return TRUE;
}
if ( GetEffectSpellId( eT ) == SPELL_RESISTANCE )
{
return TRUE;
}
if ( GetEffectSpellId( eT ) == SPELL_HOLY_AURA )
{
return TRUE;
}
if ( GetEffectSpellId( eT ) == SPELL_UNHOLY_AURA )
{
return TRUE;
}
if ( GetEffectSpellId( eT ) == SPELL_DIVINE_POWER )
{
return TRUE;
}
if ( GetEffectSpellId( eT ) == SPELL_NEGATIVE_ENERGY_PROTECTION )
{
return TRUE;
}
if ( GetEffectSpellId( eT ) == SPELL_SANCTUARY )
{
return TRUE;
}
if ( GetEffectSpellId( eT ) == SPELL_REMOVE_FEAR )
{
return TRUE;
}
if ( GetEffectSpellId( eT ) == SPELL_WAR_CRY )
{
return TRUE;
}
return FALSE;
}
int GetAverageEffectCasterLevel( object oT=OBJECT_SELF )
{
int iT = 0;
int iC = 0;
int iL = 0;
object oE;
object oB = OBJECT_INVALID;
effect eT = GetFirstEffect( oT );
while ( GetIsEffectValid( eT ) )
{
//try this to narrow down to actual "buffs"
if ( GetEffectSubType( eT ) == SUBTYPE_MAGICAL && GetEffectDurationType( eT ) == DURATION_TYPE_TEMPORARY )
{
if ( GetIsBuffEffect( eT ) )
{
iC += 1;
//try this to reduce redundant checking
oE = GetEffectCreator( eT );
if ( GetIsObjectValid( oE ) )
{
if ( oE != oB )
{
//new caster
iL = GetMaxDispelCasterLevel( oE );
oB = oE;
}
iT += iL;
iC += 1;
}
else
{
//something has happened to effect creator, assume the worst
iT += 20;
iC += 1;
}
}
}
eT = GetNextEffect( oT );
}
if ( iC )
{
return iT / iC;
}
return 0;
}
object GetStrongestEnemySummonedAssociateOwner( float fRad=10.0, object oEnt=OBJECT_SELF )
{
object oT, oC, oD, oM;
int iCnt = 0;
int iHD = 0;
int iT;
oM = OBJECT_INVALID;
oT = GetNearestCreature( CREATURE_TYPE_REPUTATION, REPUTATION_TYPE_ENEMY, oEnt, ++iCnt, CREATURE_TYPE_PERCEPTION, PERCEPTION_SEEN, CREATURE_TYPE_IS_ALIVE, TRUE );
while ( GetIsObjectValid( oT ) && GetDistanceBetween( oEnt, oT ) < fRad )
{
if ( GetIsObjectValid( oC = GetAssociate( ASSOCIATE_TYPE_SUMMONED, oT ) ) )
{
if ( ( iT = GetHitDice( oC ) ) > iHD )
{
oD = oC;
iHD = iT;
}
}
oT = GetNearestCreature( CREATURE_TYPE_REPUTATION, REPUTATION_TYPE_ENEMY, oEnt, ++iCnt, CREATURE_TYPE_PERCEPTION, PERCEPTION_SEEN, CREATURE_TYPE_IS_ALIVE, TRUE );
}
if ( GetIsObjectValid( oD ) )
{
oM = GetMaster( oD );
}
return oM;
}
vector GetEnemySummonedAssociatesVector( float fRad=10.0, object oEnt=OBJECT_SELF )
{
int iCnt1, iCnt2, iCnt3, iBestCnt;
float fRad = 20.0;
vector vT = Vector( 0.0, 0.0, 0.0 );
vector vS = Vector( 0.0, 0.0, 0.0 );
vector vU = GetPosition( oEnt );
object oT1, oT2, oM;
iCnt1 = 0;
iBestCnt = 0;
oT1 = GetNearestCreature( CREATURE_TYPE_REPUTATION, REPUTATION_TYPE_ENEMY, oEnt, ++iCnt1, CREATURE_TYPE_PERCEPTION, PERCEPTION_SEEN, CREATURE_TYPE_IS_ALIVE, TRUE );
//PrintString( "GES: " + GetName( oT1 ) );
while ( GetIsObjectValid( oT1 ) && GetDistanceBetween( oEnt, oT1 ) <= 30.0f )
{
iCnt2 = 0;
iCnt3 = 0;
oM = GetMaster( oT1 );
if ( GetIsObjectValid( oM ) && GetAssociate( ASSOCIATE_TYPE_SUMMONED, oM ) == oT1 )
{
//PrintString( "GESV: " + GetName( oT1 ) );
if ( GetCurrentAction( oT1 ) != ACTION_MOVETOPOINT )
{
iCnt3 = 1; //starts at 1 to count oSub1
vT = GetPosition ( oT1 ) - vU;
}
//oT2 = GetNearestCreature( CREATURE_TYPE_REPUTATION, REPUTATION_TYPE_ENEMY, oT1, ++iCnt2, CREATURE_TYPE_PERCEPTION, PERCEPTION_SEEN, CREATURE_TYPE_IS_ALIVE, TRUE );
oT2 = GetNearestCreature( CREATURE_TYPE_REPUTATION, REPUTATION_TYPE_FRIEND, oT1, ++iCnt2, CREATURE_TYPE_PERCEPTION, PERCEPTION_SEEN, CREATURE_TYPE_IS_ALIVE, TRUE );
//this should not pick up dead creatures
while ( GetIsObjectValid( oT2 ) && GetDistanceBetween( oT1, oT2 ) <= fRad )
{
//don't count them as target if they're on the move
if ( GetCurrentAction( oT2 ) != ACTION_MOVETOPOINT )
{
oM = GetMaster( oT2 );
if ( GetIsObjectValid( oM ) && GetAssociate( ASSOCIATE_TYPE_SUMMONED, oM ) == oT2 )
{
iCnt3++;
vT = vT + GetPosition( oT2 ) - vU;
}
}
//oT2 = GetNearestCreature( CREATURE_TYPE_REPUTATION, REPUTATION_TYPE_ENEMY, oT1, ++iCnt2, CREATURE_TYPE_PERCEPTION, PERCEPTION_SEEN, CREATURE_TYPE_IS_ALIVE, TRUE );
oT2 = GetNearestCreature( CREATURE_TYPE_REPUTATION, REPUTATION_TYPE_FRIEND, oT1, ++iCnt2, CREATURE_TYPE_PERCEPTION, PERCEPTION_SEEN, CREATURE_TYPE_IS_ALIVE, TRUE );
}
if ( iCnt3 > iBestCnt )
{
vS = vT / IntToFloat( iCnt3 );
iBestCnt = iCnt3;
}
}
oT1 = GetNearestCreature( CREATURE_TYPE_REPUTATION, REPUTATION_TYPE_ENEMY, oEnt, ++iCnt1, CREATURE_TYPE_PERCEPTION, PERCEPTION_SEEN, CREATURE_TYPE_IS_ALIVE, TRUE );
}
if ( iBestCnt )
{
return vS;
}
return Vector( 0.0, 0.0, 0.0 );
}
vector GetEnemyPlanarVector( float fRad=10.0, object oEnt=OBJECT_SELF )
{
int iCnt1, iCnt2, iCnt3, iBestCnt;
float fRad = 20.0;
vector vT = Vector( 0.0, 0.0, 0.0 );
vector vS = Vector( 0.0, 0.0, 0.0 );
vector vU = GetPosition( oEnt );
object oT1, oT2, oM;
iCnt1 = 0;
iBestCnt = 0;
oT1 = GetNearestCreature( CREATURE_TYPE_REPUTATION, REPUTATION_TYPE_ENEMY, oEnt, ++iCnt1, CREATURE_TYPE_PERCEPTION, PERCEPTION_SEEN, CREATURE_TYPE_IS_ALIVE, TRUE );
//PrintString( "GEP: " + GetName( oT1 ) );
while ( GetIsObjectValid( oT1 ) && GetDistanceBetween( oEnt, oT1 ) <= 30.0f )
{
iCnt2 = 0;
iCnt3 = 0;
if ( GetRacialType( oT1 ) == RACIAL_TYPE_OUTSIDER || GetRacialType( oT1 ) == RACIAL_TYPE_ELEMENTAL )
{
//PrintString( "GEPV: " + GetName( oT1 ) );
if ( GetCurrentAction( oT1 ) != ACTION_MOVETOPOINT )
{
iCnt3 = 1; //starts at 1 to count oSub1
vT = GetPosition ( oT1 ) - vU;
}
//oT2 = GetNearestCreature( CREATURE_TYPE_REPUTATION, REPUTATION_TYPE_ENEMY, oT1, ++iCnt2, CREATURE_TYPE_PERCEPTION, PERCEPTION_SEEN, CREATURE_TYPE_IS_ALIVE, TRUE );
oT2 = GetNearestCreature( CREATURE_TYPE_REPUTATION, REPUTATION_TYPE_FRIEND, oT1, ++iCnt2, CREATURE_TYPE_PERCEPTION, PERCEPTION_SEEN, CREATURE_TYPE_IS_ALIVE, TRUE );
//this should not pick up dead creatures
while ( GetIsObjectValid( oT2 ) && GetDistanceBetween( oT1, oT2 ) <= fRad )
{
//don't count them as target if they're on the move
if ( GetCurrentAction( oT2 ) != ACTION_MOVETOPOINT )
{
if ( GetRacialType( oT2 ) == RACIAL_TYPE_OUTSIDER || GetRacialType( oT2 ) == RACIAL_TYPE_ELEMENTAL )
{
iCnt3++;
vT = vT + GetPosition( oT2 ) - vU;
}
}
//oT2 = GetNearestCreature( CREATURE_TYPE_REPUTATION, REPUTATION_TYPE_ENEMY, oT1, ++iCnt2, CREATURE_TYPE_PERCEPTION, PERCEPTION_SEEN, CREATURE_TYPE_IS_ALIVE, TRUE );
oT2 = GetNearestCreature( CREATURE_TYPE_REPUTATION, REPUTATION_TYPE_FRIEND, oT1, ++iCnt2, CREATURE_TYPE_PERCEPTION, PERCEPTION_SEEN, CREATURE_TYPE_IS_ALIVE, TRUE );
}
if ( iCnt3 > iBestCnt )
{
vS = vT / IntToFloat( iCnt3 );
iBestCnt = iCnt3;
}
}
oT1 = GetNearestCreature( CREATURE_TYPE_REPUTATION, REPUTATION_TYPE_ENEMY, oEnt, ++iCnt1, CREATURE_TYPE_PERCEPTION, PERCEPTION_SEEN, CREATURE_TYPE_IS_ALIVE, TRUE );
}
if ( iBestCnt )
{
return vS;
}
return Vector( 0.0, 0.0, 0.0 );
}
object GetVisionDeprived( float fRad=10.0, object oT=OBJECT_SELF )
{
object oS = oT;
object oA;
object oP;
int iCnt = 0;
int iSpell = 0;
while ( GetIsObjectValid( oS ) && GetDistanceBetween( oT, oS ) < fRad && !GetIsObjectValid( oP ) )
{
if ( !GetIsObjectValid( GetLocalObject( oS, "#VISION" ) ) && ( iSpell = GetVisionSpellNeeded( oS ) ) )
{
if ( GetIsObjectValid( GetMaster( oS ) ) )
{
//associates
oA = oS;
}
else
{
//"real" allies
oP = oS;
}
}
oS = GetNearestCreature( CREATURE_TYPE_REPUTATION, REPUTATION_TYPE_FRIEND, oT, ++iCnt, CREATURE_TYPE_PERCEPTION, PERCEPTION_SEEN, CREATURE_TYPE_IS_ALIVE, TRUE );
}
if ( GetIsObjectValid( oP ) )
{
//"real" allies take preference over associates
return oP;
}
return oA;
}
object GetLeastDefendedAlly( float fRad=10.0, object oC=OBJECT_SELF )
{
object oT, oS;
int iD;
int iMinD;
int iCnt = 0;
struct sPhysDefStatus strP;
struct sSpellDefStatus strM;
iMinD = 100;
oS = oC; //start with the caster
while ( GetIsObjectValid( oS ) && GetDistanceBetween( oC, oS ) < fRad )
{
if ( !GetIsObjectValid( GetMaster( oS ) ) )
{
//don't defend associates
strP = EvaluatePhysicalDefenses( oS );
strM = EvaluateSpellDefenses( oS );
iD = strM.iTotal < strP.iTotal ? strM.iTotal : strP.iTotal;
oT = iD < iMinD ? oS : oT;
iMinD = iD < iMinD ? iD : iMinD;
}
oS = GetNearestCreature( CREATURE_TYPE_REPUTATION, REPUTATION_TYPE_FRIEND, oC, ++iCnt, CREATURE_TYPE_PERCEPTION, PERCEPTION_SEEN, CREATURE_TYPE_IS_ALIVE, TRUE );
}
return oT;
}
int GetHasRangedCapability( object oEnt=OBJECT_SELF )
{
object oI = GetFirstItemInInventory();
int iR = 0;
while ( GetIsObjectValid( oI ) && !iR )
{
iR = GetIsRangedWeapon( oI );
oI = GetNextItemInInventory();
}
return iR;
}
int GetIsRangedWeapon( object oW )
{
int iS;
if ( GetIsObjectValid( oW ) )
{
iS = GetBaseItemType( oW );
if ( iS == BASE_ITEM_DART || iS == BASE_ITEM_HEAVYCROSSBOW || iS == BASE_ITEM_LIGHTCROSSBOW ||
iS == BASE_ITEM_LONGBOW || iS == BASE_ITEM_SHORTBOW || iS == BASE_ITEM_SHURIKEN ||
iS == BASE_ITEM_SLING || iS == BASE_ITEM_THROWINGAXE )
{
return TRUE;
}
}
return FALSE;
}
object GetMostDistantEnemy( float fR=30.0, int iS=TRUE, object oC=OBJECT_SELF )
{
int iCnt = 1;
object oD = OBJECT_INVALID;
object oT = GetNearestCreature( CREATURE_TYPE_REPUTATION, REPUTATION_TYPE_ENEMY, oC, iCnt, CREATURE_TYPE_IS_ALIVE, TRUE );
while ( GetIsObjectValid( oT ) && GetDistanceBetween( oC, oT ) <= fR )
{
if ( GetObjectSeen( oT, oC ) >= iS )
{
oD = oT;
}
oT = GetNearestCreature( CREATURE_TYPE_REPUTATION, REPUTATION_TYPE_ENEMY, oC, ++iCnt, CREATURE_TYPE_IS_ALIVE, TRUE );
}
return oD;
}
vector GetSaves( object oT=OBJECT_SELF )
{
vector vS = Vector( 0.0, 0.0, 0.0 );
//int iC1, iC2, iC3, iL1, iL2, iL3;
//int iCon, iDex, iWis;
/*
iC1 = GetClassByPosition( 1, oT );
iC2 = GetClassByPosition( 2, oT );
iC3 = GetClassByPosition( 3, oT );
iL1 = GetLevelByPosition( 1, oT );
iL2 = GetLevelByPosition( 2, oT );
iL3 = GetLevelByPosition( 3, oT );
iCon = GetAbilityModifier( ABILITY_CONSTITUTION, oT );
iDex = GetAbilityModifier( ABILITY_DEXTERITY, oT );
iWis = GetAbilityModifier( ABILITY_WISDOM, oT );
*/
/*
vS += GetSavesByClass( iC1, iL1 );
vS += GetSavesByClass( iC2, iL2 );
vS += GetSavesByClass( iC3, iL3 );
vS.x += iCon + 2 * GetHasFeat( FEAT_GREAT_FORTITUDE, oT );
vS.y += iDex + 2 * GetHasFeat( FEAT_LIGHTNING_REFLEXES, oT );
vS.z += iWis + 2 * GetHasFeat( FEAT_IRON_WILL, oT );
*/
vS.x = IntToFloat( GetFortitudeSavingThrow( oT ) );
vS.y = IntToFloat( GetReflexSavingThrow( oT ) );
vS.z = IntToFloat( GetWillSavingThrow( oT ) );
return vS;
}
vector GetBaseSavesByClass( int iC, int iL )
{
vector vS = Vector( 0.0, 0.0, 0.0 );
if ( iC != CLASS_TYPE_INVALID )
{
//fort save
if ( iC == CLASS_TYPE_ANIMAL || iC == CLASS_TYPE_BARBARIAN || iC == CLASS_TYPE_BEAST ||
iC == CLASS_TYPE_CLERIC || iC == CLASS_TYPE_DRAGON || iC == CLASS_TYPE_DRUID || iC == CLASS_TYPE_FIGHTER ||
iC == CLASS_TYPE_GIANT || iC == CLASS_TYPE_HUMANOID || iC == CLASS_TYPE_MAGICAL_BEAST ||
iC == CLASS_TYPE_MONK || iC == CLASS_TYPE_OUTSIDER || iC == CLASS_TYPE_PALADIN || iC == CLASS_TYPE_RANGER ||
iC == CLASS_TYPE_SHAPECHANGER || iC == CLASS_TYPE_VERMIN )
{
vS.x += 2.0 + IntToFloat( iL / 2 );
}
else
{
vS.x += IntToFloat( iL / 3 );
}
//reflex save
if ( iC == CLASS_TYPE_ANIMAL || iC == CLASS_TYPE_BARD || iC == CLASS_TYPE_BEAST || iC == CLASS_TYPE_DRAGON ||
iC == CLASS_TYPE_FEY || iC == CLASS_TYPE_MAGICAL_BEAST || iC == CLASS_TYPE_MONK || iC == CLASS_TYPE_MONSTROUS ||
iC == CLASS_TYPE_OUTSIDER || iC == CLASS_TYPE_ROGUE || iC == CLASS_TYPE_SHAPECHANGER )
{
vS.y += 2.0 + IntToFloat( iL / 2 );
}
else
{
vS.y += IntToFloat( iL / 3 );
}
//will save
if ( iC == CLASS_TYPE_ABERRATION || iC == CLASS_TYPE_BARD || iC == CLASS_TYPE_CLERIC || iC == CLASS_TYPE_DRAGON ||
iC == CLASS_TYPE_DRUID || iC == CLASS_TYPE_ELEMENTAL || iC == CLASS_TYPE_FEY || iC == CLASS_TYPE_MONK ||
iC == CLASS_TYPE_MONSTROUS || iC == CLASS_TYPE_OUTSIDER || iC == CLASS_TYPE_SHAPECHANGER ||
iC == CLASS_TYPE_SORCERER || iC == CLASS_TYPE_WIZARD )
{
vS.z += 2.0 + IntToFloat( iL / 2 );
}
else
{
vS.z += IntToFloat( iL / 3 );
}
}
return vS;
}
vector GetAverageEnemySaveInArea( vector vP, float fR=5.0, object oC=OBJECT_SELF )
{
vector vS = Vector( 0.0, 0.0, 0.0 );
location lL = Location( GetArea( oC ), GetPosition( oC ) + vP, VectorToAngle( vP ) );
int iCnt = 0;
object oT;
oT = GetFirstObjectInShape( SHAPE_SPHERE, fR, lL );
while ( GetIsObjectValid( oT ) )
{
if ( GetIsEnemy( oT ) && ( GetObjectSeen( oT, oC ) || GetObjectHeard( oT, oC ) ) )
{
iCnt++;
vS += GetSaves( oT );
}
oT = GetNextObjectInShape( SHAPE_SPHERE, fR, lL );
}
if ( iCnt )
{
vS.x = vS.x / IntToFloat( iCnt );
vS.y = vS.y / IntToFloat( iCnt );
vS.z = vS.z / IntToFloat( iCnt );
}
return vS;
}
//Function imported from SoU x0_i0_spells
int IsImmuneToPetrification(object oCreature)
{
int nAppearance = GetAppearanceType(oCreature);
int bFlesh = FALSE;
switch (nAppearance)
{
case APPEARANCE_TYPE_BASILISK:
case APPEARANCE_TYPE_COCKATRICE:
case APPEARANCE_TYPE_MEDUSA:
case APPEARANCE_TYPE_ALLIP:
case APPEARANCE_TYPE_ELEMENTAL_AIR:
case APPEARANCE_TYPE_ELEMENTAL_AIR_ELDER:
case APPEARANCE_TYPE_ELEMENTAL_EARTH:
case APPEARANCE_TYPE_ELEMENTAL_EARTH_ELDER:
case APPEARANCE_TYPE_ELEMENTAL_FIRE:
case APPEARANCE_TYPE_ELEMENTAL_FIRE_ELDER:
case APPEARANCE_TYPE_ELEMENTAL_WATER:
case APPEARANCE_TYPE_ELEMENTAL_WATER_ELDER:
case APPEARANCE_TYPE_GOLEM_STONE:
case APPEARANCE_TYPE_GOLEM_IRON:
case APPEARANCE_TYPE_GOLEM_CLAY:
case APPEARANCE_TYPE_GOLEM_BONE:
case APPEARANCE_TYPE_GORGON:
case APPEARANCE_TYPE_HEURODIS_LICH:
case APPEARANCE_TYPE_LANTERN_ARCHON:
case APPEARANCE_TYPE_SHADOW:
case APPEARANCE_TYPE_SHADOW_FIEND:
case APPEARANCE_TYPE_SHIELD_GUARDIAN:
case APPEARANCE_TYPE_SKELETAL_DEVOURER:
case APPEARANCE_TYPE_SKELETON_CHIEFTAIN:
case APPEARANCE_TYPE_SKELETON_COMMON:
case APPEARANCE_TYPE_SKELETON_MAGE:
case APPEARANCE_TYPE_SKELETON_PRIEST:
case APPEARANCE_TYPE_SKELETON_WARRIOR:
case APPEARANCE_TYPE_SKELETON_WARRIOR_1:
case APPEARANCE_TYPE_SPECTRE:
case APPEARANCE_TYPE_WILL_O_WISP:
case APPEARANCE_TYPE_WRAITH:
case APPEARANCE_TYPE_BAT_HORROR:
bFlesh = TRUE;
}
return bFlesh;
}
object GetNearestAddledEnemy( float fRange=10.0, object oE=OBJECT_SELF )
{
object oS = OBJECT_INVALID;
int iCnt = 0;
int iEff = 0;
oS = GetNearestCreature( CREATURE_TYPE_REPUTATION, REPUTATION_TYPE_ENEMY, oE, ++iCnt, CREATURE_TYPE_IS_ALIVE, TRUE, CREATURE_TYPE_PERCEPTION, PERCEPTION_SEEN );
while ( GetIsObjectValid( oS ) && GetDistanceBetween( oE, oS ) < fRange )
{
iEff = GetEffectsOnObject( oS );
//can't extract from petrified enemies
if ( ( iEff & NO_EFFECT_PETRIFY ) == 0 )
{
if ( iEff & NO_EFFECT_STUNNED || iEff & NO_EFFECT_DAZED || iEff & NO_EFFECT_PARALYZE || iEff & NO_EFFECT_SLEEP ||
iEff & NO_EFFECT_CONFUSED )
{
//creature is an addled enemy
return oS;
}
}
oS = GetNearestCreature( CREATURE_TYPE_REPUTATION, REPUTATION_TYPE_ENEMY, oE, ++iCnt, CREATURE_TYPE_IS_ALIVE, TRUE, CREATURE_TYPE_PERCEPTION, PERCEPTION_SEEN );
}
return OBJECT_INVALID;
}
object GetNearestAddledEnemyNoExtractor( float fRange=10.0, object oE=OBJECT_SELF )
{
object oS = OBJECT_INVALID;
int iCnt = 0;
int iEff = 0;
oS = GetNearestCreature( CREATURE_TYPE_REPUTATION, REPUTATION_TYPE_ENEMY, oE, ++iCnt, CREATURE_TYPE_IS_ALIVE, TRUE, CREATURE_TYPE_PERCEPTION, PERCEPTION_SEEN );
while ( GetIsObjectValid( oS ) && GetDistanceBetween( oE, oS ) < fRange )
{
iEff = GetEffectsOnObject( oS );
//can't extract from petrified enemies
if ( IsBrainExtractable( oS ) )
{
if ( iEff & NO_EFFECT_STUNNED || iEff & NO_EFFECT_DAZED || iEff & NO_EFFECT_PARALYZE || iEff & NO_EFFECT_SLEEP )
{
//creature is an addled enemy
return oS;
}
}
oS = GetNearestCreature( CREATURE_TYPE_REPUTATION, REPUTATION_TYPE_ENEMY, oE, ++iCnt, CREATURE_TYPE_IS_ALIVE, TRUE, CREATURE_TYPE_PERCEPTION, PERCEPTION_SEEN );
}
return OBJECT_INVALID;
}
int IsBrainExtractable( object oT )
{
int iEff, iR;
int iE = TRUE;
if ( GetIsObjectValid( oT ) )
{
iEff = GetEffectsOnObject( oT );
iR = GetRacialType( oT );
if ( iEff & NO_EFFECT_PETRIFY || GetLocalInt( oT, "#EXTRACTING" ) ||
iR == RACIAL_TYPE_CONSTRUCT || iR == RACIAL_TYPE_ELEMENTAL || iR == RACIAL_TYPE_UNDEAD || iR == RACIAL_TYPE_VERMIN )
{
iE = FALSE;
}
}
return iE;
}
int GetCreatureAttackBonus( object oC=OBJECT_SELF )
{
int iA = GetBaseAttackBonus( oC );
if ( GetHasFeat( FEAT_WEAPON_FINESSE, oC ) )
{
iA += GetAbilityModifier( ABILITY_DEXTERITY, oC );
}
else
{
iA += GetAbilityModifier( ABILITY_STRENGTH, oC );
}
iA += GetHasFeat( FEAT_WEAPON_FOCUS_CREATURE, oC );
return iA;
}
int GetGrappleBonus( object oC=OBJECT_SELF )
{
return GetBaseAttackBonus( oC ) + GetAbilityModifier( ABILITY_STRENGTH, oC ) + 4 * ( GetCreatureSize( oC ) - CREATURE_SIZE_MEDIUM );
}
int GetIsMaster( object oM, object oE=OBJECT_SELF )
{
if ( GetIsObjectValid( oM ) && GetMaster( oE ) == oM )
{
return TRUE;
}
return FALSE;
}
int GetIsPerceived( object oP, int iP=0, object oE=OBJECT_SELF )
{
float fR = 0.0;
int iR = FALSE;
if ( !GetIsObjectValid( oP ) )
{
return FALSE;
}
if ( iP == NO_PERCEPTION_SEEN || iP == 0 )
{
fR = GetPerceptionRange( NO_PERCEPTION_SEEN );
if ( GetObjectSeen( oP ) && GetDistanceBetween( oE, oP ) < fR )
{
iR = TRUE;
}
}
if ( iP == NO_PERCEPTION_HEARD || iP == 0 )
{
fR = GetPerceptionRange( NO_PERCEPTION_HEARD );
if ( GetObjectHeard( oP ) && GetDistanceBetween( oE, oP ) < fR )
{
iR = TRUE;
}
}
if ( iP == NO_PERCEPTION_VANISHED || iP == 0 )
{
fR = GetPerceptionRange( NO_PERCEPTION_VANISHED );
if ( !GetIsPerceived( oP, NO_PERCEPTION_SEEN ) && !GetIsPerceived( oP, NO_PERCEPTION_HEARD ) && GetDistanceBetween( oE, oP ) < fR )
{
iR = TRUE;
}
}
//return TRUE;
return iR;
}
object GetNearestPerceivedCreature( int iP=NO_PERCEPTION_SEEN, object oE=OBJECT_SELF )
{
object oP;
//NOT FINISHED
return oP;
}
object GetNearestActiveAlly( object oE=OBJECT_SELF )
{
int iCnt = 0;
object oT = GetNearestCreature( CREATURE_TYPE_REPUTATION, REPUTATION_TYPE_FRIEND, OBJECT_SELF, ++iCnt, CREATURE_TYPE_IS_ALIVE, TRUE );
while ( GetIsObjectValid( oT ) && !GetLocalInt( oT, "#ACTIVE" ) )
{
oT = GetNearestCreature( CREATURE_TYPE_REPUTATION, REPUTATION_TYPE_FRIEND, OBJECT_SELF, ++iCnt, CREATURE_TYPE_IS_ALIVE, TRUE );
}
return oT;
}
object GetFurthestActiveAlly( float fD=50.0, object oE=OBJECT_SELF )
{
int iCnt = 0;
object oA;
object oT = GetNearestCreature( CREATURE_TYPE_REPUTATION, REPUTATION_TYPE_FRIEND, oE, ++iCnt, CREATURE_TYPE_IS_ALIVE, TRUE );
while ( GetIsObjectValid( oT ) && GetDistanceBetween( oE, oT ) < fD )
{
if ( GetLocalInt( oT, "#ACTIVE" ) )
{
oA = oT;
}
oT = GetNearestCreature( CREATURE_TYPE_REPUTATION, REPUTATION_TYPE_FRIEND, oE, ++iCnt, CREATURE_TYPE_IS_ALIVE, TRUE );
}
return oA;
}
int EstimateAttackBonus( object oC=OBJECT_SELF )
{
int iA = GetBaseAttackBonus( oC );
object oR = GetItemInSlot( INVENTORY_SLOT_RIGHTHAND );
object oL = GetItemInSlot( INVENTORY_SLOT_LEFTHAND );
//weapon focus
iA += GetHasWeaponFocus( oR );
//strength bonus or weapon finesse
if ( GetHasFeat( FEAT_WEAPON_FINESSE, oC ) && GetIsLightWeapon( oR, TRUE ) )
{
iA += GetAbilityModifier( ABILITY_DEXTERITY, oC );
}
else
{
iA += GetAbilityModifier( ABILITY_STRENGTH, oC );
}
//dual wielding modifiers
if ( ( GetIsWeapon( oR ) && GetIsWeapon( oL ) ) || GetIsDoubleWeapon( oR ) )
{
//dual wielding
iA += GetDualWieldingPenalty( oC, oL );
}
return iA;
}
int GetDualWieldingPenalty( object oC=OBJECT_SELF, object oR=OBJECT_INVALID, object oL=OBJECT_INVALID )
{
int iL = GetIsLightWeapon( oL );
int iA = GetHasFeat( FEAT_AMBIDEXTERITY, oC );
int iT = GetHasFeat( FEAT_TWO_WEAPON_FIGHTING, oC );
int iP = 0;
if ( !GetIsObjectValid( oL ) )
{
//no weapon in left hand
if ( GetIsDoubleWeapon( oR ) )
{
//right hand weapon is double weapon, effectively light offhand
iL = 1;
}
else
{
//not wielding an offhand weapon, not dual wielding, no penalty, finish here
return 0;
}
}
if ( iA && iT )
{
//ambidex, two weapon fighting
if ( iL )
{
//light offhand
iP = -2;
}
else
{
//non-light offhand
iP = -4;
}
}
else if ( iA ) //no iT
{
//ambidex, no two weapon
if ( iL )
{
//light offhand
iP = -4;
}
else
{
//non-light offhand
iP = -6;
}
}
else if ( iT ) //no iA
{
//two weapon, no ambidex
if ( iL )
{
//light offhand
iP = -2;
}
else
{
//non-light offhand
-4;
}
}
else //no iA, no iT
{
//no two weapon, no ambidex
if ( iL )
{
//light offhand
iP = -4;
}
else
{
//non-light offhand
iP = -6;
}
}
return iP;
}
int GetHasWeaponFocus( object oR, object oC=OBJECT_SELF )
{
int iF = 0;
switch ( GetBaseItemType( oR ) )
{
case BASE_ITEM_BASTARDSWORD:
iF = GetHasFeat( FEAT_WEAPON_FOCUS_BASTARD_SWORD, oC );
break;
case BASE_ITEM_BATTLEAXE:
iF = GetHasFeat( FEAT_WEAPON_FOCUS_BATTLE_AXE, oC );
break;
case BASE_ITEM_CLUB:
iF = GetHasFeat( FEAT_WEAPON_FOCUS_CLUB, oC );
break;
case BASE_ITEM_DAGGER:
iF = GetHasFeat( FEAT_WEAPON_FOCUS_DAGGER, oC );
break;
case BASE_ITEM_DART:
iF = GetHasFeat( FEAT_WEAPON_FOCUS_DART, oC );
break;
case BASE_ITEM_DIREMACE:
iF = GetHasFeat( FEAT_WEAPON_FOCUS_DIRE_MACE, oC );
break;
case BASE_ITEM_DOUBLEAXE:
iF = GetHasFeat( FEAT_WEAPON_FOCUS_DOUBLE_AXE, oC );
break;
case BASE_ITEM_GREATAXE:
iF = GetHasFeat( FEAT_WEAPON_FOCUS_GREAT_AXE, oC );
break;
case BASE_ITEM_GREATSWORD:
iF = GetHasFeat( FEAT_WEAPON_FOCUS_GREAT_SWORD, oC );
break;
case BASE_ITEM_HALBERD:
iF = GetHasFeat( FEAT_WEAPON_FOCUS_HALBERD, oC );
break;
case BASE_ITEM_HANDAXE:
iF = GetHasFeat( FEAT_WEAPON_FOCUS_HAND_AXE, oC );
break;
case BASE_ITEM_HEAVYCROSSBOW:
iF = GetHasFeat( FEAT_WEAPON_FOCUS_HEAVY_CROSSBOW, oC );
break;
case BASE_ITEM_HEAVYFLAIL:
iF = GetHasFeat( FEAT_WEAPON_FOCUS_HEAVY_FLAIL, oC );
break;
case BASE_ITEM_KAMA:
iF = GetHasFeat( FEAT_WEAPON_FOCUS_KAMA, oC );
break;
case BASE_ITEM_KATANA:
iF = GetHasFeat( FEAT_WEAPON_FOCUS_KATANA, oC );
break;
case BASE_ITEM_KUKRI:
iF = GetHasFeat( FEAT_WEAPON_FOCUS_KUKRI, oC );
break;
case BASE_ITEM_LIGHTFLAIL:
iF = GetHasFeat( FEAT_WEAPON_FOCUS_LIGHT_FLAIL, oC );
break;
case BASE_ITEM_LIGHTHAMMER:
iF = GetHasFeat( FEAT_WEAPON_FOCUS_LIGHT_HAMMER, oC );
break;
case BASE_ITEM_LIGHTMACE:
iF = GetHasFeat( FEAT_WEAPON_FOCUS_LIGHT_MACE, oC );
break;
case BASE_ITEM_LONGBOW:
iF = GetHasFeat( FEAT_WEAPON_FOCUS_LONGBOW, oC );
break;
case BASE_ITEM_LONGSWORD:
iF = GetHasFeat( FEAT_WEAPON_FOCUS_LONG_SWORD, oC );
break;
case BASE_ITEM_MORNINGSTAR:
iF = GetHasFeat( FEAT_WEAPON_FOCUS_MORNING_STAR, oC );
break;
case BASE_ITEM_QUARTERSTAFF:
iF = GetHasFeat( FEAT_WEAPON_FOCUS_STAFF, oC );
break;
case BASE_ITEM_RAPIER:
iF = GetHasFeat( FEAT_WEAPON_FOCUS_RAPIER, oC );
break;
case BASE_ITEM_SCIMITAR:
iF = GetHasFeat( FEAT_WEAPON_FOCUS_SCIMITAR, oC );
break;
case BASE_ITEM_SCYTHE:
iF = GetHasFeat( FEAT_WEAPON_FOCUS_SCYTHE, oC );
break;
case BASE_ITEM_SHORTBOW:
iF = GetHasFeat( FEAT_WEAPON_FOCUS_SHORTBOW, oC );
break;
case BASE_ITEM_SHORTSPEAR:
iF = GetHasFeat( FEAT_WEAPON_FOCUS_SPEAR, oC );
break;
case BASE_ITEM_SHORTSWORD:
iF = GetHasFeat( FEAT_WEAPON_FOCUS_SHORT_SWORD, oC );
break;
case BASE_ITEM_SHURIKEN:
iF = GetHasFeat( FEAT_WEAPON_FOCUS_SHURIKEN, oC );
break;
case BASE_ITEM_SICKLE:
iF = GetHasFeat( FEAT_WEAPON_FOCUS_SICKLE, oC );
break;
case BASE_ITEM_SLING:
iF = GetHasFeat( FEAT_WEAPON_FOCUS_SLING, oC );
break;
case BASE_ITEM_THROWINGAXE:
iF = GetHasFeat( FEAT_WEAPON_FOCUS_THROWING_AXE, oC );
break;
case BASE_ITEM_TWOBLADEDSWORD:
iF = GetHasFeat( FEAT_WEAPON_FOCUS_TWO_BLADED_SWORD, oC );
break;
case BASE_ITEM_WARHAMMER:
iF = GetHasFeat( FEAT_WEAPON_FOCUS_WAR_HAMMER, oC );
break;
case BASE_ITEM_CBLUDGWEAPON:
iF = GetHasFeat( FEAT_WEAPON_FOCUS_CREATURE, oC );
break;
case BASE_ITEM_CPIERCWEAPON:
iF = GetHasFeat( FEAT_WEAPON_FOCUS_CREATURE, oC );
break;
case BASE_ITEM_CSLASHWEAPON:
iF = GetHasFeat( FEAT_WEAPON_FOCUS_CREATURE, oC );
break;
case BASE_ITEM_CSLSHPRCWEAP:
iF = GetHasFeat( FEAT_WEAPON_FOCUS_CREATURE, oC );
break;
case BASE_ITEM_INVALID:
iF = GetHasFeat( FEAT_WEAPON_FOCUS_UNARMED_STRIKE, oC ) || GetHasFeat( FEAT_WEAPON_FOCUS_CREATURE, oC );
break;
}
return iF;
}
int GetIsArmed( object oEnt=OBJECT_SELF )
{
if ( GetIsObjectValid( GetItemInSlot( INVENTORY_SLOT_RIGHTHAND, oEnt ) ) || GetIsObjectValid( GetItemInSlot( INVENTORY_SLOT_LEFTHAND, oEnt ) ) )
{
return TRUE;
}
return FALSE;
}
int GetRelativeEnemyWeaponSize( object oT, object oEnt=OBJECT_SELF )
{
int iM = GetWeaponSize( oEnt );
int iT = GetWeaponSize( oT );
int iR = 0;
if ( iM > iT )
{
iR = 1;
}
else if ( iM < iT )
{
iR = -1;
}
return iR;
}
int GetWeaponSize( object oEnt=OBJECT_SELF )
{
//0=small, 1=medium, 2=large
int iS = 0;
int iType;
object oR = GetItemInSlot( INVENTORY_SLOT_RIGHTHAND );
if ( GetIsObjectValid( oR ) && ( iType = GetBaseItemType( oR ) ) != BASE_ITEM_INVALID )
{
if (
iType == BASE_ITEM_CLUB ||
iType == BASE_ITEM_DAGGER ||
iType == BASE_ITEM_DART ||
iType == BASE_ITEM_KAMA ||
iType == BASE_ITEM_HANDAXE ||
iType == BASE_ITEM_KUKRI ||
iType == BASE_ITEM_LIGHTFLAIL ||
iType == BASE_ITEM_LIGHTHAMMER ||
iType == BASE_ITEM_LIGHTMACE ||
iType == BASE_ITEM_RAPIER ||
iType == BASE_ITEM_SHORTSWORD ||
iType == BASE_ITEM_SHURIKEN ||
iType == BASE_ITEM_SICKLE ||
iType == BASE_ITEM_SLING ||
iType == BASE_ITEM_THROWINGAXE ||
iType == BASE_ITEM_TORCH
)
{
iS = 0;
}
else if (
iType == BASE_ITEM_BASTARDSWORD ||
iType == BASE_ITEM_BATTLEAXE ||
iType == BASE_ITEM_KATANA ||
iType == BASE_ITEM_LONGSWORD ||
iType == BASE_ITEM_MORNINGSTAR ||
iType == BASE_ITEM_SCIMITAR ||
iType == BASE_ITEM_SHORTBOW ||
iType == BASE_ITEM_SHORTSPEAR ||
iType == BASE_ITEM_WARHAMMER
)
{
iS = 1;
}
else if (
iType == BASE_ITEM_DIREMACE ||
iType == BASE_ITEM_DOUBLEAXE ||
iType == BASE_ITEM_GREATAXE ||
iType == BASE_ITEM_GREATSWORD ||
iType == BASE_ITEM_HALBERD ||
iType == BASE_ITEM_HEAVYCROSSBOW ||
iType == BASE_ITEM_HEAVYFLAIL ||
iType == BASE_ITEM_LONGBOW ||
iType == BASE_ITEM_QUARTERSTAFF ||
iType == BASE_ITEM_SCYTHE ||
iType == BASE_ITEM_TWOBLADEDSWORD
)
{
iS = 2;
}
}
return iS;
}
float GetAverageDistanceToEnemy( float fRad=60.0, object oEnt=OBJECT_SELF )
{
int iNum = 0;
float fDist = 0.0;
int iCnt = 1;
object oT = GetNearestCreature( CREATURE_TYPE_REPUTATION, REPUTATION_TYPE_ENEMY, oEnt, iCnt++, CREATURE_TYPE_PERCEPTION, PERCEPTION_SEEN, CREATURE_TYPE_IS_ALIVE, TRUE );
while ( GetIsObjectValid( oT ) && GetDistanceBetween( oEnt, oT ) <= fRad )
{
fDist += GetDistanceBetween( oEnt, oT );
iNum++;
oT = GetNearestCreature( CREATURE_TYPE_REPUTATION, REPUTATION_TYPE_ENEMY, oEnt, iCnt++, CREATURE_TYPE_PERCEPTION, PERCEPTION_SEEN, CREATURE_TYPE_IS_ALIVE, TRUE );
}
if ( iNum )
{
return fDist / iNum;
}
return 0.0;
}
int GetCombatModeModifier( int iMode=0 )
{
int iMod = 0;
if ( iMode > 0 )
{
switch ( iMode )
{
case FEAT_POWER_ATTACK:
iMod = -5;
break;
case FEAT_IMPROVED_POWER_ATTACK:
iMod = -10;
break;
case FEAT_FLURRY_OF_BLOWS:
iMod = -2;
break;
case FEAT_EXPERTISE:
iMod = -5;
break;
case FEAT_IMPROVED_EXPERTISE:
iMod = -10;
break;
case FEAT_RAPID_SHOT:
iMod = -2;
break;
}
}
return iMod;
}
int GetCombatConcentration( object oE=OBJECT_SELF )
{
int iC = GetSkillRank( SKILL_CONCENTRATION, oE ) //RANKS
+ GetAbilityModifier( ABILITY_CONSTITUTION, oE ) //CONSTITUTION MODIFIER
+ 2 * GetHasFeat( FEAT_SKILL_AFFINITY_CONCENTRATION, oE ) //SKILL AFFINITY FOR CONCENTRATION
- 4 * ( 1 - GetHasFeat( FEAT_COMBAT_CASTING, oE ) ) //COMBAT CASTING NEGATES -4 PENALTY
+ 3 * GetHasFeat( FEAT_SKILL_FOCUS_CONCENTRATION, oE ) //SKILL FOCUS CONCENTRATION
+ 10 * GetHasFeat( FEAT_EPIC_SKILL_FOCUS_CONCENTRATION, oE ); //EPIC SKILL FOCUS CONCENTRATION
return iC;
}
int GetTurningLevel( object oC=OBJECT_SELF )
{
int iC = GetLevelByClass( CLASS_TYPE_CLERIC, oC );
int iP = GetLevelByClass( CLASS_TYPE_PALADIN, oC );
int iB = GetLevelByClass( CLASS_TYPE_BLACKGUARD, oC );
//get the higher of the levels out of BLK and PAL, subtract 2 for effective turning level
int iA = iB > iP ? iB - 2 : iP - 2;
//add this to turning level if it is > 0
iC += iA > 0 ? iA : 0;
return iC;
}
void SetIsCentralEyeOpen( int iS=FALSE, object oB=OBJECT_SELF )
{
SetLocalInt( oB, s_BEHOLDER_CENTRAL_EYE_FLAG, iS );
}
int GetIsCentralEyeOpen( object oB=OBJECT_SELF )
{
return GetLocalInt( oB, s_BEHOLDER_CENTRAL_EYE_FLAG );
}