ff_u_plc_att
Attacks on placeables.
Melee attacks on placeables and doors always hit and never sneak attack; a critical hit also lowers the target’s hardness by 1. Ranged critical hits become normal hits.
Variables
ENABLE__FF_U_PLC_ATT: (string) (opt-in) Set to "Y" on module to enable the unit.
Source code
// @code
#include "ff_i_core"
const string ENABLE__FF_U_PLC_ATT = "ENABLE__FF_U_PLC_ATT";
// -----------------------------------------------------------------------------
//! @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"));
int nObjectType = GetObjectType(oTarget);
if (nObjectType != OBJECT_TYPE_PLACEABLE && nObjectType != OBJECT_TYPE_DOOR)
return;
/*
TODO: Reduce combat feedback
// 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 a melee attack on a placeable: auto-hit, no sneak attack, hardness lowered on a critical.
//! @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;
int nObjectType = GetObjectType(oTarget);
if (nObjectType != OBJECT_TYPE_PLACEABLE && nObjectType != OBJECT_TYPE_DOOR)
return;
if (stAttack.bRangedAttack)
OnRangedAttack(oAttacker);
else
OnPhysicalAttack(oAttacker);
}
// -----------------------------------------------------------------------------
void main()
{
string sEvent = NWNX_Events_GetCurrentEvent();
if (sEvent == ON_REGISTER)
{
if (!GetModuleFlag(ENABLE__FF_U_PLC_ATT, FALSE))
return;
NWNX_Damage_SetAttackEventScript("on_attack");
SubscribeToEvent(ON_DEFAULT_ATTACK, __FILE__);
SubscribeToEvent(NWNX_ON_ATTACK_TARGET_CHANGE_BEFORE, __FILE__);
}
else if (sEvent == ON_DEFAULT_ATTACK)
OnAttackPlaceable(OBJECT_SELF);
else if (sEvent == NWNX_ON_ATTACK_TARGET_CHANGE_BEFORE)
SetFeedback(OBJECT_SELF);
}