#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 ); }