Last active
February 6, 2023 19:34
-
-
Save Wolfsblvt/0ed0632ec4a330fe4affe1d4f2e1a0b1 to your computer and use it in GitHub Desktop.
4.01 hotfix Merge "damageManagerProcessor.ws" Vanilla x modCriSloMoCR
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/***********************************************************************/ | |
/** © 2015 CD PROJEKT S.A. All rights reserved. | |
/** THE WITCHER® is a trademark of CD PROJEKT S. A. | |
/** The Witcher game is based on the prose of Andrzej Sapkowski. | |
/***********************************************************************/ | |
class W3DamageManagerProcessor extends CObject | |
{ | |
//Critical Slow Motion Combat Redux | |
private var mCSMCR : CCSMCR; | |
//Critical Slow Motion Combat Redux | |
private var playerAttacker : CR4Player; | |
private var playerVictim : CR4Player; | |
private var action : W3DamageAction; | |
private var attackAction : W3Action_Attack; | |
private var weaponId : SItemUniqueId; | |
private var actorVictim : CActor; | |
private var actorAttacker : CActor; | |
private var dm : CDefinitionsManagerAccessor; | |
private var attackerMonsterCategory : EMonsterCategory; | |
private var victimMonsterCategory : EMonsterCategory; | |
private var victimCanBeHitByFists : bool; | |
public function ProcessAction(act : W3DamageAction) | |
{ | |
var wasAlive, validDamage, isFrozen, autoFinishersEnabled : bool; | |
var focusDrain : float; | |
var npc : CNewNPC; | |
var buffs : array<EEffectType>; | |
var arrStr : array<string>; | |
var aerondight : W3Effect_Aerondight; | |
var trailFxName : name; | |
var swordEntity : CWitcherSword; | |
var swordItem : SItemUniqueId; | |
var bloodType : EBloodType; | |
wasAlive = act.victim.IsAlive(); | |
npc = (CNewNPC)act.victim; | |
InitializeActionVars(act); | |
//Critical Slow Motion Combat Redux | |
mCSMCR = thePlayer.mCSMCR; | |
//Critical Slow Motion Combat Redux | |
if(playerVictim && attackAction && attackAction.IsActionMelee() && !attackAction.CanBeParried() && attackAction.IsParried()) | |
{ | |
action.GetEffectTypes(buffs); | |
if(!buffs.Contains(EET_Knockdown) && !buffs.Contains(EET_HeavyKnockdown)) | |
{ | |
action.SetParryStagger(); | |
action.SetProcessBuffsIfNoDamage(true); | |
action.AddEffectInfo(EET_LongStagger); | |
action.SetHitAnimationPlayType(EAHA_ForceNo); | |
action.SetCanPlayHitParticle(false); | |
action.RemoveBuffsByType(EET_Bleeding); | |
action.RemoveBuffsByType(EET_Bleeding1); | |
action.RemoveBuffsByType(EET_Bleeding2); | |
action.RemoveBuffsByType(EET_Bleeding3); | |
} | |
} | |
if(actorAttacker && playerVictim && ((W3PlayerWitcher)playerVictim) && GetWitcherPlayer().IsAnyQuenActive()) | |
FactsAdd("player_had_quen"); | |
ProcessPreHitModifications(); | |
ProcessActionQuest(act); | |
isFrozen = (actorVictim && actorVictim.HasBuff(EET_Frozen)); | |
validDamage = ProcessActionDamage(); | |
if(wasAlive && !action.victim.IsAlive()) | |
{ | |
arrStr.PushBack(action.victim.GetDisplayName()); | |
if(npc && npc.WillBeUnconscious()) | |
{ | |
theGame.witcherLog.AddCombatMessage(GetLocStringByKeyExtWithParams("hud_combat_log_unconscious", , , arrStr), NULL, action.victim); | |
} | |
else if(action.attacker && action.attacker.GetDisplayName() != "") | |
{ | |
arrStr.PushBack(action.attacker.GetDisplayName()); | |
theGame.witcherLog.AddCombatMessage(GetLocStringByKeyExtWithParams("hud_combat_log_killed", , , arrStr), action.attacker, action.victim); | |
} | |
else | |
{ | |
theGame.witcherLog.AddCombatMessage(GetLocStringByKeyExtWithParams("hud_combat_log_dies", , , arrStr), NULL, action.victim); | |
} | |
} | |
if( wasAlive && action.DealsAnyDamage() ) | |
{ | |
((CActor) action.attacker).SignalGameplayEventParamFloat( 'CausesDamage', MaxF( action.processedDmg.vitalityDamage, action.processedDmg.essenceDamage ) ); | |
} | |
ProcessActionReaction(isFrozen, wasAlive); | |
if(action.DealsAnyDamage() || action.ProcessBuffsIfNoDamage()) | |
ProcessActionBuffs(); | |
if(theGame.CanLog() && !validDamage && action.GetEffectsCount() == 0) | |
{ | |
LogAssert(false, "W3DamageManagerProcessor.ProcessAction: action deals no damage and gives no buffs - investigate!"); | |
if ( theGame.CanLog() ) | |
{ | |
LogDMHits("*** Action has no valid damage and no valid buffs - investigate!", action); | |
} | |
} | |
if( actorAttacker && wasAlive ) | |
actorAttacker.OnProcessActionPost(action); | |
if(actorVictim == GetWitcherPlayer() && action.DealsAnyDamage() && !action.IsDoTDamage()) | |
{ | |
if(actorAttacker && attackAction) | |
{ | |
if(actorAttacker.IsHeavyAttack( attackAction.GetAttackName() )) | |
focusDrain = CalculateAttributeValue(thePlayer.GetAttributeValue('heavy_attack_focus_drain')); | |
else if(actorAttacker.IsSuperHeavyAttack( attackAction.GetAttackName() )) | |
focusDrain = CalculateAttributeValue(thePlayer.GetAttributeValue('super_heavy_attack_focus_drain')); | |
else | |
focusDrain = CalculateAttributeValue(thePlayer.GetAttributeValue('light_attack_focus_drain')); | |
} | |
else | |
{ | |
focusDrain = CalculateAttributeValue(thePlayer.GetAttributeValue('light_attack_focus_drain')); | |
} | |
if ( GetWitcherPlayer().CanUseSkill(S_Sword_s16) ) | |
focusDrain *= 1 - (CalculateAttributeValue( thePlayer.GetSkillAttributeValue(S_Sword_s16, 'focus_drain_reduction', false, true) ) * thePlayer.GetSkillLevel(S_Sword_s16)); | |
thePlayer.DrainFocus(focusDrain); | |
} | |
if(actorAttacker == GetWitcherPlayer() && actorVictim && !actorVictim.IsAlive() && (action.IsActionMelee() || action.GetBuffSourceName() == "Kill")) | |
{ | |
autoFinishersEnabled = theGame.GetInGameConfigWrapper().GetVarValue('Gameplay', 'AutomaticFinishersEnabled'); | |
if(!autoFinishersEnabled || !thePlayer.GetFinisherVictim()) | |
{ | |
if(thePlayer.HasAbility('Runeword 10 _Stats', true)) | |
GetWitcherPlayer().Runeword10Triggerred(); | |
if(thePlayer.HasAbility('Runeword 12 _Stats', true)) | |
GetWitcherPlayer().Runeword12Triggerred(); | |
} | |
} | |
if(action.EndsQuen() && actorVictim) | |
{ | |
actorVictim.FinishQuen(false); | |
} | |
if(actorVictim == thePlayer && attackAction && attackAction.IsActionMelee() && (ShouldProcessTutorial('TutorialDodge') || ShouldProcessTutorial('TutorialCounter') || ShouldProcessTutorial('TutorialParry')) ) | |
{ | |
if(attackAction.IsCountered()) | |
{ | |
theGame.GetTutorialSystem().IncreaseCounters(); | |
} | |
else if(attackAction.IsParried()) | |
{ | |
theGame.GetTutorialSystem().IncreaseParries(); | |
} | |
if(attackAction.CanBeDodged() && !attackAction.WasDodged()) | |
{ | |
GameplayFactsAdd("tut_failed_dodge", 1, 1); | |
GameplayFactsAdd("tut_failed_roll", 1, 1); | |
} | |
} | |
//Critical Slow Motion Combat Redux | |
if ( mCSMCR.critSloMoToggle && thePlayer.IsInCombat() && action.DealsAnyDamage() ) | |
mCSMCR.Init(act, attackAction.IsCriticalHit()); | |
if ( mCSMCR.critSloMoToggle && thePlayer.IsInCombat() && (attackAction.IsCountered() || attackAction.IsParried()) ) | |
mCSMCR.Init(act,,,,,,,attackAction.IsCountered()); | |
//Critical Slow Motion Combat Redux | |
if( playerAttacker && npc && action.IsActionMelee() && action.DealtDamage() && IsRequiredAttitudeBetween( playerAttacker, npc, true )) | |
{ | |
if(!npc.HasTag( 'AerondightIgnore' )) | |
{ | |
if( playerAttacker.inv.ItemHasTag( attackAction.GetWeaponId(), 'Aerondight' ) ) | |
{ | |
aerondight = (W3Effect_Aerondight)playerAttacker.GetBuff( EET_Aerondight ); | |
aerondight.IncreaseAerondightCharges( attackAction.GetAttackName() ); | |
if( aerondight.GetCurrentCount() == aerondight.GetMaxCount() ) | |
{ | |
switch( npc.GetBloodType() ) | |
{ | |
case BT_Red : | |
trailFxName = 'aerondight_blood_red'; | |
break; | |
case BT_Yellow : | |
trailFxName = 'aerondight_blood_yellow'; | |
break; | |
case BT_Black : | |
trailFxName = 'aerondight_blood_black'; | |
break; | |
case BT_Green : | |
trailFxName = 'aerondight_blood_green'; | |
break; | |
} | |
playerAttacker.inv.GetItemEntityUnsafe( attackAction.GetWeaponId() ).PlayEffect( trailFxName ); | |
} | |
} | |
} | |
if(!action.WasDodged() && !attackAction.IsParried() && !attackAction.IsCountered()) | |
{ | |
swordItem = GetWitcherPlayer().GetHeldSword(); | |
if(swordItem != GetInvalidUniqueId()) | |
{ | |
swordEntity = (CWitcherSword)thePlayer.GetInventory().GetItemEntityUnsafe( swordItem ); | |
if(swordEntity) | |
{ | |
bloodType = npc.GetBloodType(); | |
if(bloodType == BT_Red || bloodType == BT_Yellow) | |
{ | |
swordEntity.PlayEffectSingle('weapon_blood'); | |
} | |
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') ) | |
{ | |
swordEntity.PlayEffectSingle('weapon_blood_black'); | |
} | |
else if (bloodType == BT_Green) | |
{ | |
swordEntity.PlayEffectSingle('weapon_blood_green'); | |
} | |
} | |
} | |
} | |
} | |
} | |
private final function InitializeActionVars(act : W3DamageAction) | |
{ | |
var tmpName : name; | |
var tmpBool : bool; | |
action = act; | |
playerAttacker = (CR4Player)action.attacker; | |
playerVictim = (CR4Player)action.victim; | |
attackAction = (W3Action_Attack)action; | |
actorVictim = (CActor)action.victim; | |
actorAttacker = (CActor)action.attacker; | |
dm = theGame.GetDefinitionsManager(); | |
if(attackAction) | |
weaponId = attackAction.GetWeaponId(); | |
theGame.GetMonsterParamsForActor(actorVictim, victimMonsterCategory, tmpName, tmpBool, tmpBool, victimCanBeHitByFists); | |
if(actorAttacker) | |
theGame.GetMonsterParamsForActor(actorAttacker, attackerMonsterCategory, tmpName, tmpBool, tmpBool, tmpBool); | |
} | |
private function ProcessActionQuest(act : W3DamageAction) | |
{ | |
var victimTags, attackerTags : array<name>; | |
victimTags = action.victim.GetTags(); | |
if(action.attacker) | |
attackerTags = action.attacker.GetTags(); | |
AddHitFacts( victimTags, attackerTags, "_weapon_hit" ); | |
if ((CGameplayEntity) action.victim) action.victim.OnWeaponHit(act); | |
} | |
private function ProcessActionDamage() : bool | |
{ | |
var directDmgIndex, size, i : int; | |
var dmgInfos : array< SRawDamage >; | |
var immortalityMode : EActorImmortalityMode; | |
var dmgValue : float; | |
var anyDamageProcessed, fallingRaffard : bool; | |
var victimHealthPercBeforeHit, frozenAdditionalDamage : float; | |
var powerMod : SAbilityAttributeValue; | |
var witcher : W3PlayerWitcher; | |
var canLog : bool; | |
var immortalityChannels : array<EActorImmortalityChanel>; | |
canLog = theGame.CanLog(); | |
action.SetAllProcessedDamageAs(0); | |
size = action.GetDTs( dmgInfos ); | |
action.SetDealtFireDamage(false); | |
if(!actorVictim || (!actorVictim.UsesVitality() && !actorVictim.UsesEssence()) ) | |
{ | |
for(i=0; i<size; i+=1) | |
{ | |
if(dmgInfos[i].dmgType == theGame.params.DAMAGE_NAME_FIRE && dmgInfos[i].dmgVal > 0) | |
{ | |
action.victim.OnFireHit( (CGameplayEntity)action.causer ); | |
break; | |
} | |
} | |
if ( !actorVictim.abilityManager ) | |
actorVictim.OnDeath(action); | |
return false; | |
} | |
if(actorVictim.UsesVitality()) | |
victimHealthPercBeforeHit = actorVictim.GetStatPercents(BCS_Vitality); | |
else | |
victimHealthPercBeforeHit = actorVictim.GetStatPercents(BCS_Essence); | |
if ( actorVictim && playerAttacker && victimMonsterCategory == MC_Specter && playerAttacker.HasBuff(EET_Mutagen28) && !actorVictim.HasAbility( 'ShadowFormActive' ) ) | |
{ | |
actorVictim.BlockAbility('ShadowForm', true); | |
actorVictim.BlockAbility('Flashstep', true); | |
actorVictim.BlockAbility('EssenceRegen', true); | |
actorVictim.BlockAbility('Teleport', true); | |
actorVictim.BlockAbility('Specter', true); | |
} | |
ProcessDamageIncrease( dmgInfos ); | |
if ( canLog ) | |
{ | |
LogBeginning(); | |
} | |
ProcessCriticalHitCheck(); | |
ProcessOnBeforeHitChecks(); | |
powerMod = GetAttackersPowerMod(); | |
anyDamageProcessed = false; | |
directDmgIndex = -1; | |
witcher = GetWitcherPlayer(); | |
size = dmgInfos.Size(); | |
for( i = 0; i < size; i += 1 ) | |
{ | |
if(dmgInfos[i].dmgVal == 0) | |
continue; | |
if(dmgInfos[i].dmgType == theGame.params.DAMAGE_NAME_DIRECT) | |
{ | |
directDmgIndex = i; | |
continue; | |
} | |
if(dmgInfos[i].dmgType == theGame.params.DAMAGE_NAME_POISON && witcher == actorVictim && witcher.HasBuff(EET_GoldenOriole) && witcher.GetPotionBuffLevel(EET_GoldenOriole) == 3) | |
{ | |
witcher.GainStat(BCS_Vitality, dmgInfos[i].dmgVal); | |
if ( canLog ) | |
{ | |
LogDMHits("", action); | |
LogDMHits("*** Player absorbs poison damage from level 3 Golden Oriole potion: " + dmgInfos[i].dmgVal, action); | |
} | |
dmgInfos[i].dmgVal = 0; | |
continue; | |
} | |
if ( canLog ) | |
{ | |
LogDMHits("", action); | |
LogDMHits("*** Incoming " + NoTrailZeros(dmgInfos[i].dmgVal) + " " + dmgInfos[i].dmgType + " damage", action); | |
if(action.IsDoTDamage()) | |
LogDMHits("DoT's current dt = " + NoTrailZeros(action.GetDoTdt()) + ", estimated dps = " + NoTrailZeros(dmgInfos[i].dmgVal / action.GetDoTdt()), action); | |
} | |
anyDamageProcessed = true; | |
dmgValue = MaxF(0, CalculateDamage(dmgInfos[i], powerMod)); | |
if( DamageHitsEssence( dmgInfos[i].dmgType ) ) action.processedDmg.essenceDamage += dmgValue; | |
if( DamageHitsVitality( dmgInfos[i].dmgType ) ) action.processedDmg.vitalityDamage += dmgValue; | |
if( DamageHitsMorale( dmgInfos[i].dmgType ) ) action.processedDmg.moraleDamage += dmgValue; | |
if( DamageHitsStamina( dmgInfos[i].dmgType ) ) action.processedDmg.staminaDamage += dmgValue; | |
} | |
if(size == 0 && canLog) | |
{ | |
LogDMHits("*** There is no incoming damage set (probably only buffs).", action); | |
} | |
if ( canLog ) | |
{ | |
LogDMHits("", action); | |
LogDMHits("Processing block, parry, immortality, signs and other GLOBAL damage reductions...", action); | |
} | |
if(actorVictim) | |
actorVictim.ReduceDamage(action); | |
if(directDmgIndex != -1) | |
{ | |
anyDamageProcessed = true; | |
immortalityChannels = actorVictim.GetImmortalityModeChannels(AIM_Invulnerable); | |
fallingRaffard = immortalityChannels.Size() == 1 && immortalityChannels.Contains(AIC_WhiteRaffardsPotion) && action.GetBuffSourceName() == "FallingDamage"; | |
if(action.GetIgnoreImmortalityMode() || (!actorVictim.IsImmortal() && !actorVictim.IsInvulnerable() && !actorVictim.IsKnockedUnconscious()) || fallingRaffard) | |
{ | |
action.processedDmg.vitalityDamage += dmgInfos[directDmgIndex].dmgVal; | |
action.processedDmg.essenceDamage += dmgInfos[directDmgIndex].dmgVal; | |
} | |
else if( actorVictim.IsInvulnerable() ) | |
{ | |
} | |
else if( actorVictim.IsImmortal() ) | |
{ | |
action.processedDmg.vitalityDamage += MinF(dmgInfos[directDmgIndex].dmgVal, actorVictim.GetStat(BCS_Vitality)-1 ); | |
action.processedDmg.essenceDamage += MinF(dmgInfos[directDmgIndex].dmgVal, actorVictim.GetStat(BCS_Essence)-1 ); | |
} | |
} | |
if( actorVictim.HasAbility( 'OneShotImmune' ) ) | |
{ | |
if( action.processedDmg.vitalityDamage >= actorVictim.GetStatMax( BCS_Vitality ) ) | |
{ | |
action.processedDmg.vitalityDamage = actorVictim.GetStatMax( BCS_Vitality ) - 1; | |
} | |
else if( action.processedDmg.essenceDamage >= actorVictim.GetStatMax( BCS_Essence ) ) | |
{ | |
action.processedDmg.essenceDamage = actorVictim.GetStatMax( BCS_Essence ) - 1; | |
} | |
} | |
if(action.HasDealtFireDamage()) | |
action.victim.OnFireHit( (CGameplayEntity)action.causer ); | |
ProcessInstantKill(); | |
ProcessActionDamage_DealDamage(); | |
if(playerAttacker && witcher) | |
witcher.SetRecentlyCountered(false); | |
if( attackAction && !attackAction.IsCountered() && playerVictim && attackAction.IsActionMelee()) | |
theGame.GetGamerProfile().ResetStat(ES_CounterattackChain); | |
ProcessActionDamage_ReduceDurability(); | |
if(playerAttacker && actorVictim) | |
{ | |
if(playerAttacker.inv.ItemHasAnyActiveOilApplied(weaponId) && (!playerAttacker.CanUseSkill(S_Alchemy_s06) || (playerAttacker.GetSkillLevel(S_Alchemy_s06) < 3)) ) | |
{ | |
playerAttacker.ReduceAllOilsAmmo( weaponId ); | |
if(ShouldProcessTutorial('TutorialOilAmmo')) | |
{ | |
FactsAdd("tut_used_oil_in_combat"); | |
} | |
} | |
playerAttacker.inv.ReduceItemRepairObjectBonusCharge(weaponId); | |
} | |
if(actorVictim && actorAttacker && !action.GetCannotReturnDamage() ) | |
ProcessActionReturnedDamage(); | |
return anyDamageProcessed; | |
} | |
private function ProcessInstantKill() | |
{ | |
var instantKill, focus : float; | |
if( !actorVictim || !actorAttacker || actorVictim.IsImmuneToInstantKill() ) | |
{ | |
return; | |
} | |
if( action.WasDodged() || ( attackAction && ( attackAction.IsParried() || attackAction.IsCountered() ) ) ) | |
{ | |
return; | |
} | |
if( actorAttacker.HasAbility( 'ForceInstantKill' ) && actorVictim != thePlayer ) | |
{ | |
action.SetInstantKill(); | |
} | |
if( actorAttacker == thePlayer && !action.GetIgnoreInstantKillCooldown() ) | |
{ | |
if( !GameTimeDTAtLeastRealSecs( thePlayer.lastInstantKillTime, theGame.GetGameTime(), theGame.params.INSTANT_KILL_INTERNAL_PLAYER_COOLDOWN ) ) | |
{ | |
return; | |
} | |
} | |
if( !action.GetInstantKill() ) | |
{ | |
instantKill = CalculateAttributeValue( actorAttacker.GetInventory().GetItemAttributeValue( weaponId, 'instant_kill_chance' ) ); | |
if( ( action.IsActionMelee() || action.IsActionRanged() ) && playerAttacker && action.DealsAnyDamage() && thePlayer.CanUseSkill( S_Sword_s03 ) && !playerAttacker.inv.IsItemFists( weaponId ) ) | |
{ | |
focus = thePlayer.GetStat( BCS_Focus ); | |
if( focus >= 1 ) | |
{ | |
instantKill += focus * CalculateAttributeValue( thePlayer.GetSkillAttributeValue( S_Sword_s03, 'instant_kill_chance', false, true ) ) * thePlayer.GetSkillLevel( S_Sword_s03 ); | |
} | |
} | |
} | |
if( action.GetInstantKill() || ( RandF() < instantKill ) ) | |
{ | |
if( theGame.CanLog() ) | |
{ | |
if( action.GetInstantKill() ) | |
{ | |
instantKill = 1.f; | |
} | |
LogDMHits( "Instant kill!! (" + NoTrailZeros( instantKill * 100 ) + "% chance", action ); | |
} | |
action.processedDmg.vitalityDamage += actorVictim.GetStat( BCS_Vitality ); | |
action.processedDmg.essenceDamage += actorVictim.GetStat( BCS_Essence ); | |
action.SetCriticalHit(); | |
action.SetInstantKillFloater(); | |
mCSMCR = thePlayer.mCSMCR; //Critical Slow Motion Combat Redux Compatibility | |
if( playerAttacker ) | |
{ | |
thePlayer.SetLastInstantKillTime( theGame.GetGameTime() ); | |
theSound.SoundEvent( 'cmb_play_deadly_hit' ); | |
//Critical Slow Motion Combat Redux Compatibility | |
if ( !mCSMCR.critSloMoToggle ) | |
{ | |
//Critical Slow Motion Combat Redux Compatibility | |
theGame.SetTimeScale( 0.2, theGame.GetTimescaleSource( ETS_InstantKill ), theGame.GetTimescalePriority( ETS_InstantKill ), true, true ); | |
thePlayer.AddTimer( 'RemoveInstantKillSloMo', 0.2 ); | |
} //Critical Slow Motion Combat Redux Compatibility | |
} | |
} | |
} | |
private function ProcessOnBeforeHitChecks() | |
{ | |
var effectAbilityName, monsterBonusType : name; | |
var effectType : EEffectType; | |
var null, monsterBonusVal : SAbilityAttributeValue; | |
var oilLevel, skillLevel, i : int; | |
var baseChance, perOilLevelChance, chance : float; | |
var buffs : array<name>; | |
if( playerAttacker && actorVictim && attackAction && attackAction.IsActionMelee() && playerAttacker.CanUseSkill(S_Alchemy_s12) && playerAttacker.inv.ItemHasActiveOilApplied( weaponId, victimMonsterCategory ) ) | |
{ | |
monsterBonusType = MonsterCategoryToAttackPowerBonus(victimMonsterCategory); | |
monsterBonusVal = playerAttacker.inv.GetItemAttributeValue(weaponId, monsterBonusType); | |
if(monsterBonusVal != null) | |
{ | |
oilLevel = (int)CalculateAttributeValue(playerAttacker.inv.GetItemAttributeValue(weaponId, 'level')) - 1; | |
skillLevel = playerAttacker.GetSkillLevel(S_Alchemy_s12); | |
baseChance = CalculateAttributeValue(playerAttacker.GetSkillAttributeValue(S_Alchemy_s12, 'skill_chance', false, true)); | |
perOilLevelChance = CalculateAttributeValue(playerAttacker.GetSkillAttributeValue(S_Alchemy_s12, 'oil_level_chance', false, true)); | |
chance = baseChance * skillLevel + perOilLevelChance * oilLevel; | |
if(RandF() < chance) | |
{ | |
dm.GetContainedAbilities(playerAttacker.GetSkillAbilityName(S_Alchemy_s12), buffs); | |
for(i=0; i<buffs.Size(); i+=1) | |
{ | |
EffectNameToType(buffs[i], effectType, effectAbilityName); | |
action.AddEffectInfo(effectType, , , effectAbilityName); | |
} | |
} | |
} | |
} | |
} | |
private function ProcessCriticalHitCheck() | |
{ | |
var critChance, critDamageBonus : float; | |
var canLog, meleeOrRanged, redWolfSet, isLightAttack, isHeavyAttack, mutation2 : bool; | |
var arrStr : array<string>; | |
var samum : CBaseGameplayEffect; | |
var signPower, min, max : SAbilityAttributeValue; | |
var aerondight : W3Effect_Aerondight; | |
meleeOrRanged = playerAttacker && attackAction && ( attackAction.IsActionMelee() || attackAction.IsActionRanged() ); | |
redWolfSet = ( W3Petard )action.causer && ( W3PlayerWitcher )actorAttacker && GetWitcherPlayer().IsSetBonusActive( EISB_RedWolf_1 ); | |
mutation2 = ( W3PlayerWitcher )actorAttacker && GetWitcherPlayer().IsMutationActive(EPMT_Mutation2) && action.IsActionWitcherSign(); | |
if( meleeOrRanged || redWolfSet || mutation2 ) | |
{ | |
canLog = theGame.CanLog(); | |
if( mutation2 ) | |
{ | |
if( FactsQuerySum('debug_fact_critical_boy') > 0 ) | |
{ | |
critChance = 1.f; | |
} | |
else | |
{ | |
signPower = action.GetPowerStatValue(); | |
theGame.GetDefinitionsManager().GetAbilityAttributeValue('Mutation2', 'crit_chance_factor', min, max); | |
critChance = min.valueAdditive + signPower.valueMultiplicative * min.valueMultiplicative; | |
} | |
} | |
else | |
{ | |
if( attackAction ) | |
{ | |
if( SkillEnumToName(S_Sword_s02) == attackAction.GetAttackTypeName() ) | |
{ | |
critChance += CalculateAttributeValue(playerAttacker.GetSkillAttributeValue(S_Sword_s02, theGame.params.CRITICAL_HIT_CHANCE, false, true)) * playerAttacker.GetSkillLevel(S_Sword_s02); | |
} | |
if(GetWitcherPlayer() && GetWitcherPlayer().HasRecentlyCountered() && playerAttacker.CanUseSkill(S_Sword_s11) && playerAttacker.GetSkillLevel(S_Sword_s11) > 2) | |
{ | |
critChance += CalculateAttributeValue(playerAttacker.GetSkillAttributeValue(S_Sword_s11, theGame.params.CRITICAL_HIT_CHANCE, false, true)); | |
} | |
isLightAttack = playerAttacker.IsLightAttack( attackAction.GetAttackName() ); | |
isHeavyAttack = playerAttacker.IsHeavyAttack( attackAction.GetAttackName() ); | |
critChance += playerAttacker.GetCriticalHitChance(isLightAttack, isHeavyAttack, actorVictim, victimMonsterCategory, (W3BoltProjectile)action.causer ); | |
if(action.GetIsHeadShot()) | |
{ | |
critChance += theGame.params.HEAD_SHOT_CRIT_CHANCE_BONUS; | |
actorVictim.SignalGameplayEvent( 'Headshot' ); | |
} | |
if ( actorVictim && actorVictim.IsAttackerAtBack(playerAttacker) ) | |
{ | |
critChance += theGame.params.BACK_ATTACK_CRIT_CHANCE_BONUS; | |
} | |
if( action.IsActionMelee() && playerAttacker.inv.ItemHasTag( attackAction.GetWeaponId(), 'Aerondight' ) ) | |
{ | |
aerondight = (W3Effect_Aerondight)playerAttacker.GetBuff( EET_Aerondight ); | |
if( aerondight && aerondight.IsFullyCharged() ) | |
{ | |
min = playerAttacker.GetAbilityAttributeValue( 'AerondightEffect', 'crit_chance_bonus' ); | |
critChance += min.valueAdditive; | |
} | |
} | |
} | |
else | |
{ | |
critChance += playerAttacker.GetCriticalHitChance(false, false, actorVictim, victimMonsterCategory, (W3BoltProjectile)action.causer ); | |
} | |
samum = actorVictim.GetBuff(EET_Blindness, 'petard'); | |
if(samum && samum.GetBuffLevel() == 3) | |
{ | |
critChance += 1.0f; | |
} | |
} | |
if ( canLog ) | |
{ | |
critDamageBonus = 1 + CalculateAttributeValue(actorAttacker.GetCriticalHitDamageBonus(weaponId, victimMonsterCategory, actorVictim.IsAttackerAtBack(playerAttacker))); | |
critDamageBonus += CalculateAttributeValue(actorAttacker.GetAttributeValue('critical_hit_chance_fast_style')); | |
critDamageBonus = 100 * critDamageBonus; | |
LogDMHits("", action); | |
LogDMHits("Trying critical hit (" + NoTrailZeros(critChance*100) + "% chance, dealing " + NoTrailZeros(critDamageBonus) + "% damage)...", action); | |
} | |
if(RandF() < critChance) | |
{ | |
action.SetCriticalHit(); | |
if ( canLog ) | |
{ | |
LogDMHits("********************", action); | |
LogDMHits("*** CRITICAL HIT ***", action); | |
LogDMHits("********************", action); | |
} | |
arrStr.PushBack(action.attacker.GetDisplayName()); | |
theGame.witcherLog.AddCombatMessage(theGame.witcherLog.COLOR_GOLD_BEGIN + GetLocStringByKeyExtWithParams("hud_combat_log_critical_hit",,,arrStr) + theGame.witcherLog.COLOR_GOLD_END, action.attacker, NULL); | |
} | |
else if ( canLog ) | |
{ | |
LogDMHits("... nope", action); | |
} | |
} | |
} | |
private function LogBeginning() | |
{ | |
var logStr : string; | |
if ( !theGame.CanLog() ) | |
{ | |
return; | |
} | |
LogDMHits("-----------------------------------------------------------------------------------", action); | |
logStr = "Beginning hit processing from <<" + action.attacker + ">> to <<" + action.victim + ">> via <<" + action.causer + ">>"; | |
if(attackAction) | |
{ | |
logStr += " using AttackType <<" + attackAction.GetAttackTypeName() + ">>"; | |
} | |
logStr += ":"; | |
LogDMHits(logStr, action); | |
LogDMHits("", action); | |
LogDMHits("Target stats before damage dealt are:", action); | |
if(actorVictim) | |
{ | |
if( actorVictim.UsesVitality() ) | |
LogDMHits("Vitality = " + NoTrailZeros(actorVictim.GetStat(BCS_Vitality)), action); | |
if( actorVictim.UsesEssence() ) | |
LogDMHits("Essence = " + NoTrailZeros(actorVictim.GetStat(BCS_Essence)), action); | |
if( actorVictim.GetStatMax(BCS_Stamina) > 0) | |
LogDMHits("Stamina = " + NoTrailZeros(actorVictim.GetStat(BCS_Stamina, true)), action); | |
if( actorVictim.GetStatMax(BCS_Morale) > 0) | |
LogDMHits("Morale = " + NoTrailZeros(actorVictim.GetStat(BCS_Morale)), action); | |
} | |
else | |
{ | |
LogDMHits("Undefined - victim is not a CActor and therefore has no stats", action); | |
} | |
} | |
private function ProcessDamageIncrease(out dmgInfos : array< SRawDamage >) | |
{ | |
var difficultyDamageMultiplier, rendLoad, rendBonus, overheal, rendRatio, focusCost : float; | |
var i, bonusCount : int; | |
var frozenBuff : W3Effect_Frozen; | |
var frozenDmgInfo : SRawDamage; | |
var hadFrostDamage : bool; | |
var mpac : CMovingPhysicalAgentComponent; | |
var rendBonusPerPoint, staminaRendBonus, perk20Bonus : SAbilityAttributeValue; | |
var witcherAttacker : W3PlayerWitcher; | |
var damageVal, damageBonus, min, max : SAbilityAttributeValue; | |
var npcVictim : CNewNPC; | |
var sword : SItemUniqueId; | |
var actionFreeze : W3DamageAction; | |
var aerondight : W3Effect_Aerondight; | |
var aardDamage : SRawDamage; | |
var yrdens : array<W3YrdenEntity>; | |
var j, levelDiff : int; | |
var aardDamageF : float; | |
var spellPower, spellPowerAard, spellPowerYrden : float; | |
var spNetflix : SAbilityAttributeValue; | |
var entities : array<CGameplayEntity>; | |
var skillPassiveMod : float; | |
if(actorAttacker && !actorAttacker.IgnoresDifficultySettings() && !action.IsDoTDamage()) | |
{ | |
difficultyDamageMultiplier = CalculateAttributeValue(actorAttacker.GetAttributeValue(theGame.params.DIFFICULTY_DMG_MULTIPLIER)); | |
for(i=0; i<dmgInfos.Size(); i+=1) | |
{ | |
dmgInfos[i].dmgVal = dmgInfos[i].dmgVal * difficultyDamageMultiplier; | |
} | |
} | |
if(actorVictim && playerAttacker && !action.IsDoTDamage() && actorVictim.HasBuff(EET_Frozen) && ( (W3AardProjectile)action.causer || (W3AardEntity)action.causer || action.DealsPhysicalOrSilverDamage()) ) | |
{ | |
action.SetWasFrozen(); | |
if( !( ( W3WhiteFrost )action.causer ) ) | |
{ | |
frozenBuff = (W3Effect_Frozen)actorVictim.GetBuff(EET_Frozen); | |
frozenDmgInfo.dmgVal = frozenBuff.GetAdditionalDamagePercents() * actorVictim.GetHealth(); | |
} | |
actorVictim.RemoveAllBuffsOfType(EET_Frozen); | |
action.AddEffectInfo(EET_KnockdownTypeApplicator); | |
if( !( ( W3WhiteFrost )action.causer ) ) | |
{ | |
actionFreeze = new W3DamageAction in theGame; | |
actionFreeze.Initialize( actorAttacker, actorVictim, action.causer, action.GetBuffSourceName(), EHRT_None, CPS_Undefined, action.IsActionMelee(), action.IsActionRanged(), action.IsActionWitcherSign(), action.IsActionEnvironment() ); | |
actionFreeze.SetCannotReturnDamage( true ); | |
actionFreeze.SetCanPlayHitParticle( false ); | |
actionFreeze.SetHitAnimationPlayType( EAHA_ForceNo ); | |
actionFreeze.SetWasFrozen(); | |
actionFreeze.AddDamage( theGame.params.DAMAGE_NAME_FROST, frozenDmgInfo.dmgVal ); | |
theGame.damageMgr.ProcessAction( actionFreeze ); | |
delete actionFreeze; | |
} | |
} | |
if(actorVictim && playerAttacker && GetWitcherPlayer().IsSetBonusActive( EISB_Netflix_2 ) && !action.IsDoTDamage() && ( (W3AardProjectile)action.causer || (W3AardEntity)action.causer)) | |
{ | |
yrdens = GetWitcherPlayer().yrdenEntities; | |
if(yrdens.Size() > 0) | |
{ | |
spellPowerAard = CalculateAttributeValue(GetWitcherPlayer().GetAttributeValue('spell_power_aard')); | |
spellPowerYrden = CalculateAttributeValue(GetWitcherPlayer().GetAttributeValue('spell_power_yrden')); | |
spellPower = ClampF(1 + spellPowerAard + spellPowerYrden + CalculateAttributeValue(GetWitcherPlayer().GetPowerStatValue(CPS_SpellPower)), 1, 3); | |
for(i=0; i<yrdens.Size(); i+=1) | |
{ | |
for(j=0; j<yrdens[i].validTargetsInArea.Size(); j+=1) | |
{ | |
if(yrdens[i].validTargetsInArea[j] == actorVictim ) | |
{ | |
levelDiff = playerAttacker.GetLevel() - actorVictim.GetLevel(); | |
aardDamage.dmgType = theGame.params.DAMAGE_NAME_DIRECT; | |
if( GetWitcherPlayer().CanUseSkill(S_Magic_s06) ) | |
aardDamageF = (RandRangeF(375.0, 325.0) + (playerAttacker.GetLevel() * 1.8f) + (GetWitcherPlayer().GetSkillLevel(S_Magic_s06) * 100) ) * spellPower; | |
else | |
aardDamageF = (RandRangeF(375.0, 325.0) + (playerAttacker.GetLevel() * 1.8f) ) * spellPower; | |
if( actorVictim.GetCharacterStats().HasAbilityWithTag('Boss') || (W3MonsterHuntNPC)actorVictim || (levelDiff < 0 && Abs(levelDiff) > theGame.params.LEVEL_DIFF_HIGH)) | |
{ | |
aardDamage.dmgVal = aardDamageF * 0.75f; | |
} | |
else | |
{ | |
aardDamage.dmgVal = aardDamageF; | |
} | |
spNetflix = action.GetPowerStatValue(); | |
aardDamage.dmgVal += 3 * actorVictim.GetHealth() * ( 0.01 + 0.03 * LogF( spNetflix.valueMultiplicative ) ); | |
dmgInfos.PushBack(aardDamage); | |
} | |
} | |
} | |
} | |
} | |
if(actorVictim) | |
{ | |
mpac = (CMovingPhysicalAgentComponent)actorVictim.GetMovingAgentComponent(); | |
if(mpac && mpac.IsDiving()) | |
{ | |
mpac = (CMovingPhysicalAgentComponent)actorAttacker.GetMovingAgentComponent(); | |
if(mpac && mpac.IsDiving()) | |
{ | |
action.SetUnderwaterDisplayDamageHack(); | |
if(playerAttacker && attackAction && attackAction.IsActionRanged()) | |
{ | |
for(i=0; i<dmgInfos.Size(); i+=1) | |
{ | |
if(FactsQuerySum("NewGamePlus")) | |
{ | |
dmgInfos[i].dmgVal *= (1 + theGame.params.UNDERWATER_CROSSBOW_DAMAGE_BONUS_NGP); | |
} | |
else | |
{ | |
dmgInfos[i].dmgVal *= (1 + theGame.params.UNDERWATER_CROSSBOW_DAMAGE_BONUS); | |
} | |
} | |
} | |
} | |
} | |
} | |
if(playerAttacker && attackAction && SkillNameToEnum(attackAction.GetAttackTypeName()) == S_Sword_s02) | |
{ | |
witcherAttacker = (W3PlayerWitcher)playerAttacker; | |
rendRatio = witcherAttacker.GetSpecialAttackTimeRatio(); | |
rendLoad = MinF(rendRatio * playerAttacker.GetStatMax(BCS_Focus), playerAttacker.GetStat(BCS_Focus)); | |
if(rendLoad >= 1) | |
{ | |
rendBonusPerPoint = witcherAttacker.GetSkillAttributeValue(S_Sword_s02, 'adrenaline_final_damage_bonus', false, true); | |
rendBonus = FloorF(rendLoad) * rendBonusPerPoint.valueMultiplicative; | |
for(i=0; i<dmgInfos.Size(); i+=1) | |
{ | |
dmgInfos[i].dmgVal *= (1 + rendBonus); | |
} | |
} | |
staminaRendBonus = witcherAttacker.GetSkillAttributeValue(S_Sword_s02, 'stamina_max_dmg_bonus', false, true); | |
for(i=0; i<dmgInfos.Size(); i+=1) | |
{ | |
dmgInfos[i].dmgVal *= (1 + rendRatio * staminaRendBonus.valueMultiplicative); | |
} | |
thePlayer.SetAttackActionName(''); | |
} | |
if ( actorAttacker != thePlayer && action.IsActionRanged() && (int)CalculateAttributeValue(actorAttacker.GetAttributeValue('level',,true)) > 31) | |
{ | |
damageVal = actorAttacker.GetAttributeValue('light_attack_damage_vitality',,true); | |
for(i=0; i<dmgInfos.Size(); i+=1) | |
{ | |
dmgInfos[i].dmgVal = dmgInfos[i].dmgVal + CalculateAttributeValue(damageVal) / 2; | |
} | |
} | |
if ( actorVictim && playerAttacker && attackAction && action.IsActionMelee() && thePlayer.HasAbility('Runeword 4 _Stats', true) && !attackAction.WasDodged() ) | |
{ | |
overheal = thePlayer.abilityManager.GetOverhealBonus() / thePlayer.GetStatMax(BCS_Vitality); | |
if(overheal > 0.005f) | |
{ | |
for(i=0; i<dmgInfos.Size(); i+=1) | |
{ | |
dmgInfos[i].dmgVal *= 1.0f + overheal; | |
} | |
thePlayer.abilityManager.ResetOverhealBonus(); | |
actorVictim.CreateFXEntityAtPelvis( 'runeword_4', true ); | |
} | |
} | |
if( playerAttacker && actorVictim && attackAction.IsActionMelee() && GetWitcherPlayer().IsSetBonusActive( EISB_Wolf_1 ) ) | |
{ | |
FindGameplayEntitiesInRange( entities, playerAttacker, 50, 1000, , FLAG_OnlyAliveActors ); | |
if( entities.Size() > 0 ) | |
{ | |
for( i=0; i<entities.Size(); i+=1 ) | |
{ | |
npcVictim = (CNewNPC) entities[i]; | |
if( npcVictim ) | |
{ | |
if( npcVictim.HasBuff( EET_Bleeding ) ) bonusCount += 1; | |
if( npcVictim.HasBuff( EET_Bleeding1 ) ) bonusCount += 1; | |
if( npcVictim.HasBuff( EET_Bleeding2 ) ) bonusCount += 1; | |
if( npcVictim.HasBuff( EET_Bleeding3 ) ) bonusCount += 1; | |
} | |
} | |
bonusCount *= ((W3PlayerWitcher)playerAttacker).GetSetPartsEquipped( EIST_Wolf ); | |
for( i=0; i<dmgInfos.Size() ; i+=1 ) | |
{ | |
dmgInfos[i].dmgVal *= 1 + bonusCount*0.01; | |
} | |
} | |
} | |
if( playerAttacker && playerAttacker.IsLightAttack( attackAction.GetAttackName() ) && playerAttacker.HasBuff( EET_LynxSetBonus ) && !attackAction.WasDodged() ) | |
{ | |
if( !attackAction.IsParried() && !attackAction.IsCountered() ) | |
{ | |
damageBonus = playerAttacker.GetAttributeValue( 'lynx_dmg_boost' ); | |
damageBonus.valueAdditive *= ((W3PlayerWitcher)playerAttacker).GetSetPartsEquipped( EIST_Lynx ); | |
for( i=0 ; i<dmgInfos.Size() ; i += 1 ) | |
{ | |
dmgInfos[i].dmgVal *= 1 + damageBonus.valueAdditive; | |
} | |
} | |
} | |
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() ) ) ) | |
{ | |
if( !attackAction.IsParried() && !attackAction.IsCountered() && playerAttacker.GetStat(BCS_Focus) >= 1.0f ) | |
{ | |
theGame.GetDefinitionsManager().GetAbilityAttributeValue( GetSetBonusAbility( EISB_Lynx_2 ), 'lynx_2_dmg_boost', min, max ); | |
for( i=0; i<dmgInfos.Size() ; i+=1 ) | |
{ | |
dmgInfos[i].dmgVal *= 1 + min.valueAdditive; | |
} | |
if ( !( thePlayer.IsInCombatAction() && ( thePlayer.GetCombatAction() == EBAT_SpecialAttack_Light || thePlayer.GetCombatAction() == EBAT_SpecialAttack_Heavy ) ) ) | |
{ | |
theGame.GetDefinitionsManager().GetAbilityAttributeValue( GetSetBonusAbility( EISB_Lynx_2 ), 'lynx_2_adrenaline_cost', min, max ); | |
focusCost = min.valueAdditive; | |
if( GetWitcherPlayer().GetStat( BCS_Focus ) >= focusCost ) | |
{ | |
theGame.GetDefinitionsManager().GetAbilityAttributeValue( GetSetBonusAbility( EISB_Lynx_2 ), 'lynx_2_stun_duration', min, max ); | |
attackAction.AddEffectInfo( EET_Confusion, min.valueAdditive ); | |
playerAttacker.SoundEvent( "ep2_setskill_lynx_activate" ); | |
playerAttacker.DrainFocus( focusCost ); | |
} | |
} | |
} | |
} | |
if ( playerAttacker && action.IsActionRanged() && ((W3Petard)action.causer) ) | |
{ | |
skillPassiveMod = CalculateAttributeValue(GetWitcherPlayer().GetAttributeValue('potion_duration')); | |
for( i = 0 ; i < dmgInfos.Size() ; i+=1) | |
{ | |
dmgInfos[i].dmgVal *= ( 1 + skillPassiveMod ); | |
} | |
if ( GetWitcherPlayer().CanUseSkill(S_Perk_20) && !action.IsDoTDamage() ) | |
{ | |
perk20Bonus = GetWitcherPlayer().GetSkillAttributeValue( S_Perk_20, 'dmg_multiplier', false, false); | |
for( i = 0 ; i < dmgInfos.Size() ; i+=1) | |
{ | |
dmgInfos[i].dmgVal *= ( 1 + perk20Bonus.valueMultiplicative ); | |
} | |
} | |
} | |
if( playerAttacker && action.IsActionWitcherSign() && GetWitcherPlayer().IsMutationActive( EPMT_Mutation1 ) ) | |
{ | |
sword = playerAttacker.inv.GetCurrentlyHeldSword(); | |
damageVal.valueBase = 0; | |
damageVal.valueMultiplicative = 0; | |
damageVal.valueAdditive = 0; | |
if( playerAttacker.inv.GetItemCategory(sword) == 'steelsword' ) | |
{ | |
damageVal += playerAttacker.inv.GetItemAttributeValue(sword, theGame.params.DAMAGE_NAME_SLASHING); | |
} | |
else if( playerAttacker.inv.GetItemCategory(sword) == 'silversword' ) | |
{ | |
damageVal += playerAttacker.inv.GetItemAttributeValue(sword, theGame.params.DAMAGE_NAME_SILVER); | |
} | |
theGame.GetDefinitionsManager().GetAbilityAttributeValue('Mutation1', 'dmg_bonus_factor', min, max); | |
damageVal.valueBase *= CalculateAttributeValue(min); | |
if( action.IsDoTDamage() ) | |
{ | |
damageVal.valueBase *= action.GetDoTdt(); | |
} | |
for( i = 0 ; i < dmgInfos.Size() ; i+=1) | |
{ | |
dmgInfos[i].dmgVal += damageVal.valueBase; | |
} | |
} | |
npcVictim = (CNewNPC) actorVictim; | |
if( playerAttacker && npcVictim && attackAction && action.IsActionMelee() && GetWitcherPlayer().IsMutationActive( EPMT_Mutation8 ) && ( victimMonsterCategory != MC_Human || npcVictim.IsImmuneToMutation8Finisher() ) && attackAction.GetWeaponId() == GetWitcherPlayer().GetHeldSword() ) | |
{ | |
dm.GetAbilityAttributeValue( 'Mutation8', 'dmg_bonus', min, max ); | |
for( i = 0 ; i < dmgInfos.Size() ; i+=1) | |
{ | |
dmgInfos[i].dmgVal *= 1 + min.valueMultiplicative; | |
} | |
} | |
if( playerAttacker && actorVictim && attackAction && action.IsActionMelee() && playerAttacker.inv.ItemHasTag( attackAction.GetWeaponId(), 'Aerondight' ) ) | |
{ | |
aerondight = (W3Effect_Aerondight)playerAttacker.GetBuff( EET_Aerondight ); | |
if( aerondight ) | |
{ | |
min = playerAttacker.GetAbilityAttributeValue( 'AerondightEffect', 'dmg_bonus' ); | |
bonusCount = aerondight.GetCurrentCount(); | |
if( bonusCount > 0 ) | |
{ | |
min.valueMultiplicative *= bonusCount; | |
for( i = 0 ; i < dmgInfos.Size() ; i += 1 ) | |
{ | |
dmgInfos[i].dmgVal *= 1 + min.valueMultiplicative; | |
} | |
} | |
} | |
} | |
} | |
private function ProcessActionReturnedDamage() | |
{ | |
var witcher : W3PlayerWitcher; | |
var quen : W3QuenEntity; | |
var params : SCustomEffectParams; | |
var processFireShield, canBeParried, canBeDodged, wasParried, wasDodged, returned : bool; | |
var g5Chance : SAbilityAttributeValue; | |
var dist, checkDist : float; | |
if((W3PlayerWitcher)playerVictim && !playerAttacker && actorAttacker && !action.IsDoTDamage() && action.IsActionMelee() && (attackerMonsterCategory == MC_Necrophage || attackerMonsterCategory == MC_Vampire) && actorVictim.HasBuff(EET_BlackBlood)) | |
{ | |
returned = ProcessActionBlackBloodReturnedDamage(); | |
} | |
if(action.IsActionMelee() && actorVictim.HasAbility( 'Thorns' ) ) | |
{ | |
returned = ProcessActionThornDamage() || returned; | |
} | |
if(actorVictim.HasAbility( 'Glyphword 5 _Stats', true)) | |
{ | |
if( GetAttitudeBetween(actorAttacker, actorVictim) == AIA_Hostile) | |
{ | |
if( !action.IsDoTDamage() ) | |
{ | |
g5Chance = actorVictim.GetAttributeValue('glyphword5_chance'); | |
if(RandF() < g5Chance.valueAdditive) | |
{ | |
canBeParried = attackAction.CanBeParried(); | |
canBeDodged = attackAction.CanBeDodged(); | |
wasParried = attackAction.IsParried() || attackAction.IsCountered(); | |
wasDodged = attackAction.WasDodged(); | |
if(!action.IsActionMelee() || (!canBeParried && canBeDodged && !wasDodged) || (canBeParried && !wasParried && !canBeDodged) || (canBeParried && canBeDodged && !wasDodged && !wasParried)) | |
{ | |
returned = ProcessActionReflectDamage() || returned; | |
} | |
} | |
} | |
} | |
} | |
if(playerVictim && !playerAttacker && actorAttacker && attackAction && attackAction.IsActionMelee() && thePlayer.HasBuff(EET_Mutagen26)) | |
{ | |
returned = ProcessActionLeshenMutagenDamage() || returned; | |
} | |
if(action.IsActionMelee() && actorVictim.HasAbility( 'FireShield' ) ) | |
{ | |
witcher = GetWitcherPlayer(); | |
processFireShield = true; | |
if(playerAttacker == witcher) | |
{ | |
quen = (W3QuenEntity)witcher.GetSignEntity(ST_Quen); | |
if(quen && quen.IsAnyQuenActive()) | |
{ | |
processFireShield = false; | |
} | |
} | |
if(processFireShield) | |
{ | |
params.effectType = EET_Burning; | |
params.creator = actorVictim; | |
params.sourceName = actorVictim.GetName(); | |
params.effectValue.valueMultiplicative = 0.01; | |
actorAttacker.AddEffectCustom(params); | |
returned = true; | |
} | |
} | |
if(actorAttacker.UsesEssence()) | |
{ | |
returned = ProcessSilverStudsReturnedDamage() || returned; | |
} | |
if( (W3PlayerWitcher)playerVictim && !playerAttacker && actorAttacker && !playerAttacker.IsInFistFightMiniGame() && !action.IsDoTDamage() && action.IsActionMelee() && GetWitcherPlayer().IsMutationActive( EPMT_Mutation4 ) ) | |
{ | |
dist = VecDistance( actorAttacker.GetWorldPosition(), actorVictim.GetWorldPosition() ); | |
checkDist = 3.f; | |
if( actorAttacker.IsHuge() ) | |
{ | |
checkDist += 3.f; | |
} | |
if( dist <= checkDist ) | |
{ | |
returned = GetWitcherPlayer().ProcessActionMutation4ReturnedDamage( action.processedDmg.vitalityDamage, actorAttacker, EAHA_ForceYes, action ) || returned; | |
} | |
} | |
action.SetWasDamageReturnedToAttacker( returned ); | |
} | |
private function ProcessActionLeshenMutagenDamage() : bool | |
{ | |
var damageAction : W3DamageAction; | |
var returnedDamage, pts, perc : float; | |
var mutagen : W3Mutagen26_Effect; | |
mutagen = (W3Mutagen26_Effect)playerVictim.GetBuff(EET_Mutagen26); | |
mutagen.GetReturnedDamage(pts, perc); | |
if(pts <= 0 && perc <= 0) | |
return false; | |
returnedDamage = pts + perc * action.processedDmg.vitalityDamage; | |
damageAction = new W3DamageAction in this; | |
damageAction.Initialize( action.victim, action.attacker, NULL, "Mutagen26", EHRT_None, CPS_AttackPower, true, false, false, false ); | |
damageAction.SetCannotReturnDamage( true ); | |
damageAction.SetHitAnimationPlayType( EAHA_ForceNo ); | |
damageAction.AddDamage(theGame.params.DAMAGE_NAME_DIRECT, returnedDamage); | |
theGame.damageMgr.ProcessAction(damageAction); | |
delete damageAction; | |
return true; | |
} | |
private function ProcessSilverStudsReturnedDamage() : bool | |
{ | |
var damageAction : W3DamageAction; | |
var returnedDamage : float; | |
returnedDamage = CalculateAttributeValue(actorVictim.GetAttributeValue('returned_silver_damage')); | |
if(returnedDamage <= 0) | |
return false; | |
damageAction = new W3DamageAction in this; | |
damageAction.Initialize( action.victim, action.attacker, NULL, "SilverStuds", EHRT_None, CPS_AttackPower, true, false, false, false ); | |
damageAction.SetCannotReturnDamage( true ); | |
damageAction.SetHitAnimationPlayType( EAHA_ForceNo ); | |
damageAction.AddDamage(theGame.params.DAMAGE_NAME_SILVER, returnedDamage); | |
theGame.damageMgr.ProcessAction(damageAction); | |
delete damageAction; | |
return true; | |
} | |
private function ProcessActionBlackBloodReturnedDamage() : bool | |
{ | |
var returnedAction : W3DamageAction; | |
var returnVal : SAbilityAttributeValue; | |
var bb : W3Potion_BlackBlood; | |
var potionLevel : int; | |
var returnedDamage : float; | |
if(action.processedDmg.vitalityDamage <= 0) | |
return false; | |
bb = (W3Potion_BlackBlood)actorVictim.GetBuff(EET_BlackBlood); | |
potionLevel = bb.GetBuffLevel(); | |
returnedAction = new W3DamageAction in this; | |
returnedAction.Initialize( action.victim, action.attacker, bb, "BlackBlood", EHRT_None, CPS_AttackPower, true, false, false, false ); | |
returnedAction.SetCannotReturnDamage( true ); | |
returnVal = bb.GetReturnDamageValue(); | |
if(potionLevel == 1) | |
{ | |
returnedAction.SetHitAnimationPlayType(EAHA_ForceNo); | |
} | |
else | |
{ | |
returnedAction.SetHitAnimationPlayType(EAHA_ForceYes); | |
returnedAction.SetHitReactionType(EHRT_Reflect); | |
} | |
returnedDamage = (returnVal.valueBase + action.processedDmg.vitalityDamage) * returnVal.valueMultiplicative + returnVal.valueAdditive; | |
returnedAction.AddDamage(theGame.params.DAMAGE_NAME_DIRECT, returnedDamage); | |
theGame.damageMgr.ProcessAction(returnedAction); | |
delete returnedAction; | |
return true; | |
} | |
private function ProcessActionReflectDamage() : bool | |
{ | |
var returnedAction : W3DamageAction; | |
var returnVal, min, max : SAbilityAttributeValue; | |
var potionLevel : int; | |
var returnedDamage : float; | |
var template : CEntityTemplate; | |
var fxEnt : CEntity; | |
var boneIndex: int; | |
var b : bool; | |
var component : CComponent; | |
if(action.processedDmg.vitalityDamage <= 0) | |
return false; | |
returnedDamage = CalculateAttributeValue(actorVictim.GetTotalArmor()); | |
theGame.GetDefinitionsManager().GetAbilityAttributeValue('Glyphword 5 _Stats', 'damage_mult', min, max); | |
returnedAction = new W3DamageAction in this; | |
returnedAction.Initialize( action.victim, action.attacker, NULL, "Glyphword5", EHRT_None, CPS_AttackPower, true, false, false, false ); | |
returnedAction.SetCannotReturnDamage( true ); | |
returnedAction.SetHitAnimationPlayType(EAHA_ForceYes); | |
returnedAction.SetHitReactionType(EHRT_Heavy); | |
returnedAction.AddDamage(theGame.params.DAMAGE_NAME_DIRECT, returnedDamage * min.valueMultiplicative); | |
theGame.damageMgr.ProcessAction(returnedAction); | |
delete returnedAction; | |
template = (CEntityTemplate)LoadResource('glyphword_5'); | |
component = action.attacker.GetComponent('torso3effect'); | |
if(component) | |
thePlayer.PlayEffect('reflection_damge', component); | |
else | |
thePlayer.PlayEffect('reflection_damge', action.attacker); | |
action.attacker.PlayEffect('yrden_shock'); | |
return true; | |
} | |
private function ProcessActionThornDamage() : bool | |
{ | |
var damageAction : W3DamageAction; | |
var damageVal : SAbilityAttributeValue; | |
var damage : float; | |
var inv : CInventoryComponent; | |
var damageNames : array < CName >; | |
damageAction = new W3DamageAction in this; | |
damageAction.Initialize( action.victim, action.attacker, NULL, "Thorns", EHRT_Light, CPS_AttackPower, true, false, false, false ); | |
damageAction.SetCannotReturnDamage( true ); | |
damageVal = actorVictim.GetAttributeValue( 'light_attack_damage_vitality' ); | |
inv = actorAttacker.GetInventory(); | |
inv.GetWeaponDTNames(weaponId, damageNames ); | |
damageVal.valueBase = actorAttacker.GetTotalWeaponDamage(weaponId, damageNames[0], GetInvalidUniqueId() ); | |
damageVal.valueBase *= 0.10f; | |
if( damageVal.valueBase == 0 ) | |
{ | |
damageVal.valueBase = 10; | |
} | |
damage = (damageVal.valueBase + action.processedDmg.vitalityDamage) * damageVal.valueMultiplicative + damageVal.valueAdditive; | |
damageAction.AddDamage( theGame.params.DAMAGE_NAME_PIERCING, damage ); | |
damageAction.SetHitAnimationPlayType( EAHA_ForceYes ); | |
theGame.damageMgr.ProcessAction(damageAction); | |
delete damageAction; | |
return true; | |
} | |
private function GetAttackersPowerMod() : SAbilityAttributeValue | |
{ | |
var powerMod, criticalDamageBonus, min, max, critReduction, sp : SAbilityAttributeValue; | |
var mutagen : CBaseGameplayEffect; | |
var totalBonus : float; | |
var inv : CInventoryComponent; | |
var weaponName : name; | |
powerMod = action.GetPowerStatValue(); | |
if ( powerMod.valueAdditive == 0 && powerMod.valueBase == 0 && powerMod.valueMultiplicative == 0 && theGame.CanLog() ) | |
LogDMHits("Attacker has power stat of 0!", action); | |
if(playerAttacker && attackAction && playerAttacker.IsHeavyAttack(attackAction.GetAttackName())) | |
powerMod.valueMultiplicative -= 0.433; | |
if ( playerAttacker && (W3IgniProjectile)action.causer ) | |
powerMod.valueMultiplicative = 1 + (powerMod.valueMultiplicative - 1) * theGame.params.IGNI_SPELL_POWER_MILT; | |
if ( playerAttacker && (W3AardProjectile)action.causer ) | |
powerMod.valueMultiplicative = 1; | |
inv = actorAttacker.GetInventory(); | |
weaponName = inv.GetItemName( weaponId ); | |
if( !playerAttacker && actorVictim && !thePlayer.IsInFistFightMiniGame() && GetAttitudeBetween( thePlayer, actorAttacker ) == AIA_Friendly && !actorAttacker.HasTag( 'keira' ) && !actorAttacker.HasTag( 'Yennefer' ) | |
&& ( actorAttacker.IsWeaponHeld( 'silversword' ) || actorAttacker.IsWeaponHeld( 'staff2h' ) || weaponName == 'fists_lightning' || weaponName == 'fists_fire' || actorAttacker.HasAbility( 'SkillWitcher' ) || actorAttacker.HasTag( 'regis' ) || actorAttacker.HasBuff(EET_AxiiGuardMe) ) ) | |
{ | |
if ( powerMod.valueMultiplicative <= 0.1 ) | |
{ | |
actorAttacker.AddAbility( 'FCR3HighDamageBoost' ); | |
actorAttacker.AddAbility( 'FCR3LowDamageBoost'); | |
} | |
else if ( powerMod.valueMultiplicative <= 0.4 ) | |
{ | |
actorAttacker.AddAbility( 'FCR3MedDamageBoost' ); | |
actorAttacker.AddAbility( 'FCR3LowDamageBoost' ); | |
} | |
else if ( powerMod.valueMultiplicative <= 0.9 ) | |
{ | |
actorAttacker.AddAbility( 'FCR3MedDamageBoost' ); | |
} | |
else if ( powerMod.valueMultiplicative <= 1.1 ) | |
{ | |
actorAttacker.AddAbility( 'FCR3LowDamageBoost' ); | |
} | |
} | |
if(action.IsCriticalHit()) | |
{ | |
if( playerAttacker && action.IsActionWitcherSign() && GetWitcherPlayer().IsMutationActive(EPMT_Mutation2) ) | |
{ | |
sp = action.GetPowerStatValue(); | |
theGame.GetDefinitionsManager().GetAbilityAttributeValue('Mutation2', 'crit_damage_factor', min, max); | |
criticalDamageBonus.valueAdditive = sp.valueMultiplicative * min.valueMultiplicative; | |
} | |
else | |
{ | |
criticalDamageBonus = actorAttacker.GetCriticalHitDamageBonus(weaponId, victimMonsterCategory, actorVictim.IsAttackerAtBack(playerAttacker)); | |
criticalDamageBonus += actorAttacker.GetAttributeValue('critical_hit_chance_fast_style'); | |
if(attackAction && playerAttacker) | |
{ | |
if(playerAttacker.IsHeavyAttack(attackAction.GetAttackName()) && playerAttacker.CanUseSkill(S_Sword_s08)) | |
criticalDamageBonus += playerAttacker.GetSkillAttributeValue(S_Sword_s08, theGame.params.CRITICAL_HIT_DAMAGE_BONUS, false, true) * playerAttacker.GetSkillLevel(S_Sword_s08); | |
else if (!playerAttacker.IsHeavyAttack(attackAction.GetAttackName()) && playerAttacker.CanUseSkill(S_Sword_s17)) | |
criticalDamageBonus += playerAttacker.GetSkillAttributeValue(S_Sword_s17, theGame.params.CRITICAL_HIT_DAMAGE_BONUS, false, true) * playerAttacker.GetSkillLevel(S_Sword_s17); | |
} | |
} | |
totalBonus = CalculateAttributeValue(criticalDamageBonus); | |
critReduction = actorVictim.GetAttributeValue(theGame.params.CRITICAL_HIT_REDUCTION); | |
totalBonus = totalBonus * ClampF(1 - critReduction.valueMultiplicative, 0.f, 1.f); | |
powerMod.valueMultiplicative += totalBonus; | |
} | |
if (actorVictim && playerAttacker) | |
{ | |
if ( playerAttacker.HasBuff(EET_Mutagen05) && (playerAttacker.GetStat(BCS_Vitality) == playerAttacker.GetStatMax(BCS_Vitality)) ) | |
{ | |
mutagen = playerAttacker.GetBuff(EET_Mutagen05); | |
dm.GetAbilityAttributeValue(mutagen.GetAbilityName(), 'damageIncrease', min, max); | |
powerMod += GetAttributeRandomizedValue(min, max); | |
} | |
} | |
return powerMod; | |
} | |
private function GetDamageResists(dmgType : name, out resistPts : float, out resistPerc : float) | |
{ | |
var armorReduction, armorReductionPerc, skillArmorReduction : SAbilityAttributeValue; | |
var bonusReduct, bonusResist : float; | |
var mutagenBuff : W3Mutagen28_Effect; | |
var appliedOilName, vsMonsterResistReduction : name; | |
var oils : array< W3Effect_Oil >; | |
var i : int; | |
if(attackAction && attackAction.IsActionMelee() && actorAttacker.GetInventory().IsItemFists(weaponId) && !actorVictim.UsesEssence()) | |
return; | |
if(actorVictim) | |
{ | |
actorVictim.GetResistValue( GetResistForDamage(dmgType, action.IsDoTDamage()), resistPts, resistPerc ); | |
if(playerVictim && actorAttacker && playerVictim.CanUseSkill(S_Alchemy_s05)) | |
{ | |
GetOilProtectionAgainstMonster(dmgType, bonusResist, bonusReduct); | |
resistPerc += bonusResist * playerVictim.GetSkillLevel(S_Alchemy_s05); | |
} | |
if(playerVictim && actorAttacker && playerVictim.HasBuff(EET_Mutagen28)) | |
{ | |
mutagenBuff = (W3Mutagen28_Effect)playerVictim.GetBuff(EET_Mutagen28); | |
mutagenBuff.GetProtection(attackerMonsterCategory, dmgType, action.IsDoTDamage(), bonusResist, bonusReduct); | |
resistPts += bonusReduct; | |
resistPerc += bonusResist; | |
} | |
if(actorAttacker) | |
{ | |
armorReduction = actorAttacker.GetAttributeValue('armor_reduction'); | |
armorReductionPerc = actorAttacker.GetAttributeValue('armor_reduction_perc'); | |
if(playerAttacker) | |
{ | |
vsMonsterResistReduction = MonsterCategoryToResistReduction(victimMonsterCategory); | |
oils = playerAttacker.inv.GetOilsAppliedOnItem( weaponId ); | |
if( oils.Size() > 0 ) | |
{ | |
for( i=0; i<oils.Size(); i+=1 ) | |
{ | |
appliedOilName = oils[ i ].GetOilItemName(); | |
if( oils[ i ].GetAmmoCurrentCount() > 0 && dm.ItemHasAttribute( appliedOilName, true, vsMonsterResistReduction ) ) | |
{ | |
armorReductionPerc.valueMultiplicative += oils[ i ].GetAmmoPercentage(); | |
} | |
} | |
} | |
} | |
if(playerAttacker && action.IsActionMelee() && playerAttacker.IsHeavyAttack(attackAction.GetAttackName()) && playerAttacker.CanUseSkill(S_Sword_2)) | |
armorReduction += playerAttacker.GetSkillAttributeValue(S_Sword_2, 'armor_reduction', false, true); | |
if ( playerAttacker && | |
action.IsActionMelee() && playerAttacker.IsHeavyAttack(attackAction.GetAttackName()) && | |
( dmgType == theGame.params.DAMAGE_NAME_PHYSICAL || | |
dmgType == theGame.params.DAMAGE_NAME_SLASHING || | |
dmgType == theGame.params.DAMAGE_NAME_PIERCING || | |
dmgType == theGame.params.DAMAGE_NAME_BLUDGEONING || | |
dmgType == theGame.params.DAMAGE_NAME_RENDING || | |
dmgType == theGame.params.DAMAGE_NAME_SILVER | |
) && | |
playerAttacker.CanUseSkill(S_Sword_s06) | |
) | |
{ | |
skillArmorReduction = playerAttacker.GetSkillAttributeValue(S_Sword_s06, 'armor_reduction_perc', false, true); | |
armorReductionPerc += skillArmorReduction * playerAttacker.GetSkillLevel(S_Sword_s06); | |
} | |
} | |
} | |
if(!action.GetIgnoreArmor()) | |
resistPts += CalculateAttributeValue( actorVictim.GetTotalArmor() ); | |
resistPts = MaxF(0, resistPts - CalculateAttributeValue(armorReduction) ); | |
resistPerc -= CalculateAttributeValue(armorReductionPerc); | |
resistPerc = MaxF(0, resistPerc); | |
} | |
private function CalculateDamage(dmgInfo : SRawDamage, powerMod : SAbilityAttributeValue) : float | |
{ | |
var finalDamage, finalIncomingDamage : float; | |
var resistPoints, resistPercents : float; | |
var ptsString, percString : string; | |
var mutagen : CBaseGameplayEffect; | |
var min, max : SAbilityAttributeValue; | |
var encumbranceBonus : float; | |
var temp : bool; | |
var fistfightDamageMult : float; | |
var burning : W3Effect_Burning; | |
var weaponName : name; | |
var dmgBonus : float; | |
var playerStlDmg : float; | |
var playerSlvDmg : float; | |
var playerFastSlvDmg: float; | |
var playerSlvCritDmg: float; | |
var multBonus : float; | |
var dmgLevel : int; | |
var curStats : SPlayerOffenseStats; | |
var inv : CInventoryComponent; | |
GetDamageResists(dmgInfo.dmgType, resistPoints, resistPercents); | |
if( thePlayer.IsFistFightMinigameEnabled() && actorAttacker == thePlayer ) | |
{ | |
finalDamage = MaxF(0, (dmgInfo.dmgVal)); | |
} | |
else | |
{ | |
burning = (W3Effect_Burning)action.causer; | |
if( burning && burning.IsSignEffect() ) | |
{ | |
if ( powerMod.valueMultiplicative > 2.5f ) | |
{ | |
powerMod.valueMultiplicative = 2.5f + LogF( (powerMod.valueMultiplicative - 2.5f) + 1 ); | |
} | |
} | |
finalDamage = MaxF(0, (dmgInfo.dmgVal + powerMod.valueBase) * powerMod.valueMultiplicative + powerMod.valueAdditive); | |
inv = actorAttacker.GetInventory(); | |
weaponName = inv.GetItemName( weaponId ); | |
if( thePlayer.IsCiri() ) | |
{ | |
dmgLevel = ( actorVictim.GetLevel() -2 ) * 10; | |
} | |
else | |
{ | |
dmgLevel = Min( actorVictim.GetLevel(), GetWitcherPlayer().GetLevel() ) * 40; | |
} | |
if( !playerAttacker && actorVictim && GetAttitudeBetween( thePlayer, actorAttacker ) == AIA_Friendly && !action.IsDoTDamage() && !actorAttacker.HasTag( 'Yennefer' ) && !actorAttacker.HasTag( 'keira' ) | |
&& !actorAttacker.HasTag( 'Philippa' ) && ( actorAttacker.IsWeaponHeld( 'silversword' ) || actorAttacker.IsWeaponHeld( 'staff2h' ) || weaponName == 'fists_lightning' || weaponName == 'fists_fire' | |
|| actorAttacker.HasAbility( 'SkillWitcher' ) || actorAttacker.HasTag( 'zoltan' ) || actorAttacker.HasTag( 'hjalmar' ) || actorAttacker.HasTag( 'regis' ) || actorAttacker.HasBuff(EET_AxiiGuardMe) ) && ( finalDamage < dmgLevel || thePlayer.IsCiri() ) ) | |
{ | |
dmgBonus += dmgLevel - finalDamage; | |
finalDamage = MaxF(0, (dmgInfo.dmgVal + powerMod.valueBase + dmgBonus) * powerMod.valueMultiplicative + powerMod.valueAdditive); | |
} | |
} | |
finalIncomingDamage = finalDamage; | |
if(finalDamage > 0.f) | |
{ | |
if(!action.IsPointResistIgnored() && !(dmgInfo.dmgType == theGame.params.DAMAGE_NAME_ELEMENTAL || dmgInfo.dmgType == theGame.params.DAMAGE_NAME_FIRE || dmgInfo.dmgType == theGame.params.DAMAGE_NAME_FROST )) | |
{ | |
finalDamage = MaxF(0, finalDamage - resistPoints); | |
if(finalDamage == 0.f) | |
action.SetArmorReducedDamageToZero( true ); | |
} | |
} | |
if(finalDamage > 0.f) | |
{ | |
if (playerVictim == GetWitcherPlayer() && playerVictim.HasBuff(EET_Mutagen02)) | |
{ | |
encumbranceBonus = 1 - (GetWitcherPlayer().GetEncumbrance() / GetWitcherPlayer().GetMaxRunEncumbrance(temp)); | |
if (encumbranceBonus < 0) | |
encumbranceBonus = 0; | |
mutagen = playerVictim.GetBuff(EET_Mutagen02); | |
dm.GetAbilityAttributeValue(mutagen.GetAbilityName(), 'resistGainRate', min, max); | |
encumbranceBonus *= CalculateAttributeValue(GetAttributeRandomizedValue(min, max)); | |
resistPercents += encumbranceBonus; | |
} | |
finalDamage *= 1 - resistPercents; | |
} | |
if( !playerAttacker && actorVictim && !action.IsDoTDamage() && !thePlayer.IsFistFightMinigameEnabled() && finalDamage <= actorVictim.GetMaxHealth() * 0.01 && (GetAttitudeBetween( thePlayer, actorAttacker ) == AIA_Friendly || actorAttacker.HasBuff(EET_AxiiGuardMe)) ) | |
{ | |
dmgBonus += dmgLevel - finalDamage; | |
if ( powerMod.valueMultiplicative < 1.0 ) | |
{ | |
multBonus = 1.0 - powerMod.valueMultiplicative; | |
} | |
finalDamage = MaxF(actorVictim.GetMaxHealth() * 0.01, (dmgInfo.dmgVal + powerMod.valueBase + dmgBonus) * ( powerMod.valueMultiplicative + multBonus ) + powerMod.valueAdditive); | |
if(!action.IsPointResistIgnored() && !(dmgInfo.dmgType == theGame.params.DAMAGE_NAME_ELEMENTAL || dmgInfo.dmgType == theGame.params.DAMAGE_NAME_FIRE || dmgInfo.dmgType == theGame.params.DAMAGE_NAME_FROST )) | |
{ | |
finalDamage = MaxF(actorVictim.GetMaxHealth() * 0.01, finalDamage - resistPoints); | |
if(finalDamage == 0.f) | |
action.SetArmorReducedDamageToZero( true ); | |
else | |
action.SetArmorReducedDamageToZero( false ); | |
} | |
finalDamage *= 1 - resistPercents; | |
} | |
curStats = GetWitcherPlayer().GetOffenseStatsList(); | |
playerStlDmg = MaxF(0, curStats.steelStrongDmg - resistPoints); | |
playerStlDmg *= 1 - resistPercents; | |
playerStlDmg /= 6; | |
playerFastSlvDmg = MaxF(0, curStats.silverFastDmg - resistPoints); | |
playerFastSlvDmg *= 1 - resistPercents; | |
playerFastSlvDmg /= 6; | |
playerSlvDmg = MaxF(0, curStats.silverStrongDmg - resistPoints); | |
playerSlvDmg *= 1 - resistPercents; | |
playerSlvDmg /= 6; | |
playerSlvCritDmg = MaxF(0, curStats.silverStrongCritDmg - resistPoints); | |
playerSlvCritDmg *= 1 - resistPercents; | |
playerSlvCritDmg /= 6; | |
if( !playerAttacker && actorVictim && !action.IsDoTDamage() && !thePlayer.IsFistFightMinigameEnabled() && (GetAttitudeBetween( thePlayer, actorAttacker ) == AIA_Friendly || actorAttacker.HasBuff(EET_AxiiGuardMe)) && !thePlayer.IsCiri() ) | |
{ | |
if(finalDamage > playerStlDmg && !actorAttacker.HasAbility( 'ForceInstantKill' )) | |
{ | |
if ( actorAttacker.HasTag( 'regis' ) ) | |
{ | |
if ( finalDamage > playerSlvCritDmg * 2 ) | |
{ | |
finalDamage = ClampF( finalDamage, 0, playerSlvCritDmg * 2 ); | |
finalDamage = MaxF(actorVictim.GetMaxHealth() * 0.01, finalDamage); | |
} | |
if ( finalDamage < playerSlvCritDmg ) | |
{ | |
finalDamage = ClampF( finalDamage, playerSlvCritDmg, finalDamage ); | |
} | |
} | |
else if ( actorAttacker.IsWeaponHeld( 'staff2h' ) || weaponName == 'fists_lightning' || weaponName == 'fists_fire' || action.GetPowerStatType() == CPS_SpellPower ) | |
{ | |
if ( finalDamage > playerSlvDmg * 2 ) | |
{ | |
finalDamage = ClampF( finalDamage, 0, playerSlvDmg ); | |
finalDamage = MaxF(actorVictim.GetMaxHealth() * 0.01, finalDamage); | |
} | |
if ( finalDamage < playerFastSlvDmg && attackAction ) | |
{ | |
finalDamage = ClampF( finalDamage, playerFastSlvDmg, finalDamage ); | |
} | |
} | |
else if ( actorAttacker.IsWeaponHeld( 'silversword' ) || actorAttacker.HasAbility( 'SkillWitcher' ) || actorAttacker.HasBuff(EET_AxiiGuardMe) ) | |
{ | |
if ( finalDamage > playerSlvCritDmg ) | |
{ | |
finalDamage = ClampF( finalDamage, 0, playerSlvCritDmg ); | |
finalDamage = MaxF(actorVictim.GetMaxHealth() * 0.01, finalDamage); | |
} | |
if ( action.IsActionMelee() ) | |
{ | |
if ( finalDamage < playerSlvDmg && actorVictim.UsesEssence() ) | |
{ | |
finalDamage = ClampF( finalDamage, playerSlvDmg, finalDamage ); | |
} | |
else if ( finalDamage < playerStlDmg ) | |
{ | |
finalDamage = ClampF( finalDamage, playerStlDmg, finalDamage ); | |
} | |
} | |
} | |
else | |
{ | |
finalDamage = ClampF( finalDamage, 0, playerStlDmg ); | |
finalDamage = MaxF(actorVictim.GetMaxHealth() * 0.01, finalDamage); | |
} | |
} | |
if(thePlayer.GetBossTag() != '' || (W3MonsterHuntNPC)actorVictim || actorVictim.GetCharacterStats().HasAbilityWithTag('Boss') || actorVictim.HasAbility( 'Boss' ) || actorVictim.HasAbility( 'SkillBoss') ) | |
{ | |
finalDamage = ClampF(finalDamage, 0, actorVictim.GetMaxHealth() * 0.005); | |
} | |
} | |
if(actorAttacker.HasBuff(EET_AxiiGuardMe)) | |
{ | |
switch(GetWitcherPlayer().GetSkillLevel(S_Magic_s05)) | |
{ | |
case 3: | |
finalDamage *= 1.6; | |
break; | |
case 2: | |
finalDamage *= 1.4; | |
break; | |
case 1: | |
finalDamage *= 1.2; | |
break; | |
} | |
} | |
if(dmgInfo.dmgType == theGame.params.DAMAGE_NAME_FIRE && finalDamage > 0) | |
action.SetDealtFireDamage(true); | |
if( playerAttacker && thePlayer.IsWeaponHeld('fist') && !thePlayer.IsInFistFightMiniGame() && action.IsActionMelee() ) | |
{ | |
if(FactsQuerySum("NewGamePlus") > 0) | |
{fistfightDamageMult = thePlayer.GetLevel()* 0.1;} | |
else | |
{fistfightDamageMult = thePlayer.GetLevel()* 0.05;} | |
finalDamage *= ( 1+fistfightDamageMult ); | |
} | |
if(playerAttacker && attackAction && playerAttacker.IsHeavyAttack(attackAction.GetAttackName())) | |
finalDamage *= 1.833; | |
burning = (W3Effect_Burning)action.causer; | |
if(actorVictim && (((W3IgniEntity)action.causer) || ((W3IgniProjectile)action.causer) || ( burning && burning.IsSignEffect())) ) | |
{ | |
min = actorVictim.GetAttributeValue('igni_damage_amplifier'); | |
finalDamage = finalDamage * (1 + min.valueMultiplicative) + min.valueAdditive; | |
} | |
if ( theGame.CanLog() ) | |
{ | |
LogDMHits("Single hit damage: initial damage = " + NoTrailZeros(dmgInfo.dmgVal), action); | |
LogDMHits("Single hit damage: attack_power = base: " + NoTrailZeros(powerMod.valueBase) + ", mult: " + NoTrailZeros(powerMod.valueMultiplicative) + ", add: " + NoTrailZeros(powerMod.valueAdditive), action ); | |
if(action.IsPointResistIgnored()) | |
LogDMHits("Single hit damage: resistance pts and armor = IGNORED", action); | |
else | |
LogDMHits("Single hit damage: resistance pts and armor = " + NoTrailZeros(resistPoints), action); | |
LogDMHits("Single hit damage: resistance perc = " + NoTrailZeros(resistPercents * 100), action); | |
LogDMHits("Single hit damage: final damage to sustain = " + NoTrailZeros(finalDamage), action); | |
} | |
if( playerVictim && actorAttacker && FactsQuerySum("NewGamePlus") > 0) | |
finalDamage *= 1.1; | |
return finalDamage; | |
} | |
private function ProcessActionDamage_DealDamage() | |
{ | |
var logStr : string; | |
var hpPerc : float; | |
var npcVictim : CNewNPC; | |
if ( theGame.CanLog() ) | |
{ | |
logStr = ""; | |
if(action.processedDmg.vitalityDamage > 0) logStr += NoTrailZeros(action.processedDmg.vitalityDamage) + " vitality, "; | |
if(action.processedDmg.essenceDamage > 0) logStr += NoTrailZeros(action.processedDmg.essenceDamage) + " essence, "; | |
if(action.processedDmg.staminaDamage > 0) logStr += NoTrailZeros(action.processedDmg.staminaDamage) + " stamina, "; | |
if(action.processedDmg.moraleDamage > 0) logStr += NoTrailZeros(action.processedDmg.moraleDamage) + " morale"; | |
if(logStr == "") | |
logStr = "NONE"; | |
LogDMHits("Final damage to sustain is: " + logStr, action); | |
} | |
if(actorVictim) | |
{ | |
hpPerc = actorVictim.GetHealthPercents(); | |
if(actorVictim.IsAlive()) | |
{ | |
npcVictim = (CNewNPC)actorVictim; | |
if(npcVictim && npcVictim.IsHorse()) | |
{ | |
npcVictim.GetHorseComponent().OnTakeDamage(action); | |
} | |
else | |
{ | |
actorVictim.OnTakeDamage(action); | |
} | |
} | |
if(!actorVictim.IsAlive() && hpPerc == 1) | |
action.SetWasKilledBySingleHit(); | |
} | |
if ( theGame.CanLog() ) | |
{ | |
LogDMHits("", action); | |
LogDMHits("Target stats after damage dealt are:", action); | |
if(actorVictim) | |
{ | |
if( actorVictim.UsesVitality()) LogDMHits("Vitality = " + NoTrailZeros( actorVictim.GetStat(BCS_Vitality)), action); | |
if( actorVictim.UsesEssence()) LogDMHits("Essence = " + NoTrailZeros( actorVictim.GetStat(BCS_Essence)), action); | |
if( actorVictim.GetStatMax(BCS_Stamina) > 0) LogDMHits("Stamina = " + NoTrailZeros( actorVictim.GetStat(BCS_Stamina, true)), action); | |
if( actorVictim.GetStatMax(BCS_Morale) > 0) LogDMHits("Morale = " + NoTrailZeros( actorVictim.GetStat(BCS_Morale)), action); | |
} | |
else | |
{ | |
LogDMHits("Undefined - victim is not a CActor and therefore has no stats", action); | |
} | |
} | |
} | |
private function ProcessActionDamage_ReduceDurability() | |
{ | |
var witcherPlayer : W3PlayerWitcher; | |
var dbg_currDur, dbg_prevDur1, dbg_prevDur2, dbg_prevDur3, dbg_prevDur4, dbg_prevDur : float; | |
var dbg_armor, dbg_pants, dbg_boots, dbg_gloves, reducedItemId, weapon : SItemUniqueId; | |
var slot : EEquipmentSlots; | |
var weapons : array<SItemUniqueId>; | |
var armorStringName : string; | |
var canLog, playerHasSword : bool; | |
var i : int; | |
canLog = theGame.CanLog(); | |
witcherPlayer = GetWitcherPlayer(); | |
if ( playerAttacker && playerAttacker.inv.IsIdValid( weaponId ) && playerAttacker.inv.HasItemDurability( weaponId ) ) | |
{ | |
dbg_prevDur = playerAttacker.inv.GetItemDurability(weaponId); | |
if ( playerAttacker.inv.ReduceItemDurability(weaponId) && canLog ) | |
{ | |
LogDMHits("", action); | |
LogDMHits("Player's weapon durability changes from " + NoTrailZeros(dbg_prevDur) + " to " + NoTrailZeros(action.attacker.GetInventory().GetItemDurability(weaponId)), action ); | |
} | |
} | |
else if(playerVictim && attackAction && attackAction.IsActionMelee() && (attackAction.IsParried() || attackAction.IsCountered()) ) | |
{ | |
weapons = playerVictim.inv.GetHeldWeapons(); | |
playerHasSword = false; | |
for(i=0; i<weapons.Size(); i+=1) | |
{ | |
weapon = weapons[i]; | |
if(playerVictim.inv.IsIdValid(weapon) && (playerVictim.inv.IsItemSteelSwordUsableByPlayer(weapon) || playerVictim.inv.IsItemSilverSwordUsableByPlayer(weapon)) ) | |
{ | |
playerHasSword = true; | |
break; | |
} | |
} | |
if(playerHasSword) | |
{ | |
playerVictim.inv.ReduceItemDurability(weapon); | |
} | |
} | |
else if(action.victim == witcherPlayer && (action.IsActionMelee() || action.IsActionRanged()) && action.DealsAnyDamage()) | |
{ | |
if ( canLog ) | |
{ | |
if ( witcherPlayer.GetItemEquippedOnSlot(EES_Armor, dbg_armor) ) | |
dbg_prevDur1 = action.victim.GetInventory().GetItemDurability(dbg_armor); | |
else | |
dbg_prevDur1 = 0; | |
if ( witcherPlayer.GetItemEquippedOnSlot(EES_Pants, dbg_pants) ) | |
dbg_prevDur2 = action.victim.GetInventory().GetItemDurability(dbg_pants); | |
else | |
dbg_prevDur2 = 0; | |
if ( witcherPlayer.GetItemEquippedOnSlot(EES_Boots, dbg_boots) ) | |
dbg_prevDur3 = action.victim.GetInventory().GetItemDurability(dbg_boots); | |
else | |
dbg_prevDur3 = 0; | |
if ( witcherPlayer.GetItemEquippedOnSlot(EES_Gloves, dbg_gloves) ) | |
dbg_prevDur4 = action.victim.GetInventory().GetItemDurability(dbg_gloves); | |
else | |
dbg_prevDur4 = 0; | |
} | |
slot = GetWitcherPlayer().ReduceArmorDurability(); | |
if( canLog ) | |
{ | |
LogDMHits("", action); | |
if(slot != EES_InvalidSlot) | |
{ | |
switch(slot) | |
{ | |
case EES_Armor : | |
armorStringName = "chest armor"; | |
reducedItemId = dbg_armor; | |
dbg_prevDur = dbg_prevDur1; | |
break; | |
case EES_Pants : | |
armorStringName = "pants"; | |
reducedItemId = dbg_pants; | |
dbg_prevDur = dbg_prevDur2; | |
break; | |
case EES_Boots : | |
armorStringName = "boots"; | |
reducedItemId = dbg_boots; | |
dbg_prevDur = dbg_prevDur3; | |
break; | |
case EES_Gloves : | |
armorStringName = "gloves"; | |
reducedItemId = dbg_gloves; | |
dbg_prevDur = dbg_prevDur4; | |
break; | |
} | |
dbg_currDur = action.victim.GetInventory().GetItemDurability(reducedItemId); | |
LogDMHits("", action); | |
LogDMHits("Player's <<" + armorStringName + ">> durability changes from " + NoTrailZeros(dbg_prevDur) + " to " + NoTrailZeros(dbg_currDur), action ); | |
} | |
else | |
{ | |
LogDMHits("Tried to reduce player's armor durability but failed", action); | |
} | |
} | |
if(slot != EES_InvalidSlot) | |
thePlayer.inv.ReduceItemRepairObjectBonusCharge(reducedItemId); | |
} | |
} | |
private function ProcessActionReaction(wasFrozen : bool, wasAlive : bool) | |
{ | |
var dismemberExplosion : bool; | |
var damageName : name; | |
var damage : array<SRawDamage>; | |
var points, percents, hp, dmg : float; | |
var counterAction : W3DamageAction; | |
var moveTargets : array<CActor>; | |
var i : int; | |
var canPerformFinisher : bool; | |
var weaponName : name; | |
var npcVictim : CNewNPC; | |
var toxicCloud : W3ToxicCloud; | |
var playsNonAdditiveAnim : bool; | |
var bleedCustomEffect : SCustomEffectParams; | |
var min, max : SAbilityAttributeValue; | |
var minDmg : float; | |
if(!actorVictim) | |
return; | |
npcVictim = (CNewNPC)actorVictim; | |
canPerformFinisher = CanPerformFinisher(actorVictim); | |
if( actorVictim.IsAlive() && !canPerformFinisher ) | |
{ | |
if(!action.IsDoTDamage() && action.DealtDamage()) | |
{ | |
if ( actorAttacker && npcVictim) | |
{ | |
npcVictim.NoticeActorInGuardArea( actorAttacker ); | |
} | |
if ( !playerVictim ) | |
actorVictim.RemoveAllBuffsOfType(EET_Confusion); | |
if(playerAttacker && action.IsActionMelee() && !playerAttacker.GetInventory().IsItemFists(weaponId) && playerAttacker.IsLightAttack(attackAction.GetAttackName()) && playerAttacker.CanUseSkill(S_Sword_s05)) | |
{ | |
bleedCustomEffect.effectType = EET_Bleeding; | |
bleedCustomEffect.creator = playerAttacker; | |
bleedCustomEffect.sourceName = SkillEnumToName(S_Sword_s05); | |
theGame.GetDefinitionsManager().GetAbilityAttributeValue( 'BleedingEffect', 'DirectDamage', min, max ); | |
bleedCustomEffect.effectValue = min; | |
minDmg = CalculateAttributeValue(playerAttacker.GetSkillAttributeValue(S_Sword_s05, 'dmg_per_sec', false, true)) * playerAttacker.GetSkillLevel(S_Sword_s05); | |
dmg = bleedCustomEffect.effectValue.valueAdditive + (bleedCustomEffect.effectValue.valueMultiplicative * actorVictim.GetMaxHealth()); | |
if ( dmg < minDmg ) | |
{ | |
bleedCustomEffect.effectValue.valueAdditive += minDmg - dmg; | |
} | |
actorVictim.AddEffectCustom(bleedCustomEffect); | |
} | |
} | |
if(actorVictim && wasAlive) | |
{ | |
playsNonAdditiveAnim = actorVictim.ReactToBeingHit( action ); | |
} | |
} | |
else | |
{ | |
if( !canPerformFinisher && CanDismember( wasFrozen, dismemberExplosion, weaponName ) ) | |
{ | |
ProcessDismemberment(wasFrozen, dismemberExplosion); | |
toxicCloud = (W3ToxicCloud)action.causer; | |
if(toxicCloud && toxicCloud.HasExplodingTargetDamages()) | |
ProcessToxicCloudDismemberExplosion(toxicCloud.GetExplodingTargetDamages()); | |
if(IsRequiredAttitudeBetween(thePlayer, action.victim, true)) | |
{ | |
moveTargets = thePlayer.GetMoveTargets(); | |
for ( i = 0; i < moveTargets.Size(); i += 1 ) | |
{ | |
if ( moveTargets[i].IsHuman() ) | |
moveTargets[i].DrainMorale(20.f); | |
} | |
} | |
} | |
else if ( canPerformFinisher ) | |
{ | |
if ( actorVictim.IsAlive() ) | |
actorVictim.Kill( 'Finisher', false, thePlayer ); | |
thePlayer.AddTimer( 'DelayedFinisherInputTimer', 0.1f ); | |
thePlayer.SetFinisherVictim( actorVictim ); | |
thePlayer.CleanCombatActionBuffer(); | |
thePlayer.OnBlockAllCombatTickets( true ); | |
if( actorVictim.WillBeUnconscious() ) | |
{ | |
actorVictim.SetBehaviorVariable( 'prepareForUnconsciousFinisher', 1.0f ); | |
actorVictim.ActionRotateToAsync( thePlayer.GetWorldPosition() ); | |
} | |
moveTargets = thePlayer.GetMoveTargets(); | |
for ( i = 0; i < moveTargets.Size(); i += 1 ) | |
{ | |
if ( actorVictim != moveTargets[i] ) | |
moveTargets[i].SignalGameplayEvent( 'InterruptChargeAttack' ); | |
} | |
if ( theGame.GetInGameConfigWrapper().GetVarValue('Gameplay', 'AutomaticFinishersEnabled' ) == "true" | |
|| ( (W3PlayerWitcher)playerAttacker && GetWitcherPlayer().IsMutationActive( EPMT_Mutation3 ) ) | |
|| actorVictim.WillBeUnconscious() | |
) | |
{ | |
actorVictim.AddAbility( 'ForceFinisher', false ); | |
} | |
if ( actorVictim.HasTag( 'ForceFinisher' ) ) | |
actorVictim.AddAbility( 'ForceFinisher', false ); | |
actorVictim.SignalGameplayEvent( 'ForceFinisher' ); | |
} | |
else if ( weaponName == 'fists' && npcVictim ) | |
{ | |
npcVictim.DisableAgony(); | |
} | |
thePlayer.FindMoveTarget(); | |
} | |
if( attackAction.IsActionMelee() ) | |
{ | |
actorAttacker.SignalGameplayEventParamObject( 'HitActionReaction', actorVictim ); | |
actorVictim.OnHitActionReaction( actorAttacker, weaponName ); | |
} | |
actorVictim.ProcessHitSound(action, playsNonAdditiveAnim || !actorVictim.IsAlive()); | |
if(action.IsCriticalHit() && action.DealtDamage() && !actorVictim.IsAlive() && actorAttacker == thePlayer ) | |
GCameraShake( 0.5, true, actorAttacker.GetWorldPosition(), 10 ); | |
if( attackAction && npcVictim && npcVictim.IsShielded( actorAttacker ) && attackAction.IsParried() && attackAction.GetAttackName() == 'attack_heavy' && npcVictim.GetStaminaPercents() <= 0.1 ) | |
{ | |
npcVictim.ProcessShieldDestruction(); | |
} | |
if( actorVictim && action.CanPlayHitParticle() && ( action.DealsAnyDamage() || (attackAction && attackAction.IsParried()) ) ) | |
actorVictim.PlayHitEffect(action); | |
if( action.victim.HasAbility('mon_nekker_base') && !actorVictim.CanPlayHitAnim() && !((CBaseGameplayEffect) action.causer) ) | |
{ | |
actorVictim.PlayEffect(theGame.params.LIGHT_HIT_FX); | |
actorVictim.SoundEvent("cmb_play_hit_light"); | |
} | |
if(actorVictim && playerAttacker && action.IsActionMelee() && thePlayer.inv.IsItemFists(weaponId) ) | |
{ | |
actorVictim.SignalGameplayEvent( 'wasHitByFists' ); | |
if(MonsterCategoryIsMonster(victimMonsterCategory)) | |
{ | |
if(!victimCanBeHitByFists) | |
{ | |
playerAttacker.ReactToReflectedAttack(actorVictim); | |
} | |
else | |
{ | |
actorVictim.GetResistValue(CDS_PhysicalRes, points, percents); | |
if(percents >= theGame.params.MONSTER_RESIST_THRESHOLD_TO_REFLECT_FISTS) | |
playerAttacker.ReactToReflectedAttack(actorVictim); | |
} | |
} | |
} | |
ProcessSparksFromNoDamage(); | |
//Critical Slow Motion Combat Redux | |
if ( mCSMCR.critSloMoToggle && mCSMCR.perfectDodgeOnly == 3 && playerVictim.IsCurrentlyDodging() | |
&& (playerVictim == GetWitcherPlayer() || (W3ReplacerCiri)thePlayer) && !action.DealsAnyDamage() && (!attackAction.IsCountered() || !attackAction.IsParried()) ) | |
{ | |
mCSMCR.Init(,,true,playerVictim ); | |
} | |
if(attackAction && attackAction.IsActionMelee() && actorAttacker && playerVictim && attackAction.IsCountered() && playerVictim == GetWitcherPlayer()) | |
{ | |
GetWitcherPlayer().SetRecentlyCountered(true); | |
} | |
if(attackAction && !action.IsDoTDamage() && (playerAttacker || playerVictim) && (attackAction.IsParried() || attackAction.IsCountered()) ) | |
{ | |
theGame.VibrateControllerLight(); | |
} | |
} | |
private function CanDismember( wasFrozen : bool, out dismemberExplosion : bool, out weaponName : name ) : bool | |
{ | |
var dismember : bool; | |
var dismemberChance : int; | |
var petard : W3Petard; | |
var bolt : W3BoltProjectile; | |
var arrow : W3ArrowProjectile; | |
var inv : CInventoryComponent; | |
var toxicCloud : W3ToxicCloud; | |
var witcher : W3PlayerWitcher; | |
var i : int; | |
var secondaryWeapon : bool; | |
petard = (W3Petard)action.causer; | |
bolt = (W3BoltProjectile)action.causer; | |
arrow = (W3ArrowProjectile)action.causer; | |
toxicCloud = (W3ToxicCloud)action.causer; | |
dismemberExplosion = false; | |
if(playerAttacker) | |
{ | |
secondaryWeapon = playerAttacker.inv.ItemHasTag( weaponId, 'SecondaryWeapon' ) || playerAttacker.inv.ItemHasTag( weaponId, 'Wooden' ); | |
//Critical Slow Motion Combat Redux | |
inv = actorAttacker.GetInventory(); | |
weaponName = inv.GetItemName( weaponId ); | |
if ( mCSMCR.critSloMoToggle ) | |
secondaryWeapon = false; | |
secondaryWeapon = playerAttacker.inv.ItemHasTag( weaponId, 'Wooden' ) || weaponName == 'W_Club' | |
|| weaponName == 'W_Mace01' || weaponName == 'W_Mace02' || weaponName == 'q302_Mace' || weaponName == 'W_Poker'; | |
//Critical Slow Motion Combat Redux | |
} | |
if( actorVictim.HasAbility( 'DisableDismemberment' ) ) | |
{ | |
dismember = false; | |
} | |
else if( actorVictim.HasTag( 'DisableDismemberment' ) ) | |
{ | |
dismember = false; | |
} | |
else if (actorVictim.WillBeUnconscious()) | |
{ | |
dismember = false; | |
} | |
else if (playerAttacker && secondaryWeapon ) | |
{ | |
dismember = false; | |
} | |
else if( arrow && !wasFrozen ) | |
{ | |
dismember = false; | |
} | |
else if( actorAttacker.HasAbility( 'ForceDismemberment' ) ) | |
{ | |
dismember = true; | |
dismemberExplosion = action.HasForceExplosionDismemberment(); | |
} | |
else if(wasFrozen) | |
{ | |
dismember = true; | |
dismemberExplosion = action.HasForceExplosionDismemberment(); | |
} | |
else if( (petard && petard.DismembersOnKill()) || (bolt && bolt.DismembersOnKill()) ) | |
{ | |
dismember = true; | |
dismemberExplosion = action.HasForceExplosionDismemberment(); | |
} | |
else if( (W3Effect_YrdenHealthDrain)action.causer ) | |
{ | |
dismember = true; | |
dismemberExplosion = true; | |
} | |
else if(toxicCloud && toxicCloud.HasExplodingTargetDamages()) | |
{ | |
dismember = true; | |
dismemberExplosion = true; | |
} | |
else | |
{ | |
inv = actorAttacker.GetInventory(); | |
weaponName = inv.GetItemName( weaponId ); | |
if( attackAction | |
&& !inv.IsItemSteelSwordUsableByPlayer(weaponId) | |
&& !inv.IsItemSilverSwordUsableByPlayer(weaponId) | |
&& weaponName != 'polearm' | |
&& weaponName != 'fists_lightning' | |
&& weaponName != 'fists_fire' //) //Critical Slow Motion Combat Redux | |
&& !playerAttacker.inv.ItemHasTag( weaponId, 'SecondaryWeapon' ) ) | |
//Critical Slow Motion Combat Redux | |
{ | |
dismember = false; | |
} | |
else if ( action.IsCriticalHit() ) | |
{ | |
dismember = true; | |
dismemberExplosion = action.HasForceExplosionDismemberment(); | |
//Critical Slow Motion Combat Redux | |
if ( mCSMCR.critSloMoToggle ) | |
{ | |
if ( RandRange(100) < mCSMCR.dismemberChance ) | |
dismember = true; | |
else | |
dismember = false; | |
} | |
//Critical Slow Motion Combat Redux | |
} | |
else if ( action.HasForceExplosionDismemberment() ) | |
{ | |
dismember = true; | |
dismemberExplosion = true; | |
} | |
else if ( weaponName == 'fists_lightning' || weaponName == 'fists_fire' ) | |
{ | |
if(RandRange(100) > 75) | |
dismember = true; | |
} | |
else | |
{ | |
dismemberChance = theGame.params.DISMEMBERMENT_ON_DEATH_CHANCE; | |
//Critical Slow Motion Combat Redux | |
if ( mCSMCR.critSloMoToggle && thePlayer.IsInCombat()) | |
dismemberChance = mCSMCR.dismemberChance; | |
//Critical Slow Motion Combat Redux | |
if(playerAttacker && playerAttacker.forceDismember) | |
{ | |
dismemberChance = thePlayer.forceDismemberChance; | |
dismemberExplosion = thePlayer.forceDismemberExplosion; | |
} | |
if(attackAction) | |
{ | |
dismemberChance += RoundMath(100 * CalculateAttributeValue(inv.GetItemAttributeValue(weaponId, 'dismember_chance'))); | |
dismemberExplosion = attackAction.HasForceExplosionDismemberment(); | |
} | |
witcher = (W3PlayerWitcher)actorAttacker; | |
if(witcher && witcher.CanUseSkill(S_Perk_03)) | |
dismemberChance += RoundMath(100 * CalculateAttributeValue(witcher.GetSkillAttributeValue(S_Perk_03, 'dismember_chance', false, true))); | |
if( ( W3PlayerWitcher )playerAttacker && attackAction.IsActionMelee() && GetWitcherPlayer().IsMutationActive(EPMT_Mutation3) ) | |
{ | |
if( thePlayer.inv.IsItemSteelSwordUsableByPlayer( weaponId ) || thePlayer.inv.IsItemSilverSwordUsableByPlayer( weaponId ) ) | |
{ | |
dismemberChance = 100; | |
} | |
} | |
dismemberChance = Clamp(dismemberChance, 0, 100); | |
if (RandRange(100) < dismemberChance) | |
dismember = true; | |
else | |
dismember = false; | |
} | |
} | |
//Critical Slow Motion Combat Redux | |
if ( mCSMCR.critSloMoToggle && thePlayer.IsInCombat() && (playerAttacker == GetWitcherPlayer() || (W3ReplacerCiri)thePlayer) | |
&& ! dismemberExplosion && attackAction.IsActionMelee() ) | |
mCSMCR.Init(,,,,dismember); | |
//Critical Slow Motion Combat Redux | |
return dismember; | |
} | |
private function CanPerformFinisher( actorVictim : CActor ) : bool | |
{ | |
var finisherChance : int; | |
var areEnemiesAttacking : bool; | |
var i : int; | |
var victimToPlayerVector, playerPos : Vector; | |
var item : SItemUniqueId; | |
var moveTargets : array<CActor>; | |
var b : bool; | |
var size : int; | |
var npc : CNewNPC; | |
if ( (W3ReplacerCiri)thePlayer || playerVictim || thePlayer.isInFinisher ) | |
return false; | |
if ( actorVictim.IsAlive() && !CanPerformFinisherOnAliveTarget(actorVictim) ) | |
return false; | |
if ( actorVictim.WillBeUnconscious() && !theGame.GetDLCManager().IsEP2Available() ) | |
return false; | |
moveTargets = thePlayer.GetMoveTargets(); | |
size = moveTargets.Size(); | |
playerPos = thePlayer.GetWorldPosition(); | |
if ( size > 0 ) | |
{ | |
areEnemiesAttacking = false; | |
for(i=0; i<size; i+=1) | |
{ | |
npc = (CNewNPC)moveTargets[i]; | |
if(npc && VecDistanceSquared(playerPos, moveTargets[i].GetWorldPosition()) < 7 && npc.IsAttacking() && npc != actorVictim ) | |
{ | |
areEnemiesAttacking = true; | |
break; | |
} | |
} | |
} | |
victimToPlayerVector = actorVictim.GetWorldPosition() - playerPos; | |
if ( actorVictim.IsHuman() ) | |
{ | |
npc = (CNewNPC)actorVictim; | |
if ( ( size <= 1 && theGame.params.FINISHER_ON_DEATH_CHANCE > 0 ) || ( actorVictim.HasAbility('ForceFinisher') ) || ( GetWitcherPlayer().IsMutationActive(EPMT_Mutation3) ) ) | |
{ | |
finisherChance = 100; | |
} | |
else if ( ( actorVictim.HasBuff(EET_Confusion) || actorVictim.HasBuff(EET_AxiiGuardMe) ) ) | |
{ | |
finisherChance = 75 + ( - ( npc.currentLevel - thePlayer.GetLevel() ) ); | |
} | |
else if ( npc.currentLevel - thePlayer.GetLevel() < -5 ) | |
{ | |
finisherChance = theGame.params.FINISHER_ON_DEATH_CHANCE + ( - ( npc.currentLevel - thePlayer.GetLevel() ) ); | |
} | |
else | |
finisherChance = theGame.params.FINISHER_ON_DEATH_CHANCE; | |
//Critical Slow Motion Combat Redux | |
if ( mCSMCR.critSloMoToggle ) | |
finisherChance = mCSMCR.finisherChance; | |
//Critical Slow Motion Combat Redux | |
finisherChance = Clamp(finisherChance, 0, 100); | |
} | |
else | |
finisherChance = 0; | |
if ( actorVictim.HasTag('ForceFinisher') ) | |
{ | |
finisherChance = 100; | |
areEnemiesAttacking = false; | |
} | |
item = thePlayer.inv.GetItemFromSlot( 'l_weapon' ); | |
if ( thePlayer.forceFinisher ) | |
{ | |
b = playerAttacker && attackAction && attackAction.IsActionMelee(); | |
b = b && ( actorVictim.IsHuman() && !actorVictim.IsWoman() ); | |
b = b && !thePlayer.IsInAir(); | |
b = b && ( thePlayer.IsWeaponHeld( 'steelsword') || thePlayer.IsWeaponHeld( 'silversword') ); | |
b = b && !thePlayer.IsSecondaryWeaponHeld(); | |
b = b && !thePlayer.inv.IsIdValid( item ); | |
b = b && !actorVictim.IsKnockedUnconscious(); | |
b = b && !actorVictim.HasBuff( EET_Knockdown ); | |
b = b && !actorVictim.HasBuff( EET_Ragdoll ); | |
b = b && !actorVictim.HasBuff( EET_Frozen ); | |
b = b && !actorVictim.HasAbility( 'DisableFinishers' ); | |
b = b && !thePlayer.IsUsingVehicle(); | |
b = b && thePlayer.IsAlive(); | |
b = b && !thePlayer.IsCurrentSignChanneled(); | |
} | |
else | |
{ | |
b = playerAttacker && attackAction && attackAction.IsActionMelee(); | |
b = b && ( actorVictim.IsHuman() && !actorVictim.IsWoman() ); | |
b = b && RandRange(100) < finisherChance; | |
b = b && !areEnemiesAttacking; | |
b = b && AbsF( victimToPlayerVector.Z ) < 0.4f; | |
b = b && !thePlayer.IsInAir(); | |
b = b && ( thePlayer.IsWeaponHeld( 'steelsword') || thePlayer.IsWeaponHeld( 'silversword') ); | |
b = b && !thePlayer.IsSecondaryWeaponHeld(); | |
b = b && !thePlayer.inv.IsIdValid( item ); | |
b = b && !actorVictim.IsKnockedUnconscious(); | |
b = b && !actorVictim.HasBuff( EET_Knockdown ); | |
b = b && !actorVictim.HasBuff( EET_Ragdoll ); | |
b = b && !actorVictim.HasBuff( EET_Frozen ); | |
b = b && !actorVictim.HasAbility( 'DisableFinishers' ); | |
b = b && actorVictim.GetAttitude( thePlayer ) == AIA_Hostile; | |
b = b && !thePlayer.IsUsingVehicle(); | |
b = b && thePlayer.IsAlive(); | |
b = b && !thePlayer.IsCurrentSignChanneled(); | |
b = b && ( theGame.GetWorld().NavigationCircleTest( actorVictim.GetWorldPosition(), 2.f ) || actorVictim.HasTag('ForceFinisher') ) ; | |
} | |
if ( b ) | |
{ | |
if ( !actorVictim.IsAlive() && !actorVictim.WillBeUnconscious() ) | |
actorVictim.AddAbility( 'DisableFinishers', false ); | |
return true; | |
} | |
return false; | |
} | |
private function CanPerformFinisherOnAliveTarget( actorVictim : CActor ) : bool | |
{ | |
return actorVictim.IsHuman() | |
&& ( actorVictim.HasBuff(EET_Confusion) || actorVictim.HasBuff(EET_AxiiGuardMe) ) | |
&& actorVictim.IsVulnerable() | |
&& !actorVictim.HasAbility('DisableFinisher') | |
&& !actorVictim.HasAbility('InstantKillImmune'); | |
} | |
private function ProcessActionBuffs() : bool | |
{ | |
var inv : CInventoryComponent; | |
var ret : bool; | |
if(!action.victim.IsAlive() || action.WasDodged() || (attackAction && attackAction.IsActionMelee() && !attackAction.ApplyBuffsIfParried() && attackAction.CanBeParried() && attackAction.IsParried()) ) | |
return true; | |
ApplyQuenBuffChanges(); | |
if( actorAttacker == thePlayer && action.IsActionWitcherSign() && action.IsCriticalHit() && GetWitcherPlayer().IsMutationActive( EPMT_Mutation2 ) && action.HasBuff( EET_Burning ) ) | |
{ | |
action.SetBuffSourceName( 'Mutation2ExplosionValid' ); | |
} | |
if(actorVictim && action.GetEffectsCount() > 0) | |
ret = actorVictim.ApplyActionEffects(action); | |
else | |
ret = false; | |
if(actorAttacker && actorVictim) | |
{ | |
inv = actorAttacker.GetInventory(); | |
actorAttacker.ProcessOnHitEffects(actorVictim, inv.IsItemSilverSwordUsableByPlayer(weaponId), inv.IsItemSteelSwordUsableByPlayer(weaponId), action.IsActionWitcherSign() ); | |
} | |
return ret; | |
} | |
private function ApplyQuenBuffChanges() | |
{ | |
var npc : CNewNPC; | |
var protection : bool; | |
var witcher : W3PlayerWitcher; | |
var quenEntity : W3QuenEntity; | |
var i : int; | |
var buffs : array<EEffectType>; | |
if(!actorVictim || !actorVictim.HasAlternateQuen()) | |
return; | |
npc = (CNewNPC)actorVictim; | |
if(npc) | |
{ | |
if(!action.DealsAnyDamage()) | |
protection = true; | |
} | |
else | |
{ | |
witcher = (W3PlayerWitcher)actorVictim; | |
if(witcher) | |
{ | |
quenEntity = (W3QuenEntity)witcher.GetCurrentSignEntity(); | |
if(quenEntity.GetBlockedAllDamage()) | |
{ | |
protection = true; | |
} | |
} | |
} | |
if(!protection) | |
return; | |
action.GetEffectTypes(buffs); | |
for(i=buffs.Size()-1; i>=0; i -=1) | |
{ | |
if(buffs[i] == EET_KnockdownTypeApplicator || IsKnockdownEffectType(buffs[i])) | |
continue; | |
action.RemoveBuff(i); | |
} | |
} | |
private function ProcessDismemberment(wasFrozen : bool, dismemberExplosion : bool ) | |
{ | |
var hitDirection : Vector; | |
var usedWound : name; | |
var npcVictim : CNewNPC; | |
var wounds : array< name >; | |
var i : int; | |
var petard : W3Petard; | |
var bolt : W3BoltProjectile; | |
var forcedRagdoll : bool; | |
var isExplosion : bool; | |
var dismembermentComp : CDismembermentComponent; | |
var specialWounds : array< name >; | |
var useHitDirection : bool; | |
var fxMask : EDismembermentEffectTypeFlags; | |
var template : CEntityTemplate; | |
var ent : CEntity; | |
var signType : ESignType; | |
if(!actorVictim) | |
return; | |
dismembermentComp = (CDismembermentComponent)(actorVictim.GetComponentByClassName( 'CDismembermentComponent' )); | |
if(!dismembermentComp) | |
return; | |
if(wasFrozen) | |
{ | |
ProcessFrostDismemberment(); | |
return; | |
} | |
forcedRagdoll = false; | |
petard = (W3Petard)action.causer; | |
bolt = (W3BoltProjectile)action.causer; | |
if( dismemberExplosion || (attackAction && ( attackAction.GetAttackName() == 'attack_explosion' || attackAction.HasForceExplosionDismemberment() )) | |
|| (petard && petard.DismembersOnKill()) || (bolt && bolt.DismembersOnKill()) ) | |
{ | |
isExplosion = true; | |
} | |
else | |
{ | |
isExplosion = false; | |
} | |
if(playerAttacker && thePlayer.forceDismember && IsNameValid(thePlayer.forceDismemberName)) | |
{ | |
usedWound = thePlayer.forceDismemberName; | |
} | |
else | |
{ | |
if(isExplosion) | |
{ | |
dismembermentComp.GetWoundsNames( wounds, WTF_Explosion ); | |
if( action.IsMutation2PotentialKill() ) | |
{ | |
for( i=wounds.Size()-1; i>=0; i-=1 ) | |
{ | |
if( !StrContains( wounds[ i ], "_ep2" ) ) | |
{ | |
wounds.EraseFast( i ); | |
} | |
} | |
signType = action.GetSignType(); | |
if( signType == ST_Aard ) | |
{ | |
fxMask = DETF_Aaard; | |
} | |
else if( signType == ST_Igni ) | |
{ | |
fxMask = DETF_Igni; | |
} | |
else if( signType == ST_Yrden ) | |
{ | |
fxMask = DETF_Yrden; | |
} | |
else if( signType == ST_Quen ) | |
{ | |
fxMask = DETF_Quen; | |
} | |
} | |
else | |
{ | |
fxMask = 0; | |
} | |
if ( wounds.Size() > 0 ) | |
usedWound = wounds[ RandRange( wounds.Size() ) ]; | |
if ( usedWound ) | |
StopVO( actorVictim ); | |
} | |
else if(attackAction || action.GetBuffSourceName() == "riderHit") | |
{ | |
if ( attackAction.GetAttackTypeName() == 'sword_s2' || thePlayer.isInFinisher ) | |
useHitDirection = true; | |
if ( useHitDirection ) | |
{ | |
hitDirection = actorAttacker.GetSwordTipMovementFromAnimation( attackAction.GetAttackAnimName(), attackAction.GetHitTime(), 0.1, attackAction.GetWeaponEntity() ); | |
usedWound = actorVictim.GetNearestWoundForBone( attackAction.GetHitBoneIndex(), hitDirection, WTF_Cut ); | |
} | |
else | |
{ | |
dismembermentComp.GetWoundsNames( wounds ); | |
if(wounds.Size() > 0) | |
{ | |
dismembermentComp.GetWoundsNames( specialWounds, WTF_Explosion ); | |
for ( i = 0; i < specialWounds.Size(); i += 1 ) | |
{ | |
wounds.Remove( specialWounds[i] ); | |
} | |
if(wounds.Size() > 0) | |
{ | |
dismembermentComp.GetWoundsNames( specialWounds, WTF_Frost ); | |
for ( i = 0; i < specialWounds.Size(); i += 1 ) | |
{ | |
wounds.Remove( specialWounds[i] ); | |
} | |
if ( wounds.Size() > 0 ) | |
usedWound = wounds[ RandRange( wounds.Size() ) ]; | |
} | |
} | |
} | |
} | |
} | |
if ( usedWound ) | |
{ | |
npcVictim = (CNewNPC)action.victim; | |
if(npcVictim) | |
npcVictim.DisableAgony(); | |
actorVictim.SetDismembermentInfo( usedWound, actorVictim.GetWorldPosition() - actorAttacker.GetWorldPosition(), forcedRagdoll, fxMask ); | |
actorVictim.AddTimer( 'DelayedDismemberTimer', 0.05f ); | |
actorVictim.SetBehaviorVariable( 'dismemberAnim', 1.0 ); | |
if ( usedWound == 'explode_02' || usedWound == 'explode2' || usedWound == 'explode_02_ep2' || usedWound == 'explode2_ep2') | |
{ | |
ProcessDismembermentDeathAnim( usedWound, true, EFDT_LegLeft ); | |
actorVictim.SetKinematic( false ); | |
} | |
else | |
{ | |
ProcessDismembermentDeathAnim( usedWound, false ); | |
} | |
if( usedWound == 'explode_01_ep2' || usedWound == 'explode1_ep2' || usedWound == 'explode_02_ep2' || usedWound == 'explode2_ep2' ) | |
{ | |
template = (CEntityTemplate) LoadResource( "explosion_dismember_force" ); | |
ent = theGame.CreateEntity( template, npcVictim.GetWorldPosition(), , , , true ); | |
ent.DestroyAfter( 5.f ); | |
} | |
DropEquipmentFromDismember( usedWound, true, true ); | |
if( attackAction && actorAttacker == thePlayer ) | |
GCameraShake( 0.5, true, actorAttacker.GetWorldPosition(), 10); | |
if(playerAttacker) | |
theGame.VibrateControllerHard(); | |
if( dismemberExplosion && (W3AardProjectile)action.causer ) | |
{ | |
npcVictim.AddTimer( 'AardDismemberForce', 0.00001f ); | |
} | |
} | |
else | |
{ | |
LogChannel( 'Dismemberment', "ERROR: No wound found to dismember on entity but entity supports dismemberment!!!" ); | |
} | |
} | |
function ApplyForce() | |
{ | |
var size, i : int; | |
var victim : CNewNPC; | |
var fromPos, toPos : Vector; | |
var comps : array<CComponent>; | |
var impulse : Vector; | |
victim = (CNewNPC)action.victim; | |
toPos = victim.GetWorldPosition(); | |
toPos.Z += 1.0f; | |
fromPos = toPos; | |
fromPos.Z -= 2.0f; | |
impulse = VecNormalize( toPos - fromPos.Z ) * 10; | |
comps = victim.GetComponentsByClassName('CComponent'); | |
victim.GetVisualDebug().AddArrow( 'applyForce', fromPos, toPos, 1, 0.2f, 0.2f, true, Color( 0,0,255 ), true, 5.0f ); | |
size = comps.Size(); | |
for( i = 0; i < size; i += 1 ) | |
{ | |
comps[i].ApplyLocalImpulseToPhysicalObject( impulse ); | |
} | |
} | |
private function ProcessFrostDismemberment() | |
{ | |
var dismembermentComp : CDismembermentComponent; | |
var wounds : array< name >; | |
var wound : name; | |
var i, fxMask : int; | |
var npcVictim : CNewNPC; | |
dismembermentComp = (CDismembermentComponent)(actorVictim.GetComponentByClassName( 'CDismembermentComponent' )); | |
if(!dismembermentComp) | |
return; | |
dismembermentComp.GetWoundsNames( wounds, WTF_Frost ); | |
if( theGame.GetDLCManager().IsEP2Enabled() ) | |
{ | |
fxMask = DETF_Mutation6; | |
for( i=wounds.Size()-1; i>=0; i-=1 ) | |
{ | |
if( !StrContains( wounds[ i ], "_ep2" ) ) | |
{ | |
wounds.EraseFast( i ); | |
} | |
} | |
} | |
else | |
{ | |
fxMask = 0; | |
} | |
if ( wounds.Size() > 0 ) | |
{ | |
wound = wounds[ RandRange( wounds.Size() ) ]; | |
} | |
else | |
{ | |
return; | |
} | |
npcVictim = (CNewNPC)action.victim; | |
if(npcVictim) | |
{ | |
npcVictim.DisableAgony(); | |
StopVO( npcVictim ); | |
} | |
actorVictim.SetDismembermentInfo( wound, actorVictim.GetWorldPosition() - actorAttacker.GetWorldPosition(), true, fxMask ); | |
actorVictim.AddTimer( 'DelayedDismemberTimer', 0.05f ); | |
if( wound == 'explode_02' || wound == 'explode2' || wound == 'explode_02_ep2' || wound == 'explode2_ep2' ) | |
{ | |
ProcessDismembermentDeathAnim( wound, true, EFDT_LegLeft ); | |
npcVictim.SetKinematic(false); | |
} | |
else | |
{ | |
ProcessDismembermentDeathAnim( wound, false ); | |
} | |
DropEquipmentFromDismember( wound, true, true ); | |
if( attackAction ) | |
GCameraShake( 0.5, true, actorAttacker.GetWorldPosition(), 10); | |
if(playerAttacker) | |
theGame.VibrateControllerHard(); | |
} | |
private function ProcessDismembermentDeathAnim( nearestWound : name, forceDeathType : bool, optional deathType : EFinisherDeathType ) | |
{ | |
var dropCurveName : name; | |
if ( forceDeathType ) | |
{ | |
if ( deathType == EFDT_Head ) | |
StopVO( actorVictim ); | |
actorVictim.SetBehaviorVariable( 'FinisherDeathType', (int)deathType ); | |
return; | |
} | |
dropCurveName = ( (CDismembermentComponent)(actorVictim.GetComponentByClassName( 'CDismembermentComponent' )) ).GetMainCurveName( nearestWound ); | |
if ( dropCurveName == 'head' ) | |
{ | |
actorVictim.SetBehaviorVariable( 'FinisherDeathType', (int)EFDT_Head ); | |
StopVO( actorVictim ); | |
} | |
else if ( dropCurveName == 'torso_left' || dropCurveName == 'torso_right' || dropCurveName == 'torso' ) | |
actorVictim.SetBehaviorVariable( 'FinisherDeathType', (int)EFDT_Torso ); | |
else if ( dropCurveName == 'arm_right' ) | |
actorVictim.SetBehaviorVariable( 'FinisherDeathType', (int)EFDT_ArmRight ); | |
else if ( dropCurveName == 'arm_left' ) | |
actorVictim.SetBehaviorVariable( 'FinisherDeathType', (int)EFDT_ArmLeft ); | |
else if ( dropCurveName == 'leg_left' ) | |
actorVictim.SetBehaviorVariable( 'FinisherDeathType', (int)EFDT_LegLeft ); | |
else if ( dropCurveName == 'leg_right' ) | |
actorVictim.SetBehaviorVariable( 'FinisherDeathType', (int)EFDT_LegRight ); | |
else | |
actorVictim.SetBehaviorVariable( 'FinisherDeathType', (int)EFDT_None ); | |
} | |
private function StopVO( actor : CActor ) | |
{ | |
actor.SoundEvent( "grunt_vo_death_stop", 'head' ); | |
} | |
private function DropEquipmentFromDismember( nearestWound : name, optional dropLeft, dropRight : bool ) | |
{ | |
var dropCurveName : name; | |
if( actorVictim.HasAbility( 'DontDropWeaponsOnDismemberment' ) ) | |
{ | |
return; | |
} | |
dropCurveName = ( (CDismembermentComponent)(actorVictim.GetComponentByClassName( 'CDismembermentComponent' )) ).GetMainCurveName( nearestWound ); | |
if ( ChangeHeldItemAppearance() ) | |
{ | |
actorVictim.SignalGameplayEvent('DropWeaponsInDeathTask'); | |
return; | |
} | |
if ( dropLeft || dropRight ) | |
{ | |
if ( dropLeft ) | |
actorVictim.DropItemFromSlot( 'l_weapon', true ); | |
if ( dropRight ) | |
actorVictim.DropItemFromSlot( 'r_weapon', true ); | |
return; | |
} | |
if ( dropCurveName == 'arm_right' ) | |
actorVictim.DropItemFromSlot( 'r_weapon', true ); | |
else if ( dropCurveName == 'arm_left' ) | |
actorVictim.DropItemFromSlot( 'l_weapon', true ); | |
else if ( dropCurveName == 'torso_left' || dropCurveName == 'torso_right' || dropCurveName == 'torso' ) | |
{ | |
actorVictim.DropItemFromSlot( 'l_weapon', true ); | |
actorVictim.DropItemFromSlot( 'r_weapon', true ); | |
} | |
else if ( dropCurveName == 'head' || dropCurveName == 'leg_left' || dropCurveName == 'leg_right' ) | |
{ | |
if( RandRange(100) < 50 ) | |
actorVictim.DropItemFromSlot( 'l_weapon', true ); | |
if( RandRange(100) < 50 ) | |
actorVictim.DropItemFromSlot( 'r_weapon', true ); | |
} | |
} | |
function ChangeHeldItemAppearance() : bool | |
{ | |
var inv : CInventoryComponent; | |
var weapon : SItemUniqueId; | |
inv = actorVictim.GetInventory(); | |
weapon = inv.GetItemFromSlot('l_weapon'); | |
if ( inv.IsIdValid( weapon ) ) | |
{ | |
if ( inv.ItemHasTag(weapon,'bow') || inv.ItemHasTag(weapon,'crossbow') ) | |
inv.GetItemEntityUnsafe(weapon).ApplyAppearance("rigid"); | |
return true; | |
} | |
weapon = inv.GetItemFromSlot('r_weapon'); | |
if ( inv.IsIdValid( weapon ) ) | |
{ | |
if ( inv.ItemHasTag(weapon,'bow') || inv.ItemHasTag(weapon,'crossbow') ) | |
inv.GetItemEntityUnsafe(weapon).ApplyAppearance("rigid"); | |
return true; | |
} | |
return false; | |
} | |
private function GetOilProtectionAgainstMonster(dmgType : name, out resist : float, out reduct : float) | |
{ | |
var i : int; | |
var heldWeapons : array< SItemUniqueId >; | |
var weapon : SItemUniqueId; | |
resist = 0; | |
reduct = 0; | |
heldWeapons = thePlayer.inv.GetHeldWeapons(); | |
for( i=0; i<heldWeapons.Size(); i+=1 ) | |
{ | |
if( !thePlayer.inv.IsItemFists( heldWeapons[ i ] ) ) | |
{ | |
weapon = heldWeapons[ i ]; | |
break; | |
} | |
} | |
if( !thePlayer.inv.IsIdValid( weapon ) ) | |
{ | |
return; | |
} | |
if( !thePlayer.inv.ItemHasActiveOilApplied( weapon, attackerMonsterCategory ) ) | |
{ | |
return; | |
} | |
resist = CalculateAttributeValue( thePlayer.GetSkillAttributeValue( S_Alchemy_s05, 'defence_bonus', false, true ) ); | |
} | |
private function ProcessToxicCloudDismemberExplosion(damages : array<SRawDamage>) | |
{ | |
var act : W3DamageAction; | |
var i, j : int; | |
var ents : array<CGameplayEntity>; | |
if(damages.Size() == 0) | |
{ | |
LogAssert(false, "W3DamageManagerProcessor.ProcessToxicCloudDismemberExplosion: trying to process but no damages are passed! Aborting!"); | |
return; | |
} | |
FindGameplayEntitiesInSphere(ents, action.victim.GetWorldPosition(), 3, 1000, , FLAG_OnlyAliveActors); | |
for(i=0; i<ents.Size(); i+=1) | |
{ | |
act = new W3DamageAction in this; | |
act.Initialize(action.attacker, ents[i], action.causer, 'Dragons_Dream_3', EHRT_Heavy, CPS_Undefined, false, false, false, true); | |
for(j=0; j<damages.Size(); j+=1) | |
{ | |
act.AddDamage(damages[j].dmgType, damages[j].dmgVal); | |
} | |
theGame.damageMgr.ProcessAction(act); | |
delete act; | |
} | |
} | |
private final function ProcessSparksFromNoDamage() | |
{ | |
var sparksEntity, weaponEntity : CEntity; | |
var weaponTipPosition : Vector; | |
var weaponSlotMatrix : Matrix; | |
if(!playerAttacker || !attackAction || !attackAction.IsActionMelee() || attackAction.DealsAnyDamage()) | |
return; | |
if( ( !attackAction.DidArmorReduceDamageToZero() && !actorVictim.IsVampire() && ( attackAction.IsParried() || attackAction.IsCountered() ) ) | |
|| ( ( attackAction.IsParried() || attackAction.IsCountered() ) && !actorVictim.IsHuman() && !actorVictim.IsVampire() ) | |
|| actorVictim.IsCurrentlyDodging() ) | |
return; | |
if(actorVictim.HasTag('NoSparksOnArmorDmgReduced')) | |
return; | |
if (!actorVictim.GetGameplayVisibility()) | |
return; | |
weaponEntity = playerAttacker.inv.GetItemEntityUnsafe(weaponId); | |
weaponEntity.CalcEntitySlotMatrix( 'blood_fx_point', weaponSlotMatrix ); | |
weaponTipPosition = MatrixGetTranslation( weaponSlotMatrix ); | |
sparksEntity = theGame.CreateEntity( (CEntityTemplate)LoadResource( 'sword_colision_fx' ), weaponTipPosition ); | |
sparksEntity.PlayEffect('sparks'); | |
} | |
private function ProcessPreHitModifications() | |
{ | |
var fireDamage, totalDmg, maxHealth, currHealth : float; | |
var attribute, min, max : SAbilityAttributeValue; | |
var infusion : ESignType; | |
var hack : array< SIgniEffects >; | |
var dmgValTemp : float; | |
var igni : W3IgniEntity; | |
var quen : W3QuenEntity; | |
if( actorVictim.HasAbility( 'HitWindowOpened' ) && !action.IsDoTDamage() ) | |
{ | |
if( actorVictim.HasTag( 'fairytale_witch' ) ) | |
{ | |
((CNewNPC)actorVictim).SetBehaviorVariable( 'shouldBreakFlightLoop', 1.0 ); | |
} | |
else | |
{ | |
quen = (W3QuenEntity)action.causer; | |
if( !quen ) | |
{ | |
if( actorVictim.HasTag( 'dettlaff_vampire' ) ) | |
{ | |
actorVictim.StopEffect( 'shadowdash' ); | |
} | |
action.ClearDamage(); | |
if( action.IsActionMelee() ) | |
{ | |
actorVictim.PlayEffect( 'special_attack_break' ); | |
} | |
actorVictim.SetBehaviorVariable( 'repelType', 0 ); | |
actorVictim.AddEffectDefault( EET_CounterStrikeHit, thePlayer ); | |
action.RemoveBuffsByType( EET_KnockdownTypeApplicator ); | |
} | |
} | |
((CNewNPC)actorVictim).SetHitWindowOpened( false ); | |
} | |
if(playerAttacker && attackAction && attackAction.IsActionMelee() && (W3PlayerWitcher)thePlayer && thePlayer.HasAbility('Runeword 1 _Stats', true)) | |
{ | |
infusion = GetWitcherPlayer().GetRunewordInfusionType(); | |
switch(infusion) | |
{ | |
case ST_Aard: | |
action.AddEffectInfo(EET_KnockdownTypeApplicator); | |
action.SetProcessBuffsIfNoDamage(true); | |
attackAction.SetApplyBuffsIfParried(true); | |
actorVictim.CreateFXEntityAtPelvis( 'runeword_1_aard', false ); | |
break; | |
case ST_Axii: | |
action.AddEffectInfo(EET_Confusion); | |
action.SetProcessBuffsIfNoDamage(true); | |
attackAction.SetApplyBuffsIfParried(true); | |
break; | |
case ST_Igni: | |
totalDmg = action.GetDamageValueTotal(); | |
attribute = thePlayer.GetAttributeValue('runeword1_fire_dmg'); | |
fireDamage = totalDmg * attribute.valueMultiplicative; | |
action.AddDamage(theGame.params.DAMAGE_NAME_FIRE, fireDamage); | |
action.SetCanPlayHitParticle(false); | |
action.victim.AddTimer('Runeword1DisableFireFX', 1.f); | |
action.SetHitReactionType(EHRT_Heavy); | |
action.victim.PlayEffect('critical_burning'); | |
break; | |
case ST_Yrden: | |
attribute = thePlayer.GetAttributeValue('runeword1_yrden_duration'); | |
action.AddEffectInfo(EET_Slowdown, attribute.valueAdditive); | |
action.SetProcessBuffsIfNoDamage(true); | |
attackAction.SetApplyBuffsIfParried(true); | |
break; | |
default: | |
break; | |
} | |
} | |
if( playerAttacker && actorVictim && (W3PlayerWitcher)playerAttacker && GetWitcherPlayer().IsMutationActive( EPMT_Mutation9 ) && (W3BoltProjectile)action.causer ) | |
{ | |
maxHealth = actorVictim.GetMaxHealth(); | |
currHealth = actorVictim.GetHealth(); | |
if( AbsF( maxHealth - currHealth ) < 1.f ) | |
{ | |
theGame.GetDefinitionsManager().GetAbilityAttributeValue('Mutation9', 'health_reduction', min, max); | |
actorVictim.ForceSetStat( actorVictim.GetUsedHealthType(), maxHealth * ( 1 - min.valueMultiplicative ) ); | |
} | |
action.AddEffectInfo( EET_KnockdownTypeApplicator, 0.1f, , , , 1.f ); | |
} | |
} | |
} | |
exec function ForceDismember( b: bool, optional chance : int, optional n : name, optional e : bool ) | |
{ | |
var temp : CR4Player; | |
temp = thePlayer; | |
temp.forceDismember = b; | |
temp.forceDismemberName = n; | |
temp.forceDismemberChance = chance; | |
temp.forceDismemberExplosion = e; | |
} | |
exec function ForceFinisher( b: bool, optional n : name, optional rightStance : bool ) | |
{ | |
var temp : CR4Player; | |
temp = thePlayer; | |
temp.forcedStance = rightStance; | |
temp.forceFinisher = b; | |
temp.forceFinisherAnimName = n; | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/***********************************************************************/ | |
/** © 2015 CD PROJEKT S.A. All rights reserved. | |
/** THE WITCHER® is a trademark of CD PROJEKT S. A. | |
/** The Witcher game is based on the prose of Andrzej Sapkowski. | |
/***********************************************************************/ | |
class W3ArrowProjectile extends W3AdvancedProjectile | |
{ | |
editable var defaultTrail : name; default defaultTrail = 'arrow_trail'; | |
//Critical Slow Motion Combat Redux | |
private var mCSMCR : CCSMCR; | |
//Critical Slow Motion Combat Redux | |
public var underwaterTrail : name; default underwaterTrail = 'arrow_trail_underwater'; | |
private var boneName : name; | |
private var activeTrail : name; | |
private var shouldBeAttachedToVictim : bool; default shouldBeAttachedToVictim = true; | |
protected var isOnFire : bool; | |
protected var isUnderwater : bool; | |
protected var isBouncedArrow : bool; | |
protected var isScheduledForDestruction : bool; default isScheduledForDestruction = false; | |
event OnProjectileShot( targetCurrentPosition : Vector, optional target : CNode ) | |
{ | |
super.OnProjectileShot(targetCurrentPosition,target); | |
if ( !IsNameValid(activeTrail) ) | |
{ | |
if( ( W3PlayerWitcher ) GetOwner() && GetWitcherPlayer().IsMutationActive( EPMT_Mutation9 ) ) | |
{ | |
defaultTrail = 'arrow_trail_mutation_9'; | |
} | |
ActivateTrail( defaultTrail ); | |
this.SoundEvent( "cmb_arrow_swoosh" ); | |
} | |
} | |
event OnRangeReached() | |
{ | |
StopAllEffects(); | |
if( !isScheduledForDestruction ) | |
{ | |
AddTimer( 'TimeDestroy', 2, false ); | |
isScheduledForDestruction = true; | |
} | |
} | |
event OnProjectileCollision( pos, normal : Vector, collidingComponent : CComponent, hitCollisionsGroups : array< name >, actorIndex : int, shapeIndex : int ) | |
{ | |
var actorVictim : CActor; | |
var casterPos : Vector; | |
var parryInfo : SParryInfo; | |
var arrowHitPos : Vector; | |
var bounce : bool; | |
var abs : array<name>; | |
var isRolling : bool; | |
var template : CEntityTemplate; | |
var meshComponent : CMeshComponent; | |
var boundingBox : Box; | |
var arrowSize : Vector; | |
var hitPos : Vector; | |
if ( yrdenAlternate ) | |
{ | |
return true; | |
} | |
SetShouldBeAttachedToVictim( true ); | |
if ( !isActive ) | |
{ | |
return true; | |
} | |
if(collidingComponent) | |
victim = (CGameplayEntity)collidingComponent.GetEntity(); | |
if ( collidingComponent || !hitCollisionsGroups.Contains( 'Water' ) ) | |
RemoveTimer( 'CheckIfInfWaterLoop' ); | |
super.OnProjectileCollision(pos, normal, collidingComponent, hitCollisionsGroups, actorIndex, shapeIndex); | |
if( collidingComponent && !hitCollisionsGroups.Contains( 'Static' ) ) | |
{ | |
if ( !victim || collidedEntities.Contains(victim) || victim == caster ) | |
return false; | |
actorVictim = (CActor)victim; | |
if ( hitCollisionsGroups.Contains( 'Ragdoll' ) && actorVictim ) | |
{ | |
boneName = ((CMovingPhysicalAgentComponent)actorVictim.GetMovingAgentComponent()).GetRagdollBoneName(actorIndex); | |
} | |
} | |
else if ( hitCollisionsGroups.Contains( 'Terrain' ) || hitCollisionsGroups.Contains( 'Static' ) || hitCollisionsGroups.Contains( 'Foliage' ) ) | |
{ | |
StopProjectile(); | |
isActive = false; | |
StopActiveTrail(); | |
AddTimer('TimeDestroy', 5, false); | |
isScheduledForDestruction = true; | |
arrowHitPos = pos + RotForward( this.GetWorldRotation() ) * 0.5f; | |
Teleport( arrowHitPos ); | |
this.SoundEvent("cmb_arrow_impact_dirt"); | |
return true; | |
} | |
else if ( hitCollisionsGroups.Contains( 'Water' ) ) | |
{ | |
if ( isUnderwater ) | |
{ | |
return false; | |
} | |
SoundEvent("cmb_arrow_impact_water"); | |
CheckIfInfWater(); | |
return true; | |
} | |
else | |
{ | |
return false; | |
} | |
if ( !actorVictim ) | |
{ | |
StopProjectile(); | |
isActive = false; | |
StopActiveTrail(); | |
AddTimer('TimeDestroy', 5, false); | |
isScheduledForDestruction = true; | |
if( StrFindFirst( this.GetName(), "bolt" ) != -1 ) | |
{ | |
meshComponent = (CMeshComponent)GetComponentByClassName('CMeshComponent'); | |
if( meshComponent ) | |
{ | |
boundingBox = meshComponent.GetBoundingBox(); | |
arrowSize = boundingBox.Max - boundingBox.Min; | |
hitPos = pos; | |
hitPos -= RotForward( this.GetWorldRotation() ) * arrowSize.X * 0.7f; | |
Teleport( hitPos ); | |
} | |
} | |
ProcessDamageAction(victim, pos, boneName); | |
this.SoundEvent("cmb_arrow_impact_wood"); | |
return true; | |
} | |
else if (victim == thePlayer) | |
{ | |
bounce = false; | |
if ( thePlayer.IsCurrentlyDodging() && thePlayer.GetBehaviorVariable( 'isRolling' ) == 1.f ) | |
{ | |
isRolling = true; | |
} | |
else if(thePlayer.HasAbility( 'Glyphword 1 _Stats', true )) | |
{ | |
thePlayer.PlayEffect('glyphword_reflection'); | |
template = (CEntityTemplate)LoadResource('glyphword_1'); | |
theGame.CreateEntity(template, GetWorldPosition(), thePlayer.GetWorldRotation(), , , true); | |
if ( thePlayer.CheckCounterSpamming( (CActor)caster ) && thePlayer.GetSkillLevel(S_Sword_s10) > 1 ) | |
{ | |
casterPos = caster.GetWorldPosition(); | |
casterPos.Z += 1.5; | |
this.Init(thePlayer); | |
if ( thePlayer.GetSkillLevel(S_Sword_s10) == 3 ) | |
{ | |
this.projDMG *= 1 + CalculateAttributeValue( thePlayer.GetSkillAttributeValue(S_Sword_s10, 'damage_increase', false, true) ); | |
} | |
this.ShootProjectileAtPosition(2,projSpeed*0.7,casterPos); | |
ActivateTrail('arrow_trail_red'); | |
return true; | |
} | |
else | |
{ | |
this.SoundEvent( "cmb_arrow_bounce" ); | |
bounce = true; | |
} | |
} | |
else if(thePlayer.CanParryAttack() && thePlayer.CanUseSkill(S_Sword_s10)) | |
{ | |
parryInfo = thePlayer.ProcessParryInfo(((CActor)caster),((CActor)victim),AST_Jab,ASD_NotSet,'attack_light',((CActor)caster).GetInventory().GetItemFromSlot('l_weapon'), true); | |
if ( thePlayer.PerformParryCheck(parryInfo) ) | |
{ | |
if ( thePlayer.CheckCounterSpamming( (CActor)caster ) && thePlayer.GetSkillLevel(S_Sword_s10) > 1 ) | |
{ | |
casterPos = caster.GetWorldPosition(); | |
casterPos.Z += 1.5; | |
this.Init(thePlayer); | |
if ( thePlayer.GetSkillLevel(S_Sword_s10) == 3 ) | |
{ | |
this.projDMG *= 1 + CalculateAttributeValue( thePlayer.GetSkillAttributeValue(S_Sword_s10, 'damage_increase', false, true) ); | |
} | |
this.ShootProjectileAtPosition(2,projSpeed*0.7,casterPos); | |
ActivateTrail('arrow_trail_red'); | |
isBouncedArrow = true; | |
//Critical Slow Motion Combat Redux | |
mCSMCR = thePlayer.mCSMCR; | |
if ( mCSMCR.critSloMoToggle && thePlayer.IsInCombat() ) | |
mCSMCR.Init(,,,,,,,isBouncedArrow,isBouncedArrow); | |
//Critical Slow Motion Combat Redux | |
return true; | |
} | |
else | |
{ | |
bounce = true; | |
} | |
} | |
} | |
if(!bounce) | |
{ | |
thePlayer.GetCharacterStats().GetAbilities(abs, true); | |
bounce = abs.Contains(theGame.params.BOUNCE_ARROWS_ABILITY); | |
if(bounce) | |
{ | |
FactsAdd("sq108_arrow_deflected"); | |
thePlayer.PlayEffect( 'bolt_bump' ); | |
} | |
} | |
if(bounce) | |
{ | |
this.bounceOfVelocityPreserve = 0.7; | |
this.BounceOff(normal,pos); | |
this.Init(thePlayer); | |
ActivateTrail('arrow_trail_orange'); | |
return false; | |
} | |
else if ( !isRolling ) | |
{ | |
if( actorVictim.IsAlive() ) | |
ProcessDamageAction( actorVictim, pos, boneName ); | |
this.SoundEvent( "cmb_arrow_impact_body" ); | |
if( IsNameValid( boneName ) ) | |
AttachArrowToRagdoll( actorVictim, pos, boneName ); | |
else | |
{ | |
StopProjectile(); | |
StopActiveTrail(); | |
isActive = false; | |
SmartDestroy(); | |
} | |
} | |
} | |
else if ( (CNewNPC)victim && ((CNewNPC)victim).IsShielded(caster) ) | |
{ | |
((CNewNPC)victim).SignalGameplayEvent('PerformAdditiveParry'); | |
this.SoundEvent("cmb_arrow_impact_wood"); | |
AttachArrowToShield(actorVictim, pos); | |
} | |
else | |
{ | |
if(actorVictim.IsAlive()) | |
{ | |
if ( actorVictim.HasAbility( 'BounceBoltsWildhunt' )) | |
{ | |
this.bounceOfVelocityPreserve = 0.1; | |
this.BounceOff(normal, pos); | |
this.Init(actorVictim); | |
this.PlayEffect('sparks'); | |
this.SoundEvent("cmb_arrow_impact_metal"); | |
ActivateTrail('arrow_trail_orange'); | |
return false; | |
} | |
else | |
{ | |
ProcessDamageAction(actorVictim, pos, boneName); | |
} | |
} | |
else if ( actorVictim.IsInAgony() ) | |
{ | |
actorVictim.SignalGameplayEvent('AbandonAgony'); | |
actorVictim.SetKinematic(false); | |
} | |
this.SoundEvent("cmb_arrow_impact_body"); | |
if( ShouldPierceVictim( actorVictim ) ) | |
{ | |
Mutation9HitFX( actorVictim ); | |
} | |
else if(IsNameValid(boneName)) | |
{ | |
AttachArrowToRagdoll(actorVictim,pos,boneName); | |
} | |
else | |
{ | |
StopProjectile(); | |
StopActiveTrail(); | |
isActive = false; | |
SmartDestroy(); | |
} | |
} | |
return true; | |
} | |
public final function Mutation9HitFX( actorVictim : CActor ) | |
{ | |
var ent : CEntity; | |
GCameraShake( 0.2f ); | |
if(IsNameValid(boneName)) | |
{ | |
ent = actorVictim.CreateFXEntityAtBone( 'mutation9_hit', boneName, true ); | |
} | |
else | |
{ | |
ent = actorVictim.CreateFXEntityAtPelvis( 'mutation9_hit', true ); | |
} | |
ent.PlayEffect( 'hit_refraction' ); | |
ent.SoundEvent( 'ep2_mutations_09_bolt_impact_armor_type' ); | |
} | |
protected function ShouldPierceVictim( victim : CActor ) : bool | |
{ | |
if( victim && GetOwner() && (W3PlayerWitcher)GetOwner() && GetWitcherPlayer().IsMutationActive( EPMT_Mutation9 ) ) | |
{ | |
return true; | |
} | |
return false; | |
} | |
event OnFireHit(source : CGameplayEntity) | |
{ | |
if ( !isUnderwater && isActive ) | |
{ | |
super.OnFireHit(source); | |
ToggleFire(true); | |
} | |
} | |
public function ToggleFire( toggle : bool ) | |
{ | |
if( !isOnFire && toggle ) | |
{ | |
isOnFire = true; | |
ActivateTrail('arrow_trail_fire'); | |
this.PlayEffect('fire'); | |
} | |
else if( isOnFire && !toggle ) | |
{ | |
isOnFire = false; | |
ActivateTrail(defaultTrail); | |
this.StopEffect('fire'); | |
} | |
} | |
function ToggleUnderwater( toggle : bool ) | |
{ | |
if( !isUnderwater && toggle ) | |
{ | |
isUnderwater = true; | |
} | |
else if( isUnderwater && !toggle ) | |
{ | |
isUnderwater = false; | |
this.isActive = false; | |
this.DestroyAfter(0.5); | |
} | |
} | |
function SmartDestroy() | |
{ | |
var i : int; | |
var compList : array<CComponent>; | |
compList = GetComponentsByClassName('CDrawableComponent'); | |
for ( i=0; i<compList.Size(); i+=1 ) | |
{ | |
((CDrawableComponent)compList[i]).SetVisible(false); | |
} | |
if( !isScheduledForDestruction ) | |
{ | |
AddTimer('TimeDestroy', 3, false); | |
isScheduledForDestruction = true; | |
} | |
} | |
function ActivateTrail( trailName : name ) | |
{ | |
if ( trailName != activeTrail ) | |
{ | |
if ( activeTrail ) | |
StopEffect( activeTrail ); | |
PlayEffect( trailName ); | |
activeTrail = trailName; | |
} | |
} | |
function StopActiveTrail() | |
{ | |
if (activeTrail) | |
{ | |
StopEffect( activeTrail ); | |
activeTrail = ''; | |
} | |
} | |
timer function CheckIfInfWaterLoop( timeDelta : float , id : int) | |
{ | |
if ( CheckIfInfWater() ) | |
RemoveTimer( 'CheckIfInfWaterLoop' ); | |
} | |
protected function CheckIfInfWater() : bool | |
{ | |
var entityPos : Vector; | |
var waterLevel : float; | |
entityPos = this.GetWorldPosition(); | |
waterLevel = theGame.GetWorld().GetWaterLevel( entityPos ); | |
if ( isUnderwater ) | |
{ | |
if ( waterLevel < entityPos.Z ) | |
{ | |
ToggleUnderwater( false ); | |
ActivateTrail(defaultTrail); | |
projAngle = 5.f; | |
return true; | |
} | |
} | |
else | |
{ | |
if ( waterLevel > entityPos.Z ) | |
{ | |
ToggleUnderwater( true ); | |
ToggleFire(false); | |
ActivateTrail(underwaterTrail); | |
projAngle = 2.f; | |
return true; | |
} | |
} | |
return false; | |
} | |
public function ThrowProjectile( targetPosIn : Vector ) | |
{ | |
CheckIfInfWater(); | |
AddTimer( 'CheckIfInfWaterLoop', 0.05, true ); | |
} | |
function AttachArrowToShield( victim : CActor, pos : Vector ) | |
{ | |
var bones : array<name>; | |
var res : bool; | |
var inv : CInventoryComponent; | |
var shield : CEntity; | |
var relativeRot : EulerAngles; | |
var relativePos : Vector; | |
StopProjectile(); | |
StopActiveTrail(); | |
isActive = false; | |
inv = victim.GetInventory(); | |
shield = inv.GetItemEntityUnsafe(inv.GetItemFromSlot('l_weapon')); | |
if( ((W3BoltProjectile)this) ) | |
{ | |
relativePos.X = RandRangeF(0.22f, -0.22f); | |
relativePos.Y = RandRangeF(0.25f, 0.2f); | |
relativePos.Z = RandRangeF(0.22f, -0.22f); | |
relativeRot.Pitch = 180 + RandRange(10, -10); | |
relativeRot.Roll = RandRange(10, -10); | |
relativeRot.Yaw = RandRange(10, -10); | |
} | |
else | |
{ | |
relativePos.X = RandRangeF(0.22f, -0.22f); | |
relativePos.Y = RandRangeF(-0.1f, -0.25f); | |
relativePos.Z = RandRangeF(0.22f, -0.22f); | |
relativeRot.Pitch = 180 + RandRange(10, -10); | |
relativeRot.Roll = RandRange(10, -10); | |
relativeRot.Yaw = RandRange(10, -10); | |
} | |
this.CreateAttachment( shield, , relativePos, relativeRot ); | |
} | |
function AttachArrowToRagdoll(victim : CActor, pos : Vector, boneName : name) | |
{ | |
var bones : array<name>; | |
var res : bool; | |
var arrowHitPos : Vector; | |
var timerAmount : float; | |
var shouldPierceVictim : bool; | |
var meshComponent : CMeshComponent; | |
var arrowSize : Vector; | |
var boundingBox : Box; | |
var rotMat : Matrix; | |
shouldPierceVictim = ShouldPierceVictim( victim ); | |
if( !shouldPierceVictim ) | |
{ | |
StopProjectile(); | |
StopActiveTrail(); | |
isActive = false; | |
} | |
bones.PushBack( 'head' ); | |
bones.PushBack( 'hroll' ); | |
bones.PushBack( 'neck' ); | |
if ( ( victim == thePlayer && bones.Contains(boneName) ) || ( ((CNewNPC)victim).IsHorse() && !shouldPierceVictim ) ) | |
{ | |
SmartDestroy(); | |
} | |
else if( !shouldPierceVictim ) | |
{ | |
arrowHitPos = pos; | |
meshComponent = (CMeshComponent)GetComponentByClassName('CMeshComponent'); | |
if( meshComponent ) | |
{ | |
boundingBox = meshComponent.GetBoundingBox(); | |
arrowSize = boundingBox.Max - boundingBox.Min; | |
rotMat = MatrixBuiltRotation( this.GetWorldRotation() ); | |
rotMat = MatrixGetInverted( rotMat ); | |
arrowSize = VecTransformDir( rotMat, arrowSize ); | |
if( arrowSize.Y > 0 ) | |
arrowHitPos += RotForward( this.GetWorldRotation() ) * arrowSize.Y * 0.1f; | |
else | |
arrowHitPos -= RotForward( this.GetWorldRotation() ) * arrowSize.Y * 0.9f; | |
} | |
if ( boneName ) | |
{ | |
res = this.CreateAttachmentAtBoneWS(victim, boneName, arrowHitPos, this.GetWorldRotation()); | |
} | |
else | |
{ | |
res = this.CreateAttachmentAtBoneWS(victim, 'torso3', arrowHitPos, this.GetWorldRotation()); | |
} | |
if ( res ) | |
{ | |
if( victim == thePlayer && !GetShouldBeAttachedToVictim() ) | |
timerAmount = 0.01; | |
else if( victim == thePlayer ) | |
timerAmount = 3; | |
else | |
timerAmount = 5; | |
AddTimer('TimeDestroy', timerAmount, false); | |
isScheduledForDestruction = true; | |
} | |
else | |
SmartDestroy(); | |
} | |
} | |
protected function ProcessDamageAction(victim : CGameplayEntity, pos : Vector, boneName : name) | |
{ | |
var action : W3DamageAction; | |
var victimTags, attackerTags : array<name>; | |
var none : SAbilityAttributeValue; | |
action = new W3DamageAction in this; | |
action.Initialize((CGameplayEntity)caster,victim,this,caster.GetName(),EHRT_Light,CPS_AttackPower,false,true,false,false); | |
if( isOnFire ) | |
{ | |
action.AddEffectInfo(EET_Burning); | |
action.AddDamage(theGame.params.DAMAGE_NAME_FIRE, projDMG ); | |
action.AddDamage(theGame.params.DAMAGE_NAME_SILVER, projSilverDMG ); | |
} | |
else | |
{ | |
action.AddDamage(theGame.params.DAMAGE_NAME_PIERCING, projDMG ); | |
action.AddDamage(theGame.params.DAMAGE_NAME_SILVER, projSilverDMG ); | |
} | |
if( this.projEfect != EET_Undefined ) | |
{ | |
action.AddEffectInfo(this.projEfect); | |
} | |
if ( ((CNewNPC)victim) ) | |
{ | |
if ( boneName == 'head' || boneName == 'neck' || boneName == 'hroll' || ( boneName == 'pelvis' && ((CNewNPC)victim).IsHuman() ) ) | |
action.SetHeadShot(); | |
} | |
if(isBouncedArrow) | |
{ | |
action.SetBouncedArrow(); | |
} | |
theGame.damageMgr.ProcessAction( action ); | |
collidedEntities.PushBack(victim); | |
delete action; | |
victimTags = victim.GetTags(); | |
attackerTags = caster.GetTags(); | |
AddHitFacts( victimTags, attackerTags, "_arrow_hit" ); | |
} | |
public function SetShouldBeAttachedToVictim( val : bool ) { shouldBeAttachedToVictim = val; } | |
public function GetShouldBeAttachedToVictim() : bool { return shouldBeAttachedToVictim; } | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment