242 lines
11 KiB
Plaintext
242 lines
11 KiB
Plaintext
|
/*/////////////////////// [On Damaged] /////////////////////////////////////////
|
||
|
Filename: nw_c2_default6 or J_AI_OnDamaged
|
||
|
///////////////////////// [On Damaged] /////////////////////////////////////////
|
||
|
We attack any damager if same area (and not already fighting
|
||
|
then search for enemies (defaults to searching if there are no enemies left).
|
||
|
///////////////////////// [History] ////////////////////////////////////////////
|
||
|
1.3 - If we have a damager, not equal faction, and not a DM...
|
||
|
- We set Max Elemental damage.
|
||
|
- Sets the highest damager and amount (if the new damager is seen/heard)
|
||
|
- Polymorph improved a little
|
||
|
- Hide check
|
||
|
- Morale penalty (if set)
|
||
|
1.4 - Elemental damage fixed with bugfixed introduced in later patches.
|
||
|
- Moved things around, more documentation, a little more ordered.
|
||
|
- Added the missing silent shout strings to get allies to attack.
|
||
|
- Damaged taunting will not happen if we are dead.
|
||
|
///////////////////////// [Workings] ///////////////////////////////////////////
|
||
|
Now with fixes, we can correctly set physical damage done (and elemental
|
||
|
damage).
|
||
|
|
||
|
Otherwise, this acts like a hositile spell, or a normal attack or pickpocket
|
||
|
attempt would - and attack the damn person who dares damage us!
|
||
|
///////////////////////// [Arguments] //////////////////////////////////////////
|
||
|
Arguments: GetTotalDamageDealt, GetLastDamager, GetCurrentHitPoints (and max),
|
||
|
GetDamageDealtByType (must be done seperatly for each, doesn't count melee damage)
|
||
|
///////////////////////// [On Damaged] ///////////////////////////////////////*/
|
||
|
|
||
|
#include "J_INC_OTHER_AI"
|
||
|
|
||
|
void main()
|
||
|
{
|
||
|
// Pre-damaged-event. Returns TRUE if we interrupt this script call.
|
||
|
if(FirePreUserEvent(AI_FLAG_UDE_DAMAGED_PRE_EVENT, EVENT_DAMAGED_PRE_EVENT)) return;
|
||
|
|
||
|
// AI status check. Is the AI on?
|
||
|
if(GetAIOff()) return;
|
||
|
|
||
|
// Define Objects/Integers.
|
||
|
int nDamage = GetTotalDamageDealt();
|
||
|
object oDamager = GetLastDamager();
|
||
|
// Check to see if we will polymorph.
|
||
|
int nPolymorph = GetAIConstant(AI_POLYMORPH_INTO);
|
||
|
|
||
|
// Total up the physical damage
|
||
|
|
||
|
// Polymorph check.
|
||
|
if(nPolymorph >= 0)
|
||
|
{
|
||
|
// We won't polymorph if already so
|
||
|
if(!GetHasEffect(EFFECT_TYPE_POLYMORPH))
|
||
|
{
|
||
|
// Polymorph into the requested shape. Cannot be dispelled.
|
||
|
effect eShape = SupernaturalEffect(EffectPolymorph(nPolymorph));
|
||
|
effect eVis = EffectVisualEffect(VFX_FNF_SUMMON_UNDEAD);
|
||
|
DelayCommand(1.0, ApplyEffectToObject(DURATION_TYPE_PERMANENT, eShape, OBJECT_SELF));
|
||
|
DelayCommand(1.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, eVis, OBJECT_SELF));
|
||
|
}
|
||
|
DeleteAIConstant(AI_POLYMORPH_INTO);// We set it to invalid (sets to 0).
|
||
|
}
|
||
|
// First, we check AOE spells...
|
||
|
if(GetObjectType(oDamager) == OBJECT_TYPE_AREA_OF_EFFECT)
|
||
|
{
|
||
|
// Set the damage done by it (the last damage)
|
||
|
// Set to the tag of the AOE, prefixed AI style to be sure.
|
||
|
// - Note, doesn't matter about things like
|
||
|
if(nDamage > 0)
|
||
|
{
|
||
|
// Set it to object to string, which we will delete later anywho.
|
||
|
SetAIInteger(ObjectToString(oDamager), nDamage);
|
||
|
}
|
||
|
}
|
||
|
// Hostile attacker...but it doesn't matter (at the moment) if they even
|
||
|
// did damage.
|
||
|
// * GetIgnoreNoFriend() wrappers DM, Validity, Faction Equal and Dead checks in one
|
||
|
else if(!GetIgnoreNoFriend(oDamager))
|
||
|
{
|
||
|
// Adjust automatically if set. (and not an AOE)
|
||
|
if(GetSpawnInCondition(AI_FLAG_OTHER_CHANGE_FACTIONS_TO_HOSTILE_ON_ATTACK, AI_OTHER_MASTER))
|
||
|
{
|
||
|
if(!GetIsEnemy(oDamager) && !GetFactionEqual(oDamager))
|
||
|
{
|
||
|
AdjustReputation(oDamager, OBJECT_SELF, -100);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// Turn of hiding, a timer to activate Hiding in the main file. This is
|
||
|
// done in each of the events, with the opposition checking seen/heard.
|
||
|
TurnOffHiding(oDamager);
|
||
|
|
||
|
// Did they do damage to use? (IE: No DR) Some things are inapproprate
|
||
|
// to check if no damage was actually done.
|
||
|
if(nDamage > 0)
|
||
|
{
|
||
|
// Speak the damaged string, if applicable.
|
||
|
// * Don't speak when dead. 1.4 change (an obvious one to make)
|
||
|
if(CanSpeak())
|
||
|
{
|
||
|
SpeakArrayString(AI_TALK_ON_DAMAGED);
|
||
|
}
|
||
|
// 1.4 note: These two variables are currently *unused* apart from
|
||
|
// healing. When healing a being (even another NPC) they are checked
|
||
|
// for massive damage. Can not bother to set the highest damager for now.
|
||
|
// NEW:
|
||
|
int nHighestDamage = GetAIInteger(AI_HIGHEST_DAMAGE_AMOUNT);
|
||
|
if(nDamage >= nHighestDamage)
|
||
|
{
|
||
|
SetAIInteger(AI_HIGHEST_DAMAGE_AMOUNT, nDamage);
|
||
|
}
|
||
|
|
||
|
/* OLD:
|
||
|
|
||
|
// Get the previous highest damager, and highest damage amount
|
||
|
object oHighestDamager = GetAIObject(AI_HIGHEST_DAMAGER);
|
||
|
int nHighestDamage = GetAIInteger(AI_HIGHEST_DAMAGE_AMOUNT);
|
||
|
// Set the highest damager, if they are seen or heard, and have done loads.
|
||
|
if((GetObjectSeen(oDamager) || GetObjectHeard(oDamager)) &&
|
||
|
nDamage >= nHighestDamage || !GetIsObjectValid(oHighestDamager))
|
||
|
{
|
||
|
SetAIObject(AI_HIGHEST_DAMAGER, oDamager);
|
||
|
SetAIInteger(AI_HIGHEST_DAMAGE_AMOUNT, nDamage);
|
||
|
}
|
||
|
// Else, if the original was not valid...or not seen/heard, we
|
||
|
// delete it so we don't bother to use it later.
|
||
|
else if(!GetIsObjectValid(oHighestDamager) ||
|
||
|
(!GetObjectSeen(oHighestDamager) && !GetObjectHeard(oHighestDamager)))
|
||
|
{
|
||
|
DeleteAIObject(AI_HIGHEST_DAMAGER);
|
||
|
DeleteAIInteger(AI_HIGHEST_DAMAGE_AMOUNT);
|
||
|
}
|
||
|
*/
|
||
|
|
||
|
// Get all the physical damage. Elemental damage is then nDamage minus
|
||
|
// the physical damage.
|
||
|
int nPhysical = GetDamageDealtByType(DAMAGE_TYPE_BASE_WEAPON |
|
||
|
DAMAGE_TYPE_BLUDGEONING |
|
||
|
DAMAGE_TYPE_PIERCING |
|
||
|
DAMAGE_TYPE_SLASHING);
|
||
|
// If they are all -1, then we make nPhysical 0.
|
||
|
if(nPhysical <= -1) nPhysical = 0;
|
||
|
|
||
|
// Physical damage - only sets if the last damager is the last attacker.
|
||
|
if(GetAIObject(AI_STORED_LAST_ATTACKER) == oDamager)
|
||
|
{
|
||
|
// Get the previous highest damage and test it
|
||
|
if(nPhysical > GetAIInteger(AI_HIGHEST_PHISICAL_DAMAGE_AMOUNT))
|
||
|
{
|
||
|
// If higher, and was a melee/ranged attacker, set it.
|
||
|
// This does include other additional physical damage - EG:
|
||
|
// weapon property: Bonus Damage.
|
||
|
SetAIInteger(AI_HIGHEST_PHISICAL_DAMAGE_AMOUNT, nPhysical);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// Set the max elemental damage done, for better use of elemental
|
||
|
// protections. This is set for the most damage...so it could be
|
||
|
// 1 (for a +1 fire weapon, any number of hits) or over 50 (good
|
||
|
// fireball/flame storm etc.)
|
||
|
int nElemental = nDamage - nPhysical;
|
||
|
if(nElemental > GetAIInteger(MAX_ELEMENTAL_DAMAGE))
|
||
|
{
|
||
|
SetAIInteger(MAX_ELEMENTAL_DAMAGE, nElemental);
|
||
|
}
|
||
|
// Set the last damage done, may set to 0 of course :-P
|
||
|
// * This is only set if they did damage us at all, however.
|
||
|
SetAIInteger(LAST_ELEMENTAL_DAMAGE, nElemental);
|
||
|
|
||
|
// Morale: We may get a penalty if it does more than a cirtain amount of HP damage.
|
||
|
// Other: We set highest damager and amount.
|
||
|
if(!GetSpawnInCondition(AI_FLAG_FLEEING_FEARLESS, AI_TARGETING_FLEE_MASTER))
|
||
|
{
|
||
|
// Get penalty and how much damage at once needs to be done
|
||
|
int nPenalty = GetBoundriedAIInteger(AI_DAMAGE_AT_ONCE_PENALTY, 6, 50, 1);
|
||
|
int nToDamage = GetBoundriedAIInteger(AI_DAMAGE_AT_ONCE_FOR_MORALE_PENALTY, GetMaxHitPoints()/6, GetMaxHitPoints(), 1);
|
||
|
if(nDamage > nToDamage)
|
||
|
{
|
||
|
// 61: "[Damaged] Morale Penalty for 600 seconds [Penalty]" + IntToString(iPenalty)
|
||
|
DebugActionSpeakByInt(61, OBJECT_INVALID, nPenalty);
|
||
|
// Apply penalty
|
||
|
SetMoralePenalty(nPenalty, 300.0);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
// If we are not attacking anything, and not in combat, react!
|
||
|
if(!CannotPerformCombatRound())
|
||
|
{
|
||
|
// 62: "[Damaged] Not in combat: DCR [Damager]" + GetName(oDamager)
|
||
|
DebugActionSpeakByInt(62, oDamager);
|
||
|
|
||
|
// Check if they are in the same area. Can be a left AOE spell.
|
||
|
// Don't attack purposly across area's.
|
||
|
if(GetArea(oDamager) == GetArea(OBJECT_SELF))
|
||
|
{
|
||
|
// Shout to allies to attack the enemy who attacked me
|
||
|
AISpeakString(AI_SHOUT_I_WAS_ATTACKED);
|
||
|
|
||
|
DetermineCombatRound(oDamager);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
// Shout to allies to attack, or be prepared.
|
||
|
AISpeakString(AI_SHOUT_CALL_TO_ARMS);
|
||
|
|
||
|
DetermineCombatRound();
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
// Shout to allies to attack, or be prepared.
|
||
|
AISpeakString(AI_SHOUT_CALL_TO_ARMS);
|
||
|
}
|
||
|
}
|
||
|
// Else it is friendly, or invalid damager
|
||
|
else
|
||
|
{
|
||
|
// Still will react - eg: A left AOE spell (which might mean a battle
|
||
|
// just happened)
|
||
|
if(!CannotPerformCombatRound())
|
||
|
{
|
||
|
// Shout to allies to attack generally. No target to specifically attack,
|
||
|
// as it is an ally.
|
||
|
AISpeakString(AI_SHOUT_CALL_TO_ARMS);
|
||
|
|
||
|
// 63: [Damaged] Not in combat: DCR. Ally hit us. [Damager(Ally?)]" + GetName(oDamager)
|
||
|
DebugActionSpeakByInt(63, oDamager);
|
||
|
DetermineCombatRound();
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
// Shout to allies to attack, or be prepared.
|
||
|
AISpeakString(AI_SHOUT_CALL_TO_ARMS);
|
||
|
}
|
||
|
}
|
||
|
// User defined event - for normally immoral creatures.
|
||
|
if(GetCurrentHitPoints() == 1)
|
||
|
{
|
||
|
// Fire the immortal damaged at 1 HP event.
|
||
|
FireUserEvent(AI_FLAG_UDE_DAMAGED_AT_1_HP, EVENT_DAMAGED_AT_1_HP);
|
||
|
}
|
||
|
// Fire End of Damaged event
|
||
|
FireUserEvent(AI_FLAG_UDE_DAMAGED_EVENT, EVENT_DAMAGED_EVENT);
|
||
|
}
|