Combat GetAttackResult
From Dragon Age Toolset Wiki
Called by:
Calls:
Parameters:
Variables:
Returns:
Used for:
/** * @brief Determine whether or not an attack hits a target. * * Note that this function only calculates to hit and crits, death blows are * determined in Combat_PerformAttack * * @param oAttacker The attacker * @param oTarget The target that is being attacked * @param nAbility If != 0, it won't trigger backstabs and deathblows. * * @returns COMBAT_RESULT_HIT, COMBAT_RESULT_CRITICALHIT or COMBAT_RESULT_MISS * * @author Georg Zoeller * **/ int Combat_GetAttackResult(object oAttacker, object oTarget, object oWeapon, float fBonus = 0.0f, int nAbility = 0); int Combat_GetAttackResult(object oAttacker, object oTarget, object oWeapon, float fBonus = 0.0f, int nAbility = 0) { // ------------------------------------------------------------------------- // Debug // ------------------------------------------------------------------------- int nForcedCombatResult = GetForcedCombatResult(oAttacker); if (nForcedCombatResult != -1) { #ifdef DEBUG Log_Trace_Combat("combat_h.GetAttackResult"," Skipped rules, FORCED RESULT IS:" + ToString(nForcedCombatResult), oTarget); #endif return nForcedCombatResult; } // ------------------------------------------------------------------------- // Placeables are always hit // ------------------------------------------------------------------------- if (GetObjectType(oTarget) == OBJECT_TYPE_PLACEABLE) { #ifdef DEBUG Log_Trace_Combat("combat_h.GetAttackResult"," Placeable, automatic result : COMBAT_RESULT_HIT", oTarget); #endif return COMBAT_RESULT_HIT; } // ------------------------------------------------------------------------- // Displacement // ------------------------------------------------------------------------- float fDisplace = GetCreatureProperty(oTarget, PROPERTY_ATTRIBUTE_DISPLACEMENT); float fRand = RandomFloat()*100.0; if ( fRand < fDisplace) { #ifdef DEBUG Log_Trace_Combat("combat_h.GetAttackResult"," Displacement effect kciked in, automatic result : COMBAT_RESULT_MISS", oTarget); #endif // --------------------------------------------------------------------- // if the target has the evasion talent, attribute this miss to the talent // (random 50% because the anim is interrupting) // --------------------------------------------------------------------- if (HasAbility(oTarget, ABILITY_TALENT_EVASION) && fRand < (20.0f - (RandomFloat()*10.0f) )) { command currentCmd = GetCurrentCommand(oTarget); int nCmdType = GetCommandType(currentCmd); // Evasion only plays during attack and wait commands. if ( nCmdType == COMMAND_TYPE_WAIT || nCmdType == COMMAND_TYPE_ATTACK || nCmdType == COMMAND_TYPE_INVALID ) { ApplyEffectOnObject(EFFECT_DURATION_TYPE_INSTANT, Effect(1055), oTarget, 0.0f, oTarget, ABILITY_TALENT_EVASION); } } return COMBAT_RESULT_MISS; } int nAttackType = Combat_GetAttackType(oAttacker, oWeapon); int nRet; // ------------------------------------------------------------------------- // Get the attackers attack rating (includes effects and equipment stats) // ------------------------------------------------------------------------- float fAttackRating; if (GetBaseItemType(oWeapon) == BASE_ITEM_TYPE_STAFF) { // --------------------------------------------------------------------- // Staves always hit // --------------------------------------------------------------------- return COMBAT_RESULT_HIT; } fAttackRating = GetCreatureAttackRating (oAttacker); // ------------------------------------------------------------------------- // Add item stat (usually 0) along with scripted boni and attack bias. // ------------------------------------------------------------------------- fAttackRating += GetItemStat(oWeapon, ITEM_STAT_ATTACK) + fBonus + ATTACK_HIT_BIAS; // ------------------------------------------------------------------------- // Easier difficulties grant the player a bonus. // ------------------------------------------------------------------------- fAttackRating += Diff_GetRulesAttackBonus(oAttacker); // ------------------------------------------------------------------------- // This section deals with figuring out which critical hit modifier (melee, ranged, etc) // to use for this attack. // ------------------------------------------------------------------------- float fCriticalHitModifier; int nCriticalHitModifier = (nAttackType == ATTACK_TYPE_RANGED) ? CRITICAL_MODIFIER_RANGED : CRITICAL_MODIFIER_MELEE; fCriticalHitModifier = GetCreatureCriticalHitModifier(oAttacker, nCriticalHitModifier); fCriticalHitModifier += GetItemStat(oWeapon, ITEM_STAT_CRIT_CHANCE_MODIFIER); // ------------------------------------------------------------------------- // Bravery grants +3.5 critical hit per enemy past the first 2 // ------------------------------------------------------------------------- if (HasAbility(oAttacker, ABILITY_TALENT_BRAVERY)) { int nEnemies = Max(0,GetArraySize(GetCreaturesInMeleeRing(oAttacker,0.0, 359.99f,TRUE,0))-2); fCriticalHitModifier += nEnemies * 3.5f; } // ------------------------------------------------------------------------- // Calculate Flanking Bonus // ------------------------------------------------------------------------- float fFlanking = Combat_GetFlankingBonus(oAttacker, oTarget); if (fFlanking > 0.0 ) { // --------------------------------------------------------------------- // Also increase chance for critical hits by 1/5th of the flanking bonus // --------------------------------------------------------------------- fCriticalHitModifier *= (1.0 + (fFlanking/5.0)); } // ------------------------------------------------------------------------- // Range plays a role too. // ------------------------------------------------------------------------- float fDistance = GetDistanceBetween(oAttacker, oTarget); float fNoPenaltyDistance = MaxF(POINT_BLANK_RANGE,GetItemStat(oWeapon, ITEM_STAT_OPTIMUM_RANGE)); fDistance = MaxF(fDistance-fNoPenaltyDistance,0.0f); float fAttackRoll = 50.0; float fPenalties = fDistance; // every meter distance past the free range is -1! float fAttack = fAttackRating + fAttackRoll + fFlanking - fPenalties; // >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> // BEGIN SECTION CRITICAL HITS // >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> int bThreatenCritical = (RandomFloat()*100.0f < fCriticalHitModifier ); if (!bThreatenCritical) { // --------------------------------------------------------------------- // Attacking out of stealth always threatens crit. // --------------------------------------------------------------------- if (IsModalAbilityActive(oAttacker, ABILITY_SKILL_STEALTH_1)) { bThreatenCritical = TRUE; } // ----------------------------------------------------------------- // Death hex effect ... all hits are auto crit // ----------------------------------------------------------------- if (GetHasEffects(oTarget, EFFECT_TYPE_DEATH_HEX)) { bThreatenCritical = TRUE; } // ----------------------------------------------------------------- // Autocrit effect // ----------------------------------------------------------------- if (GetHasEffects(oAttacker, EFFECT_TYPE_AUTOCRIT)) { bThreatenCritical = TRUE; } } else { // --------------------------------------------------------------------- // Double strike does not allow crits // --------------------------------------------------------------------- if (IsModalAbilityActive(oAttacker, ABILITY_TALENT_DUAL_WEAPON_DOUBLE_STRIKE)) { bThreatenCritical = FALSE; } // rapid shot doesn't allow critical strikes if (IsModalAbilityActive(oAttacker, ABILITY_TALENT_RAPIDSHOT)) { bThreatenCritical = FALSE; } } // --------------------------------------------------------------------- // Targets that have critical hit immunity can not be crit... // --------------------------------------------------------------------- if (bThreatenCritical) { Log_Trace_Combat("combat_h.GetAttackResult"," Critical hit averted, target has critical hit immunity", oTarget); bThreatenCritical = !HasAbility(oTarget, ABILITY_TRAIT_CRITICAL_HIT_IMMUNITY); } // <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< // END SECTION CRITICAL HITS // <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< // ------------------------------------------------------------------------- // This section deals with calculating the defense values of the attack target // ------------------------------------------------------------------------- float fDefenseRating = GetCreatureDefense(oTarget) + ((nAttackType == ATTACK_TYPE_RANGED) ? GetCreatureProperty(oTarget,PROPERTY_ATTRIBUTE_MISSILE_SHIELD):0.0f); // ------------------------------------------------------------------------- // Easier difficulties grant the player a bonus. // ------------------------------------------------------------------------- fDefenseRating += Diff_GetRulesDefenseBonus(oTarget); // ------------------------------------------------------------------------- // A hit is successful if the attack rating exceeds the defense rating // ------------------------------------------------------------------------- if (RandomFloat()*100.0f < fAttack - fDefenseRating) { // --------------------------------------------------------------------- // If we threatened a critical, we crit here, otherwise just report normal hit // --------------------------------------------------------------------- nRet = ( (bThreatenCritical) ? COMBAT_RESULT_CRITICALHIT : COMBAT_RESULT_HIT ); if ( nAttackType == ATTACK_TYPE_MELEE) { // ----------------------------------------------------------------- // If we are backstabbing, we change the result here if it // was a crit. Abilities never bs (anim priority) // ----------------------------------------------------------------- if ( nAbility == 0 && Combat_CheckBackstab(oAttacker, oTarget, oWeapon,fFlanking)) { nRet = COMBAT_RESULT_BACKSTAB; } } } // ------------------------------------------------------------------------- // Miss... // ------------------------------------------------------------------------- else { nRet = COMBAT_RESULT_MISS; } // ------------------------------------------------------------------------- // Misdirection Hex // ------------------------------------------------------------------------- if (GetHasEffects(oAttacker, EFFECT_TYPE_MISDIRECTION_HEX)) { #ifdef DEBUG Log_Trace_Combat("combat_h.GetAttackResult"," Attacker under misdirection hex: Hits are misses, crits are hits.", oTarget); #endif if (nRet == COMBAT_RESULT_HIT || nRet == COMBAT_RESULT_BACKSTAB) { nRet = COMBAT_RESULT_MISS; } else if (nRet == COMBAT_RESULT_CRITICALHIT) { nRet = COMBAT_RESULT_HIT; } } // return COMBAT_RESULT_BACKSTAB; #ifdef DEBUG Log_Trace_Combat("combat_h.GetAttackResult"," ToHit Calculation: " + " fAttack:" + ToString(fAttack) + " = (fAttackRating: " + ToString(fAttackRating) + " fAttackRoll:" + ToString(fAttackRoll) + " (range penalty:" + ToString(fPenalties) + ")"+ " fFlanking: " + ToString(fFlanking) + " fBonus(script): " + ToString(fBonus) + ")" , oAttacker, oTarget, LOG_CHANNEL_COMBAT_TOHIT ); Log_Trace_Combat("combat_h.GetAttackResult"," ToHit Calculation (2): " + " fDefenseRating: " + ToString(fDefenseRating) + " fCriticalHitModifier: " + ToString(fCriticalHitModifier) + " bThreatenCritical: " + ToString(bThreatenCritical), oAttacker, oTarget, LOG_CHANNEL_COMBAT_TOHIT ); #endif return nRet; }