Advertisement
lufusol

damageManagerProcessor.ws for Holy Sword Any Weapon for Witcher 3 4.01

Feb 11th, 2023 (edited)
1,425
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. /***********************************************************************/
  2. /**     © 2015 CD PROJEKT S.A. All rights reserved.
  3. /**     THE WITCHER® is a trademark of CD PROJEKT S. A.
  4. /**     The Witcher game is based on the prose of Andrzej Sapkowski.
  5. /***********************************************************************/
  6.  
  7.  
  8.  
  9.  
  10.  
  11. class W3DamageManagerProcessor extends CObject
  12. {
  13.    
  14.     private var playerAttacker              : CR4Player;               
  15.     private var playerVictim                : CR4Player;               
  16.     private var action                      : W3DamageAction;
  17.     private var attackAction                : W3Action_Attack;         
  18.     private var weaponId                    : SItemUniqueId;           
  19.     private var actorVictim                 : CActor;                  
  20.     private var actorAttacker               : CActor;                  
  21.     private var dm                          : CDefinitionsManagerAccessor;
  22.     private var attackerMonsterCategory     : EMonsterCategory;
  23.     private var victimMonsterCategory       : EMonsterCategory;
  24.     private var victimCanBeHitByFists       : bool;
  25.    
  26.    
  27.     public function ProcessAction(act : W3DamageAction)
  28.     {
  29.         var wasAlive, validDamage, isFrozen, autoFinishersEnabled : bool;
  30.         var focusDrain : float;
  31.         var npc : CNewNPC;
  32.         var buffs : array<EEffectType>;
  33.         var arrStr : array<string>;
  34.         var aerondight  : W3Effect_Aerondight;
  35.         var trailFxName : name;
  36.        
  37.        
  38.         var swordEntity : CWitcherSword;
  39.         var swordItem : SItemUniqueId;
  40.         var bloodType : EBloodType;
  41.        
  42.            
  43.         wasAlive = act.victim.IsAlive();       
  44.         npc = (CNewNPC)act.victim;
  45.        
  46.        
  47.         InitializeActionVars(act);
  48.        
  49.        
  50.        
  51.         if(playerVictim && attackAction && attackAction.IsActionMelee() && !attackAction.CanBeParried() && attackAction.IsParried())
  52.         {
  53.             action.GetEffectTypes(buffs);
  54.            
  55.             if(!buffs.Contains(EET_Knockdown) && !buffs.Contains(EET_HeavyKnockdown))
  56.             {
  57.                
  58.                 action.SetParryStagger();
  59.                
  60.                
  61.                 action.SetProcessBuffsIfNoDamage(true);
  62.                
  63.                
  64.                 action.AddEffectInfo(EET_LongStagger);
  65.                
  66.                
  67.                 action.SetHitAnimationPlayType(EAHA_ForceNo);
  68.                 action.SetCanPlayHitParticle(false);
  69.                
  70.                
  71.                 action.RemoveBuffsByType(EET_Bleeding);
  72.                
  73.                
  74.                 action.RemoveBuffsByType(EET_Bleeding1);
  75.                 action.RemoveBuffsByType(EET_Bleeding2);
  76.                 action.RemoveBuffsByType(EET_Bleeding3);
  77.                
  78.             }
  79.         }
  80.        
  81.        
  82.         if(actorAttacker && playerVictim && ((W3PlayerWitcher)playerVictim) && GetWitcherPlayer().IsAnyQuenActive())
  83.             FactsAdd("player_had_quen");
  84.        
  85.        
  86.         ProcessPreHitModifications();
  87.  
  88.        
  89.         ProcessActionQuest(act);
  90.        
  91.        
  92.         isFrozen = (actorVictim && actorVictim.HasBuff(EET_Frozen));
  93.        
  94.        
  95.         validDamage = ProcessActionDamage();
  96.        
  97.        
  98.         if(wasAlive && !action.victim.IsAlive())
  99.         {
  100.             arrStr.PushBack(action.victim.GetDisplayName());
  101.             if(npc && npc.WillBeUnconscious())
  102.             {
  103.                 theGame.witcherLog.AddCombatMessage(GetLocStringByKeyExtWithParams("hud_combat_log_unconscious", , , arrStr), NULL, action.victim);
  104.             }
  105.             else if(action.attacker && action.attacker.GetDisplayName() != "")
  106.             {
  107.                 arrStr.PushBack(action.attacker.GetDisplayName());
  108.                 theGame.witcherLog.AddCombatMessage(GetLocStringByKeyExtWithParams("hud_combat_log_killed", , , arrStr), action.attacker, action.victim);
  109.             }
  110.             else
  111.             {
  112.                 theGame.witcherLog.AddCombatMessage(GetLocStringByKeyExtWithParams("hud_combat_log_dies", , , arrStr), NULL, action.victim);
  113.             }
  114.         }
  115.        
  116.         if( wasAlive && action.DealsAnyDamage() )
  117.         {
  118.             ((CActor) action.attacker).SignalGameplayEventParamFloat(  'CausesDamage', MaxF( action.processedDmg.vitalityDamage, action.processedDmg.essenceDamage ) );
  119.         }
  120.        
  121.        
  122.         ProcessActionReaction(isFrozen, wasAlive);
  123.        
  124.        
  125.         if(action.DealsAnyDamage() || action.ProcessBuffsIfNoDamage())
  126.             ProcessActionBuffs();
  127.        
  128.        
  129.         if(theGame.CanLog() && !validDamage && action.GetEffectsCount() == 0)
  130.         {
  131.             LogAssert(false, "W3DamageManagerProcessor.ProcessAction: action deals no damage and gives no buffs - investigate!");
  132.             if ( theGame.CanLog() )
  133.             {
  134.                 LogDMHits("*** Action has no valid damage and no valid buffs - investigate!", action);
  135.             }
  136.         }
  137.        
  138.        
  139.         if( actorAttacker && wasAlive )
  140.             actorAttacker.OnProcessActionPost(action);
  141.  
  142.        
  143.         if(actorVictim == GetWitcherPlayer() && action.DealsAnyDamage() && !action.IsDoTDamage())
  144.         {
  145.             if(actorAttacker && attackAction)
  146.             {
  147.                 if(actorAttacker.IsHeavyAttack( attackAction.GetAttackName() ))
  148.                     focusDrain = CalculateAttributeValue(thePlayer.GetAttributeValue('heavy_attack_focus_drain'));
  149.                 else if(actorAttacker.IsSuperHeavyAttack( attackAction.GetAttackName() ))
  150.                     focusDrain = CalculateAttributeValue(thePlayer.GetAttributeValue('super_heavy_attack_focus_drain'));
  151.                 else
  152.                     focusDrain = CalculateAttributeValue(thePlayer.GetAttributeValue('light_attack_focus_drain'));
  153.             }
  154.             else
  155.             {
  156.                
  157.                 focusDrain = CalculateAttributeValue(thePlayer.GetAttributeValue('light_attack_focus_drain'));
  158.             }
  159.            
  160.            
  161.             if ( GetWitcherPlayer().CanUseSkill(S_Sword_s16) )
  162.                 focusDrain *= 1 - (CalculateAttributeValue( thePlayer.GetSkillAttributeValue(S_Sword_s16, 'focus_drain_reduction', false, true) ) * thePlayer.GetSkillLevel(S_Sword_s16));
  163.                
  164.             thePlayer.DrainFocus(focusDrain);
  165.         }
  166.        
  167.        
  168.         if(actorAttacker == GetWitcherPlayer() && actorVictim && !actorVictim.IsAlive() && (action.IsActionMelee() || action.GetBuffSourceName() == "Kill"))
  169.         {
  170.             autoFinishersEnabled = theGame.GetInGameConfigWrapper().GetVarValue('Gameplay', 'AutomaticFinishersEnabled');
  171.            
  172.            
  173.            
  174.            
  175.             if(!autoFinishersEnabled || !thePlayer.GetFinisherVictim())
  176.             {
  177.                 if(thePlayer.HasAbility('Runeword 10 _Stats', true))
  178.                     GetWitcherPlayer().Runeword10Triggerred();
  179.                 if(thePlayer.HasAbility('Runeword 12 _Stats', true))
  180.                     GetWitcherPlayer().Runeword12Triggerred();
  181.             }
  182.         }
  183.        
  184.        
  185.         if(action.EndsQuen() && actorVictim)
  186.         {
  187.             actorVictim.FinishQuen(false);         
  188.         }
  189.  
  190.        
  191.         if(actorVictim == thePlayer && attackAction && attackAction.IsActionMelee() && (ShouldProcessTutorial('TutorialDodge') || ShouldProcessTutorial('TutorialCounter') || ShouldProcessTutorial('TutorialParry')) )
  192.         {
  193.             if(attackAction.IsCountered())
  194.             {
  195.                 theGame.GetTutorialSystem().IncreaseCounters();
  196.             }
  197.             else if(attackAction.IsParried())
  198.             {
  199.                 theGame.GetTutorialSystem().IncreaseParries();
  200.             }
  201.            
  202.             if(attackAction.CanBeDodged() && !attackAction.WasDodged())
  203.             {
  204.                 GameplayFactsAdd("tut_failed_dodge", 1, 1);
  205.                 GameplayFactsAdd("tut_failed_roll", 1, 1);
  206.             }
  207.         }
  208.        
  209.     //HolySwordAerondight++
  210.     /*
  211.         if( playerAttacker && npc && action.IsActionMelee() && action.DealtDamage() && IsRequiredAttitudeBetween( playerAttacker, npc, true ))
  212.         {      
  213.             if(!npc.HasTag( 'AerondightIgnore' ))  
  214.     */
  215.         GetWitcherPlayer().SetAerondightTrigger(true);
  216.        
  217.             if( playerAttacker && npc && action.IsActionMelee() && action.DealtDamage() && IsRequiredAttitudeBetween( playerAttacker, npc, true ) && !npc.HasTag( 'AerondightIgnore' ) )
  218.     //HolySwordAerondight--
  219.             {
  220.                 if( playerAttacker.inv.ItemHasTag( attackAction.GetWeaponId(), 'Aerondight' ) )
  221.                 {
  222.                    
  223.                     aerondight = (W3Effect_Aerondight)playerAttacker.GetBuff( EET_Aerondight );
  224.                     aerondight.IncreaseAerondightCharges( attackAction.GetAttackName() );
  225.                    
  226.                    
  227.                     if( aerondight.GetCurrentCount() == aerondight.GetMaxCount() )
  228.                     {
  229.                         switch( npc.GetBloodType() )
  230.                         {
  231.                             case BT_Red :
  232.                                 trailFxName = 'aerondight_blood_red';
  233.                                 break;
  234.                                
  235.                             case BT_Yellow :
  236.                                 trailFxName = 'aerondight_blood_yellow';
  237.                                 break;
  238.                            
  239.                             case BT_Black :
  240.                                 trailFxName = 'aerondight_blood_black';
  241.                                 break;
  242.                            
  243.                             case BT_Green :
  244.                                 trailFxName = 'aerondight_blood_green';
  245.                                 break;
  246.                         }
  247.                        
  248.                         playerAttacker.inv.GetItemEntityUnsafe( attackAction.GetWeaponId() ).PlayEffect( trailFxName );
  249.                     }
  250.                 }
  251.             }
  252.            
  253.             /* //HolySwordAerondight
  254.            
  255.             if(!action.WasDodged() && !attackAction.IsParried() && !attackAction.IsCountered())
  256.             {
  257.                 swordItem = GetWitcherPlayer().GetHeldSword();
  258.                 if(swordItem != GetInvalidUniqueId())
  259.                 {
  260.                     swordEntity = (CWitcherSword)thePlayer.GetInventory().GetItemEntityUnsafe( swordItem );
  261.                     if(swordEntity)
  262.                     {
  263.                         bloodType = npc.GetBloodType();
  264.                         if(bloodType == BT_Red || bloodType == BT_Yellow)
  265.                         {
  266.                             swordEntity.PlayEffectSingle('weapon_blood');
  267.                         }
  268.                         else if (bloodType == BT_Black || npc.HasAbility('mon_kikimora_warrior') || npc.HasAbility('mon_kikimora_worker') || npc.HasAbility('mon_black_spider_base') || npc.HasAbility('mon_black_spider_ep2_base') )
  269.                         {
  270.                             swordEntity.PlayEffectSingle('weapon_blood_black');
  271.                         }
  272.                         else if (bloodType == BT_Green)
  273.                         {
  274.                             swordEntity.PlayEffectSingle('weapon_blood_green');
  275.                         }
  276.                     }
  277.                 }
  278.             }
  279.            
  280.         }
  281.             */ //HolySwordAerondight
  282.     }
  283.    
  284.    
  285.     private final function InitializeActionVars(act : W3DamageAction)
  286.     {
  287.         var tmpName : name;
  288.         var tmpBool : bool;
  289.    
  290.         action              = act;
  291.         playerAttacker      = (CR4Player)action.attacker;
  292.         playerVictim        = (CR4Player)action.victim;
  293.         attackAction        = (W3Action_Attack)action;     
  294.         actorVictim         = (CActor)action.victim;
  295.         actorAttacker       = (CActor)action.attacker;
  296.         dm                  = theGame.GetDefinitionsManager();
  297.        
  298.         if(attackAction)
  299.             weaponId        = attackAction.GetWeaponId();
  300.            
  301.         theGame.GetMonsterParamsForActor(actorVictim, victimMonsterCategory, tmpName, tmpBool, tmpBool, victimCanBeHitByFists);
  302.        
  303.         if(actorAttacker)
  304.             theGame.GetMonsterParamsForActor(actorAttacker, attackerMonsterCategory, tmpName, tmpBool, tmpBool, tmpBool);
  305.     }
  306.    
  307.    
  308.    
  309.    
  310.    
  311.    
  312.     private function ProcessActionQuest(act : W3DamageAction)
  313.     {
  314.         var victimTags, attackerTags : array<name>;
  315.        
  316.         victimTags = action.victim.GetTags();
  317.        
  318.         if(action.attacker)
  319.             attackerTags = action.attacker.GetTags();
  320.        
  321.         AddHitFacts( victimTags, attackerTags, "_weapon_hit" );
  322.        
  323.        
  324.         if ((CGameplayEntity) action.victim) action.victim.OnWeaponHit(act);
  325.     }
  326.    
  327.    
  328.    
  329.    
  330.    
  331.     private function ProcessActionDamage() : bool
  332.     {
  333.         var directDmgIndex, size, i : int;
  334.         var dmgInfos : array< SRawDamage >;
  335.         var immortalityMode : EActorImmortalityMode;
  336.         var dmgValue : float;
  337.         var anyDamageProcessed, fallingRaffard : bool;
  338.         var victimHealthPercBeforeHit, frozenAdditionalDamage : float;     
  339.         var powerMod : SAbilityAttributeValue;
  340.         var witcher : W3PlayerWitcher;
  341.         var canLog : bool;
  342.         var immortalityChannels : array<EActorImmortalityChanel>;
  343.        
  344.         canLog = theGame.CanLog();
  345.        
  346.        
  347.         action.SetAllProcessedDamageAs(0);
  348.         size = action.GetDTs( dmgInfos );
  349.         action.SetDealtFireDamage(false);      
  350.        
  351.        
  352.         if(!actorVictim || (!actorVictim.UsesVitality() && !actorVictim.UsesEssence()) )
  353.         {
  354.            
  355.             for(i=0; i<size; i+=1)
  356.             {
  357.                 if(dmgInfos[i].dmgType == theGame.params.DAMAGE_NAME_FIRE && dmgInfos[i].dmgVal > 0)
  358.                 {
  359.                     action.victim.OnFireHit( (CGameplayEntity)action.causer );
  360.                     break;
  361.                 }
  362.             }
  363.            
  364.             if ( !actorVictim.abilityManager )
  365.                 actorVictim.OnDeath(action);
  366.            
  367.             return false;
  368.         }
  369.        
  370.        
  371.         if(actorVictim.UsesVitality())
  372.             victimHealthPercBeforeHit = actorVictim.GetStatPercents(BCS_Vitality);
  373.         else
  374.             victimHealthPercBeforeHit = actorVictim.GetStatPercents(BCS_Essence);
  375.            
  376.        
  377.         if ( actorVictim && playerAttacker && victimMonsterCategory == MC_Specter && playerAttacker.HasBuff(EET_Mutagen28) && !actorVictim.HasAbility( 'ShadowFormActive' ) )
  378.         {
  379.             actorVictim.BlockAbility('ShadowForm', true);          
  380.             actorVictim.BlockAbility('Flashstep', true);           
  381.             actorVictim.BlockAbility('EssenceRegen', true);
  382.             actorVictim.BlockAbility('Teleport', true);
  383.            
  384.             actorVictim.BlockAbility('Specter', true);         
  385.         }
  386.        
  387.  
  388.    
  389.        
  390.         ProcessDamageIncrease( dmgInfos );
  391.                    
  392.        
  393.         if ( canLog )
  394.         {
  395.             LogBeginning();
  396.         }
  397.            
  398.        
  399.         ProcessCriticalHitCheck();
  400.        
  401.        
  402.         ProcessOnBeforeHitChecks();
  403.        
  404.        
  405.         powerMod = GetAttackersPowerMod();
  406.  
  407.        
  408.         anyDamageProcessed = false;
  409.         directDmgIndex = -1;
  410.         witcher = GetWitcherPlayer();
  411.         size = dmgInfos.Size();        
  412.         for( i = 0; i < size; i += 1 )
  413.         {
  414.            
  415.             if(dmgInfos[i].dmgVal == 0)
  416.                 continue;
  417.            
  418.             if(dmgInfos[i].dmgType == theGame.params.DAMAGE_NAME_DIRECT)
  419.             {
  420.                 directDmgIndex = i;
  421.                 continue;
  422.             }
  423.            
  424.            
  425.             if(dmgInfos[i].dmgType == theGame.params.DAMAGE_NAME_POISON && witcher == actorVictim && witcher.HasBuff(EET_GoldenOriole) && witcher.GetPotionBuffLevel(EET_GoldenOriole) == 3)
  426.             {
  427.                
  428.                 witcher.GainStat(BCS_Vitality, dmgInfos[i].dmgVal);
  429.                
  430.                
  431.                 if ( canLog )
  432.                 {
  433.                     LogDMHits("", action);
  434.                     LogDMHits("*** Player absorbs poison damage from level 3 Golden Oriole potion: " + dmgInfos[i].dmgVal, action);
  435.                 }
  436.                
  437.                
  438.                 dmgInfos[i].dmgVal = 0;
  439.                
  440.                 continue;
  441.             }
  442.            
  443.            
  444.             if ( canLog )
  445.             {
  446.                 LogDMHits("", action);
  447.                 LogDMHits("*** Incoming " + NoTrailZeros(dmgInfos[i].dmgVal) + " " + dmgInfos[i].dmgType + " damage", action);
  448.                 if(action.IsDoTDamage())
  449.                     LogDMHits("DoT's current dt = " + NoTrailZeros(action.GetDoTdt()) + ", estimated dps = " + NoTrailZeros(dmgInfos[i].dmgVal / action.GetDoTdt()), action);
  450.             }
  451.            
  452.            
  453.             anyDamageProcessed = true;
  454.                
  455.            
  456.             dmgValue = MaxF(0, CalculateDamage(dmgInfos[i], powerMod));
  457.        
  458.            
  459.             if( DamageHitsEssence(  dmgInfos[i].dmgType ) )     action.processedDmg.essenceDamage  += dmgValue;
  460.             if( DamageHitsVitality( dmgInfos[i].dmgType ) )     action.processedDmg.vitalityDamage += dmgValue;
  461.             if( DamageHitsMorale(   dmgInfos[i].dmgType ) )     action.processedDmg.moraleDamage   += dmgValue;
  462.             if( DamageHitsStamina(  dmgInfos[i].dmgType ) )     action.processedDmg.staminaDamage  += dmgValue;
  463.         }
  464.        
  465.         if(size == 0 && canLog)
  466.         {
  467.             LogDMHits("*** There is no incoming damage set (probably only buffs).", action);
  468.         }
  469.        
  470.         if ( canLog )
  471.         {
  472.             LogDMHits("", action);
  473.             LogDMHits("Processing block, parry, immortality, signs and other GLOBAL damage reductions...", action);    
  474.         }
  475.        
  476.        
  477.         if(actorVictim)
  478.             actorVictim.ReduceDamage(action);
  479.                
  480.        
  481.         if(directDmgIndex != -1)
  482.         {
  483.             anyDamageProcessed = true;
  484.            
  485.            
  486.             immortalityChannels = actorVictim.GetImmortalityModeChannels(AIM_Invulnerable);
  487.             fallingRaffard = immortalityChannels.Size() == 1 && immortalityChannels.Contains(AIC_WhiteRaffardsPotion) && action.GetBuffSourceName() == "FallingDamage";
  488.            
  489.             if(action.GetIgnoreImmortalityMode() || (!actorVictim.IsImmortal() && !actorVictim.IsInvulnerable() && !actorVictim.IsKnockedUnconscious()) || fallingRaffard)
  490.             {
  491.                 action.processedDmg.vitalityDamage += dmgInfos[directDmgIndex].dmgVal;
  492.                 action.processedDmg.essenceDamage  += dmgInfos[directDmgIndex].dmgVal;
  493.             }
  494.             else if( actorVictim.IsInvulnerable() )
  495.             {
  496.                
  497.             }
  498.             else if( actorVictim.IsImmortal() )
  499.             {
  500.                
  501.                 action.processedDmg.vitalityDamage += MinF(dmgInfos[directDmgIndex].dmgVal, actorVictim.GetStat(BCS_Vitality)-1 );
  502.                 action.processedDmg.essenceDamage  += MinF(dmgInfos[directDmgIndex].dmgVal, actorVictim.GetStat(BCS_Essence)-1 );
  503.             }
  504.         }
  505.        
  506.        
  507.         if( actorVictim.HasAbility( 'OneShotImmune' ) )
  508.         {
  509.             if( action.processedDmg.vitalityDamage >= actorVictim.GetStatMax( BCS_Vitality ) )
  510.             {
  511.                 action.processedDmg.vitalityDamage = actorVictim.GetStatMax( BCS_Vitality ) - 1;
  512.             }
  513.             else if( action.processedDmg.essenceDamage >= actorVictim.GetStatMax( BCS_Essence ) )
  514.             {
  515.                 action.processedDmg.essenceDamage = actorVictim.GetStatMax( BCS_Essence ) - 1;
  516.             }
  517.         }
  518.        
  519.        
  520.         if(action.HasDealtFireDamage())
  521.             action.victim.OnFireHit( (CGameplayEntity)action.causer );
  522.            
  523.        
  524.         ProcessInstantKill();
  525.            
  526.        
  527.         ProcessActionDamage_DealDamage();
  528.        
  529.        
  530.         if(playerAttacker && witcher)
  531.             witcher.SetRecentlyCountered(false);
  532.        
  533.        
  534.         if( attackAction && !attackAction.IsCountered() && playerVictim && attackAction.IsActionMelee())
  535.             theGame.GetGamerProfile().ResetStat(ES_CounterattackChain);
  536.        
  537.        
  538.         ProcessActionDamage_ReduceDurability();
  539.        
  540.        
  541.         if(playerAttacker && actorVictim)
  542.         {
  543.            
  544.             if(playerAttacker.inv.ItemHasAnyActiveOilApplied(weaponId) && (!playerAttacker.CanUseSkill(S_Alchemy_s06) || (playerAttacker.GetSkillLevel(S_Alchemy_s06) < 3)) )
  545.             {          
  546.                 playerAttacker.ReduceAllOilsAmmo( weaponId );
  547.                
  548.                 if(ShouldProcessTutorial('TutorialOilAmmo'))
  549.                 {
  550.                     FactsAdd("tut_used_oil_in_combat");
  551.                 }
  552.             }
  553.            
  554.            
  555.             playerAttacker.inv.ReduceItemRepairObjectBonusCharge(weaponId);
  556.         }
  557.        
  558.        
  559.         if(actorVictim && actorAttacker && !action.GetCannotReturnDamage() )
  560.             ProcessActionReturnedDamage(); 
  561.        
  562.         return anyDamageProcessed;
  563.     }
  564.    
  565.    
  566.     private function ProcessInstantKill()
  567.     {
  568.         var instantKill, focus : float;
  569.  
  570.         if( !actorVictim || !actorAttacker || actorVictim.IsImmuneToInstantKill() )
  571.         {
  572.             return;
  573.         }
  574.        
  575.        
  576.         if( action.WasDodged() || ( attackAction && ( attackAction.IsParried() || attackAction.IsCountered() ) ) )
  577.         {
  578.             return;
  579.         }
  580.        
  581.         if( actorAttacker.HasAbility( 'ForceInstantKill' ) && actorVictim != thePlayer )
  582.         {
  583.             action.SetInstantKill();
  584.         }
  585.        
  586.        
  587.         if( actorAttacker == thePlayer && !action.GetIgnoreInstantKillCooldown() )
  588.         {
  589.             if( !GameTimeDTAtLeastRealSecs( thePlayer.lastInstantKillTime, theGame.GetGameTime(), theGame.params.INSTANT_KILL_INTERNAL_PLAYER_COOLDOWN ) )
  590.             {
  591.                 return;
  592.             }
  593.         }
  594.    
  595.        
  596.         if( !action.GetInstantKill() )
  597.         {
  598.            
  599.             instantKill = CalculateAttributeValue( actorAttacker.GetInventory().GetItemAttributeValue( weaponId, 'instant_kill_chance' ) );
  600.            
  601.            
  602.             if( ( action.IsActionMelee() || action.IsActionRanged() ) && playerAttacker && action.DealsAnyDamage() && thePlayer.CanUseSkill( S_Sword_s03 ) && !playerAttacker.inv.IsItemFists( weaponId ) )
  603.             {
  604.                 focus = thePlayer.GetStat( BCS_Focus );
  605.                
  606.                 if( focus >= 1 )
  607.                 {
  608.                     instantKill += focus * CalculateAttributeValue( thePlayer.GetSkillAttributeValue( S_Sword_s03, 'instant_kill_chance', false, true ) ) * thePlayer.GetSkillLevel( S_Sword_s03 );
  609.                 }
  610.             }
  611.         }
  612.        
  613.        
  614.         if( action.GetInstantKill() || ( RandF() < instantKill ) )
  615.         {
  616.             if( theGame.CanLog() )
  617.             {
  618.                 if( action.GetInstantKill() )
  619.                 {
  620.                     instantKill = 1.f;
  621.                 }
  622.                 LogDMHits( "Instant kill!! (" + NoTrailZeros( instantKill * 100 ) + "% chance", action );
  623.             }
  624.        
  625.             action.processedDmg.vitalityDamage += actorVictim.GetStat( BCS_Vitality );
  626.             action.processedDmg.essenceDamage += actorVictim.GetStat( BCS_Essence );
  627.             action.SetCriticalHit();   
  628.             action.SetInstantKillFloater();        
  629.            
  630.            
  631.             if( playerAttacker )
  632.             {
  633.                 thePlayer.SetLastInstantKillTime( theGame.GetGameTime() );
  634.                 theSound.SoundEvent( 'cmb_play_deadly_hit' );
  635.                 theGame.SetTimeScale( 0.2, theGame.GetTimescaleSource( ETS_InstantKill ), theGame.GetTimescalePriority( ETS_InstantKill ), true, true );
  636.                 thePlayer.AddTimer( 'RemoveInstantKillSloMo', 0.2 );
  637.             }          
  638.         }
  639.     }
  640.    
  641.    
  642.     private function ProcessOnBeforeHitChecks()
  643.     {
  644.         var effectAbilityName, monsterBonusType : name;
  645.         var effectType : EEffectType;
  646.         var null, monsterBonusVal : SAbilityAttributeValue;
  647.         var oilLevel, skillLevel, i : int;
  648.         var baseChance, perOilLevelChance, chance : float;
  649.         var buffs : array<name>;
  650.    
  651.        
  652.         if( playerAttacker && actorVictim && attackAction && attackAction.IsActionMelee() && playerAttacker.CanUseSkill(S_Alchemy_s12) && playerAttacker.inv.ItemHasActiveOilApplied( weaponId, victimMonsterCategory ) )
  653.         {
  654.            
  655.             monsterBonusType = MonsterCategoryToAttackPowerBonus(victimMonsterCategory);
  656.             monsterBonusVal = playerAttacker.inv.GetItemAttributeValue(weaponId, monsterBonusType);
  657.        
  658.             if(monsterBonusVal != null)
  659.             {
  660.                
  661.                 oilLevel = (int)CalculateAttributeValue(playerAttacker.inv.GetItemAttributeValue(weaponId, 'level')) - 1;              
  662.                 skillLevel = playerAttacker.GetSkillLevel(S_Alchemy_s12);
  663.                 baseChance = CalculateAttributeValue(playerAttacker.GetSkillAttributeValue(S_Alchemy_s12, 'skill_chance', false, true));
  664.                 perOilLevelChance = CalculateAttributeValue(playerAttacker.GetSkillAttributeValue(S_Alchemy_s12, 'oil_level_chance', false, true));                    
  665.                 chance = baseChance * skillLevel + perOilLevelChance * oilLevel;
  666.                
  667.                
  668.                 if(RandF() < chance)
  669.                 {
  670.                    
  671.                     dm.GetContainedAbilities(playerAttacker.GetSkillAbilityName(S_Alchemy_s12), buffs);
  672.                     for(i=0; i<buffs.Size(); i+=1)
  673.                     {
  674.                         EffectNameToType(buffs[i], effectType, effectAbilityName);
  675.                         action.AddEffectInfo(effectType, , , effectAbilityName);
  676.                     }
  677.                 }
  678.             }
  679.         }
  680.     }
  681.    
  682.    
  683.     private function ProcessCriticalHitCheck()
  684.     {
  685.         var critChance, critDamageBonus : float;
  686.         var canLog, meleeOrRanged, redWolfSet, isLightAttack, isHeavyAttack, mutation2 : bool;
  687.         var arrStr : array<string>;
  688.         var samum : CBaseGameplayEffect;
  689.         var signPower, min, max : SAbilityAttributeValue;
  690.         var aerondight : W3Effect_Aerondight;
  691.        
  692.         meleeOrRanged = playerAttacker && attackAction && ( attackAction.IsActionMelee() || attackAction.IsActionRanged() );
  693.         redWolfSet = ( W3Petard )action.causer && ( W3PlayerWitcher )actorAttacker && GetWitcherPlayer().IsSetBonusActive( EISB_RedWolf_1 );
  694.         mutation2 = ( W3PlayerWitcher )actorAttacker && GetWitcherPlayer().IsMutationActive(EPMT_Mutation2) && action.IsActionWitcherSign();
  695.        
  696.         if( meleeOrRanged || redWolfSet || mutation2 )
  697.         {
  698.             canLog = theGame.CanLog();
  699.        
  700.            
  701.             if( mutation2 )
  702.             {
  703.                 if( FactsQuerySum('debug_fact_critical_boy') > 0 )
  704.                 {
  705.                     critChance = 1.f;
  706.                 }
  707.                 else
  708.                 {
  709.                     signPower = action.GetPowerStatValue();
  710.                     theGame.GetDefinitionsManager().GetAbilityAttributeValue('Mutation2', 'crit_chance_factor', min, max);
  711.                     critChance = min.valueAdditive + signPower.valueMultiplicative * min.valueMultiplicative;
  712.                 }
  713.             }          
  714.             else
  715.             {
  716.                 if( attackAction )
  717.                 {
  718.                    
  719.                     if( SkillEnumToName(S_Sword_s02) == attackAction.GetAttackTypeName() )
  720.                     {              
  721.                         critChance += CalculateAttributeValue(playerAttacker.GetSkillAttributeValue(S_Sword_s02, theGame.params.CRITICAL_HIT_CHANCE, false, true)) * playerAttacker.GetSkillLevel(S_Sword_s02);
  722.                     }
  723.                    
  724.                    
  725.                     if(GetWitcherPlayer() && GetWitcherPlayer().HasRecentlyCountered() && playerAttacker.CanUseSkill(S_Sword_s11) && playerAttacker.GetSkillLevel(S_Sword_s11) > 2)
  726.                     {
  727.                         critChance += CalculateAttributeValue(playerAttacker.GetSkillAttributeValue(S_Sword_s11, theGame.params.CRITICAL_HIT_CHANCE, false, true));
  728.                     }
  729.                    
  730.                    
  731.                     isLightAttack = playerAttacker.IsLightAttack( attackAction.GetAttackName() );
  732.                     isHeavyAttack = playerAttacker.IsHeavyAttack( attackAction.GetAttackName() );
  733.                     critChance += playerAttacker.GetCriticalHitChance(isLightAttack, isHeavyAttack, actorVictim, victimMonsterCategory, (W3BoltProjectile)action.causer );
  734.                    
  735.                    
  736.                     if(action.GetIsHeadShot())
  737.                     {
  738.                         critChance += theGame.params.HEAD_SHOT_CRIT_CHANCE_BONUS;
  739.                         actorVictim.SignalGameplayEvent( 'Headshot' );
  740.                     }
  741.                    
  742.                    
  743.                     if ( actorVictim && actorVictim.IsAttackerAtBack(playerAttacker) )
  744.                     {
  745.                         critChance += theGame.params.BACK_ATTACK_CRIT_CHANCE_BONUS;
  746.                     }
  747.                        
  748.                    
  749.                     if( action.IsActionMelee() && playerAttacker.inv.ItemHasTag( attackAction.GetWeaponId(), 'Aerondight' ) )
  750.                     {
  751.                         aerondight = (W3Effect_Aerondight)playerAttacker.GetBuff( EET_Aerondight );
  752.                        
  753.                         if( aerondight && aerondight.IsFullyCharged() )
  754.                         {
  755.                            
  756.                             min = playerAttacker.GetAbilityAttributeValue( 'AerondightEffect', 'crit_chance_bonus' );
  757.                             critChance += min.valueAdditive;
  758.                         }
  759.                     }
  760.                 }
  761.                 else
  762.                 {
  763.                    
  764.                     critChance += playerAttacker.GetCriticalHitChance(false, false, actorVictim, victimMonsterCategory, (W3BoltProjectile)action.causer );
  765.                 }
  766.                
  767.                
  768.                 samum = actorVictim.GetBuff(EET_Blindness, 'petard');
  769.                 if(samum && samum.GetBuffLevel() == 3)
  770.                 {
  771.                     critChance += 1.0f;
  772.                 }
  773.             }
  774.            
  775.            
  776.             if ( canLog )
  777.             {
  778.                
  779.                 critDamageBonus = 1 + CalculateAttributeValue(actorAttacker.GetCriticalHitDamageBonus(weaponId, victimMonsterCategory, actorVictim.IsAttackerAtBack(playerAttacker)));
  780.                 critDamageBonus += CalculateAttributeValue(actorAttacker.GetAttributeValue('critical_hit_chance_fast_style'));
  781.                 critDamageBonus = 100 * critDamageBonus;
  782.                
  783.                
  784.                 LogDMHits("", action);             
  785.                 LogDMHits("Trying critical hit (" + NoTrailZeros(critChance*100) + "% chance, dealing " + NoTrailZeros(critDamageBonus) + "% damage)...", action);
  786.             }
  787.            
  788.            
  789.             if(RandF() < critChance)
  790.             {
  791.                
  792.                 action.SetCriticalHit();
  793.                                
  794.                 if ( canLog )
  795.                 {
  796.                     LogDMHits("********************", action);
  797.                     LogDMHits("*** CRITICAL HIT ***", action);
  798.                     LogDMHits("********************", action);             
  799.                 }
  800.                
  801.                 arrStr.PushBack(action.attacker.GetDisplayName());
  802.                 theGame.witcherLog.AddCombatMessage(theGame.witcherLog.COLOR_GOLD_BEGIN + GetLocStringByKeyExtWithParams("hud_combat_log_critical_hit",,,arrStr) + theGame.witcherLog.COLOR_GOLD_END, action.attacker, NULL);
  803.             }
  804.             else if ( canLog )
  805.             {
  806.                 LogDMHits("... nope", action);
  807.             }
  808.         }  
  809.     }
  810.    
  811.    
  812.     private function LogBeginning()
  813.     {
  814.         var logStr : string;
  815.        
  816.         if ( !theGame.CanLog() )
  817.         {
  818.             return;
  819.         }
  820.        
  821.         LogDMHits("-----------------------------------------------------------------------------------", action);      
  822.         logStr = "Beginning hit processing from <<" + action.attacker + ">> to <<" + action.victim + ">> via <<" + action.causer + ">>";
  823.         if(attackAction)
  824.         {
  825.             logStr += " using AttackType <<" + attackAction.GetAttackTypeName() + ">>";    
  826.         }
  827.         logStr += ":";
  828.         LogDMHits(logStr, action);
  829.         LogDMHits("", action);
  830.         LogDMHits("Target stats before damage dealt are:", action);
  831.         if(actorVictim)
  832.         {
  833.             if( actorVictim.UsesVitality() )
  834.                 LogDMHits("Vitality = " + NoTrailZeros(actorVictim.GetStat(BCS_Vitality)), action);
  835.             if( actorVictim.UsesEssence() )
  836.                 LogDMHits("Essence = " + NoTrailZeros(actorVictim.GetStat(BCS_Essence)), action);
  837.             if( actorVictim.GetStatMax(BCS_Stamina) > 0)
  838.                 LogDMHits("Stamina = " + NoTrailZeros(actorVictim.GetStat(BCS_Stamina, true)), action);
  839.             if( actorVictim.GetStatMax(BCS_Morale) > 0)
  840.                 LogDMHits("Morale = " + NoTrailZeros(actorVictim.GetStat(BCS_Morale)), action);
  841.         }
  842.         else
  843.         {
  844.             LogDMHits("Undefined - victim is not a CActor and therefore has no stats", action);
  845.         }
  846.     }
  847.    
  848.    
  849.     private function ProcessDamageIncrease(out dmgInfos : array< SRawDamage >)
  850.     {
  851.         var difficultyDamageMultiplier, rendLoad, rendBonus, overheal, rendRatio, focusCost : float;
  852.         var i, bonusCount : int;
  853.         var frozenBuff : W3Effect_Frozen;
  854.         var frozenDmgInfo : SRawDamage;
  855.         var hadFrostDamage : bool;
  856.         var mpac : CMovingPhysicalAgentComponent;
  857.         var rendBonusPerPoint, staminaRendBonus, perk20Bonus : SAbilityAttributeValue;
  858.         var witcherAttacker : W3PlayerWitcher;
  859.         var damageVal, damageBonus, min, max            : SAbilityAttributeValue;      
  860.         var npcVictim : CNewNPC;
  861.         var sword : SItemUniqueId;
  862.         var actionFreeze : W3DamageAction;
  863.         var aerondight  : W3Effect_Aerondight;
  864.        
  865.        
  866.         var aardDamage : SRawDamage;
  867.         var yrdens : array<W3YrdenEntity>;
  868.         var j, levelDiff : int;
  869.         var aardDamageF : float;
  870.         var spellPower, spellPowerAard, spellPowerYrden : float;
  871.         var spNetflix : SAbilityAttributeValue;
  872.        
  873.        
  874.        
  875.         var entities : array<CGameplayEntity>;
  876.         var skillPassiveMod : float;
  877.        
  878.  
  879.        
  880.        
  881.         if(actorAttacker && !actorAttacker.IgnoresDifficultySettings() && !action.IsDoTDamage())
  882.         {
  883.             difficultyDamageMultiplier = CalculateAttributeValue(actorAttacker.GetAttributeValue(theGame.params.DIFFICULTY_DMG_MULTIPLIER));
  884.             for(i=0; i<dmgInfos.Size(); i+=1)
  885.             {
  886.                 dmgInfos[i].dmgVal = dmgInfos[i].dmgVal * difficultyDamageMultiplier;
  887.             }
  888.         }
  889.            
  890.        
  891.        
  892.        
  893.         if(actorVictim && playerAttacker && !action.IsDoTDamage() && actorVictim.HasBuff(EET_Frozen) && ( (W3AardProjectile)action.causer || (W3AardEntity)action.causer || action.DealsPhysicalOrSilverDamage()) )
  894.         {
  895.            
  896.             action.SetWasFrozen();
  897.            
  898.            
  899.             if( !( ( W3WhiteFrost )action.causer ) )
  900.             {              
  901.                 frozenBuff = (W3Effect_Frozen)actorVictim.GetBuff(EET_Frozen);         
  902.                 frozenDmgInfo.dmgVal = frozenBuff.GetAdditionalDamagePercents() * actorVictim.GetHealth();
  903.             }
  904.            
  905.            
  906.             actorVictim.RemoveAllBuffsOfType(EET_Frozen);
  907.             action.AddEffectInfo(EET_KnockdownTypeApplicator);
  908.            
  909.            
  910.             if( !( ( W3WhiteFrost )action.causer ) )
  911.             {
  912.                 actionFreeze = new W3DamageAction in theGame;
  913.                 actionFreeze.Initialize( actorAttacker, actorVictim, action.causer, action.GetBuffSourceName(), EHRT_None, CPS_Undefined, action.IsActionMelee(), action.IsActionRanged(), action.IsActionWitcherSign(), action.IsActionEnvironment() );
  914.                 actionFreeze.SetCannotReturnDamage( true );
  915.                 actionFreeze.SetCanPlayHitParticle( false );
  916.                 actionFreeze.SetHitAnimationPlayType( EAHA_ForceNo );
  917.                 actionFreeze.SetWasFrozen();       
  918.                 actionFreeze.AddDamage( theGame.params.DAMAGE_NAME_FROST, frozenDmgInfo.dmgVal );
  919.                 theGame.damageMgr.ProcessAction( actionFreeze );
  920.                 delete actionFreeze;
  921.             }
  922.         }
  923.        
  924.        
  925.        
  926.         if(actorVictim && playerAttacker && GetWitcherPlayer().IsSetBonusActive( EISB_Netflix_2 ) && !action.IsDoTDamage() && ( (W3AardProjectile)action.causer || (W3AardEntity)action.causer))
  927.         {  
  928.             yrdens = GetWitcherPlayer().yrdenEntities;
  929.            
  930.             if(yrdens.Size() > 0)
  931.             {
  932.                 spellPowerAard = CalculateAttributeValue(GetWitcherPlayer().GetAttributeValue('spell_power_aard'));
  933.                 spellPowerYrden = CalculateAttributeValue(GetWitcherPlayer().GetAttributeValue('spell_power_yrden'));              
  934.                 spellPower = ClampF(1 + spellPowerAard + spellPowerYrden + CalculateAttributeValue(GetWitcherPlayer().GetPowerStatValue(CPS_SpellPower)), 1, 3);               
  935.            
  936.                 for(i=0; i<yrdens.Size(); i+=1)
  937.                 {
  938.                     for(j=0; j<yrdens[i].validTargetsInArea.Size(); j+=1)
  939.                     {          
  940.                         if(yrdens[i].validTargetsInArea[j] == actorVictim )
  941.                         {
  942.                             levelDiff = playerAttacker.GetLevel() - actorVictim.GetLevel();
  943.                             aardDamage.dmgType = theGame.params.DAMAGE_NAME_DIRECT;
  944.                             if( GetWitcherPlayer().CanUseSkill(S_Magic_s06) )
  945.                                 aardDamageF = (RandRangeF(375.0, 325.0) + (playerAttacker.GetLevel() * 1.8f) + (GetWitcherPlayer().GetSkillLevel(S_Magic_s06) * 100) ) * spellPower;
  946.                             else
  947.                                 aardDamageF = (RandRangeF(375.0, 325.0) + (playerAttacker.GetLevel() * 1.8f) ) * spellPower;
  948.                            
  949.                             if( actorVictim.GetCharacterStats().HasAbilityWithTag('Boss') || (W3MonsterHuntNPC)actorVictim || (levelDiff < 0 && Abs(levelDiff) > theGame.params.LEVEL_DIFF_HIGH))
  950.                             {
  951.                                 aardDamage.dmgVal = aardDamageF * 0.75f;
  952.                             }                  
  953.                             else
  954.                             {
  955.                                 aardDamage.dmgVal = aardDamageF;
  956.                             }
  957.                            
  958.                             spNetflix = action.GetPowerStatValue();
  959.                             aardDamage.dmgVal += 3 * actorVictim.GetHealth() * ( 0.01 + 0.03 * LogF( spNetflix.valueMultiplicative ) );
  960.                             dmgInfos.PushBack(aardDamage);
  961.                         }
  962.                     }
  963.                 }
  964.             }
  965.         }
  966.            
  967.        
  968.         if(actorVictim)
  969.         {
  970.             mpac = (CMovingPhysicalAgentComponent)actorVictim.GetMovingAgentComponent();
  971.                        
  972.             if(mpac && mpac.IsDiving())
  973.             {
  974.                 mpac = (CMovingPhysicalAgentComponent)actorAttacker.GetMovingAgentComponent(); 
  975.                
  976.                 if(mpac && mpac.IsDiving())
  977.                 {
  978.                     action.SetUnderwaterDisplayDamageHack();
  979.                
  980.                     if(playerAttacker && attackAction && attackAction.IsActionRanged())
  981.                     {
  982.                         for(i=0; i<dmgInfos.Size(); i+=1)
  983.                         {
  984.                             if(FactsQuerySum("NewGamePlus"))
  985.                             {
  986.                                 dmgInfos[i].dmgVal *= (1 + theGame.params.UNDERWATER_CROSSBOW_DAMAGE_BONUS_NGP);
  987.                             }
  988.                             else
  989.                             {
  990.                                 dmgInfos[i].dmgVal *= (1 + theGame.params.UNDERWATER_CROSSBOW_DAMAGE_BONUS);
  991.                             }
  992.                         }
  993.                     }
  994.                 }
  995.             }
  996.         }
  997.        
  998.        
  999.         if(playerAttacker && attackAction && SkillNameToEnum(attackAction.GetAttackTypeName()) == S_Sword_s02)
  1000.         {
  1001.             witcherAttacker = (W3PlayerWitcher)playerAttacker;
  1002.            
  1003.            
  1004.             rendRatio = witcherAttacker.GetSpecialAttackTimeRatio();
  1005.            
  1006.            
  1007.             rendLoad = MinF(rendRatio * playerAttacker.GetStatMax(BCS_Focus), playerAttacker.GetStat(BCS_Focus));
  1008.            
  1009.            
  1010.             if(rendLoad >= 1)
  1011.             {
  1012.                 rendBonusPerPoint = witcherAttacker.GetSkillAttributeValue(S_Sword_s02, 'adrenaline_final_damage_bonus', false, true);
  1013.                 rendBonus = FloorF(rendLoad) * rendBonusPerPoint.valueMultiplicative;
  1014.                
  1015.                 for(i=0; i<dmgInfos.Size(); i+=1)
  1016.                 {
  1017.                     dmgInfos[i].dmgVal *= (1 + rendBonus);
  1018.                 }
  1019.             }
  1020.            
  1021.            
  1022.             staminaRendBonus = witcherAttacker.GetSkillAttributeValue(S_Sword_s02, 'stamina_max_dmg_bonus', false, true);
  1023.            
  1024.             for(i=0; i<dmgInfos.Size(); i+=1)
  1025.             {
  1026.                 dmgInfos[i].dmgVal *= (1 + rendRatio * staminaRendBonus.valueMultiplicative);
  1027.             }
  1028.            
  1029.            
  1030.             thePlayer.SetAttackActionName('');
  1031.         }  
  1032.  
  1033.        
  1034.         if ( actorAttacker != thePlayer && action.IsActionRanged() && (int)CalculateAttributeValue(actorAttacker.GetAttributeValue('level',,true)) > 31)
  1035.         {
  1036.             damageVal = actorAttacker.GetAttributeValue('light_attack_damage_vitality',,true);
  1037.             for(i=0; i<dmgInfos.Size(); i+=1)
  1038.             {
  1039.                 dmgInfos[i].dmgVal = dmgInfos[i].dmgVal + CalculateAttributeValue(damageVal) / 2;
  1040.             }
  1041.         }
  1042.        
  1043.        
  1044.         if ( actorVictim && playerAttacker && attackAction && action.IsActionMelee() && thePlayer.HasAbility('Runeword 4 _Stats', true) && !attackAction.WasDodged() )
  1045.         {
  1046.             overheal = thePlayer.abilityManager.GetOverhealBonus() / thePlayer.GetStatMax(BCS_Vitality);
  1047.        
  1048.             if(overheal > 0.005f)
  1049.             {
  1050.                 for(i=0; i<dmgInfos.Size(); i+=1)
  1051.                 {
  1052.                     dmgInfos[i].dmgVal *= 1.0f + overheal;
  1053.                 }
  1054.            
  1055.                 thePlayer.abilityManager.ResetOverhealBonus();
  1056.                
  1057.                
  1058.                 actorVictim.CreateFXEntityAtPelvis( 'runeword_4', true );              
  1059.             }
  1060.         }
  1061.        
  1062.        
  1063.         if( playerAttacker && actorVictim && attackAction.IsActionMelee() && GetWitcherPlayer().IsSetBonusActive( EISB_Wolf_1 ) )
  1064.         {
  1065.             FindGameplayEntitiesInRange( entities, playerAttacker, 50, 1000, , FLAG_OnlyAliveActors );
  1066.             if( entities.Size() > 0 )
  1067.             {
  1068.                 for( i=0; i<entities.Size(); i+=1 )
  1069.                 {
  1070.                     npcVictim = (CNewNPC) entities[i];
  1071.                     if( npcVictim )
  1072.                     {
  1073.                         if( npcVictim.HasBuff( EET_Bleeding ) )  bonusCount += 1;
  1074.                         if( npcVictim.HasBuff( EET_Bleeding1 ) ) bonusCount += 1;
  1075.                         if( npcVictim.HasBuff( EET_Bleeding2 ) ) bonusCount += 1;
  1076.                         if( npcVictim.HasBuff( EET_Bleeding3 ) ) bonusCount += 1;
  1077.                     }
  1078.                 }
  1079.                
  1080.                 bonusCount *= ((W3PlayerWitcher)playerAttacker).GetSetPartsEquipped( EIST_Wolf );
  1081.                
  1082.                 for( i=0; i<dmgInfos.Size() ; i+=1 )
  1083.                 {
  1084.                     dmgInfos[i].dmgVal *= 1 + bonusCount*0.01;
  1085.                 }
  1086.             }
  1087.         }
  1088.        
  1089.        
  1090.        
  1091.         if( playerAttacker && playerAttacker.IsLightAttack( attackAction.GetAttackName() ) && playerAttacker.HasBuff( EET_LynxSetBonus ) && !attackAction.WasDodged() )
  1092.         {
  1093.             if( !attackAction.IsParried() && !attackAction.IsCountered() )
  1094.             {
  1095.                
  1096.                 damageBonus = playerAttacker.GetAttributeValue( 'lynx_dmg_boost' );
  1097.                
  1098.                 damageBonus.valueAdditive *= ((W3PlayerWitcher)playerAttacker).GetSetPartsEquipped( EIST_Lynx );
  1099.                
  1100.                 for( i=0 ; i<dmgInfos.Size() ; i += 1 )
  1101.                 {
  1102.                     dmgInfos[i].dmgVal *= 1 + damageBonus.valueAdditive;
  1103.                 }
  1104.             }
  1105.         }
  1106.  
  1107.        
  1108.         if( playerAttacker && attackAction.IsActionMelee() && actorVictim.IsAttackerAtBack( playerAttacker ) && !actorVictim.HasAbility( 'CannotBeAttackedFromBehind' ) && ((W3PlayerWitcher)playerAttacker).IsSetBonusActive( EISB_Lynx_2 ) && !attackAction.WasDodged() && ( playerAttacker.inv.IsItemSteelSwordUsableByPlayer( attackAction.GetWeaponId() ) || playerAttacker.inv.IsItemSilverSwordUsableByPlayer( attackAction.GetWeaponId() ) ) )
  1109.         {
  1110.             if( !attackAction.IsParried() && !attackAction.IsCountered() && playerAttacker.GetStat(BCS_Focus) >= 1.0f )
  1111.             {
  1112.                 theGame.GetDefinitionsManager().GetAbilityAttributeValue( GetSetBonusAbility( EISB_Lynx_2 ), 'lynx_2_dmg_boost', min, max );
  1113.                 for( i=0; i<dmgInfos.Size() ; i+=1 )
  1114.                 {
  1115.                     dmgInfos[i].dmgVal *= 1 + min.valueAdditive;
  1116.                 }
  1117.                
  1118.                 if ( !( thePlayer.IsInCombatAction() && ( thePlayer.GetCombatAction() == EBAT_SpecialAttack_Light || thePlayer.GetCombatAction() == EBAT_SpecialAttack_Heavy ) ) )
  1119.                 {
  1120.                     theGame.GetDefinitionsManager().GetAbilityAttributeValue( GetSetBonusAbility( EISB_Lynx_2 ), 'lynx_2_adrenaline_cost', min, max );
  1121.                     focusCost = min.valueAdditive;
  1122.                     if( GetWitcherPlayer().GetStat( BCS_Focus ) >= focusCost )
  1123.                     {              
  1124.                         theGame.GetDefinitionsManager().GetAbilityAttributeValue( GetSetBonusAbility( EISB_Lynx_2 ), 'lynx_2_stun_duration', min, max );
  1125.                         attackAction.AddEffectInfo( EET_Confusion, min.valueAdditive );
  1126.                         playerAttacker.SoundEvent( "ep2_setskill_lynx_activate" );
  1127.                         playerAttacker.DrainFocus( focusCost );
  1128.                     }
  1129.                 }
  1130.             }
  1131.         }
  1132.  
  1133.        
  1134.        
  1135.        
  1136.         if ( playerAttacker && action.IsActionRanged() && ((W3Petard)action.causer) )
  1137.         {
  1138.             skillPassiveMod = CalculateAttributeValue(GetWitcherPlayer().GetAttributeValue('potion_duration'));
  1139.             for( i = 0 ; i < dmgInfos.Size() ; i+=1)
  1140.             {
  1141.                 dmgInfos[i].dmgVal *= ( 1 + skillPassiveMod );
  1142.             }
  1143.            
  1144.            
  1145.             if ( GetWitcherPlayer().CanUseSkill(S_Perk_20) && !action.IsDoTDamage() )
  1146.             {
  1147.                 perk20Bonus = GetWitcherPlayer().GetSkillAttributeValue( S_Perk_20, 'dmg_multiplier', false, false);
  1148.                 for( i = 0 ; i < dmgInfos.Size() ; i+=1)
  1149.                 {
  1150.                     dmgInfos[i].dmgVal *= ( 1 + perk20Bonus.valueMultiplicative );
  1151.                 }
  1152.             }
  1153.            
  1154.         }
  1155.        
  1156.        
  1157.         if( playerAttacker && action.IsActionWitcherSign() && GetWitcherPlayer().IsMutationActive( EPMT_Mutation1 ) )
  1158.         {
  1159.             sword = playerAttacker.inv.GetCurrentlyHeldSword();
  1160.            
  1161.             damageVal.valueBase = 0;
  1162.             damageVal.valueMultiplicative = 0;
  1163.             damageVal.valueAdditive = 0;
  1164.        
  1165.             if( playerAttacker.inv.GetItemCategory(sword) == 'steelsword' )
  1166.             {
  1167.                 damageVal += playerAttacker.inv.GetItemAttributeValue(sword, theGame.params.DAMAGE_NAME_SLASHING);
  1168.             }
  1169.             else if( playerAttacker.inv.GetItemCategory(sword) == 'silversword' )
  1170.             {
  1171.                 damageVal += playerAttacker.inv.GetItemAttributeValue(sword, theGame.params.DAMAGE_NAME_SILVER);
  1172.             }
  1173.             theGame.GetDefinitionsManager().GetAbilityAttributeValue('Mutation1', 'dmg_bonus_factor', min, max);               
  1174.            
  1175.             damageVal.valueBase *= CalculateAttributeValue(min);
  1176.            
  1177.             if( action.IsDoTDamage() )
  1178.             {
  1179.                 damageVal.valueBase *= action.GetDoTdt();
  1180.             }
  1181.            
  1182.             for( i = 0 ; i < dmgInfos.Size() ; i+=1)
  1183.             {
  1184.                 dmgInfos[i].dmgVal += damageVal.valueBase;
  1185.             }
  1186.         }
  1187.        
  1188.        
  1189.         npcVictim = (CNewNPC) actorVictim;
  1190.         if( playerAttacker && npcVictim && attackAction && action.IsActionMelee() && GetWitcherPlayer().IsMutationActive( EPMT_Mutation8 ) && ( victimMonsterCategory != MC_Human || npcVictim.IsImmuneToMutation8Finisher() ) && attackAction.GetWeaponId() == GetWitcherPlayer().GetHeldSword() )
  1191.         {
  1192.             dm.GetAbilityAttributeValue( 'Mutation8', 'dmg_bonus', min, max );
  1193.            
  1194.             for( i = 0 ; i < dmgInfos.Size() ; i+=1)
  1195.             {
  1196.                 dmgInfos[i].dmgVal *= 1 + min.valueMultiplicative;
  1197.             }
  1198.         }
  1199.        
  1200.        
  1201.         if( playerAttacker && actorVictim && attackAction && action.IsActionMelee() && playerAttacker.inv.ItemHasTag( attackAction.GetWeaponId(), 'Aerondight' ) )
  1202.         {  
  1203.             aerondight = (W3Effect_Aerondight)playerAttacker.GetBuff( EET_Aerondight );
  1204.            
  1205.             if( aerondight )
  1206.             {
  1207.                 min = playerAttacker.GetAbilityAttributeValue( 'AerondightEffect', 'dmg_bonus' );
  1208.                 bonusCount = aerondight.GetCurrentCount();
  1209.            
  1210.                 if( bonusCount > 0 )
  1211.                 {
  1212.                     min.valueMultiplicative *= bonusCount;
  1213.                    
  1214.                     for( i = 0 ; i < dmgInfos.Size() ; i += 1 )
  1215.                     {
  1216.                         dmgInfos[i].dmgVal *= 1 + min.valueMultiplicative;
  1217.                     }
  1218.                 }              
  1219.             }
  1220.         }  
  1221.     }
  1222.    
  1223.    
  1224.     private function ProcessActionReturnedDamage()
  1225.     {
  1226.         var witcher             : W3PlayerWitcher;
  1227.         var quen                : W3QuenEntity;
  1228.         var params              : SCustomEffectParams;
  1229.         var processFireShield, canBeParried, canBeDodged, wasParried, wasDodged, returned : bool;
  1230.         var g5Chance            : SAbilityAttributeValue;
  1231.         var dist, checkDist     : float;
  1232.        
  1233.        
  1234.         if((W3PlayerWitcher)playerVictim && !playerAttacker && actorAttacker && !action.IsDoTDamage() && action.IsActionMelee() && (attackerMonsterCategory == MC_Necrophage || attackerMonsterCategory == MC_Vampire) && actorVictim.HasBuff(EET_BlackBlood))
  1235.         {
  1236.             returned = ProcessActionBlackBloodReturnedDamage();    
  1237.         }
  1238.        
  1239.        
  1240.         if(action.IsActionMelee() && actorVictim.HasAbility( 'Thorns' ) )
  1241.         {
  1242.             returned = ProcessActionThornDamage() || returned;
  1243.         }
  1244.        
  1245.         if(actorVictim.HasAbility( 'Glyphword 5 _Stats', true))
  1246.         {          
  1247.             if( GetAttitudeBetween(actorAttacker, actorVictim) == AIA_Hostile)
  1248.             {
  1249.                 if( !action.IsDoTDamage() )
  1250.                 {
  1251.                     g5Chance = actorVictim.GetAttributeValue('glyphword5_chance');
  1252.                    
  1253.                     if(RandF() < g5Chance.valueAdditive)
  1254.                     {
  1255.                         canBeParried = attackAction.CanBeParried();
  1256.                         canBeDodged = attackAction.CanBeDodged();
  1257.                         wasParried = attackAction.IsParried() || attackAction.IsCountered();
  1258.                         wasDodged = attackAction.WasDodged();
  1259.                
  1260.                         if(!action.IsActionMelee() || (!canBeParried && canBeDodged && !wasDodged) || (canBeParried && !wasParried && !canBeDodged) || (canBeParried && canBeDodged && !wasDodged && !wasParried))
  1261.                         {
  1262.                             returned = ProcessActionReflectDamage() || returned;
  1263.                         }
  1264.                     }  
  1265.                 }
  1266.             }          
  1267.            
  1268.         }
  1269.        
  1270.        
  1271.         if(playerVictim && !playerAttacker && actorAttacker && attackAction && attackAction.IsActionMelee() && thePlayer.HasBuff(EET_Mutagen26))
  1272.         {
  1273.             returned = ProcessActionLeshenMutagenDamage() || returned;
  1274.         }
  1275.        
  1276.        
  1277.         if(action.IsActionMelee() && actorVictim.HasAbility( 'FireShield' ) )
  1278.         {
  1279.             witcher = GetWitcherPlayer();          
  1280.             processFireShield = true;          
  1281.             if(playerAttacker == witcher)
  1282.             {
  1283.                 quen = (W3QuenEntity)witcher.GetSignEntity(ST_Quen);
  1284.                 if(quen && quen.IsAnyQuenActive())
  1285.                 {
  1286.                     processFireShield = false;
  1287.                 }
  1288.             }
  1289.            
  1290.             if(processFireShield)
  1291.             {
  1292.                 params.effectType = EET_Burning;
  1293.                 params.creator = actorVictim;
  1294.                 params.sourceName = actorVictim.GetName();
  1295.                
  1296.                 params.effectValue.valueMultiplicative = 0.01;
  1297.                 actorAttacker.AddEffectCustom(params);
  1298.                 returned = true;
  1299.             }
  1300.         }
  1301.        
  1302.        
  1303.         if(actorAttacker.UsesEssence())
  1304.         {
  1305.             returned = ProcessSilverStudsReturnedDamage() || returned;
  1306.         }
  1307.            
  1308.        
  1309.         if( (W3PlayerWitcher)playerVictim && !playerAttacker && actorAttacker && !playerAttacker.IsInFistFightMiniGame() && !action.IsDoTDamage() && action.IsActionMelee() && GetWitcherPlayer().IsMutationActive( EPMT_Mutation4 ) )
  1310.         {
  1311.            
  1312.             dist = VecDistance( actorAttacker.GetWorldPosition(), actorVictim.GetWorldPosition() );
  1313.             checkDist = 3.f;
  1314.             if( actorAttacker.IsHuge() )
  1315.             {
  1316.                 checkDist += 3.f;
  1317.             }
  1318.  
  1319.             if( dist <= checkDist )
  1320.             {
  1321.                 returned = GetWitcherPlayer().ProcessActionMutation4ReturnedDamage( action.processedDmg.vitalityDamage, actorAttacker, EAHA_ForceYes, action ) || returned;
  1322.             }
  1323.         }
  1324.        
  1325.         action.SetWasDamageReturnedToAttacker( returned );
  1326.     }
  1327.    
  1328.    
  1329.     private function ProcessActionLeshenMutagenDamage() : bool
  1330.     {
  1331.         var damageAction : W3DamageAction;
  1332.         var returnedDamage, pts, perc : float;
  1333.         var mutagen : W3Mutagen26_Effect;
  1334.        
  1335.         mutagen = (W3Mutagen26_Effect)playerVictim.GetBuff(EET_Mutagen26);
  1336.         mutagen.GetReturnedDamage(pts, perc);
  1337.        
  1338.         if(pts <= 0 && perc <= 0)
  1339.             return false;
  1340.            
  1341.        
  1342.        
  1343.         returnedDamage = pts + perc * action.processedDmg.vitalityDamage;
  1344.        
  1345.        
  1346.        
  1347.         damageAction = new W3DamageAction in this;     
  1348.         damageAction.Initialize( action.victim, action.attacker, NULL, "Mutagen26", EHRT_None, CPS_AttackPower, true, false, false, false );       
  1349.         damageAction.SetCannotReturnDamage( true );    
  1350.         damageAction.SetHitAnimationPlayType( EAHA_ForceNo );      
  1351.        
  1352.        
  1353.        
  1354.         damageAction.AddDamage(theGame.params.DAMAGE_NAME_DIRECT, returnedDamage);
  1355.        
  1356.        
  1357.         theGame.damageMgr.ProcessAction(damageAction);
  1358.         delete damageAction;
  1359.        
  1360.         return true;
  1361.     }
  1362.    
  1363.    
  1364.     private function ProcessSilverStudsReturnedDamage() : bool
  1365.     {
  1366.         var damageAction : W3DamageAction;
  1367.         var returnedDamage : float;
  1368.        
  1369.         returnedDamage = CalculateAttributeValue(actorVictim.GetAttributeValue('returned_silver_damage'));
  1370.        
  1371.         if(returnedDamage <= 0)
  1372.             return false;
  1373.        
  1374.         damageAction = new W3DamageAction in this;     
  1375.         damageAction.Initialize( action.victim, action.attacker, NULL, "SilverStuds", EHRT_None, CPS_AttackPower, true, false, false, false );     
  1376.         damageAction.SetCannotReturnDamage( true );    
  1377.         damageAction.SetHitAnimationPlayType( EAHA_ForceNo );      
  1378.        
  1379.         damageAction.AddDamage(theGame.params.DAMAGE_NAME_SILVER, returnedDamage);
  1380.        
  1381.         theGame.damageMgr.ProcessAction(damageAction);
  1382.         delete damageAction;
  1383.        
  1384.         return true;
  1385.     }
  1386.    
  1387.    
  1388.     private function ProcessActionBlackBloodReturnedDamage() : bool
  1389.     {
  1390.         var returnedAction : W3DamageAction;
  1391.         var returnVal : SAbilityAttributeValue;
  1392.         var bb : W3Potion_BlackBlood;
  1393.         var potionLevel : int;
  1394.         var returnedDamage : float;
  1395.    
  1396.         if(action.processedDmg.vitalityDamage <= 0)
  1397.             return false;
  1398.        
  1399.         bb = (W3Potion_BlackBlood)actorVictim.GetBuff(EET_BlackBlood);
  1400.         potionLevel = bb.GetBuffLevel();
  1401.        
  1402.        
  1403.         returnedAction = new W3DamageAction in this;       
  1404.         returnedAction.Initialize( action.victim, action.attacker, bb, "BlackBlood", EHRT_None, CPS_AttackPower, true, false, false, false );      
  1405.         returnedAction.SetCannotReturnDamage( true );      
  1406.        
  1407.         returnVal = bb.GetReturnDamageValue();
  1408.        
  1409.         if(potionLevel == 1)
  1410.         {
  1411.             returnedAction.SetHitAnimationPlayType(EAHA_ForceNo);
  1412.         }
  1413.         else
  1414.         {
  1415.             returnedAction.SetHitAnimationPlayType(EAHA_ForceYes);
  1416.             returnedAction.SetHitReactionType(EHRT_Reflect);
  1417.         }
  1418.        
  1419.         returnedDamage = (returnVal.valueBase + action.processedDmg.vitalityDamage) * returnVal.valueMultiplicative + returnVal.valueAdditive;
  1420.         returnedAction.AddDamage(theGame.params.DAMAGE_NAME_DIRECT, returnedDamage);
  1421.        
  1422.         theGame.damageMgr.ProcessAction(returnedAction);
  1423.         delete returnedAction;
  1424.         return true;
  1425.     }
  1426.    
  1427.    
  1428.     private function ProcessActionReflectDamage() : bool
  1429.     {
  1430.         var returnedAction : W3DamageAction;
  1431.         var returnVal, min, max : SAbilityAttributeValue;
  1432.         var potionLevel : int;
  1433.         var returnedDamage : float;
  1434.         var template : CEntityTemplate;
  1435.         var fxEnt : CEntity;
  1436.         var boneIndex: int;
  1437.         var b : bool;
  1438.         var component : CComponent;
  1439.        
  1440.        
  1441.         if(action.processedDmg.vitalityDamage <= 0)
  1442.             return false;
  1443.        
  1444.         returnedDamage = CalculateAttributeValue(actorVictim.GetTotalArmor());
  1445.         theGame.GetDefinitionsManager().GetAbilityAttributeValue('Glyphword 5 _Stats', 'damage_mult', min, max);
  1446.        
  1447.        
  1448.        
  1449.        
  1450.         returnedAction = new W3DamageAction in this;       
  1451.         returnedAction.Initialize( action.victim, action.attacker, NULL, "Glyphword5", EHRT_None, CPS_AttackPower, true, false, false, false );    
  1452.         returnedAction.SetCannotReturnDamage( true );      
  1453.         returnedAction.SetHitAnimationPlayType(EAHA_ForceYes);
  1454.         returnedAction.SetHitReactionType(EHRT_Heavy);
  1455.        
  1456.         returnedAction.AddDamage(theGame.params.DAMAGE_NAME_DIRECT, returnedDamage * min.valueMultiplicative);
  1457.        
  1458.        
  1459.        
  1460.        
  1461.         theGame.damageMgr.ProcessAction(returnedAction);
  1462.         delete returnedAction;
  1463.        
  1464.         template = (CEntityTemplate)LoadResource('glyphword_5');
  1465.        
  1466.        
  1467.        
  1468.        
  1469.        
  1470.        
  1471.         component = action.attacker.GetComponent('torso3effect');
  1472.         if(component)
  1473.             thePlayer.PlayEffect('reflection_damge', component);
  1474.         else
  1475.             thePlayer.PlayEffect('reflection_damge', action.attacker);
  1476.         action.attacker.PlayEffect('yrden_shock');
  1477.        
  1478.         return true;
  1479.     }
  1480.    
  1481.    
  1482.     private function ProcessActionThornDamage() : bool
  1483.     {
  1484.         var damageAction        : W3DamageAction;
  1485.         var damageVal           : SAbilityAttributeValue;
  1486.         var damage              : float;
  1487.         var inv                 : CInventoryComponent;
  1488.         var damageNames         : array < CName >;
  1489.        
  1490.         damageAction    = new W3DamageAction in this;
  1491.        
  1492.         damageAction.Initialize( action.victim, action.attacker, NULL, "Thorns", EHRT_Light, CPS_AttackPower, true, false, false, false );
  1493.        
  1494.         damageAction.SetCannotReturnDamage( true );    
  1495.        
  1496.         damageVal               =  actorVictim.GetAttributeValue( 'light_attack_damage_vitality' );
  1497.        
  1498.        
  1499.        
  1500.        
  1501.        
  1502.         inv = actorAttacker.GetInventory();    
  1503.         inv.GetWeaponDTNames(weaponId, damageNames );
  1504.         damageVal.valueBase  = actorAttacker.GetTotalWeaponDamage(weaponId, damageNames[0], GetInvalidUniqueId() );
  1505.        
  1506.         damageVal.valueBase *= 0.10f;
  1507.        
  1508.         if( damageVal.valueBase == 0 )
  1509.         {
  1510.             damageVal.valueBase = 10;
  1511.         }
  1512.                
  1513.         damage = (damageVal.valueBase + action.processedDmg.vitalityDamage) * damageVal.valueMultiplicative + damageVal.valueAdditive;
  1514.         damageAction.AddDamage(  theGame.params.DAMAGE_NAME_PIERCING, damage );
  1515.        
  1516.         damageAction.SetHitAnimationPlayType( EAHA_ForceYes );
  1517.         theGame.damageMgr.ProcessAction(damageAction);
  1518.         delete damageAction;
  1519.        
  1520.         return true;
  1521.     }
  1522.        
  1523.    
  1524.     private function GetAttackersPowerMod() : SAbilityAttributeValue
  1525.     {      
  1526.         var powerMod, criticalDamageBonus, min, max, critReduction, sp : SAbilityAttributeValue;
  1527.         var mutagen : CBaseGameplayEffect;
  1528.         var totalBonus : float;
  1529.        
  1530.        
  1531.         var inv : CInventoryComponent;
  1532.         var weaponName : name;
  1533.        
  1534.            
  1535.        
  1536.         powerMod = action.GetPowerStatValue();
  1537.         if ( powerMod.valueAdditive == 0 && powerMod.valueBase == 0 && powerMod.valueMultiplicative == 0 && theGame.CanLog() )
  1538.             LogDMHits("Attacker has power stat of 0!", action);
  1539.        
  1540.        
  1541.         if(playerAttacker && attackAction && playerAttacker.IsHeavyAttack(attackAction.GetAttackName()))
  1542.             powerMod.valueMultiplicative -= 0.433;
  1543.        
  1544.        
  1545.         if ( playerAttacker && (W3IgniProjectile)action.causer )
  1546.             powerMod.valueMultiplicative = 1 + (powerMod.valueMultiplicative - 1) * theGame.params.IGNI_SPELL_POWER_MILT;
  1547.        
  1548.        
  1549.         if ( playerAttacker && (W3AardProjectile)action.causer )
  1550.             powerMod.valueMultiplicative = 1;
  1551.        
  1552.        
  1553.        
  1554.         inv = actorAttacker.GetInventory();
  1555.         weaponName = inv.GetItemName( weaponId );
  1556.        
  1557.         if( !playerAttacker && actorVictim && !thePlayer.IsInFistFightMiniGame() && GetAttitudeBetween( thePlayer, actorAttacker ) == AIA_Friendly && !actorAttacker.HasTag( 'keira' ) && !actorAttacker.HasTag( 'Yennefer' )
  1558.             && ( actorAttacker.IsWeaponHeld( 'silversword' ) || actorAttacker.IsWeaponHeld( 'staff2h' ) || weaponName == 'fists_lightning' || weaponName == 'fists_fire' || actorAttacker.HasAbility( 'SkillWitcher' ) || actorAttacker.HasTag( 'regis' )  || actorAttacker.HasBuff(EET_AxiiGuardMe) ) )
  1559.         {
  1560.             if ( powerMod.valueMultiplicative <= 0.1 )
  1561.             {
  1562.                 actorAttacker.AddAbility( 'FCR3HighDamageBoost' );
  1563.                 actorAttacker.AddAbility( 'FCR3LowDamageBoost');
  1564.             }
  1565.             else if ( powerMod.valueMultiplicative <= 0.4 )
  1566.             {
  1567.                 actorAttacker.AddAbility( 'FCR3MedDamageBoost' );
  1568.                 actorAttacker.AddAbility( 'FCR3LowDamageBoost' );
  1569.             }
  1570.             else if ( powerMod.valueMultiplicative <= 0.9 )
  1571.             {
  1572.                 actorAttacker.AddAbility( 'FCR3MedDamageBoost' );
  1573.             }
  1574.             else if ( powerMod.valueMultiplicative <= 1.1 )
  1575.             {
  1576.                 actorAttacker.AddAbility( 'FCR3LowDamageBoost' );
  1577.             }
  1578.         }
  1579.        
  1580.        
  1581.        
  1582.         if(action.IsCriticalHit())
  1583.         {
  1584.            
  1585.             if( playerAttacker && action.IsActionWitcherSign() && GetWitcherPlayer().IsMutationActive(EPMT_Mutation2) )
  1586.             {
  1587.                 sp = action.GetPowerStatValue();
  1588.                
  1589.                 theGame.GetDefinitionsManager().GetAbilityAttributeValue('Mutation2', 'crit_damage_factor', min, max);             
  1590.                 criticalDamageBonus.valueAdditive = sp.valueMultiplicative * min.valueMultiplicative;
  1591.             }
  1592.             else
  1593.             {
  1594.                 criticalDamageBonus = actorAttacker.GetCriticalHitDamageBonus(weaponId, victimMonsterCategory, actorVictim.IsAttackerAtBack(playerAttacker));
  1595.                
  1596.                 criticalDamageBonus += actorAttacker.GetAttributeValue('critical_hit_chance_fast_style');
  1597.                
  1598.                 if(attackAction && playerAttacker)
  1599.                 {
  1600.                     if(playerAttacker.IsHeavyAttack(attackAction.GetAttackName()) && playerAttacker.CanUseSkill(S_Sword_s08))
  1601.                         criticalDamageBonus += playerAttacker.GetSkillAttributeValue(S_Sword_s08, theGame.params.CRITICAL_HIT_DAMAGE_BONUS, false, true) * playerAttacker.GetSkillLevel(S_Sword_s08);
  1602.                     else if (!playerAttacker.IsHeavyAttack(attackAction.GetAttackName()) && playerAttacker.CanUseSkill(S_Sword_s17))
  1603.                         criticalDamageBonus += playerAttacker.GetSkillAttributeValue(S_Sword_s17, theGame.params.CRITICAL_HIT_DAMAGE_BONUS, false, true) * playerAttacker.GetSkillLevel(S_Sword_s17);
  1604.                 }
  1605.             }
  1606.            
  1607.            
  1608.             totalBonus = CalculateAttributeValue(criticalDamageBonus);
  1609.             critReduction = actorVictim.GetAttributeValue(theGame.params.CRITICAL_HIT_REDUCTION);
  1610.             totalBonus = totalBonus * ClampF(1 - critReduction.valueMultiplicative, 0.f, 1.f);
  1611.            
  1612.            
  1613.             powerMod.valueMultiplicative += totalBonus;
  1614.         }
  1615.        
  1616.        
  1617.         if (actorVictim && playerAttacker)
  1618.         {
  1619.             if ( playerAttacker.HasBuff(EET_Mutagen05) && (playerAttacker.GetStat(BCS_Vitality) == playerAttacker.GetStatMax(BCS_Vitality)) )
  1620.             {
  1621.                 mutagen = playerAttacker.GetBuff(EET_Mutagen05);
  1622.                 dm.GetAbilityAttributeValue(mutagen.GetAbilityName(), 'damageIncrease', min, max);
  1623.                 powerMod += GetAttributeRandomizedValue(min, max);
  1624.             }
  1625.         }
  1626.            
  1627.         return powerMod;
  1628.     }
  1629.    
  1630.    
  1631.     private function GetDamageResists(dmgType : name, out resistPts : float, out resistPerc : float)
  1632.     {
  1633.         var armorReduction, armorReductionPerc, skillArmorReduction : SAbilityAttributeValue;
  1634.         var bonusReduct, bonusResist : float;
  1635.         var mutagenBuff : W3Mutagen28_Effect;
  1636.         var appliedOilName, vsMonsterResistReduction : name;
  1637.         var oils : array< W3Effect_Oil >;
  1638.         var i : int;
  1639.        
  1640.        
  1641.         if(attackAction && attackAction.IsActionMelee() && actorAttacker.GetInventory().IsItemFists(weaponId) && !actorVictim.UsesEssence())
  1642.             return;
  1643.            
  1644.        
  1645.         if(actorVictim)
  1646.         {
  1647.            
  1648.             actorVictim.GetResistValue( GetResistForDamage(dmgType, action.IsDoTDamage()), resistPts, resistPerc );
  1649.            
  1650.            
  1651.             if(playerVictim && actorAttacker && playerVictim.CanUseSkill(S_Alchemy_s05))
  1652.             {
  1653.                 GetOilProtectionAgainstMonster(dmgType, bonusResist, bonusReduct);
  1654.                
  1655.                 resistPerc += bonusResist * playerVictim.GetSkillLevel(S_Alchemy_s05);
  1656.             }
  1657.            
  1658.            
  1659.             if(playerVictim && actorAttacker && playerVictim.HasBuff(EET_Mutagen28))
  1660.             {
  1661.                 mutagenBuff = (W3Mutagen28_Effect)playerVictim.GetBuff(EET_Mutagen28);
  1662.                 mutagenBuff.GetProtection(attackerMonsterCategory, dmgType, action.IsDoTDamage(), bonusResist, bonusReduct);
  1663.                 resistPts += bonusReduct;
  1664.                 resistPerc += bonusResist;
  1665.             }
  1666.            
  1667.            
  1668.             if(actorAttacker)
  1669.             {
  1670.                
  1671.                 armorReduction = actorAttacker.GetAttributeValue('armor_reduction');
  1672.                 armorReductionPerc = actorAttacker.GetAttributeValue('armor_reduction_perc');
  1673.                
  1674.                
  1675.                 if(playerAttacker)
  1676.                 {
  1677.                     vsMonsterResistReduction = MonsterCategoryToResistReduction(victimMonsterCategory);
  1678.                     oils = playerAttacker.inv.GetOilsAppliedOnItem( weaponId );
  1679.                    
  1680.                     if( oils.Size() > 0 )
  1681.                     {
  1682.                         for( i=0; i<oils.Size(); i+=1 )
  1683.                         {
  1684.                             appliedOilName = oils[ i ].GetOilItemName();
  1685.                            
  1686.                            
  1687.                             if( oils[ i ].GetAmmoCurrentCount() > 0 && dm.ItemHasAttribute( appliedOilName, true, vsMonsterResistReduction ) )
  1688.                             {
  1689.                                 armorReductionPerc.valueMultiplicative += oils[ i ].GetAmmoPercentage();
  1690.                             }
  1691.                         }
  1692.                     }
  1693.                 }
  1694.                
  1695.                
  1696.                 if(playerAttacker && action.IsActionMelee() && playerAttacker.IsHeavyAttack(attackAction.GetAttackName()) && playerAttacker.CanUseSkill(S_Sword_2))
  1697.                     armorReduction += playerAttacker.GetSkillAttributeValue(S_Sword_2, 'armor_reduction', false, true);
  1698.                
  1699.                
  1700.                 if ( playerAttacker &&
  1701.                      action.IsActionMelee() && playerAttacker.IsHeavyAttack(attackAction.GetAttackName()) &&
  1702.                      ( dmgType == theGame.params.DAMAGE_NAME_PHYSICAL ||
  1703.                        dmgType == theGame.params.DAMAGE_NAME_SLASHING ||
  1704.                        dmgType == theGame.params.DAMAGE_NAME_PIERCING ||
  1705.                        dmgType == theGame.params.DAMAGE_NAME_BLUDGEONING ||
  1706.                        dmgType == theGame.params.DAMAGE_NAME_RENDING ||
  1707.                        dmgType == theGame.params.DAMAGE_NAME_SILVER
  1708.                      ) &&
  1709.                      playerAttacker.CanUseSkill(S_Sword_s06)
  1710.                    )
  1711.                 {
  1712.                    
  1713.                     skillArmorReduction = playerAttacker.GetSkillAttributeValue(S_Sword_s06, 'armor_reduction_perc', false, true);
  1714.                     armorReductionPerc += skillArmorReduction * playerAttacker.GetSkillLevel(S_Sword_s06);             
  1715.                 }
  1716.             }
  1717.         }
  1718.        
  1719.        
  1720.         if(!action.GetIgnoreArmor())
  1721.             resistPts += CalculateAttributeValue( actorVictim.GetTotalArmor() );
  1722.        
  1723.        
  1724.         resistPts = MaxF(0, resistPts - CalculateAttributeValue(armorReduction) );     
  1725.         resistPerc -= CalculateAttributeValue(armorReductionPerc);     
  1726.        
  1727.        
  1728.        
  1729.         resistPerc = MaxF(0, resistPerc);
  1730.     }
  1731.        
  1732.    
  1733.     private function CalculateDamage(dmgInfo : SRawDamage, powerMod : SAbilityAttributeValue) : float
  1734.     {
  1735.         var finalDamage, finalIncomingDamage : float;
  1736.         var resistPoints, resistPercents : float;
  1737.         var ptsString, percString : string;
  1738.         var mutagen : CBaseGameplayEffect;
  1739.         var min, max : SAbilityAttributeValue;
  1740.         var encumbranceBonus : float;
  1741.         var temp : bool;
  1742.         var fistfightDamageMult : float;
  1743.         var burning : W3Effect_Burning;
  1744.        
  1745.        
  1746.         var weaponName      : name;
  1747.         var dmgBonus        : float;
  1748.         var playerStlDmg    : float;
  1749.         var playerSlvDmg    : float;
  1750.         var playerFastSlvDmg: float;
  1751.         var playerSlvCritDmg: float;
  1752.         var multBonus       : float;
  1753.         var dmgLevel        : int;
  1754.         var curStats        : SPlayerOffenseStats;
  1755.         var inv             : CInventoryComponent;
  1756.        
  1757.    
  1758.        
  1759.         GetDamageResists(dmgInfo.dmgType, resistPoints, resistPercents);
  1760.    
  1761.        
  1762.         if( thePlayer.IsFistFightMinigameEnabled() && actorAttacker == thePlayer )
  1763.         {
  1764.             finalDamage = MaxF(0, (dmgInfo.dmgVal));
  1765.         }
  1766.         else
  1767.         {
  1768.            
  1769.             burning = (W3Effect_Burning)action.causer;
  1770.             if( burning && burning.IsSignEffect() )
  1771.             {
  1772.                 if ( powerMod.valueMultiplicative > 2.5f )
  1773.                 {
  1774.                     powerMod.valueMultiplicative = 2.5f + LogF( (powerMod.valueMultiplicative - 2.5f) + 1 );
  1775.                 }
  1776.             }
  1777.            
  1778.             finalDamage = MaxF(0, (dmgInfo.dmgVal + powerMod.valueBase) * powerMod.valueMultiplicative + powerMod.valueAdditive);
  1779.            
  1780.            
  1781.            
  1782.             inv = actorAttacker.GetInventory();
  1783.             weaponName = inv.GetItemName( weaponId );
  1784.             if( thePlayer.IsCiri() )
  1785.             {
  1786.                 dmgLevel = ( actorVictim.GetLevel() -2 ) * 10;
  1787.             }
  1788.             else
  1789.             {
  1790.                 dmgLevel = Min( actorVictim.GetLevel(), GetWitcherPlayer().GetLevel() ) * 40;
  1791.             }
  1792.            
  1793.             if( !playerAttacker && actorVictim && GetAttitudeBetween( thePlayer, actorAttacker ) == AIA_Friendly && !action.IsDoTDamage() && !actorAttacker.HasTag( 'Yennefer' ) && !actorAttacker.HasTag( 'keira' )
  1794.                 && !actorAttacker.HasTag( 'Philippa' ) && ( actorAttacker.IsWeaponHeld( 'silversword' ) || actorAttacker.IsWeaponHeld( 'staff2h' ) || weaponName == 'fists_lightning' || weaponName == 'fists_fire'
  1795.                 || actorAttacker.HasAbility( 'SkillWitcher' ) || actorAttacker.HasTag( 'zoltan' ) || actorAttacker.HasTag( 'hjalmar' ) || actorAttacker.HasTag( 'regis' ) || actorAttacker.HasBuff(EET_AxiiGuardMe) ) && ( finalDamage < dmgLevel || thePlayer.IsCiri() ) )
  1796.             {
  1797.                 dmgBonus += dmgLevel - finalDamage;
  1798.                 finalDamage = MaxF(0, (dmgInfo.dmgVal + powerMod.valueBase + dmgBonus) * powerMod.valueMultiplicative + powerMod.valueAdditive);
  1799.             }
  1800.            
  1801.         }
  1802.            
  1803.         finalIncomingDamage = finalDamage;
  1804.            
  1805.         if(finalDamage > 0.f)
  1806.         {
  1807.            
  1808.             if(!action.IsPointResistIgnored() && !(dmgInfo.dmgType == theGame.params.DAMAGE_NAME_ELEMENTAL || dmgInfo.dmgType == theGame.params.DAMAGE_NAME_FIRE || dmgInfo.dmgType == theGame.params.DAMAGE_NAME_FROST ))
  1809.             {
  1810.                 finalDamage = MaxF(0, finalDamage - resistPoints);
  1811.                
  1812.                 if(finalDamage == 0.f)
  1813.                     action.SetArmorReducedDamageToZero( true );
  1814.             }
  1815.         }
  1816.        
  1817.         if(finalDamage > 0.f)
  1818.         {
  1819.            
  1820.             if (playerVictim == GetWitcherPlayer() && playerVictim.HasBuff(EET_Mutagen02))
  1821.             {
  1822.                 encumbranceBonus = 1 - (GetWitcherPlayer().GetEncumbrance() / GetWitcherPlayer().GetMaxRunEncumbrance(temp));
  1823.                 if (encumbranceBonus < 0)
  1824.                     encumbranceBonus = 0;
  1825.                 mutagen = playerVictim.GetBuff(EET_Mutagen02);
  1826.                 dm.GetAbilityAttributeValue(mutagen.GetAbilityName(), 'resistGainRate', min, max);
  1827.                 encumbranceBonus *= CalculateAttributeValue(GetAttributeRandomizedValue(min, max));
  1828.                 resistPercents += encumbranceBonus;
  1829.             }
  1830.             finalDamage *= 1 - resistPercents;
  1831.         }  
  1832.  
  1833.  
  1834.  
  1835.        
  1836.        
  1837.         if( !playerAttacker && actorVictim && !action.IsDoTDamage() && !thePlayer.IsFistFightMinigameEnabled() && finalDamage <= actorVictim.GetMaxHealth() * 0.01 && (GetAttitudeBetween( thePlayer, actorAttacker ) == AIA_Friendly || actorAttacker.HasBuff(EET_AxiiGuardMe)) )
  1838.         {
  1839.             dmgBonus += dmgLevel - finalDamage;
  1840.             if ( powerMod.valueMultiplicative < 1.0 )
  1841.             {
  1842.                 multBonus = 1.0 - powerMod.valueMultiplicative;
  1843.             }
  1844.             finalDamage = MaxF(actorVictim.GetMaxHealth() * 0.01, (dmgInfo.dmgVal + powerMod.valueBase + dmgBonus) * ( powerMod.valueMultiplicative + multBonus ) + powerMod.valueAdditive);
  1845.            
  1846.             if(!action.IsPointResistIgnored() && !(dmgInfo.dmgType == theGame.params.DAMAGE_NAME_ELEMENTAL || dmgInfo.dmgType == theGame.params.DAMAGE_NAME_FIRE || dmgInfo.dmgType == theGame.params.DAMAGE_NAME_FROST ))
  1847.             {
  1848.                 finalDamage = MaxF(actorVictim.GetMaxHealth() * 0.01, finalDamage - resistPoints);
  1849.                
  1850.                 if(finalDamage == 0.f)
  1851.                     action.SetArmorReducedDamageToZero( true );
  1852.                 else
  1853.                     action.SetArmorReducedDamageToZero( false );
  1854.             }
  1855.            
  1856.             finalDamage *= 1 - resistPercents;
  1857.         }
  1858.        
  1859.        
  1860.         curStats = GetWitcherPlayer().GetOffenseStatsList();
  1861.         playerStlDmg = MaxF(0, curStats.steelStrongDmg - resistPoints);
  1862.         playerStlDmg *= 1 - resistPercents;
  1863.         playerStlDmg /= 6;
  1864.        
  1865.         playerFastSlvDmg = MaxF(0, curStats.silverFastDmg - resistPoints);
  1866.         playerFastSlvDmg *= 1 - resistPercents;
  1867.         playerFastSlvDmg /= 6;
  1868.  
  1869.         playerSlvDmg = MaxF(0, curStats.silverStrongDmg - resistPoints);
  1870.         playerSlvDmg *= 1 - resistPercents;
  1871.         playerSlvDmg /= 6;
  1872.        
  1873.         playerSlvCritDmg = MaxF(0, curStats.silverStrongCritDmg - resistPoints);
  1874.         playerSlvCritDmg *= 1 - resistPercents;
  1875.         playerSlvCritDmg /= 6;
  1876.        
  1877.         if( !playerAttacker && actorVictim && !action.IsDoTDamage() && !thePlayer.IsFistFightMinigameEnabled() && (GetAttitudeBetween( thePlayer, actorAttacker ) == AIA_Friendly || actorAttacker.HasBuff(EET_AxiiGuardMe)) && !thePlayer.IsCiri()  )
  1878.         {
  1879.             if(finalDamage > playerStlDmg && !actorAttacker.HasAbility( 'ForceInstantKill' ))
  1880.             {
  1881.                 if ( actorAttacker.HasTag( 'regis' ) )
  1882.                 {
  1883.                     if ( finalDamage > playerSlvCritDmg * 2 )
  1884.                     {
  1885.                         finalDamage = ClampF( finalDamage, 0, playerSlvCritDmg * 2 );
  1886.                         finalDamage = MaxF(actorVictim.GetMaxHealth() * 0.01, finalDamage);
  1887.                     }
  1888.                     if ( finalDamage < playerSlvCritDmg )
  1889.                     {
  1890.                         finalDamage = ClampF( finalDamage, playerSlvCritDmg, finalDamage );
  1891.                     }
  1892.                 }
  1893.                 else if ( actorAttacker.IsWeaponHeld( 'staff2h' ) || weaponName == 'fists_lightning' || weaponName == 'fists_fire' || action.GetPowerStatType() == CPS_SpellPower )
  1894.                 {
  1895.                     if ( finalDamage > playerSlvDmg * 2 )
  1896.                     {
  1897.                         finalDamage = ClampF( finalDamage, 0, playerSlvDmg );
  1898.                         finalDamage = MaxF(actorVictim.GetMaxHealth() * 0.01, finalDamage);
  1899.                     }
  1900.                    
  1901.                     if ( finalDamage < playerFastSlvDmg && attackAction )
  1902.                     {
  1903.                         finalDamage = ClampF( finalDamage, playerFastSlvDmg, finalDamage );
  1904.                     }
  1905.                 }
  1906.                 else if ( actorAttacker.IsWeaponHeld( 'silversword' ) || actorAttacker.HasAbility( 'SkillWitcher' ) || actorAttacker.HasBuff(EET_AxiiGuardMe) )
  1907.                 {
  1908.                     if ( finalDamage > playerSlvCritDmg )
  1909.                     {
  1910.                         finalDamage = ClampF( finalDamage, 0, playerSlvCritDmg );
  1911.                         finalDamage = MaxF(actorVictim.GetMaxHealth() * 0.01, finalDamage);
  1912.                     }
  1913.                     if ( action.IsActionMelee() )
  1914.                     {
  1915.                        
  1916.                         if ( finalDamage < playerSlvDmg && actorVictim.UsesEssence() )
  1917.                         {
  1918.                             finalDamage = ClampF( finalDamage, playerSlvDmg, finalDamage );
  1919.                         }
  1920.                         else if ( finalDamage < playerStlDmg )
  1921.                         {
  1922.                             finalDamage = ClampF( finalDamage, playerStlDmg, finalDamage );
  1923.                         }
  1924.                     }
  1925.                 }
  1926.                 else
  1927.                 {
  1928.                     finalDamage = ClampF( finalDamage, 0, playerStlDmg );
  1929.                     finalDamage = MaxF(actorVictim.GetMaxHealth() * 0.01, finalDamage);
  1930.                 }
  1931.             }
  1932.        
  1933.            
  1934.             if(thePlayer.GetBossTag() != '' || (W3MonsterHuntNPC)actorVictim || actorVictim.GetCharacterStats().HasAbilityWithTag('Boss') || actorVictim.HasAbility( 'Boss' ) || actorVictim.HasAbility( 'SkillBoss') )
  1935.             {
  1936.                 finalDamage = ClampF(finalDamage, 0, actorVictim.GetMaxHealth() * 0.005);
  1937.             }
  1938.         }
  1939.         if(actorAttacker.HasBuff(EET_AxiiGuardMe))
  1940.         {
  1941.             switch(GetWitcherPlayer().GetSkillLevel(S_Magic_s05))
  1942.             {
  1943.                 case 3:
  1944.                     finalDamage *= 1.6;
  1945.                     break;
  1946.                 case 2:
  1947.                     finalDamage *= 1.4;
  1948.                     break;
  1949.                 case 1:
  1950.                     finalDamage *= 1.2;
  1951.                     break;
  1952.             }
  1953.         }
  1954.        
  1955.    
  1956.        
  1957.         if(dmgInfo.dmgType == theGame.params.DAMAGE_NAME_FIRE && finalDamage > 0)
  1958.             action.SetDealtFireDamage(true);
  1959.            
  1960.         if( playerAttacker && thePlayer.IsWeaponHeld('fist') && !thePlayer.IsInFistFightMiniGame() && action.IsActionMelee() )
  1961.         {
  1962.             if(FactsQuerySum("NewGamePlus") > 0)
  1963.             {fistfightDamageMult = thePlayer.GetLevel()* 0.1;}
  1964.             else
  1965.             {fistfightDamageMult = thePlayer.GetLevel()* 0.05;}
  1966.            
  1967.             finalDamage *= ( 1+fistfightDamageMult );
  1968.         }
  1969.        
  1970.         if(playerAttacker && attackAction && playerAttacker.IsHeavyAttack(attackAction.GetAttackName()))
  1971.             finalDamage *= 1.833;
  1972.            
  1973.        
  1974.         burning = (W3Effect_Burning)action.causer;
  1975.         if(actorVictim && (((W3IgniEntity)action.causer) || ((W3IgniProjectile)action.causer) || ( burning && burning.IsSignEffect())) )
  1976.         {
  1977.             min = actorVictim.GetAttributeValue('igni_damage_amplifier');
  1978.             finalDamage = finalDamage * (1 + min.valueMultiplicative) + min.valueAdditive;
  1979.         }
  1980.        
  1981.        
  1982.        
  1983.        
  1984.         if ( theGame.CanLog() )
  1985.         {
  1986.             LogDMHits("Single hit damage: initial damage = " + NoTrailZeros(dmgInfo.dmgVal), action);
  1987.             LogDMHits("Single hit damage: attack_power = base: " + NoTrailZeros(powerMod.valueBase) + ", mult: " + NoTrailZeros(powerMod.valueMultiplicative) + ", add: " + NoTrailZeros(powerMod.valueAdditive), action );
  1988.             if(action.IsPointResistIgnored())
  1989.                 LogDMHits("Single hit damage: resistance pts and armor = IGNORED", action);
  1990.             else
  1991.                 LogDMHits("Single hit damage: resistance pts and armor = " + NoTrailZeros(resistPoints), action);          
  1992.             LogDMHits("Single hit damage: resistance perc = " + NoTrailZeros(resistPercents * 100), action);
  1993.             LogDMHits("Single hit damage: final damage to sustain = " + NoTrailZeros(finalDamage), action);
  1994.         }
  1995.        
  1996.        
  1997.         if( playerVictim && actorAttacker && FactsQuerySum("NewGamePlus") > 0)
  1998.             finalDamage *= 1.1;
  1999.        
  2000.            
  2001.         return finalDamage;
  2002.     }
  2003.    
  2004.    
  2005.     private function ProcessActionDamage_DealDamage()
  2006.     {
  2007.         var logStr : string;
  2008.         var hpPerc : float;
  2009.         var npcVictim : CNewNPC;
  2010.    
  2011.        
  2012.         if ( theGame.CanLog() )
  2013.         {
  2014.             logStr = "";
  2015.             if(action.processedDmg.vitalityDamage > 0)          logStr += NoTrailZeros(action.processedDmg.vitalityDamage) + " vitality, ";
  2016.             if(action.processedDmg.essenceDamage > 0)           logStr += NoTrailZeros(action.processedDmg.essenceDamage) + " essence, ";
  2017.             if(action.processedDmg.staminaDamage > 0)           logStr += NoTrailZeros(action.processedDmg.staminaDamage) + " stamina, ";
  2018.             if(action.processedDmg.moraleDamage > 0)            logStr += NoTrailZeros(action.processedDmg.moraleDamage) + " morale";
  2019.                
  2020.             if(logStr == "")
  2021.                 logStr = "NONE";
  2022.             LogDMHits("Final damage to sustain is: " + logStr, action);
  2023.         }
  2024.                
  2025.        
  2026.         if(actorVictim)
  2027.         {
  2028.             hpPerc = actorVictim.GetHealthPercents();
  2029.            
  2030.            
  2031.             if(actorVictim.IsAlive())
  2032.             {
  2033.                 npcVictim = (CNewNPC)actorVictim;
  2034.                 if(npcVictim && npcVictim.IsHorse())
  2035.                 {
  2036.                     npcVictim.GetHorseComponent().OnTakeDamage(action);
  2037.                 }
  2038.                 else
  2039.                 {
  2040.                     actorVictim.OnTakeDamage(action);
  2041.                 }
  2042.             }
  2043.            
  2044.             if(!actorVictim.IsAlive() && hpPerc == 1)
  2045.                 action.SetWasKilledBySingleHit();
  2046.         }
  2047.            
  2048.         if ( theGame.CanLog() )
  2049.         {
  2050.             LogDMHits("", action);
  2051.             LogDMHits("Target stats after damage dealt are:", action);
  2052.             if(actorVictim)
  2053.             {
  2054.                 if( actorVictim.UsesVitality())                     LogDMHits("Vitality = " + NoTrailZeros( actorVictim.GetStat(BCS_Vitality)), action);
  2055.                 if( actorVictim.UsesEssence())                      LogDMHits("Essence = "  + NoTrailZeros( actorVictim.GetStat(BCS_Essence)), action);
  2056.                 if( actorVictim.GetStatMax(BCS_Stamina) > 0)        LogDMHits("Stamina = "  + NoTrailZeros( actorVictim.GetStat(BCS_Stamina, true)), action);
  2057.                 if( actorVictim.GetStatMax(BCS_Morale) > 0)         LogDMHits("Morale = "   + NoTrailZeros( actorVictim.GetStat(BCS_Morale)), action);
  2058.             }
  2059.             else
  2060.             {
  2061.                 LogDMHits("Undefined - victim is not a CActor and therefore has no stats", action);
  2062.             }
  2063.         }
  2064.     }
  2065.    
  2066.    
  2067.     private function ProcessActionDamage_ReduceDurability()
  2068.     {      
  2069.         var witcherPlayer : W3PlayerWitcher;
  2070.         var dbg_currDur, dbg_prevDur1, dbg_prevDur2, dbg_prevDur3, dbg_prevDur4, dbg_prevDur : float;
  2071.         var dbg_armor, dbg_pants, dbg_boots, dbg_gloves, reducedItemId, weapon : SItemUniqueId;
  2072.         var slot : EEquipmentSlots;
  2073.         var weapons : array<SItemUniqueId>;
  2074.         var armorStringName : string;
  2075.         var canLog, playerHasSword : bool;
  2076.         var i : int;
  2077.        
  2078.         canLog = theGame.CanLog();
  2079.  
  2080.         witcherPlayer = GetWitcherPlayer();
  2081.    
  2082.        
  2083.         if ( playerAttacker && playerAttacker.inv.IsIdValid( weaponId ) && playerAttacker.inv.HasItemDurability( weaponId ) )
  2084.         {      
  2085.             dbg_prevDur = playerAttacker.inv.GetItemDurability(weaponId);
  2086.                        
  2087.             if ( playerAttacker.inv.ReduceItemDurability(weaponId) && canLog )
  2088.             {
  2089.                 LogDMHits("", action);
  2090.                 LogDMHits("Player's weapon durability changes from " + NoTrailZeros(dbg_prevDur) + " to " + NoTrailZeros(action.attacker.GetInventory().GetItemDurability(weaponId)), action );
  2091.             }
  2092.         }
  2093.        
  2094.         else if(playerVictim && attackAction && attackAction.IsActionMelee() && (attackAction.IsParried() || attackAction.IsCountered()) )
  2095.         {
  2096.             weapons = playerVictim.inv.GetHeldWeapons();
  2097.             playerHasSword = false;
  2098.             for(i=0; i<weapons.Size(); i+=1)
  2099.             {
  2100.                 weapon = weapons[i];
  2101.                 if(playerVictim.inv.IsIdValid(weapon) && (playerVictim.inv.IsItemSteelSwordUsableByPlayer(weapon) || playerVictim.inv.IsItemSilverSwordUsableByPlayer(weapon)) )
  2102.                 {
  2103.                     playerHasSword = true;
  2104.                     break;
  2105.                 }
  2106.             }
  2107.            
  2108.             if(playerHasSword)
  2109.             {
  2110.                 playerVictim.inv.ReduceItemDurability(weapon);
  2111.             }
  2112.         }
  2113.        
  2114.         else if(action.victim == witcherPlayer && (action.IsActionMelee() || action.IsActionRanged()) && action.DealsAnyDamage())
  2115.         {
  2116.            
  2117.             if ( canLog )
  2118.             {
  2119.                 if ( witcherPlayer.GetItemEquippedOnSlot(EES_Armor, dbg_armor) )
  2120.                     dbg_prevDur1 = action.victim.GetInventory().GetItemDurability(dbg_armor);
  2121.                 else
  2122.                     dbg_prevDur1 = 0;
  2123.                    
  2124.                 if ( witcherPlayer.GetItemEquippedOnSlot(EES_Pants, dbg_pants) )
  2125.                     dbg_prevDur2 = action.victim.GetInventory().GetItemDurability(dbg_pants);
  2126.                 else
  2127.                     dbg_prevDur2 = 0;
  2128.                    
  2129.                 if ( witcherPlayer.GetItemEquippedOnSlot(EES_Boots, dbg_boots) )
  2130.                     dbg_prevDur3 = action.victim.GetInventory().GetItemDurability(dbg_boots);
  2131.                 else
  2132.                     dbg_prevDur3 = 0;
  2133.                    
  2134.                 if ( witcherPlayer.GetItemEquippedOnSlot(EES_Gloves, dbg_gloves) )
  2135.                     dbg_prevDur4 = action.victim.GetInventory().GetItemDurability(dbg_gloves);
  2136.                 else
  2137.                     dbg_prevDur4 = 0;
  2138.             }
  2139.            
  2140.             slot = GetWitcherPlayer().ReduceArmorDurability();
  2141.            
  2142.            
  2143.             if( canLog )
  2144.             {
  2145.                 LogDMHits("", action);
  2146.                 if(slot != EES_InvalidSlot)
  2147.                 {      
  2148.                     switch(slot)
  2149.                     {
  2150.                         case EES_Armor :
  2151.                             armorStringName = "chest armor";
  2152.                             reducedItemId = dbg_armor;
  2153.                             dbg_prevDur = dbg_prevDur1;
  2154.                             break;
  2155.                         case EES_Pants :
  2156.                             armorStringName = "pants";
  2157.                             reducedItemId = dbg_pants;
  2158.                             dbg_prevDur = dbg_prevDur2;
  2159.                             break;
  2160.                         case EES_Boots :
  2161.                             armorStringName = "boots";
  2162.                             reducedItemId = dbg_boots;
  2163.                             dbg_prevDur = dbg_prevDur3;
  2164.                             break;
  2165.                         case EES_Gloves :
  2166.                             armorStringName = "gloves";
  2167.                             reducedItemId = dbg_gloves;
  2168.                             dbg_prevDur = dbg_prevDur4;
  2169.                             break;
  2170.                     }
  2171.                    
  2172.                     dbg_currDur = action.victim.GetInventory().GetItemDurability(reducedItemId);
  2173.                     LogDMHits("", action);
  2174.                     LogDMHits("Player's <<" + armorStringName + ">> durability changes from " + NoTrailZeros(dbg_prevDur) + " to " + NoTrailZeros(dbg_currDur), action );
  2175.                 }
  2176.                 else
  2177.                 {
  2178.                     LogDMHits("Tried to reduce player's armor durability but failed", action);
  2179.                 }
  2180.             }
  2181.                
  2182.            
  2183.             if(slot != EES_InvalidSlot)
  2184.                 thePlayer.inv.ReduceItemRepairObjectBonusCharge(reducedItemId);
  2185.         }
  2186.     }  
  2187.    
  2188.    
  2189.    
  2190.    
  2191.    
  2192.    
  2193.     private function ProcessActionReaction(wasFrozen : bool, wasAlive : bool)
  2194.     {
  2195.         var dismemberExplosion          : bool;
  2196.         var damageName                  : name;
  2197.         var damage                      : array<SRawDamage>;
  2198.         var points, percents, hp, dmg   : float;
  2199.         var counterAction               : W3DamageAction;      
  2200.         var moveTargets                 : array<CActor>;
  2201.         var i                           : int;
  2202.         var canPerformFinisher          : bool;
  2203.         var weaponName                  : name;
  2204.         var npcVictim                   : CNewNPC;
  2205.         var toxicCloud                  : W3ToxicCloud;
  2206.         var playsNonAdditiveAnim        : bool;
  2207.         var bleedCustomEffect           : SCustomEffectParams;
  2208.        
  2209.        
  2210.         var min, max                    : SAbilityAttributeValue;
  2211.         var minDmg                      : float;
  2212.        
  2213.        
  2214.         if(!actorVictim)
  2215.             return;
  2216.        
  2217.         npcVictim = (CNewNPC)actorVictim;
  2218.        
  2219.         canPerformFinisher = CanPerformFinisher(actorVictim);
  2220.        
  2221.         if( actorVictim.IsAlive() && !canPerformFinisher )
  2222.         {
  2223.            
  2224.             if(!action.IsDoTDamage() && action.DealtDamage())
  2225.             {
  2226.                 if ( actorAttacker && npcVictim)
  2227.                 {
  2228.                     npcVictim.NoticeActorInGuardArea( actorAttacker );
  2229.                 }
  2230.  
  2231.                
  2232.                 if ( !playerVictim )
  2233.                     actorVictim.RemoveAllBuffsOfType(EET_Confusion);
  2234.                
  2235.                
  2236.                 if(playerAttacker && action.IsActionMelee() && !playerAttacker.GetInventory().IsItemFists(weaponId) && playerAttacker.IsLightAttack(attackAction.GetAttackName()) && playerAttacker.CanUseSkill(S_Sword_s05))
  2237.                 {
  2238.                     bleedCustomEffect.effectType = EET_Bleeding;
  2239.                     bleedCustomEffect.creator = playerAttacker;
  2240.                     bleedCustomEffect.sourceName = SkillEnumToName(S_Sword_s05);
  2241.                    
  2242.                    
  2243.                    
  2244.                     theGame.GetDefinitionsManager().GetAbilityAttributeValue( 'BleedingEffect', 'DirectDamage', min, max );
  2245.                     bleedCustomEffect.effectValue = min;
  2246.                     minDmg = CalculateAttributeValue(playerAttacker.GetSkillAttributeValue(S_Sword_s05, 'dmg_per_sec', false, true)) * playerAttacker.GetSkillLevel(S_Sword_s05);
  2247.                     dmg = bleedCustomEffect.effectValue.valueAdditive + (bleedCustomEffect.effectValue.valueMultiplicative * actorVictim.GetMaxHealth());
  2248.                    
  2249.                     if ( dmg < minDmg )
  2250.                     {
  2251.                         bleedCustomEffect.effectValue.valueAdditive += minDmg - dmg;
  2252.                     }
  2253.                    
  2254.                    
  2255.                    
  2256.                     actorVictim.AddEffectCustom(bleedCustomEffect);
  2257.                 }
  2258.             }
  2259.            
  2260.            
  2261.             if(actorVictim && wasAlive)
  2262.             {
  2263.                 playsNonAdditiveAnim = actorVictim.ReactToBeingHit( action );
  2264.             }              
  2265.         }
  2266.         else
  2267.         {
  2268.            
  2269.             if( !canPerformFinisher && CanDismember( wasFrozen, dismemberExplosion, weaponName ) )
  2270.             {
  2271.                 ProcessDismemberment(wasFrozen, dismemberExplosion);
  2272.                 toxicCloud = (W3ToxicCloud)action.causer;
  2273.                
  2274.                 if(toxicCloud && toxicCloud.HasExplodingTargetDamages())
  2275.                     ProcessToxicCloudDismemberExplosion(toxicCloud.GetExplodingTargetDamages());
  2276.                    
  2277.                
  2278.                 if(IsRequiredAttitudeBetween(thePlayer, action.victim, true))
  2279.                 {
  2280.                     moveTargets = thePlayer.GetMoveTargets();
  2281.                     for ( i = 0; i < moveTargets.Size(); i += 1 )
  2282.                     {
  2283.                         if ( moveTargets[i].IsHuman() )
  2284.                             moveTargets[i].DrainMorale(20.f);
  2285.                     }
  2286.                 }
  2287.             }
  2288.            
  2289.             else if ( canPerformFinisher )
  2290.             {
  2291.                 if ( actorVictim.IsAlive() )
  2292.                     actorVictim.Kill( 'Finisher', false, thePlayer );
  2293.                    
  2294.                 thePlayer.AddTimer( 'DelayedFinisherInputTimer', 0.1f );
  2295.                 thePlayer.SetFinisherVictim( actorVictim );
  2296.                 thePlayer.CleanCombatActionBuffer();
  2297.                 thePlayer.OnBlockAllCombatTickets( true );
  2298.                
  2299.                 if( actorVictim.WillBeUnconscious() )
  2300.                 {
  2301.                     actorVictim.SetBehaviorVariable( 'prepareForUnconsciousFinisher', 1.0f );
  2302.                     actorVictim.ActionRotateToAsync( thePlayer.GetWorldPosition() );
  2303.                 }
  2304.                
  2305.                 moveTargets = thePlayer.GetMoveTargets();
  2306.                
  2307.                 for ( i = 0; i < moveTargets.Size(); i += 1 )
  2308.                 {
  2309.                     if ( actorVictim != moveTargets[i] )
  2310.                         moveTargets[i].SignalGameplayEvent( 'InterruptChargeAttack' );
  2311.                 }  
  2312.                
  2313.                 if  (   theGame.GetInGameConfigWrapper().GetVarValue('Gameplay', 'AutomaticFinishersEnabled' ) == "true"
  2314.                     || ( (W3PlayerWitcher)playerAttacker && GetWitcherPlayer().IsMutationActive( EPMT_Mutation3 ) )
  2315.                     ||  actorVictim.WillBeUnconscious()
  2316.                     )
  2317.                 {
  2318.                     actorVictim.AddAbility( 'ForceFinisher', false );
  2319.                 }
  2320.                
  2321.                 if ( actorVictim.HasTag( 'ForceFinisher' ) )
  2322.                     actorVictim.AddAbility( 'ForceFinisher', false );
  2323.                
  2324.                 actorVictim.SignalGameplayEvent( 'ForceFinisher' );
  2325.             }
  2326.             else if ( weaponName == 'fists' && npcVictim )
  2327.             {
  2328.                 npcVictim.DisableAgony();  
  2329.             }
  2330.            
  2331.             thePlayer.FindMoveTarget();
  2332.         }
  2333.        
  2334.         if( attackAction.IsActionMelee() )
  2335.         {
  2336.             actorAttacker.SignalGameplayEventParamObject( 'HitActionReaction', actorVictim );
  2337.             actorVictim.OnHitActionReaction( actorAttacker, weaponName );
  2338.         }
  2339.        
  2340.        
  2341.         actorVictim.ProcessHitSound(action, playsNonAdditiveAnim || !actorVictim.IsAlive());
  2342.        
  2343.        
  2344.        
  2345.         if(action.IsCriticalHit() && action.DealtDamage() && !actorVictim.IsAlive() && actorAttacker == thePlayer )
  2346.             GCameraShake( 0.5, true, actorAttacker.GetWorldPosition(), 10 );
  2347.        
  2348.        
  2349.         if( attackAction && npcVictim && npcVictim.IsShielded( actorAttacker ) && attackAction.IsParried() && attackAction.GetAttackName() == 'attack_heavy' &&  npcVictim.GetStaminaPercents() <= 0.1 )
  2350.         {
  2351.             npcVictim.ProcessShieldDestruction();
  2352.         }
  2353.        
  2354.        
  2355.         if( actorVictim && action.CanPlayHitParticle() && ( action.DealsAnyDamage() || (attackAction && attackAction.IsParried()) ) )
  2356.             actorVictim.PlayHitEffect(action);
  2357.            
  2358.  
  2359.         if( action.victim.HasAbility('mon_nekker_base') && !actorVictim.CanPlayHitAnim() && !((CBaseGameplayEffect) action.causer) )
  2360.         {
  2361.            
  2362.             actorVictim.PlayEffect(theGame.params.LIGHT_HIT_FX);
  2363.             actorVictim.SoundEvent("cmb_play_hit_light");
  2364.         }
  2365.            
  2366.        
  2367.         if(actorVictim && playerAttacker && action.IsActionMelee() && thePlayer.inv.IsItemFists(weaponId) )
  2368.         {
  2369.             actorVictim.SignalGameplayEvent( 'wasHitByFists' );
  2370.                
  2371.             if(MonsterCategoryIsMonster(victimMonsterCategory))
  2372.             {
  2373.                 if(!victimCanBeHitByFists)
  2374.                 {
  2375.                     playerAttacker.ReactToReflectedAttack(actorVictim);
  2376.                 }
  2377.                 else
  2378.                 {          
  2379.                     actorVictim.GetResistValue(CDS_PhysicalRes, points, percents);
  2380.                
  2381.                     if(percents >= theGame.params.MONSTER_RESIST_THRESHOLD_TO_REFLECT_FISTS)
  2382.                         playerAttacker.ReactToReflectedAttack(actorVictim);
  2383.                 }
  2384.             }          
  2385.         }
  2386.        
  2387.        
  2388.         ProcessSparksFromNoDamage();
  2389.        
  2390.        
  2391.         if(attackAction && attackAction.IsActionMelee() && actorAttacker && playerVictim && attackAction.IsCountered() && playerVictim == GetWitcherPlayer())
  2392.         {
  2393.             GetWitcherPlayer().SetRecentlyCountered(true);
  2394.         }
  2395.        
  2396.        
  2397.        
  2398.        
  2399.         if(attackAction && !action.IsDoTDamage() && (playerAttacker || playerVictim) && (attackAction.IsParried() || attackAction.IsCountered()) )
  2400.         {
  2401.             theGame.VibrateControllerLight();
  2402.         }
  2403.     }
  2404.    
  2405.     private function CanDismember( wasFrozen : bool, out dismemberExplosion : bool, out weaponName : name ) : bool
  2406.     {
  2407.         var dismember           : bool;
  2408.         var dismemberChance     : int;
  2409.         var petard              : W3Petard;
  2410.         var bolt                : W3BoltProjectile;
  2411.         var arrow               : W3ArrowProjectile;
  2412.         var inv                 : CInventoryComponent;
  2413.         var toxicCloud          : W3ToxicCloud;
  2414.         var witcher             : W3PlayerWitcher;
  2415.         var i                   : int;
  2416.         var secondaryWeapon     : bool;
  2417.  
  2418.         petard = (W3Petard)action.causer;
  2419.         bolt = (W3BoltProjectile)action.causer;
  2420.         arrow = (W3ArrowProjectile)action.causer;
  2421.         toxicCloud = (W3ToxicCloud)action.causer;
  2422.        
  2423.         dismemberExplosion = false;
  2424.        
  2425.         if(playerAttacker)
  2426.         {
  2427.             secondaryWeapon = playerAttacker.inv.ItemHasTag( weaponId, 'SecondaryWeapon' ) || playerAttacker.inv.ItemHasTag( weaponId, 'Wooden' );
  2428.         }
  2429.        
  2430.         if( actorVictim.HasAbility( 'DisableDismemberment' ) )
  2431.         {
  2432.             dismember = false;
  2433.         }
  2434.         else if( actorVictim.HasTag( 'DisableDismemberment' ) )
  2435.         {
  2436.             dismember = false;
  2437.         }
  2438.         else if (actorVictim.WillBeUnconscious())
  2439.         {
  2440.             dismember = false;     
  2441.         }
  2442.         else if (playerAttacker && secondaryWeapon )
  2443.         {
  2444.             dismember = false;
  2445.         }
  2446.         else if( arrow && !wasFrozen )
  2447.         {
  2448.             dismember = false;
  2449.         }      
  2450.         else if( actorAttacker.HasAbility( 'ForceDismemberment' ) )
  2451.         {
  2452.             dismember = true;
  2453.             dismemberExplosion = action.HasForceExplosionDismemberment();
  2454.         }
  2455.         else if(wasFrozen)
  2456.         {
  2457.             dismember = true;
  2458.             dismemberExplosion = action.HasForceExplosionDismemberment();
  2459.         }                      
  2460.         else if( (petard && petard.DismembersOnKill()) || (bolt && bolt.DismembersOnKill()) )
  2461.         {
  2462.             dismember = true;
  2463.             dismemberExplosion = action.HasForceExplosionDismemberment();
  2464.         }
  2465.         else if( (W3Effect_YrdenHealthDrain)action.causer )
  2466.         {
  2467.             dismember = true;
  2468.             dismemberExplosion = true;
  2469.         }
  2470.         else if(toxicCloud && toxicCloud.HasExplodingTargetDamages())
  2471.         {
  2472.             dismember = true;
  2473.             dismemberExplosion = true;
  2474.         }
  2475.         else
  2476.         {
  2477.             inv = actorAttacker.GetInventory();
  2478.             weaponName = inv.GetItemName( weaponId );
  2479.            
  2480.             if( attackAction
  2481.                 && !inv.IsItemSteelSwordUsableByPlayer(weaponId)
  2482.                 && !inv.IsItemSilverSwordUsableByPlayer(weaponId)
  2483.                 && weaponName != 'polearm'
  2484.                 && weaponName != 'fists_lightning'
  2485.                 && weaponName != 'fists_fire' )
  2486.             {
  2487.                 dismember = false;
  2488.             }          
  2489.             else if ( action.IsCriticalHit() )
  2490.             {
  2491.                 dismember = true;
  2492.                 dismemberExplosion = action.HasForceExplosionDismemberment();
  2493.             }
  2494.             else if ( action.HasForceExplosionDismemberment() )
  2495.             {
  2496.                 dismember = true;
  2497.                 dismemberExplosion = true;
  2498.             }
  2499.            
  2500.             else if ( weaponName == 'fists_lightning' || weaponName == 'fists_fire' )
  2501.             {
  2502.                 if(RandRange(100) > 75)
  2503.                     dismember = true;
  2504.             }
  2505.            
  2506.             else
  2507.             {
  2508.                
  2509.                 dismemberChance = theGame.params.DISMEMBERMENT_ON_DEATH_CHANCE;
  2510.                
  2511.                
  2512.                 if(playerAttacker && playerAttacker.forceDismember)
  2513.                 {
  2514.                     dismemberChance = thePlayer.forceDismemberChance;
  2515.                     dismemberExplosion = thePlayer.forceDismemberExplosion;
  2516.                 }
  2517.                
  2518.                
  2519.                 if(attackAction)
  2520.                 {
  2521.                     dismemberChance += RoundMath(100 * CalculateAttributeValue(inv.GetItemAttributeValue(weaponId, 'dismember_chance')));
  2522.                     dismemberExplosion = attackAction.HasForceExplosionDismemberment();
  2523.                 }
  2524.                    
  2525.                
  2526.                 witcher = (W3PlayerWitcher)actorAttacker;
  2527.                 if(witcher && witcher.CanUseSkill(S_Perk_03))
  2528.                     dismemberChance += RoundMath(100 * CalculateAttributeValue(witcher.GetSkillAttributeValue(S_Perk_03, 'dismember_chance', false, true)));
  2529.                
  2530.                
  2531.                 if( ( W3PlayerWitcher )playerAttacker && attackAction.IsActionMelee() && GetWitcherPlayer().IsMutationActive(EPMT_Mutation3) ) 
  2532.                 {
  2533.                     if( thePlayer.inv.IsItemSteelSwordUsableByPlayer( weaponId ) || thePlayer.inv.IsItemSilverSwordUsableByPlayer( weaponId ) )
  2534.                     {
  2535.                         dismemberChance = 100;
  2536.                     }
  2537.                 }
  2538.                
  2539.                 dismemberChance = Clamp(dismemberChance, 0, 100);
  2540.                
  2541.                 if (RandRange(100) < dismemberChance)
  2542.                     dismember = true;
  2543.                 else
  2544.                     dismember = false;
  2545.             }
  2546.         }      
  2547.  
  2548.         return dismember;
  2549.     }  
  2550.    
  2551.     private function CanPerformFinisher( actorVictim : CActor ) : bool
  2552.     {
  2553.         var finisherChance          : int;
  2554.         var areEnemiesAttacking     : bool;
  2555.         var i                       : int;
  2556.         var victimToPlayerVector, playerPos : Vector;
  2557.         var item                    : SItemUniqueId;
  2558.         var moveTargets             : array<CActor>;
  2559.         var b                       : bool;
  2560.         var size                    : int;
  2561.         var npc                     : CNewNPC;
  2562.        
  2563.         if ( (W3ReplacerCiri)thePlayer || playerVictim || thePlayer.isInFinisher )
  2564.             return false;
  2565.        
  2566.         if ( actorVictim.IsAlive() && !CanPerformFinisherOnAliveTarget(actorVictim) )
  2567.             return false;
  2568.        
  2569.        
  2570.         if ( actorVictim.WillBeUnconscious() && !theGame.GetDLCManager().IsEP2Available() )
  2571.             return false;
  2572.        
  2573.         moveTargets = thePlayer.GetMoveTargets();  
  2574.         size = moveTargets.Size();
  2575.         playerPos = thePlayer.GetWorldPosition();
  2576.    
  2577.         if ( size > 0 )
  2578.         {
  2579.             areEnemiesAttacking = false;           
  2580.             for(i=0; i<size; i+=1)
  2581.             {
  2582.                 npc = (CNewNPC)moveTargets[i];
  2583.                 if(npc && VecDistanceSquared(playerPos, moveTargets[i].GetWorldPosition()) < 7 && npc.IsAttacking() && npc != actorVictim )
  2584.                 {
  2585.                     areEnemiesAttacking = true;
  2586.                     break;
  2587.                 }
  2588.             }
  2589.         }
  2590.        
  2591.         victimToPlayerVector = actorVictim.GetWorldPosition() - playerPos;
  2592.        
  2593.         if ( actorVictim.IsHuman() )
  2594.         {
  2595.             npc = (CNewNPC)actorVictim;
  2596.             if ( ( size <= 1 && theGame.params.FINISHER_ON_DEATH_CHANCE > 0 ) || ( actorVictim.HasAbility('ForceFinisher') ) || ( GetWitcherPlayer().IsMutationActive(EPMT_Mutation3) ) )
  2597.             {
  2598.                 finisherChance = 100;
  2599.             }
  2600.             else if ( ( actorVictim.HasBuff(EET_Confusion) || actorVictim.HasBuff(EET_AxiiGuardMe) ) )
  2601.             {
  2602.                 finisherChance = 75 + ( - ( npc.currentLevel - thePlayer.GetLevel() ) );
  2603.             }
  2604.             else if ( npc.currentLevel - thePlayer.GetLevel() < -5 )
  2605.             {
  2606.                 finisherChance = theGame.params.FINISHER_ON_DEATH_CHANCE + ( - ( npc.currentLevel - thePlayer.GetLevel() ) );
  2607.             }
  2608.             else
  2609.                 finisherChance = theGame.params.FINISHER_ON_DEATH_CHANCE;
  2610.                
  2611.             finisherChance = Clamp(finisherChance, 0, 100);
  2612.         }
  2613.         else
  2614.             finisherChance = 0;
  2615.            
  2616.         if ( actorVictim.HasTag('ForceFinisher') )
  2617.         {
  2618.             finisherChance = 100;
  2619.             areEnemiesAttacking = false;
  2620.         }
  2621.            
  2622.         item = thePlayer.inv.GetItemFromSlot( 'l_weapon' );
  2623.        
  2624.         if ( thePlayer.forceFinisher )
  2625.         {
  2626.             b = playerAttacker && attackAction && attackAction.IsActionMelee();
  2627.             b = b && ( actorVictim.IsHuman() && !actorVictim.IsWoman() );
  2628.             b = b && !thePlayer.IsInAir();
  2629.             b = b && ( thePlayer.IsWeaponHeld( 'steelsword') || thePlayer.IsWeaponHeld( 'silversword') );
  2630.             b = b && !thePlayer.IsSecondaryWeaponHeld();
  2631.             b = b && !thePlayer.inv.IsIdValid( item );
  2632.             b = b && !actorVictim.IsKnockedUnconscious();
  2633.             b = b && !actorVictim.HasBuff( EET_Knockdown );
  2634.             b = b && !actorVictim.HasBuff( EET_Ragdoll );
  2635.             b = b && !actorVictim.HasBuff( EET_Frozen );
  2636.             b = b && !actorVictim.HasAbility( 'DisableFinishers' );
  2637.             b = b && !thePlayer.IsUsingVehicle();
  2638.             b = b && thePlayer.IsAlive();
  2639.             b = b && !thePlayer.IsCurrentSignChanneled();
  2640.         }
  2641.         else
  2642.         {
  2643.             b = playerAttacker && attackAction && attackAction.IsActionMelee();
  2644.             b = b && ( actorVictim.IsHuman() && !actorVictim.IsWoman() );
  2645.             b = b && RandRange(100) < finisherChance;
  2646.             b = b && !areEnemiesAttacking;
  2647.             b = b && AbsF( victimToPlayerVector.Z ) < 0.4f;
  2648.             b = b && !thePlayer.IsInAir();
  2649.             b = b && ( thePlayer.IsWeaponHeld( 'steelsword') || thePlayer.IsWeaponHeld( 'silversword') );
  2650.             b = b && !thePlayer.IsSecondaryWeaponHeld();
  2651.             b = b && !thePlayer.inv.IsIdValid( item );
  2652.             b = b && !actorVictim.IsKnockedUnconscious();
  2653.             b = b && !actorVictim.HasBuff( EET_Knockdown );
  2654.             b = b && !actorVictim.HasBuff( EET_Ragdoll );
  2655.             b = b && !actorVictim.HasBuff( EET_Frozen );
  2656.             b = b && !actorVictim.HasAbility( 'DisableFinishers' );
  2657.             b = b && actorVictim.GetAttitude( thePlayer ) == AIA_Hostile;
  2658.             b = b && !thePlayer.IsUsingVehicle();
  2659.             b = b && thePlayer.IsAlive();
  2660.             b = b && !thePlayer.IsCurrentSignChanneled();
  2661.             b = b && ( theGame.GetWorld().NavigationCircleTest( actorVictim.GetWorldPosition(), 2.f ) || actorVictim.HasTag('ForceFinisher') ) ;
  2662.            
  2663.         }
  2664.  
  2665.         if ( b  )
  2666.         {
  2667.             if ( !actorVictim.IsAlive() && !actorVictim.WillBeUnconscious() )
  2668.                 actorVictim.AddAbility( 'DisableFinishers', false );
  2669.                
  2670.             return true;
  2671.         }
  2672.        
  2673.         return false;
  2674.     }
  2675.    
  2676.     private function CanPerformFinisherOnAliveTarget( actorVictim : CActor ) : bool
  2677.     {
  2678.         return actorVictim.IsHuman()
  2679.         && ( actorVictim.HasBuff(EET_Confusion) || actorVictim.HasBuff(EET_AxiiGuardMe) )
  2680.         && actorVictim.IsVulnerable()
  2681.         && !actorVictim.HasAbility('DisableFinisher')
  2682.         && !actorVictim.HasAbility('InstantKillImmune');
  2683.     }
  2684.    
  2685.    
  2686.    
  2687.    
  2688.    
  2689.    
  2690.     private function ProcessActionBuffs() : bool
  2691.     {
  2692.         var inv : CInventoryComponent;
  2693.         var ret : bool;
  2694.    
  2695.        
  2696.         if(!action.victim.IsAlive() || action.WasDodged() || (attackAction && attackAction.IsActionMelee() && !attackAction.ApplyBuffsIfParried() && attackAction.CanBeParried() && attackAction.IsParried()) )
  2697.             return true;
  2698.            
  2699.        
  2700.         ApplyQuenBuffChanges();
  2701.    
  2702.        
  2703.         if( actorAttacker == thePlayer && action.IsActionWitcherSign() && action.IsCriticalHit() && GetWitcherPlayer().IsMutationActive( EPMT_Mutation2 ) && action.HasBuff( EET_Burning ) )
  2704.         {
  2705.             action.SetBuffSourceName( 'Mutation2ExplosionValid' );
  2706.         }
  2707.    
  2708.        
  2709.         if(actorVictim && action.GetEffectsCount() > 0)
  2710.             ret = actorVictim.ApplyActionEffects(action);
  2711.         else
  2712.             ret = false;
  2713.            
  2714.        
  2715.         if(actorAttacker && actorVictim)
  2716.         {
  2717.             inv = actorAttacker.GetInventory();
  2718.             actorAttacker.ProcessOnHitEffects(actorVictim, inv.IsItemSilverSwordUsableByPlayer(weaponId), inv.IsItemSteelSwordUsableByPlayer(weaponId), action.IsActionWitcherSign() );
  2719.         }
  2720.        
  2721.         return ret;
  2722.     }
  2723.    
  2724.    
  2725.     private function ApplyQuenBuffChanges()
  2726.     {
  2727.         var npc : CNewNPC;
  2728.         var protection : bool;
  2729.         var witcher : W3PlayerWitcher;
  2730.         var quenEntity : W3QuenEntity;
  2731.         var i : int;
  2732.         var buffs : array<EEffectType>;
  2733.    
  2734.         if(!actorVictim || !actorVictim.HasAlternateQuen())
  2735.             return;
  2736.        
  2737.         npc = (CNewNPC)actorVictim;
  2738.         if(npc)
  2739.         {
  2740.             if(!action.DealsAnyDamage())
  2741.                 protection = true;
  2742.         }
  2743.         else
  2744.         {
  2745.             witcher = (W3PlayerWitcher)actorVictim;
  2746.             if(witcher)
  2747.             {
  2748.                 quenEntity = (W3QuenEntity)witcher.GetCurrentSignEntity();
  2749.                 if(quenEntity.GetBlockedAllDamage())
  2750.                 {
  2751.                     protection = true;
  2752.                 }
  2753.             }
  2754.         }
  2755.        
  2756.         if(!protection)
  2757.             return;
  2758.            
  2759.         action.GetEffectTypes(buffs);
  2760.         for(i=buffs.Size()-1; i>=0; i -=1)
  2761.         {
  2762.             if(buffs[i] == EET_KnockdownTypeApplicator || IsKnockdownEffectType(buffs[i]))
  2763.                 continue;
  2764.                
  2765.             action.RemoveBuff(i);
  2766.         }
  2767.     }
  2768.    
  2769.    
  2770.    
  2771.    
  2772.     private function ProcessDismemberment(wasFrozen : bool, dismemberExplosion : bool )
  2773.     {
  2774.         var hitDirection        : Vector;
  2775.         var usedWound           : name;
  2776.         var npcVictim           : CNewNPC;
  2777.         var wounds              : array< name >;
  2778.         var i                   : int;
  2779.         var petard              : W3Petard;
  2780.         var bolt                : W3BoltProjectile;    
  2781.         var forcedRagdoll       : bool;
  2782.         var isExplosion         : bool;
  2783.         var dismembermentComp   : CDismembermentComponent;
  2784.         var specialWounds       : array< name >;
  2785.         var useHitDirection     : bool;
  2786.         var fxMask              : EDismembermentEffectTypeFlags;
  2787.         var template            : CEntityTemplate;
  2788.         var ent                 : CEntity;
  2789.         var signType            : ESignType;
  2790.        
  2791.         if(!actorVictim)
  2792.             return;
  2793.            
  2794.         dismembermentComp = (CDismembermentComponent)(actorVictim.GetComponentByClassName( 'CDismembermentComponent' ));
  2795.         if(!dismembermentComp)
  2796.             return;
  2797.            
  2798.         if(wasFrozen)
  2799.         {
  2800.             ProcessFrostDismemberment();
  2801.             return;
  2802.         }
  2803.        
  2804.         forcedRagdoll = false;
  2805.        
  2806.        
  2807.         petard = (W3Petard)action.causer;
  2808.         bolt = (W3BoltProjectile)action.causer;
  2809.        
  2810.         if( dismemberExplosion || (attackAction && ( attackAction.GetAttackName() == 'attack_explosion' || attackAction.HasForceExplosionDismemberment() ))
  2811.             || (petard && petard.DismembersOnKill()) || (bolt && bolt.DismembersOnKill()) )
  2812.         {
  2813.             isExplosion = true;
  2814.         }
  2815.         else
  2816.         {
  2817.             isExplosion = false;
  2818.         }
  2819.        
  2820.        
  2821.         if(playerAttacker && thePlayer.forceDismember && IsNameValid(thePlayer.forceDismemberName))
  2822.         {
  2823.             usedWound = thePlayer.forceDismemberName;
  2824.         }
  2825.         else
  2826.         {  
  2827.            
  2828.             if(isExplosion)
  2829.             {
  2830.                 dismembermentComp.GetWoundsNames( wounds, WTF_Explosion ); 
  2831.  
  2832.                
  2833.                 if( action.IsMutation2PotentialKill() )
  2834.                 {
  2835.                    
  2836.                     for( i=wounds.Size()-1; i>=0; i-=1 )
  2837.                     {
  2838.                         if( !StrContains( wounds[ i ], "_ep2" ) )
  2839.                         {
  2840.                             wounds.EraseFast( i );
  2841.                         }
  2842.                     }
  2843.                    
  2844.                     signType = action.GetSignType();
  2845.                     if( signType == ST_Aard )
  2846.                     {
  2847.                         fxMask = DETF_Aaard;
  2848.                     }
  2849.                     else if( signType == ST_Igni )
  2850.                     {
  2851.                         fxMask = DETF_Igni;
  2852.                     }
  2853.                     else if( signType == ST_Yrden )
  2854.                     {
  2855.                         fxMask = DETF_Yrden;
  2856.                     }
  2857.                     else if( signType == ST_Quen )
  2858.                     {
  2859.                         fxMask = DETF_Quen;
  2860.                     }
  2861.                 }
  2862.                 else
  2863.                 {
  2864.                     fxMask = 0;
  2865.                 }
  2866.                
  2867.                 if ( wounds.Size() > 0 )
  2868.                     usedWound = wounds[ RandRange( wounds.Size() ) ];
  2869.                    
  2870.                 if ( usedWound )
  2871.                     StopVO( actorVictim );
  2872.             }
  2873.             else if(attackAction || action.GetBuffSourceName() == "riderHit")
  2874.             {
  2875.                 if  ( attackAction.GetAttackTypeName() == 'sword_s2' || thePlayer.isInFinisher )
  2876.                     useHitDirection = true;
  2877.                
  2878.                 if ( useHitDirection )
  2879.                 {
  2880.                     hitDirection = actorAttacker.GetSwordTipMovementFromAnimation( attackAction.GetAttackAnimName(), attackAction.GetHitTime(), 0.1, attackAction.GetWeaponEntity() );
  2881.                     usedWound = actorVictim.GetNearestWoundForBone( attackAction.GetHitBoneIndex(), hitDirection, WTF_Cut );
  2882.                 }
  2883.                 else
  2884.                 {          
  2885.                    
  2886.                     dismembermentComp.GetWoundsNames( wounds );
  2887.                    
  2888.                    
  2889.                     if(wounds.Size() > 0)
  2890.                     {
  2891.                         dismembermentComp.GetWoundsNames( specialWounds, WTF_Explosion );
  2892.                         for ( i = 0; i < specialWounds.Size(); i += 1 )
  2893.                         {
  2894.                             wounds.Remove( specialWounds[i] );
  2895.                         }
  2896.                        
  2897.                         if(wounds.Size() > 0)
  2898.                         {
  2899.                            
  2900.                             dismembermentComp.GetWoundsNames( specialWounds, WTF_Frost );
  2901.                             for ( i = 0; i < specialWounds.Size(); i += 1 )
  2902.                             {
  2903.                                 wounds.Remove( specialWounds[i] );
  2904.                             }
  2905.                            
  2906.                            
  2907.                             if ( wounds.Size() > 0 )
  2908.                                 usedWound = wounds[ RandRange( wounds.Size() ) ];
  2909.                         }
  2910.                     }
  2911.                 }
  2912.             }
  2913.         }
  2914.        
  2915.         if ( usedWound )
  2916.         {
  2917.             npcVictim = (CNewNPC)action.victim;
  2918.             if(npcVictim)
  2919.                 npcVictim.DisableAgony();          
  2920.            
  2921.             actorVictim.SetDismembermentInfo( usedWound, actorVictim.GetWorldPosition() - actorAttacker.GetWorldPosition(), forcedRagdoll, fxMask );
  2922.             actorVictim.AddTimer( 'DelayedDismemberTimer', 0.05f );
  2923.             actorVictim.SetBehaviorVariable( 'dismemberAnim', 1.0 );
  2924.            
  2925.            
  2926.             if ( usedWound == 'explode_02' || usedWound == 'explode2' || usedWound == 'explode_02_ep2' || usedWound == 'explode2_ep2')
  2927.             {
  2928.                 ProcessDismembermentDeathAnim( usedWound, true, EFDT_LegLeft );
  2929.                 actorVictim.SetKinematic( false );
  2930.                
  2931.             }
  2932.             else
  2933.             {
  2934.                 ProcessDismembermentDeathAnim( usedWound, false );
  2935.             }
  2936.            
  2937.            
  2938.             if( usedWound == 'explode_01_ep2' || usedWound == 'explode1_ep2' || usedWound == 'explode_02_ep2' || usedWound == 'explode2_ep2' )
  2939.             {
  2940.                 template = (CEntityTemplate) LoadResource( "explosion_dismember_force" );
  2941.                 ent = theGame.CreateEntity( template, npcVictim.GetWorldPosition(), , , , true );
  2942.                 ent.DestroyAfter( 5.f );
  2943.             }
  2944.            
  2945.             DropEquipmentFromDismember( usedWound, true, true );
  2946.            
  2947.             if( attackAction && actorAttacker == thePlayer )           
  2948.                 GCameraShake( 0.5, true, actorAttacker.GetWorldPosition(), 10);
  2949.                
  2950.             if(playerAttacker)
  2951.                 theGame.VibrateControllerHard();   
  2952.                
  2953.            
  2954.             if( dismemberExplosion && (W3AardProjectile)action.causer )
  2955.             {
  2956.                 npcVictim.AddTimer( 'AardDismemberForce', 0.00001f );
  2957.             }
  2958.         }
  2959.         else
  2960.         {
  2961.             LogChannel( 'Dismemberment', "ERROR: No wound found to dismember on entity but entity supports dismemberment!!!" );
  2962.         }
  2963.     }
  2964.    
  2965.     function ApplyForce()
  2966.     {
  2967.         var size, i : int;
  2968.         var victim : CNewNPC;
  2969.         var fromPos, toPos : Vector;
  2970.         var comps : array<CComponent>;
  2971.         var impulse : Vector;
  2972.        
  2973.         victim = (CNewNPC)action.victim;
  2974.         toPos = victim.GetWorldPosition();
  2975.         toPos.Z += 1.0f;
  2976.         fromPos = toPos;
  2977.         fromPos.Z -= 2.0f;
  2978.         impulse = VecNormalize( toPos - fromPos.Z ) * 10;
  2979.        
  2980.         comps = victim.GetComponentsByClassName('CComponent');
  2981.         victim.GetVisualDebug().AddArrow( 'applyForce', fromPos, toPos, 1, 0.2f, 0.2f, true, Color( 0,0,255 ), true, 5.0f );
  2982.         size = comps.Size();
  2983.         for( i = 0; i < size; i += 1 )
  2984.         {
  2985.             comps[i].ApplyLocalImpulseToPhysicalObject( impulse );
  2986.         }
  2987.     }
  2988.    
  2989.     private function ProcessFrostDismemberment()
  2990.     {
  2991.         var dismembermentComp   : CDismembermentComponent;
  2992.         var wounds              : array< name >;
  2993.         var wound               : name;
  2994.         var i, fxMask           : int;
  2995.         var npcVictim           : CNewNPC;
  2996.        
  2997.         dismembermentComp = (CDismembermentComponent)(actorVictim.GetComponentByClassName( 'CDismembermentComponent' ));
  2998.         if(!dismembermentComp)
  2999.             return;
  3000.        
  3001.         dismembermentComp.GetWoundsNames( wounds, WTF_Frost );
  3002.        
  3003.        
  3004.        
  3005.         if( theGame.GetDLCManager().IsEP2Enabled() )
  3006.         {
  3007.             fxMask = DETF_Mutation6;
  3008.            
  3009.            
  3010.             for( i=wounds.Size()-1; i>=0; i-=1 )
  3011.             {
  3012.                 if( !StrContains( wounds[ i ], "_ep2" ) )
  3013.                 {
  3014.                     wounds.EraseFast( i );
  3015.                 }
  3016.             }
  3017.         }
  3018.         else
  3019.         {
  3020.             fxMask = 0;
  3021.         }
  3022.        
  3023.         if ( wounds.Size() > 0 )
  3024.         {
  3025.             wound = wounds[ RandRange( wounds.Size() ) ];
  3026.         }
  3027.         else
  3028.         {
  3029.             return;
  3030.         }
  3031.        
  3032.         npcVictim = (CNewNPC)action.victim;
  3033.         if(npcVictim)
  3034.         {
  3035.             npcVictim.DisableAgony();
  3036.             StopVO( npcVictim );
  3037.         }
  3038.        
  3039.         actorVictim.SetDismembermentInfo( wound, actorVictim.GetWorldPosition() - actorAttacker.GetWorldPosition(), true, fxMask );
  3040.         actorVictim.AddTimer( 'DelayedDismemberTimer', 0.05f );
  3041.         if( wound == 'explode_02' || wound == 'explode2' || wound == 'explode_02_ep2' || wound == 'explode2_ep2' )
  3042.         {
  3043.             ProcessDismembermentDeathAnim( wound, true, EFDT_LegLeft );
  3044.             npcVictim.SetKinematic(false);
  3045.         }
  3046.         else
  3047.         {
  3048.             ProcessDismembermentDeathAnim( wound, false );
  3049.         }
  3050.         DropEquipmentFromDismember( wound, true, true );
  3051.        
  3052.         if( attackAction )         
  3053.             GCameraShake( 0.5, true, actorAttacker.GetWorldPosition(), 10);
  3054.            
  3055.         if(playerAttacker)
  3056.             theGame.VibrateControllerHard();   
  3057.     }
  3058.    
  3059.    
  3060.     private function ProcessDismembermentDeathAnim( nearestWound : name, forceDeathType : bool, optional deathType : EFinisherDeathType )
  3061.     {
  3062.         var dropCurveName : name;
  3063.        
  3064.         if ( forceDeathType )
  3065.         {
  3066.             if ( deathType == EFDT_Head )
  3067.                 StopVO( actorVictim );
  3068.                
  3069.             actorVictim.SetBehaviorVariable( 'FinisherDeathType', (int)deathType );
  3070.            
  3071.             return;
  3072.         }
  3073.        
  3074.         dropCurveName = ( (CDismembermentComponent)(actorVictim.GetComponentByClassName( 'CDismembermentComponent' )) ).GetMainCurveName( nearestWound );
  3075.        
  3076.         if ( dropCurveName == 'head' )
  3077.         {
  3078.             actorVictim.SetBehaviorVariable( 'FinisherDeathType', (int)EFDT_Head );
  3079.             StopVO( actorVictim );
  3080.         }
  3081.         else if ( dropCurveName == 'torso_left' || dropCurveName == 'torso_right' || dropCurveName == 'torso' )
  3082.             actorVictim.SetBehaviorVariable( 'FinisherDeathType', (int)EFDT_Torso );
  3083.         else if ( dropCurveName == 'arm_right' )
  3084.             actorVictim.SetBehaviorVariable( 'FinisherDeathType', (int)EFDT_ArmRight );
  3085.         else if ( dropCurveName == 'arm_left' )
  3086.             actorVictim.SetBehaviorVariable( 'FinisherDeathType', (int)EFDT_ArmLeft );
  3087.         else if ( dropCurveName == 'leg_left' )
  3088.             actorVictim.SetBehaviorVariable( 'FinisherDeathType', (int)EFDT_LegLeft );
  3089.         else if ( dropCurveName == 'leg_right' )
  3090.             actorVictim.SetBehaviorVariable( 'FinisherDeathType', (int)EFDT_LegRight );
  3091.         else
  3092.             actorVictim.SetBehaviorVariable( 'FinisherDeathType', (int)EFDT_None );
  3093.     }
  3094.    
  3095.     private function StopVO( actor : CActor )
  3096.     {
  3097.         actor.SoundEvent( "grunt_vo_death_stop", 'head' );
  3098.     }
  3099.  
  3100.     private function DropEquipmentFromDismember( nearestWound : name, optional dropLeft, dropRight : bool )
  3101.     {
  3102.         var dropCurveName : name;
  3103.        
  3104.         if( actorVictim.HasAbility( 'DontDropWeaponsOnDismemberment' ) )
  3105.         {
  3106.             return;
  3107.         }
  3108.        
  3109.         dropCurveName = ( (CDismembermentComponent)(actorVictim.GetComponentByClassName( 'CDismembermentComponent' )) ).GetMainCurveName( nearestWound );
  3110.        
  3111.         if ( ChangeHeldItemAppearance() )
  3112.         {
  3113.             actorVictim.SignalGameplayEvent('DropWeaponsInDeathTask');
  3114.             return;
  3115.         }
  3116.        
  3117.         if ( dropLeft || dropRight )
  3118.         {
  3119.            
  3120.             if ( dropLeft )
  3121.                 actorVictim.DropItemFromSlot( 'l_weapon', true );
  3122.            
  3123.             if ( dropRight )
  3124.                 actorVictim.DropItemFromSlot( 'r_weapon', true );          
  3125.            
  3126.             return;
  3127.         }
  3128.        
  3129.         if ( dropCurveName == 'arm_right' )
  3130.             actorVictim.DropItemFromSlot( 'r_weapon', true );
  3131.         else if ( dropCurveName == 'arm_left' )
  3132.             actorVictim.DropItemFromSlot( 'l_weapon', true );
  3133.         else if ( dropCurveName == 'torso_left' || dropCurveName == 'torso_right' || dropCurveName == 'torso' )
  3134.         {
  3135.             actorVictim.DropItemFromSlot( 'l_weapon', true );
  3136.             actorVictim.DropItemFromSlot( 'r_weapon', true );
  3137.         }          
  3138.         else if ( dropCurveName == 'head' || dropCurveName == 'leg_left' || dropCurveName == 'leg_right' )
  3139.         {
  3140.             if(  RandRange(100) < 50 )
  3141.                 actorVictim.DropItemFromSlot( 'l_weapon', true );
  3142.            
  3143.             if(  RandRange(100) < 50 )
  3144.                 actorVictim.DropItemFromSlot( 'r_weapon', true );
  3145.         }
  3146.     }
  3147.    
  3148.     function ChangeHeldItemAppearance() : bool
  3149.     {
  3150.         var inv : CInventoryComponent;
  3151.         var weapon : SItemUniqueId;
  3152.        
  3153.         inv = actorVictim.GetInventory();
  3154.        
  3155.         weapon = inv.GetItemFromSlot('l_weapon');
  3156.        
  3157.         if ( inv.IsIdValid( weapon ) )
  3158.         {
  3159.             if ( inv.ItemHasTag(weapon,'bow') || inv.ItemHasTag(weapon,'crossbow') )
  3160.                 inv.GetItemEntityUnsafe(weapon).ApplyAppearance("rigid");
  3161.             return true;
  3162.         }
  3163.        
  3164.         weapon = inv.GetItemFromSlot('r_weapon');
  3165.        
  3166.         if ( inv.IsIdValid( weapon ) )
  3167.         {
  3168.             if ( inv.ItemHasTag(weapon,'bow') || inv.ItemHasTag(weapon,'crossbow') )
  3169.                 inv.GetItemEntityUnsafe(weapon).ApplyAppearance("rigid");
  3170.             return true;
  3171.         }
  3172.    
  3173.         return false;
  3174.     }
  3175.    
  3176.    
  3177.     private function GetOilProtectionAgainstMonster(dmgType : name, out resist : float, out reduct : float)
  3178.     {
  3179.         var i : int;
  3180.         var heldWeapons : array< SItemUniqueId >;
  3181.         var weapon : SItemUniqueId;
  3182.        
  3183.         resist = 0;
  3184.         reduct = 0;
  3185.        
  3186.        
  3187.         heldWeapons = thePlayer.inv.GetHeldWeapons();
  3188.        
  3189.        
  3190.         for( i=0; i<heldWeapons.Size(); i+=1 )
  3191.         {
  3192.             if( !thePlayer.inv.IsItemFists( heldWeapons[ i ] ) )
  3193.             {
  3194.                 weapon = heldWeapons[ i ];
  3195.                 break;
  3196.             }
  3197.         }
  3198.        
  3199.        
  3200.         if( !thePlayer.inv.IsIdValid( weapon ) )
  3201.         {
  3202.             return;
  3203.         }
  3204.    
  3205.        
  3206.         if( !thePlayer.inv.ItemHasActiveOilApplied( weapon, attackerMonsterCategory ) )
  3207.         {
  3208.             return;
  3209.         }
  3210.        
  3211.         resist = CalculateAttributeValue( thePlayer.GetSkillAttributeValue( S_Alchemy_s05, 'defence_bonus', false, true ) );       
  3212.     }
  3213.    
  3214.    
  3215.     private function ProcessToxicCloudDismemberExplosion(damages : array<SRawDamage>)
  3216.     {
  3217.         var act : W3DamageAction;
  3218.         var i, j : int;
  3219.         var ents : array<CGameplayEntity>;
  3220.        
  3221.        
  3222.         if(damages.Size() == 0)
  3223.         {
  3224.             LogAssert(false, "W3DamageManagerProcessor.ProcessToxicCloudDismemberExplosion: trying to process but no damages are passed! Aborting!");
  3225.             return;
  3226.         }      
  3227.        
  3228.        
  3229.         FindGameplayEntitiesInSphere(ents, action.victim.GetWorldPosition(), 3, 1000, , FLAG_OnlyAliveActors);
  3230.        
  3231.        
  3232.         for(i=0; i<ents.Size(); i+=1)
  3233.         {
  3234.             act = new W3DamageAction in this;
  3235.             act.Initialize(action.attacker, ents[i], action.causer, 'Dragons_Dream_3', EHRT_Heavy, CPS_Undefined, false, false, false, true);
  3236.            
  3237.             for(j=0; j<damages.Size(); j+=1)
  3238.             {
  3239.                 act.AddDamage(damages[j].dmgType, damages[j].dmgVal);
  3240.             }
  3241.            
  3242.             theGame.damageMgr.ProcessAction(act);
  3243.             delete act;
  3244.         }
  3245.     }
  3246.    
  3247.    
  3248.     private final function ProcessSparksFromNoDamage()
  3249.     {
  3250.         var sparksEntity, weaponEntity : CEntity;
  3251.         var weaponTipPosition : Vector;
  3252.         var weaponSlotMatrix : Matrix;
  3253.        
  3254.        
  3255.         if(!playerAttacker || !attackAction || !attackAction.IsActionMelee() || attackAction.DealsAnyDamage())
  3256.             return;
  3257.        
  3258.        
  3259.         if( ( !attackAction.DidArmorReduceDamageToZero() && !actorVictim.IsVampire() && ( attackAction.IsParried() || attackAction.IsCountered() ) )
  3260.             || ( ( attackAction.IsParried() || attackAction.IsCountered() ) && !actorVictim.IsHuman() && !actorVictim.IsVampire() )
  3261.             || actorVictim.IsCurrentlyDodging() )
  3262.             return;
  3263.        
  3264.        
  3265.         if(actorVictim.HasTag('NoSparksOnArmorDmgReduced'))
  3266.             return;
  3267.        
  3268.        
  3269.         if (!actorVictim.GetGameplayVisibility())
  3270.             return;
  3271.        
  3272.        
  3273.         weaponEntity = playerAttacker.inv.GetItemEntityUnsafe(weaponId);
  3274.         weaponEntity.CalcEntitySlotMatrix( 'blood_fx_point', weaponSlotMatrix );
  3275.         weaponTipPosition = MatrixGetTranslation( weaponSlotMatrix );
  3276.        
  3277.        
  3278.         sparksEntity = theGame.CreateEntity( (CEntityTemplate)LoadResource( 'sword_colision_fx' ), weaponTipPosition );
  3279.         sparksEntity.PlayEffect('sparks');
  3280.     }
  3281.    
  3282.     private function ProcessPreHitModifications()
  3283.     {
  3284.         var fireDamage, totalDmg, maxHealth, currHealth : float;
  3285.         var attribute, min, max : SAbilityAttributeValue;
  3286.         var infusion : ESignType;
  3287.         var hack : array< SIgniEffects >;
  3288.         var dmgValTemp : float;
  3289.         var igni : W3IgniEntity;
  3290.         var quen : W3QuenEntity;
  3291.         var fxEntity : CEntity; //HolySwordAerondight
  3292.  
  3293.         if( actorVictim.HasAbility( 'HitWindowOpened' ) && !action.IsDoTDamage() )
  3294.         {
  3295.             if( actorVictim.HasTag( 'fairytale_witch' ) )
  3296.             {
  3297.                
  3298.                
  3299.                
  3300.                
  3301.                
  3302.                
  3303.                     ((CNewNPC)actorVictim).SetBehaviorVariable( 'shouldBreakFlightLoop', 1.0 );
  3304.                
  3305.             }
  3306.             else
  3307.             {
  3308.                 quen = (W3QuenEntity)action.causer;
  3309.            
  3310.                 if( !quen )
  3311.                 {
  3312.                     if( actorVictim.HasTag( 'dettlaff_vampire' ) )
  3313.                     {
  3314.                         actorVictim.StopEffect( 'shadowdash' );
  3315.                     }
  3316.                    
  3317.                     action.ClearDamage();
  3318.                     if( action.IsActionMelee() )
  3319.                     {
  3320.                         actorVictim.PlayEffect( 'special_attack_break' );
  3321.                     }
  3322.                     actorVictim.SetBehaviorVariable( 'repelType', 0 );
  3323.                    
  3324.                     actorVictim.AddEffectDefault( EET_CounterStrikeHit, thePlayer );
  3325.                     action.RemoveBuffsByType( EET_KnockdownTypeApplicator );
  3326.                 }
  3327.             }
  3328.            
  3329.             ((CNewNPC)actorVictim).SetHitWindowOpened( false );
  3330.         }
  3331.        
  3332.        
  3333.        
  3334.         if(playerAttacker && attackAction && attackAction.IsActionMelee() && (W3PlayerWitcher)thePlayer && thePlayer.HasAbility('Runeword 1 _Stats', true))
  3335.         {
  3336.             infusion = GetWitcherPlayer().GetRunewordInfusionType();
  3337.            
  3338.             switch(infusion)
  3339.             {
  3340.                 case ST_Aard:
  3341.                     action.AddEffectInfo(EET_KnockdownTypeApplicator);
  3342.                     action.SetProcessBuffsIfNoDamage(true);
  3343.                     attackAction.SetApplyBuffsIfParried(true);
  3344.                     actorVictim.CreateFXEntityAtPelvis( 'runeword_1_aard', false );
  3345.                     break;
  3346.                 case ST_Axii:
  3347.                     action.AddEffectInfo(EET_Confusion);
  3348.                     action.SetProcessBuffsIfNoDamage(true);
  3349.                     attackAction.SetApplyBuffsIfParried(true);
  3350.                     break;
  3351.                 case ST_Igni:
  3352.                    
  3353.                     totalDmg = action.GetDamageValueTotal();
  3354.                     attribute = thePlayer.GetAttributeValue('runeword1_fire_dmg');
  3355.                     fireDamage = totalDmg * attribute.valueMultiplicative;
  3356.                     action.AddDamage(theGame.params.DAMAGE_NAME_FIRE, fireDamage);
  3357.                    
  3358.                    
  3359.                     action.SetCanPlayHitParticle(false);                   
  3360.                     action.victim.AddTimer('Runeword1DisableFireFX', 1.f);
  3361.                     action.SetHitReactionType(EHRT_Heavy); 
  3362.                     action.victim.PlayEffect('critical_burning');
  3363.                     break;
  3364.                 case ST_Yrden:
  3365.                     attribute = thePlayer.GetAttributeValue('runeword1_yrden_duration');
  3366.                     action.AddEffectInfo(EET_Slowdown, attribute.valueAdditive);
  3367.                     action.SetProcessBuffsIfNoDamage(true);
  3368.                     attackAction.SetApplyBuffsIfParried(true);
  3369.                     break;
  3370.                 default:       
  3371.                     break;
  3372.             }
  3373.         }
  3374.         //HolySwordAerondight++
  3375.         if(playerAttacker && attackAction && attackAction.IsActionMelee() && (W3PlayerWitcher)thePlayer &&  GetWitcherPlayer().GetAerondightTrigger())
  3376.         {
  3377.             action.SetProcessBuffsIfNoDamage(false);
  3378.             totalDmg = action.GetDamageValueTotal();
  3379.             fireDamage = totalDmg * 0.20;
  3380.             action.AddDamage(theGame.params.DAMAGE_NAME_ELEMENTAL, fireDamage);
  3381.  
  3382.             actorVictim.CreateFXEntityAtPelvis( 'runeword_1_quen', false );
  3383.             action.SetCanPlayHitParticle(true);
  3384.             action.SetHitReactionType(EHRT_Heavy);
  3385.             action.victim.PlayEffect('yrden_shock');                   
  3386.             //action.victim.PlayEffect( 'hit_electric_quen');
  3387.            
  3388.             //fxEntity = GetWitcherPlayer().CreateFXEntityAtPelvis( 'mutation2_critical', false );
  3389.             //fxEntity.Teleport(action.victim.GetWorldPosition());
  3390.             //fxEntity.PlayEffect( 'critical_quen' );
  3391.             //fxEntity.DestroyAfter(0.5);          
  3392.         }
  3393.         //HolySwordAerondight--
  3394.        
  3395.        
  3396.         if( playerAttacker && actorVictim && (W3PlayerWitcher)playerAttacker && GetWitcherPlayer().IsMutationActive( EPMT_Mutation9 ) && (W3BoltProjectile)action.causer )
  3397.         {
  3398.             maxHealth = actorVictim.GetMaxHealth();
  3399.             currHealth = actorVictim.GetHealth();
  3400.            
  3401.            
  3402.             if( AbsF( maxHealth - currHealth ) < 1.f )
  3403.             {
  3404.                 theGame.GetDefinitionsManager().GetAbilityAttributeValue('Mutation9', 'health_reduction', min, max);
  3405.                 actorVictim.ForceSetStat( actorVictim.GetUsedHealthType(), maxHealth * ( 1 - min.valueMultiplicative ) );
  3406.             }
  3407.            
  3408.            
  3409.             action.AddEffectInfo( EET_KnockdownTypeApplicator, 0.1f, , , , 1.f );
  3410.         }
  3411.     }
  3412. }
  3413.  
  3414. exec function ForceDismember( b: bool, optional chance : int, optional n : name, optional e : bool )
  3415. {
  3416.     var temp : CR4Player;
  3417.    
  3418.     temp = thePlayer;
  3419.     temp.forceDismember = b;
  3420.     temp.forceDismemberName = n;
  3421.     temp.forceDismemberChance = chance;
  3422.     temp.forceDismemberExplosion = e;
  3423. }
  3424.  
  3425. exec function ForceFinisher( b: bool, optional n : name, optional rightStance : bool )
  3426. {
  3427.     var temp : CR4Player;
  3428.    
  3429.     temp = thePlayer;
  3430.     temp.forcedStance = rightStance;
  3431.     temp.forceFinisher = b;
  3432.     temp.forceFinisherAnimName = n;
  3433. }
  3434.  
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement