ff_u_att_plc
Handle an attack event.
Variables
ENABLE__FF_U_ATT_PLC: (string) (opt-in) Set to "Y" to enable unit.
cf: ff_u_att_feedbk, ff_u_att_plc, ff_u_feedback
Source code
// @code
#include "ff_i_core"
const string ENABLE__FF_U_ATT_PLC = "ENABLE__FF_U_ATT_PLC";
// -----------------------------------------------------------------------------
//! @brief Adjust combat feedback visibility based on whether oPC is attacking a placeable.
//! @param oPC A player character.
void SetFeedback(object oPC);
void SetFeedback(object oPC)
{
if (!GetIsPC(oPC))
return;
object oTarget = StringToObject(NWNX_Events_GetEventData("NEW_TARGET_OBJECT_ID"));
if (GetObjectType(oTarget) != OBJECT_TYPE_PLACEABLE)
return;
// 61939,,,"You cannot damage your target with your currently equipped weapon!"
if (GetPlotFlag(oTarget))
{
NWNX_Feedback_SetFeedbackMessageHidden(NWNX_FEEDBACK_COMBAT_WEAPON_NOT_EFFECTIVE, FALSE, oPC);
NWNX_Player_SetTlkOverride(oPC, 61939, "The object is indestructible.");
}
else
NWNX_Feedback_SetFeedbackMessageHidden(NWNX_FEEDBACK_COMBAT_WEAPON_NOT_EFFECTIVE, TRUE, oPC);
NWNX_Feedback_SetCombatLogMessageHidden(NWNX_FEEDBACK_COMBATLOG_COMPLEX_ATTACK, TRUE, oPC);
if (!GetIsDebug())
{
NWNX_Feedback_SetCombatLogMessageHidden(NWNX_FEEDBACK_COMBATLOG_COMPLEX_DAMAGE, TRUE, oPC);
NWNX_Feedback_SetCombatLogMessageHidden(NWNX_FEEDBACK_COMBATLOG_SIMPLE_DAMAGE, TRUE, oPC);
}
NWNX_Feedback_SetFeedbackMessageHidden(NWNX_FEEDBACK_COMBAT_DAMAGE_RESISTANCE, TRUE, oPC);
NWNX_Feedback_SetFeedbackMessageHidden(NWNX_FEEDBACK_COMBAT_DAMAGE_RESISTANCE_REMAINING, TRUE, oPC);
}
// -----------------------------------------------------------------------------
//! @brief Downgrade critical hits to normal hits for ranged attacks on placeables.
//! @param oAttacker The attacking creature.
void OnRangedAttack(object oAttacker);
void OnRangedAttack(object oAttacker)
{
struct NWNX_Damage_AttackEventData stAttack = NWNX_Damage_GetAttackEventData();
if (stAttack.iAttackResult == 3) // Critical
stAttack.iAttackResult = 1; // normal hit
NWNX_Damage_SetAttackEventData(stAttack);
}
// -----------------------------------------------------------------------------
//! @brief Handle melee attack on a placeable: auto-hit, disable sneak attack, reduce hardness on crit.
//! @param oAttacker The attacking creature.
void OnPhysicalAttack(object oAttacker);
void OnPhysicalAttack(object oAttacker)
{
struct NWNX_Damage_AttackEventData stAttack = NWNX_Damage_GetAttackEventData();
object oTarget = stAttack.oTarget;
stAttack.iSneakAttack = 0; // never
if (stAttack.iAttackResult == 3) // Critical
{
// On a critical hit, reduce the hardness
int nHardness = GetHardness(oTarget);
nHardness = max(0, nHardness - 1);
SetHardness(nHardness, oTarget);
}
else
stAttack.iAttackResult = 7; // automatic hit
NWNX_Damage_SetAttackEventData(stAttack);
}
// -----------------------------------------------------------------------------
//! @brief Dispatch ranged or melee placeable attack handling.
//! @param oAttacker The attacking creature.
void OnAttackPlaceable(object oAttacker)
{
struct NWNX_Damage_AttackEventData stAttack = NWNX_Damage_GetAttackEventData();
object oTarget = stAttack.oTarget;
if (GetObjectType(oTarget) != OBJECT_TYPE_PLACEABLE)
return;
if (stAttack.bRangedAttack)
OnRangedAttack(oAttacker);
else
OnPhysicalAttack(oAttacker);
}
// -----------------------------------------------------------------------------
void main()
{
object oModule = GetModule();
if (!GetModuleFlag(ENABLE__FF_U_ATT_PLC, FALSE))
return;
string sEvent = GetCurrentEvent();
if (sEvent == ON_REGISTER)
{
SubscribeToEvent(ON_DEFAULT_ATTACK, __FILE__);
SubscribeToEvent(ON_BEFORE_ATTACK_TARGET_CHANGE, __FILE__);
}
else if (sEvent == ON_DEFAULT_ATTACK)
OnAttackPlaceable(OBJECT_SELF);
else if (sEvent == ON_AFTER_ATTACK_TARGET_CHANGE)
SetFeedback(OBJECT_SELF);
}