Difference between revisions of "Combat PerformAttack"
From Dragon Age Toolset Wiki
Mouser9169 (Talk | contribs) m |
m (Fixing category) |
||
(One intermediate revision by one other user not shown) | |||
Line 6: | Line 6: | ||
Variables: | Variables: | ||
+ | |||
+ | Returns: | ||
Used for: | Used for: | ||
Line 219: | Line 221: | ||
} | } | ||
</dascript> | </dascript> | ||
− | + | [[Category:Functions from combat_h]] |
Latest revision as of 15:31, 7 August 2011
Called by:
Calls:
Parameters:
Variables:
Returns:
Used for:
/** * @brief Handles processing an Attack Command * * @param oAttacker The command owner, usually OBJECT_SELF * @param oTarget The Target of the command * * @returns CombatAttackResultStruct with damage and attackresult populated * * "Don't touch this if you want to live" * * @author Georg Zoeller **/ struct CombatAttackResultStruct Combat_PerformAttack(object oAttacker, object oTarget, object oWeapon , float fDamageOverride = 0.0f, int nAbility = 0); struct CombatAttackResultStruct Combat_PerformAttack(object oAttacker, object oTarget, object oWeapon , float fDamageOverride = 0.0f, int nAbility = 0) { struct CombatAttackResultStruct stRet; float fDamage = 0.0f; int nAttackType = Combat_GetAttackType(oAttacker, oWeapon); stRet.fAttackDuration = ATTACK_LOOP_DURATION_INVALID ; // ------------------------------------------------------------------------- // Attack check happens here... // ------------------------------------------------------------------------- stRet.nAttackResult = Combat_GetAttackResult(oAttacker, oTarget, oWeapon ); // ------------------------------------------------------------------------- // If attack result was not a miss, go on to calculate damage // ------------------------------------------------------------------------- if (stRet.nAttackResult != COMBAT_RESULT_MISS) { int bCriticalHit = (stRet.nAttackResult == COMBAT_RESULT_CRITICALHIT); // ------------------------------------------------------------------------- // If attack result was not a miss, check if we need to handle a deathblow // ------------------------------------------------------------------------- fDamage = ( (fDamageOverride == 0.0f) ? Combat_Damage_GetAttackDamage(oAttacker, oTarget, oWeapon, stRet.nAttackResult) : fDamageOverride); float fTargetHealth = GetCurrentHealth( oTarget ); // ----------------------------------------------------------------- // Ranged weapons attacks are not synched and therefore we never // need to worry about reporting deathblows to the engine. // --------------------------------------------------------------------- // --------------------------------------------------------------------- // When not using a ranged weapon, there are synchronize death blows to handle // --------------------------------------------------------------------- if ( nAttackType != ATTACK_TYPE_RANGED && nAbility == 0 && stRet.nAttackResult != COMBAT_RESULT_MISS ) { // ----------------------------------------------------------------- // Deathblows against doors look cool, but really... // ----------------------------------------------------------------- if ( GetObjectType(oTarget) == OBJECT_TYPE_CREATURE) { // --------------------------------------------------------- // Special conditions. // // There are a few cases in the single player campaign // where we want the spectacular deathblow to occur if possible. // // The following logic defines these conditions // --------------------------------------------------------- int nAppearance = GetAppearanceType(oTarget) ; int nRank = GetCreatureRank(oTarget); int bSpecial = FALSE; // --------------------------------------------------------- // ... all boss ogres (there's 1 in the official campaign) by request // from Dr. Muzyka. // ... all elite bosses // --------------------------------------------------------- if ( (nAppearance == APR_TYPE_OGRE || (nRank == CREATURE_RANK_BOSS||nRank == CREATURE_RANK_ELITE_BOSS) ) || nRank == CREATURE_RANK_ELITE_BOSS) { // ------------------------------------------------- // ... but only if they are at the health threshold // required for deathblows to trigger // ------------------------------------------------- if (IsHumanoid(oAttacker)) { bSpecial = _GetRelativeResourceLevel(oTarget, PROPERTY_DEPLETABLE_HEALTH) < SPECIAL_BOSS_DEATHBLOW_THRESHOLD; } } // --------------------------------------------------------- // Deathblows occur when // ... target isn't immortal (duh) AND // ... the damage of the hit exceeds the creature's health OR // ... aforementioned 'special' conditions are met. // --------------------------------------------------------- if ( (!IsImmortal( oTarget ) && (fDamage >= fTargetHealth || bSpecial))) { // ----------------------------------------------------- // ... only from party members AND // ... if we determine that a deathblow doesn't interrupt gameplay OR // ... aforementioned 'special' conditions are met // ----------------------------------------------------- if (IsPartyMember(oAttacker) && (CheckForDeathblow(oAttacker, oTarget) || bSpecial)) { // ------------------------------------------------- // Verify some more conditions... // ------------------------------------------------- int bDeathBlow = Combat_GetValidDeathblow(oAttacker, oTarget); if (bDeathBlow) { stRet.nAttackResult = COMBAT_RESULT_DEATHBLOW ; // --------------------------------------------- // Special treatment for ogre // Reason: The ogre, unlike all other special bosses // has a second, non spectacular deathblow. // if we specify 0, there's a 50% chance that // one is played, which we don't want in this // case, so we're passing the id of the // spectacular one instead. // --------------------------------------------- if (bSpecial && nAppearance == APR_TYPE_OGRE) { stRet.nDeathblowType = 5; // 5 - ogre slowmo deathblow } else { stRet.nDeathblowType = 0; // 0 - auto select in engine; } } else { // Failure to meet conditions: convert to hit. if (stRet.nAttackResult != COMBAT_RESULT_BACKSTAB) { stRet.nAttackResult = COMBAT_RESULT_HIT; } } } else { // Failure to meet conditions: convert to hit. if (stRet.nAttackResult != COMBAT_RESULT_BACKSTAB) { stRet.nAttackResult = COMBAT_RESULT_HIT; } } } /* ishumanoid*/ } /* obj_type creature*/ } } int nDamageType = DAMAGE_TYPE_PHYSICAL; if ( nAttackType == ATTACK_TYPE_RANGED) { // --------------------------------------------------------------------- // Certain projectiles modifyt the damage type done by a ranged weapon // This is defined in PRJ_BASE. // --------------------------------------------------------------------- int nProjectileIndex = GetLocalInt(oWeapon,PROJECTILE_OVERRIDE); if (nProjectileIndex) { int nDamageTypeOverride = GetM2DAInt(TABLE_PROJECTILES,"DamageType",nProjectileIndex); if (nDamageTypeOverride>0) { nDamageType = nDamageTypeOverride; } } // --------------------------------------------------------------------- // When using a ranged weapon, we need to report the duration of the // aim loop to the engine // --------------------------------------------------------------------- stRet.fAttackDuration = GetCreatureRangedDrawSpeed(oAttacker, oWeapon); } else { float fSpeed = CalculateAttackTiming(oAttacker, oWeapon); if (fSpeed>0.0f) { stRet.fAttackDuration = fSpeed; } } // ------------------------------------------------------------------------- // The Impact effect is not a real effect - it is not ever applied. Instead // it is used to marshal information about the attack back to the impact // event. // ------------------------------------------------------------------------- stRet.eImpactEffect = EffectImpact(fDamage, oWeapon, 0, 0, nDamageType); #ifdef DEBUG Log_Trace_Combat("combat_h.Combat_PerformAttack"," Attack Result: " + Log_GetAttackResultNameById(stRet.nAttackResult), oAttacker, oTarget, LOG_CHANNEL_COMBAT_TOHIT ); #endif return stRet; }